summaryrefslogtreecommitdiffstats
path: root/sys/netpfil/ipfw/ip_fw_table_algo.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil/ipfw/ip_fw_table_algo.c')
-rw-r--r--sys/netpfil/ipfw/ip_fw_table_algo.c720
1 files changed, 545 insertions, 175 deletions
diff --git a/sys/netpfil/ipfw/ip_fw_table_algo.c b/sys/netpfil/ipfw/ip_fw_table_algo.c
index 7dcfe6a..3147464 100644
--- a/sys/netpfil/ipfw/ip_fw_table_algo.c
+++ b/sys/netpfil/ipfw/ip_fw_table_algo.c
@@ -29,14 +29,6 @@ __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-
/*
* Lookup table algorithms.
*
- * Lookup tables are implemented (at the moment) using the radix
- * tree used for routing tables. Tables store key-value entries, where
- * keys are network prefixes (addr/masklen), and values are integers.
- * As a degenerate case we can interpret keys as 32-bit integers
- * (with a /32 mask).
- *
- * The table is protected by the IPFW lock even for manipulation coming
- * from userland, because operations are typically fast.
*/
#include "opt_ipfw.h"
@@ -68,6 +60,17 @@ __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-
static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
+static int badd(const void *key, void *item, void *base, size_t nmemb,
+ size_t size, int (*compar) (const void *, const void *));
+static int bdel(const void *key, void *base, size_t nmemb, size_t size,
+ int (*compar) (const void *, const void *));
+
+
+/*
+ * CIDR implementation using radix
+ *
+ */
+
/*
* The radix code expects addr and mask to be array of bytes,
* with the first byte being the length of the array. rn_inithead
@@ -83,11 +86,9 @@ static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
*/
#define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
#define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
-#define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname))
#define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
#define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr))
-#define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname))
struct radix_cidr_entry {
struct radix_node rn[2];
@@ -110,23 +111,6 @@ struct radix_cidr_xentry {
uint8_t masklen;
};
-struct xaddr_iface {
- uint8_t if_len; /* length of this struct */
- uint8_t pad[7]; /* Align name */
- char ifname[IF_NAMESIZE]; /* Interface name */
-};
-
-struct radix_iface {
- struct radix_node rn[2];
- struct xaddr_iface iface;
- uint32_t value;
-};
-
-/*
- * CIDR implementation using radix
- *
- */
-
static int
ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
uint32_t *val)
@@ -164,7 +148,8 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
* New table
*/
static int
-ta_init_radix(void **ta_state, struct table_info *ti, char *data)
+ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+ char *data)
{
if (!rn_inithead(&ti->state, OFF_LEN_INET))
@@ -310,7 +295,8 @@ ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
static int
-ta_prepare_add_cidr(struct tentry_info *tei, void *ta_buf)
+ta_prepare_add_cidr(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
{
struct ta_buf_cidr *tb;
struct radix_cidr_entry *ent;
@@ -432,7 +418,8 @@ ta_add_cidr(void *ta_state, struct table_info *ti,
}
static int
-ta_prepare_del_cidr(struct tentry_info *tei, void *ta_buf)
+ta_prepare_del_cidr(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
{
struct ta_buf_cidr *tb;
struct sockaddr_in sa, mask;
@@ -512,7 +499,8 @@ ta_del_cidr(void *ta_state, struct table_info *ti,
}
static void
-ta_flush_cidr_entry(struct tentry_info *tei, void *ta_buf)
+ta_flush_cidr_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
{
struct ta_buf_cidr *tb;
@@ -539,25 +527,168 @@ struct table_algo radix_cidr = {
/*
- * Iface table cmds
+ * Iface table cmds.
+ *
+ * Implementation:
+ *
+ * Runtime part:
+ * - sorted array of "struct ifidx" pointed by ti->state.
+ * Array is allocated with routing 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
+ *
+ * Table data:
+ * - "struct iftable_cfg" is allocated to store table state (ta_state).
+ * - All table records are stored inside namedobj instance.
*
*/
+struct ifidx {
+ uint16_t kidx;
+ uint16_t spare;
+ uint32_t value;
+};
+
+struct iftable_cfg;
+
+struct ifentry {
+ struct named_object no;
+ struct ipfw_ifc ic;
+ struct iftable_cfg *icfg;
+ TAILQ_ENTRY(ifentry) next;
+ uint32_t value;
+ int linked;
+};
+
+struct iftable_cfg {
+ struct namedobj_instance *ii;
+ struct ip_fw_chain *ch;
+ struct table_info *ti;
+ void *main_ptr;
+ size_t size; /* Number of items allocated in array */
+ size_t count; /* Number of all items */
+ size_t used; /* Number of items _active_ now */
+};
+
+#define IFIDX_CHUNK 16
+
+int compare_ifidx(const void *k, const void *v);
+static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
+
+int
+compare_ifidx(const void *k, const void *v)
+{
+ struct ifidx *ifidx;
+ uint16_t key;
+
+ key = *((uint16_t *)k);
+ ifidx = (struct ifidx *)v;
+
+ if (key < ifidx->kidx)
+ return (-1);
+ else if (key > ifidx->kidx)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Adds item @item with key @key into ascending-sorted array @base.
+ * Assumes @base has enough additional storage.
+ *
+ * Returns 1 on success, 0 on duplicate key.
+ */
static int
-ta_lookup_iface(struct table_info *ti, void *key, uint32_t keylen,
+badd(const void *key, void *item, void *base, size_t nmemb,
+ size_t size, int (*compar) (const void *, const void *))
+{
+ int min, max, mid, shift, res;
+ caddr_t paddr;
+
+ if (nmemb == 0) {
+ memcpy(base, item, size);
+ return (1);
+ }
+
+ /* Binary search */
+ min = 0;
+ max = nmemb - 1;
+ mid = 0;
+ while (min <= max) {
+ mid = (min + max) / 2;
+ res = compar(key, (const void *)((caddr_t)base + mid * size));
+ if (res == 0)
+ return (0);
+
+ if (res > 0)
+ min = mid + 1;
+ else
+ max = mid - 1;
+ }
+
+ /* Item not found. */
+ res = compar(key, (const void *)((caddr_t)base + mid * size));
+ if (res > 0)
+ shift = mid + 1;
+ else
+ shift = mid;
+
+ paddr = (caddr_t)base + shift * size;
+ if (nmemb > shift)
+ memmove(paddr + size, paddr, (nmemb - shift) * size);
+
+ memcpy(paddr, item, size);
+
+ return (1);
+}
+
+/*
+ * Deletes item with key @key from ascending-sorted array @base.
+ *
+ * Returns 1 on success, 0 for non-existent key.
+ */
+static int
+bdel(const void *key, void *base, size_t nmemb, size_t size,
+ int (*compar) (const void *, const void *))
+{
+ caddr_t item;
+ size_t sz;
+
+ item = (caddr_t)bsearch(key, base, nmemb, size, compar);
+
+ if (item == NULL)
+ return (0);
+
+ sz = (caddr_t)base + nmemb * size - item;
+
+ if (sz > 0)
+ memmove(item, item + size, sz);
+
+ return (1);
+}
+
+static struct ifidx *
+ifidx_find(struct table_info *ti, void *key)
+{
+ struct ifidx *ifi;
+
+ ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
+ compare_ifidx);
+
+ return (ifi);
+}
+
+static int
+ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
uint32_t *val)
{
- struct radix_node_head *rnh;
- struct xaddr_iface iface;
- struct radix_iface *xent;
+ struct ifidx *ifi;
- KEY_LEN(iface) = KEY_LEN_IFACE +
- strlcpy(iface.ifname, (char *)key, IF_NAMESIZE) + 1;
+ ifi = ifidx_find(ti, key);
- rnh = (struct radix_node_head *)ti->xstate;
- xent = (struct radix_iface *)(rnh->rnh_matchaddr(&iface, rnh));
- if (xent != NULL) {
- *val = xent->value;
+ if (ifi != NULL) {
+ *val = ifi->value;
return (1);
}
@@ -565,59 +696,94 @@ ta_lookup_iface(struct table_info *ti, void *key, uint32_t keylen,
}
static int
-flush_iface_entry(struct radix_node *rn, void *arg)
+ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+ char *data)
{
- struct radix_node_head * const rnh = arg;
- struct radix_iface *xent;
+ struct iftable_cfg *icfg;
+
+ icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
+
+ icfg->ii = ipfw_objhash_create(16);
+ icfg->main_ptr = malloc(sizeof(struct ifidx) * IFIDX_CHUNK, M_IPFW,
+ M_WAITOK | M_ZERO);
+ icfg->size = IFIDX_CHUNK;
+ icfg->ch = ch;
+
+ *ta_state = icfg;
+ ti->state = icfg->main_ptr;
+ ti->lookup = ta_lookup_ifidx;
- xent = (struct radix_iface *)
- rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
- if (xent != NULL)
- free(xent, M_IPFW_TBL);
return (0);
}
-static int
-ta_init_iface(void **ta_state, struct table_info *ti, char *data)
+/*
+ * Handle tableinfo @ti pointer change (on table array resize).
+ */
+static void
+ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
{
+ struct iftable_cfg *icfg;
- if (!rn_inithead(&ti->xstate, OFF_LEN_IFACE))
- return (ENOMEM);
+ icfg = (struct iftable_cfg *)ta_state;
+ icfg->ti = ti;
+}
- *ta_state = NULL;
- ti->lookup = ta_lookup_iface;
+static void
+destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
+ void *arg)
+{
+ struct ifentry *ife;
+ struct ip_fw_chain *ch;
- return (0);
+ ch = (struct ip_fw_chain *)arg;
+ ife = (struct ifentry *)no;
+
+ ipfw_iface_del_notify(ch, &ife->ic);
+ free(ife, M_IPFW_TBL);
}
+/*
+ * Destroys table @ti
+ */
static void
-ta_destroy_iface(void *ta_state, struct table_info *ti)
+ta_destroy_ifidx(void *ta_state, struct table_info *ti)
{
- struct radix_node_head *rnh;
+ struct iftable_cfg *icfg;
+ struct ip_fw_chain *ch;
- rnh = (struct radix_node_head *)(ti->xstate);
- rnh->rnh_walktree(rnh, flush_iface_entry, rnh);
- rn_detachhead(&ti->xstate);
+ icfg = (struct iftable_cfg *)ta_state;
+ ch = icfg->ch;
+
+ if (icfg->main_ptr != NULL)
+ free(icfg->main_ptr, M_IPFW);
+
+ ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
+
+ ipfw_objhash_destroy(icfg->ii);
+
+ free(icfg, M_IPFW);
}
-struct ta_buf_iface
+struct ta_buf_ifidx
{
- void *addr_ptr;
- void *mask_ptr;
- void *ent_ptr;
- struct xaddr_iface iface;
+ struct ifentry *ife;
+ uint32_t value;
};
+/*
+ * Prepare state to add to the table:
+ * allocate ifentry and reference needed interface.
+ */
static int
-ta_prepare_add_iface(struct tentry_info *tei, void *ta_buf)
+ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
{
- struct ta_buf_iface *tb;
- struct radix_iface *xent;
- int mlen;
+ struct ta_buf_ifidx *tb;
char *ifname;
+ struct ifentry *ife;
- tb = (struct ta_buf_iface *)ta_buf;
+ tb = (struct ta_buf_ifidx *)ta_buf;
memset(tb, 0, sizeof(struct ta_buf_cidr));
/* Check if string is terminated */
@@ -625,189 +791,393 @@ ta_prepare_add_iface(struct tentry_info *tei, void *ta_buf)
if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
return (EINVAL);
- /* Include last \0 into comparison */
- mlen = strlen(ifname) + 1;
+ ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
+ ife->value = tei->value;
+ ife->ic.cb = if_notifier;
+ ife->ic.cbdata = ife;
+
+ if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0)
+ return (EINVAL);
- xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
- xent->value = tei->value;
- /* Set 'total' structure length */
- KEY_LEN(xent->iface) = KEY_LEN_IFACE + mlen;
- memcpy(xent->iface.ifname, tei->paddr, mlen);
- /* Set pointers */
- tb->ent_ptr = xent;
- tb->addr_ptr = (struct sockaddr *)&xent->iface;
- /* Assume direct match */
- tb->mask_ptr = NULL;
+ /* Use ipfw_iface 'ifname' field as stable storage */
+ ife->no.name = ife->ic.iface->ifname;
+
+ tb->ife = ife;
return (0);
}
static int
-ta_add_iface(void *ta_state, struct table_info *ti,
+ta_add_ifidx(void *ta_state, struct table_info *ti,
struct tentry_info *tei, void *ta_buf, uint64_t *pflags)
{
- struct radix_node_head *rnh;
- struct radix_node *rn;
- struct ta_buf_iface *tb;
- uint32_t value;
+ struct iftable_cfg *icfg;
+ struct ifentry *ife, *tmp;
+ struct ta_buf_ifidx *tb;
+ struct ipfw_iface *iif;
+ struct ifidx *ifi;
+ char *ifname;
- tb = (struct ta_buf_iface *)ta_buf;
+ tb = (struct ta_buf_ifidx *)ta_buf;
+ ifname = (char *)tei->paddr;
+ icfg = (struct iftable_cfg *)ta_state;
+ ife = tb->ife;
- rnh = ti->xstate;
- rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr);
-
- if (rn == NULL) {
+ ife->icfg = icfg;
+
+ tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
+
+ if (tmp != NULL) {
if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
return (EEXIST);
- /* Record already exists. Update value if we're asked to */
- rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh);
- if (rn == NULL) {
- /* Radix may have failed addition for other reasons */
- return (EINVAL);
+
+ /* We need to update value */
+ iif = tmp->ic.iface;
+ tmp->value = ife->value;
+
+ if (iif->resolved != 0) {
+ /* We need to update runtime value, too */
+ ifi = ifidx_find(ti, &iif->ifindex);
+ ifi->value = ife->value;
}
-
- value = ((struct radix_iface *)tb->ent_ptr)->value;
- ((struct radix_iface *)rn)->value = value;
/* Indicate that update has happened instead of addition */
tei->flags |= TEI_FLAGS_UPDATED;
-
return (0);
}
- tb->ent_ptr = NULL;
+ /* Link to internal list */
+ ipfw_objhash_add(icfg->ii, &ife->no);
+
+ /* Link notifier (possible running its callback) */
+ ipfw_iface_add_notify(icfg->ch, &ife->ic);
+ icfg->count++;
+
+ if (icfg->count + 1 == icfg->size) {
+ /* Notify core we need to grow */
+ *pflags = icfg->size + IFIDX_CHUNK;
+ }
+
+ tb->ife = NULL;
return (0);
}
+/*
+ * Prepare to delete key from table.
+ * Do basic interface name checks.
+ */
static int
-ta_prepare_del_iface(struct tentry_info *tei, void *ta_buf)
+ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
{
struct ta_buf_iface *tb;
- int mlen;
- char c;
+ char *ifname;
tb = (struct ta_buf_iface *)ta_buf;
memset(tb, 0, sizeof(struct ta_buf_cidr));
/* Check if string is terminated */
- c = ((char *)tei->paddr)[IF_NAMESIZE - 1];
- ((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0';
- mlen = strlen((char *)tei->paddr);
- if ((mlen == IF_NAMESIZE - 1) && (c != '\0'))
+ ifname = (char *)tei->paddr;
+ if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
return (EINVAL);
- struct xaddr_iface ifname, ifmask;
- memset(&ifname, 0, sizeof(ifname));
-
- /* Include last \0 into comparison */
- mlen++;
-
- /* Set 'total' structure length */
- KEY_LEN(ifname) = KEY_LEN_IFACE + mlen;
- KEY_LEN(ifmask) = KEY_LEN_IFACE + mlen;
- /* Assume direct match */
- memcpy(ifname.ifname, tei->paddr, mlen);
- /* Set pointers */
- tb->iface = ifname;
- tb->addr_ptr = &tb->iface;
- tb->mask_ptr = NULL;
-
return (0);
}
+/*
+ * Remove key from both configuration list and
+ * runtime array. Removed interface notification.
+ */
static int
-ta_del_iface(void *ta_state, struct table_info *ti,
+ta_del_ifidx(void *ta_state, struct table_info *ti,
struct tentry_info *tei, void *ta_buf, uint64_t *pflags)
{
- struct radix_node_head *rnh;
- struct radix_node *rn;
- struct ta_buf_iface *tb;
+ struct iftable_cfg *icfg;
+ struct ifentry *ife;
+ struct ta_buf_ifidx *tb;
+ char *ifname;
+ uint16_t ifindex;
+ int res;
- tb = (struct ta_buf_iface *)ta_buf;
+ tb = (struct ta_buf_ifidx *)ta_buf;
+ ifname = (char *)tei->paddr;
+ icfg = (struct iftable_cfg *)ta_state;
+ ife = tb->ife;
- rnh = ti->xstate;
- rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh);
+ ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
- tb->ent_ptr = rn;
-
- if (rn == NULL)
+ if (ife == NULL)
return (ENOENT);
+ if (ife->linked != 0) {
+ /* We have to remove item from runtime */
+ ifindex = ife->ic.iface->ifindex;
+
+ res = bdel(&ifindex, icfg->main_ptr, icfg->used,
+ sizeof(struct ifidx), compare_ifidx);
+
+ KASSERT(res == 1, ("index %d does not exist", ifindex));
+ icfg->used--;
+ ti->data = icfg->used;
+ ife->linked = 0;
+ }
+
+ /* Unlink from local list */
+ ipfw_objhash_del(icfg->ii, &ife->no);
+ /* Unlink notifier */
+ ipfw_iface_del_notify(icfg->ch, &ife->ic);
+
+ icfg->count--;
+
+ tb->ife = ife;
+
return (0);
}
+/*
+ * Flush deleted entry.
+ * Drops interface reference and frees entry.
+ */
static void
-ta_flush_iface_entry(struct tentry_info *tei, void *ta_buf)
+ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
{
- struct ta_buf_iface *tb;
+ struct ta_buf_ifidx *tb;
- tb = (struct ta_buf_iface *)ta_buf;
+ tb = (struct ta_buf_ifidx *)ta_buf;
- if (tb->ent_ptr != NULL)
- free(tb->ent_ptr, M_IPFW_TBL);
+ if (tb->ife != NULL) {
+ /* Unlink first */
+ ipfw_iface_unref(ch, &tb->ife->ic);
+ free(tb->ife, M_IPFW_TBL);
+ }
+}
+
+
+/*
+ * Handle interface announce/withdrawal for particular table.
+ * Every real runtime array modification happens here.
+ */
+static void
+if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
+{
+ struct ifentry *ife;
+ struct ifidx ifi;
+ struct iftable_cfg *icfg;
+ struct table_info *ti;
+ int res;
+
+ ife = (struct ifentry *)cbdata;
+ icfg = ife->icfg;
+ ti = icfg->ti;
+
+ KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
+
+ if (ife->linked == 0 && ifindex != 0) {
+ /* Interface announce */
+ ifi.kidx = ifindex;
+ ifi.spare = 0;
+ ifi.value = ife->value;
+ res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
+ sizeof(struct ifidx), compare_ifidx);
+ KASSERT(res == 1, ("index %d already exists", ifindex));
+ icfg->used++;
+ ti->data = icfg->used;
+ ife->linked = 1;
+ } else if (ife->linked != 0 && ifindex == 0) {
+ /* Interface withdrawal */
+ ifindex = ife->ic.iface->ifindex;
+
+ res = bdel(&ifindex, icfg->main_ptr, icfg->used,
+ sizeof(struct ifidx), compare_ifidx);
+
+ KASSERT(res == 1, ("index %d does not exist", ifindex));
+ icfg->used--;
+ ti->data = icfg->used;
+ ife->linked = 0;
+ }
+}
+
+
+/*
+ * Table growing callbacks.
+ */
+
+struct mod_ifidx {
+ void *main_ptr;
+ size_t size;
+};
+
+/*
+ * Allocate ned, larger runtime ifidx array.
+ */
+static int
+ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
+{
+ struct mod_ifidx *mi;
+
+ mi = (struct mod_ifidx *)ta_buf;
+
+ memset(mi, 0, sizeof(struct mod_ifidx));
+ mi->size = *pflags;
+ mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
+ M_WAITOK | M_ZERO);
+
+ return (0);
+}
+
+/*
+ * Copy data from old runtime array to new one.
+ */
+static int
+ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
+ uint64_t *pflags)
+{
+ struct mod_ifidx *mi;
+ struct iftable_cfg *icfg;
+
+ mi = (struct mod_ifidx *)ta_buf;
+ icfg = (struct iftable_cfg *)ta_state;
+
+ /* Check if we still need to grow array */
+ if (icfg->size >= mi->size) {
+ *pflags = 0;
+ return (0);
+ }
+
+ memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
+
+ return (0);
+}
+
+/*
+ * Switch old & new arrays.
+ */
+static int
+ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
+ uint64_t pflags)
+{
+ struct mod_ifidx *mi;
+ struct iftable_cfg *icfg;
+ void *old_ptr;
+
+ mi = (struct mod_ifidx *)ta_buf;
+ icfg = (struct iftable_cfg *)ta_state;
+
+ old_ptr = icfg->main_ptr;
+ icfg->main_ptr = mi->main_ptr;
+ icfg->size = mi->size;
+ ti->state = icfg->main_ptr;
+
+ mi->main_ptr = old_ptr;
+
+ return (0);
+}
+
+/*
+ * Free unneded array.
+ */
+static void
+ta_flush_mod_ifidx(void *ta_buf)
+{
+ struct mod_ifidx *mi;
+
+ mi = (struct mod_ifidx *)ta_buf;
+ if (mi->main_ptr != NULL)
+ free(mi->main_ptr, M_IPFW);
}
static int
-ta_dump_iface_tentry(void *ta_state, struct table_info *ti, void *e,
+ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
ipfw_obj_tentry *tent)
{
- struct radix_iface *xn;
+ struct ifentry *ife;
+
+ ife = (struct ifentry *)e;
- xn = (struct radix_iface *)e;
tent->masklen = 8 * IF_NAMESIZE;
- memcpy(&tent->k, &xn->iface.ifname, IF_NAMESIZE);
- tent->value = xn->value;
+ memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
+ tent->value = ife->value;
return (0);
}
static int
-ta_find_iface_tentry(void *ta_state, struct table_info *ti, void *key,
+ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, void *key,
uint32_t keylen, ipfw_obj_tentry *tent)
{
- struct radix_node_head *rnh;
- struct xaddr_iface iface;
- void *e;
- e = NULL;
+ struct iftable_cfg *icfg;
+ struct ifentry *ife;
+ char *ifname;
- KEY_LEN(iface) = KEY_LEN_IFACE +
- strlcpy(iface.ifname, (char *)key, IF_NAMESIZE) + 1;
+ icfg = (struct iftable_cfg *)ta_state;
+ ifname = (char *)key;
- rnh = (struct radix_node_head *)ti->xstate;
- e = rnh->rnh_matchaddr(&iface, rnh);
+ if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
+ return (EINVAL);
- if (e != NULL) {
- ta_dump_iface_tentry(ta_state, ti, e, tent);
+ ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
+
+ if (ife != NULL) {
+ ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
return (0);
}
return (ENOENT);
}
+struct wa_ifidx {
+ ta_foreach_f *f;
+ void *arg;
+};
+
static void
-ta_foreach_iface(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
void *arg)
{
- struct radix_node_head *rnh;
+ struct ifentry *ife;
+ struct wa_ifidx *wa;
- rnh = (struct radix_node_head *)(ti->xstate);
- rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
+ ife = (struct ifentry *)no;
+ wa = (struct wa_ifidx *)arg;
+
+ wa->f(ife, wa->arg);
+}
+
+static void
+ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+ void *arg)
+{
+ struct iftable_cfg *icfg;
+ struct wa_ifidx wa;
+
+ icfg = (struct iftable_cfg *)ta_state;
+
+ wa.f = f;
+ wa.arg = arg;
+
+ ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
}
-struct table_algo radix_iface = {
- .name = "radix_iface",
- .lookup = ta_lookup_iface,
- .init = ta_init_iface,
- .destroy = ta_destroy_iface,
- .prepare_add = ta_prepare_add_iface,
- .prepare_del = ta_prepare_del_iface,
- .add = ta_add_iface,
- .del = ta_del_iface,
- .flush_entry = ta_flush_iface_entry,
- .foreach = ta_foreach_iface,
- .dump_tentry = ta_dump_iface_tentry,
- .find_tentry = ta_find_iface_tentry,
+struct table_algo idx_iface = {
+ .name = "idx_iface",
+ .lookup = ta_lookup_ifidx,
+ .init = ta_init_ifidx,
+ .destroy = ta_destroy_ifidx,
+ .prepare_add = ta_prepare_add_ifidx,
+ .prepare_del = ta_prepare_del_ifidx,
+ .add = ta_add_ifidx,
+ .del = ta_del_ifidx,
+ .flush_entry = ta_flush_ifidx_entry,
+ .foreach = ta_foreach_ifidx,
+ .dump_tentry = ta_dump_ifidx_tentry,
+ .find_tentry = ta_find_ifidx_tentry,
+ .prepare_mod = ta_prepare_mod_ifidx,
+ .fill_mod = ta_fill_mod_ifidx,
+ .modify = ta_modify_ifidx,
+ .flush_mod = ta_flush_mod_ifidx,
+ .change_ti = ta_change_ti_ifidx,
};
void
@@ -817,7 +1187,7 @@ ipfw_table_algo_init(struct ip_fw_chain *chain)
* Register all algorithms presented here.
*/
ipfw_add_table_algo(chain, &radix_cidr);
- ipfw_add_table_algo(chain, &radix_iface);
+ ipfw_add_table_algo(chain, &idx_iface);
}
void
OpenPOWER on IntegriCloud