2 * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-12 09:59:11Z melifaro $");
30 * Lookup table algorithms.
37 #error IPFIREWALL requires INET.
39 #include "opt_inet6.h"
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/kernel.h>
46 #include <sys/rwlock.h>
47 #include <sys/socket.h>
48 #include <sys/queue.h>
49 #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
50 #include <net/radix.h>
51 #include <net/route.h>
54 #include <netinet/in.h>
55 #include <netinet/ip_var.h> /* struct ipfw_rule_ref */
56 #include <netinet/ip_fw.h>
58 #include <netpfil/ipfw/ip_fw_private.h>
59 #include <netpfil/ipfw/ip_fw_table.h>
61 static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
63 static int badd(const void *key, void *item, void *base, size_t nmemb,
64 size_t size, int (*compar) (const void *, const void *));
65 static int bdel(const void *key, void *base, size_t nmemb, size_t size,
66 int (*compar) (const void *, const void *));
70 * CIDR implementation using radix
75 * The radix code expects addr and mask to be array of bytes,
76 * with the first byte being the length of the array. rn_inithead
77 * is called with the offset in bits of the lookup key within the
78 * array. If we use a sockaddr_in as the underlying type,
79 * sin_len is conveniently located at offset 0, sin_addr is at
80 * offset 4 and normally aligned.
81 * But for portability, let's avoid assumption and make the code explicit
83 #define KEY_LEN(v) *((uint8_t *)&(v))
85 * Do not require radix to compare more than actual IPv4/IPv6 address
87 #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
88 #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
90 #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
91 #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr))
93 struct radix_cidr_entry {
94 struct radix_node rn[2];
95 struct sockaddr_in addr;
104 struct in6_addr sin6_addr;
107 struct radix_cidr_xentry {
108 struct radix_node rn[2];
115 ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
118 struct radix_node_head *rnh;
120 if (keylen == sizeof(in_addr_t)) {
121 struct radix_cidr_entry *ent;
122 struct sockaddr_in sa;
123 KEY_LEN(sa) = KEY_LEN_INET;
124 sa.sin_addr.s_addr = *((in_addr_t *)key);
125 rnh = (struct radix_node_head *)ti->state;
126 ent = (struct radix_cidr_entry *)(rnh->rnh_matchaddr(&sa, rnh));
132 struct radix_cidr_xentry *xent;
134 KEY_LEN(sa6) = KEY_LEN_INET6;
135 memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
136 rnh = (struct radix_node_head *)ti->xstate;
137 xent = (struct radix_cidr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
151 ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
152 char *data, uint8_t tflags)
155 if (!rn_inithead(&ti->state, OFF_LEN_INET))
157 if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
158 rn_detachhead(&ti->state);
163 ti->lookup = ta_lookup_radix;
169 flush_table_entry(struct radix_node *rn, void *arg)
171 struct radix_node_head * const rnh = arg;
172 struct radix_cidr_entry *ent;
174 ent = (struct radix_cidr_entry *)
175 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
177 free(ent, M_IPFW_TBL);
182 ta_destroy_radix(void *ta_state, struct table_info *ti)
184 struct radix_node_head *rnh;
186 rnh = (struct radix_node_head *)(ti->state);
187 rnh->rnh_walktree(rnh, flush_table_entry, rnh);
188 rn_detachhead(&ti->state);
190 rnh = (struct radix_node_head *)(ti->xstate);
191 rnh->rnh_walktree(rnh, flush_table_entry, rnh);
192 rn_detachhead(&ti->xstate);
196 ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
197 ipfw_obj_tentry *tent)
199 struct radix_cidr_entry *n;
200 struct radix_cidr_xentry *xn;
202 n = (struct radix_cidr_entry *)e;
204 /* Guess IPv4/IPv6 radix by sockaddr family */
205 if (n->addr.sin_family == AF_INET) {
206 tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
207 tent->masklen = n->masklen;
208 tent->subtype = AF_INET;
209 tent->value = n->value;
212 xn = (struct radix_cidr_xentry *)e;
213 memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr));
214 tent->masklen = xn->masklen;
215 tent->subtype = AF_INET6;
216 tent->value = xn->value;
224 ta_find_radix_tentry(void *ta_state, struct table_info *ti,
225 ipfw_obj_tentry *tent)
227 struct radix_node_head *rnh;
231 if (tent->subtype == AF_INET) {
232 struct sockaddr_in sa;
233 KEY_LEN(sa) = KEY_LEN_INET;
234 sa.sin_addr.s_addr = tent->k.addr.s_addr;
235 rnh = (struct radix_node_head *)ti->state;
236 e = rnh->rnh_matchaddr(&sa, rnh);
239 KEY_LEN(sa6) = KEY_LEN_INET6;
240 memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
241 rnh = (struct radix_node_head *)ti->xstate;
242 e = rnh->rnh_matchaddr(&sa6, rnh);
246 ta_dump_radix_tentry(ta_state, ti, e, tent);
254 ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
257 struct radix_node_head *rnh;
259 rnh = (struct radix_node_head *)(ti->state);
260 rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
262 rnh = (struct radix_node_head *)(ti->xstate);
263 rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
270 struct sockaddr *addr_ptr;
271 struct sockaddr *mask_ptr;
274 struct sockaddr_in sa;
275 struct sockaddr_in ma;
286 ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
290 for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
292 *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
297 tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
298 struct sockaddr *ma, int *set_mask)
301 struct sockaddr_in *addr, *mask;
302 struct sockaddr_in6 *addr6, *mask6;
307 if (tei->subtype == AF_INET) {
309 addr = (struct sockaddr_in *)sa;
310 mask = (struct sockaddr_in *)ma;
311 /* Set 'total' structure length */
312 KEY_LEN(*addr) = KEY_LEN_INET;
313 KEY_LEN(*mask) = KEY_LEN_INET;
314 addr->sin_family = AF_INET;
315 mask->sin_addr.s_addr =
316 htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
317 a4 = *((in_addr_t *)tei->paddr);
318 addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr;
325 } else if (tei->subtype == AF_INET6) {
327 addr6 = (struct sockaddr_in6 *)sa;
328 mask6 = (struct sockaddr_in6 *)ma;
329 /* Set 'total' structure length */
330 KEY_LEN(*addr6) = KEY_LEN_INET6;
331 KEY_LEN(*mask6) = KEY_LEN_INET6;
332 addr6->sin6_family = AF_INET6;
333 ipv6_writemask(&mask6->sin6_addr, mlen);
334 memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr));
335 APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr);
345 ta_prepare_add_cidr(struct ip_fw_chain *ch, struct tentry_info *tei,
348 struct ta_buf_cidr *tb;
349 struct radix_cidr_entry *ent;
350 struct radix_cidr_xentry *xent;
351 struct sockaddr *addr, *mask;
354 tb = (struct ta_buf_cidr *)ta_buf;
359 if (tei->subtype == AF_INET) {
363 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
364 ent->value = tei->value;
367 addr = (struct sockaddr *)&ent->addr;
368 mask = (struct sockaddr *)&tb->addr.a4.ma;
372 } else if (tei->subtype == AF_INET6) {
376 xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
377 xent->value = tei->value;
378 xent->masklen = mlen;
380 addr = (struct sockaddr *)&xent->addr6;
381 mask = (struct sockaddr *)&tb->addr.a6.ma;
385 /* Unknown CIDR type */
389 tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
399 ta_add_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei,
400 void *ta_buf, uint32_t *pnum)
402 struct radix_node_head *rnh;
403 struct radix_node *rn;
404 struct ta_buf_cidr *tb;
405 uint32_t *old_value, value;
407 tb = (struct ta_buf_cidr *)ta_buf;
409 if (tei->subtype == AF_INET)
414 /* Search for an entry first */
415 rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh);
417 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
419 /* Record already exists. Update value if we're asked to */
420 if (tei->subtype == AF_INET)
421 old_value = &((struct radix_cidr_entry *)rn)->value;
423 old_value = &((struct radix_cidr_xentry *)rn)->value;
426 *old_value = tei->value;
429 /* Indicate that update has happened instead of addition */
430 tei->flags |= TEI_FLAGS_UPDATED;
436 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
439 rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr);
452 ta_prepare_del_cidr(struct ip_fw_chain *ch, struct tentry_info *tei,
455 struct ta_buf_cidr *tb;
456 struct sockaddr *addr, *mask;
459 tb = (struct ta_buf_cidr *)ta_buf;
464 if (tei->subtype == AF_INET) {
468 addr = (struct sockaddr *)&tb->addr.a4.sa;
469 mask = (struct sockaddr *)&tb->addr.a4.ma;
471 } else if (tei->subtype == AF_INET6) {
475 addr = (struct sockaddr *)&tb->addr.a6.sa;
476 mask = (struct sockaddr *)&tb->addr.a6.ma;
481 tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
490 ta_del_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei,
491 void *ta_buf, uint32_t *pnum)
493 struct radix_node_head *rnh;
494 struct radix_node *rn;
495 struct ta_buf_cidr *tb;
497 tb = (struct ta_buf_cidr *)ta_buf;
499 if (tei->subtype == AF_INET)
504 rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh);
506 /* Save entry value to @tei */
507 if (tei->subtype == AF_INET)
508 tei->value = ((struct radix_cidr_entry *)rn)->value;
510 tei->value = ((struct radix_cidr_xentry *)rn)->value;
523 ta_flush_cidr_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
526 struct ta_buf_cidr *tb;
528 tb = (struct ta_buf_cidr *)ta_buf;
530 if (tb->ent_ptr != NULL)
531 free(tb->ent_ptr, M_IPFW_TBL);
535 ta_has_space_radix(void *ta_state, struct table_info *ti, uint32_t count,
540 * radix does not not require additional memory allocations
541 * other than nodes itself. Adding new masks to the tree do
542 * but we don't have any API to call (and we don't known which
548 struct table_algo cidr_radix = {
549 .name = "cidr:radix",
550 .type = IPFW_TABLE_CIDR,
551 .flags = TA_FLAG_DEFAULT,
552 .ta_buf_size = sizeof(struct ta_buf_cidr),
553 .init = ta_init_radix,
554 .destroy = ta_destroy_radix,
555 .prepare_add = ta_prepare_add_cidr,
556 .prepare_del = ta_prepare_del_cidr,
559 .flush_entry = ta_flush_cidr_entry,
560 .foreach = ta_foreach_radix,
561 .dump_tentry = ta_dump_radix_tentry,
562 .find_tentry = ta_find_radix_tentry,
563 .has_space = ta_has_space_radix,
572 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
575 * inv.mask4: 32 - mask
577 * 1) _slow lookup: mask
578 * 2) _aligned: (128 - mask) / 8
589 SLIST_HEAD(chashbhead, chashentry);
592 struct chashbhead *head4;
593 struct chashbhead *head6;
603 SLIST_ENTRY(chashentry) next;
607 uint32_t a4; /* Host format */
608 struct in6_addr a6; /* Network format */
612 static __inline uint32_t
613 hash_ip(uint32_t addr, int hsize)
616 return (addr % (hsize - 1));
619 static __inline uint32_t
620 hash_ip6(struct in6_addr *addr6, int hsize)
624 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
625 addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
627 return (i % (hsize - 1));
631 static __inline uint16_t
632 hash_ip64(struct in6_addr *addr6, int hsize)
636 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
638 return (i % (hsize - 1));
642 static __inline uint32_t
643 hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
645 struct in6_addr mask6;
647 ipv6_writemask(&mask6, mask);
648 memcpy(addr6, key, sizeof(struct in6_addr));
649 APPLY_MASK(addr6, &mask6);
650 return (hash_ip6(addr6, hsize));
653 static __inline uint32_t
654 hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
658 paddr = (uint64_t *)addr6;
661 memcpy(addr6, key, mask);
662 return (hash_ip6(addr6, hsize));
666 ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
669 struct chashbhead *head;
670 struct chashentry *ent;
671 uint16_t hash, hsize;
674 if (keylen == sizeof(in_addr_t)) {
675 head = (struct chashbhead *)ti->state;
676 imask = ti->data >> 24;
677 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
679 a = ntohl(*((in_addr_t *)key));
681 hash = hash_ip(a, hsize);
682 SLIST_FOREACH(ent, &head[hash], next) {
683 if (ent->a.a4 == a) {
689 /* IPv6: worst scenario: non-round mask */
690 struct in6_addr addr6;
691 head = (struct chashbhead *)ti->xstate;
692 imask = (ti->data & 0xFF0000) >> 16;
693 hsize = 1 << (ti->data & 0xFF);
694 hash = hash_ip6_slow(&addr6, key, imask, hsize);
695 SLIST_FOREACH(ent, &head[hash], next) {
696 if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
707 ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
710 struct chashbhead *head;
711 struct chashentry *ent;
712 uint16_t hash, hsize;
715 if (keylen == sizeof(in_addr_t)) {
716 head = (struct chashbhead *)ti->state;
717 imask = ti->data >> 24;
718 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
720 a = ntohl(*((in_addr_t *)key));
722 hash = hash_ip(a, hsize);
723 SLIST_FOREACH(ent, &head[hash], next) {
724 if (ent->a.a4 == a) {
730 /* IPv6: aligned to 8bit mask */
731 struct in6_addr addr6;
732 uint64_t *paddr, *ptmp;
733 head = (struct chashbhead *)ti->xstate;
734 imask = (ti->data & 0xFF0000) >> 16;
735 hsize = 1 << (ti->data & 0xFF);
737 hash = hash_ip6_al(&addr6, key, imask, hsize);
738 paddr = (uint64_t *)&addr6;
739 SLIST_FOREACH(ent, &head[hash], next) {
740 ptmp = (uint64_t *)&ent->a.a6;
741 if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
752 ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
755 struct chashbhead *head;
756 struct chashentry *ent;
757 uint16_t hash, hsize;
760 if (keylen == sizeof(in_addr_t)) {
761 head = (struct chashbhead *)ti->state;
762 imask = ti->data >> 24;
763 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
765 a = ntohl(*((in_addr_t *)key));
767 hash = hash_ip(a, hsize);
768 SLIST_FOREACH(ent, &head[hash], next) {
769 if (ent->a.a4 == a) {
777 head = (struct chashbhead *)ti->xstate;
778 paddr = (uint64_t *)key;
779 hsize = 1 << (ti->data & 0xFF);
781 hash = hash_ip64((struct in6_addr *)key, hsize);
782 SLIST_FOREACH(ent, &head[hash], next) {
783 paddr = (uint64_t *)&ent->a.a6;
795 chash_parse_opts(struct chash_cfg *ccfg, char *data)
797 char *pdel, *pend, *s;
805 if ((pdel = strchr(data, ' ')) == NULL)
809 if (strncmp(pdel, "masks=", 6) != 0)
811 if ((s = strchr(pdel, ' ')) != NULL)
818 mask4 = strtol(pdel, &pend, 10);
824 mask6 = strtol(pdel, &pend, 10);
827 } else if (*pend != '\0')
830 if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
840 ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
843 struct chash_cfg *ccfg;
845 ccfg = (struct chash_cfg *)ta_state;
847 if (ccfg->mask4 != 32 || ccfg->mask6 != 128)
848 snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash",
849 ccfg->mask4, ccfg->mask6);
851 snprintf(buf, bufsize, "%s", "cidr:hash");
868 * We assume 'data' to be either NULL or the following format:
869 * 'cidr:hash [masks=/32[,/128]]'
872 ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
873 char *data, uint8_t tflags)
877 struct chash_cfg *ccfg;
879 ccfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
884 if ((error = chash_parse_opts(ccfg, data)) != 0) {
892 ccfg->head4 = malloc(sizeof(struct chashbhead) * ccfg->size4, M_IPFW,
894 ccfg->head6 = malloc(sizeof(struct chashbhead) * ccfg->size6, M_IPFW,
896 for (i = 0; i < ccfg->size4; i++)
897 SLIST_INIT(&ccfg->head4[i]);
898 for (i = 0; i < ccfg->size6; i++)
899 SLIST_INIT(&ccfg->head6[i]);
903 ti->state = ccfg->head4;
904 ti->xstate = ccfg->head6;
906 /* Store data depending on v6 mask length */
907 hsize = log2(ccfg->size4) << 8 | log2(ccfg->size6);
908 if (ccfg->mask6 == 64) {
909 ti->data = (32 - ccfg->mask4) << 24 | (128 - ccfg->mask6) << 16|
911 ti->lookup = ta_lookup_chash_64;
912 } else if ((ccfg->mask6 % 8) == 0) {
913 ti->data = (32 - ccfg->mask4) << 24 |
914 ccfg->mask6 << 13 | hsize;
915 ti->lookup = ta_lookup_chash_aligned;
918 ti->data = (32 - ccfg->mask4) << 24 |
919 ccfg->mask6 << 16 | hsize;
920 ti->lookup = ta_lookup_chash_slow;
927 ta_destroy_chash(void *ta_state, struct table_info *ti)
929 struct chash_cfg *ccfg;
930 struct chashentry *ent, *ent_next;
933 ccfg = (struct chash_cfg *)ta_state;
935 for (i = 0; i < ccfg->size4; i++)
936 SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
937 free(ent, M_IPFW_TBL);
939 for (i = 0; i < ccfg->size6; i++)
940 SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
941 free(ent, M_IPFW_TBL);
943 free(ccfg->head4, M_IPFW);
944 free(ccfg->head6, M_IPFW);
950 ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
951 ipfw_obj_tentry *tent)
953 struct chash_cfg *ccfg;
954 struct chashentry *ent;
956 ccfg = (struct chash_cfg *)ta_state;
957 ent = (struct chashentry *)e;
959 if (ent->type == AF_INET) {
960 tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - ccfg->mask4));
961 tent->masklen = ccfg->mask4;
962 tent->subtype = AF_INET;
963 tent->value = ent->value;
966 memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
967 tent->masklen = ccfg->mask6;
968 tent->subtype = AF_INET6;
969 tent->value = ent->value;
977 hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size)
982 hash = hash_ip(ent->a.a4, size);
985 hash = hash_ip64(&ent->a.a6, size);
987 hash = hash_ip6(&ent->a.a6, size);
994 tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
996 struct in6_addr mask6;
1000 mlen = tei->masklen;
1002 if (tei->subtype == AF_INET) {
1006 ent->type = AF_INET;
1008 /* Calculate masked address */
1009 ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1012 } else if (tei->subtype == AF_INET6) {
1016 ent->type = AF_INET6;
1018 ipv6_writemask(&mask6, mlen);
1019 memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1020 APPLY_MASK(&ent->a.a6, &mask6);
1023 /* Unknown CIDR type */
1026 ent->value = tei->value;
1033 ta_find_chash_tentry(void *ta_state, struct table_info *ti,
1034 ipfw_obj_tentry *tent)
1036 struct chash_cfg *ccfg;
1037 struct chashbhead *head;
1038 struct chashentry ent, *tmp;
1039 struct tentry_info tei;
1043 ccfg = (struct chash_cfg *)ta_state;
1045 memset(&ent, 0, sizeof(ent));
1046 memset(&tei, 0, sizeof(tei));
1048 if (tent->subtype == AF_INET) {
1049 tei.paddr = &tent->k.addr;
1050 tei.masklen = ccfg->mask4;
1051 tei.subtype = AF_INET;
1053 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1057 hash = hash_ent(&ent, AF_INET, ccfg->mask4, ccfg->size4);
1058 /* Check for existence */
1059 SLIST_FOREACH(tmp, &head[hash], next) {
1060 if (tmp->a.a4 != ent.a.a4)
1063 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1067 tei.paddr = &tent->k.addr6;
1068 tei.masklen = ccfg->mask6;
1069 tei.subtype = AF_INET6;
1071 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1075 hash = hash_ent(&ent, AF_INET6, ccfg->mask6, ccfg->size6);
1076 /* Check for existence */
1077 SLIST_FOREACH(tmp, &head[hash], next) {
1078 if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
1080 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1089 ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
1092 struct chash_cfg *ccfg;
1093 struct chashentry *ent, *ent_next;
1096 ccfg = (struct chash_cfg *)ta_state;
1098 for (i = 0; i < ccfg->size4; i++)
1099 SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
1102 for (i = 0; i < ccfg->size6; i++)
1103 SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
1111 struct chashentry ent;
1115 ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1118 struct ta_buf_chash *tb;
1119 struct chashentry *ent;
1122 tb = (struct ta_buf_chash *)ta_buf;
1124 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1126 error = tei_to_chash_ent(tei, ent);
1128 free(ent, M_IPFW_TBL);
1137 ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1138 void *ta_buf, uint32_t *pnum)
1140 struct chash_cfg *ccfg;
1141 struct chashbhead *head;
1142 struct chashentry *ent, *tmp;
1143 struct ta_buf_chash *tb;
1145 uint32_t hash, value;
1147 ccfg = (struct chash_cfg *)ta_state;
1148 tb = (struct ta_buf_chash *)ta_buf;
1149 ent = (struct chashentry *)tb->ent_ptr;
1153 if (tei->subtype == AF_INET) {
1154 if (tei->masklen != ccfg->mask4)
1157 hash = hash_ent(ent, AF_INET, ccfg->mask4, ccfg->size4);
1159 /* Check for existence */
1160 SLIST_FOREACH(tmp, &head[hash], next) {
1161 if (tmp->a.a4 == ent->a.a4) {
1167 if (tei->masklen != ccfg->mask6)
1170 hash = hash_ent(ent, AF_INET6, ccfg->mask6, ccfg->size6);
1171 /* Check for existence */
1172 SLIST_FOREACH(tmp, &head[hash], next) {
1173 if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) {
1181 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1183 /* Record already exists. Update value if we're asked to */
1185 tmp->value = tei->value;
1187 /* Indicate that update has happened instead of addition */
1188 tei->flags |= TEI_FLAGS_UPDATED;
1191 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
1193 SLIST_INSERT_HEAD(&head[hash], ent, next);
1197 /* Update counters */
1198 if (tei->subtype == AF_INET)
1208 ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1211 struct ta_buf_chash *tb;
1213 tb = (struct ta_buf_chash *)ta_buf;
1215 return (tei_to_chash_ent(tei, &tb->ent));
1219 ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1220 void *ta_buf, uint32_t *pnum)
1222 struct chash_cfg *ccfg;
1223 struct chashbhead *head;
1224 struct chashentry *ent, *tmp_next, *dent;
1225 struct ta_buf_chash *tb;
1228 ccfg = (struct chash_cfg *)ta_state;
1229 tb = (struct ta_buf_chash *)ta_buf;
1232 if (tei->subtype == AF_INET) {
1233 if (tei->masklen != ccfg->mask4)
1236 hash = hash_ent(dent, AF_INET, ccfg->mask4, ccfg->size4);
1238 SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
1239 if (ent->a.a4 != dent->a.a4)
1242 SLIST_REMOVE(&head[hash], ent, chashentry, next);
1245 tei->value = ent->value;
1250 if (tei->masklen != ccfg->mask6)
1253 hash = hash_ent(dent, AF_INET6, ccfg->mask6, ccfg->size6);
1254 SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
1255 if (memcmp(&ent->a.a6, &dent->a.a6, 16) != 0)
1258 SLIST_REMOVE(&head[hash], ent, chashentry, next);
1261 tei->value = ent->value;
1271 ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1274 struct ta_buf_chash *tb;
1276 tb = (struct ta_buf_chash *)ta_buf;
1278 if (tb->ent_ptr != NULL)
1279 free(tb->ent_ptr, M_IPFW_TBL);
1283 * Hash growing callbacks.
1294 ta_has_space_chash(void *ta_state, struct table_info *ti, uint32_t count,
1297 struct chash_cfg *cfg;
1301 * Since we don't know exact number of IPv4/IPv6 records in @count,
1302 * ignore non-zero @count value at all. Check current hash sizes
1303 * and return appropriate data.
1306 cfg = (struct chash_cfg *)ta_state;
1309 if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
1310 data |= (cfg->size4 * 2) << 16;
1311 if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
1312 data |= cfg->size6 * 2;
1323 * Allocate new, larger chash.
1326 ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags)
1328 struct mod_item *mi;
1329 struct chashbhead *head;
1332 mi = (struct mod_item *)ta_buf;
1334 memset(mi, 0, sizeof(struct mod_item));
1335 mi->size = (*pflags >> 16) & 0xFFFF;
1336 mi->size6 = *pflags & 0xFFFF;
1338 head = malloc(sizeof(struct chashbhead) * mi->size,
1339 M_IPFW, M_WAITOK | M_ZERO);
1340 for (i = 0; i < mi->size; i++)
1341 SLIST_INIT(&head[i]);
1342 mi->main_ptr = head;
1345 if (mi->size6 > 0) {
1346 head = malloc(sizeof(struct chashbhead) * mi->size6,
1347 M_IPFW, M_WAITOK | M_ZERO);
1348 for (i = 0; i < mi->size6; i++)
1349 SLIST_INIT(&head[i]);
1350 mi->main_ptr6 = head;
1357 * Copy data from old runtime array to new one.
1360 ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1364 /* In is not possible to do rehash if we're not holidng WLOCK. */
1369 * Switch old & new arrays.
1372 ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1375 struct mod_item *mi;
1376 struct chash_cfg *cfg;
1377 struct chashbhead *old_head, *new_head;
1378 struct chashentry *ent, *ent_next;
1381 size_t old_size, new_size;
1383 mi = (struct mod_item *)ta_buf;
1384 cfg = (struct chash_cfg *)ta_state;
1386 /* Check which hash we need to grow and do we still need that */
1387 if (mi->size > 0 && cfg->size4 < mi->size) {
1388 new_head = (struct chashbhead *)mi->main_ptr;
1389 new_size = mi->size;
1390 old_size = cfg->size4;
1391 old_head = ti->state;
1395 for (i = 0; i < old_size; i++) {
1396 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1397 nhash = hash_ent(ent, af, mlen, new_size);
1398 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1402 ti->state = new_head;
1403 cfg->head4 = new_head;
1404 cfg->size4 = mi->size;
1405 mi->main_ptr = old_head;
1408 if (mi->size6 > 0 && cfg->size6 < mi->size6) {
1409 new_head = (struct chashbhead *)mi->main_ptr6;
1410 new_size = mi->size6;
1411 old_size = cfg->size6;
1412 old_head = ti->xstate;
1416 for (i = 0; i < old_size; i++) {
1417 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1418 nhash = hash_ent(ent, af, mlen, new_size);
1419 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1423 ti->xstate = new_head;
1424 cfg->head6 = new_head;
1425 cfg->size6 = mi->size6;
1426 mi->main_ptr6 = old_head;
1429 /* Update lower 32 bits with new values */
1430 ti->data &= 0xFFFFFFFF00000000;
1431 ti->data |= log2(cfg->size4) << 8 | log2(cfg->size6);
1437 * Free unneded array.
1440 ta_flush_mod_chash(void *ta_buf)
1442 struct mod_item *mi;
1444 mi = (struct mod_item *)ta_buf;
1445 if (mi->main_ptr != NULL)
1446 free(mi->main_ptr, M_IPFW);
1447 if (mi->main_ptr6 != NULL)
1448 free(mi->main_ptr6, M_IPFW);
1451 struct table_algo cidr_hash = {
1452 .name = "cidr:hash",
1453 .type = IPFW_TABLE_CIDR,
1454 .ta_buf_size = sizeof(struct ta_buf_chash),
1455 .init = ta_init_chash,
1456 .destroy = ta_destroy_chash,
1457 .prepare_add = ta_prepare_add_chash,
1458 .prepare_del = ta_prepare_del_chash,
1459 .add = ta_add_chash,
1460 .del = ta_del_chash,
1461 .flush_entry = ta_flush_chash_entry,
1462 .foreach = ta_foreach_chash,
1463 .dump_tentry = ta_dump_chash_tentry,
1464 .find_tentry = ta_find_chash_tentry,
1465 .print_config = ta_print_chash_config,
1466 .has_space = ta_has_space_chash,
1467 .prepare_mod = ta_prepare_mod_chash,
1468 .fill_mod = ta_fill_mod_chash,
1469 .modify = ta_modify_chash,
1470 .flush_mod = ta_flush_mod_chash,
1480 * - sorted array of "struct ifidx" pointed by ti->state.
1481 * Array is allocated with rounding up to IFIDX_CHUNK. Only existing
1482 * interfaces are stored in array, however its allocated size is
1483 * sufficient to hold all table records if needed.
1484 * - current array size is stored in ti->data
1487 * - "struct iftable_cfg" is allocated to store table state (ta_state).
1488 * - All table records are stored inside namedobj instance.
1501 struct named_object no;
1503 struct iftable_cfg *icfg;
1508 struct iftable_cfg {
1509 struct namedobj_instance *ii;
1510 struct ip_fw_chain *ch;
1511 struct table_info *ti;
1513 size_t size; /* Number of items allocated in array */
1514 size_t count; /* Number of all items */
1515 size_t used; /* Number of items _active_ now */
1518 #define IFIDX_CHUNK 16
1520 int compare_ifidx(const void *k, const void *v);
1521 static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
1524 compare_ifidx(const void *k, const void *v)
1526 struct ifidx *ifidx;
1529 key = *((uint16_t *)k);
1530 ifidx = (struct ifidx *)v;
1532 if (key < ifidx->kidx)
1534 else if (key > ifidx->kidx)
1541 * Adds item @item with key @key into ascending-sorted array @base.
1542 * Assumes @base has enough additional storage.
1544 * Returns 1 on success, 0 on duplicate key.
1547 badd(const void *key, void *item, void *base, size_t nmemb,
1548 size_t size, int (*compar) (const void *, const void *))
1550 int min, max, mid, shift, res;
1554 memcpy(base, item, size);
1562 while (min <= max) {
1563 mid = (min + max) / 2;
1564 res = compar(key, (const void *)((caddr_t)base + mid * size));
1574 /* Item not found. */
1575 res = compar(key, (const void *)((caddr_t)base + mid * size));
1581 paddr = (caddr_t)base + shift * size;
1583 memmove(paddr + size, paddr, (nmemb - shift) * size);
1585 memcpy(paddr, item, size);
1591 * Deletes item with key @key from ascending-sorted array @base.
1593 * Returns 1 on success, 0 for non-existent key.
1596 bdel(const void *key, void *base, size_t nmemb, size_t size,
1597 int (*compar) (const void *, const void *))
1602 item = (caddr_t)bsearch(key, base, nmemb, size, compar);
1607 sz = (caddr_t)base + nmemb * size - item;
1610 memmove(item, item + size, sz);
1615 static struct ifidx *
1616 ifidx_find(struct table_info *ti, void *key)
1620 ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
1627 ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
1632 ifi = ifidx_find(ti, key);
1643 ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1644 char *data, uint8_t tflags)
1646 struct iftable_cfg *icfg;
1648 icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
1650 icfg->ii = ipfw_objhash_create(16);
1651 icfg->main_ptr = malloc(sizeof(struct ifidx) * IFIDX_CHUNK, M_IPFW,
1653 icfg->size = IFIDX_CHUNK;
1657 ti->state = icfg->main_ptr;
1658 ti->lookup = ta_lookup_ifidx;
1664 * Handle tableinfo @ti pointer change (on table array resize).
1667 ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
1669 struct iftable_cfg *icfg;
1671 icfg = (struct iftable_cfg *)ta_state;
1676 destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
1679 struct ifentry *ife;
1680 struct ip_fw_chain *ch;
1682 ch = (struct ip_fw_chain *)arg;
1683 ife = (struct ifentry *)no;
1685 ipfw_iface_del_notify(ch, &ife->ic);
1686 free(ife, M_IPFW_TBL);
1691 * Destroys table @ti
1694 ta_destroy_ifidx(void *ta_state, struct table_info *ti)
1696 struct iftable_cfg *icfg;
1697 struct ip_fw_chain *ch;
1699 icfg = (struct iftable_cfg *)ta_state;
1702 if (icfg->main_ptr != NULL)
1703 free(icfg->main_ptr, M_IPFW);
1705 ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
1707 ipfw_objhash_destroy(icfg->ii);
1714 struct ifentry *ife;
1719 * Prepare state to add to the table:
1720 * allocate ifentry and reference needed interface.
1723 ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1726 struct ta_buf_ifidx *tb;
1728 struct ifentry *ife;
1730 tb = (struct ta_buf_ifidx *)ta_buf;
1732 /* Check if string is terminated */
1733 ifname = (char *)tei->paddr;
1734 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1737 ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
1738 ife->value = tei->value;
1739 ife->ic.cb = if_notifier;
1740 ife->ic.cbdata = ife;
1742 if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0)
1745 /* Use ipfw_iface 'ifname' field as stable storage */
1746 ife->no.name = ife->ic.iface->ifname;
1754 ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1755 void *ta_buf, uint32_t *pnum)
1757 struct iftable_cfg *icfg;
1758 struct ifentry *ife, *tmp;
1759 struct ta_buf_ifidx *tb;
1760 struct ipfw_iface *iif;
1765 tb = (struct ta_buf_ifidx *)ta_buf;
1766 ifname = (char *)tei->paddr;
1767 icfg = (struct iftable_cfg *)ta_state;
1772 tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1775 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1778 /* Exchange values in @tmp and @tei */
1780 tmp->value = tei->value;
1783 iif = tmp->ic.iface;
1784 if (iif->resolved != 0) {
1785 /* We have to update runtime value, too */
1786 ifi = ifidx_find(ti, &iif->ifindex);
1787 ifi->value = ife->value;
1790 /* Indicate that update has happened instead of addition */
1791 tei->flags |= TEI_FLAGS_UPDATED;
1796 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
1799 /* Link to internal list */
1800 ipfw_objhash_add(icfg->ii, &ife->no);
1802 /* Link notifier (possible running its callback) */
1803 ipfw_iface_add_notify(icfg->ch, &ife->ic);
1813 * Prepare to delete key from table.
1814 * Do basic interface name checks.
1817 ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1820 struct ta_buf_ifidx *tb;
1823 tb = (struct ta_buf_ifidx *)ta_buf;
1825 /* Check if string is terminated */
1826 ifname = (char *)tei->paddr;
1827 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1834 * Remove key from both configuration list and
1835 * runtime array. Removed interface notification.
1838 ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1839 void *ta_buf, uint32_t *pnum)
1841 struct iftable_cfg *icfg;
1842 struct ifentry *ife;
1843 struct ta_buf_ifidx *tb;
1848 tb = (struct ta_buf_ifidx *)ta_buf;
1849 ifname = (char *)tei->paddr;
1850 icfg = (struct iftable_cfg *)ta_state;
1853 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1858 if (ife->linked != 0) {
1859 /* We have to remove item from runtime */
1860 ifindex = ife->ic.iface->ifindex;
1862 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
1863 sizeof(struct ifidx), compare_ifidx);
1865 KASSERT(res == 1, ("index %d does not exist", ifindex));
1867 ti->data = icfg->used;
1871 /* Unlink from local list */
1872 ipfw_objhash_del(icfg->ii, &ife->no);
1873 /* Unlink notifier */
1874 ipfw_iface_del_notify(icfg->ch, &ife->ic);
1877 tei->value = ife->value;
1886 * Flush deleted entry.
1887 * Drops interface reference and frees entry.
1890 ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1893 struct ta_buf_ifidx *tb;
1895 tb = (struct ta_buf_ifidx *)ta_buf;
1897 if (tb->ife != NULL) {
1899 ipfw_iface_unref(ch, &tb->ife->ic);
1900 free(tb->ife, M_IPFW_TBL);
1906 * Handle interface announce/withdrawal for particular table.
1907 * Every real runtime array modification happens here.
1910 if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
1912 struct ifentry *ife;
1914 struct iftable_cfg *icfg;
1915 struct table_info *ti;
1918 ife = (struct ifentry *)cbdata;
1922 KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
1924 if (ife->linked == 0 && ifindex != 0) {
1925 /* Interface announce */
1928 ifi.value = ife->value;
1929 res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
1930 sizeof(struct ifidx), compare_ifidx);
1931 KASSERT(res == 1, ("index %d already exists", ifindex));
1933 ti->data = icfg->used;
1935 } else if (ife->linked != 0 && ifindex == 0) {
1936 /* Interface withdrawal */
1937 ifindex = ife->ic.iface->ifindex;
1939 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
1940 sizeof(struct ifidx), compare_ifidx);
1942 KASSERT(res == 1, ("index %d does not exist", ifindex));
1944 ti->data = icfg->used;
1951 * Table growing callbacks.
1960 ta_has_space_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
1963 struct iftable_cfg *cfg;
1965 cfg = (struct iftable_cfg *)ta_state;
1967 if (cfg->count + count > cfg->size) {
1968 *pflags = roundup2(cfg->count + count, IFIDX_CHUNK);
1976 * Allocate ned, larger runtime ifidx array.
1979 ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
1981 struct mod_ifidx *mi;
1983 mi = (struct mod_ifidx *)ta_buf;
1985 memset(mi, 0, sizeof(struct mod_ifidx));
1987 mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
1994 * Copy data from old runtime array to new one.
1997 ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2000 struct mod_ifidx *mi;
2001 struct iftable_cfg *icfg;
2003 mi = (struct mod_ifidx *)ta_buf;
2004 icfg = (struct iftable_cfg *)ta_state;
2006 /* Check if we still need to grow array */
2007 if (icfg->size >= mi->size) {
2012 memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
2018 * Switch old & new arrays.
2021 ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2024 struct mod_ifidx *mi;
2025 struct iftable_cfg *icfg;
2028 mi = (struct mod_ifidx *)ta_buf;
2029 icfg = (struct iftable_cfg *)ta_state;
2031 old_ptr = icfg->main_ptr;
2032 icfg->main_ptr = mi->main_ptr;
2033 icfg->size = mi->size;
2034 ti->state = icfg->main_ptr;
2036 mi->main_ptr = old_ptr;
2042 * Free unneded array.
2045 ta_flush_mod_ifidx(void *ta_buf)
2047 struct mod_ifidx *mi;
2049 mi = (struct mod_ifidx *)ta_buf;
2050 if (mi->main_ptr != NULL)
2051 free(mi->main_ptr, M_IPFW);
2055 ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
2056 ipfw_obj_tentry *tent)
2058 struct ifentry *ife;
2060 ife = (struct ifentry *)e;
2062 tent->masklen = 8 * IF_NAMESIZE;
2063 memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
2064 tent->value = ife->value;
2070 ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
2071 ipfw_obj_tentry *tent)
2073 struct iftable_cfg *icfg;
2074 struct ifentry *ife;
2077 icfg = (struct iftable_cfg *)ta_state;
2078 ifname = tent->k.iface;
2080 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2083 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2086 ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
2099 foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
2102 struct ifentry *ife;
2103 struct wa_ifidx *wa;
2105 ife = (struct ifentry *)no;
2106 wa = (struct wa_ifidx *)arg;
2108 wa->f(ife, wa->arg);
2112 ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2115 struct iftable_cfg *icfg;
2118 icfg = (struct iftable_cfg *)ta_state;
2123 ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
2126 struct table_algo iface_idx = {
2127 .name = "iface:array",
2128 .type = IPFW_TABLE_INTERFACE,
2129 .flags = TA_FLAG_DEFAULT,
2130 .ta_buf_size = sizeof(struct ta_buf_ifidx),
2131 .init = ta_init_ifidx,
2132 .destroy = ta_destroy_ifidx,
2133 .prepare_add = ta_prepare_add_ifidx,
2134 .prepare_del = ta_prepare_del_ifidx,
2135 .add = ta_add_ifidx,
2136 .del = ta_del_ifidx,
2137 .flush_entry = ta_flush_ifidx_entry,
2138 .foreach = ta_foreach_ifidx,
2139 .dump_tentry = ta_dump_ifidx_tentry,
2140 .find_tentry = ta_find_ifidx_tentry,
2141 .has_space = ta_has_space_ifidx,
2142 .prepare_mod = ta_prepare_mod_ifidx,
2143 .fill_mod = ta_fill_mod_ifidx,
2144 .modify = ta_modify_ifidx,
2145 .flush_mod = ta_flush_mod_ifidx,
2146 .change_ti = ta_change_ti_ifidx,
2150 * Number array cmds.
2155 * - sorted array of "struct numarray" pointed by ti->state.
2156 * Array is allocated with rounding up to NUMARRAY_CHUNK.
2157 * - current array size is stored in ti->data
2166 struct numarray_cfg {
2168 size_t size; /* Number of items allocated in array */
2169 size_t used; /* Number of items _active_ now */
2172 #define NUMARRAY_CHUNK 16
2174 int compare_numarray(const void *k, const void *v);
2177 compare_numarray(const void *k, const void *v)
2179 struct numarray *na;
2182 key = *((uint32_t *)k);
2183 na = (struct numarray *)v;
2185 if (key < na->number)
2187 else if (key > na->number)
2193 static struct numarray *
2194 numarray_find(struct table_info *ti, void *key)
2196 struct numarray *ri;
2198 ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
2205 ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
2208 struct numarray *ri;
2210 ri = numarray_find(ti, key);
2221 ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2222 char *data, uint8_t tflags)
2224 struct numarray_cfg *cfg;
2226 cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
2228 cfg->size = NUMARRAY_CHUNK;
2229 cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
2233 ti->state = cfg->main_ptr;
2234 ti->lookup = ta_lookup_numarray;
2240 * Destroys table @ti
2243 ta_destroy_numarray(void *ta_state, struct table_info *ti)
2245 struct numarray_cfg *cfg;
2247 cfg = (struct numarray_cfg *)ta_state;
2249 if (cfg->main_ptr != NULL)
2250 free(cfg->main_ptr, M_IPFW);
2255 struct ta_buf_numarray
2261 * Prepare for addition/deletion to an array.
2264 ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
2267 struct ta_buf_numarray *tb;
2269 tb = (struct ta_buf_numarray *)ta_buf;
2271 tb->na.number = *((uint32_t *)tei->paddr);
2272 tb->na.value = tei->value;
2278 ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2279 void *ta_buf, uint32_t *pnum)
2281 struct numarray_cfg *cfg;
2282 struct ta_buf_numarray *tb;
2283 struct numarray *ri;
2287 tb = (struct ta_buf_numarray*)ta_buf;
2288 cfg = (struct numarray_cfg *)ta_state;
2290 ri = numarray_find(ti, &tb->na.number);
2293 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2296 /* Exchange values between ri and @tei */
2298 ri->value = tei->value;
2300 /* Indicate that update has happened instead of addition */
2301 tei->flags |= TEI_FLAGS_UPDATED;
2306 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2309 res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
2310 sizeof(struct numarray), compare_numarray);
2312 KASSERT(res == 1, ("number %d already exists", tb->na.number));
2314 ti->data = cfg->used;
2321 * Remove key from both configuration list and
2322 * runtime array. Removed interface notification.
2325 ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2326 void *ta_buf, uint32_t *pnum)
2328 struct numarray_cfg *cfg;
2329 struct ta_buf_numarray *tb;
2330 struct numarray *ri;
2333 tb = (struct ta_buf_numarray *)ta_buf;
2334 cfg = (struct numarray_cfg *)ta_state;
2336 ri = numarray_find(ti, &tb->na.number);
2340 tei->value = ri->value;
2342 res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
2343 sizeof(struct numarray), compare_numarray);
2345 KASSERT(res == 1, ("number %u does not exist", tb->na.number));
2347 ti->data = cfg->used;
2354 ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2363 * Table growing callbacks.
2367 ta_has_space_numarray(void *ta_state, struct table_info *ti, uint32_t count,
2370 struct numarray_cfg *cfg;
2372 cfg = (struct numarray_cfg *)ta_state;
2374 if (cfg->used + count > cfg->size) {
2375 *pflags = roundup2(cfg->used + count, NUMARRAY_CHUNK);
2383 * Allocate new, larger runtime array.
2386 ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
2388 struct mod_item *mi;
2390 mi = (struct mod_item *)ta_buf;
2392 memset(mi, 0, sizeof(struct mod_item));
2394 mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
2401 * Copy data from old runtime array to new one.
2404 ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2407 struct mod_item *mi;
2408 struct numarray_cfg *cfg;
2410 mi = (struct mod_item *)ta_buf;
2411 cfg = (struct numarray_cfg *)ta_state;
2413 /* Check if we still need to grow array */
2414 if (cfg->size >= mi->size) {
2419 memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
2425 * Switch old & new arrays.
2428 ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2431 struct mod_item *mi;
2432 struct numarray_cfg *cfg;
2435 mi = (struct mod_item *)ta_buf;
2436 cfg = (struct numarray_cfg *)ta_state;
2438 old_ptr = cfg->main_ptr;
2439 cfg->main_ptr = mi->main_ptr;
2440 cfg->size = mi->size;
2441 ti->state = cfg->main_ptr;
2443 mi->main_ptr = old_ptr;
2449 * Free unneded array.
2452 ta_flush_mod_numarray(void *ta_buf)
2454 struct mod_item *mi;
2456 mi = (struct mod_item *)ta_buf;
2457 if (mi->main_ptr != NULL)
2458 free(mi->main_ptr, M_IPFW);
2462 ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
2463 ipfw_obj_tentry *tent)
2465 struct numarray *na;
2467 na = (struct numarray *)e;
2469 tent->k.key = na->number;
2470 tent->value = na->value;
2476 ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2477 ipfw_obj_tentry *tent)
2479 struct numarray_cfg *cfg;
2480 struct numarray *ri;
2482 cfg = (struct numarray_cfg *)ta_state;
2484 ri = numarray_find(ti, &tent->k.key);
2487 ta_dump_numarray_tentry(ta_state, ti, ri, tent);
2495 ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2498 struct numarray_cfg *cfg;
2499 struct numarray *array;
2502 cfg = (struct numarray_cfg *)ta_state;
2503 array = cfg->main_ptr;
2505 for (i = 0; i < cfg->used; i++)
2509 struct table_algo number_array = {
2510 .name = "number:array",
2511 .type = IPFW_TABLE_NUMBER,
2512 .ta_buf_size = sizeof(struct ta_buf_numarray),
2513 .init = ta_init_numarray,
2514 .destroy = ta_destroy_numarray,
2515 .prepare_add = ta_prepare_add_numarray,
2516 .prepare_del = ta_prepare_add_numarray,
2517 .add = ta_add_numarray,
2518 .del = ta_del_numarray,
2519 .flush_entry = ta_flush_numarray_entry,
2520 .foreach = ta_foreach_numarray,
2521 .dump_tentry = ta_dump_numarray_tentry,
2522 .find_tentry = ta_find_numarray_tentry,
2523 .has_space = ta_has_space_numarray,
2524 .prepare_mod = ta_prepare_mod_numarray,
2525 .fill_mod = ta_fill_mod_numarray,
2526 .modify = ta_modify_numarray,
2527 .flush_mod = ta_flush_mod_numarray,
2535 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
2538 * inv.mask4: 32 - mask
2540 * 1) _slow lookup: mask
2541 * 2) _aligned: (128 - mask) / 8
2552 SLIST_HEAD(fhashbhead, fhashentry);
2555 SLIST_ENTRY(fhashentry) next;
2565 struct fhashentry4 {
2566 struct fhashentry e;
2571 struct fhashentry6 {
2572 struct fhashentry e;
2573 struct in6_addr dip6;
2574 struct in6_addr sip6;
2578 struct fhashbhead *head;
2581 struct fhashentry4 fe4;
2582 struct fhashentry6 fe6;
2586 cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
2590 ka = (uint64_t *)(&a->next + 1);
2591 kb = (uint64_t *)(&b->next + 1);
2593 if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0))
2599 static __inline uint32_t
2600 hash_flow4(struct fhashentry4 *f, int hsize)
2604 i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport);
2606 return (i % (hsize - 1));
2609 static __inline uint32_t
2610 hash_flow6(struct fhashentry6 *f, int hsize)
2614 i = (f->dip6.__u6_addr.__u6_addr32[2]) ^
2615 (f->dip6.__u6_addr.__u6_addr32[3]) ^
2616 (f->sip6.__u6_addr.__u6_addr32[2]) ^
2617 (f->sip6.__u6_addr.__u6_addr32[3]) ^
2618 (f->e.dport) ^ (f->e.sport);
2620 return (i % (hsize - 1));
2624 hash_flow_ent(struct fhashentry *ent, uint32_t size)
2628 if (ent->af == AF_INET) {
2629 hash = hash_flow4((struct fhashentry4 *)ent, size);
2631 hash = hash_flow6((struct fhashentry6 *)ent, size);
2638 ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
2641 struct fhashbhead *head;
2642 struct fhashentry *ent;
2643 struct fhashentry4 *m4;
2644 struct ipfw_flow_id *id;
2645 uint16_t hash, hsize;
2647 id = (struct ipfw_flow_id *)key;
2648 head = (struct fhashbhead *)ti->state;
2650 m4 = (struct fhashentry4 *)ti->xstate;
2652 if (id->addr_type == 4) {
2653 struct fhashentry4 f;
2655 /* Copy hash mask */
2658 f.dip.s_addr &= id->dst_ip;
2659 f.sip.s_addr &= id->src_ip;
2660 f.e.dport &= id->dst_port;
2661 f.e.sport &= id->src_port;
2662 f.e.proto &= id->proto;
2663 hash = hash_flow4(&f, hsize);
2664 SLIST_FOREACH(ent, &head[hash], next) {
2665 if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
2670 } else if (id->addr_type == 6) {
2671 struct fhashentry6 f;
2674 /* Copy hash mask */
2675 f = *((struct fhashentry6 *)(m4 + 1));
2677 /* Handle lack of __u6_addr.__u6_addr64 */
2678 fp = (uint64_t *)&f.dip6;
2679 idp = (uint64_t *)&id->dst_ip6;
2680 /* src IPv6 is stored after dst IPv6 */
2685 f.e.dport &= id->dst_port;
2686 f.e.sport &= id->src_port;
2687 f.e.proto &= id->proto;
2688 hash = hash_flow6(&f, hsize);
2689 SLIST_FOREACH(ent, &head[hash], next) {
2690 if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
2704 ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2705 char *data, uint8_t tflags)
2708 struct fhash_cfg *cfg;
2709 struct fhashentry4 *fe4;
2710 struct fhashentry6 *fe6;
2712 cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
2716 cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW,
2718 for (i = 0; i < cfg->size; i++)
2719 SLIST_INIT(&cfg->head[i]);
2721 /* Fill in fe masks based on @tflags */
2724 if (tflags & IPFW_TFFLAG_SRCIP) {
2725 memset(&fe4->sip, 0xFF, sizeof(fe4->sip));
2726 memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6));
2728 if (tflags & IPFW_TFFLAG_DSTIP) {
2729 memset(&fe4->dip, 0xFF, sizeof(fe4->dip));
2730 memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6));
2732 if (tflags & IPFW_TFFLAG_SRCPORT) {
2733 memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport));
2734 memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport));
2736 if (tflags & IPFW_TFFLAG_DSTPORT) {
2737 memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport));
2738 memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport));
2740 if (tflags & IPFW_TFFLAG_PROTO) {
2741 memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto));
2742 memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto));
2745 fe4->e.af = AF_INET;
2746 fe6->e.af = AF_INET6;
2749 ti->state = cfg->head;
2750 ti->xstate = &cfg->fe4;
2751 ti->data = cfg->size;
2752 ti->lookup = ta_lookup_fhash;
2758 ta_destroy_fhash(void *ta_state, struct table_info *ti)
2760 struct fhash_cfg *cfg;
2761 struct fhashentry *ent, *ent_next;
2764 cfg = (struct fhash_cfg *)ta_state;
2766 for (i = 0; i < cfg->size; i++)
2767 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
2768 free(ent, M_IPFW_TBL);
2770 free(cfg->head, M_IPFW);
2775 ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
2776 ipfw_obj_tentry *tent)
2778 struct fhash_cfg *cfg;
2779 struct fhashentry *ent;
2780 struct fhashentry4 *fe4;
2781 struct fhashentry6 *fe6;
2782 struct tflow_entry *tfe;
2784 cfg = (struct fhash_cfg *)ta_state;
2785 ent = (struct fhashentry *)e;
2786 tfe = &tent->k.flow;
2789 tfe->proto = ent->proto;
2790 tfe->dport = htons(ent->dport);
2791 tfe->sport = htons(ent->sport);
2792 tent->value = ent->value;
2793 tent->subtype = ent->af;
2795 if (ent->af == AF_INET) {
2796 fe4 = (struct fhashentry4 *)ent;
2797 tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr);
2798 tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr);
2802 fe6 = (struct fhashentry6 *)ent;
2803 tfe->a.a6.sip6 = fe6->sip6;
2804 tfe->a.a6.dip6 = fe6->dip6;
2805 tent->masklen = 128;
2813 tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
2815 struct fhashentry4 *fe4;
2816 struct fhashentry6 *fe6;
2817 struct tflow_entry *tfe;
2819 tfe = (struct tflow_entry *)tei->paddr;
2821 ent->af = tei->subtype;
2822 ent->proto = tfe->proto;
2823 ent->value = tei->value;
2824 ent->dport = ntohs(tfe->dport);
2825 ent->sport = ntohs(tfe->sport);
2827 if (tei->subtype == AF_INET) {
2829 fe4 = (struct fhashentry4 *)ent;
2830 fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr);
2831 fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr);
2834 } else if (tei->subtype == AF_INET6) {
2835 fe6 = (struct fhashentry6 *)ent;
2836 fe6->sip6 = tfe->a.a6.sip6;
2837 fe6->dip6 = tfe->a.a6.dip6;
2840 /* Unknown CIDR type */
2849 ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
2850 ipfw_obj_tentry *tent)
2852 struct fhash_cfg *cfg;
2853 struct fhashbhead *head;
2854 struct fhashentry *ent, *tmp;
2855 struct fhashentry6 fe6;
2856 struct tentry_info tei;
2861 cfg = (struct fhash_cfg *)ta_state;
2865 memset(&fe6, 0, sizeof(fe6));
2866 memset(&tei, 0, sizeof(tei));
2868 tei.paddr = &tent->k.flow;
2869 tei.subtype = tent->subtype;
2871 if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
2875 hash = hash_flow_ent(ent, cfg->size);
2877 if (tei.subtype == AF_INET)
2878 sz = 2 * sizeof(struct in_addr);
2880 sz = 2 * sizeof(struct in6_addr);
2882 /* Check for existence */
2883 SLIST_FOREACH(tmp, &head[hash], next) {
2884 if (cmp_flow_ent(tmp, ent, sz) != 0) {
2885 ta_dump_fhash_tentry(ta_state, ti, tmp, tent);
2894 ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2897 struct fhash_cfg *cfg;
2898 struct fhashentry *ent, *ent_next;
2901 cfg = (struct fhash_cfg *)ta_state;
2903 for (i = 0; i < cfg->size; i++)
2904 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
2912 struct fhashentry6 fe6;
2916 ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
2919 struct ta_buf_fhash *tb;
2920 struct fhashentry *ent;
2924 tb = (struct ta_buf_fhash *)ta_buf;
2926 if (tei->subtype == AF_INET)
2927 sz = sizeof(struct fhashentry4);
2928 else if (tei->subtype == AF_INET6)
2929 sz = sizeof(struct fhashentry6);
2933 ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO);
2935 error = tei_to_fhash_ent(tei, ent);
2937 free(ent, M_IPFW_TBL);
2946 ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2947 void *ta_buf, uint32_t *pnum)
2949 struct fhash_cfg *cfg;
2950 struct fhashbhead *head;
2951 struct fhashentry *ent, *tmp;
2952 struct ta_buf_fhash *tb;
2954 uint32_t hash, value;
2957 cfg = (struct fhash_cfg *)ta_state;
2958 tb = (struct ta_buf_fhash *)ta_buf;
2959 ent = (struct fhashentry *)tb->ent_ptr;
2963 hash = hash_flow_ent(ent, cfg->size);
2965 if (tei->subtype == AF_INET)
2966 sz = 2 * sizeof(struct in_addr);
2968 sz = 2 * sizeof(struct in6_addr);
2970 /* Check for existence */
2971 SLIST_FOREACH(tmp, &head[hash], next) {
2972 if (cmp_flow_ent(tmp, ent, sz) != 0) {
2979 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2981 /* Record already exists. Update value if we're asked to */
2982 /* Exchange values between tmp and @tei */
2984 tmp->value = tei->value;
2986 /* Indicate that update has happened instead of addition */
2987 tei->flags |= TEI_FLAGS_UPDATED;
2990 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2993 SLIST_INSERT_HEAD(&head[hash], ent, next);
2997 /* Update counters and check if we need to grow hash */
3005 ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3008 struct ta_buf_fhash *tb;
3010 tb = (struct ta_buf_fhash *)ta_buf;
3012 return (tei_to_fhash_ent(tei, &tb->fe6.e));
3016 ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3017 void *ta_buf, uint32_t *pnum)
3019 struct fhash_cfg *cfg;
3020 struct fhashbhead *head;
3021 struct fhashentry *ent, *tmp;
3022 struct ta_buf_fhash *tb;
3026 cfg = (struct fhash_cfg *)ta_state;
3027 tb = (struct ta_buf_fhash *)ta_buf;
3031 hash = hash_flow_ent(ent, cfg->size);
3033 if (tei->subtype == AF_INET)
3034 sz = 2 * sizeof(struct in_addr);
3036 sz = 2 * sizeof(struct in6_addr);
3038 /* Check for existence */
3039 SLIST_FOREACH(tmp, &head[hash], next) {
3040 if (cmp_flow_ent(tmp, ent, sz) == 0)
3043 SLIST_REMOVE(&head[hash], tmp, fhashentry, next);
3044 tei->value = tmp->value;
3055 ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3058 struct ta_buf_fhash *tb;
3060 tb = (struct ta_buf_fhash *)ta_buf;
3062 if (tb->ent_ptr != NULL)
3063 free(tb->ent_ptr, M_IPFW_TBL);
3067 * Hash growing callbacks.
3071 ta_has_space_fhash(void *ta_state, struct table_info *ti, uint32_t count,
3074 struct fhash_cfg *cfg;
3076 cfg = (struct fhash_cfg *)ta_state;
3078 if (cfg->items > cfg->size && cfg->size < 65536) {
3079 *pflags = cfg->size * 2;
3087 * Allocate new, larger fhash.
3090 ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags)
3092 struct mod_item *mi;
3093 struct fhashbhead *head;
3096 mi = (struct mod_item *)ta_buf;
3098 memset(mi, 0, sizeof(struct mod_item));
3100 head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW,
3102 for (i = 0; i < mi->size; i++)
3103 SLIST_INIT(&head[i]);
3105 mi->main_ptr = head;
3111 * Copy data from old runtime array to new one.
3114 ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3118 /* In is not possible to do rehash if we're not holidng WLOCK. */
3124 * Switch old & new arrays.
3127 ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3130 struct mod_item *mi;
3131 struct fhash_cfg *cfg;
3132 struct fhashbhead *old_head, *new_head;
3133 struct fhashentry *ent, *ent_next;
3138 mi = (struct mod_item *)ta_buf;
3139 cfg = (struct fhash_cfg *)ta_state;
3141 /* Check which hash we need to grow and do we still need that */
3142 old_size = cfg->size;
3143 old_head = ti->state;
3145 if (old_size >= mi->size)
3148 new_head = (struct fhashbhead *)mi->main_ptr;
3149 for (i = 0; i < old_size; i++) {
3150 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
3151 nhash = hash_flow_ent(ent, mi->size);
3152 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
3156 ti->state = new_head;
3157 ti->data = mi->size;
3158 cfg->head = new_head;
3159 cfg->size = mi->size;
3161 mi->main_ptr = old_head;
3167 * Free unneded array.
3170 ta_flush_mod_fhash(void *ta_buf)
3172 struct mod_item *mi;
3174 mi = (struct mod_item *)ta_buf;
3175 if (mi->main_ptr != NULL)
3176 free(mi->main_ptr, M_IPFW);
3179 struct table_algo flow_hash = {
3180 .name = "flow:hash",
3181 .type = IPFW_TABLE_FLOW,
3182 .flags = TA_FLAG_DEFAULT,
3183 .ta_buf_size = sizeof(struct ta_buf_fhash),
3184 .init = ta_init_fhash,
3185 .destroy = ta_destroy_fhash,
3186 .prepare_add = ta_prepare_add_fhash,
3187 .prepare_del = ta_prepare_del_fhash,
3188 .add = ta_add_fhash,
3189 .del = ta_del_fhash,
3190 .flush_entry = ta_flush_fhash_entry,
3191 .foreach = ta_foreach_fhash,
3192 .dump_tentry = ta_dump_fhash_tentry,
3193 .find_tentry = ta_find_fhash_tentry,
3194 .has_space = ta_has_space_fhash,
3195 .prepare_mod = ta_prepare_mod_fhash,
3196 .fill_mod = ta_fill_mod_fhash,
3197 .modify = ta_modify_fhash,
3198 .flush_mod = ta_flush_mod_fhash,
3201 ipfw_table_algo_init(struct ip_fw_chain *ch)
3206 * Register all algorithms presented here.
3208 sz = sizeof(struct table_algo);
3209 ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx);
3210 ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx);
3211 ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
3212 ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
3213 ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
3217 ipfw_table_algo_destroy(struct ip_fw_chain *ch)
3220 ipfw_del_table_algo(ch, cidr_radix.idx);
3221 ipfw_del_table_algo(ch, cidr_hash.idx);
3222 ipfw_del_table_algo(ch, iface_idx.idx);
3223 ipfw_del_table_algo(ch, number_array.idx);
3224 ipfw_del_table_algo(ch, flow_hash.idx);