Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 14 Aug 2014 20:17:23 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r270001 - projects/ipfw/sys/netpfil/ipfw
Message-ID:  <201408142017.s7EKHN5W083982@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);
 }
 
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408142017.s7EKHN5W083982>