PERFORCE change 164713 for review

Tatsiana Elavaya tsel at FreeBSD.org
Fri Jun 19 16:39:56 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=164713

Change 164713 by tsel at tsel_mz on 2009/06/19 16:39:02

	Dynamicly allocate optimization buffers
	Use sysctl to control optimization parameters
	Add extra debugging to check optmization correctness
	Handle F_NOT and F_OR instructions correctly
	Rule alias related fixes

Affected files ...

.. //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/Makefile#2 edit
.. //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/ipfw.8#2 edit
.. //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/ipfw2.c#6 edit
.. //depot/projects/soc2009/tsel_ipfw/sys/modules/ipfw/Makefile#2 edit
.. //depot/projects/soc2009/tsel_ipfw/sys/netinet/ip_fw.h#4 edit
.. //depot/projects/soc2009/tsel_ipfw/sys/netinet/ip_fw2.c#3 edit

Differences ...

==== //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/Makefile#2 (text+ko) ====

@@ -4,5 +4,6 @@
 SRCS=	ipfw2.c dummynet.c ipv6.c main.c nat.c altq.c
 WARNS?=	2
 MAN=	ipfw.8
+DEBUG_FLAGS+= -g
 
 .include <bsd.prog.mk>

==== //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/ipfw.8#2 (text+ko) ====

@@ -28,10 +28,10 @@
 .Op Ar number ...
 .Nm
 .Cm enable
-.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive
+.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive | optimization
 .Nm
 .Cm disable
-.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive
+.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive | optimization
 .Pp
 .Nm
 .Cm set Oo Cm disable Ar number ... Oc Op Cm enable Ar number ...
@@ -2580,6 +2580,11 @@
 Enables the firewall.
 Setting this variable to 0 lets you run your machine without
 firewall even if compiled in.
+.It Va net.inet.ip.fw.optimization_enable : No 1
+Enables the rule processing optimization.
+Optimization should also be enabled for a ruleset by
+.Nm ipfw optimimize
+command.
 .It Va net.inet6.ip6.fw.enable : No 1
 provides the same functionality as above for the IPv6 case.
 .It Va net.inet.ip.fw.one_pass : No 1

==== //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/ipfw2.c#6 (text+ko) ====

@@ -475,7 +475,7 @@
 {
 	static struct ip_fw *raw_rules = NULL;
 	static struct ip_fw **rules = NULL;
-	static rules_len = 0;
+	static int rules_len = 0;
 	int i, sz;
 
 	if (raw_rules == NULL || rules == NULL) {
@@ -1824,6 +1824,9 @@
 		    &which, sizeof(which));
 	} else if (_substrcmp(*av, "altq") == 0) {
 		altq_set_enabled(which);
+	} else if (_substrcmp(*av, "optimization") == 0) {
+		sysctlbyname("net.inet.ip.fw.optimization_enable", NULL, 0,
+		    &which, sizeof(which));
 	} else {
 		warnx("unrecognize enable/disable keyword: %s\n", *av);
 	}
@@ -1870,7 +1873,7 @@
 		for (r = data; r->rulenum < IPFW_DEFAULT_RULE; r = NEXT(r)) {
 			alias = get_rule_alias(r);
 			if (alias)
-				printf("%-5d %s\n", r, alias);
+				printf("%-5d %s\n", r->rulenum, alias);
 		}
 		ac--; av++;
 		goto done;
@@ -1966,9 +1969,15 @@
 		if (*endptr == '-')
 			last = strtoul(endptr+1, &endptr, 10);
 		if (*endptr) {
-			exitval = EX_USAGE;
-			warnx("invalid rule number: %s", *(lav - 1));
-			continue;
+			int alias_rulenum = alias_lookup_rulenum(*(lav - 1));
+
+			if (alias_rulenum > 0) {
+				last = rnum = alias_rulenum;
+			} else {
+				exitval = EX_USAGE;
+				warnx("invalid rule number: %s", *(lav - 1));
+				continue;
+			}
 		}
 		for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) {
 			if (r->rulenum > last)
@@ -2051,8 +2060,8 @@
 int
 insn_eq(ipfw_insn *a, ipfw_insn *b)
 {
-	if (a->opcode != b->opcode)
-		return (0);
+	if (F_LEN(a) != F_LEN(b) || a->arg1 != b->arg1 || a->opcode != b->opcode)
+		return 0;
 	switch (a->opcode) {
 	case O_IP_SRC:
 	case O_IP_SRC_MASK:
@@ -2110,13 +2119,13 @@
 	case O_IP4:
 		break;
 	default:
-		return(0);
+		return 0;
 	}
-	if (F_LEN(a) != F_LEN(b))
-		return(0);
-	if (memcmp(a, b, F_LEN(a) * 4) == 0)
-		return(1);
-	return(0);
+	if (F_LEN(a) == 1)
+		return 1;
+	if (memcmp(a, b, (F_LEN(a) - 1)* 4) == 0)
+		return 1;
+	return 0;
 }
 
 int
@@ -2137,7 +2146,7 @@
 			new_m->group = g;
 			LIST_INSERT_HEAD(&g->match_head, new_m, match_entries);
 			g->match_count++;
-			return(1);
+			return 1;
 		}
 	}
 
@@ -2147,7 +2156,7 @@
 	LIST_INSERT_HEAD(group_head, g, group_entries);
 	(*group_count)++;
 
-	return(0);
+	return 0;
 }
 
 void
@@ -2169,7 +2178,7 @@
 	int i;
 
 	if (a[0] == NULL)
-		return (a[1] == NULL ? 0 : 1);
+		return a[1] == NULL ? 0 : 1;
 	if (a[1] == NULL)
 		return -1;
 	for (i = 0; i < 2; i++) {
@@ -2197,6 +2206,25 @@
 
 }
 
+static void
+optimization_setup(int enable, int labels)
+{
+	if (enable) {
+		labels = (labels + 7)/8;
+		if (sysctlbyname("net.inet.ip.fw.optimization_buf",
+					NULL, 0, &labels, sizeof(labels)) == -1) {
+			errx(EX_DATAERR, "optimization not supported");
+		}
+	}
+
+	if (sysctlbyname("net.inet.ip.fw.optimization_enable",
+				NULL, 0, &enable, sizeof(enable)) == -1) {
+		errx(EX_DATAERR, "optimization not supported");
+	}
+	
+
+}
+
 void
 ipfw_optimize(int argc, char **argv)
 {
@@ -2205,7 +2233,7 @@
 	struct insn_match_rule *match_rules;
 	struct ip_fw **rules;
 	struct ip_fw *orule;
-	int c, i, group_count, rules_count;
+	int c, i, group_count, rules_count, labels_max;
 
 	if (co.test_only) {
 		fprintf(stderr, "Testing only, optimization disabled\n");
@@ -2254,8 +2282,15 @@
 		}
 	}
 
+	i = sizeof(labels_max);
+	if (sysctlbyname("net.inet.ip.fw.optimization_buf_max",
+				&labels_max, &i, NULL, 0) == -1) {
+		errx(EX_DATAERR, "optimization not supported");
+	}
+	labels_max *= 8;
+
 	qsort(groups_sort, group_count, sizeof(void*), insn_match_group_cmp);
-	for (i = 0; i < group_count && i < IPFW_OPTIMIZE_LABEL_MAX && groups_sort[i]->rank; i++) {
+	for (i = 0; i < group_count && i < labels_max && groups_sort[i]->rank; i++) {
 		struct insn_match *m = LIST_FIRST(&groups_sort[i]->match_head);
 		groups_sort[i]->label = i;
 		printf("sorted: %d; opcode %d; match_count %d; rank %d\n", 
@@ -2270,6 +2305,8 @@
 	}
 	group_count = c;
 
+	optimization_setup(0, 0);
+
 	orule = (struct ip_fw*)safe_calloc(1, sizeof(struct ip_fw) + 255*4);
 	for (i = 0; rules[i]; i++) {
 		struct insn_match *m, *m_tmp;
@@ -2311,6 +2348,8 @@
 				show_ipfw(orule, 0, 0);
 		}
 	}
+
+	optimization_setup(1, group_count);
 }
 
 static int
@@ -2320,10 +2359,10 @@
 
 	if (!inet_aton(host, ipaddr)) {
 		if ((he = gethostbyname(host)) == NULL)
-			return(-1);
+			return -1;
 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
 	}
-	return(0);
+	return 0;
 }
 
 /*
@@ -3017,6 +3056,9 @@
 		ipfw_insn_alias *alias_cmd = (ipfw_insn_alias *) action;
 
 		NEED1("missing alias name");
+		for (i = 0; isdigit(av[1][i]) || av[1][i] == '+' || av[1][i] == '-'; i++) { ; }
+		if (av[1][i] == '\0' || strpbrk(av[1], " \t\n\r") != NULL || strcmp(av[1], "alias") == 0)
+			errx(EX_DATAERR, "invalid alias '%s'", av[1]);
 		alias_rule = alias_lookup_rulenum(av[1]);
 		if (alias_rule > 0)
 			errx(EX_DATAERR, "rule %d already has alias %s", alias_rule, av[1]);
@@ -4026,12 +4068,18 @@
 	}
 
 	while (ac) {
+		int alias_rulenum = alias_lookup_rulenum(*av);
+
 		/* Rule number */
-		if (isdigit(**av)) {
-			arg = strtonum(*av, 0, 0xffff, &errstr);
-			if (errstr)
-				errx(EX_DATAERR,
-				    "invalid rule number %s\n", *av);
+		if (alias_rulenum > 0 || isdigit(**av) ) {
+			if (alias_rulenum < 0) {
+				arg = strtonum(*av, 0, 0xffff, &errstr);
+				if (errstr)
+					errx(EX_DATAERR,
+					    "invalid rule number %s\n", *av);
+			} else {
+				arg = alias_rulenum;
+			}
 			saved_arg = arg;
 			if (co.use_set)
 				arg |= (1 << 24) | ((co.use_set - 1) << 16);

==== //depot/projects/soc2009/tsel_ipfw/sys/modules/ipfw/Makefile#2 (text+ko) ====

@@ -26,4 +26,6 @@
 .endif
 .endif
 
+DEBUG_FLAGS+= -DIPFW_OPTIMIZE_DEBUG
+
 .include <bsd.kmod.mk>

==== //depot/projects/soc2009/tsel_ipfw/sys/netinet/ip_fw.h#4 (text+ko) ====

@@ -42,8 +42,6 @@
  */
 #define	IPFW_TABLES_MAX		128
 
-#define	IPFW_OPTIMIZE_LABEL_MAX		128
-
 /*
  * The kernel representation of ipfw rules is made of a list of
  * 'instructions' (for all practical purposes equivalent to BPF
@@ -731,6 +729,10 @@
 	u_int64_t		_norule_counter;
 	struct callout		_ipfw_timeout;
 	struct eventhandler_entry *_ifaddr_event_tag;
+	int			_optimization_enable;
+	int			_optimization_buf_sz;
+	volatile uint32_t	_optimization_buf_use;
+	uint32_t		**_optimization_bufs;
 };
 
 #ifndef VIMAGE
@@ -775,6 +777,10 @@
 #define	V_norule_counter	VNET_IPFW(norule_counter)
 #define	V_ipfw_timeout		VNET_IPFW(ipfw_timeout)
 #define	V_ifaddr_event_tag	VNET_IPFW(ifaddr_event_tag)
+#define	V_optimization_enable	VNET_IPFW(optimization_enable)
+#define	V_optimization_buf_sz	VNET_IPFW(optimization_buf_sz)
+#define	V_optimization_buf_use	VNET_IPFW(optimization_buf_use)
+#define	V_optimization_bufs	VNET_IPFW(optimization_bufs)
 
 #endif /* _KERNEL */
 #endif /* _IPFW2_H */

==== //depot/projects/soc2009/tsel_ipfw/sys/netinet/ip_fw2.c#3 (text+ko) ====

@@ -171,9 +171,18 @@
 
 #ifdef VIMAGE_GLOBALS
 static int autoinc_step;
+static int optimization_enable;
+static int optimization_buf_sz;
+static volatile uint32_t optimization_buf_use;
+static uint32_t *optimization_bufs;
 #endif
 
 extern int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
+static int ipfw_optimization_buf_hook(SYSCTL_HANDLER_ARGS);
+
+#define OPTIMIZATION_POOLS		4
+#define OPTIMIZATION_BUF_MAX		PAGE_SIZE
+#define OPTIMIZATION_BUF_INITIAL	32
 
 #ifdef SYSCTL_NODE
 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
@@ -197,6 +206,15 @@
     NULL, IPFW_TABLES_MAX, "The maximum number of tables.");
 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
     &default_to_accept, 0, "Make the default rule accept all packets.");
+SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, optimization_enable,
+    CTLFLAG_RW, optimization_enable, 1, "Enable rule processing optimization.");
+SYSCTL_V_PROC(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, optimization_buf,
+    CTLTYPE_INT | CTLFLAG_RW, optimization_buf_sz, 0,
+    ipfw_optimization_buf_hook, "I", "Optimization buffer size.");
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, optimization_buf_max,
+    CTLFLAG_RD, NULL, OPTIMIZATION_BUF_MAX, "Maximum optimization buffer size.");
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, optimization_pools,
+    CTLFLAG_RD, NULL, OPTIMIZATION_POOLS, "Number of preallocated buffers.");
 TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
 #endif /* SYSCTL_NODE */
 
@@ -323,6 +341,61 @@
 static int fw_deny_unknown_exthdrs;
 #endif
 
+static int
+ipfw_optimization_buf_hook(SYSCTL_HANDLER_ARGS)
+{
+	INIT_VNET_IPFW(curvnet);
+	uint32_t *bufs[OPTIMIZATION_POOLS];
+	uint32_t *buf;
+	int sz = *(int *)arg1;
+	int i, error;
+
+	error = sysctl_handle_int(oidp, &sz, 0, req);
+	if (error)
+		return error;
+
+	if (sz <= 0 || sz > OPTIMIZATION_BUF_MAX)
+		return EINVAL;
+
+	if (sz % 32)
+		sz += 32 - (sz % 32);
+	if (sz > OPTIMIZATION_BUF_MAX)
+		sz = OPTIMIZATION_BUF_MAX;
+
+	/* do not shrink buffers. ruleset may contain old o_optimize insn's */
+	if (sz <= *(int *)arg1)
+		return 0;
+
+	for (i = 0; i < OPTIMIZATION_POOLS; i++) {
+		bufs[i] = malloc(OPTIMIZATION_BUF_MAX, M_IPFW, M_WAITOK | M_ZERO);
+	}
+
+	IPFW_WLOCK(&V_layer3_chain);
+
+	KASSERT(V_optimization_buf_use == 0, ("Optimiation buffers still in use"));
+	if (V_optimization_buf_use != 0) {
+		/* DEBUG */
+		printf("!!!! optimization buffers still in use: %x\n", V_optimization_buf_use);
+		return EIO;
+	}
+	
+	for (i = 0; i < OPTIMIZATION_POOLS; i++) {
+		buf = V_optimization_bufs[i];
+		V_optimization_bufs[i] = bufs[i];
+		bufs[i] = buf;
+	}
+	
+	*(int *)arg1 = sz;
+	
+	IPFW_WUNLOCK(&V_layer3_chain);
+
+	for (i = 0; i < OPTIMIZATION_POOLS; i++) {
+		free(bufs[i], M_IPFW);
+	}
+
+	return 0;
+}
+
 /*
  * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
  * Other macros just cast void * into the appropriate type
@@ -2108,6 +2181,45 @@
 	return match;
 }
 
+static inline uint32_t*
+optimization_buf_ref(uint32_t *ind)
+{
+	int bit;
+	uint32_t use;
+	uint32_t *buf;
+
+	buf = NULL;
+	*ind = 0;
+	do {
+		use = atomic_load_acq_32(&V_optimization_buf_use);
+
+		bit = ffs(~use);
+		/* do not spin if there's no free buffer available */
+		if (bit == 0 || bit > OPTIMIZATION_POOLS)
+			break;
+		if (atomic_cmpset_32(&V_optimization_buf_use, use, use | (1 << (bit - 1)))) {
+			buf = V_optimization_bufs[(bit - 1)];
+			*ind = bit;
+		}
+	} while (buf == NULL);
+
+	return buf;
+}
+
+static inline void
+optimization_buf_rel(uint32_t *ind)
+{
+	uint32_t use, mask;
+
+	if (!*ind)
+		return;
+	mask = 1 << (*ind - 1);
+	do {
+		use = atomic_load_acq_32(&V_optimization_buf_use);
+	} while (atomic_cmpset_32(&V_optimization_buf_use, use, use | mask) == 0);
+	*ind = 0;
+}
+
 /*
  * The main check routine for the firewall.
  *
@@ -2266,9 +2378,10 @@
 	/* end of ipv6 variables */
 	int is_ipv4 = 0;
 
-#define GET_OPTIMIZE_LABEL(a) optimize_state[(a) / 32] & (1 << ((a) % 32))
-#define SET_OPTIMIZE_LABEL(a) optimize_state[(a) / 32] |= (1 << ((a) % 32))
-	uint32_t optimize_state[IPFW_OPTIMIZE_LABEL_MAX/32];
+#define GET_OPTIMIZ_LABEL(a) (optimiz_buf ? optimiz_buf[(a) / 32] & (1 << ((a) % 32)) : 0)
+#define SET_OPTIMIZ_LABEL(a) (optimiz_buf ? optimiz_buf[(a) / 32] |= (1 << ((a) % 32)) : 0)
+	uint32_t *optimiz_buf = NULL;
+	uint32_t optimiz_buf_ind = 0;
 
 	if (m->m_flags & M_SKIP_FIREWALL)
 		return (IP_FW_PASS);	/* accept */
@@ -2563,8 +2676,15 @@
 		m_tag_delete(m, mtag);
 	}
 
-	/* reset optimization state */
-	bzero(optimize_state, sizeof(optimize_state));
+	if (V_optimization_enable) {
+		/* get optimization buffer */
+		optimiz_buf = optimization_buf_ref(&optimiz_buf_ind);
+
+		/* reset optimization state */
+		if (optimiz_buf)
+			bzero(optimiz_buf, V_optimization_buf_sz);
+	}
+
 
 	/*
 	 * Now scan the rules, and parse microinstructions for each rule.
@@ -2573,7 +2693,10 @@
 		ipfw_insn *cmd;
 		uint32_t tablearg = 0;
 		int l, cmdlen, skip_or; /* skip rest of OR block */
-		int optimize_match = 0;
+		int optimiz_match = 0;
+#ifdef IPFW_OPTIMIZE_DEBUG
+		ipfw_insn_u32 *optimiz_cmd = NULL;
+#endif
 
 again:
 		if (V_set_disable & (1 << f->set) )
@@ -2606,11 +2729,24 @@
 			}
 			match = 0; /* set to 1 if we succeed */
 
-			if (optimize_match > 0) {
-				printf("IPFW: optimize %d %d\n", cmd->opcode, optimize_match - 1);
-				optimize_match = 0;
+			if (V_optimization_enable && optimiz_match > 0 && cmd->opcode != O_OPTIMIZE) {
+#ifdef IPFW_OPTIMIZE_DEBUG
+				if (optimiz_cmd->o.arg1 != cmd->opcode || 
+						optimiz_cmd->d[0] + 1 != optimiz_match) {
+					printf("ipfw: optimization error %d %d; expected %d %d\n", 
+							cmd->opcode, optimiz_match - 1, 
+							optimiz_cmd->o.arg1, optimiz_cmd->d[0] + 1);
+				}
+#else
+				printf("ipfw: optimized %d %d\n", cmd->opcode, optimiz_match - 1);
+				optimiz_match = 0;
 				match = !(cmd->len & F_NOT);
-			} else switch (cmd->opcode) {
+#endif
+			}
+#ifndef IPFW_OPTIMIZE_DEBUG
+			else
+#endif
+			switch (cmd->opcode) {
 			/*
 			 * The first set of opcodes compares the packet's
 			 * fields with some pattern, setting 'match' if a
@@ -3155,12 +3291,23 @@
 				break;
 			}
 			case O_OPTIMIZE: {
-				int label = ((ipfw_insn_u32 *)cmd)->d[0];
+				int label = ((ipfw_insn_u32 *) cmd)->d[0];
+
+				if (!V_optimization_enable || !optimiz_buf || 
+						label > V_optimization_buf_sz * 8)
+					continue;
 
-				if (GET_OPTIMIZE_LABEL(label))
-					optimize_match = label + 1;
+				if (optimiz_match) {
+					printf("ipfw: unexpected O_OPTIMIZE instruction. ignoring");
+					continue;
+				}
+#ifdef IPFW_OPTIMIZE_DEBUG
+				optimiz_cmd = (ipfw_insn_u32 *) cmd;
+#endif
+				if (GET_OPTIMIZ_LABEL(label))
+					optimiz_match = label + 1;
 				else
-					optimize_match = -(label + 1);
+					optimiz_match = -(label + 1);
 				continue;
 			}
 				
@@ -3280,6 +3427,7 @@
 				if (mtag == NULL) {
 					/* XXX statistic */
 					/* drop packet */
+					optimization_buf_rel(&optimiz_buf_ind);
 					IPFW_RUNLOCK(chain);
 					return (IP_FW_DENY);
 				}
@@ -3465,20 +3613,30 @@
 				panic("-- unknown opcode %d\n", cmd->opcode);
 			} /* end of switch() on opcodes */
 
+#ifdef IPFW_OPTIMIZE_DEBUG
+			if (optimiz_match > 0 && !match)
+				printf("ipfw: optimization error: cmd mismatch %d (optimiz_cmd=%d) %d\n", cmd->opcode, optimiz_cmd->o.arg1, optimiz_match);
+#endif
+			if (V_optimization_enable) {
+				if (match) {
+					if (optimiz_match < 0) {
+						optimiz_match = -optimiz_match - 1;
+						SET_OPTIMIZ_LABEL(optimiz_match);
+						printf("ipfw: set optimize match %d %d\n", cmd->opcode, optimiz_match);
+						optimiz_match = 0;
+					}
+				} else {
+					optimiz_match = 0;
+				}
+			}
+
 			if (cmd->len & F_NOT)
 				match = !match;
 
 			if (match) {
-				if (optimize_match < 0) {
-					optimize_match = -optimize_match - 1;
-					SET_OPTIMIZE_LABEL(optimize_match);
-					printf("IPFW: set optimize match %d %d\n", cmd->opcode, optimize_match);
-					optimize_match = 0;
-				}
 				if (cmd->len & F_OR)
 					skip_or = 1;
 			} else {
-				optimize_match = 0;
 				if (!(cmd->len & F_OR)) /* not an OR block, */
 					break;		/* try next rule    */
 			}
@@ -3489,6 +3647,7 @@
 
 	}		/* end of outer for, scan rules */
 	printf("ipfw: ouch!, skip past end of rules, denying packet\n");
+	optimization_buf_rel(&optimiz_buf_ind);
 	IPFW_RUNLOCK(chain);
 	return (IP_FW_DENY);
 
@@ -3497,6 +3656,7 @@
 	f->pcnt++;
 	f->bcnt += pktlen;
 	f->timestamp = time_uptime;
+	optimization_buf_rel(&optimiz_buf_ind);
 	IPFW_RUNLOCK(chain);
 	return (retval);
 
@@ -4634,7 +4794,7 @@
 {
 	INIT_VNET_IPFW(curvnet);
 	struct ip_fw default_rule;
-	int error;
+	int error, i;
 
 	V_autoinc_step = 100;	/* bounded to 1..1000 in add_rule() */
 
@@ -4657,6 +4817,13 @@
 
 	V_fw_deny_unknown_exthdrs = 1;
 
+	V_optimization_bufs = malloc(OPTIMIZATION_POOLS * sizeof(uint32_t *), M_IPFW, M_WAITOK);
+	V_optimization_buf_use = 0;
+	V_optimization_buf_sz = OPTIMIZATION_BUF_INITIAL;
+	for (i = 0; i < OPTIMIZATION_POOLS; i++) {
+		V_optimization_bufs[i] = malloc(V_optimization_buf_sz, M_IPFW, M_WAITOK | M_ZERO);
+	}
+
 #ifdef INET6
 	/* Setup IPv6 fw sysctl tree. */
 	sysctl_ctx_init(&ip6_fw_sysctl_ctx);
@@ -4759,6 +4926,7 @@
 {
 	INIT_VNET_IPFW(curvnet);
 	struct ip_fw *reap;
+	int i;
 
 	ip_fw_chk_ptr = NULL;
 	ip_fw_ctl_ptr = NULL;
@@ -4775,6 +4943,10 @@
 	uma_zdestroy(ipfw_dyn_rule_zone);
 	if (V_ipfw_dyn_v != NULL)
 		free(V_ipfw_dyn_v, M_IPFW);
+	for (i = 0; i < OPTIMIZATION_POOLS; i++)
+		free(V_optimization_bufs[i], M_IPFW);
+	free(V_optimization_bufs, M_IPFW);
+	V_optimization_buf_use = 0;
 	IPFW_LOCK_DESTROY(&V_layer3_chain);
 
 #ifdef INET6


More information about the p4-projects mailing list