svn commit: r269252 - projects/ipfw/sys/netpfil/ipfw

Alexander V. Chernikov melifaro at FreeBSD.org
Tue Jul 29 19:49:39 UTC 2014


Author: melifaro
Date: Tue Jul 29 19:49:38 2014
New Revision: 269252
URL: http://svnweb.freebsd.org/changeset/base/269252

Log:
  * Add new ipfw cidr algorihm: hash table.
  Algorithm works with both IPv4 and IPv6 prefixes, /32 and /128
  ranges are assumed by default.
  It works the following way: input IP address is masked to specified
  mask, hashed and searched inside hash bucket.
  
  Current implementation does not support "lookup" method and hash auto-resize.
  This will be changed soon.
  
  some examples:
  
  ipfw table mi_test2 create type cidr algo cidr:hash
  ipfw table mi_test create type cidr algo "cidr:hash masks=/30,/64"
  
  ipfw table mi_test2 info
  +++ table(mi_test2), set(0) +++
   type: cidr, kindex: 7
   valtype: number, references: 0
   algorithm: cidr:hash
   items: 0, size: 220
  
  ipfw table mi_test info
  +++ table(mi_test), set(0) +++
   type: cidr, kindex: 6
   valtype: number, references: 0
   algorithm: cidr:hash masks=/30,/64
   items: 0, size: 220
  
  ipfw table mi_test add 10.0.0.5/30
  ipfw table mi_test add 10.0.0.8/30
  ipfw table mi_test add 2a02:6b8:b010::1/64 25
  
  ipfw table mi_test list
  +++ table(mi_test), set(0) +++
  10.0.0.4/30 0
  10.0.0.8/30 0
  2a02:6b8:b010::/64 25

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	Tue Jul 29 19:49:27 2014	(r269251)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Tue Jul 29 19:49:38 2014	(r269252)
@@ -1592,10 +1592,9 @@ find_table_algo(struct tables_config *tc
 	/* Search by type */
 	switch (ti->type) {
 	case IPFW_TABLE_CIDR:
-		return (&radix_cidr);
+		return (&cidr_radix);
 	case IPFW_TABLE_INTERFACE:
-		return (&idx_iface);
-		//return (&radix_iface);
+		return (&iface_idx);
 	}
 
 	return (NULL);

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Tue Jul 29 19:49:27 2014	(r269251)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Tue Jul 29 19:49:38 2014	(r269252)
@@ -118,7 +118,7 @@ struct table_algo {
 };
 
 void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta);
-extern struct table_algo radix_cidr, idx_iface;
+extern struct table_algo cidr_radix, iface_idx;
 
 void ipfw_table_algo_init(struct ip_fw_chain *chain);
 void ipfw_table_algo_destroy(struct ip_fw_chain *chain);

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Tue Jul 29 19:49:27 2014	(r269251)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Tue Jul 29 19:49:38 2014	(r269252)
@@ -514,7 +514,7 @@ ta_flush_cidr_entry(struct ip_fw_chain *
 		free(tb->ent_ptr, M_IPFW_TBL);
 }
 
-struct table_algo radix_cidr = {
+struct table_algo cidr_radix = {
 	.name		= "cidr:radix",
 	.lookup		= ta_lookup_radix,
 	.init		= ta_init_radix,
@@ -531,6 +531,686 @@ struct table_algo radix_cidr = {
 
 
 /*
+ * cidr:hash cmds
+ *
+ *
+ * ti->data:
+ * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
+ * [        8][        8[          8][         8]
+ *
+ * inv.mask4: 32 - mask
+ * inv.mask6:
+ * 1) _slow lookup: mask
+ * 2) _aligned: (128 - mask) / 8
+ * 3) _64: 8
+ */
+
+struct chashentry;
+
+SLIST_HEAD(chashbhead, chashentry);
+
+struct chash_cfg {
+	struct chashbhead *head4;
+	struct chashbhead *head6;
+	size_t	size4;
+	size_t	size6;
+	size_t	items;
+	uint8_t	mask4;
+	uint8_t	mask6;
+};
+
+struct chashentry {
+	SLIST_ENTRY(chashentry)	next;
+	uint32_t	value;
+	uint32_t	type;
+	union {
+		uint32_t	a4;	/* Host format */
+		struct in6_addr	a6;	/* Network format */
+	} a;
+};
+
+static __inline uint32_t
+hash_ip(uint32_t addr, int hsize)
+{
+
+	return (addr % (hsize - 1));
+}
+
+static __inline uint32_t
+hash_ip6(struct in6_addr *addr6, int hsize)
+{
+	uint32_t i;
+
+	i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
+	    addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
+
+	return (i % (hsize - 1));
+}
+
+
+static __inline uint16_t
+hash_ip64(struct in6_addr *addr6, int hsize)
+{
+	uint32_t i;
+
+	i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
+
+	return (i % (hsize - 1));
+}
+
+
+static __inline uint32_t
+hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
+{
+	struct in6_addr mask6;
+
+	ipv6_writemask(&mask6, mask);
+	memcpy(addr6, key, sizeof(struct in6_addr));
+	APPLY_MASK(addr6, &mask6);
+	return (hash_ip6(addr6, hsize));
+}
+
+static __inline uint32_t
+hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
+{
+	uint64_t *paddr;
+
+	paddr = (uint64_t *)addr6;
+	*paddr = 0;
+	*(paddr + 1) = 0;
+	memcpy(addr6, key, mask);
+	return (hash_ip6(addr6, hsize));
+}
+
+static int
+ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
+    uint32_t *val)
+{
+	struct chashbhead *head;
+	struct chashentry *ent;
+	uint16_t hash, hsize;
+	uint8_t imask;
+
+	if (keylen == sizeof(in_addr_t)) {
+		head = (struct chashbhead *)ti->state;
+		imask = ti->data >> 24;
+		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
+		uint32_t a;
+		a = ntohl(*((in_addr_t *)key));
+		a = a >> imask;
+		hash = hash_ip(a, hsize);
+		SLIST_FOREACH(ent, &head[hash], next) {
+			if (ent->a.a4 == a) {
+				*val = ent->value;
+				return (1);
+			}
+		}
+	} else {
+		/* IPv6: worst scenario: non-round mask */
+		struct in6_addr addr6;
+		head = (struct chashbhead *)ti->xstate;
+		imask = (ti->data & 0xFF0000) >> 16;
+		hsize = 1 << (ti->data & 0xFF);
+		hash = hash_ip6_slow(&addr6, key, imask, hsize);
+		SLIST_FOREACH(ent, &head[hash], next) {
+			if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
+				*val = ent->value;
+				return (1);
+			}
+		}
+	}
+
+	return (0);
+}
+
+static int
+ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
+    uint32_t *val)
+{
+	struct chashbhead *head;
+	struct chashentry *ent;
+	uint16_t hash, hsize;
+	uint8_t imask;
+
+	if (keylen == sizeof(in_addr_t)) {
+		head = (struct chashbhead *)ti->state;
+		imask = ti->data >> 24;
+		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
+		uint32_t a;
+		a = ntohl(*((in_addr_t *)key));
+		a = a >> imask;
+		hash = hash_ip(a, hsize);
+		SLIST_FOREACH(ent, &head[hash], next) {
+			if (ent->a.a4 == a) {
+				*val = ent->value;
+				return (1);
+			}
+		}
+	} else {
+		/* IPv6: aligned to 8bit mask */
+		struct in6_addr addr6;
+		uint64_t *paddr, *ptmp;
+		head = (struct chashbhead *)ti->xstate;
+		imask = (ti->data & 0xFF0000) >> 16;
+		hsize = 1 << (ti->data & 0xFF);
+
+		hash = hash_ip6_al(&addr6, key, imask, hsize);
+		paddr = (uint64_t *)&addr6;
+		SLIST_FOREACH(ent, &head[hash], next) {
+			ptmp = (uint64_t *)&ent->a.a6;
+			if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
+				*val = ent->value;
+				return (1);
+			}
+		}
+	}
+
+	return (0);
+}
+
+static int
+ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
+    uint32_t *val)
+{
+	struct chashbhead *head;
+	struct chashentry *ent;
+	uint16_t hash, hsize;
+	uint8_t imask;
+
+	if (keylen == sizeof(in_addr_t)) {
+		head = (struct chashbhead *)ti->state;
+		imask = ti->data >> 24;
+		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
+		uint32_t a;
+		a = ntohl(*((in_addr_t *)key));
+		a = a >> imask;
+		hash = hash_ip(a, hsize);
+		SLIST_FOREACH(ent, &head[hash], next) {
+			if (ent->a.a4 == a) {
+				*val = ent->value;
+				return (1);
+			}
+		}
+	} else {
+		/* IPv6: /64 */
+		uint64_t a6, *paddr;
+		head = (struct chashbhead *)ti->xstate;
+		paddr = (uint64_t *)key;
+		hsize = 1 << (ti->data & 0xFF);
+		a6 = *paddr;
+		hash = hash_ip64((struct in6_addr *)key, hsize);
+		SLIST_FOREACH(ent, &head[hash], next) {
+			paddr = (uint64_t *)&ent->a.a6;
+			if (a6 == *paddr) {
+				*val = ent->value;
+				return (1);
+			}
+		}
+	}
+
+	return (0);
+}
+
+static int
+chash_parse_opts(struct chash_cfg *ccfg, char *data)
+{
+	char *pdel, *pend, *s;
+	int mask4, mask6;
+
+	mask4 = ccfg->mask4;
+	mask6 = ccfg->mask6;
+
+	if (data == NULL)
+		return (0);
+	if ((pdel = strchr(data, ' ')) == NULL)
+		return (0);
+	while (*pdel == ' ')
+		pdel++;
+	if (strncmp(pdel, "masks=", 6) != 0)
+		return (EINVAL);
+	if ((s = strchr(pdel, ' ')) != NULL)
+		*s++ = '\0';
+
+	pdel += 6;
+	/* Need /XX[,/YY] */
+	if (*pdel++ != '/')
+		return (EINVAL);
+	mask4 = strtol(pdel, &pend, 10);
+	if (*pend == ',') {
+		/* ,/YY */
+		pdel = pend + 1;
+		if (*pdel++ != '/')
+			return (EINVAL);
+		mask6 = strtol(pdel, &pend, 10);
+		if (*pend != '\0')
+			return (EINVAL);
+	} else if (*pend != '\0')
+		return (EINVAL);
+
+	if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
+		return (EINVAL);
+
+	ccfg->mask4 = mask4;
+	ccfg->mask6 = mask6;
+
+	return (0);
+}
+
+static void
+ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
+    size_t bufsize)
+{
+	struct chash_cfg *ccfg;
+
+	ccfg = (struct chash_cfg *)ta_state;
+
+	if (ccfg->mask4 != 32 || ccfg->mask6 != 128)
+		snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash",
+		    ccfg->mask4, ccfg->mask6);
+	else
+		snprintf(buf, bufsize, "%s", "cidr:hash");
+}
+
+
+/*
+ * New table.
+ * We assume 'data' to be either NULL or the following format:
+ * 'cidr:hash [masks=/32[,/128]]'
+ */
+static int
+ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+    char *data)
+{
+	int error, i;
+	int v4, v6;
+	struct chash_cfg *ccfg;
+
+	ccfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
+
+	ccfg->mask4 = 32;
+	ccfg->mask6 = 128;
+
+	if ((error = chash_parse_opts(ccfg, data)) != 0) {
+		free(ccfg, M_IPFW);
+		return (error);
+	}
+
+	v4 = 7;
+	v6 = 7;
+	ccfg->size4 = 1 << v4;
+	ccfg->size6 = 1 << v6;
+
+	ccfg->head4 = malloc(sizeof(struct chashbhead) * ccfg->size4, M_IPFW,
+	    M_WAITOK | M_ZERO);
+	ccfg->head6 = malloc(sizeof(struct chashbhead) * ccfg->size6, M_IPFW,
+	    M_WAITOK | M_ZERO);
+	for (i = 0; i < ccfg->size4; i++)
+		SLIST_INIT(&ccfg->head4[i]);
+	for (i = 0; i < ccfg->size6; i++)
+		SLIST_INIT(&ccfg->head6[i]);
+
+
+	*ta_state = ccfg;
+	ti->state = ccfg->head4;
+	ti->xstate = ccfg->head6;
+
+	/* Store data depending on v6 mask length */
+	if (ccfg->mask6 == 64) {
+		ti->data = (32 - ccfg->mask4) << 24 | (128 - ccfg->mask6) << 16 |
+		    v4 << 8 | v6;
+		ti->lookup = ta_lookup_chash_64;
+	} else if ((ccfg->mask6  % 8) == 0) {
+		ti->data = (32 - ccfg->mask4) << 24 |
+		    ccfg->mask6 << 13 | v4 << 8 | v6;
+		ti->lookup = ta_lookup_chash_aligned;
+	} else {
+		/* don't do that! */
+		ti->data = (32 - ccfg->mask4) << 24 |
+		    ccfg->mask6 << 16 | v4 << 8 | v6;
+		ti->lookup = ta_lookup_chash_slow;
+	}
+
+	return (0);
+}
+
+static void
+ta_destroy_chash(void *ta_state, struct table_info *ti)
+{
+	struct chash_cfg *ccfg;
+	struct chashentry *ent, *ent_next;
+	int i;
+
+	ccfg = (struct chash_cfg *)ta_state;
+
+	for (i = 0; i < ccfg->size4; i++)
+		SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
+			free(ent, M_IPFW_TBL);
+
+	for (i = 0; i < ccfg->size6; i++)
+		SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
+			free(ent, M_IPFW_TBL);
+
+	free(ccfg->head4, M_IPFW);
+	free(ccfg->head6, M_IPFW);
+}
+
+static int
+ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
+    ipfw_obj_tentry *tent)
+{
+	struct chash_cfg *ccfg;
+	struct chashentry *ent;
+
+	ccfg = (struct chash_cfg *)ta_state;
+	ent = (struct chashentry *)e;
+
+	if (ent->type == AF_INET) {
+		tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - ccfg->mask4));
+		tent->masklen = ccfg->mask4;
+		tent->subtype = AF_INET;
+		tent->value = ent->value;
+#ifdef INET6
+	} else {
+		memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
+		tent->masklen = ccfg->mask6;
+		tent->subtype = AF_INET6;
+		tent->value = ent->value;
+#endif
+	}
+
+	return (0);
+}
+
+static int
+ta_find_chash_tentry(void *ta_state, struct table_info *ti, void *key,
+    uint32_t keylen, ipfw_obj_tentry *tent)
+{
+#if 0
+	struct radix_node_head *rnh;
+	void *e;
+
+	e = NULL;
+	if (keylen == sizeof(in_addr_t)) {
+		struct sockaddr_in sa;
+		KEY_LEN(sa) = KEY_LEN_INET;
+		sa.sin_addr.s_addr = *((in_addr_t *)key);
+		rnh = (struct radix_node_head *)ti->state;
+		e = rnh->rnh_matchaddr(&sa, rnh);
+	} else {
+		struct sa_in6 sa6;
+		KEY_LEN(sa6) = KEY_LEN_INET6;
+		memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
+		rnh = (struct radix_node_head *)ti->xstate;
+		e = rnh->rnh_matchaddr(&sa6, rnh);
+	}
+
+	if (e != NULL) {
+		ta_dump_radix_tentry(ta_state, ti, e, tent);
+		return (0);
+	}
+#endif
+	return (ENOENT);
+}
+
+static void
+ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+    void *arg)
+{
+	struct chash_cfg *ccfg;
+	struct chashentry *ent, *ent_next;
+	int i;
+
+	ccfg = (struct chash_cfg *)ta_state;
+
+	for (i = 0; i < ccfg->size4; i++)
+		SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
+			f(ent, arg);
+
+	for (i = 0; i < ccfg->size6; i++)
+		SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
+			f(ent, arg);
+}
+
+
+struct ta_buf_chash
+{
+	void *ent_ptr;
+	int type;
+	union {
+		uint32_t	a4;
+		struct in6_addr	a6;
+	} a;
+};
+
+static int
+ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
+    void *ta_buf)
+{
+	struct ta_buf_chash *tb;
+	struct chashentry *ent;
+	int mlen;
+	struct in6_addr mask6;
+
+	tb = (struct ta_buf_chash *)ta_buf;
+	memset(tb, 0, sizeof(struct ta_buf_chash));
+
+	mlen = tei->masklen;
+	
+	if (tei->subtype == AF_INET) {
+#ifdef INET
+		if (mlen > 32)
+			return (EINVAL);
+		ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
+		ent->value = tei->value;
+		ent->type = AF_INET;
+
+		/* Calculate mask */
+		ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
+		tb->ent_ptr = ent;
+#endif
+#ifdef INET6
+	} else if (tei->subtype == AF_INET6) {
+		/* IPv6 case */
+		if (mlen > 128)
+			return (EINVAL);
+		ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
+		ent->value = tei->value;
+		ent->type = AF_INET6;
+
+		ipv6_writemask(&mask6, mlen);
+		memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
+		APPLY_MASK(&ent->a.a6, &mask6);
+		tb->ent_ptr = ent;
+#endif
+	} else {
+		/* Unknown CIDR type */
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+static int
+ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+    void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+{
+	struct chash_cfg *ccfg;
+	struct chashbhead *head;
+	struct chashentry *ent, *tmp;
+	struct ta_buf_chash *tb;
+	int exists;
+	uint32_t hash;
+
+	ccfg = (struct chash_cfg *)ta_state;
+	tb = (struct ta_buf_chash *)ta_buf;
+	ent = (struct chashentry *)tb->ent_ptr;
+	hash = 0;
+	exists = 0;
+
+	if (tei->subtype == AF_INET) {
+		if (tei->masklen != ccfg->mask4)
+			return (EINVAL);
+		head = ccfg->head4;
+		hash = hash_ip(ent->a.a4, ccfg->size4);
+		/* Check for existence */
+		SLIST_FOREACH(tmp, &head[hash], next) {
+			if (tmp->a.a4 == ent->a.a4) {
+				exists = 1;
+				break;
+			}
+		}
+	} else {
+		if (tei->masklen != ccfg->mask6)
+			return (EINVAL);
+		head = ccfg->head6;
+		if (tei->masklen == 64)
+			hash = hash_ip64(&ent->a.a6, ccfg->size6);
+		else
+			hash = hash_ip6(&ent->a.a6, ccfg->size6);
+		/* Check for existence */
+		SLIST_FOREACH(tmp, &head[hash], next) {
+			if (memcmp(&tmp->a.a6, &ent->a.a6, 16)) {
+				exists = 1;
+				break;
+			}
+		}
+	}
+
+	if (exists == 1) {
+		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
+			return (EEXIST);
+		/* Record already exists. Update value if we're asked to */
+		tmp->value = tei->value;
+		/* Indicate that update has happened instead of addition */
+		tei->flags |= TEI_FLAGS_UPDATED;
+		*pnum = 0;
+	} else {
+		SLIST_INSERT_HEAD(&head[hash], ent, next);
+		tb->ent_ptr = NULL;
+		*pnum = 1;
+	}
+
+	return (0);
+}
+
+static int
+ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
+    void *ta_buf)
+{
+	struct ta_buf_chash *tb;
+	int mlen;
+	struct in6_addr mask6;
+
+	tb = (struct ta_buf_chash *)ta_buf;
+	memset(tb, 0, sizeof(struct ta_buf_chash));
+
+	mlen = tei->masklen;
+	
+	if (tei->subtype == AF_INET) {
+#ifdef INET
+		if (mlen > 32)
+			return (EINVAL);
+		tb->type = AF_INET;
+
+		/* Calculate masked address */
+		tb->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
+#endif
+#ifdef INET6
+	} else if (tei->subtype == AF_INET6) {
+		/* IPv6 case */
+		if (mlen > 128)
+			return (EINVAL);
+		tb->type = AF_INET6;
+
+		ipv6_writemask(&mask6, mlen);
+		memcpy(&tb->a.a6, tei->paddr, sizeof(struct in6_addr));
+		APPLY_MASK(&tb->a.a6, &mask6);
+#endif
+	} else {
+		/* Unknown CIDR type */
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+static int
+ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+    void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+{
+	struct chash_cfg *ccfg;
+	struct chashbhead *head;
+	struct chashentry *ent, *tmp_next;
+	struct ta_buf_chash *tb;
+	uint32_t hash;
+
+	ccfg = (struct chash_cfg *)ta_state;
+	tb = (struct ta_buf_chash *)ta_buf;
+
+	if (tei->subtype == AF_INET) {
+		if (tei->masklen != ccfg->mask4)
+			return (EINVAL);
+		head = ccfg->head4;
+		hash = hash_ip(tb->a.a4, ccfg->size4);
+
+		SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
+			if (ent->a.a4 == tb->a.a4) {
+				SLIST_REMOVE(&head[hash], ent, chashentry,next);
+				*pnum = 1;
+				return (0);
+			}
+		}
+	} else {
+		if (tei->masklen != ccfg->mask6)
+			return (EINVAL);
+		head = ccfg->head6;
+		if (tei->masklen == 64)
+			hash = hash_ip64(&tb->a.a6, ccfg->size6);
+		else
+			hash = hash_ip6(&tb->a.a6, ccfg->size6);
+
+		SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
+			if (memcmp(&ent->a.a6, &tb->a.a6, 16)) {
+				SLIST_REMOVE(&head[hash], ent, chashentry,next);
+				*pnum = 1;
+				return (0);
+			}
+		}
+	}
+
+	return (ENOENT);
+}
+
+static void
+ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
+    void *ta_buf)
+{
+	struct ta_buf_chash *tb;
+
+	tb = (struct ta_buf_chash *)ta_buf;
+
+	if (tb->ent_ptr != NULL)
+		free(tb->ent_ptr, M_IPFW_TBL);
+}
+
+struct table_algo cidr_hash = {
+	.name		= "cidr:hash",
+	.lookup		= ta_lookup_chash_slow,
+	.init		= ta_init_chash,
+	.destroy	= ta_destroy_chash,
+	.prepare_add	= ta_prepare_add_chash,
+	.prepare_del	= ta_prepare_del_chash,
+	.add		= ta_add_chash,
+	.del		= ta_del_chash,
+	.flush_entry	= ta_flush_chash_entry,
+	.foreach	= ta_foreach_chash,
+	.dump_tentry	= ta_dump_chash_tentry,
+	.find_tentry	= ta_find_chash_tentry,
+	.print_config	= ta_print_chash_config,
+};
+
+
+/*
  * Iface table cmds.
  *
  * Implementation:
@@ -560,7 +1240,6 @@ struct ifentry {
 	struct named_object	no;
 	struct ipfw_ifc		ic;
 	struct iftable_cfg	*icfg;
-	TAILQ_ENTRY(ifentry)	next;
 	uint32_t		value;
 	int			linked;
 };
@@ -788,7 +1467,7 @@ ta_prepare_add_ifidx(struct ip_fw_chain 
 	struct ifentry *ife;
 
 	tb = (struct ta_buf_ifidx *)ta_buf;
-	memset(tb, 0, sizeof(struct ta_buf_cidr));
+	memset(tb, 0, sizeof(struct ta_buf_ifidx));
 
 	/* Check if string is terminated */
 	ifname = (char *)tei->paddr;
@@ -877,11 +1556,11 @@ static int
 ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
     void *ta_buf)
 {
-	struct ta_buf_iface *tb;
+	struct ta_buf_ifidx *tb;
 	char *ifname;
 
-	tb = (struct ta_buf_iface *)ta_buf;
-	memset(tb, 0, sizeof(struct ta_buf_cidr));
+	tb = (struct ta_buf_ifidx *)ta_buf;
+	memset(tb, 0, sizeof(struct ta_buf_ifidx));
 
 	/* Check if string is terminated */
 	ifname = (char *)tei->paddr;
@@ -1167,7 +1846,7 @@ ta_foreach_ifidx(void *ta_state, struct 
 	ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
 }
 
-struct table_algo idx_iface = {
+struct table_algo iface_idx = {
 	.name		= "iface:array",
 	.lookup		= ta_lookup_ifidx,
 	.init		= ta_init_ifidx,
@@ -1193,8 +1872,9 @@ ipfw_table_algo_init(struct ip_fw_chain 
 	/*
 	 * Register all algorithms presented here.
 	 */
-	ipfw_add_table_algo(chain, &radix_cidr);
-	ipfw_add_table_algo(chain, &idx_iface);
+	ipfw_add_table_algo(chain, &cidr_radix);
+	ipfw_add_table_algo(chain, &cidr_hash);
+	ipfw_add_table_algo(chain, &iface_idx);
 }
 
 void


More information about the svn-src-projects mailing list