svn commit: r269304 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Wed Jul 30 14:52:28 UTC 2014
Author: melifaro
Date: Wed Jul 30 14:52:26 2014
New Revision: 269304
URL: http://svnweb.freebsd.org/changeset/base/269304
Log:
* 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.
Modified:
projects/ipfw/sbin/ipfw/ipfw2.c
projects/ipfw/sbin/ipfw/tables.c
projects/ipfw/sys/netinet/ip_fw.h
projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c Wed Jul 30 14:52:04 2014 (r269303)
+++ projects/ipfw/sbin/ipfw/ipfw2.c Wed Jul 30 14:52:26 2014 (r269304)
@@ -1096,6 +1096,7 @@ print_ip(struct format_opts *fo, ipfw_in
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_in
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_in
}
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
}
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,
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 @@ read_options:
case TOK_LOOKUP: {
ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
- char *p;
int j;
if (!av[0] || !av[1])
@@ -4397,9 +4399,11 @@ read_options:
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;
Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c Wed Jul 30 14:52:04 2014 (r269303)
+++ projects/ipfw/sbin/ipfw/tables.c Wed Jul 30 14:52:26 2014 (r269304)
@@ -82,7 +82,7 @@ static int tables_foreach(table_cb_t *f,
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
/* 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, ip
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;
}
}
Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h Wed Jul 30 14:52:04 2014 (r269303)
+++ projects/ipfw/sys/netinet/ip_fw.h Wed Jul 30 14:52:26 2014 (r269304)
@@ -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 */
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Wed Jul 30 14:52:04 2014 (r269303)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Wed Jul 30 14:52:26 2014 (r269304)
@@ -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;
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Wed Jul 30 14:52:04 2014 (r269303)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Wed Jul 30 14:52:26 2014 (r269304)
@@ -593,6 +593,9 @@ ipfw_find_table_entry(struct ip_fw_chain
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, ui
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;
}
}
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Wed Jul 30 14:52:04 2014 (r269303)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Wed Jul 30 14:52:26 2014 (r269304)
@@ -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
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_cha
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);
}
More information about the svn-src-projects
mailing list