svn commit: r269706 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw

Alexander V. Chernikov melifaro at FreeBSD.org
Fri Aug 8 09:27:51 UTC 2014


Author: melifaro
Date: Fri Aug  8 09:27:49 2014
New Revision: 269706
URL: http://svnweb.freebsd.org/changeset/base/269706

Log:
  * Add IP_FW_TABLE_XMODIFY opcode
  * Since there seems to be lack of consensus on strict value typing,
    remove non-default value types. Use userland-only "value format type"
    to print values.
  
  Kernel changes:
  * Add IP_FW_XMODIFY to permit table run-time modifications.
    Currently we support changing limit and value format type.
  
  Userland changes:
  * Support IP_FW_XMODIFY opcode.
  * Support specifying value format type (ftype) in tablble create/modify req
  * Fine-print value type/value format type.

Modified:
  projects/ipfw/sbin/ipfw/ipfw2.h
  projects/ipfw/sbin/ipfw/tables.c
  projects/ipfw/sys/netinet/ip_fw.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

Modified: projects/ipfw/sbin/ipfw/ipfw2.h
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.h	Fri Aug  8 09:17:02 2014	(r269705)
+++ projects/ipfw/sbin/ipfw/ipfw2.h	Fri Aug  8 09:27:49 2014	(r269706)
@@ -215,6 +215,7 @@ enum tokens {
 	TOK_LIST,
 	TOK_INFO,
 	TOK_DETAIL,
+	TOK_MODIFY,
 	TOK_FLUSH,
 	TOK_SWAP,
 	TOK_ADD,
@@ -222,6 +223,7 @@ enum tokens {
 	TOK_VALTYPE,
 	TOK_ALGO,
 	TOK_TALIST,
+	TOK_FTYPE,
 };
 /*
  * the following macro returns an error message if we run out of

Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c	Fri Aug  8 09:17:02 2014	(r269705)
+++ projects/ipfw/sbin/ipfw/tables.c	Fri Aug  8 09:27:49 2014	(r269706)
@@ -54,9 +54,11 @@ static void table_modify_record(ipfw_obj
 static int table_flush(ipfw_obj_header *oh);
 static int table_destroy(ipfw_obj_header *oh);
 static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
+static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i);
+static int table_do_swap(ipfw_obj_header *oh, char *second);
 static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
+static void table_modify(ipfw_obj_header *oh, int ac, char *av[]);
 static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
-static int table_do_swap(ipfw_obj_header *oh, char *second);
 static int table_swap(ipfw_obj_header *oh, char *second);
 static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
 static int table_show_info(ipfw_xtable_info *i, void *arg);
@@ -90,18 +92,23 @@ static struct _s_x tabletypes[] = {
 };
 
 static struct _s_x tablevaltypes[] = {
-      { "dscp",		IPFW_VTYPE_DSCP },
-      { "ip",		IPFW_VTYPE_IP },
       { "number",	IPFW_VTYPE_U32 },
       { NULL, 0 }
 };
 
+static struct _s_x tablefvaltypes[] = {
+      { "ip",		IPFW_VFTYPE_IP },
+      { "number",	IPFW_VFTYPE_U32 },
+      { NULL, 0 }
+};
+
 static struct _s_x tablecmds[] = {
       { "add",		TOK_ADD },
       { "delete",	TOK_DEL },
       { "create",	TOK_CREATE },
       { "destroy",	TOK_DESTROY },
       { "flush",	TOK_FLUSH },
+      { "modify",	TOK_MODIFY },
       { "swap",		TOK_SWAP },
       { "info",		TOK_INFO },
       { "detail",	TOK_DETAIL },
@@ -192,6 +199,10 @@ ipfw_table_handler(int ac, char *av[])
 		ac--; av++;
 		table_create(&oh, ac, av);
 		break;
+	case TOK_MODIFY:
+		ac--; av++;
+		table_modify(&oh, ac, av);
+		break;
 	case TOK_DESTROY:
 		if (table_destroy(&oh) != 0)
 			err(EX_OSERR, "failed to destroy table %s", tablename);
@@ -265,6 +276,7 @@ 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 },
@@ -330,8 +342,6 @@ table_print_type(char *tbuf, size_t size
  * ipfw table NAME create [ type { cidr | iface | u32 } ]
  *     [ valtype { number | ip | dscp } ]
  *     [ algo algoname ]
- *
- * Request: [ ipfw_obj_header ipfw_xtable_info ]
  */
 static void
 table_create(ipfw_obj_header *oh, int ac, char *av[])
@@ -394,6 +404,18 @@ table_create(ipfw_obj_header *oh, int ac
 			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);
+			break;
 		case TOK_ALGO:
 			NEED1("table algorithm name required");
 			if (strlen(*av) > sizeof(xi.algoname))
@@ -431,6 +453,79 @@ table_do_create(ipfw_obj_header *oh, ipf
 }
 
 /*
+ * Modifies existing table
+ *
+ * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ]
+ */
+static void
+table_modify(ipfw_obj_header *oh, int ac, char *av[])
+{
+	ipfw_xtable_info xi;
+	int error, tcmd, val;
+	size_t sz;
+	char tbuf[128];
+
+	sz = sizeof(tbuf);
+	memset(&xi, 0, sizeof(xi));
+
+	/* Set some defaults to preserve compability */
+	xi.type = IPFW_TABLE_CIDR;
+	xi.vtype = IPFW_VTYPE_U32;
+
+	while (ac > 0) {
+		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
+			errx(EX_USAGE, "unknown option: %s", *av);
+		ac--; av++;
+
+		switch (tcmd) {
+		case TOK_LIMIT:
+			NEED1("limit value required");
+			xi.limit = strtol(*av, NULL, 10);
+			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;
+		}
+	}
+
+	if ((error = table_do_modify(oh, &xi)) != 0)
+		err(EX_OSERR, "Table modification failed");
+}
+
+/*
+ * Modifies existing table.
+ *
+ * Request: [ ipfw_obj_header ipfw_xtable_info ]
+ *
+ * Returns 0 on success.
+ */
+static int
+table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
+{
+	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
+	int error;
+
+	memcpy(tbuf, oh, sizeof(*oh));
+	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
+	oh = (ipfw_obj_header *)tbuf;
+
+	error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
+
+	return (error);
+}
+/*
  * Destroys given table specified by @oh->ntlv.
  * Returns 0 on success.
  */
@@ -584,19 +679,25 @@ table_show_tainfo(ipfw_xtable_info *i, s
 static int
 table_show_info(ipfw_xtable_info *i, void *arg)
 {
-	const char *vtype;
+	const char *vtype, *vftype;
 	ipfw_ta_tinfo *tainfo;
 	int afdata, afitem;
 	struct ta_cldata d;
-	char ttype[64];
+	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);
 
 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
 	printf(" kindex: %d, type: %s\n", i->kidx, ttype);
-	printf(" valtype: %s, references: %u\n", vtype, i->refcnt);
+	printf(" valtype: %s, references: %u\n", tvtype, i->refcnt);
 	printf(" algorithm: %s\n", i->algoname);
 	printf(" items: %u, size: %u\n", i->count, i->size);
 	if (i->limit > 0)
@@ -1092,9 +1193,22 @@ static void
 tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
     uint8_t type, uint8_t vtype)
 {
-	int code;
+	uint32_t val;
 	char *p;
 
+	/* Try to interpret as number first */
+	tent->value = strtoul(arg, &p, 0);
+	if (*p == '\0')
+		return;
+	if (inet_pton(AF_INET, arg, &val) == 1) {
+		tent->value = ntohl(val);
+		return;
+	}
+	/* Try hostname */
+	if (lookup_host(arg, (struct in_addr *)&tent->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);
@@ -1122,6 +1236,7 @@ tentry_fill_value(ipfw_obj_header *oh, i
 	default:
 		errx(EX_OSERR, "Unsupported format type %d", vtype);
 	}
+#endif
 }
 
 /*
@@ -1250,7 +1365,7 @@ table_show_entry(ipfw_xtable_info *i, ip
 
 	tval = tent->value;
 
-	if (co.do_value_as_ip) {
+	if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) {
 		tval = htonl(tval);
 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
 	} else

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Fri Aug  8 09:17:02 2014	(r269705)
+++ projects/ipfw/sys/netinet/ip_fw.h	Fri Aug  8 09:27:49 2014	(r269706)
@@ -83,7 +83,7 @@ typedef struct _ip_fw3_opheader {
 #define	IP_FW_TABLE_XINFO	93	/* request info for one table */
 #define	IP_FW_TABLE_XFLUSH	94	/* flush table data */
 #define	IP_FW_TABLE_XCREATE	95	/* create new table  */
-//#define	IP_FW_TABLE_XMODIFY	96	/* modify existing table */
+#define	IP_FW_TABLE_XMODIFY	96	/* modify existing table */
 #define	IP_FW_XGET		97	/* Retrieve configuration */
 #define	IP_FW_XADD		98	/* add rule */
 #define	IP_FW_XDEL		99	/* del rule */
@@ -686,9 +686,12 @@ struct _ipfw_dyn_rule {
 #define	IPFW_TABLE_FLOW		4	/* Table for holding flow data */
 #define	IPFW_TABLE_MAXTYPE	4	/* Maximum valid number */
 
+/* Value types */
 #define	IPFW_VTYPE_U32		1	/* Skipto/tablearg integer */
-#define	IPFW_VTYPE_IP		2	/* Nexthop IP address */
-#define	IPFW_VTYPE_DSCP		3	/* DiffServ codepoints */
+
+/* Value format types */
+#define	IPFW_VFTYPE_U32		0	/* Skipto/tablearg integer */
+#define	IPFW_VFTYPE_IP		1	/* Nexthop IP address */
 
 typedef struct	_ipfw_table_entry {
 	in_addr_t	addr;		/* network address		*/
@@ -844,15 +847,16 @@ typedef struct _ipfw_ta_tinfo {
 typedef struct _ipfw_xtable_info {
 	uint8_t		type;		/* table type (cidr,iface,..)	*/
 	uint8_t		tflags;		/* type flags			*/
-	uint8_t		ftype;		/* table value format type	*/
-	uint8_t		vtype;		/* value type			*/
+	uint8_t		vtype;		/* value type (u32)		*/
+	uint8_t		vftype;		/* value format type (ip,number)*/
+	uint16_t	mflags;		/* modification flags		*/
+	uint16_t	spare;
 	uint32_t	set;		/* set table is in		*/
 	uint32_t	kidx;		/* kernel index			*/
 	uint32_t	refcnt;		/* number of references		*/
 	uint32_t	count;		/* Number of records		*/
 	uint32_t	size;		/* Total size of records(export)*/
 	uint32_t	limit;		/* Max number of records	*/
-	uint32_t	spare;
 	char		tablename[64];	/* table name */
 	char		algoname[64];	/* algorithm name		*/
 	ipfw_ta_tinfo	ta_info;	/* additional algo stats	*/
@@ -862,6 +866,8 @@ typedef struct _ipfw_xtable_info {
 #define	IPFW_TFFLAG_SRCPORT	0x04
 #define	IPFW_TFFLAG_DSTPORT	0x08
 #define	IPFW_TFFLAG_PROTO	0x10
+#define	IPFW_TMFLAGS_FTYPE	0x01	/* Change ftype field		*/
+#define	IPFW_TMFLAGS_LIMIT	0x02	/* Change limit value		*/
 
 typedef struct _ipfw_iface_info {
 	char		ifname[64];	/* interface name		*/

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Fri Aug  8 09:17:02 2014	(r269705)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Fri Aug  8 09:27:49 2014	(r269706)
@@ -2321,6 +2321,10 @@ ipfw_ctl3(struct sockopt *sopt)
 		error = ipfw_flush_table(chain, op3, &sdata);
 		break;
 
+	case IP_FW_TABLE_XMODIFY:
+		error = ipfw_modify_table(chain, op3, &sdata);
+		break;
+
 	case IP_FW_TABLE_XINFO:
 		error = ipfw_describe_table(chain, &sdata);
 		break;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Fri Aug  8 09:17:02 2014	(r269705)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Fri Aug  8 09:27:49 2014	(r269706)
@@ -73,12 +73,16 @@ __FBSDID("$FreeBSD$");
  */
 struct table_config {
 	struct named_object	no;
-	uint8_t		vtype;		/* format table type */
-	uint8_t		linked;		/* 1 if already linked */
+	uint8_t		vtype;		/* value type */
+	uint8_t		vftype;		/* value format type */
 	uint8_t		tflags;		/* type flags */
-	uint8_t		ochanged;	/* used by set swapping */
+	uint8_t		spare0;	
 	uint32_t	count;		/* Number of records */
 	uint32_t	limit;		/* Max number of records */
+	uint8_t		linked;		/* 1 if already linked */
+	uint8_t		ochanged;	/* used by set swapping */
+	uint16_t	spare1;
+	uint32_t	spare2;
 	uint32_t	ocount;		/* used by set swapping */
 	uint64_t	gencnt;		/* generation count */
 	char		tablename[64];	/* table name */
@@ -168,7 +172,7 @@ add_table_entry(struct ip_fw_chain *ch, 
 		}
 
 		/* Try to exit early on limit hit */
-		if (tc->limit != 0 && tc->count == tc->limit &&
+		if (tc->limit != 0 && tc->count >= tc->limit &&
 		    (tei->flags & TEI_FLAGS_UPDATE) == 0) {
 				IPFW_UH_WUNLOCK(ch);
 				return (EFBIG);
@@ -239,7 +243,7 @@ add_table_entry(struct ip_fw_chain *ch, 
 	tc->no.refcnt--;
 	
 	/* Check limit before adding */
-	if (tc->limit != 0 && tc->count == tc->limit) {
+	if (tc->limit != 0 && tc->count >= tc->limit) {
 		if ((tei->flags & TEI_FLAGS_UPDATE) == 0) {
 			IPFW_UH_WUNLOCK(ch);
 			ta->flush_entry(ch, tei, &ta_buf);
@@ -1335,6 +1339,56 @@ ipfw_dump_table_v0(struct ip_fw_chain *c
 }
 
 /*
+ * Modifies existing table.
+ * Data layout (v0)(current):
+ * Request: [ ipfw_obj_header ipfw_xtable_info ]
+ *
+ * Returns 0 on success
+ */
+int
+ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd)
+{
+	struct _ipfw_obj_header *oh;
+	ipfw_xtable_info *i;
+	char *tname;
+	struct tid_info ti;
+	struct namedobj_instance *ni;
+	struct table_config *tc;
+
+	if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
+		return (EINVAL);
+
+	oh = (struct _ipfw_obj_header *)sd->kbuf;
+	i = (ipfw_xtable_info *)(oh + 1);
+
+	/*
+	 * Verify user-supplied strings.
+	 * Check for null-terminated/zero-length strings/
+	 */
+	tname = oh->ntlv.name;
+	if (ipfw_check_table_name(tname) != 0)
+		return (EINVAL);
+
+	objheader_to_ti(oh, &ti);
+	ti.type = i->type;
+
+	IPFW_UH_WLOCK(ch);
+	ni = CHAIN_TO_NI(ch);
+	if ((tc = find_table(ni, &ti)) == NULL) {
+		IPFW_UH_WUNLOCK(ch);
+		return (ESRCH);
+	}
+	if ((i->mflags & IPFW_TMFLAGS_FTYPE) != 0)
+		tc->vftype = i->vftype;
+	if ((i->mflags & IPFW_TMFLAGS_LIMIT) != 0)
+		tc->limit = i->limit;
+	IPFW_UH_WUNLOCK(ch);
+
+	return (0);
+}
+
+/*
  * Creates new table.
  * Data layout (v0)(current):
  * Request: [ ipfw_obj_header ipfw_xtable_info ]
@@ -1415,6 +1469,7 @@ create_table_internal(struct ip_fw_chain
 	if (tc == NULL)
 		return (ENOMEM);
 
+	tc->vftype = i->vftype;
 	tc->limit = i->limit;
 
 	IPFW_UH_WLOCK(ch);
@@ -1498,6 +1553,7 @@ export_table_info(struct ip_fw_chain *ch
 	i->type = tc->no.type;
 	i->tflags = tc->tflags;
 	i->vtype = tc->vtype;
+	i->vftype = tc->vftype;
 	i->set = tc->no.set;
 	i->kidx = tc->no.kidx;
 	i->refcnt = tc->no.refcnt;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Fri Aug  8 09:17:02 2014	(r269705)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Fri Aug  8 09:27:49 2014	(r269706)
@@ -146,6 +146,8 @@ int ipfw_find_table_entry(struct ip_fw_c
     struct sockopt_data *sd);
 int ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd);
+int ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
 int ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd);
 int ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,


More information about the svn-src-projects mailing list