svn commit: r270001 - projects/ipfw/sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Thu Aug 14 22:01:29 UTC 2014
Author: melifaro
Date: Thu Aug 14 20:17:23 2014
New Revision: 270001
URL: http://svnweb.freebsd.org/changeset/base/270001
Log:
* Add cidr:kfib algo type just for fun. It binds kernel fib
of given number to a table.
Example:
# ipfw table fib2 create algo "cidr:kfib fib=2"
# ipfw table fib2 info
+++ table(fib2), set(0) +++
kindex: 2, type: cidr, locked
valtype: number, references: 0
algorithm: cidr:kfib fib=2
items: 11, size: 288
# ipfw table fib2 list
+++ table(fib2), set(0) +++
10.0.0.0/24 0
127.0.0.1/32 0
::/96 0
::1/128 0
::ffff:0.0.0.0/96 0
2a02:978:2::/112 0
fe80::/10 0
fe80:1::/64 0
fe80:2::/64 0
fe80:3::/64 0
ff02::/16 0
# ipfw table fib2 lookup 10.0.0.5
10.0.0.0/24 0
# ipfw table fib2 lookup 2a02:978:2::11
2a02:978:2::/112 0
# ipfw table fib2 detail
+++ table(fib2), set(0) +++
kindex: 2, type: cidr, locked
valtype: number, references: 0
algorithm: cidr:kfib fib=2
items: 11, size: 288
IPv4 algorithm radix info
items: 0 itemsize: 200
IPv6 algorithm radix info
items: 0 itemsize: 200
Modified:
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Thu Aug 14 19:15:20 2014 (r270000)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Thu Aug 14 20:17:23 2014 (r270001)
@@ -1885,6 +1885,60 @@ ipfw_mark_table_kidx(struct ip_fw_chain
return (count);
}
+struct dump_args {
+ struct table_info *ti;
+ struct table_config *tc;
+ struct sockopt_data *sd;
+ uint32_t cnt;
+ uint16_t uidx;
+ int error;
+ ipfw_table_entry *ent;
+ uint32_t size;
+ ipfw_obj_tentry tent;
+};
+
+static int
+count_ext_entries(void *e, void *arg)
+{
+ struct dump_args *da;
+
+ da = (struct dump_args *)arg;
+ da->cnt++;
+
+ return (0);
+}
+
+/*
+ * Gets number of items from table either using
+ * internal counter or calling algo callback for
+ * externally-managed tables.
+ *
+ * Returns number of records.
+ */
+static uint32_t
+table_get_count(struct ip_fw_chain *ch, struct table_config *tc)
+{
+ struct table_info *ti;
+ struct table_algo *ta;
+ struct dump_args da;
+
+ ti = KIDX_TO_TI(ch, tc->no.kidx);
+ ta = tc->ta;
+
+ /* Use internal counter for self-managed tables */
+ if ((ta->flags & TA_FLAG_READONLY) == 0)
+ return (tc->count);
+
+ /* Use callback to quickly get number of items */
+ if ((ta->flags & TA_FLAG_EXTCOUNTER) != 0)
+ return (ta->get_count(tc->astate, ti));
+
+ /* Count number of iterms ourselves */
+ memset(&da, 0, sizeof(da));
+ ta->foreach(tc->astate, ti, count_ext_entries, &da);
+
+ return (da.cnt);
+}
/*
* Exports table @tc info into standard ipfw_xtable_info format.
@@ -1903,7 +1957,7 @@ export_table_info(struct ip_fw_chain *ch
i->set = tc->no.set;
i->kidx = tc->no.kidx;
i->refcnt = tc->no.refcnt;
- i->count = tc->count;
+ i->count = table_get_count(ch, tc);
i->limit = tc->limit;
i->flags |= (tc->locked != 0) ? IPFW_TGFLAGS_LOCKED : 0;
i->size = tc->count * sizeof(ipfw_obj_tentry);
@@ -1982,18 +2036,6 @@ export_tables(struct ip_fw_chain *ch, ip
return (0);
}
-struct dump_args {
- struct table_info *ti;
- struct table_config *tc;
- struct sockopt_data *sd;
- uint32_t cnt;
- uint16_t uidx;
- int error;
- ipfw_table_entry *ent;
- uint32_t size;
- ipfw_obj_tentry tent;
-};
-
int
ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd)
@@ -2092,7 +2134,7 @@ ipfw_dump_table_v0(struct ip_fw_chain *c
struct table_config *tc;
struct table_algo *ta;
struct dump_args da;
- size_t sz;
+ size_t sz, count;
xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
if (xtbl == NULL)
@@ -2106,9 +2148,10 @@ ipfw_dump_table_v0(struct ip_fw_chain *c
IPFW_UH_RUNLOCK(ch);
return (0);
}
- sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
+ count = table_get_count(ch, tc);
+ sz = count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
- xtbl->cnt = tc->count;
+ xtbl->cnt = count;
xtbl->size = sz;
xtbl->type = tc->no.type;
xtbl->tbl = ti.uidx;
@@ -2149,7 +2192,7 @@ ipfw_count_table(struct ip_fw_chain *ch,
if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
return (ESRCH);
- *cnt = tc->count;
+ *cnt = table_get_count(ch, tc);
return (0);
}
@@ -2160,13 +2203,16 @@ int
ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
{
struct table_config *tc;
+ uint32_t count;
if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
*cnt = 0;
return (0); /* 'table all list' requires success */
}
- *cnt = tc->count * sizeof(ipfw_table_xentry);
- if (tc->count > 0)
+
+ count = table_get_count(ch, tc);
+ *cnt = count * sizeof(ipfw_table_xentry);
+ if (count > 0)
*cnt += sizeof(ipfw_xtable);
return (0);
}
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Thu Aug 14 19:15:20 2014 (r270000)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Thu Aug 14 20:17:23 2014 (r270001)
@@ -105,6 +105,7 @@ typedef int ta_find_tentry(void *ta_stat
ipfw_obj_tentry *tent);
typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti,
ipfw_ta_tinfo *tinfo);
+typedef uint32_t ta_get_count(void *ta_state, struct table_info *ti);
struct table_algo {
char name[16];
@@ -131,9 +132,11 @@ struct table_algo {
ta_dump_tentry *dump_tentry;
ta_print_config *print_config;
ta_dump_tinfo *dump_tinfo;
+ ta_get_count *get_count;
};
#define TA_FLAG_DEFAULT 0x01 /* Algo is default for given type */
#define TA_FLAG_READONLY 0x02 /* Algo does not support modifications*/
+#define TA_FLAG_EXTCOUNTER 0x04 /* Algo has external counter available*/
int ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta,
size_t size, int *idx);
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Thu Aug 14 19:15:20 2014 (r270000)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Thu Aug 14 20:17:23 2014 (r270001)
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD: projects/ipfw/sys/ne
#include <sys/queue.h>
#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
#include <net/radix.h>
+#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip_var.h> /* struct ipfw_rule_ref */
@@ -3519,6 +3520,263 @@ struct table_algo flow_hash = {
.flush_mod = ta_flush_mod_fhash,
};
+/*
+ * Kernel fibs bindings.
+ *
+ * Implementation:
+ *
+ * Runtime part:
+ * - fully relies on route API
+ * - fib number is stored in ti->data
+ *
+ */
+
+static struct rtentry *
+lookup_kfib(void *key, int keylen, int fib)
+{
+ struct sockaddr *s;
+
+ if (keylen == 4) {
+ struct sockaddr_in sin;
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(struct sockaddr_in);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = *(in_addr_t *)key;
+ s = (struct sockaddr *)&sin;
+ } else {
+ struct sockaddr_in6 sin6;
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = *(struct in6_addr *)key;
+ s = (struct sockaddr *)&sin6;
+ }
+
+ return (rtalloc1_fib(s, 0, 0, fib));
+}
+
+static int
+ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
+ uint32_t *val)
+{
+ struct rtentry *rte;
+
+ if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL)
+ return (0);
+
+ *val = 0;
+ RTFREE_LOCKED(rte);
+
+ return (1);
+}
+
+/* Parse 'fib=%d' */
+static int
+kfib_parse_opts(int *pfib, char *data)
+{
+ char *pdel, *pend, *s;
+ int fibnum;
+
+ if (data == NULL)
+ return (0);
+ if ((pdel = strchr(data, ' ')) == NULL)
+ return (0);
+ while (*pdel == ' ')
+ pdel++;
+ if (strncmp(pdel, "fib=", 4) != 0)
+ return (EINVAL);
+ if ((s = strchr(pdel, ' ')) != NULL)
+ *s++ = '\0';
+
+ pdel += 4;
+ /* Need \d+ */
+ fibnum = strtol(pdel, &pend, 10);
+ if (*pend != '\0')
+ return (EINVAL);
+
+ *pfib = fibnum;
+
+ return (0);
+}
+
+static void
+ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf,
+ size_t bufsize)
+{
+
+ if (ti->data != 0)
+ snprintf(buf, bufsize, "%s fib=%lu", "cidr:kfib", ti->data);
+ else
+ snprintf(buf, bufsize, "%s", "cidr:kfib");
+}
+
+static int
+ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+ char *data, uint8_t tflags)
+{
+ int error, fibnum;
+
+ fibnum = 0;
+ if ((error = kfib_parse_opts(&fibnum, data)) != 0)
+ return (error);
+
+ if (fibnum >= rt_numfibs)
+ return (E2BIG);
+
+ ti->data = fibnum;
+ ti->lookup = ta_lookup_kfib;
+
+ return (0);
+}
+
+/*
+ * Destroys table @ti
+ */
+static void
+ta_destroy_kfib(void *ta_state, struct table_info *ti)
+{
+
+}
+
+/*
+ * Provide algo-specific table info
+ */
+static void
+ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
+{
+
+ tinfo->flags = IPFW_TATFLAGS_AFDATA;
+ tinfo->taclass4 = IPFW_TACLASS_RADIX;
+ tinfo->count4 = 0;
+ tinfo->itemsize4 = sizeof(struct rtentry);
+ tinfo->taclass6 = IPFW_TACLASS_RADIX;
+ tinfo->count6 = 0;
+ tinfo->itemsize6 = sizeof(struct rtentry);
+}
+
+static int
+contigmask(uint8_t *p, int len)
+{
+ int i, n;
+
+ for (i = 0; i < len ; i++)
+ if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
+ break;
+ for (n= i + 1; n < len; n++)
+ if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0)
+ return (-1); /* mask not contiguous */
+ return (i);
+}
+
+
+static int
+ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
+ ipfw_obj_tentry *tent)
+{
+ struct rtentry *rte;
+ struct sockaddr_in *addr, *mask;
+ struct sockaddr_in6 *addr6, *mask6;
+ int len;
+
+ rte = (struct rtentry *)e;
+ addr = (struct sockaddr_in *)rt_key(rte);
+ mask = (struct sockaddr_in *)rt_mask(rte);
+ len = 0;
+
+ /* Guess IPv4/IPv6 radix by sockaddr family */
+ if (addr->sin_family == AF_INET) {
+ tent->k.addr.s_addr = addr->sin_addr.s_addr;
+ len = 32;
+ if (mask != NULL)
+ len = contigmask((uint8_t *)&mask->sin_addr, 32);
+ if (len == -1)
+ len = 0;
+ tent->masklen = len;
+ tent->subtype = AF_INET;
+ tent->value = 0; /* Do we need to put GW here? */
+#ifdef INET6
+ } else if (addr->sin_family == AF_INET6) {
+ addr6 = (struct sockaddr_in6 *)addr;
+ mask6 = (struct sockaddr_in6 *)mask;
+ memcpy(&tent->k, &addr6->sin6_addr, sizeof(struct in6_addr));
+ len = 128;
+ if (mask6 != NULL)
+ len = contigmask((uint8_t *)&mask6->sin6_addr, 128);
+ if (len == -1)
+ len = 0;
+ tent->masklen = len;
+ tent->subtype = AF_INET6;
+ tent->value = 0;
+#endif
+ }
+
+ return (0);
+}
+
+static int
+ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct rtentry *rte;
+ void *key;
+ int keylen;
+
+ if (tent->subtype == AF_INET) {
+ key = &tent->k.addr;
+ keylen = sizeof(struct in_addr);
+ } else {
+ key = &tent->k.addr6;
+ keylen = sizeof(struct in6_addr);
+ }
+
+ if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL)
+ return (0);
+
+ if (rte != NULL) {
+ ta_dump_kfib_tentry(ta_state, ti, rte, tent);
+ RTFREE_LOCKED(rte);
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static void
+ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+ void *arg)
+{
+ struct radix_node_head *rnh;
+ int error;
+
+ rnh = rt_tables_get_rnh(ti->data, AF_INET);
+ if (rnh != NULL) {
+ RADIX_NODE_HEAD_RLOCK(rnh);
+ error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
+ RADIX_NODE_HEAD_RUNLOCK(rnh);
+ }
+
+ rnh = rt_tables_get_rnh(ti->data, AF_INET6);
+ if (rnh != NULL) {
+ RADIX_NODE_HEAD_RLOCK(rnh);
+ error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
+ RADIX_NODE_HEAD_RUNLOCK(rnh);
+ }
+}
+
+struct table_algo cidr_kfib = {
+ .name = "cidr:kfib",
+ .type = IPFW_TABLE_CIDR,
+ .flags = TA_FLAG_READONLY,
+ .ta_buf_size = 0,
+ .init = ta_init_kfib,
+ .destroy = ta_destroy_kfib,
+ .foreach = ta_foreach_kfib,
+ .dump_tentry = ta_dump_kfib_tentry,
+ .find_tentry = ta_find_kfib_tentry,
+ .dump_tinfo = ta_dump_kfib_tinfo,
+ .print_config = ta_print_kfib_config,
+};
+
void
ipfw_table_algo_init(struct ip_fw_chain *ch)
{
@@ -3533,6 +3791,7 @@ ipfw_table_algo_init(struct ip_fw_chain
ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
+ ipfw_add_table_algo(ch, &cidr_kfib, sz, &cidr_kfib.idx);
}
void
@@ -3544,6 +3803,7 @@ ipfw_table_algo_destroy(struct ip_fw_cha
ipfw_del_table_algo(ch, iface_idx.idx);
ipfw_del_table_algo(ch, number_array.idx);
ipfw_del_table_algo(ch, flow_hash.idx);
+ ipfw_del_table_algo(ch, cidr_kfib.idx);
}
More information about the svn-src-projects
mailing list