svn commit: r270906 - in projects/ipfw: sbin/ipfw sys/conf sys/modules/ipfw sys/netinet sys/netpfil/ipfw

Alexander V. Chernikov melifaro at FreeBSD.org
Sun Aug 31 23:51:11 UTC 2014


Author: melifaro
Date: Sun Aug 31 23:51:09 2014
New Revision: 270906
URL: http://svnweb.freebsd.org/changeset/base/270906

Log:
  Add support for multi-field values inside ipfw tables.
  This is the last major change in given branch.
  
  Kernel changes:
  * Use 64-bytes structures to hold multi-value variables.
  * Use shared array to hold values from all tables (assume
    each table algo is capable of holding 32-byte variables).
  * Add some placeholders to support per-table value arrays in future.
  * Use simple eventhandler-style API to ease the process of adding new
    table items. Currently table addition may required multiple UH drops/
    acquires which is quite tricky due to atomic table modificatio/swap
    support, shared array resize, etc. Deal with it by calling special
    notifier capable of rolling back state before actually performing
    swap/resize operations. Original operation then restarts itself after
    acquiring UH lock.
  * Bump all objhash users default values to at least 64
  * Fix custom hashing inside objhash.
  
  Userland changes:
  * Add support for dumping shared value array via "vlist" internal cmd.
  * Some small print/fill_flags dixes to support u32 values.
  * valtype is now bitmask of
    <skipto|pipe|fib|nat|dscp|tag|divert|netgraph|limit|ipv4|ipv6>.
    New values can hold distinct values for each of this types.
  * Provide special "legacy" type which assumes all values are the same.
  * More helpers/docs following..
  
  Some examples:
  
  3:41 [1] zfscurr0# ipfw table mimimi create valtype skipto,limit,ipv4,ipv6
  3:41 [1] zfscurr0# ipfw table mimimi info
  +++ table(mimimi), set(0) +++
   kindex: 2, type: addr
   references: 0, valtype: skipto,limit,ipv4,ipv6
   algorithm: addr:radix
   items: 0, size: 296
  3:42 [1] zfscurr0# ipfw table mimimi add 10.0.0.5 3000,10,10.0.0.1,2a02:978:2::1
  added: 10.0.0.5/32 3000,10,10.0.0.1,2a02:978:2::1
  3:42 [1] zfscurr0# ipfw table mimimi list
  +++ table(mimimi), set(0) +++
  10.0.0.5/32 3000,0,10.0.0.1,2a02:978:2::1

Added:
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table_value.c
Modified:
  projects/ipfw/sbin/ipfw/ipfw2.c
  projects/ipfw/sbin/ipfw/ipfw2.h
  projects/ipfw/sbin/ipfw/tables.c
  projects/ipfw/sys/conf/files
  projects/ipfw/sys/modules/ipfw/Makefile
  projects/ipfw/sys/netinet/ip_fw.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_log.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c

Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c	Sun Aug 31 23:09:23 2014	(r270905)
+++ projects/ipfw/sbin/ipfw/ipfw2.c	Sun Aug 31 23:51:09 2014	(r270906)
@@ -712,12 +712,13 @@ concat_tokens(char *buf, size_t bufsize,
  * helper function to process a set of flags and set bits in the
  * appropriate masks.
  */
-void
-fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear)
+int
+fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
+    uint32_t *clear)
 {
 	char *q;	/* points to the separator */
 	int val;
-	uint8_t *which;	/* mask we are working on */
+	uint32_t *which;	/* mask we are working on */
 
 	while (p && *p) {
 		if (*p == '!') {
@@ -729,15 +730,19 @@ fill_flags(struct _s_x *flags, char *p, 
 		if (q)
 			*q++ = '\0';
 		val = match_token(flags, p);
-		if (val <= 0)
-			errx(EX_DATAERR, "invalid flag %s", p);
-		*which |= (uint8_t)val;
+		if (val <= 0) {
+			if (e != NULL)
+				*e = p;
+			return (-1);
+		}
+		*which |= (uint32_t)val;
 		p = q;
 	}
+	return (0);
 }
 
 void
-print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set)
+print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set)
 {
 	char const *comma = "";
 	int i, l;
@@ -2992,9 +2997,11 @@ static void
 fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode,
 	struct _s_x *flags, char *p)
 {
-	uint8_t set = 0, clear = 0;
+	char *e;
+	uint32_t set = 0, clear = 0;
 
-	fill_flags(flags, p, &set, &clear);
+	if (fill_flags(flags, p, &e, &set, &clear) != 0)
+		errx(EX_DATAERR, "invalid flag %s", e);
 
 	cmd->opcode = opcode;
 	cmd->len =  (cmd->len & (F_NOT | F_OR)) | 1;
@@ -4825,6 +4832,7 @@ ipfw_flush(int force)
 static struct _s_x intcmds[] = {
       { "talist",	TOK_TALIST },
       { "iflist",	TOK_IFLIST },
+      { "vlist",	TOK_VLIST },
       { NULL, 0 }
 };
 
@@ -4846,6 +4854,9 @@ ipfw_internal_handler(int ac, char *av[]
 	case TOK_TALIST:
 		ipfw_list_ta(ac, av);
 		break;
+	case TOK_VLIST:
+		ipfw_list_values(ac, av);
+		break;
 	}
 }
 

Modified: projects/ipfw/sbin/ipfw/ipfw2.h
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.h	Sun Aug 31 23:09:23 2014	(r270905)
+++ projects/ipfw/sbin/ipfw/ipfw2.h	Sun Aug 31 23:51:09 2014	(r270906)
@@ -223,10 +223,10 @@ enum tokens {
 	TOK_VALTYPE,
 	TOK_ALGO,
 	TOK_TALIST,
-	TOK_FTYPE,
 	TOK_ATOMIC,
 	TOK_LOCK,
 	TOK_UNLOCK,
+	TOK_VLIST,
 };
 
 /*
@@ -265,8 +265,9 @@ int match_token_relaxed(struct _s_x *tab
 char const *match_value(struct _s_x *p, int value);
 size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table,
     char *delimiter);
-void fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear);
-void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set);
+int fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
+    uint32_t *clear);
+void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set);
 
 struct _ip_fw3_opheader;
 int do_cmd(int optname, void *optval, uintptr_t optlen);
@@ -347,4 +348,5 @@ char *table_search_ctlv(struct _ipfw_obj
 void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv);
 int table_check_name(char *tablename);
 void ipfw_list_ta(int ac, char *av[]);
+void ipfw_list_values(int ac, char *av[]);
 

Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c	Sun Aug 31 23:09:23 2014	(r270905)
+++ projects/ipfw/sbin/ipfw/tables.c	Sun Aug 31 23:51:09 2014	(r270906)
@@ -67,9 +67,11 @@ static void table_show_list(ipfw_obj_hea
 static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
 
 static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
-    char *key, int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
+    char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi);
 static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
-    char *arg, uint8_t type, uint8_t vtype);
+    char *arg, uint8_t type, uint32_t vmask);
+static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
+    uint32_t vmask, int print_ip);
 
 typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
 static int tables_foreach(table_cb_t *f, void *arg, int sort);
@@ -87,13 +89,17 @@ static struct _s_x tabletypes[] = {
 };
 
 static struct _s_x tablevaltypes[] = {
-      { "number",	IPFW_VTYPE_U32 },
-      { NULL, 0 }
-};
-
-static struct _s_x tablefvaltypes[] = {
-      { "ip",		IPFW_VFTYPE_IP },
-      { "number",	IPFW_VFTYPE_U32 },
+      { "skipto",	IPFW_VTYPE_SKIPTO },
+      { "pipe",		IPFW_VTYPE_PIPE },
+      { "fib",		IPFW_VTYPE_FIB },
+      { "nat",		IPFW_VTYPE_NAT },
+      { "dscp",		IPFW_VTYPE_DSCP },
+      { "tag",		IPFW_VTYPE_TAG },
+      { "divert",	IPFW_VTYPE_DIVERT },
+      { "netgraph",	IPFW_VTYPE_NETGRAPH },
+      { "limit",	IPFW_VTYPE_LIMIT },
+      { "ipv4",		IPFW_VTYPE_NH4 },
+      { "ipv6",		IPFW_VTYPE_NH6 },
       { NULL, 0 }
 };
 
@@ -311,7 +317,6 @@ table_fill_objheader(ipfw_obj_header *oh
 
 static struct _s_x tablenewcmds[] = {
       { "type",		TOK_TYPE },
-      { "ftype",	TOK_FTYPE },
       { "valtype",	TOK_VALTYPE },
       { "algo",		TOK_ALGO },
       { "limit",	TOK_LIMIT },
@@ -331,14 +336,16 @@ static struct _s_x flowtypecmds[] = {
 int
 table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
 {
-	uint8_t fset, fclear;
+	uint32_t fset, fclear;
+	char *e;
 
 	/* Parse type options */
 	switch(ttype) {
 	case IPFW_TABLE_FLOW:
 		fset = fclear = 0;
-		fill_flags(flowtypecmds, p, &fset,
-		    &fclear);
+		if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0)
+			errx(EX_USAGE,
+			    "unable to parse flow option %s", e);
 		*tflags = fset;
 		break;
 	default:
@@ -383,8 +390,9 @@ table_create(ipfw_obj_header *oh, int ac
 {
 	ipfw_xtable_info xi;
 	int error, tcmd, val;
+	uint32_t fset, fclear;
 	size_t sz;
-	char *p;
+	char *e, *p;
 	char tbuf[128];
 
 	sz = sizeof(tbuf);
@@ -424,27 +432,16 @@ table_create(ipfw_obj_header *oh, int ac
 			break;
 		case TOK_VALTYPE:
 			NEED1("table value type required");
-			val = match_token(tablevaltypes, *av);
+			fset = fclear = 0;
+			val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear);
 			if (val != -1) {
-				xi.vtype = val;
+				xi.vmask = fset;
 				ac--; av++;
 				break;
 			}
 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
-			    *av, tbuf);
-			break;
-		case TOK_FTYPE:
-			NEED1("table value format type required");
-			val = match_token(tablefvaltypes, *av);
-			if (val != -1) {
-				xi.vftype = val;
-				ac--; av++;
-				break;
-			}
-			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
-			errx(EX_USAGE, "Unknown format type: %s. Supported: %s",
-			    *av, tbuf);
+			    e, tbuf);
 			break;
 		case TOK_ALGO:
 			NEED1("table algorithm name required");
@@ -462,8 +459,8 @@ table_create(ipfw_obj_header *oh, int ac
 	/* Set some defaults to preserve compability */
 	if (xi.algoname[0] == '\0' && xi.type == 0)
 		xi.type = IPFW_TABLE_ADDR;
-	if (xi.vtype == 0)
-		xi.vtype = IPFW_VTYPE_U32;
+	if (xi.vmask == 0)
+		xi.vmask = IPFW_VTYPE_LEGACY;
 
 	if ((error = table_do_create(oh, &xi)) != 0)
 		err(EX_OSERR, "Table creation failed");
@@ -494,13 +491,13 @@ table_do_create(ipfw_obj_header *oh, ipf
 /*
  * Modifies existing table
  *
- * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ]
+ * ipfw table NAME modify [ limit number ]
  */
 static void
 table_modify(ipfw_obj_header *oh, int ac, char *av[])
 {
 	ipfw_xtable_info xi;
-	int error, tcmd, val;
+	int error, tcmd;
 	size_t sz;
 	char tbuf[128];
 
@@ -518,19 +515,8 @@ table_modify(ipfw_obj_header *oh, int ac
 			xi.mflags |= IPFW_TMFLAGS_LIMIT;
 			ac--; av++;
 			break;
-		case TOK_FTYPE:
-			NEED1("table value format type required");
-			val = match_token(tablefvaltypes, *av);
-			if (val != -1) {
-				xi.vftype = val;
-				xi.mflags |= IPFW_TMFLAGS_FTYPE;
-				ac--; av++;
-				break;
-			}
-			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
-			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
-			    *av, tbuf);
-			break;
+		default:
+			errx(EX_USAGE, "cmd is not supported for modificatiob");
 		}
 	}
 
@@ -726,34 +712,39 @@ table_show_tainfo(ipfw_xtable_info *i, s
 	}
 }
 
+static void
+table_print_valheader(char *buf, size_t bufsize, uint32_t vmask)
+{
+
+	if (vmask == IPFW_VTYPE_LEGACY) {
+		snprintf(buf, bufsize, "legacy");
+		return;
+	}
+
+	print_flags_buffer(buf, bufsize, tablevaltypes, vmask);
+}
+
 /*
  * Prints table info struct @i in human-readable form.
  */
 static int
 table_show_info(ipfw_xtable_info *i, void *arg)
 {
-	const char *vtype, *vftype;
+	const char *vtype;
 	ipfw_ta_tinfo *tainfo;
 	int afdata, afitem;
 	struct ta_cldata d;
 	char ttype[64], tvtype[64];
 
 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
-	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
-		vtype = "unknown";
-	if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL)
-		vftype = "unknown";
-	if (strcmp(vtype, vftype) != 0)
-		snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype);
-	else
-		snprintf(tvtype, sizeof(tvtype), "%s", vtype);
+	table_print_valheader(tvtype, sizeof(tvtype), i->vmask);
 
 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
 	if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0)
 		printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype);
 	else
 		printf(" kindex: %d, type: %s\n", i->kidx, ttype);
-	printf(" valtype: %s, references: %u\n", tvtype, i->refcnt);
+	printf(" references: %u, valtype: %s\n", i->refcnt, tvtype);
 	printf(" algorithm: %s\n", i->algoname);
 	printf(" items: %u, size: %u\n", i->count, i->size);
 	if (i->limit > 0)
@@ -895,7 +886,8 @@ table_modify_record(ipfw_obj_header *oh,
 {
 	ipfw_obj_tentry *ptent, tent, *tent_buf;
 	ipfw_xtable_info xi;
-	uint8_t type, vtype;
+	uint8_t type;
+	uint32_t vmask;
 	int cmd, count, error, i, ignored;
 	char *texterr, *etxt, *px;
 
@@ -933,14 +925,14 @@ table_modify_record(ipfw_obj_header *oh,
 	memset(&xi, 0, sizeof(xi));
 	count = 0;
 	while (ac > 0) {
-		tentry_fill_key(oh, ptent, *av, add, &type, &vtype, &xi);
+		tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi);
 
 		/*
 		 * compability layer: auto-create table if not exists
 		 */
 		if (xi.tablename[0] == '\0') {
 			xi.type = type;
-			xi.vtype = vtype;
+			xi.vmask = vmask;
 			strlcpy(xi.tablename, oh->ntlv.name,
 			    sizeof(xi.tablename));
 			fprintf(stderr, "DEPRECATED: inserting data info "
@@ -953,7 +945,7 @@ table_modify_record(ipfw_obj_header *oh,
 		ac--; av++;
 	
 		if (add != 0 && ac > 0) {
-			tentry_fill_value(oh, ptent, *av, type, vtype);
+			tentry_fill_value(oh, ptent, *av, type, vmask);
 			ac--; av++;
 		}
 
@@ -966,6 +958,8 @@ table_modify_record(ipfw_obj_header *oh,
 
 	error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
 
+	quiet = 0;
+
 	/*
 	 * Compatibility stuff: do not yell on duplicate keys or
 	 * failed deletions.
@@ -1062,7 +1056,8 @@ table_do_lookup(ipfw_obj_header *oh, cha
 {
 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
 	ipfw_obj_tentry *tent;
-	uint8_t type, vtype;
+	uint8_t type;
+	uint32_t vmask;
 	int error;
 	size_t sz;
 
@@ -1074,7 +1069,7 @@ table_do_lookup(ipfw_obj_header *oh, cha
 	tent->head.length = sizeof(*tent);
 	tent->idx = 1;
 
-	tentry_fill_key(oh, tent, key, 0, &type, &vtype, xi);
+	tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi);
 	oh->ntlv.type = type;
 
 	sz = sizeof(xbuf);
@@ -1321,15 +1316,16 @@ tentry_fill_key_type(char *arg, ipfw_obj
 
 static void
 tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
-    int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
+    int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi)
 {
-	uint8_t type, tflags, vtype;
+	uint8_t type, tflags;
+	uint32_t vmask;
 	int error;
 	char *del;
 
 	type = 0;
 	tflags = 0;
-	vtype = 0;
+	vmask = 0;
 
 	if (xi->tablename[0] == '\0')
 		error = table_get_info(oh, xi);
@@ -1340,7 +1336,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
 		/* Table found. */
 		type = xi->type;
 		tflags = xi->tflags;
-		vtype = xi->vtype;
+		vmask = xi->vmask;
 	} else {
 		if (error != ESRCH)
 			errx(EX_OSERR, "Error requesting table %s info",
@@ -1359,11 +1355,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
 			/* OK Prepare and send */
 			type = IPFW_TABLE_ADDR;
-			/*
-			 * XXX: Value type is forced to be u32.
-			 * This should be changed for MFC.
-			 */
-			vtype = IPFW_VTYPE_U32;
+			vmask = IPFW_VTYPE_LEGACY;
 		} else {
 			/* Inknown key */
 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
@@ -1376,57 +1368,156 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
 	tentry_fill_key_type(key, tent, type, tflags);
 
 	*ptype = type;
-	*pvtype = vtype;
+	*pvmask = vmask;
 }
 
 static void
-tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
-    uint8_t type, uint8_t vtype)
+set_legacy_value(uint32_t val, ipfw_table_value *v)
 {
-	uint32_t val;
-	char *p;
+	v->tag = val;
+	v->pipe = val;
+	v->divert = val;
+	v->skipto = val;
+	v->netgraph = val;
+	v->fib = val;
+	v->nat = val;
+	v->nh4 = val;
+	v->dscp = (uint8_t)val;
+	v->limit = val;
+}
 
-	/* Try to interpret as number first */
-	tent->v.value = strtoul(arg, &p, 0);
-	if (*p == '\0')
-		return;
-	if (inet_pton(AF_INET, arg, &val) == 1) {
-		tent->v.value = ntohl(val);
-		return;
+static void
+tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
+    uint8_t type, uint32_t vmask)
+{
+	uint32_t a4, flag, val, vm;
+	ipfw_table_value *v;
+	uint32_t i;
+	char *comma, *e, *etype, *n, *p;
+
+	v = &tent->v.value;
+	vm = vmask;
+
+	/* Compat layer: keep old behavior for legacy value types */
+	if (vmask == IPFW_VTYPE_LEGACY) {
+		/* Try to interpret as number first */
+		val = strtoul(arg, &p, 0);
+		if (*p == '\0') {
+			set_legacy_value(val, v);
+			return;
+		}
+		if (inet_pton(AF_INET, arg, &val) == 1) {
+			set_legacy_value(ntohl(val), v);
+			return;
+		}
+		/* Try hostname */
+		if (lookup_host(arg, (struct in_addr *)&val) == 0) {
+			set_legacy_value(val, v);
+			return;
+		}
+		errx(EX_OSERR, "Unable to parse value %s", arg);
 	}
-	/* Try hostname */
-	if (lookup_host(arg, (struct in_addr *)&tent->v.value) == 0)
-		return;
-	errx(EX_OSERR, "Unable to parse value %s", arg);
-#if 0
-	switch (vtype) {
-	case IPFW_VTYPE_U32:
-		tent->value = strtoul(arg, &p, 0);
-		if (*p != '\0')
-			errx(EX_USAGE, "Invalid number: %s", arg);
-		break;
-	case IPFW_VTYPE_IP:
-		if (inet_pton(AF_INET, arg, &tent->value) == 1)
+
+	/*
+	 * Shorthands: handle single value if vmask consists
+	 * of numbers only. e.g.:
+	 * vmask = "fib,skipto" -> treat input "1" as "1,1"
+	 */
+
+	n = arg;
+	etype = NULL;
+	for (i = 1; i < (1 << 31); i *= 2) {
+		if ((flag = (vmask & i)) == 0)
+			continue;
+		vmask &= ~flag;
+
+		if ((comma = strchr(n, ',')) != NULL)
+			*comma = '\0';
+
+		switch (flag) {
+		case IPFW_VTYPE_TAG:
+			v->tag = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "tag";
+			break;
+		case IPFW_VTYPE_PIPE:
+			v->pipe = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "pipe";
+			break;
+		case IPFW_VTYPE_DIVERT:
+			v->divert = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "divert";
+			break;
+		case IPFW_VTYPE_SKIPTO:
+			v->skipto = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "skipto";
+			break;
+		case IPFW_VTYPE_NETGRAPH:
+			v->netgraph = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "netgraph";
+			break;
+		case IPFW_VTYPE_FIB:
+			v->fib = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "fib";
+			break;
+		case IPFW_VTYPE_NAT:
+			v->nat = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "nat";
+			break;
+		case IPFW_VTYPE_LIMIT:
+			v->limit = strtol(n, &e, 10);
+			if (*e != '\0')
+				etype = "limit";
+			break;
+		case IPFW_VTYPE_NH4:
+			if (strchr(n, '.') != NULL &&
+			    inet_pton(AF_INET, n, &a4) == 1) {
+				v->nh4 = ntohl(a4);
+				break;
+			}
+			if (lookup_host(n, (struct in_addr *)&v->nh4) == 0)
+				break;
+			etype = "ipv4";
+			break;
+		case IPFW_VTYPE_DSCP:
+			if (isalpha(*n)) {
+				if ((v->dscp = match_token(f_ipdscp, n)) != -1)
+					break;
+				else
+					etype = "DSCP code";
+			} else {
+				v->dscp = strtol(n, &e, 10);
+				if (v->dscp > 63 || *e != '\0')
+					etype = "DSCP value";
+			}
+			break;
+		case IPFW_VTYPE_NH6:
+			if (strchr(n, ':') != NULL &&
+			    inet_pton(AF_INET6, n, &v->nh6) == 1)
+				break;
+			etype = "ipv6";
 			break;
-		/* Try hostname */
-		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
-			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
-		break;
-	case IPFW_VTYPE_DSCP:
-		if (isalpha(*arg)) {
-			if ((code = match_token(f_ipdscp, arg)) == -1)
-				errx(EX_DATAERR, "Unknown DSCP code");
-		} else {
-			code = strtoul(arg, NULL, 10);
-			if (code < 0 || code > 63)
-				errx(EX_DATAERR, "Invalid DSCP value");
 		}
-		tent->value = code;
-		break;
-	default:
-		errx(EX_OSERR, "Unsupported format type %d", vtype);
+
+		if (etype != NULL)
+			errx(EX_USAGE, "Unable to parse %s as %s", n, etype);
+
+		if (comma != NULL)
+			*comma++ = ',';
+
+		if ((n = comma) != NULL)
+			continue;
+
+		/* End of input. */
+		if (vmask != 0)
+			errx(EX_USAGE, "Not enough fields inside value");
 	}
-#endif
 }
 
 /*
@@ -1558,20 +1649,90 @@ table_show_list(ipfw_obj_header *oh, int
 }
 
 static void
+table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
+    uint32_t vmask, int print_ip)
+{
+	uint32_t flag, i, l;
+	size_t sz;
+	struct in_addr a4;
+	char abuf[INET6_ADDRSTRLEN];
+
+	sz = bufsize;
+
+	/*
+	 * Some shorthands for printing values:
+	 * legacy assumes all values are equal, so keep the first one.
+	 */
+	if (vmask == IPFW_VTYPE_LEGACY) {
+		if (print_ip != 0) {
+			flag = htonl(v->tag);
+			inet_ntop(AF_INET, &flag, buf, sz);
+		} else
+			snprintf(buf, sz, "%u", v->tag);
+		return;
+	}
+
+	for (i = 1; i < (1 << 31); i *= 2) {
+		if ((flag = (vmask & i)) == 0)
+			continue;
+		l = 0;
+
+		switch (flag) {
+		case IPFW_VTYPE_TAG:
+			l = snprintf(buf, sz, "%u,", v->tag);
+			break;
+		case IPFW_VTYPE_PIPE:
+			l = snprintf(buf, sz, "%u,", v->pipe);
+			break;
+		case IPFW_VTYPE_DIVERT:
+			l = snprintf(buf, sz, "%d,", v->divert);
+			break;
+		case IPFW_VTYPE_SKIPTO:
+			l = snprintf(buf, sz, "%d,", v->skipto);
+			break;
+		case IPFW_VTYPE_NETGRAPH:
+			l = snprintf(buf, sz, "%u,", v->netgraph);
+			break;
+		case IPFW_VTYPE_FIB:
+			l = snprintf(buf, sz, "%u,", v->fib);
+			break;
+		case IPFW_VTYPE_NAT:
+			l = snprintf(buf, sz, "%u,", v->nat);
+			break;
+		case IPFW_VTYPE_LIMIT:
+			l = snprintf(buf, sz, "%u,", v->limit);
+			break;
+		case IPFW_VTYPE_NH4:
+			a4.s_addr = htonl(v->nh4);
+			inet_ntop(AF_INET, &a4, abuf, sizeof(abuf));
+			l = snprintf(buf, sz, "%s,", abuf);
+			break;
+		case IPFW_VTYPE_DSCP:
+			l = snprintf(buf, sz, "%d,", v->dscp);
+			break;
+		case IPFW_VTYPE_NH6:
+			inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf));
+			l = snprintf(buf, sz, "%s,", abuf);
+			break;
+		}
+
+		buf += l;
+		sz -= l;
+	}
+
+	if (sz != bufsize)
+		*(buf - 1) = '\0';
+}
+
+static void
 table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
 {
-	char *comma, tbuf[128], pval[32];
+	char *comma, tbuf[128], pval[128];
 	void *paddr;
-	uint32_t tval;
 	struct tflow_entry *tfe;
 
-	tval = tent->v.value;
-
-	if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) {
-		tval = htonl(tval);
-		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
-	} else
-		snprintf(pval, sizeof(pval), "%u", tval);
+	table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask,
+	    co.do_value_as_ip);
 
 	switch (i->type) {
 	case IPFW_TABLE_ADDR:
@@ -1633,7 +1794,7 @@ table_show_entry(ipfw_xtable_info *i, ip
 }
 
 static int
-table_do_get_algolist(ipfw_obj_lheader **polh)
+table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh)
 {
 	ipfw_obj_lheader req, *olh;
 	size_t sz;
@@ -1642,7 +1803,7 @@ table_do_get_algolist(ipfw_obj_lheader *
 	memset(&req, 0, sizeof(req));
 	sz = sizeof(req);
 
-	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
+	error = do_get3(opcode, &req.opheader, &sz);
 	if (error != 0 && error != ENOMEM)
 		return (error);
 
@@ -1651,7 +1812,7 @@ table_do_get_algolist(ipfw_obj_lheader *
 		return (ENOMEM);
 
 	olh->size = sz;
-	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
+	if ((error = do_get3(opcode, &olh->opheader, &sz)) != 0) {
 		free(olh);
 		return (error);
 	}
@@ -1660,6 +1821,20 @@ table_do_get_algolist(ipfw_obj_lheader *
 	return (0);
 }
 
+static int
+table_do_get_algolist(ipfw_obj_lheader **polh)
+{
+
+	return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh));
+}
+
+static int
+table_do_get_vlist(ipfw_obj_lheader **polh)
+{
+
+	return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh));
+}
+
 void
 ipfw_list_ta(int ac, char *av[])
 {
@@ -1685,6 +1860,71 @@ ipfw_list_ta(int ac, char *av[])
 	free(olh);
 }
 
+
+/* Copy of current kernel table_value structure */
+struct _table_value {
+	uint32_t	tag;		/* O_TAG/O_TAGGED */
+	uint32_t	pipe;		/* O_PIPE/O_QUEUE */
+	uint16_t	divert;		/* O_DIVERT/O_TEE */
+	uint16_t	skipto;		/* skipto, CALLRET */
+	uint32_t	netgraph;	/* O_NETGRAPH/O_NGTEE */
+	uint32_t	fib;		/* O_SETFIB */
+	uint32_t	nat;		/* O_NAT */
+	uint32_t	nh4;
+	uint8_t		dscp;
+	uint8_t		spare0[3];
+	/* -- 32 bytes -- */
+	struct in6_addr	nh6;
+	uint32_t	limit;		/* O_LIMIT */
+	uint32_t	spare1;
+	uint64_t	refcnt;		/* Number of references */
+};
+
+int
+compare_values(const void *_a, const void *_b)
+{
+	struct _table_value *a, *b;
+
+	a = (struct _table_value *)_a;
+	b = (struct _table_value *)_b;
+
+	if (a->spare1 < b->spare1)
+		return (-1);
+	else if (a->spare1 > b->spare1)
+		return (1);
+
+	return (0);
+}
+
+void
+ipfw_list_values(int ac, char *av[])
+{
+	ipfw_obj_lheader *olh;
+	struct _table_value *v;
+	int error, i;
+	uint32_t vmask;
+	char buf[128];
+
+	error = table_do_get_vlist(&olh);
+	if (error != 0)
+		err(EX_OSERR, "Unable to request value list");
+
+	vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */
+
+	table_print_valheader(buf, sizeof(buf), vmask);
+	printf("HEADER: %s\n", buf);
+	v = (struct _table_value *)(olh + 1);
+	qsort(v, olh->count, olh->objsize, compare_values);
+	for (i = 0; i < olh->count; i++) {
+		table_show_value(buf, sizeof(buf), (ipfw_table_value *)v,
+		    vmask, 0);
+		printf("[%u] refs=%lu %s\n", v->spare1, v->refcnt, buf);
+		v = (struct _table_value *)((caddr_t)v + olh->objsize);
+	}
+
+	free(olh);
+}
+
 int
 compare_ntlv(const void *_a, const void *_b)
 {

Modified: projects/ipfw/sys/conf/files
==============================================================================
--- projects/ipfw/sys/conf/files	Sun Aug 31 23:09:23 2014	(r270905)
+++ projects/ipfw/sys/conf/files	Sun Aug 31 23:51:09 2014	(r270906)
@@ -3494,6 +3494,7 @@ netpfil/ipfw/ip_fw_pfil.c	optional inet 
 netpfil/ipfw/ip_fw_sockopt.c	optional inet ipfirewall
 netpfil/ipfw/ip_fw_table.c	optional inet ipfirewall
 netpfil/ipfw/ip_fw_table_algo.c	optional inet ipfirewall
+netpfil/ipfw/ip_fw_table_value.c	optional inet ipfirewall
 netpfil/ipfw/ip_fw_iface.c	optional inet ipfirewall
 netpfil/ipfw/ip_fw_nat.c	optional inet ipfirewall_nat
 netpfil/pf/if_pflog.c		optional pflog pf inet

Modified: projects/ipfw/sys/modules/ipfw/Makefile
==============================================================================
--- projects/ipfw/sys/modules/ipfw/Makefile	Sun Aug 31 23:09:23 2014	(r270905)
+++ projects/ipfw/sys/modules/ipfw/Makefile	Sun Aug 31 23:51:09 2014	(r270906)
@@ -8,6 +8,7 @@ KMOD=	ipfw
 SRCS=	ip_fw2.c ip_fw_pfil.c
 SRCS+=	ip_fw_dynamic.c ip_fw_log.c
 SRCS+=	ip_fw_sockopt.c ip_fw_table.c ip_fw_table_algo.c ip_fw_iface.c
+SRCS+=	ip_fw_table_value.c
 SRCS+=	opt_inet.h opt_inet6.h opt_ipdivert.h opt_ipfw.h opt_ipsec.h
 
 CFLAGS+= -DIPFIREWALL

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Sun Aug 31 23:09:23 2014	(r270905)
+++ projects/ipfw/sys/netinet/ip_fw.h	Sun Aug 31 23:51:09 2014	(r270906)
@@ -96,6 +96,7 @@ typedef struct _ip_fw3_opheader {
 #define	IP_FW_XIFLIST		107	/* list tracked interfaces */
 #define	IP_FW_TABLES_ALIST	108	/* list table algorithms */
 #define	IP_FW_TABLE_XSWAP	109	/* swap two tables */
+#define	IP_FW_TABLE_VLIST	110	/* dump table value hash */
 
 /*
  * The kernel representation of ipfw rules is made of a list of
@@ -663,11 +664,18 @@ struct _ipfw_dyn_rule {
 #define	IPFW_TABLE_CIDR	IPFW_TABLE_ADDR	/* compat */
 
 /* Value types */
-#define	IPFW_VTYPE_U32		1	/* Skipto/tablearg integer */
-
-/* Value format types */
-#define	IPFW_VFTYPE_U32		0	/* Skipto/tablearg integer */
-#define	IPFW_VFTYPE_IP		1	/* Nexthop IP address */
+#define	IPFW_VTYPE_LEGACY	0xFFFFFFFF	/* All data is filled in */
+#define	IPFW_VTYPE_SKIPTO	0x00000001	/* skipto/call/callreturn */
+#define	IPFW_VTYPE_PIPE		0x00000002	/* pipe/queue */
+#define	IPFW_VTYPE_FIB		0x00000004	/* setfib */
+#define	IPFW_VTYPE_NAT		0x00000008	/* nat */
+#define	IPFW_VTYPE_DSCP		0x00000010	/* dscp */
+#define	IPFW_VTYPE_TAG		0x00000020	/* tag/untag */
+#define	IPFW_VTYPE_DIVERT	0x00000040	/* divert/tee */
+#define	IPFW_VTYPE_NETGRAPH	0x00000080	/* netgraph/ngtee */
+#define	IPFW_VTYPE_LIMIT	0x00000100	/* IPv6 nexthop */
+#define	IPFW_VTYPE_NH4		0x00000200	/* IPv4 nexthop */
+#define	IPFW_VTYPE_NH6		0x00000400	/* IPv6 nexthop */
 
 typedef struct	_ipfw_table_entry {
 	in_addr_t	addr;		/* network address		*/
@@ -751,6 +759,23 @@ struct tflow_entry {
 	} a;
 };
 
+typedef struct _ipfw_table_value {
+	uint32_t	tag;		/* O_TAG/O_TAGGED */
+	uint32_t	pipe;		/* O_PIPE/O_QUEUE */
+	uint16_t	divert;		/* O_DIVERT/O_TEE */
+	uint16_t	skipto;		/* skipto, CALLRET */
+	uint32_t	netgraph;	/* O_NETGRAPH/O_NGTEE */
+	uint32_t	fib;		/* O_SETFIB */
+	uint32_t	nat;		/* O_NAT */
+	uint32_t	nh4;
+	uint8_t		dscp;
+	uint8_t		spare0[3];
+	struct in6_addr	nh6;
+	uint32_t	limit;		/* O_LIMIT */
+	uint32_t	spare1;
+	uint64_t	reserved;
+} ipfw_table_value;
+
 /* Table entry TLV */
 typedef struct	_ipfw_obj_tentry {
 	ipfw_obj_tlv	head;		/* TLV header			*/
@@ -769,8 +794,8 @@ typedef struct	_ipfw_obj_tentry {
 		struct tflow_entry	flow;	
 	} k;
 	union {
-		uint32_t		value;	/* 32-bit value */
-		char			storage[64]; /* Future needs	*/
+		ipfw_table_value	value;	/* value data */
+		uint32_t		kidx;	/* value kernel index */
 	} v;
 } ipfw_obj_tentry;
 #define	IPFW_TF_UPDATE	0x01		/* Update record if exists	*/
@@ -839,10 +864,10 @@ typedef struct _ipfw_ta_tinfo {
 typedef struct _ipfw_xtable_info {
 	uint8_t		type;		/* table type (addr,iface,..)	*/
 	uint8_t		tflags;		/* type flags			*/
-	uint8_t		vtype;		/* value type (u32)		*/
-	uint8_t		vftype;		/* value format type (ip,number)*/
 	uint16_t	mflags;		/* modification flags		*/
 	uint16_t	flags;		/* generic table flags		*/
+	uint16_t	spare[3];
+	uint32_t	vmask;		/* bitmask with value types 	*/
 	uint32_t	set;		/* set table is in		*/
 	uint32_t	kidx;		/* kernel index			*/
 	uint32_t	refcnt;		/* number of references		*/
@@ -862,7 +887,6 @@ typedef struct _ipfw_xtable_info {
 #define	IPFW_TFFLAG_DSTPORT	0x08
 #define	IPFW_TFFLAG_PROTO	0x10
 /* Table modification flags */
-#define	IPFW_TMFLAGS_FTYPE	0x0001	/* Change ftype field		*/
 #define	IPFW_TMFLAGS_LIMIT	0x0002	/* Change limit value		*/
 #define	IPFW_TMFLAGS_LOCK	0x0004	/* Change table lock state	*/
 

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Sun Aug 31 23:09:23 2014	(r270905)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Sun Aug 31 23:51:09 2014	(r270906)
@@ -817,7 +817,7 @@ jump_fast(struct ip_fw_chain *chain, str
 	if (num != IP_FW_TARG && f->cached_id == chain->id)
 		f_pos = f->cached_pos;
 	else {
-		int i = IP_FW_ARG_TABLEARG(num);
+		int i = IP_FW_ARG_TABLEARG(chain, num, skipto);
 		/* make sure we do not jump backward */
 		if (jump_backwards == 0 && i <= f->rulenum)
 			i = f->rulenum + 1;
@@ -844,7 +844,7 @@ jump_linear(struct ip_fw_chain *chain, s
 {
 	int f_pos;
 
-	num = IP_FW_ARG_TABLEARG(num);
+	num = IP_FW_ARG_TABLEARG(chain, num, skipto);
 	/* make sure we do not jump backward */
 	if (jump_backwards == 0 && num <= f->rulenum)
 		num = f->rulenum + 1;
@@ -853,6 +853,7 @@ jump_linear(struct ip_fw_chain *chain, s
 	return (f_pos);
 }
 
+#define	TARG(k, f)	IP_FW_ARG_TABLEARG(chain, k, f)
 /*
  * The main check routine for the firewall.
  *
@@ -1841,7 +1842,7 @@ do {								\
 			}
 
 			case O_LOG:
-				ipfw_log(f, hlen, args, m,
+				ipfw_log(chain, f, hlen, args, m,
 				    oif, offset | ip6f_mf, tablearg, ip);
 				match = 1;
 				break;
@@ -1963,7 +1964,7 @@ do {								\
 
 			case O_TAG: {
 				struct m_tag *mtag;
-				uint32_t tag = IP_FW_ARG_TABLEARG(cmd->arg1);
+				uint32_t tag = TARG(cmd->arg1, tag);
 
 				/* Packet is already tagged with this tag? */
 				mtag = m_tag_locate(m, MTAG_IPFW, tag, NULL);
@@ -2044,7 +2045,7 @@ do {								\

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-projects mailing list