PERFORCE change 166208 for review
Tatsiana Elavaya
tsel at FreeBSD.org
Fri Jul 17 18:52:24 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=166208
Change 166208 by tsel at 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
More information about the p4-projects
mailing list