From owner-p4-projects@FreeBSD.ORG Fri Jun 19 16:39:56 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 236071065673; Fri, 19 Jun 2009 16:39:56 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D70CE106564A for ; Fri, 19 Jun 2009 16:39:55 +0000 (UTC) (envelope-from tsel@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id BBAA28FC1D for ; Fri, 19 Jun 2009 16:39:55 +0000 (UTC) (envelope-from tsel@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n5JGdtb1058902 for ; Fri, 19 Jun 2009 16:39:55 GMT (envelope-from tsel@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n5JGdtPx058900 for perforce@freebsd.org; Fri, 19 Jun 2009 16:39:55 GMT (envelope-from tsel@FreeBSD.org) Date: Fri, 19 Jun 2009 16:39:55 GMT Message-Id: <200906191639.n5JGdtPx058900@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to tsel@FreeBSD.org using -f From: Tatsiana Elavaya To: Perforce Change Reviews Cc: Subject: PERFORCE change 164713 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Jun 2009 16:39:56 -0000 http://perforce.freebsd.org/chv.cgi?CH=164713 Change 164713 by tsel@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 ==== //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 ==== //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