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

Alexander V. Chernikov melifaro at FreeBSD.org
Sun Jul 6 23:26:36 UTC 2014


Author: melifaro
Date: Sun Jul  6 23:26:34 2014
New Revision: 268347
URL: http://svnweb.freebsd.org/changeset/base/268347

Log:
  * Prepare to pass other dynamic states via ipfw_dump_config()
  
  Kernel changes:
  * Change dump format for dynamic states:
    each state is now stored inside ipfw_obj_dyntlv
    last dynamic state is indicated by IPFW_DF_LAST flag
  * Do not perform sooptcopyout() for !SOPT_GET requests.
  
  Userland changes:
  * Introduce foreach_state() function handler to ease work
    with different states passed by ipfw_dump_config().

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

Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c	Sun Jul  6 23:24:06 2014	(r268346)
+++ projects/ipfw/sbin/ipfw/ipfw2.c	Sun Jul  6 23:26:34 2014	(r268347)
@@ -64,6 +64,7 @@ struct format_opts {
 	uint32_t flags;		/* request flags */
 	uint32_t first;		/* first rule to request */
 	uint32_t last;		/* last rule to request */
+	uint32_t dcnt;		/* number of dynamic states */
 	ipfw_obj_ctlv *tstate;	/* table state data */
 };
 
@@ -2161,13 +2162,85 @@ ipfw_sysctl_handler(char *av[], int whic
 	}
 }
 
+typedef void state_cb(struct cmdline_opts *co, struct format_opts *fo,
+    void *arg, void *state);
+
+static void
+prepare_format_dyn(struct cmdline_opts *co, struct format_opts *fo,
+    void *arg, void *_state)
+{
+	ipfw_dyn_rule *d;
+	int width;
+	uint8_t set;
+
+	d = (ipfw_dyn_rule *)_state;
+	/* Count _ALL_ states */
+	fo->dcnt++;
+
+	if (co->use_set) {
+		/* skip states from another set */
+		bcopy((char *)&d->rule + sizeof(uint16_t), &set,
+		    sizeof(uint8_t));
+		if (set != co->use_set - 1)
+			return;
+	}
+
+	width = pr_u64(NULL, &d->pcnt, 0);
+	if (width > fo->pcwidth)
+		fo->pcwidth = width;
+
+	width = pr_u64(NULL, &d->bcnt, 0);
+	if (width > fo->bcwidth)
+		fo->bcwidth = width;
+}
+
+static int
+foreach_state(struct cmdline_opts *co, struct format_opts *fo,
+    caddr_t base, size_t sz, state_cb dyn_bc, void *dyn_arg)
+{
+	int ttype;
+	state_cb *fptr;
+	void *farg;
+	ipfw_obj_tlv *tlv;
+	ipfw_obj_ctlv *ctlv;
+
+	fptr = NULL;
+	ttype = 0;
+
+	while (sz > 0) {
+		ctlv = (ipfw_obj_ctlv *)base;
+		switch (ctlv->head.type) {
+		case IPFW_TLV_DYNSTATE_LIST:
+			base += sizeof(*ctlv);
+			sz -= sizeof(*ctlv);
+			ttype = IPFW_TLV_DYN_ENT;
+			fptr = dyn_bc;
+			farg = dyn_arg;
+			break;
+		default:
+			return (sz);
+		}
+
+		while (sz > 0) {
+			tlv = (ipfw_obj_tlv *)base;
+			if (tlv->type != ttype)
+				break;
+
+			fptr(co, fo, farg, tlv + 1);
+			sz -= tlv->length;
+			base += tlv->length;
+		}
+	}
+
+	return (sz);
+}
+
 static void
 prepare_format_opts(struct cmdline_opts *co, struct format_opts *fo,
-    struct ip_fw *r, ipfw_dyn_rule *d, int rcnt, int dcnt)
+    struct ip_fw *r, int rcnt, caddr_t base, size_t sz)
 {
 	int bcwidth, pcwidth, width;
 	int n;
-	uint32_t set;
 #define NEXT(r)	((struct ip_fw *)((char *)r + RULESIZE(r)))
 
 	bcwidth = 0;
@@ -2189,31 +2262,16 @@ prepare_format_opts(struct cmdline_opts 
 				bcwidth = width;
 		}
 	}
-	if (co->do_dynamic && dcnt > 0) {
-		for (n = 0; n < dcnt; n++, d++) {
-			if (co->use_set) {
-				/* skip rules from another set */
-				bcopy((char *)&d->rule + sizeof(uint16_t),
-				      &set, sizeof(uint8_t));
-				if (set != co->use_set - 1)
-					continue;
-			}
-			width = pr_u64(NULL, &d->pcnt, 0);
-			if (width > pcwidth)
-				pcwidth = width;
-
-			width = pr_u64(NULL, &d->bcnt, 0);
-			if (width > bcwidth)
-				bcwidth = width;
-		}
-	}
-
 	fo->bcwidth = bcwidth;
 	fo->pcwidth = pcwidth;
+
+	fo->dcnt = 0;
+	if (co->do_dynamic && sz > 0)
+		sz = foreach_state(co, fo, base, sz, prepare_format_dyn, NULL);
 }
 
 static int
-ipfw_list_static_range(struct cmdline_opts *co, struct format_opts *fo,
+list_static_range(struct cmdline_opts *co, struct format_opts *fo,
     struct buf_pr *bp, struct ip_fw *r, int rcnt)
 {
 	int n, seen;
@@ -2234,35 +2292,42 @@ ipfw_list_static_range(struct cmdline_op
 }
 
 static void
-ipfw_list_dyn_range(struct cmdline_opts *co, struct format_opts *fo,
-    struct buf_pr *bp, ipfw_dyn_rule *d, int dcnt, int objsize)
+list_dyn_state(struct cmdline_opts *co, struct format_opts *fo,
+    void *_arg, void *_state)
 {
-	int n;
-	uint8_t set;
 	uint16_t rulenum;
+	uint8_t set;
+	ipfw_dyn_rule *d;
+	struct buf_pr *bp;
 
-	for (n = 0; n < dcnt; n++) {
-		bcopy(&d->rule, &rulenum, sizeof(rulenum));
-		if (rulenum > fo->last)
-			break;
-		if (co->use_set) {
-			bcopy((char *)&d->rule + sizeof(uint16_t),
-			      &set, sizeof(uint8_t));
-			if (set != co->use_set - 1) {
-				d = (ipfw_dyn_rule *)((caddr_t)d + objsize);
-				continue;
-			}
-		}
-		if (rulenum >= fo->first) {
-			show_dyn_state(co, fo, bp, d);
-			printf("%s\n", bp->buf);
-			bp_flush(bp);
-		}
+	d = (ipfw_dyn_rule *)_state;
+	bp = (struct buf_pr *)_arg;
 
-		d = (ipfw_dyn_rule *)((caddr_t)d + objsize);
+	bcopy(&d->rule, &rulenum, sizeof(rulenum));
+	if (rulenum > fo->last)
+		return;
+	if (co->use_set) {
+		bcopy((char *)&d->rule + sizeof(uint16_t),
+		      &set, sizeof(uint8_t));
+		if (set != co->use_set - 1)
+			return;
+	}
+	if (rulenum >= fo->first) {
+		show_dyn_state(co, fo, bp, d);
+		printf("%s\n", bp->buf);
+		bp_flush(bp);
 	}
 }
 
+static int
+list_dyn_range(struct cmdline_opts *co, struct format_opts *fo,
+    struct buf_pr *bp, caddr_t base, size_t sz)
+{
+
+	sz = foreach_state(co, fo, base, sz, list_dyn_state, bp);
+	return (sz);
+}
+
 void
 ipfw_list(int ac, char *av[], int show_counters)
 {
@@ -2325,13 +2390,14 @@ ipfw_show_config(struct cmdline_opts *co
     ipfw_cfg_lheader *cfg, size_t sz, int ac, char *av[])
 {
 	struct ip_fw *rbase;
-	ipfw_dyn_rule *dynbase;
-	int rcnt, dcnt;
+	caddr_t dynbase;
+	size_t dynsz;
+	int rcnt;
 	int exitval = EX_OK;
 	int lac;
 	char **lav;
 	char *endptr;
-	size_t dobjsz, read;
+	size_t read;
 	struct buf_pr bp;
 	ipfw_obj_ctlv *ctlv, *tstate;
 
@@ -2341,7 +2407,7 @@ ipfw_show_config(struct cmdline_opts *co
 	tstate = NULL;
 	rbase = NULL;
 	dynbase = NULL;
-	dobjsz = 0;
+	dynsz = 0;
 	read = 0;
 
 	ctlv = (ipfw_obj_ctlv *)(cfg + 1);
@@ -2365,26 +2431,23 @@ ipfw_show_config(struct cmdline_opts *co
 	}
 
 	if ((cfg->flags & IPFW_CFG_GET_STATES) && (read != sz))  {
-		/* We may have some dynamic rules */
-		read += sizeof(ipfw_obj_ctlv);
-		dobjsz = ctlv->objsize;
-		dcnt = (sz - read) / dobjsz;
-		if (dcnt != 0)
-			dynbase = (ipfw_dyn_rule *)(ctlv + 1);
+		/* We may have some dynamic states */
+		dynbase = (caddr_t)ctlv;
+		dynsz = sz - read;
 	}
 
-	prepare_format_opts(co, fo, rbase, dynbase, rcnt, dcnt);
+	prepare_format_opts(co, fo, rbase, rcnt, dynbase, dynsz);
 	bp_alloc(&bp, 4096);
 
 	/* if no rule numbers were specified, list all rules */
 	if (ac == 0) {
 		fo->first = 0;
 		fo->last = IPFW_DEFAULT_RULE;
-		ipfw_list_static_range(co, fo, &bp, rbase, rcnt);
+		list_static_range(co, fo, &bp, rbase, rcnt);
 
-		if (co->do_dynamic && dcnt) {
-			printf("## Dynamic rules (%d):\n", dcnt);
-			ipfw_list_dyn_range(co, fo, &bp, dynbase, dcnt, dobjsz);
+		if (co->do_dynamic && dynsz > 0) {
+			printf("## Dynamic rules (%d):\n", fo->dcnt);
+			list_dyn_range(co, fo, &bp, dynbase, dynsz);
 		}
 
 		bp_free(&bp);
@@ -2403,7 +2466,7 @@ ipfw_show_config(struct cmdline_opts *co
 			continue;
 		}
 
-		if (ipfw_list_static_range(co, fo, &bp, rbase, rcnt) == 0) {
+		if (list_static_range(co, fo, &bp, rbase, rcnt) == 0) {
 			/* give precedence to other error(s) */
 			if (exitval == EX_OK)
 				exitval = EX_UNAVAILABLE;
@@ -2415,7 +2478,7 @@ ipfw_show_config(struct cmdline_opts *co
 		}
 	}
 
-	if (co->do_dynamic && dcnt > 0) {
+	if (co->do_dynamic && dynsz > 0) {
 		printf("## Dynamic rules:\n");
 		for (lac = ac, lav = av; lac != 0; lac--) {
 			fo->last = fo->first = strtoul(*lav++, &endptr, 10);
@@ -2424,7 +2487,7 @@ ipfw_show_config(struct cmdline_opts *co
 			if (*endptr)
 				/* already warned */
 				continue;
-			ipfw_list_dyn_range(co, fo, &bp, dynbase, dcnt, dobjsz);
+			list_dyn_range(co, fo, &bp, dynbase, dynsz);
 		}
 	}
 

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Sun Jul  6 23:24:06 2014	(r268346)
+++ projects/ipfw/sys/netinet/ip_fw.h	Sun Jul  6 23:26:34 2014	(r268347)
@@ -695,8 +695,9 @@ typedef struct  _ipfw_obj_tlv {
 #define	IPFW_TLV_TBL_NAME	1
 #define	IPFW_TLV_TBLNAME_LIST	2
 #define	IPFW_TLV_RULE_LIST	3
-#define	IPFW_TLV_STATE_LIST	4
+#define	IPFW_TLV_DYNSTATE_LIST	4
 #define	IPFW_TLV_TBL_ENT	5
+#define	IPFW_TLV_DYN_ENT	6
 
 /* Object name TLV */
 typedef struct _ipfw_obj_ntlv {
@@ -726,6 +727,12 @@ typedef struct	_ipfw_obj_tentry {
 } ipfw_obj_tentry;
 #define	IPFW_TF_UPDATE	0x01		/* Update record if exists	*/
 
+typedef struct _ipfw_obj_dyntlv {
+	ipfw_obj_tlv	head;
+	ipfw_dyn_rule	state;
+} ipfw_obj_dyntlv;
+#define	IPFW_DF_LAST	0x01		/* Last state in chain		*/
+
 /* Containter TLVs */
 typedef struct _ipfw_obj_ctlv {
 	ipfw_obj_tlv	head;		/* TLV header			*/

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c	Sun Jul  6 23:24:06 2014	(r268346)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c	Sun Jul  6 23:26:34 2014	(r268347)
@@ -1444,7 +1444,7 @@ sysctl_ipfw_dyn_count(SYSCTL_HANDLER_ARG
 #endif
 
 /*
- * Returns number of dynamic rules.
+ * Returns size of dynamic states in legacy format
  */
 int
 ipfw_dyn_len(void)
@@ -1454,6 +1454,17 @@ ipfw_dyn_len(void)
 		(DYN_COUNT * sizeof(ipfw_dyn_rule));
 }
 
+/*
+ * Returns number of dynamic states.
+ * Used by dump format v1 (current).
+ */
+int
+ipfw_dyn_get_count(void)
+{
+
+	return (V_ipfw_dyn_v == NULL) ? 0 : DYN_COUNT;
+}
+
 static void
 export_dyn_rule(ipfw_dyn_rule *src, ipfw_dyn_rule *dst)
 {
@@ -1479,15 +1490,18 @@ export_dyn_rule(ipfw_dyn_rule *src, ipfw
 
 /*
  * Fills int buffer given by @sd with dynamic states.
+ * Used by dump format v1 (current).
  *
  * Returns 0 on success.
  */
 int
 ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd)
 {
-	ipfw_dyn_rule *p, *dst, *last = NULL;
+	ipfw_dyn_rule *p;
+	ipfw_obj_dyntlv *dst, *last;
 	ipfw_obj_ctlv *ctlv;
 	int i;
+	size_t sz;
 
 	if (V_ipfw_dyn_v == NULL)
 		return (0);
@@ -1497,33 +1511,36 @@ ipfw_dump_states(struct ip_fw_chain *cha
 	ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
 	if (ctlv == NULL)
 		return (ENOMEM);
-	ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
-	ctlv->objsize = sizeof(ipfw_dyn_rule);
+	sz = sizeof(ipfw_obj_dyntlv);
+	ctlv->head.type = IPFW_TLV_DYNSTATE_LIST;
+	ctlv->objsize = sz;
+	last = NULL;
 
 	for (i = 0 ; i < V_curr_dyn_buckets; i++) {
 		IPFW_BUCK_LOCK(i);
 		for (p = V_ipfw_dyn_v[i].head ; p != NULL; p = p->next) {
-			dst = (ipfw_dyn_rule *)ipfw_get_sopt_space(sd,
-			    sizeof(*dst));
+			dst = (ipfw_obj_dyntlv *)ipfw_get_sopt_space(sd, sz);
 			if (dst == NULL) {
 				IPFW_BUCK_UNLOCK(i);
 				return (ENOMEM);
 			}
 
-			export_dyn_rule(p, dst);
+			export_dyn_rule(p, &dst->state);
+			dst->head.length = sz;
+			dst->head.type = IPFW_TLV_DYN_ENT;
 			last = dst;
 		}
 		IPFW_BUCK_UNLOCK(i);
 	}
 
 	if (last != NULL) /* mark last dynamic rule */
-		bzero(&last->next, sizeof(last));
+		last->head.flags = IPFW_DF_LAST;
 
 	return (0);
 }
 
 /*
- * Fill given buffer with dynamic states.
+ * Fill given buffer with dynamic states (legacy format).
  * IPFW_UH_RLOCK has to be held while calling.
  */
 void

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Sun Jul  6 23:24:06 2014	(r268346)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Sun Jul  6 23:26:34 2014	(r268347)
@@ -194,6 +194,7 @@ int ipfw_dump_states(struct ip_fw_chain 
 void ipfw_dyn_init(struct ip_fw_chain *);	/* per-vnet initialization */
 void ipfw_dyn_uninit(int);	/* per-vnet deinitialization */
 int ipfw_dyn_len(void);
+int ipfw_dyn_get_count(void);
 
 /* common variables */
 VNET_DECLARE(int, fw_one_pass);

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Jul  6 23:24:06 2014	(r268346)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Jul  6 23:26:34 2014	(r268347)
@@ -1201,9 +1201,8 @@ dump_config(struct ip_fw_chain *chain, s
 		sz += da.rsize + sizeof(ipfw_obj_ctlv);
 	}
 
-	if (hdr->flags & IPFW_CFG_GET_STATES) {
-		sz += ipfw_dyn_len();
-	}
+	if (hdr->flags & IPFW_CFG_GET_STATES)
+		sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv);
 
 	/* Fill header anyway */
 	hdr->size = sz;
@@ -1916,8 +1915,11 @@ ipfw_flush_sopt_data(struct sockopt_data
 	if (sd->koff == 0)
 		return (0);
 
-	if ((error = sooptcopyout(sd->sopt, sd->kbuf, sd->koff)) != 0)
-		return (error);
+	if (sd->sopt->sopt_dir == SOPT_GET) {
+		error = sooptcopyout(sd->sopt, sd->kbuf, sd->koff);
+		if (error != 0)
+			return (error);
+	}
 
 	memset(sd->kbuf, 0, sd->ksize);
 	sd->ktotal += sd->koff;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Sun Jul  6 23:24:06 2014	(r268346)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Sun Jul  6 23:26:34 2014	(r268347)
@@ -800,13 +800,13 @@ struct table_algo radix_iface = {
 	.name		= "radix_iface",
 	.lookup		= ta_lookup_iface,
 	.init		= ta_init_iface,
-	.destroy		= ta_destroy_iface,
+	.destroy	= ta_destroy_iface,
 	.prepare_add	= ta_prepare_add_iface,
 	.prepare_del	= ta_prepare_del_iface,
 	.add		= ta_add_iface,
 	.del		= ta_del_iface,
 	.flush_entry	= ta_flush_iface_entry,
-	.foreach		= ta_foreach_iface,
+	.foreach	= ta_foreach_iface,
 	.dump_tentry	= ta_dump_iface_tentry,
 	.find_tentry	= ta_find_iface_tentry,
 };


More information about the svn-src-projects mailing list