* 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.
This commit is contained in:
Alexander V. Chernikov 2014-09-05 11:11:15 +00:00
parent e822d9364e
commit 6b988f3a27
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/ipfw/; revision=271158
7 changed files with 458 additions and 325 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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 @@ dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
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);
@ -2251,6 +2281,189 @@ add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
return (error);
}
/*
* 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)

View File

@ -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);
@ -886,30 +880,6 @@ check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts,
return (error);
}
/*
* 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):
@ -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 @@ flush_table(struct ip_fw_chain *ch, struct tid_info *ti)
*
* 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 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
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);
}

View File

@ -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);

View File

@ -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));
}