Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 30 Jul 2014 14:52:26 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r269304 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw
Message-ID:  <201407301452.s6UEqQxm064634@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Wed Jul 30 14:52:26 2014
New Revision: 269304
URL: http://svnweb.freebsd.org/changeset/base/269304

Log:
  * Add number:array algorithm lookup method.
  
  Kernel changes:
  * s/IPFW_TABLE_U32/IPFW_TABLE_NUMBER/
  * Force "lookup <port|uid|gid|jid>" to be IPFW_TABLE_NUMBER
  * Support "lookup" method for number tables
  * Add number:array algorihm (i32 as key, auto-growing).
  
  Userland changes:
  * Support named tables in "lookup <tag> Table"
  * Fix handling of "table(NAME,val)" case
  * Support printing "number" table data.

Modified:
  projects/ipfw/sbin/ipfw/ipfw2.c
  projects/ipfw/sbin/ipfw/tables.c
  projects/ipfw/sys/netinet/ip_fw.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c

Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c	Wed Jul 30 14:52:04 2014	(r269303)
+++ projects/ipfw/sbin/ipfw/ipfw2.c	Wed Jul 30 14:52:26 2014	(r269304)
@@ -1096,6 +1096,7 @@ print_ip(struct format_opts *fo, ipfw_in
 	struct hostent *he = NULL;
 	uint32_t len = F_LEN((ipfw_insn *)cmd);
 	uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
+	char *t;
 
 	if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
 		uint32_t d = a[1];
@@ -1103,8 +1104,9 @@ print_ip(struct format_opts *fo, ipfw_in
 
 		if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
 			arg = match_value(rule_options, lookup_key[d]);
-		printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "",
-			arg, cmd->o.arg1);
+		t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
+		printf("%s lookup %s %s", cmd->o.len & F_NOT ? " not": "",
+			arg, t);
 		return;
 	}
 	printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
@@ -1115,7 +1117,6 @@ print_ip(struct format_opts *fo, ipfw_in
 	}
 	if (cmd->o.opcode == O_IP_SRC_LOOKUP ||
 	    cmd->o.opcode == O_IP_DST_LOOKUP) {
-		char *t;
 		t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
 		printf("table(%s", t);
 		if (len == F_INSN_SIZE(ipfw_insn_u32))
@@ -2624,14 +2625,9 @@ struct tidx {
 static uint16_t
 pack_table(struct tidx *tstate, char *name, uint32_t set)
 {
-	char *p;
 	int i;
 	ipfw_obj_ntlv *ntlv;
 
-	if ((p = strchr(name, ')')) == NULL)
-		return (0);
-	*p = '\0';
-
 	if (table_check_name(name) != 0)
 		return (0);
 
@@ -2694,6 +2690,9 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int
 	}
 
 	if (strncmp(av, "table(", 6) == 0) {
+		if ((p = strchr(av + 6, ')')) == NULL)
+			errx(EX_DATAERR, "forgotten parenthesis: '%s'", av);
+		*p = '\0';
 		p = strchr(av + 6, ',');
 		if (p)
 			*p++ = '\0';
@@ -2983,6 +2982,7 @@ ipfw_delete(char *av[])
 static void
 fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate)
 {
+	char *p;
 	uint16_t uidx;
 
 	cmd->name[0] = '\0';
@@ -2994,7 +2994,10 @@ fill_iface(ipfw_insn_if *cmd, char *arg,
 	if (strcmp(arg, "any") == 0)
 		cmd->o.len = 0;		/* effectively ignore this command */
 	else if (strncmp(arg, "table(", 6) == 0) {
-		char *p = strchr(arg + 6, ',');
+		if ((p = strchr(arg + 6, ')')) == NULL)
+			errx(EX_DATAERR, "forgotten parenthesis: '%s'", arg);
+		*p = '\0';
+		p = strchr(arg + 6, ',');
 		if (p)
 			*p++ = '\0';
 		if ((uidx = pack_table(tstate, arg + 6, 0)) == 0)
@@ -4381,7 +4384,6 @@ read_options:
 
 		case TOK_LOOKUP: {
 			ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
-			char *p;
 			int j;
 
 			if (!av[0] || !av[1])
@@ -4397,9 +4399,11 @@ read_options:
 				errx(EX_USAGE, "format: cannot lookup on %s", *av);
 			__PAST_END(c->d, 1) = j; // i converted to option
 			av++;
-			cmd->arg1 = strtoul(*av, &p, 0);
-			if (p && *p)
-				errx(EX_USAGE, "format: lookup argument tablenum");
+
+			if ((j = pack_table(tstate, *av, 0)) == 0)
+				errx(EX_DATAERR, "Invalid table name: %s", *av);
+
+			cmd->arg1 = j;
 			av++;
 		    }
 			break;

Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c	Wed Jul 30 14:52:04 2014	(r269303)
+++ projects/ipfw/sbin/ipfw/tables.c	Wed Jul 30 14:52:26 2014	(r269304)
@@ -82,7 +82,7 @@ static int tables_foreach(table_cb_t *f,
 static struct _s_x tabletypes[] = {
       { "cidr",		IPFW_TABLE_CIDR },
       { "iface",	IPFW_TABLE_INTERFACE },
-      { "u32",		IPFW_TABLE_U32 },
+      { "number",	IPFW_TABLE_NUMBER },
       { NULL, 0 }
 };
 
@@ -654,7 +654,7 @@ tentry_fill_key_type(char *arg, ipfw_obj
 		/* Set mask to exact match */
 		masklen = 8 * IF_NAMESIZE;
 		break;
-	case IPFW_TABLE_U32:
+	case IPFW_TABLE_NUMBER:
 		/* Port or any other key */
 		key = strtol(arg, &p, 10);
 		if (*p != '\0')
@@ -899,6 +899,16 @@ table_show_entry(ipfw_xtable_info *i, ip
 			    inet_ntoa(*(struct in_addr *)&tval));
 		} else
 			printf("%s %u\n", tent->k.iface, tval);
+		break;
+	case IPFW_TABLE_NUMBER:
+		/* numbers */
+		if (co.do_value_as_ip) {
+			tval = htonl(tval);
+			printf("%u %s\n", tent->k.key,
+			    inet_ntoa(*(struct in_addr *)&tval));
+		} else
+			printf("%u %u\n", tent->k.key, tval);
+		break;
 	}
 }
 

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Wed Jul 30 14:52:04 2014	(r269303)
+++ projects/ipfw/sys/netinet/ip_fw.h	Wed Jul 30 14:52:26 2014	(r269304)
@@ -674,7 +674,7 @@ struct _ipfw_dyn_rule {
 
 #define	IPFW_TABLE_CIDR		1	/* Table for holding IPv4/IPv6 prefixes */
 #define	IPFW_TABLE_INTERFACE	2	/* Table for holding interface names */
-#define	IPFW_TABLE_U32		3	/* Table for holidng ports/uid/gid/etc */
+#define	IPFW_TABLE_NUMBER	3	/* Table for holding ports/uid/gid/etc */
 #define	IPFW_TABLE_MAXTYPE	3	/* Maximum valid number */
 
 #define	IPFW_VTYPE_U32		1	/* Skipto/tablearg integer */

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Wed Jul 30 14:52:04 2014	(r269303)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Wed Jul 30 14:52:26 2014	(r269304)
@@ -1473,9 +1473,9 @@ do {								\
 						proto != IPPROTO_UDP)
 					    break;
 					else if (v == 2)
-					    key = htonl(dst_port);
+					    key = dst_port;
 					else if (v == 3)
-					    key = htonl(src_port);
+					    key = src_port;
 #ifndef USERSPACE
 					else if (v == 4 || v == 5) {
 					    check_uidgid(
@@ -1494,7 +1494,6 @@ do {								\
 					    else if (v == 5 /* O_JAIL */)
 						key = ucred_cache.xid;
 #endif /* !__FreeBSD__ */
-					    key = htonl(key);
 					} else
 #endif /* !USERSPACE */
 					    break;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Wed Jul 30 14:52:04 2014	(r269303)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Wed Jul 30 14:52:26 2014	(r269304)
@@ -593,6 +593,9 @@ ipfw_find_table_entry(struct ip_fw_chain
 			IPFW_UH_RUNLOCK(ch);
 			return (EINVAL);
 		}
+	case IPFW_TABLE_NUMBER:
+		plen = sizeof(uint32_t);
+		break;
 
 		break;
 	default:
@@ -1744,17 +1747,19 @@ classify_table_opcode(ipfw_insn *cmd, ui
 			case 2:
 			case 3:
 				/* src/dst port */
-				//type = IPFW_TABLE_U16;
+				*ptype = IPFW_TABLE_NUMBER;
 				break;
 			case 4:
 				/* uid/gid */
-				//type = IPFW_TABLE_U32;
+				*ptype = IPFW_TABLE_NUMBER;
+				break;
 			case 5:
-				//type = IPFW_TABLE_U32;
 				/* jid */
+				*ptype = IPFW_TABLE_NUMBER;
+				break;
 			case 6:
-				//type = IPFW_TABLE_U16;
 				/* dscp */
+				*ptype = IPFW_TABLE_NUMBER;
 				break;
 			}
 		}

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Wed Jul 30 14:52:04 2014	(r269303)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Wed Jul 30 14:52:26 2014	(r269304)
@@ -1376,7 +1376,7 @@ struct table_algo cidr_hash = {
  *
  * Runtime part:
  * - sorted array of "struct ifidx" pointed by ti->state.
- *   Array is allocated with routing up to IFIDX_CHUNK. Only existing
+ *   Array is allocated with rounding up to IFIDX_CHUNK. Only existing
  *   interfaces are stored in array, however its allocated size is
  *   sufficient to hold all table records if needed.
  * - current array size is stored in ti->data
@@ -2025,6 +2025,368 @@ struct table_algo iface_idx = {
 	.change_ti	= ta_change_ti_ifidx,
 };
 
+/*
+ * Number array cmds.
+ *
+ * Implementation:
+ *
+ * Runtime part:
+ * - sorted array of "struct numarray" pointed by ti->state.
+ *   Array is allocated with rounding up to NUMARRAY_CHUNK.
+ * - current array size is stored in ti->data
+ *
+ */
+
+struct numarray {
+	uint32_t	number;
+	uint32_t	value;
+};
+
+struct numarray_cfg {
+	void	*main_ptr;
+	size_t	size;	/* Number of items allocated in array */
+	size_t	used;	/* Number of items _active_ now */
+};
+
+#define	NUMARRAY_CHUNK	16
+
+int compare_numarray(const void *k, const void *v);
+
+int
+compare_numarray(const void *k, const void *v)
+{
+	struct numarray *na;
+	uint32_t key;
+
+	key = *((uint32_t *)k);
+	na = (struct numarray *)v;
+
+	if (key < na->number)
+		return (-1);
+	else if (key > na->number)
+		return (1);
+	
+	return (0);
+}
+
+static struct numarray *
+numarray_find(struct table_info *ti, void *key)
+{
+	struct numarray *ri;
+
+	ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
+	    compare_ifidx);
+
+	return (ri);
+}
+
+static int
+ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
+    uint32_t *val)
+{
+	struct numarray *ri;
+
+	ri = numarray_find(ti, key);
+
+	if (ri != NULL) {
+		*val = ri->value;
+		return (1);
+	}
+
+	return (0);
+}
+
+static int
+ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+    char *data)
+{
+	struct numarray_cfg *cfg;
+
+	cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
+
+	cfg->size = NUMARRAY_CHUNK;
+	cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
+	    M_WAITOK | M_ZERO);
+
+	*ta_state = cfg;
+	ti->state = cfg->main_ptr;
+	ti->lookup = ta_lookup_numarray;
+
+	return (0);
+}
+
+/*
+ * Destroys table @ti
+ */
+static void
+ta_destroy_numarray(void *ta_state, struct table_info *ti)
+{
+	struct numarray_cfg *cfg;
+
+	cfg = (struct numarray_cfg *)ta_state;
+
+	if (cfg->main_ptr != NULL)
+		free(cfg->main_ptr, M_IPFW);
+
+	free(cfg, M_IPFW);
+}
+
+struct ta_buf_numarray
+{
+	struct numarray na;
+};
+
+/*
+ * Prepare for addition/deletion to an array.
+ */
+static int
+ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
+    void *ta_buf)
+{
+	struct ta_buf_numarray *tb;
+
+	tb = (struct ta_buf_numarray *)ta_buf;
+	memset(tb, 0, sizeof(*tb));
+
+	tb->na.number = *((uint32_t *)tei->paddr);
+	tb->na.value = tei->value;
+
+	return (0);
+}
+
+static int
+ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+    void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+{
+	struct numarray_cfg *cfg;
+	struct ta_buf_numarray *tb;
+	struct numarray *ri;
+	int res;
+
+	tb = (struct ta_buf_numarray*)ta_buf;
+	cfg = (struct numarray_cfg *)ta_state;
+
+	ri = numarray_find(ti, &tb->na.number);
+	
+	if (ri != NULL) {
+		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
+			return (EEXIST);
+
+		/* We need to update value */
+		ri->value = tb->na.value;
+		/* Indicate that update has happened instead of addition */
+		tei->flags |= TEI_FLAGS_UPDATED;
+		*pnum = 0;
+		return (0);
+	}
+
+	res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
+	    sizeof(struct numarray), compare_numarray);
+
+	KASSERT(res == 1, ("number %d already exists", tb->na.number));
+	cfg->used++;
+	ti->data = cfg->used;
+
+	if (cfg->used + 1 == cfg->size) {
+		/* Notify core we need to grow */
+		*pflags = cfg->size + NUMARRAY_CHUNK;
+	}
+	*pnum = 1;
+
+	return (0);
+}
+
+/*
+ * Remove key from both configuration list and
+ * runtime array. Removed interface notification.
+ */
+static int
+ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+    void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+{
+	struct numarray_cfg *cfg;
+	struct ta_buf_numarray *tb;
+	struct numarray *ri;
+	int res;
+
+	tb = (struct ta_buf_numarray *)ta_buf;
+	cfg = (struct numarray_cfg *)ta_state;
+
+	ri = numarray_find(ti, &tb->na.number);
+	if (ri == NULL)
+		return (ENOENT);
+	
+	res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
+	    sizeof(struct numarray), compare_numarray);
+
+	KASSERT(res == 1, ("number %u does not exist", tb->na.number));
+	cfg->used--;
+	ti->data = cfg->used;
+
+	*pnum = 1;
+
+	return (0);
+}
+
+static void
+ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
+    void *ta_buf)
+{
+
+	/* Do nothing */
+}
+
+
+/*
+ * Table growing callbacks.
+ */
+
+/*
+ * Allocate ned, larger runtime numarray array.
+ */
+static int
+ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
+{
+	struct mod_item *mi;
+
+	mi = (struct mod_item *)ta_buf;
+
+	memset(mi, 0, sizeof(struct mod_item));
+	mi->size = *pflags;
+	mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
+	    M_WAITOK | M_ZERO);
+
+	return (0);
+}
+
+/*
+ * Copy data from old runtime array to new one.
+ */
+static int
+ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
+    uint64_t *pflags)
+{
+	struct mod_item *mi;
+	struct numarray_cfg *cfg;
+
+	mi = (struct mod_item *)ta_buf;
+	cfg = (struct numarray_cfg *)ta_state;
+
+	/* Check if we still need to grow array */
+	if (cfg->size >= mi->size) {
+		*pflags = 0;
+		return (0);
+	}
+
+	memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
+
+	return (0);
+}
+
+/*
+ * Switch old & new arrays.
+ */
+static int
+ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
+    uint64_t pflags)
+{
+	struct mod_item *mi;
+	struct numarray_cfg *cfg;
+	void *old_ptr;
+
+	mi = (struct mod_item *)ta_buf;
+	cfg = (struct numarray_cfg *)ta_state;
+
+	old_ptr = cfg->main_ptr;
+	cfg->main_ptr = mi->main_ptr;
+	cfg->size = mi->size;
+	ti->state = cfg->main_ptr;
+
+	mi->main_ptr = old_ptr;
+
+	return (0);
+}
+
+/*
+ * Free unneded array.
+ */
+static void
+ta_flush_mod_numarray(void *ta_buf)
+{
+	struct mod_item *mi;
+
+	mi = (struct mod_item *)ta_buf;
+	if (mi->main_ptr != NULL)
+		free(mi->main_ptr, M_IPFW);
+}
+
+static int
+ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
+    ipfw_obj_tentry *tent)
+{
+	struct numarray *na;
+
+	na = (struct numarray *)e;
+
+	tent->k.key = na->number;
+	tent->value = na->value;
+
+	return (0);
+}
+
+static int
+ta_find_numarray_tentry(void *ta_state, struct table_info *ti, void *key,
+    uint32_t keylen, ipfw_obj_tentry *tent)
+{
+	struct numarray_cfg *cfg;
+	struct numarray *ri;
+
+	cfg = (struct numarray_cfg *)ta_state;
+
+	ri = numarray_find(ti, key);
+
+	if (ri != NULL) {
+		ta_dump_numarray_tentry(ta_state, ti, ri, tent);
+		return (0);
+	}
+
+	return (ENOENT);
+}
+
+static void
+ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+    void *arg)
+{
+	struct numarray_cfg *cfg;
+	struct numarray *array;
+	int i;
+
+	cfg = (struct numarray_cfg *)ta_state;
+	array = cfg->main_ptr;
+
+	for (i = 0; i < cfg->used; i++)
+		f(&array[i], arg);
+}
+
+struct table_algo number_array = {
+	.name		= "number:array",
+	.type		= IPFW_TABLE_NUMBER,
+	.init		= ta_init_numarray,
+	.destroy	= ta_destroy_numarray,
+	.prepare_add	= ta_prepare_add_numarray,
+	.prepare_del	= ta_prepare_add_numarray,
+	.add		= ta_add_numarray,
+	.del		= ta_del_numarray,
+	.flush_entry	= ta_flush_numarray_entry,
+	.foreach	= ta_foreach_numarray,
+	.dump_tentry	= ta_dump_numarray_tentry,
+	.find_tentry	= ta_find_numarray_tentry,
+	.prepare_mod	= ta_prepare_mod_numarray,
+	.fill_mod	= ta_fill_mod_numarray,
+	.modify		= ta_modify_numarray,
+	.flush_mod	= ta_flush_mod_numarray,
+};
+
 void
 ipfw_table_algo_init(struct ip_fw_chain *ch)
 {
@@ -2037,6 +2399,7 @@ ipfw_table_algo_init(struct ip_fw_chain 
 	ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx);
 	ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx);
 	ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
+	ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
 }
 
 void
@@ -2046,6 +2409,7 @@ ipfw_table_algo_destroy(struct ip_fw_cha
 	ipfw_del_table_algo(ch, cidr_radix.idx);
 	ipfw_del_table_algo(ch, cidr_hash.idx);
 	ipfw_del_table_algo(ch, iface_idx.idx);
+	ipfw_del_table_algo(ch, number_array.idx);
 }
 
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407301452.s6UEqQxm064634>