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