Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Sep 2014 11:11:15 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r271158 - projects/ipfw/sys/netpfil/ipfw
Message-ID:  <201409051111.s85BBFfc047710@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Fri Sep  5 11:11:15 2014
New Revision: 271158
URL: http://svnweb.freebsd.org/changeset/base/271158

Log:
  * Use modular opcode handling inside ipfw_ctl3() instead of static switch.
  * Provide hints for subsystem initializers if they are called for
    the first/last time.
  * Convert every IP_FW3 opcode user to use new sopt API.

Modified:
  projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_iface.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_value.c

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Fri Sep  5 11:10:44 2014	(r271157)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Fri Sep  5 11:11:15 2014	(r271158)
@@ -2667,6 +2667,7 @@ ipfw_init(void)
 	if (default_fw_tables > IPFW_TABLES_MAX)
 	  default_fw_tables = IPFW_TABLES_MAX;
 
+	ipfw_init_sopt_handler();
 	ipfw_log_bpf(1); /* init */
 	ipfw_iface_init();
 	return (error);
@@ -2681,6 +2682,7 @@ ipfw_destroy(void)
 
 	ipfw_iface_destroy();
 	ipfw_log_bpf(0); /* uninit */
+	ipfw_destroy_sopt_handler();
 	printf("IP firewall unloaded\n");
 }
 
@@ -2691,12 +2693,14 @@ ipfw_destroy(void)
 static int
 vnet_ipfw_init(const void *unused)
 {
-	int error;
+	int error, first;
 	struct ip_fw *rule = NULL;
 	struct ip_fw_chain *chain;
 
 	chain = &V_layer3_chain;
 
+	first = IS_DEFAULT_VNET(curvnet) ? 1 : 0;
+
 	/* First set up some values that are compile time options */
 	V_autoinc_step = 100;	/* bounded to 1..1000 in add_rule() */
 	V_fw_deny_unknown_exthdrs = 1;
@@ -2718,7 +2722,7 @@ vnet_ipfw_init(const void *unused)
 
 	/* Set initial number of tables */
 	V_fw_tables_max = default_fw_tables;
-	error = ipfw_init_tables(chain);
+	error = ipfw_init_tables(chain, first);
 	if (error) {
 		printf("ipfw2: setting up tables failed\n");
 		free(chain->map, M_IPFW);
@@ -2771,7 +2775,7 @@ vnet_ipfw_uninit(const void *unused)
 {
 	struct ip_fw *reap;
 	struct ip_fw_chain *chain = &V_layer3_chain;
-	int i;
+	int i, last;
 
 	V_ipfw_vnet_ready = 0; /* tell new callers to go away */
 	/*
@@ -2781,6 +2785,9 @@ vnet_ipfw_uninit(const void *unused)
 	 */
 	(void)ipfw_attach_hooks(0 /* detach */);
 	V_ip_fw_ctl_ptr = NULL;
+
+	last = IS_DEFAULT_VNET(curvnet) ? 1 : 0;
+
 	IPFW_UH_WLOCK(chain);
 	IPFW_UH_WUNLOCK(chain);
 	IPFW_UH_WLOCK(chain);
@@ -2797,7 +2804,7 @@ vnet_ipfw_uninit(const void *unused)
 	ipfw_destroy_skipto_cache(chain);
 	IPFW_WUNLOCK(chain);
 	IPFW_UH_WUNLOCK(chain);
-	ipfw_destroy_tables(chain);
+	ipfw_destroy_tables(chain, last);
 	if (reap != NULL)
 		ipfw_reap_rules(reap);
 	vnet_ipfw_iface_destroy(chain);

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_iface.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_iface.c	Fri Sep  5 11:10:44 2014	(r271157)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_iface.c	Fri Sep  5 11:11:15 2014	(r271158)
@@ -65,6 +65,12 @@ static void handle_ifdetach(struct ip_fw
     uint16_t ifindex);
 static void handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
     uint16_t ifindex);
+static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
+
+static struct ipfw_sopt_handler	scodes[] = {
+	{ IP_FW_XIFLIST,	0,	HDIR_GET,	list_ifaces },
+};
 
 /*
  * FreeBSD Kernel interface.
@@ -200,6 +206,7 @@ ipfw_iface_init()
 {
 
 	mtx_init(&vnet_mtx, "IPFW ifhandler mtx", NULL, MTX_DEF);
+	IPFW_ADD_SOPT_HANDLER(1, scodes);
 	return (0);
 }
 
@@ -211,6 +218,7 @@ void
 ipfw_iface_destroy()
 {
 
+	IPFW_DEL_SOPT_HANDLER(1, scodes);
 	mtx_destroy(&vnet_mtx);
 }
 
@@ -483,8 +491,8 @@ export_iface_internal(struct namedobj_in
  *
  * Returns 0 on success
  */
-int
-ipfw_list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	struct namedobj_instance *ii;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Fri Sep  5 11:10:44 2014	(r271157)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Fri Sep  5 11:11:15 2014	(r271158)
@@ -520,8 +520,6 @@ int ipfw_iface_ref(struct ip_fw_chain *c
 void ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic);
 void ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic);
 void ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic);
-int ipfw_list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
 
 /* In ip_fw_sockopt.c */
 void ipfw_init_skipto_cache(struct ip_fw_chain *chain);
@@ -537,8 +535,35 @@ void ipfw_destroy_counters(void);
 struct ip_fw *ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize);
 int ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt);
 
+typedef int (sopt_handler_f)(struct ip_fw_chain *ch,
+    ip_fw3_opheader *op3, struct sockopt_data *sd);
+struct ipfw_sopt_handler {
+	uint16_t	opcode;
+	uint8_t		version;
+	uint8_t		dir;
+	sopt_handler_f	*handler;
+	uint64_t	refcnt;
+};
+#define	HDIR_SET	0x01	/* Handler is used to set some data */
+#define	HDIR_GET	0x02	/* Handler is used to retrieve data */
+#define	HDIR_BOTH	HDIR_GET|HDIR_SET
+
+void ipfw_init_sopt_handler(void);
+void ipfw_destroy_sopt_handler(void);
+void ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count);
+int ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count);
 caddr_t ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed);
 caddr_t ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed);
+#define	IPFW_ADD_SOPT_HANDLER(f, c)	do {	\
+	if ((f) != 0) 				\
+		ipfw_add_sopt_handler(c,	\
+		    sizeof(c) / sizeof(c[0]));	\
+	} while(0)
+#define	IPFW_DEL_SOPT_HANDLER(l, c)	do {	\
+	if ((l) != 0) 				\
+		ipfw_del_sopt_handler(c,	\
+		    sizeof(c) / sizeof(c[0]));	\
+	} while(0)
 
 typedef void (objhash_cb_t)(struct namedobj_instance *ni, struct named_object *,
     void *arg);
@@ -580,10 +605,10 @@ int ipfw_lookup_table(struct ip_fw_chain
     uint32_t *val);
 int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
     void *paddr, uint32_t *val);
-int ipfw_init_tables(struct ip_fw_chain *ch);
+int ipfw_init_tables(struct ip_fw_chain *ch, int first);
 int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables);
 int ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int nsets);
-void ipfw_destroy_tables(struct ip_fw_chain *ch);
+void ipfw_destroy_tables(struct ip_fw_chain *ch, int last);
 
 /* In ip_fw_nat.c -- XXX to be moved to ip_var.h */
 

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Fri Sep  5 11:10:44 2014	(r271157)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Fri Sep  5 11:11:15 2014	(r271158)
@@ -98,9 +98,47 @@ static uint32_t objhash_hash_name(struct
 static uint32_t objhash_hash_idx(struct namedobj_instance *ni, uint32_t val);
 static int objhash_cmp_name(struct named_object *no, void *name, uint32_t set);
 
+MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
+
+static int dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
+static int add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
+static int del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
+static int clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
+static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
+static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
+
+/* ctl3 handler data */
+struct mtx ctl3_lock;
+#define	CTL3_LOCK_INIT()	mtx_init(&ctl3_lock, "ctl3_lock", NULL, MTX_DEF)
+#define	CTL3_LOCK_DESTROY()	mtx_destroy(&ctl3_lock)
+#define	CTL3_LOCK()		mtx_lock(&ctl3_lock)
+#define	CTL3_UNLOCK()		mtx_unlock(&ctl3_lock)
+
+static struct ipfw_sopt_handler *ctl3_handlers;
+static size_t ctl3_hsize;
+static uint64_t ctl3_refct, ctl3_gencnt;
+#define	CTL3_SMALLBUF	4096			/* small page-size write buffer */
+#define	CTL3_LARGEBUF	16 * 1024 * 1024	/* handle large rulesets */
+
 static int ipfw_flush_sopt_data(struct sockopt_data *sd);
 
-MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
+static struct ipfw_sopt_handler	scodes[] = {
+	{ IP_FW_XGET,		0,	HDIR_GET,	dump_config },
+	{ IP_FW_XADD,		0,	HDIR_BOTH,	add_rules },
+	{ IP_FW_XDEL,		0,	HDIR_BOTH,	del_rules },
+	{ IP_FW_XZERO,		0,	HDIR_SET,	clear_rules },
+	{ IP_FW_XRESETLOG,	0,	HDIR_SET,	clear_rules },
+	{ IP_FW_XMOVE,		0,	HDIR_SET,	move_rules },
+	{ IP_FW_SET_SWAP,	0,	HDIR_SET,	manage_sets },
+	{ IP_FW_SET_MOVE,	0,	HDIR_SET,	manage_sets },
+	{ IP_FW_SET_ENABLE,	0,	HDIR_SET,	manage_sets },
+};
 
 /*
  * static variables followed by global ones
@@ -2027,11 +2065,6 @@ cleanup:
 	return (error);
 }
 
-#define IP_FW3_OPLENGTH(x)	((x)->sopt_valsize - sizeof(ip_fw3_opheader))
-#define	IP_FW3_WRITEBUF	4096			/* small page-size write buffer */
-#define	IP_FW3_READBUF	16 * 1024 * 1024	/* handle large rulesets */
-
-
 static int
 check_object_name(ipfw_obj_ntlv *ntlv)
 {
@@ -2085,9 +2118,6 @@ add_rules(struct ip_fw_chain *chain, ip_
 	struct rule_check_info rci, *ci, *cbuf;
 	int i, rsize;
 
-	if (sd->valsize > IP_FW3_READBUF)
-		return (EINVAL);
-
 	op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize);
 	ctlv = (ipfw_obj_ctlv *)(op3 + 1);
 
@@ -2252,6 +2282,189 @@ add_rules(struct ip_fw_chain *chain, ip_
 }
 
 /*
+ * Compares two sopt handlers (code, version and handler ptr).
+ * Used both as qsort() and bsearch().
+ * Does not compare handler for latter case.
+ *
+ * Returns 0 if match is found.
+ */
+static int
+compare_sh(const void *_a, const void *_b)
+{
+	struct ipfw_sopt_handler *a, *b;
+
+	a = (struct ipfw_sopt_handler *)_a;
+	b = (struct ipfw_sopt_handler *)_b;
+
+	if (a->opcode < b->opcode)
+		return (-1);
+	else if (a->opcode > b->opcode)
+		return (1);
+
+	if (a->version < b->version)
+		return (-1);
+	else if (a->version > b->version)
+		return (1);
+
+	/* bsearch helper */
+	if (a->handler == NULL)
+		return (0);
+
+	if ((uintptr_t)a->handler < (uintptr_t)b->handler)
+		return (-1);
+	else if ((uintptr_t)b->handler > (uintptr_t)b->handler)
+		return (1);
+
+	return (0);
+}
+
+/*
+ * Finds sopt handler based on @code and @version.
+ *
+ * Returns pointer to handler or NULL.
+ */
+static struct ipfw_sopt_handler *
+find_sh(uint16_t code, uint8_t version, void *handler)
+{
+	struct ipfw_sopt_handler *sh, h;
+
+	memset(&h, 0, sizeof(h));
+	h.opcode = code;
+	h.version = version;
+	h.handler = handler;
+
+	sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers,
+	    ctl3_hsize, sizeof(h), compare_sh);
+
+	return (sh);
+}
+
+static int
+find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh)
+{
+	struct ipfw_sopt_handler *sh;
+
+	CTL3_LOCK();
+	if ((sh = find_sh(opcode, version, NULL)) == NULL) {
+		CTL3_UNLOCK();
+		printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n",
+		    opcode, version);
+		return (EINVAL);
+	}
+	sh->refcnt++;
+	ctl3_refct++;
+	/* Copy handler data to requested buffer */
+	*psh = *sh; 
+	CTL3_UNLOCK();
+
+	return (0);
+}
+
+static void
+find_unref_sh(struct ipfw_sopt_handler *psh)
+{
+	struct ipfw_sopt_handler *sh;
+
+	CTL3_LOCK();
+	sh = find_sh(psh->opcode, psh->version, NULL);
+	KASSERT(sh != NULL, ("ctl3 handler disappeared"));
+	sh->refcnt--;
+	ctl3_refct--;
+	CTL3_UNLOCK();
+}
+
+void
+ipfw_init_sopt_handler()
+{
+
+	CTL3_LOCK_INIT();
+	IPFW_ADD_SOPT_HANDLER(1, scodes);
+}
+
+void
+ipfw_destroy_sopt_handler()
+{
+
+	IPFW_DEL_SOPT_HANDLER(1, scodes);
+	CTL3_LOCK_DESTROY();
+}
+
+/*
+ * Adds one or more sockopt handlers to the global array.
+ * Function may sleep.
+ */
+void
+ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
+{
+	size_t sz;
+	struct ipfw_sopt_handler *tmp;
+
+	CTL3_LOCK();
+
+	for (;;) {
+		sz = ctl3_hsize + count;
+		CTL3_UNLOCK();
+		tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO);
+		CTL3_LOCK();
+		if (ctl3_hsize + count <= sz)
+			break;
+
+		/* Retry */
+		free(tmp, M_IPFW);
+	}
+
+	/* Merge old & new arrays */
+	sz = ctl3_hsize + count;
+	memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh));
+	memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh));
+	qsort(tmp, sz, sizeof(*sh), compare_sh);
+	/* Switch new and free old */
+	if (ctl3_handlers != NULL)
+		free(ctl3_handlers, M_IPFW);
+	ctl3_handlers = tmp;
+	ctl3_hsize = sz;
+	ctl3_gencnt++;
+
+	CTL3_UNLOCK();
+}
+
+/*
+ * Removes one or more sockopt handlers from the global array.
+ */
+int
+ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
+{
+	size_t sz;
+	struct ipfw_sopt_handler *tmp, *h;
+	int i;
+
+	CTL3_LOCK();
+
+	for (i = 0; i < count; i++) {
+		tmp = &sh[i];
+		h = find_sh(tmp->opcode, tmp->version, tmp->handler);
+		if (h == NULL)
+			continue;
+
+		sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h);
+		memmove(h, h + 1, sz);
+		ctl3_hsize--;
+	}
+
+	if (ctl3_hsize == 0) {
+		if (ctl3_handlers != NULL)
+			free(ctl3_handlers, M_IPFW);
+		ctl3_handlers = NULL;
+	}
+
+	ctl3_gencnt++;
+
+	CTL3_UNLOCK();
+
+	return (0);
+}
+
+/*
  * Writes data accumulated in @sd to sockopt buffer.
  * Zeroes internal @sd buffer.
  */
@@ -2341,12 +2554,12 @@ ipfw_get_sopt_header(struct sockopt_data
 int
 ipfw_ctl3(struct sockopt *sopt)
 {
-	int error, ctype;
-	size_t bsize_max, size, valsize;
+	int error;
+	size_t size, valsize;
 	struct ip_fw_chain *chain;
-	uint32_t opt;
 	char xbuf[256];
 	struct sockopt_data sdata;
+	struct ipfw_sopt_handler h;
 	ip_fw3_opheader *op3 = NULL;
 
 	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
@@ -2367,52 +2580,55 @@ ipfw_ctl3(struct sockopt *sopt)
 	error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3));
 	if (error != 0)
 		return (error);
-	opt = op3->opcode;
 	sopt->sopt_valsize = valsize;
 
 	/*
-	 * Determine opcode type/buffer size:
-	 * use on-stack xbuf for short request,
-	 * allocate sliding-window buf for data export or
-	 * contigious buffer for special ops.
+	 * Find and reference command.
 	 */
-	ctype = (sopt->sopt_dir == SOPT_GET) ? SOPT_GET : SOPT_SET;
-	switch (opt) {
-	case IP_FW_XADD:
-	case IP_FW_XDEL:
-	case IP_FW_TABLE_XADD:
-	case IP_FW_TABLE_XDEL:
-		ctype = SOPT_SET;
-		bsize_max = IP_FW3_READBUF;
-		break;
-	default:
-		bsize_max = IP_FW3_WRITEBUF;
-	}
+	error = find_ref_sh(op3->opcode, op3->version, &h);
+	if (error != 0)
+		return (error);
 
 	/*
 	 * Disallow modifications in really-really secure mode, but still allow
 	 * the logging counters to be reset.
 	 */
-	if (ctype == SOPT_SET && opt != IP_FW_XRESETLOG) {
+	if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) {
 		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
-		if (error != 0)
+		if (error != 0) {
+			find_unref_sh(&h);
 			return (error);
+		}
 	}
 
 	/*
 	 * Fill in sockopt_data structure that may be useful for
 	 * IP_FW3 get requests.
 	 */
-
 	if (valsize <= sizeof(xbuf)) {
+		/* use on-stack buffer */
 		sdata.kbuf = xbuf;
 		sdata.ksize = sizeof(xbuf);
 		sdata.kavail = valsize;
 	} else {
-		if (valsize < bsize_max)
+
+		/*
+		 * Determine opcode type/buffer size:
+		 * allocate sliding-window buf for data export or
+		 * contigious buffer for special ops.
+		 */
+		if ((h.dir & HDIR_SET) != 0) {
+			/* Set request. Allocate contigous buffer. */
+			if (valsize > CTL3_LARGEBUF) {
+				find_unref_sh(&h);
+				return (EFBIG);
+			}
+
 			size = valsize;
-		else
-			size = bsize_max;
+		} else {
+			/* Get request. Allocate sliding window buffer */
+			size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF;
+		}
 
 		sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
 		sdata.ksize = size;
@@ -2433,95 +2649,10 @@ ipfw_ctl3(struct sockopt *sopt)
 	    sizeof(ip_fw3_opheader))) != 0)
 		return (error);
 	op3 = (ip_fw3_opheader *)sdata.kbuf;
-	opt = op3->opcode;
-
-	switch (opt) {
-	case IP_FW_XGET:
-		error = dump_config(chain, op3, &sdata);
-		break;
-
-	case IP_FW_XADD:
-		error = add_rules(chain, op3, &sdata);
-		break;
-
-	case IP_FW_XDEL:
-		error = del_rules(chain, op3, &sdata);
-		break;
-
-	case IP_FW_XZERO:
-	case IP_FW_XRESETLOG:
-		error = clear_rules(chain, op3, &sdata);
-		break;
-
-	case IP_FW_XMOVE:
-		error = move_rules(chain, op3, &sdata);
-		break;
-
-	case IP_FW_SET_SWAP:
-	case IP_FW_SET_MOVE:
-	case IP_FW_SET_ENABLE:
-		error = manage_sets(chain, op3, &sdata);
-		break;
-
-	case IP_FW_XIFLIST:
-		error = ipfw_list_ifaces(chain, op3, &sdata);
-		break;
-
-	/*--- TABLE opcodes ---*/
-	case IP_FW_TABLE_XCREATE:
-		error = ipfw_create_table(chain, op3, &sdata);
-		break;
-
-	case IP_FW_TABLE_XDESTROY:
-	case IP_FW_TABLE_XFLUSH:
-		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, op3, &sdata);
-		break;
-
-	case IP_FW_TABLES_XLIST:
-		error = ipfw_list_tables(chain, op3, &sdata);
-		break;
-
-	case IP_FW_TABLE_XLIST:
-		error = ipfw_dump_table(chain, op3, &sdata);
-		break;
-
-	case IP_FW_TABLE_XADD:
-	case IP_FW_TABLE_XDEL:
-		error = ipfw_manage_table_ent(chain, op3, &sdata);
-		break;
-
-	case IP_FW_TABLE_XFIND:
-		error = ipfw_find_table_entry(chain, op3, &sdata);
-		break;
-
-	case IP_FW_TABLE_XSWAP:
-		error = ipfw_swap_table(chain, op3, &sdata);
-		break;
-
-	case IP_FW_TABLES_ALIST:
-		error = ipfw_list_table_algo(chain, op3, &sdata);
-		break;
-
-	case IP_FW_TABLE_VLIST:
-		error = ipfw_list_table_values(chain, op3, &sdata);
-		break;
 
-	case IP_FW_TABLE_XGETSIZE:
-		error = ipfw_get_table_size(chain, op3, &sdata);
-		break;
-
-	default:
-		printf("ipfw: ipfw_ctl3 invalid option %d\n", opt);
-		error = EINVAL;
-	}
+	/* Finally, run handler */
+	error = h.handler(chain, op3, &sdata);
+	find_unref_sh(&h);
 
 	/* Flush state and free buffers */
 	if (error == 0)

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Fri Sep  5 11:10:44 2014	(r271157)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Fri Sep  5 11:11:15 2014	(r271158)
@@ -107,12 +107,6 @@ static void export_table_info(struct ip_
 static int dump_table_tentry(void *e, void *arg);
 static int dump_table_xentry(void *e, void *arg);
 
-static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd);
-static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd);
-static int ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
 static int swap_tables(struct ip_fw_chain *ch, struct tid_info *a,
     struct tid_info *b);
 
@@ -887,30 +881,6 @@ check_table_space(struct ip_fw_chain *ch
 }
 
 /*
- * Selects appropriate table operation handler
- * depending on opcode version.
- */
-int
-ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	int error;
-
-	switch (op3->version) {
-	case 0:
-		error = ipfw_manage_table_ent_v0(ch, op3, sd);
-		break;
-	case 1:
-		error = ipfw_manage_table_ent_v1(ch, op3, sd);
-		break;
-	default:
-		error = ENOTSUP;
-	}
-
-	return (error);
-}
-
-/*
  * Adds or deletes record in table.
  * Data layout (v0):
  * Request: [ ip_fw3_opheader ipfw_table_xentry ]
@@ -918,7 +888,7 @@ ipfw_manage_table_ent(struct ip_fw_chain
  * Returns 0 on success
  */
 static int
-ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	ipfw_table_xentry *xent;
@@ -975,7 +945,7 @@ ipfw_manage_table_ent_v0(struct ip_fw_ch
  * Returns 0 on success
  */
 static int
-ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	ipfw_obj_tentry *tent, *ptent;
@@ -1095,8 +1065,8 @@ ipfw_manage_table_ent_v1(struct ip_fw_ch
  *
  * Returns 0 on success
  */
-int
-ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	ipfw_obj_tentry *tent;
@@ -1163,8 +1133,8 @@ ipfw_find_table_entry(struct ip_fw_chain
  *
  * Returns 0 on success
  */
-int
-ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+flush_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	int error;
@@ -1323,8 +1293,8 @@ restart:
  *
  * Returns 0 on success
  */
-int
-ipfw_swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	int error;
@@ -1508,64 +1478,6 @@ destroy_table(struct ip_fw_chain *ch, st
 	return (0);
 }
 
-static void
-destroy_table_locked(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-
-	unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no);
-	if (ipfw_objhash_free_idx(ni, no->kidx) != 0)
-		printf("Error unlinking kidx %d from table %s\n",
-		    no->kidx, no->name);
-	free_table_config(ni, (struct table_config *)no);
-}
-
-/*
- * Shuts tables module down.
- */
-void
-ipfw_destroy_tables(struct ip_fw_chain *ch)
-{
-
-	/* Remove all tables from working set */
-	IPFW_UH_WLOCK(ch);
-	IPFW_WLOCK(ch);
-	ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch);
-	IPFW_WUNLOCK(ch);
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Free pointers itself */
-	free(ch->tablestate, M_IPFW);
-
-	ipfw_table_value_destroy(ch);
-	ipfw_table_algo_destroy(ch);
-
-	ipfw_objhash_destroy(CHAIN_TO_NI(ch));
-	free(CHAIN_TO_TCFG(ch), M_IPFW);
-}
-
-/*
- * Starts tables module.
- */
-int
-ipfw_init_tables(struct ip_fw_chain *ch)
-{
-	struct tables_config *tcfg;
-
-	/* Allocate pointers */
-	ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info),
-	    M_IPFW, M_WAITOK | M_ZERO);
-
-	tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO);
-	tcfg->namehash = ipfw_objhash_create(V_fw_tables_max);
-	ch->tblcfg = tcfg;
-
-	ipfw_table_value_init(ch);
-	ipfw_table_algo_init(ch);
-
-	return (0);
-}
-
 /*
  * Grow tables index.
  *
@@ -1753,8 +1665,8 @@ ipfw_lookup_table_extended(struct ip_fw_
  *
  * Returns 0 on success
  */
-int
-ipfw_list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	struct _ipfw_obj_lheader *olh;
@@ -1781,8 +1693,8 @@ ipfw_list_tables(struct ip_fw_chain *ch,
  *
  * Returns 0 on success.
  */
-int
-ipfw_describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	struct _ipfw_obj_header *oh;
@@ -1816,8 +1728,8 @@ ipfw_describe_table(struct ip_fw_chain *
  *
  * Returns 0 on success
  */
-int
-ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	struct _ipfw_obj_header *oh;
@@ -1873,8 +1785,8 @@ ipfw_modify_table(struct ip_fw_chain *ch
  *
  * Returns 0 on success
  */
-int
-ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	struct _ipfw_obj_header *oh;
@@ -2243,26 +2155,6 @@ export_tables(struct ip_fw_chain *ch, ip
 	return (0);
 }
 
-int
-ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	int error;
-
-	switch (op3->version) {
-	case 0:
-		error = ipfw_dump_table_v0(ch, sd);
-		break;
-	case 1:
-		error = ipfw_dump_table_v1(ch, sd);
-		break;
-	default:
-		error = ENOTSUP;
-	}
-
-	return (error);
-}
-
 /*
  * Dumps all table data
  * Data layout (v1)(current):
@@ -2272,7 +2164,8 @@ ipfw_dump_table(struct ip_fw_chain *ch, 
  * Returns 0 on success
  */
 static int
-ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
+dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd)
 {
 	struct _ipfw_obj_header *oh;
 	ipfw_xtable_info *i;
@@ -2335,7 +2228,8 @@ ipfw_dump_table_v1(struct ip_fw_chain *c
  * Returns 0 on success
  */
 static int
-ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd)
+dump_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd)
 {
 	ipfw_xtable *xtbl;
 	struct tid_info ti;
@@ -2394,8 +2288,8 @@ ipfw_dump_table_v0(struct ip_fw_chain *c
 /*
  * Legacy function to retrieve number of items in table.
  */
-int
-ipfw_get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	uint32_t *tbl;
@@ -2800,8 +2694,8 @@ ipfw_del_table_algo(struct ip_fw_chain *
  *
  * Returns 0 on success
  */
-int
-ipfw_list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
 {
 	struct _ipfw_obj_lheader *olh;
@@ -3666,3 +3560,85 @@ free:
 	return (error);
 }
 
+static struct ipfw_sopt_handler	scodes[] = {
+	{ IP_FW_TABLE_XCREATE,	0,	HDIR_SET,	create_table },
+	{ IP_FW_TABLE_XDESTROY,	0,	HDIR_SET,	flush_table_v0 },
+	{ IP_FW_TABLE_XFLUSH,	0,	HDIR_SET,	flush_table_v0 },
+	{ IP_FW_TABLE_XMODIFY,	0,	HDIR_BOTH,	modify_table },
+	{ IP_FW_TABLE_XINFO,	0,	HDIR_GET,	describe_table },
+	{ IP_FW_TABLES_XLIST,	0,	HDIR_GET,	list_tables },
+	{ IP_FW_TABLE_XLIST,	0,	HDIR_GET,	dump_table_v0 },
+	{ IP_FW_TABLE_XLIST,	1,	HDIR_GET,	dump_table_v1 },
+	{ IP_FW_TABLE_XADD,	0,	HDIR_BOTH,	manage_table_ent_v0 },
+	{ IP_FW_TABLE_XADD,	1,	HDIR_BOTH,	manage_table_ent_v1 },
+	{ IP_FW_TABLE_XDEL,	0,	HDIR_BOTH,	manage_table_ent_v0 },
+	{ IP_FW_TABLE_XDEL,	1,	HDIR_BOTH,	manage_table_ent_v1 },
+	{ IP_FW_TABLE_XFIND,	0,	HDIR_GET,	find_table_entry },
+	{ IP_FW_TABLE_XSWAP,	0,	HDIR_SET,	swap_table },
+	{ IP_FW_TABLES_ALIST,	0,	HDIR_GET,	list_table_algo },
+	{ IP_FW_TABLE_XGETSIZE,	0,	HDIR_GET,	get_table_size },
+};
+
+static void
+destroy_table_locked(struct namedobj_instance *ni, struct named_object *no,
+    void *arg)
+{
+
+	unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no);
+	if (ipfw_objhash_free_idx(ni, no->kidx) != 0)
+		printf("Error unlinking kidx %d from table %s\n",
+		    no->kidx, no->name);
+	free_table_config(ni, (struct table_config *)no);
+}
+
+/*
+ * Shuts tables module down.
+ */
+void
+ipfw_destroy_tables(struct ip_fw_chain *ch, int last)
+{
+
+	IPFW_DEL_SOPT_HANDLER(last, scodes);
+
+	/* Remove all tables from working set */
+	IPFW_UH_WLOCK(ch);
+	IPFW_WLOCK(ch);
+	ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch);
+	IPFW_WUNLOCK(ch);
+	IPFW_UH_WUNLOCK(ch);
+
+	/* Free pointers itself */
+	free(ch->tablestate, M_IPFW);
+
+	ipfw_table_value_destroy(ch, last);
+	ipfw_table_algo_destroy(ch);
+
+	ipfw_objhash_destroy(CHAIN_TO_NI(ch));
+	free(CHAIN_TO_TCFG(ch), M_IPFW);
+}
+
+/*
+ * Starts tables module.
+ */
+int
+ipfw_init_tables(struct ip_fw_chain *ch, int first)
+{
+	struct tables_config *tcfg;
+
+	/* Allocate pointers */
+	ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info),
+	    M_IPFW, M_WAITOK | M_ZERO);
+
+	tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO);
+	tcfg->namehash = ipfw_objhash_create(V_fw_tables_max);
+	ch->tblcfg = tcfg;
+
+	ipfw_table_value_init(ch, first);
+	ipfw_table_algo_init(ch);
+
+	IPFW_ADD_SOPT_HANDLER(first, scodes);
+	return (0);
+}
+
+
+

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Fri Sep  5 11:10:44 2014	(r271157)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Fri Sep  5 11:11:15 2014	(r271158)
@@ -161,29 +161,6 @@ void ipfw_del_table_algo(struct ip_fw_ch
 void ipfw_table_algo_init(struct ip_fw_chain *chain);
 void ipfw_table_algo_destroy(struct ip_fw_chain *chain);
 
-
-/* direct ipfw_ctl handlers */
-int ipfw_list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3,

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



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