Date: Sat, 8 Oct 2011 03:58:20 +0000 (UTC) From: Lawrence Stewart <lstewart@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r226126 - in projects/diffused_head/sys: modules modules/diffuse modules/diffuse/diffuse netinet netinet/ipfw sys Message-ID: <201110080358.p983wK5b041188@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201110080358.p983wK5b041188>