From owner-p4-projects@FreeBSD.ORG Fri Jul 17 18:52:24 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 0839C1065674; Fri, 17 Jul 2009 18:52:24 +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 BC1AC1065672 for ; Fri, 17 Jul 2009 18:52:23 +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 A97618FC0C for ; Fri, 17 Jul 2009 18:52:23 +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 n6HIqNwx010096 for ; Fri, 17 Jul 2009 18:52:23 GMT (envelope-from tsel@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n6HIqNUw010094 for perforce@freebsd.org; Fri, 17 Jul 2009 18:52:23 GMT (envelope-from tsel@FreeBSD.org) Date: Fri, 17 Jul 2009 18:52:23 GMT Message-Id: <200907171852.n6HIqNUw010094@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 166208 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, 17 Jul 2009 18:52:24 -0000 http://perforce.freebsd.org/chv.cgi?CH=166208 Change 166208 by tsel@tsel_mz on 2009/07/17 18:51:37 Introduce ipfw.hll - high(er) level language preprocessor for ipfw Fix merge after ip_fw2.c was moved to netinet/ipfw/ Support optimization of rules with same numbers Use internal rule index instead rule number to count rule rank Affected files ... .. //depot/projects/soc2009/tsel_ipfw/libexec/ipfw.hll/Makefile#1 add .. //depot/projects/soc2009/tsel_ipfw/libexec/ipfw.hll/ipfw.hll.c#1 add .. //depot/projects/soc2009/tsel_ipfw/libexec/ipfw.hll/ipfw.hll.h#1 add .. //depot/projects/soc2009/tsel_ipfw/libexec/ipfw.hll/parse.y#1 add .. //depot/projects/soc2009/tsel_ipfw/libexec/ipfw.hll/subr.c#1 add .. //depot/projects/soc2009/tsel_ipfw/libexec/ipfw.hll/token.l#1 add .. //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/ipfw2.c#12 edit .. //depot/projects/soc2009/tsel_ipfw/sys/netinet/ip_fw2.c#8 delete .. //depot/projects/soc2009/tsel_ipfw/sys/netinet/ipfw/ip_fw2.c#2 edit Differences ... ==== //depot/projects/soc2009/tsel_ipfw/sbin/ipfw/ipfw2.c#12 (text+ko) ==== @@ -2063,6 +2063,7 @@ struct insn_match_rule { struct insn_match_rule_head rule_head; struct ip_fw *rule; + int ruleind; }; struct insn_match { @@ -2212,7 +2213,7 @@ { struct insn_match_group *a[2] = { _a, _b }; struct insn_match *m; - int i, min_r, max_r; + int i, min_r, max_r, ruleind; if (a[0] == NULL) return a[1] == NULL ? 0 : 1; @@ -2221,13 +2222,13 @@ for (i = 0; i < 2; i++) { if (a[i]->rank || a[i]->match_count == 0) continue; - min_r = max_r = LIST_FIRST(&a[i]->match_head)->match_rule->rule->rulenum; + min_r = max_r = LIST_FIRST(&a[i]->match_head)->match_rule->ruleind; LIST_FOREACH(m, &a[i]->match_head, match_entries) { - int rulenum = m->match_rule->rule->rulenum; - if (rulenum < min_r) - min_r = rulenum; - else if (rulenum > max_r) - max_r = rulenum; + ruleind = m->match_rule->ruleind; + if (ruleind < min_r) + min_r = ruleind; + else if (ruleind > max_r) + max_r = ruleind; } a[i]->rank = ((a[i]->match_count & 0x7fff) << 16) - (max_r - min_r); } @@ -2362,7 +2363,7 @@ l = rule_buf->rulenum & 0xffff; if (do_cmd(IP_FW_DEL, &l, sizeof(l))) - errx(EX_DATAERR, "rule %u: setsockopt(IP_FW_DEL)", rule_buf->rulenum); + warnx("rule %u: setsockopt(IP_FW_DEL)", rule_buf->rulenum); l = RULESIZE(rule_buf); if (do_cmd(IP_FW_ADD, rule_buf, (uintptr_t)&l)) @@ -2401,12 +2402,10 @@ match_rules = safe_calloc(rules_count, sizeof(struct insn_match_rule)); for (i = 0; i < rules_count; i++) { - if (i > 0 && rules[i]->rulenum == rules[i - 1]->rulenum) - errx(EX_DATAERR, "rule number is not unique: %d", rules[i]->rulenum); - l = RULESIZE(rules[i]); rules[i] = memcpy(safe_calloc(1, l), rules[i], l); match_rules[i].rule = rules[i]; + match_rules[i].ruleind = i + 1; for (l = rules[i]->cmd_len, cmd = rules[i]->cmd; l > 0;) { l -= F_LEN(cmd); ==== //depot/projects/soc2009/tsel_ipfw/sys/netinet/ipfw/ip_fw2.c#2 (text+ko) ==== @@ -158,9 +158,19 @@ #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_ROUND (sizeof(uint32_t) * 8) +#define OPTIMIZATION_BUF_INITIAL OPTIMIZATION_BUF_ROUND #ifdef SYSCTL_NODE SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); @@ -184,6 +194,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 */ @@ -310,6 +329,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 % OPTIMIZATION_BUF_ROUND) + sz += OPTIMIZATION_BUF_ROUND - (sz % OPTIMIZATION_BUF_ROUND); + if (sz > OPTIMIZATION_BUF_MAX) + sz = OPTIMIZATION_BUF_MAX; + + /* do not shrink buffers. ruleset may contain old o_optimize instructions */ + if (sz <= *(int *)arg1) + return 0; + + for (i = 0; i < OPTIMIZATION_POOLS; i++) { + bufs[i] = malloc(sz, 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 @@ -904,6 +978,11 @@ case O_REASS: action = "Reass"; break; + case O_ALIAS: + ((ipfw_insn_alias *)cmd)->alias[IPFW_ALIAS_NAME_SIZE - 1] = '\0'; + snprintf(SNPARGS(action2, 0), "Alias %s", + ((ipfw_insn_alias *)cmd)->alias); + break; default: action = "UNKNOWN"; break; @@ -2073,6 +2152,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. * @@ -2231,6 +2349,13 @@ /* end of ipv6 variables */ int is_ipv4 = 0; +#define GET_OPTIMIZ_LABEL(a) (optimiz_buf ? optimiz_buf[((a) - 1) / 32] & (1 << (((a) - 1) % 32)) : 0) +#define SET_OPTIMIZ_LABEL(a) (optimiz_buf ? optimiz_buf[((a) - 1) / 32] |= (1 << (((a) - 1) % 32)) : 0) +#define GET_NEG_OPTIMIZ_LABEL(a) GET_OPTIMIZ_LABEL((a) + V_optimization_buf_sz*4) +#define SET_NEG_OPTIMIZ_LABEL(a) SET_OPTIMIZ_LABEL((a) + V_optimization_buf_sz*4) + uint32_t *optimiz_buf = NULL; + uint32_t optimiz_buf_ind = 0; + if (m->m_flags & M_SKIP_FIREWALL) return (IP_FW_PASS); /* accept */ @@ -2536,6 +2661,16 @@ m_tag_delete(m, mtag); } + 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. */ @@ -2543,6 +2678,11 @@ ipfw_insn *cmd; uint32_t tablearg = 0; int l, cmdlen, skip_or; /* skip rest of OR block */ + ipfw_insn_u16 *optimiz_cmd = NULL; + int optimiz_ind = 0, optimiz_match = 0; +#ifdef IPFW_OPTIMIZE_DEBUG + int optimiz_match_neg = 0; +#endif again: if (V_set_disable & (1 << f->set) ) @@ -2575,6 +2715,39 @@ } match = 0; /* set to 1 if we succeed */ + if (V_optimization_enable && optimiz_cmd != NULL && cmd->opcode != O_OPTIMIZE) { + int label = optimiz_cmd->ports[optimiz_ind]; + + if (optimiz_ind >= (F_LEN(&optimiz_cmd->o) - 1) * 2 || label == 0) { + optimiz_cmd = NULL; + optimiz_ind = 0; + optimiz_match = 0; + } else { + optimiz_ind++; + if (GET_OPTIMIZ_LABEL(label)) { + optimiz_match = label; +#ifdef IPFW_OPTIMIZE_DEBUG + printf("ipfw: rule %d: optimized %d %d\n", f->rulenum, cmd->opcode, optimiz_match); + optimiz_match_neg = 0; +#else + continue; +#endif + } else if (GET_NEG_OPTIMIZ_LABEL(label)) { + optimiz_match = label; +#ifdef IPFW_OPTIMIZE_DEBUG + printf("ipfw: rule %d: negative optimized %d %d\n", f->rulenum, cmd->opcode, optimiz_match); + optimiz_match_neg = 1; +#else + goto next_rule; +#endif + + } else { + optimiz_match = -label; + } + } + + } + switch (cmd->opcode) { /* * The first set of opcodes compares the packet's @@ -3119,6 +3292,32 @@ } break; } + case O_OPTIMIZE: { + optimiz_cmd = (ipfw_insn_u16 *) cmd; + optimiz_ind = 0; + + if (!V_optimization_enable || !optimiz_buf) { + optimiz_cmd = NULL; + continue; + } + + for (int i = 0; i < (F_LEN(cmd) - 1) * 2; i++) + if (optimiz_cmd->ports[i] > V_optimization_buf_sz * 8 / 2) { +#ifdef IPFW_OPTIMIZE_DEBUG + printf("ipfw: invalid O_OPTIMIZE instruction. ignoring"); +#endif + optimiz_cmd = NULL; + continue; + } + + if (optimiz_match) { +#ifdef IPFW_OPTIMIZE_DEBUG + printf("ipfw: unexpected O_OPTIMIZE instruction. ignoring"); +#endif + continue; + } + continue; + } /* * The second set of opcodes represents 'actions', @@ -3238,6 +3437,7 @@ if (mtag == NULL) { /* XXX statistic */ /* drop packet */ + optimization_buf_rel(&optimiz_buf_ind); IPFW_RUNLOCK(chain); if (ucred_cache != NULL) crfree(ucred_cache); @@ -3371,6 +3571,9 @@ } else retval = IP_FW_DENY; goto done; + + case O_ALIAS: + break; } case O_REASS: { @@ -3431,6 +3634,24 @@ if (cmd->len & F_NOT) match = !match; +#ifdef IPFW_OPTIMIZE_DEBUG + if (optimiz_match > 0 && (match != !optimiz_match_neg || cmd->len & F_OR)) + printf("ipfw: rule %d: optimization error: cmd mismatch %d (optimiz_ind=%d, neg=%d) %d\n", f->rulenum, cmd->opcode, optimiz_ind, optimiz_match_neg, optimiz_match); +#endif + if (V_optimization_enable) { + if (optimiz_match < 0) { + optimiz_match = -optimiz_match; + if (match) + SET_OPTIMIZ_LABEL(optimiz_match); + else + SET_NEG_OPTIMIZ_LABEL(optimiz_match); +#ifdef IPFW_OPTIMIZE_DEBUG + printf("ipfw: rule %d: set %soptimize match %d %d\n", f->rulenum, match ? "" : "negative ", cmd->opcode, optimiz_match); +#endif + } + optimiz_match = 0; + } + if (match) { if (cmd->len & F_OR) skip_or = 1; @@ -3445,6 +3666,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); if (ucred_cache != NULL) crfree(ucred_cache); @@ -3455,6 +3677,7 @@ f->pcnt++; f->bcnt += pktlen; f->timestamp = time_uptime; + optimization_buf_rel(&optimiz_buf_ind); IPFW_RUNLOCK(chain); if (ucred_cache != NULL) crfree(ucred_cache); @@ -4032,6 +4255,11 @@ goto bad_size; break; + case O_OPTIMIZE: + if (cmdlen < F_INSN_SIZE(ipfw_insn_u16)) + goto bad_size; + break; + case O_ALTQ: if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) goto bad_size; @@ -4099,6 +4327,10 @@ return EINVAL; } break; + case O_ALIAS: + if (cmdlen != F_INSN_SIZE(ipfw_insn_alias)) + goto bad_size; + break; #ifdef INET6 case O_IP6_SRC: case O_IP6_DST: @@ -4578,7 +4810,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() */ @@ -4601,6 +4833,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); @@ -4703,6 +4942,7 @@ { INIT_VNET_IPFW(curvnet); struct ip_fw *reap; + int i; ip_fw_chk_ptr = NULL; ip_fw_ctl_ptr = NULL; @@ -4717,6 +4957,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