* Add number:array algorithm lookup method.
Kernel changes: * s/IPFW_TABLE_U32/IPFW_TABLE_NUMBER/ * Force "lookup <port|uid|gid|jid>" to be IPFW_TABLE_NUMBER * Support "lookup" method for number tables * Add number:array algorihm (i32 as key, auto-growing). Userland changes: * Support named tables in "lookup <tag> Table" * Fix handling of "table(NAME,val)" case * Support printing "number" table data.
This commit is contained in:
parent
ce2817b51c
commit
b23d5de9b6
@ -1096,6 +1096,7 @@ print_ip(struct format_opts *fo, ipfw_insn_ip *cmd, char const *s)
|
||||
struct hostent *he = NULL;
|
||||
uint32_t len = F_LEN((ipfw_insn *)cmd);
|
||||
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
|
||||
char *t;
|
||||
|
||||
if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
|
||||
uint32_t d = a[1];
|
||||
@ -1103,8 +1104,9 @@ print_ip(struct format_opts *fo, ipfw_insn_ip *cmd, char const *s)
|
||||
|
||||
if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
|
||||
arg = match_value(rule_options, lookup_key[d]);
|
||||
printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "",
|
||||
arg, cmd->o.arg1);
|
||||
t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
|
||||
printf("%s lookup %s %s", cmd->o.len & F_NOT ? " not": "",
|
||||
arg, t);
|
||||
return;
|
||||
}
|
||||
printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
|
||||
@ -1115,7 +1117,6 @@ print_ip(struct format_opts *fo, ipfw_insn_ip *cmd, char const *s)
|
||||
}
|
||||
if (cmd->o.opcode == O_IP_SRC_LOOKUP ||
|
||||
cmd->o.opcode == O_IP_DST_LOOKUP) {
|
||||
char *t;
|
||||
t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
|
||||
printf("table(%s", t);
|
||||
if (len == F_INSN_SIZE(ipfw_insn_u32))
|
||||
@ -2624,14 +2625,9 @@ struct tidx {
|
||||
static uint16_t
|
||||
pack_table(struct tidx *tstate, char *name, uint32_t set)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
ipfw_obj_ntlv *ntlv;
|
||||
|
||||
if ((p = strchr(name, ')')) == NULL)
|
||||
return (0);
|
||||
*p = '\0';
|
||||
|
||||
if (table_check_name(name) != 0)
|
||||
return (0);
|
||||
|
||||
@ -2694,6 +2690,9 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int cblen, struct tidx *tstate)
|
||||
}
|
||||
|
||||
if (strncmp(av, "table(", 6) == 0) {
|
||||
if ((p = strchr(av + 6, ')')) == NULL)
|
||||
errx(EX_DATAERR, "forgotten parenthesis: '%s'", av);
|
||||
*p = '\0';
|
||||
p = strchr(av + 6, ',');
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
@ -2983,6 +2982,7 @@ ipfw_delete(char *av[])
|
||||
static void
|
||||
fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate)
|
||||
{
|
||||
char *p;
|
||||
uint16_t uidx;
|
||||
|
||||
cmd->name[0] = '\0';
|
||||
@ -2994,7 +2994,10 @@ fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate)
|
||||
if (strcmp(arg, "any") == 0)
|
||||
cmd->o.len = 0; /* effectively ignore this command */
|
||||
else if (strncmp(arg, "table(", 6) == 0) {
|
||||
char *p = strchr(arg + 6, ',');
|
||||
if ((p = strchr(arg + 6, ')')) == NULL)
|
||||
errx(EX_DATAERR, "forgotten parenthesis: '%s'", arg);
|
||||
*p = '\0';
|
||||
p = strchr(arg + 6, ',');
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
if ((uidx = pack_table(tstate, arg + 6, 0)) == 0)
|
||||
@ -4381,7 +4384,6 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
|
||||
|
||||
case TOK_LOOKUP: {
|
||||
ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
|
||||
char *p;
|
||||
int j;
|
||||
|
||||
if (!av[0] || !av[1])
|
||||
@ -4397,9 +4399,11 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
|
||||
errx(EX_USAGE, "format: cannot lookup on %s", *av);
|
||||
__PAST_END(c->d, 1) = j; // i converted to option
|
||||
av++;
|
||||
cmd->arg1 = strtoul(*av, &p, 0);
|
||||
if (p && *p)
|
||||
errx(EX_USAGE, "format: lookup argument tablenum");
|
||||
|
||||
if ((j = pack_table(tstate, *av, 0)) == 0)
|
||||
errx(EX_DATAERR, "Invalid table name: %s", *av);
|
||||
|
||||
cmd->arg1 = j;
|
||||
av++;
|
||||
}
|
||||
break;
|
||||
|
@ -82,7 +82,7 @@ static int tables_foreach(table_cb_t *f, void *arg, int sort);
|
||||
static struct _s_x tabletypes[] = {
|
||||
{ "cidr", IPFW_TABLE_CIDR },
|
||||
{ "iface", IPFW_TABLE_INTERFACE },
|
||||
{ "u32", IPFW_TABLE_U32 },
|
||||
{ "number", IPFW_TABLE_NUMBER },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@ -654,7 +654,7 @@ tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
|
||||
/* Set mask to exact match */
|
||||
masklen = 8 * IF_NAMESIZE;
|
||||
break;
|
||||
case IPFW_TABLE_U32:
|
||||
case IPFW_TABLE_NUMBER:
|
||||
/* Port or any other key */
|
||||
key = strtol(arg, &p, 10);
|
||||
if (*p != '\0')
|
||||
@ -899,6 +899,16 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
|
||||
inet_ntoa(*(struct in_addr *)&tval));
|
||||
} else
|
||||
printf("%s %u\n", tent->k.iface, tval);
|
||||
break;
|
||||
case IPFW_TABLE_NUMBER:
|
||||
/* numbers */
|
||||
if (co.do_value_as_ip) {
|
||||
tval = htonl(tval);
|
||||
printf("%u %s\n", tent->k.key,
|
||||
inet_ntoa(*(struct in_addr *)&tval));
|
||||
} else
|
||||
printf("%u %u\n", tent->k.key, tval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,7 +674,7 @@ struct _ipfw_dyn_rule {
|
||||
|
||||
#define IPFW_TABLE_CIDR 1 /* Table for holding IPv4/IPv6 prefixes */
|
||||
#define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */
|
||||
#define IPFW_TABLE_U32 3 /* Table for holidng ports/uid/gid/etc */
|
||||
#define IPFW_TABLE_NUMBER 3 /* Table for holding ports/uid/gid/etc */
|
||||
#define IPFW_TABLE_MAXTYPE 3 /* Maximum valid number */
|
||||
|
||||
#define IPFW_VTYPE_U32 1 /* Skipto/tablearg integer */
|
||||
|
@ -1473,9 +1473,9 @@ do { \
|
||||
proto != IPPROTO_UDP)
|
||||
break;
|
||||
else if (v == 2)
|
||||
key = htonl(dst_port);
|
||||
key = dst_port;
|
||||
else if (v == 3)
|
||||
key = htonl(src_port);
|
||||
key = src_port;
|
||||
#ifndef USERSPACE
|
||||
else if (v == 4 || v == 5) {
|
||||
check_uidgid(
|
||||
@ -1494,7 +1494,6 @@ do { \
|
||||
else if (v == 5 /* O_JAIL */)
|
||||
key = ucred_cache.xid;
|
||||
#endif /* !__FreeBSD__ */
|
||||
key = htonl(key);
|
||||
} else
|
||||
#endif /* !USERSPACE */
|
||||
break;
|
||||
|
@ -593,6 +593,9 @@ ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
IPFW_UH_RUNLOCK(ch);
|
||||
return (EINVAL);
|
||||
}
|
||||
case IPFW_TABLE_NUMBER:
|
||||
plen = sizeof(uint32_t);
|
||||
break;
|
||||
|
||||
break;
|
||||
default:
|
||||
@ -1744,17 +1747,19 @@ classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
|
||||
case 2:
|
||||
case 3:
|
||||
/* src/dst port */
|
||||
//type = IPFW_TABLE_U16;
|
||||
*ptype = IPFW_TABLE_NUMBER;
|
||||
break;
|
||||
case 4:
|
||||
/* uid/gid */
|
||||
//type = IPFW_TABLE_U32;
|
||||
*ptype = IPFW_TABLE_NUMBER;
|
||||
break;
|
||||
case 5:
|
||||
//type = IPFW_TABLE_U32;
|
||||
/* jid */
|
||||
*ptype = IPFW_TABLE_NUMBER;
|
||||
break;
|
||||
case 6:
|
||||
//type = IPFW_TABLE_U16;
|
||||
/* dscp */
|
||||
*ptype = IPFW_TABLE_NUMBER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1376,7 +1376,7 @@ struct table_algo cidr_hash = {
|
||||
*
|
||||
* Runtime part:
|
||||
* - sorted array of "struct ifidx" pointed by ti->state.
|
||||
* Array is allocated with routing up to IFIDX_CHUNK. Only existing
|
||||
* Array is allocated with rounding up to IFIDX_CHUNK. Only existing
|
||||
* interfaces are stored in array, however its allocated size is
|
||||
* sufficient to hold all table records if needed.
|
||||
* - current array size is stored in ti->data
|
||||
@ -2025,6 +2025,368 @@ struct table_algo iface_idx = {
|
||||
.change_ti = ta_change_ti_ifidx,
|
||||
};
|
||||
|
||||
/*
|
||||
* Number array cmds.
|
||||
*
|
||||
* Implementation:
|
||||
*
|
||||
* Runtime part:
|
||||
* - sorted array of "struct numarray" pointed by ti->state.
|
||||
* Array is allocated with rounding up to NUMARRAY_CHUNK.
|
||||
* - current array size is stored in ti->data
|
||||
*
|
||||
*/
|
||||
|
||||
struct numarray {
|
||||
uint32_t number;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
struct numarray_cfg {
|
||||
void *main_ptr;
|
||||
size_t size; /* Number of items allocated in array */
|
||||
size_t used; /* Number of items _active_ now */
|
||||
};
|
||||
|
||||
#define NUMARRAY_CHUNK 16
|
||||
|
||||
int compare_numarray(const void *k, const void *v);
|
||||
|
||||
int
|
||||
compare_numarray(const void *k, const void *v)
|
||||
{
|
||||
struct numarray *na;
|
||||
uint32_t key;
|
||||
|
||||
key = *((uint32_t *)k);
|
||||
na = (struct numarray *)v;
|
||||
|
||||
if (key < na->number)
|
||||
return (-1);
|
||||
else if (key > na->number)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct numarray *
|
||||
numarray_find(struct table_info *ti, void *key)
|
||||
{
|
||||
struct numarray *ri;
|
||||
|
||||
ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
|
||||
compare_ifidx);
|
||||
|
||||
return (ri);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
|
||||
uint32_t *val)
|
||||
{
|
||||
struct numarray *ri;
|
||||
|
||||
ri = numarray_find(ti, key);
|
||||
|
||||
if (ri != NULL) {
|
||||
*val = ri->value;
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
|
||||
char *data)
|
||||
{
|
||||
struct numarray_cfg *cfg;
|
||||
|
||||
cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
|
||||
|
||||
cfg->size = NUMARRAY_CHUNK;
|
||||
cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
*ta_state = cfg;
|
||||
ti->state = cfg->main_ptr;
|
||||
ti->lookup = ta_lookup_numarray;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys table @ti
|
||||
*/
|
||||
static void
|
||||
ta_destroy_numarray(void *ta_state, struct table_info *ti)
|
||||
{
|
||||
struct numarray_cfg *cfg;
|
||||
|
||||
cfg = (struct numarray_cfg *)ta_state;
|
||||
|
||||
if (cfg->main_ptr != NULL)
|
||||
free(cfg->main_ptr, M_IPFW);
|
||||
|
||||
free(cfg, M_IPFW);
|
||||
}
|
||||
|
||||
struct ta_buf_numarray
|
||||
{
|
||||
struct numarray na;
|
||||
};
|
||||
|
||||
/*
|
||||
* Prepare for addition/deletion to an array.
|
||||
*/
|
||||
static int
|
||||
ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
void *ta_buf)
|
||||
{
|
||||
struct ta_buf_numarray *tb;
|
||||
|
||||
tb = (struct ta_buf_numarray *)ta_buf;
|
||||
memset(tb, 0, sizeof(*tb));
|
||||
|
||||
tb->na.number = *((uint32_t *)tei->paddr);
|
||||
tb->na.value = tei->value;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
|
||||
void *ta_buf, uint64_t *pflags, uint32_t *pnum)
|
||||
{
|
||||
struct numarray_cfg *cfg;
|
||||
struct ta_buf_numarray *tb;
|
||||
struct numarray *ri;
|
||||
int res;
|
||||
|
||||
tb = (struct ta_buf_numarray*)ta_buf;
|
||||
cfg = (struct numarray_cfg *)ta_state;
|
||||
|
||||
ri = numarray_find(ti, &tb->na.number);
|
||||
|
||||
if (ri != NULL) {
|
||||
if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
|
||||
return (EEXIST);
|
||||
|
||||
/* We need to update value */
|
||||
ri->value = tb->na.value;
|
||||
/* Indicate that update has happened instead of addition */
|
||||
tei->flags |= TEI_FLAGS_UPDATED;
|
||||
*pnum = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
|
||||
sizeof(struct numarray), compare_numarray);
|
||||
|
||||
KASSERT(res == 1, ("number %d already exists", tb->na.number));
|
||||
cfg->used++;
|
||||
ti->data = cfg->used;
|
||||
|
||||
if (cfg->used + 1 == cfg->size) {
|
||||
/* Notify core we need to grow */
|
||||
*pflags = cfg->size + NUMARRAY_CHUNK;
|
||||
}
|
||||
*pnum = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove key from both configuration list and
|
||||
* runtime array. Removed interface notification.
|
||||
*/
|
||||
static int
|
||||
ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
|
||||
void *ta_buf, uint64_t *pflags, uint32_t *pnum)
|
||||
{
|
||||
struct numarray_cfg *cfg;
|
||||
struct ta_buf_numarray *tb;
|
||||
struct numarray *ri;
|
||||
int res;
|
||||
|
||||
tb = (struct ta_buf_numarray *)ta_buf;
|
||||
cfg = (struct numarray_cfg *)ta_state;
|
||||
|
||||
ri = numarray_find(ti, &tb->na.number);
|
||||
if (ri == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
|
||||
sizeof(struct numarray), compare_numarray);
|
||||
|
||||
KASSERT(res == 1, ("number %u does not exist", tb->na.number));
|
||||
cfg->used--;
|
||||
ti->data = cfg->used;
|
||||
|
||||
*pnum = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
void *ta_buf)
|
||||
{
|
||||
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Table growing callbacks.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allocate ned, larger runtime numarray array.
|
||||
*/
|
||||
static int
|
||||
ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
|
||||
{
|
||||
struct mod_item *mi;
|
||||
|
||||
mi = (struct mod_item *)ta_buf;
|
||||
|
||||
memset(mi, 0, sizeof(struct mod_item));
|
||||
mi->size = *pflags;
|
||||
mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data from old runtime array to new one.
|
||||
*/
|
||||
static int
|
||||
ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
|
||||
uint64_t *pflags)
|
||||
{
|
||||
struct mod_item *mi;
|
||||
struct numarray_cfg *cfg;
|
||||
|
||||
mi = (struct mod_item *)ta_buf;
|
||||
cfg = (struct numarray_cfg *)ta_state;
|
||||
|
||||
/* Check if we still need to grow array */
|
||||
if (cfg->size >= mi->size) {
|
||||
*pflags = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch old & new arrays.
|
||||
*/
|
||||
static int
|
||||
ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
|
||||
uint64_t pflags)
|
||||
{
|
||||
struct mod_item *mi;
|
||||
struct numarray_cfg *cfg;
|
||||
void *old_ptr;
|
||||
|
||||
mi = (struct mod_item *)ta_buf;
|
||||
cfg = (struct numarray_cfg *)ta_state;
|
||||
|
||||
old_ptr = cfg->main_ptr;
|
||||
cfg->main_ptr = mi->main_ptr;
|
||||
cfg->size = mi->size;
|
||||
ti->state = cfg->main_ptr;
|
||||
|
||||
mi->main_ptr = old_ptr;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free unneded array.
|
||||
*/
|
||||
static void
|
||||
ta_flush_mod_numarray(void *ta_buf)
|
||||
{
|
||||
struct mod_item *mi;
|
||||
|
||||
mi = (struct mod_item *)ta_buf;
|
||||
if (mi->main_ptr != NULL)
|
||||
free(mi->main_ptr, M_IPFW);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
|
||||
ipfw_obj_tentry *tent)
|
||||
{
|
||||
struct numarray *na;
|
||||
|
||||
na = (struct numarray *)e;
|
||||
|
||||
tent->k.key = na->number;
|
||||
tent->value = na->value;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_find_numarray_tentry(void *ta_state, struct table_info *ti, void *key,
|
||||
uint32_t keylen, ipfw_obj_tentry *tent)
|
||||
{
|
||||
struct numarray_cfg *cfg;
|
||||
struct numarray *ri;
|
||||
|
||||
cfg = (struct numarray_cfg *)ta_state;
|
||||
|
||||
ri = numarray_find(ti, key);
|
||||
|
||||
if (ri != NULL) {
|
||||
ta_dump_numarray_tentry(ta_state, ti, ri, tent);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static void
|
||||
ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
|
||||
void *arg)
|
||||
{
|
||||
struct numarray_cfg *cfg;
|
||||
struct numarray *array;
|
||||
int i;
|
||||
|
||||
cfg = (struct numarray_cfg *)ta_state;
|
||||
array = cfg->main_ptr;
|
||||
|
||||
for (i = 0; i < cfg->used; i++)
|
||||
f(&array[i], arg);
|
||||
}
|
||||
|
||||
struct table_algo number_array = {
|
||||
.name = "number:array",
|
||||
.type = IPFW_TABLE_NUMBER,
|
||||
.init = ta_init_numarray,
|
||||
.destroy = ta_destroy_numarray,
|
||||
.prepare_add = ta_prepare_add_numarray,
|
||||
.prepare_del = ta_prepare_add_numarray,
|
||||
.add = ta_add_numarray,
|
||||
.del = ta_del_numarray,
|
||||
.flush_entry = ta_flush_numarray_entry,
|
||||
.foreach = ta_foreach_numarray,
|
||||
.dump_tentry = ta_dump_numarray_tentry,
|
||||
.find_tentry = ta_find_numarray_tentry,
|
||||
.prepare_mod = ta_prepare_mod_numarray,
|
||||
.fill_mod = ta_fill_mod_numarray,
|
||||
.modify = ta_modify_numarray,
|
||||
.flush_mod = ta_flush_mod_numarray,
|
||||
};
|
||||
|
||||
void
|
||||
ipfw_table_algo_init(struct ip_fw_chain *ch)
|
||||
{
|
||||
@ -2037,6 +2399,7 @@ ipfw_table_algo_init(struct ip_fw_chain *ch)
|
||||
ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx);
|
||||
ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx);
|
||||
ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
|
||||
ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2046,6 +2409,7 @@ ipfw_table_algo_destroy(struct ip_fw_chain *ch)
|
||||
ipfw_del_table_algo(ch, cidr_radix.idx);
|
||||
ipfw_del_table_algo(ch, cidr_hash.idx);
|
||||
ipfw_del_table_algo(ch, iface_idx.idx);
|
||||
ipfw_del_table_algo(ch, number_array.idx);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user