summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2014-09-05 11:11:15 +0000
committermelifaro <melifaro@FreeBSD.org>2014-09-05 11:11:15 +0000
commit03b9e62107da29243ccd8f49a709c5821f6a73eb (patch)
tree52f5d4415ac60be1b166d1eda0f57d1a14e469f5
parentd8fb572c3627643813e23dfc45401656a2f9be44 (diff)
downloadFreeBSD-src-03b9e62107da29243ccd8f49a709c5821f6a73eb.zip
FreeBSD-src-03b9e62107da29243ccd8f49a709c5821f6a73eb.tar.gz
* 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.
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c15
-rw-r--r--sys/netpfil/ipfw/ip_fw_iface.c12
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h33
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c377
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c236
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.h29
-rw-r--r--sys/netpfil/ipfw/ip_fw_table_value.c81
7 files changed, 458 insertions, 325 deletions
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index b11c10d..843bc41 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -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);
diff --git a/sys/netpfil/ipfw/ip_fw_iface.c b/sys/netpfil/ipfw/ip_fw_iface.c
index 8f38ae7..9fb5e10 100644
--- a/sys/netpfil/ipfw/ip_fw_iface.c
+++ b/sys/netpfil/ipfw/ip_fw_iface.c
@@ -65,6 +65,12 @@ static void handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
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_instance *ii, struct named_object *no,
*
* 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;
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index 6879588..9a65b3f 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -520,8 +520,6 @@ int ipfw_iface_ref(struct ip_fw_chain *ch, char *name,
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 *ch, uint16_t tbl, in_addr_t addr,
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 */
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index 33ce32b..051dc00 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -98,9 +98,47 @@ static uint32_t objhash_hash_name(struct namedobj_instance *ni, void *key,
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_fw3_opheader *op3,
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_fw3_opheader *op3,
}
/*
+ * 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 *sd, size_t needed)
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)
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index b670552..f2129d9 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -107,12 +107,6 @@ static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
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, struct tableop_state *ts,
}
/*
- * 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 *ch, ip_fw3_opheader *op3,
* 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_chain *ch, ip_fw3_opheader *op3,
* 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_chain *ch, ip_fw3_opheader *op3,
*
* 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 *ch, ip_fw3_opheader *op3,
*
* 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, struct tid_info *ti)
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_chain *ch, uint16_t tbl, uint16_t plen,
*
* 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, ip_fw3_opheader *op3,
*
* 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 *ch, ip_fw3_opheader *op3,
*
* 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, ip_fw3_opheader *op3,
*
* 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, ipfw_obj_lheader *olh,
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, ip_fw3_opheader *op3,
* 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 *ch, struct sockopt_data *sd)
* 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 *ch, struct sockopt_data *sd)
/*
* 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 *ch, int idx)
*
* 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);
+}
+
+
+
diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h
index c8c1405..cefaaf2 100644
--- a/sys/netpfil/ipfw/ip_fw_table.h
+++ b/sys/netpfil/ipfw/ip_fw_table.h
@@ -161,29 +161,6 @@ void ipfw_del_table_algo(struct ip_fw_chain *ch, int idx);
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,
- struct sockopt_data *sd);
-int ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
- struct sockopt_data *sd);
-int ipfw_describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
- struct sockopt_data *sd);
-
-int ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
- 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,
- struct sockopt_data *sd);
-int ipfw_list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
- struct sockopt_data *sd);
-int ipfw_swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
- struct sockopt_data *sd);
/* Exported to support legacy opcodes */
int add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
struct tentry_info *tei, uint8_t flags, uint32_t count);
@@ -196,12 +173,10 @@ int ipfw_get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd);
/* ipfw_table_value.c functions */
-int ipfw_list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
- struct sockopt_data *sd);
struct table_config;
struct tableop_state;
-void ipfw_table_value_init(struct ip_fw_chain *ch);
-void ipfw_table_value_destroy(struct ip_fw_chain *ch);
+void ipfw_table_value_init(struct ip_fw_chain *ch, int first);
+void ipfw_table_value_destroy(struct ip_fw_chain *ch, int last);
int ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts);
void ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
struct tentry_info *tei, uint32_t count, int rollback);
diff --git a/sys/netpfil/ipfw/ip_fw_table_value.c b/sys/netpfil/ipfw/ip_fw_table_value.c
index a8d4a31..cff8d76 100644
--- a/sys/netpfil/ipfw/ip_fw_table_value.c
+++ b/sys/netpfil/ipfw/ip_fw_table_value.c
@@ -60,6 +60,13 @@ static uint32_t hash_table_value(struct namedobj_instance *ni, void *key,
uint32_t kopt);
static int cmp_table_value(struct named_object *no, void *key, uint32_t kopt);
+static int list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+ struct sockopt_data *sd);
+
+static struct ipfw_sopt_handler scodes[] = {
+ { IP_FW_TABLE_VLIST, 0, HDIR_GET, list_table_values },
+};
+
#define CHAIN_TO_VI(chain) (CHAIN_TO_TCFG(chain)->valhash)
struct table_val_link
@@ -77,39 +84,6 @@ struct vdump_args {
};
-void
-ipfw_table_value_init(struct ip_fw_chain *ch)
-{
- struct tables_config *tcfg;
-
- ch->valuestate = malloc(VALDATA_START_SIZE * sizeof(struct table_value),
- M_IPFW, M_WAITOK | M_ZERO);
-
- tcfg = ch->tblcfg;
-
- tcfg->val_size = VALDATA_START_SIZE;
- tcfg->valhash = ipfw_objhash_create(tcfg->val_size);
- ipfw_objhash_set_funcs(tcfg->valhash, hash_table_value,
- cmp_table_value);
-}
-
-static void
-destroy_value(struct namedobj_instance *ni, struct named_object *no,
- void *arg)
-{
-
- free(no, M_IPFW);
-}
-
-void
-ipfw_table_value_destroy(struct ip_fw_chain *ch)
-{
-
- free(ch->valuestate, M_IPFW);
- ipfw_objhash_foreach(CHAIN_TO_VI(ch), destroy_value, ch);
- ipfw_objhash_destroy(CHAIN_TO_VI(ch));
-}
-
static uint32_t
hash_table_value(struct namedobj_instance *ni, void *key, uint32_t kopt)
{
@@ -734,8 +708,8 @@ dump_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg)
*
* Returns 0 on success
*/
-int
-ipfw_list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+static int
+list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd)
{
struct _ipfw_obj_lheader *olh;
@@ -779,3 +753,40 @@ ipfw_list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
return (0);
}
+void
+ipfw_table_value_init(struct ip_fw_chain *ch, int first)
+{
+ struct tables_config *tcfg;
+
+ ch->valuestate = malloc(VALDATA_START_SIZE * sizeof(struct table_value),
+ M_IPFW, M_WAITOK | M_ZERO);
+
+ tcfg = ch->tblcfg;
+
+ tcfg->val_size = VALDATA_START_SIZE;
+ tcfg->valhash = ipfw_objhash_create(tcfg->val_size);
+ ipfw_objhash_set_funcs(tcfg->valhash, hash_table_value,
+ cmp_table_value);
+
+ IPFW_ADD_SOPT_HANDLER(first, scodes);
+}
+
+static void
+destroy_value(struct namedobj_instance *ni, struct named_object *no,
+ void *arg)
+{
+
+ free(no, M_IPFW);
+}
+
+void
+ipfw_table_value_destroy(struct ip_fw_chain *ch, int last)
+{
+
+ IPFW_DEL_SOPT_HANDLER(last, scodes);
+
+ free(ch->valuestate, M_IPFW);
+ ipfw_objhash_foreach(CHAIN_TO_VI(ch), destroy_value, ch);
+ ipfw_objhash_destroy(CHAIN_TO_VI(ch));
+}
+
OpenPOWER on IntegriCloud