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