svn commit: r226126 - in projects/diffused_head/sys: modules
modules/diffuse modules/diffuse/diffuse netinet netinet/ipfw sys
Lawrence Stewart
lstewart at FreeBSD.org
Sat Oct 8 03:58:21 UTC 2011
Author: lstewart
Date: Sat Oct 8 03:58:20 2011
New Revision: 226126
URL: http://svn.freebsd.org/changeset/base/226126
Log:
Add the core DIFFUSE kernel module code and supporting build infrastructure.
This module provides the kernel-side support for handling DIFFUSE's IPFW
configuration extensions, rule exporting, classifier/feature modules and
flow-related housekeeping.
Sponsored by: FreeBSD Foundation
Reviewed by: bz
Added:
projects/diffused_head/sys/modules/diffuse/
projects/diffused_head/sys/modules/diffuse/Makefile (contents, props changed)
projects/diffused_head/sys/modules/diffuse/diffuse/
projects/diffused_head/sys/modules/diffuse/diffuse/Makefile (contents, props changed)
projects/diffused_head/sys/netinet/ip_diffuse_export.h (contents, props changed)
projects/diffused_head/sys/netinet/ipfw/diffuse_classifier.h (contents, props changed)
projects/diffused_head/sys/netinet/ipfw/diffuse_classifier_module.h (contents, props changed)
projects/diffused_head/sys/netinet/ipfw/diffuse_export.c (contents, props changed)
projects/diffused_head/sys/netinet/ipfw/diffuse_feature_module.h (contents, props changed)
projects/diffused_head/sys/netinet/ipfw/diffuse_flowtable.c (contents, props changed)
projects/diffused_head/sys/netinet/ipfw/diffuse_user_compat.h (contents, props changed)
projects/diffused_head/sys/netinet/ipfw/ip_diffuse.c (contents, props changed)
Modified:
projects/diffused_head/sys/modules/Makefile
projects/diffused_head/sys/sys/time.h
Modified: projects/diffused_head/sys/modules/Makefile
==============================================================================
--- projects/diffused_head/sys/modules/Makefile Sat Oct 8 02:58:23 2011 (r226125)
+++ projects/diffused_head/sys/modules/Makefile Sat Oct 8 03:58:20 2011 (r226126)
@@ -78,6 +78,7 @@ SUBDIR= ${_3dfx} \
dcons \
dcons_crom \
de \
+ ${_diffuse} \
${_dpms} \
${_dpt} \
${_drm} \
@@ -365,6 +366,7 @@ _random= random
.endif
.if ${MK_INET_SUPPORT} != "no" || defined(ALL_MODULES)
+_diffuse= diffuse
_if_gre= if_gre
.endif
Added: projects/diffused_head/sys/modules/diffuse/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/diffused_head/sys/modules/diffuse/Makefile Sat Oct 8 03:58:20 2011 (r226126)
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= diffuse
+
+.include <bsd.subdir.mk>
Added: projects/diffused_head/sys/modules/diffuse/diffuse/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/diffused_head/sys/modules/diffuse/diffuse/Makefile Sat Oct 8 03:58:20 2011 (r226126)
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+.PATH: ${.CURDIR}/../../../netinet/ipfw
+
+KMOD= diffuse
+SRCS= diffuse_export.c \
+ diffuse_flowtable.c \
+ ip_diffuse.c \
+ opt_inet6.h
+
+.if !defined(KERNBUILDDIR)
+.if ${MK_INET_SUPPORT} != "no"
+opt_inet.h:
+ echo "#define INET 1" > ${.TARGET}
+.endif
+.if ${MK_INET6_SUPPORT} != "no"
+opt_inet6.h:
+ echo "#define INET6 1" > ${.TARGET}
+.endif
+.endif
+
+.include <bsd.kmod.mk>
Added: projects/diffused_head/sys/netinet/ip_diffuse_export.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/diffused_head/sys/netinet/ip_diffuse_export.h Sat Oct 8 03:58:20 2011 (r226126)
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2010-2011
+ * Swinburne University of Technology, Melbourne, Australia.
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University of Technology, by Sebastian Zander, made
+ * possible in part by a gift from The Cisco University Research Program Fund, a
+ * corporate advised fund of Silicon Valley Community Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * The public header file for DIFFUSE export protocol stuff.
+ */
+
+#ifndef _NETINET_IP_DIFFUSE_EXPORT_H_
+#define _NETINET_IP_DIFFUSE_EXPORT_H_
+
+/* DIFFUSE protocol version. */
+#define DIP_VERSION 1
+
+/* Used if querying MTU from routing table fails. */
+#define DIP_DEFAULT_MTU 1500
+
+enum dip_msg_types {
+ DIP_MSG_ADD = 0,
+ DIP_MSG_REMOVE
+};
+
+enum dip_timeout_types {
+ DIP_TIMEOUT_NONE = 0,
+ DIP_TIMEOUT_RULE,
+ DIP_TIMEOUT_FLOW
+};
+
+enum dip_info_element_types {
+ DIP_IE_NOP = 0,
+ DIP_IE_SRC_IPV4,
+ DIP_IE_DST_IPV4,
+ DIP_IE_SRC_PORT,
+ DIP_IE_DST_PORT,
+ DIP_IE_PROTO,
+ DIP_IE_SRC_IPV6,
+ DIP_IE_DST_IPV6,
+ DIP_IE_IPV4_TOS,
+ DIP_IE_IPV6_LABEL,
+ DIP_IE_CLASS_LABEL,
+ DIP_IE_MATCH_DIR,
+ DIP_IE_MSG_TYPE, /* Add or remove. */
+ DIP_IE_TIMEOUT_TYPE, /* Rule timeout vs flow timeout. */
+ DIP_IE_TIMEOUT, /* Timeout value. */
+ DIP_IE_ACTION_FLAGS, /* Bidir. */
+ DIP_IE_PCKT_CNT, /* Current number of packets. */
+ DIP_IE_KBYTE_CNT, /* Current number of bytes. */
+ DIP_IE_ACTION, /* Type of action. */
+ DIP_IE_ACTION_PARAMS, /* Opaque, passed on to packet filter. */
+ DIP_IE_EXPORT_NAME, /* Name of export. */
+ DIP_IE_CLASSIFIER_NAME, /* Name of classifier. */
+ DIP_IE_CLASSES /* Classifier names/classes. */
+};
+
+#define DI_IS_FIXED_LEN(x) (((x) & 0xC000) == 0x0)
+#define DI_IS_VARIABLE_LEN(x) (((x) & 0xC000) == 0x8000)
+#define DI_IS_DYNAMIC_LEN(x) (((x) & 0xC000) == 0xC000)
+
+struct dip_info_element {
+ uint16_t idx;
+ uint16_t id;
+ int16_t len;
+};
+
+struct dip_info_descr {
+ uint16_t idx;
+ uint16_t id;
+ int16_t len; /* Length in bytes, 0/-1 = var/dynamic length. */
+ char *name;
+};
+
+struct dip_header {
+ uint16_t version;
+ uint16_t msg_len;
+ uint32_t seq_no;
+ uint32_t time;
+};
+
+struct dip_set_header {
+ uint16_t set_id;
+ uint16_t set_len;
+};
+
+struct dip_templ_header {
+ uint16_t templ_id;
+ uint16_t flags;
+};
+
+#if defined(WITH_DIP_INFO)
+static struct dip_info_descr dip_info[] = {
+ {DIP_IE_NOP, 0, 0, "NOP"},
+ {DIP_IE_SRC_IPV4, 1, 4, "SrcIP"},
+ {DIP_IE_DST_IPV4, 2, 4, "DstIP"},
+ {DIP_IE_SRC_PORT, 3, 2, "SrcPort"},
+ {DIP_IE_DST_PORT, 4, 2, "DstPort"},
+ {DIP_IE_PROTO, 5, 1, "Proto"},
+ {DIP_IE_SRC_IPV6, 6, 16, "SrcIP6"},
+ {DIP_IE_DST_IPV6, 7, 16, "DstIP6"},
+ {DIP_IE_IPV4_TOS, 8, 1, "ToS"},
+ {DIP_IE_IPV6_LABEL, 9, 3, "IP6Label"},
+ {DIP_IE_CLASS_LABEL, 10, 2, "Class"},
+ {DIP_IE_MATCH_DIR, 11, 1, "MatchDir"},
+ {DIP_IE_MSG_TYPE, 12, 1, "MsgType"},
+ {DIP_IE_TIMEOUT_TYPE, 13, 1, "TimeoutType"},
+ {DIP_IE_TIMEOUT, 14, 2, "TimeoutValue"},
+ {DIP_IE_ACTION_FLAGS, 15, 2, "ActionFlags"},
+ {DIP_IE_PCKT_CNT, 16, 4, "Packets"},
+ {DIP_IE_KBYTE_CNT, 17, 4, "KBytes"},
+ {DIP_IE_ACTION, 32768, 0, "Action"},
+ {DIP_IE_ACTION_PARAMS, 32769, 0, "ActionParams"},
+ {DIP_IE_EXPORT_NAME, 32770, 0, "ExportName"},
+ {DIP_IE_CLASSIFIER_NAME, 32771, 0, "ClassName"},
+ {DIP_IE_CLASSES, 49152, -1, "ClassNames"},
+ {DIP_IE_NOP, 0, 0, "Unknown"}
+};
+#endif
+
+#endif /* _NETINET_IP_DIFFUSE_EXPORT_H_ */
Added: projects/diffused_head/sys/netinet/ipfw/diffuse_classifier.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/diffused_head/sys/netinet/ipfw/diffuse_classifier.h Sat Oct 8 03:58:20 2011 (r226126)
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2010-2011
+ * Swinburne University of Technology, Melbourne, Australia.
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University of Technology, by Sebastian Zander, made
+ * possible in part by a gift from The Cisco University Research Program Fund, a
+ * corporate advised fund of Silicon Valley Community Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NETINET_IPFW_DIFFUSE_CLASSIFIER_H_
+#define _NETINET_IPFW_DIFFUSE_CLASSIFIER_H_
+
+struct di_cdata;
+struct di_fdata;
+
+/*
+ * Descriptor for a classifier. Contains all function pointers for a given
+ * classifier. This is typically created when a module is loaded, and stored in
+ * a global list of classifiers.
+ */
+struct di_classifier_alg {
+ const char *name; /* Classifier name. */
+ volatile int ref_count; /* Number of instances in the system. */
+
+ /*
+ * Init instance.
+ * param1: pointer to instance config
+ * param2: config from userspace
+ * return: non-zero on error
+ */
+ int (*init_instance)(struct di_cdata *, struct di_oid *);
+
+ /*
+ * Destroy instance.
+ * param1: pointer to instance config
+ * return: non-zero on error
+ */
+ int (*destroy_instance)(struct di_cdata *);
+
+ /*
+ * Classify packet (sub flow).
+ * param1: pointer to instance config
+ * param2: pointer to features
+ * param3: number of features
+ * return: class
+ */
+ int (*classify)(struct di_cdata *, int32_t *, int);
+
+ /*
+ * Get configuration data.
+ * param1: pointer to instance config
+ * param2: pointer to configuration
+ * param3: only compute size (if 1)
+ * return: number of stats
+ */
+ int (*get_conf)(struct di_cdata *, struct di_oid *, int);
+
+ /*
+ * Get number of features needed.
+ * param1: pointer to instance config
+ * return: number of features
+ */
+ int (*get_feature_cnt)(struct di_cdata *);
+
+ /*
+ * Get number of classes.
+ * param1: pointer to instance config
+ * return: number of classes
+ */
+ int (*get_class_cnt)(struct di_cdata *);
+
+ SLIST_ENTRY(di_classifier_alg) next; /* Next in the list. */
+};
+
+#endif /* _NETINET_IPFW_DIFFUSE_CLASSIFIER_H_ */
Added: projects/diffused_head/sys/netinet/ipfw/diffuse_classifier_module.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/diffused_head/sys/netinet/ipfw/diffuse_classifier_module.h Sat Oct 8 03:58:20 2011 (r226126)
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2010-2011
+ * Swinburne University of Technology, Melbourne, Australia.
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University of Technology, by Sebastian Zander, made
+ * possible in part by a gift from The Cisco University Research Program Fund, a
+ * corporate advised fund of Silicon Valley Community Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NETINET_IPFW_DIFFUSE_CLASSIFIER_MODULE_H_
+#define _NETINET_IPFW_DIFFUSE_CLASSIFIER_MODULE_H_
+
+#define DECLARE_DIFFUSE_CLASSIFIER_MODULE(cname, cstruct) \
+ static moduledata_t di_classifier_##cname = { \
+ .name = #cname, \
+ .evhand = diffuse_classifier_modevent, \
+ .priv = cstruct \
+ }; \
+ DECLARE_MODULE(cname, di_classifier_##cname, \
+ SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); \
+ MODULE_DEPEND(cname, diffuse, 1, 1, 1)
+
+int diffuse_classifier_modevent(module_t mod, int cmd, void *arg);
+
+#endif /* _NETINET_IPFW_DIFFUSE_CLASSIFIER_MODULE_H_ */
Added: projects/diffused_head/sys/netinet/ipfw/diffuse_export.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/diffused_head/sys/netinet/ipfw/diffuse_export.c Sat Oct 8 03:58:20 2011 (r226126)
@@ -0,0 +1,750 @@
+/*-
+ * Copyright (c) 2010-2011
+ * Swinburne University of Technology, Melbourne, Australia.
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University of Technology, by Sebastian Zander, made
+ * possible in part by a gift from The Cisco University Research Program Fund, a
+ * corporate advised fund of Silicon Valley Community Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Functions to manage the export protocol.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(KLD_MODULE)
+#include "opt_ipfw.h"
+#include "opt_inet.h"
+#ifndef INET
+#error DIFFUSE requires INET.
+#endif /* INET */
+#endif
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_fw.h>
+#include <netinet/ip_diffuse.h>
+#define WITH_DIP_INFO 1
+#include <netinet/ip_diffuse_export.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+
+#include <netinet/ipfw/diffuse_common.h>
+#include <netinet/ipfw/diffuse_private.h>
+
+static VNET_DEFINE(uint32_t, ex_max_qsize);
+#define V_ex_max_qsize VNET(ex_max_qsize)
+
+static uma_zone_t di_rec_zone;
+
+#ifndef __FreeBSD__
+DEFINE_SPINLOCK(di_er_mtx);
+#else
+static struct mtx di_er_mtx; /* Mutex guarding dynamic rules. */
+#endif
+
+#define DI_ER_LOCK() mtx_lock(&di_er_mtx)
+#define DI_ER_UNLOCK() mtx_unlock(&di_er_mtx)
+#define DI_ER_LOCK_ASSERT() mtx_assert(&di_er_mtx, MA_OWNED)
+#define DI_ER_LOCK_DESTROY() mtx_destroy(&di_er_mtx)
+#define DI_ER_LOCK_INIT() mtx_init(&di_er_mtx, \
+ "DIFFUSE export record list", NULL, MTX_DEF)
+
+uint16_t def_template[15] = {
+ DIP_IE_EXPORT_NAME,
+ DIP_IE_MSG_TYPE,
+ DIP_IE_SRC_IPV4,
+ DIP_IE_DST_IPV4,
+ DIP_IE_SRC_PORT,
+ DIP_IE_DST_PORT,
+ DIP_IE_PROTO,
+ DIP_IE_PCKT_CNT,
+ DIP_IE_KBYTE_CNT,
+ DIP_IE_CLASSES,
+ DIP_IE_TIMEOUT_TYPE,
+ DIP_IE_TIMEOUT,
+ DIP_IE_ACTION,
+ DIP_IE_ACTION_FLAGS,
+ DIP_IE_ACTION_PARAMS
+};
+
+#define N_TEMPLATE_ITEMS (sizeof(def_template) / sizeof(*def_template))
+
+/*
+ * Length of the fixed size, per-packet header on outgoing flow rule template
+ * based export packets.
+ * The packet header consists of the following parts (in order):
+ * - struct dip_header
+ * - struct dip_set_header
+ * - struct dip_templ_header
+ * - A uint16_t ID field for each information element (IE)
+ * - A uint16_t length field for variable length IEs (there are currently 4)
+ */
+#define DIP_FIXED_HDR_LEN (sizeof(struct dip_header) + \
+ sizeof(struct dip_set_header) + sizeof(struct dip_templ_header) + \
+ (N_TEMPLATE_ITEMS * sizeof(uint16_t)) + 4 * sizeof(uint16_t))
+
+/* Size for one data set. */
+static int def_data_size;
+
+/* Offset into mhead where the data set header starts. */
+static int def_data_shdr_offs;
+
+/* Template for packet header. */
+static struct mbuf *mhead;
+
+#ifdef SYSCTL_NODE
+SYSBEGIN(xxx)
+SYSCTL_DECL(_net_inet_ip_diffuse);
+SYSCTL_VNET_UINT(_net_inet_ip_diffuse, OID_AUTO, ex_max_qsize, CTLFLAG_RW,
+ &VNET_NAME(ex_max_qsize), 0, "Max export record queue size");
+SYSEND
+#endif /* SYSCTL_NODE */
+
+/* Compute static size of one data set according to template. */
+static int
+_get_data_size(void)
+{
+ int i, n, size;
+
+ size = 0;
+
+ for (i = 0; i < N_TEMPLATE_ITEMS; i++) {
+ n = dip_info[def_template[i]].len;
+ if (n > 0)
+ size += n;
+ else if (n == 0) {
+ if (def_template[i] == DIP_IE_ACTION ||
+ def_template[i] == DIP_IE_EXPORT_NAME ||
+ def_template[i] == DIP_IE_CLASSIFIER_NAME) {
+ size += DI_MAX_NAME_STR_LEN;
+ } else if (def_template[i] == DIP_IE_ACTION_PARAMS) {
+ size += DI_MAX_PARAM_STR_LEN;
+ }
+ }
+ /* Do not count dynamic length fields here. */
+ }
+
+ return (size);
+}
+
+/* Compute dynamic size of record r. */
+static int
+get_data_size(struct di_export_rec *r)
+{
+ int i, l, slen;
+
+ l = 0;
+
+ for (i = 0; i < r->tcnt; i++) {
+ slen = strlen(r->class_tags[i].cname);
+ /* String, null, class. */
+ l += slen + 1 + dip_info[DIP_IE_CLASS_LABEL].len;
+ }
+ l++; /* Field length byte. */
+
+ return (def_data_size + l);
+}
+
+static inline uint32_t
+tv_sub0_ms(struct timeval *num, struct timeval *sub)
+{
+ struct timeval rv;
+
+ rv = tv_sub0(num, sub);
+
+ return (tvtoms(&rv));
+}
+
+static void
+remove_rec(struct di_export_rec *r)
+{
+
+ DI_ER_LOCK_ASSERT();
+
+ TAILQ_REMOVE(&di_conf.export_rec_list, r, next);
+ uma_zfree(di_rec_zone, r);
+ di_conf.export_rec_count--;
+}
+
+struct di_export_rec *
+diffuse_export_add_rec(struct di_ft_entry *q, struct di_export *ex,
+ int add_command)
+{
+ struct di_export_rec *r, *s;
+ struct di_flow_class *c;
+ int have_entry;
+
+ r = NULL;
+ have_entry = 0;
+
+ /* We don't handle exporting v6 flow records yet. */
+ if (q->id.addr_type == 6)
+ return (NULL);
+
+ DI_ER_LOCK();
+
+ /* Update and export entry if we have one for this flow already. */
+ TAILQ_FOREACH(s, &di_conf.export_rec_list, next) {
+ /*
+ * Only compare pointer for speed. If new flow with same 5-tuple
+ * we may add another record for same 5-tuple
+ */
+ if (s->ft_rec == q) {
+ have_entry = 1;
+ r = s;
+ break;
+ }
+ }
+
+ if (!have_entry) {
+ r = uma_zalloc(di_rec_zone, M_NOWAIT | M_ZERO);
+ if (r == NULL) {
+ DI_ER_UNLOCK();
+ return (NULL);
+ }
+ strcpy(r->ename, ex->name);
+ r->ft_rec = q;
+ }
+
+ getmicrotime(&r->time);
+ r->id = q->id;
+ r->fcnt = q->fcnt;
+ r->ftype = q->ftype;
+ r->mtype = add_command ? DIP_MSG_ADD : DIP_MSG_REMOVE;
+ r->ttype = di_conf.an_rule_removal;
+ r->pcnt = q->pcnt;
+ /*
+ * The flow byte count we send across the wire is in KBytes
+ * (see DIP_IE_KBYTE_CNT in <sys/netinet/ip_diffuse_export.h>).
+ */
+ r->bcnt = q->bcnt / 1000;
+ if (add_command) {
+ r->tval = (uint16_t) (q->expire > time_uptime) ?
+ q->expire - time_uptime : 0;
+ r->tval++; /* Make it slightly larger. */
+ } else {
+ r->tval = 0;
+ }
+
+ /* Class tags (only confirmed!). */
+ r->tcnt = 0;
+ SLIST_FOREACH(c, &q->flow_classes, next) {
+ if (r->tcnt >= DI_MAX_CLASSES)
+ break;
+
+ if (c->confirm >= ex->conf.confirm) {
+ strcpy(r->class_tags[r->tcnt].cname, c->cname);
+ r->class_tags[r->tcnt].class = c->class;
+ r->tcnt++;
+ }
+ }
+
+ if (!have_entry) {
+ if (r->ftype & DI_FLOW_TYPE_BIDIRECTIONAL ||
+ ex->conf.atype & DI_ACTION_TYPE_BIDIRECTIONAL)
+ r->action_dir = DI_ACTION_TYPE_BIDIRECTIONAL;
+ else
+ r->action_dir = DI_ACTION_TYPE_UNIDIRECTIONAL;
+
+ strcpy(r->action, ex->conf.action);
+ strcpy(r->act_params, ex->conf.action_param);
+ TAILQ_INSERT_TAIL(&di_conf.export_rec_list, r, next);
+ di_conf.export_rec_count++;
+ r->no_earlier.tv_sec = r->no_earlier.tv_usec = 0;
+ }
+
+ DI_ER_UNLOCK();
+
+ return (r);
+}
+
+/* Limit total number of records. */
+void
+diffuse_export_prune_recs(void)
+{
+ struct di_export_rec *r;
+
+ DI_ER_LOCK();
+
+ if (V_ex_max_qsize > 65535)
+ V_ex_max_qsize = 65535;
+
+ if (V_ex_max_qsize < 0)
+ V_ex_max_qsize = 0;
+
+ while (di_conf.export_rec_count > V_ex_max_qsize) {
+ r = TAILQ_FIRST(&di_conf.export_rec_list);
+ remove_rec(r);
+ }
+
+ DI_ER_UNLOCK();
+}
+
+int
+diffuse_export_remove_recs(char *ename)
+{
+ struct di_export_rec *r, *tmp;
+
+ DI_ER_LOCK();
+
+ TAILQ_FOREACH_SAFE(r, &di_conf.export_rec_list, next, tmp) {
+ if (ename == NULL || !strcmp(r->ename, ename))
+ remove_rec(r);
+ }
+
+ DI_ER_UNLOCK();
+
+ return (0);
+}
+
+/* Open and bind socket. */
+struct socket *
+diffuse_export_open(struct di_export_config *conf)
+{
+ struct socket *sock;
+ struct thread *td;
+ int ret;
+
+ sock = NULL;
+ td = curthread;
+
+ if (mhead != NULL) {
+ /* Open UDP socket. */
+ ret = socreate(AF_INET, &sock, SOCK_DGRAM, IPPROTO_UDP,
+ td->td_ucred, td);
+ if (ret)
+ DID("socket create error %d", ret);
+ }
+
+ return (sock);
+}
+
+/*
+ * Prepare the packet header for later use. Every packet contains one rule spec
+ * template followed by data.
+ */
+static void
+prepare_header(void)
+{
+#define SET_ID_OPTS_TPL 0
+#define SET_ID_FLOWRULE_TPL 1
+#define SET_ID_DATA 256
+
+ struct dip_header *hdr;
+ struct dip_set_header *shdr;
+ struct dip_templ_header *thdr;
+ int i, offs;
+ char *buf;
+
+ /*
+ * Ensures we will be able to shoehorn the entire fixed length header
+ * into a single mbuf.
+ */
+ CTASSERT(MHLEN >= DIP_FIXED_HDR_LEN);
+
+ offs = 0;
+
+ mhead = m_gethdr(M_WAITOK, MT_DATA);
+ mhead->m_next = NULL;
+ buf = mtod(mhead, char *);
+ hdr = (struct dip_header *)buf;
+ hdr->version = htons((uint16_t)DIP_VERSION);
+ hdr->msg_len = 0;
+ hdr->seq_no = 0;
+ hdr->time = 0;
+ offs += sizeof(struct dip_header);
+
+ shdr = (struct dip_set_header *)(buf + offs);
+ shdr->set_id = htons((uint16_t)SET_ID_FLOWRULE_TPL);
+ shdr->set_len = 0;
+ offs += sizeof(struct dip_set_header);
+
+ thdr = (struct dip_templ_header *)(buf + offs);
+ thdr->templ_id = htons((uint16_t)SET_ID_DATA);
+ thdr->flags = 0;
+ offs += sizeof(struct dip_templ_header);
+
+ for (i = 0; i < N_TEMPLATE_ITEMS; i++) {
+ *((uint16_t *)(buf + offs)) =
+ htons(dip_info[def_template[i]].id);
+ offs += sizeof(uint16_t);
+ if (def_template[i] == DIP_IE_ACTION ||
+ def_template[i] == DIP_IE_EXPORT_NAME ||
+ def_template[i] == DIP_IE_CLASSIFIER_NAME) {
+ *((uint16_t *)(buf + offs)) =
+ htons((uint16_t)DI_MAX_NAME_STR_LEN);
+ offs += sizeof(uint16_t);
+ } else if (def_template[i] == DIP_IE_ACTION_PARAMS) {
+ *((uint16_t *)(buf + offs)) =
+ htons((uint16_t)DI_MAX_PARAM_STR_LEN);
+ offs += sizeof(uint16_t);
+ }
+ }
+
+ shdr->set_len = htons(offs - sizeof(struct dip_header));
+ def_data_shdr_offs = offs;
+ shdr = (struct dip_set_header *)(buf + offs);
+ shdr->set_id = htons((uint16_t)SET_ID_DATA);
+ shdr->set_len = htons(sizeof(struct dip_set_header));
+ offs += sizeof(struct dip_set_header);
+
+ hdr->msg_len = htons(offs);
+ mhead->m_len = offs;
+
+ m_fixhdr(mhead);
+ mhead->m_pkthdr.rcvif = NULL;
+}
+
+/*
+ * If r is not NULL we add data and possibly send if packet length reached.
+ * If r is NULL we just send packet if we have an mbuf.
+ */
+static void
+add_record(struct di_export *ex, struct di_export_rec *r,
+ struct timeval *tv, int dyn_rsize)
+{
+ struct dip_header *hdr;
+ struct dip_set_header *shdr;
+ struct di_export_config *conf;
+ struct mbuf *md;
+ char *buf;
+ int i, new_header, offs, slen;
+ unsigned char *lfield;
+
+ DI_ER_LOCK_ASSERT();
+
+ conf = &ex->conf;
+ new_header = offs = 0;
+
+ if (ex->mh == NULL) {
+ ex->mh = m_dup(mhead, MT_DATA);
+ ex->mh->m_next = NULL;
+ ex->mh->m_nextpkt = NULL;
+ ex->mt = ex->mh;
+ /* Make sure IPFW/DIFFUSE skips exporter packets. */
+ ex->mh->m_flags |= M_SKIP_FIREWALL;
+ new_header = 1;
+ }
+
+ /* Update stuff in packet header. */
+ buf = mtod(ex->mh, char *);
+ hdr = (struct dip_header *)buf;
+ if (new_header)
+ hdr->seq_no = htonl(ex->seq_no++);
+
+ hdr->time = htonl(tv->tv_sec);
+ hdr->msg_len = htons(ntohs(hdr->msg_len) + dyn_rsize);
+
+ /* Update stuff in data set header. */
+ shdr = (struct dip_set_header *)(buf + def_data_shdr_offs);
+ shdr->set_len = htons(ntohs(shdr->set_len) + dyn_rsize);
+
+ /* Find space for data, add new mbuf if required. */
+ if (ex->mt == ex->mh || (MLEN - ex->mt->m_len) < dyn_rsize) {
+ /* Add new mbuf to chain. */
+ md = m_get(M_NOWAIT, MT_DATA);
+ if (!md)
+ return;
+ md->m_next = NULL;
+ ex->mt->m_next = md;
+ ex->mt = md;
+ }
+
+ buf = mtod(ex->mt, char *);
+ offs = ex->mt->m_len;
+
+ /* Fill in data. */
+ /* XXX: Create function with a switch for all IEs. */
+ memcpy((char *)(buf + offs), r->ename, DI_MAX_NAME_STR_LEN);
+ offs += DI_MAX_NAME_STR_LEN;
+ *((uint8_t *)(buf + offs)) = r->mtype;
+ offs += sizeof(uint8_t);
+ *((uint32_t *)(buf + offs)) = htonl(r->id.src_ip);
+ offs += sizeof(uint32_t);
+ *((uint32_t *)(buf + offs)) = htonl(r->id.dst_ip);
+ offs += sizeof(uint32_t);
+ *((uint16_t *)(buf + offs)) = htons(r->id.src_port);
+ offs += sizeof(uint16_t);
+ *((uint16_t *)(buf + offs)) = htons(r->id.dst_port);
+ offs += sizeof(uint16_t);
+ *((uint8_t *)(buf + offs)) = r->id.proto;
+ offs += sizeof(uint8_t);
+ *((uint32_t *)(buf + offs)) = htonl(r->pcnt);
+ offs += sizeof(uint32_t);
+ *((uint32_t *)(buf + offs)) = htonl(r->bcnt);
+ offs += sizeof(uint32_t);
+
+ lfield = buf + offs;
+ offs++;
+ *lfield = 1;
+ /*
+ * tcnt will be <= DI_MAX_CLASSES which is set so that lfield will
+ * never overflow.
+ */
+ for (i = 0; i < r->tcnt; i++) {
+ slen = strlen(r->class_tags[i].cname);
+ memcpy((char *)(buf + offs), r->class_tags[i].cname, slen + 1);
+ offs += slen + 1;
+ *((uint16_t *)(buf + offs)) = htons(r->class_tags[i].class);
+ offs += sizeof(uint16_t);
+ KASSERT((*lfield + slen + 1 + sizeof(uint16_t) <
+ (1 << sizeof(*lfield))), ("%s: lfield overflowed",
+ __func__));
+ *lfield += slen + 1 + sizeof(uint16_t);
+ }
+ *((uint8_t *)(buf + offs)) = r->ttype;
+ offs += sizeof(uint8_t);
+ *((uint16_t *)(buf + offs)) = htons(r->tval);
+ offs += sizeof(uint16_t);
+ memcpy((char *)(buf + offs), r->action, DI_MAX_NAME_STR_LEN);
+ offs += DI_MAX_NAME_STR_LEN;
+ *((uint16_t *)(buf + offs)) = htons((uint16_t)r->action_dir);
+ offs += sizeof(uint16_t);
+ memcpy((char *)(buf + offs), r->act_params, DI_MAX_PARAM_STR_LEN);
+ offs += DI_MAX_PARAM_STR_LEN;
+
+ ex->mt->m_len = offs;
+
+ /* Fix chain header, e.g. adjust chain length. */
+ m_fixhdr(ex->mh);
+ ex->mh->m_pkthdr.rcvif = NULL;
+}
+
+static inline int
+queue_tx_pkt_if(struct di_export *ex, int dyn_rsize, struct timeval *tv,
+ struct mbuf **tx_pkt_queue, int force)
+{
+ struct route sro;
+ struct sockaddr_in *dst;
+ unsigned long mtu;
+ int ready_to_send;
+
+ DI_ER_LOCK_ASSERT();
+
+ ready_to_send = 0;
+ mtu = DIP_DEFAULT_MTU;
+
+ bzero(&sro, sizeof(sro));
+ dst = (struct sockaddr_in *)&sro.ro_dst;
+ dst->sin_family = AF_INET;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_addr = ex->conf.ip;
+ in_rtalloc_ign(&sro, 0, ex->sock->so_fibnum);
+
+ if (sro.ro_rt != NULL) {
+ if (sro.ro_rt->rt_rmx.rmx_mtu == 0)
+ mtu = sro.ro_rt->rt_ifp->if_mtu;
+ else
+ mtu = min(sro.ro_rt->rt_rmx.rmx_mtu,
+ sro.ro_rt->rt_ifp->if_mtu);
+ RTFREE(sro.ro_rt);
+ }
+
+ /*
+ * If the export packet currently being constructed (chain headed by
+ * ex->mh) would be overfilled by adding a record of size dyn_rsize,
+ * move the chain to the tx_pkt_queue and set the ex chain headers to
+ * NULL so that add_record() will start a new chain.
+ */
+ if (force || (ex->mt->m_len + dyn_rsize) >=
+ (mtu - sizeof(struct ip) + sizeof(struct udphdr))) {
+ /* Add to queue. */
+ if (*tx_pkt_queue == NULL) {
+ *tx_pkt_queue = ex->mh;
+ } else {
+ while ((*tx_pkt_queue)->m_nextpkt != NULL)
+ tx_pkt_queue = &((*tx_pkt_queue)->m_nextpkt);
+
+ (*tx_pkt_queue)->m_nextpkt = ex->mh;
+ }
+
+ ex->mh = NULL;
+ ex->mt = NULL;
+ ex->last_pkt_time = *tv;
+ ready_to_send = 1;
+ }
+
+ return (ready_to_send);
+}
+
+int
+diffuse_export_send(struct di_export *ex)
+{
+ static int waiting = 0; /* Number of records waiting to be sent. */
+ struct thread *td;
+ struct di_export_rec *r, *tmp;
+ struct di_export_config *conf;
+ struct timeval tv;
+ /* Copies for sending outside lock. */
+ struct socket *sock;
+ struct sockaddr_in sin;
+ struct mbuf *next_tx_pkt, *tx_pkt_queue;
+ int cnt, dyn_rsize, ret;
+
+ td = curthread;
+ sock = NULL;
+ tx_pkt_queue = NULL;
+ conf = &ex->conf;
+ cnt = waiting; /* Number of records processed */
+
+ DI_ER_LOCK();
+
+ if (di_conf.export_rec_count == 0 ||
+ waiting + di_conf.export_rec_count < conf->min_batch) {
+ DI_ER_UNLOCK();
+ return (0);
+ }
+
+ getmicrotime(&tv);
+
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list