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>
52 #include <netinet/in.h>
53 #include <netinet/ip_var.h> /* struct ipfw_rule_ref */
54 #include <netinet/ip_fw.h>
56 #include <netpfil/ipfw/ip_fw_private.h>
57 #include <netpfil/ipfw/ip_fw_table.h>
59 static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
62 * Utility structures/functions common to more than one algo
72 static int badd(const void *key, void *item, void *base, size_t nmemb,
73 size_t size, int (*compar) (const void *, const void *));
74 static int bdel(const void *key, void *base, size_t nmemb, size_t size,
75 int (*compar) (const void *, const void *));
79 * CIDR implementation using radix
84 * The radix code expects addr and mask to be array of bytes,
85 * with the first byte being the length of the array. rn_inithead
86 * is called with the offset in bits of the lookup key within the
87 * array. If we use a sockaddr_in as the underlying type,
88 * sin_len is conveniently located at offset 0, sin_addr is at
89 * offset 4 and normally aligned.
90 * But for portability, let's avoid assumption and make the code explicit
92 #define KEY_LEN(v) *((uint8_t *)&(v))
94 * Do not require radix to compare more than actual IPv4/IPv6 address
96 #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
97 #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
99 #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
100 #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr))
102 struct radix_cidr_entry {
103 struct radix_node rn[2];
104 struct sockaddr_in addr;
113 struct in6_addr sin6_addr;
116 struct radix_cidr_xentry {
117 struct radix_node rn[2];
124 struct radix_node_head *head4;
125 struct radix_node_head *head6;
133 struct sockaddr *addr_ptr;
134 struct sockaddr *mask_ptr;
137 struct sockaddr_in sa;
138 struct sockaddr_in ma;
148 ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
151 struct radix_node_head *rnh;
153 if (keylen == sizeof(in_addr_t)) {
154 struct radix_cidr_entry *ent;
155 struct sockaddr_in sa;
156 KEY_LEN(sa) = KEY_LEN_INET;
157 sa.sin_addr.s_addr = *((in_addr_t *)key);
158 rnh = (struct radix_node_head *)ti->state;
159 ent = (struct radix_cidr_entry *)(rnh->rnh_matchaddr(&sa, rnh));
165 struct radix_cidr_xentry *xent;
167 KEY_LEN(sa6) = KEY_LEN_INET6;
168 memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
169 rnh = (struct radix_node_head *)ti->xstate;
170 xent = (struct radix_cidr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
184 ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
185 char *data, uint8_t tflags)
187 struct radix_cfg *cfg;
189 if (!rn_inithead(&ti->state, OFF_LEN_INET))
191 if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
192 rn_detachhead(&ti->state);
196 cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
199 ti->lookup = ta_lookup_radix;
205 flush_radix_entry(struct radix_node *rn, void *arg)
207 struct radix_node_head * const rnh = arg;
208 struct radix_cidr_entry *ent;
210 ent = (struct radix_cidr_entry *)
211 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
213 free(ent, M_IPFW_TBL);
218 ta_destroy_radix(void *ta_state, struct table_info *ti)
220 struct radix_cfg *cfg;
221 struct radix_node_head *rnh;
223 cfg = (struct radix_cfg *)ta_state;
225 rnh = (struct radix_node_head *)(ti->state);
226 rnh->rnh_walktree(rnh, flush_radix_entry, rnh);
227 rn_detachhead(&ti->state);
229 rnh = (struct radix_node_head *)(ti->xstate);
230 rnh->rnh_walktree(rnh, flush_radix_entry, rnh);
231 rn_detachhead(&ti->xstate);
237 * Provide algo-specific table info
240 ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
242 struct radix_cfg *cfg;
244 cfg = (struct radix_cfg *)ta_state;
246 tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
247 tinfo->taclass4 = IPFW_TACLASS_RADIX;
248 tinfo->count4 = cfg->count4;
249 tinfo->itemsize4 = sizeof(struct radix_cidr_entry);
250 tinfo->taclass6 = IPFW_TACLASS_RADIX;
251 tinfo->count6 = cfg->count6;
252 tinfo->itemsize6 = sizeof(struct radix_cidr_xentry);
256 ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
257 ipfw_obj_tentry *tent)
259 struct radix_cidr_entry *n;
260 struct radix_cidr_xentry *xn;
262 n = (struct radix_cidr_entry *)e;
264 /* Guess IPv4/IPv6 radix by sockaddr family */
265 if (n->addr.sin_family == AF_INET) {
266 tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
267 tent->masklen = n->masklen;
268 tent->subtype = AF_INET;
269 tent->value = n->value;
272 xn = (struct radix_cidr_xentry *)e;
273 memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr));
274 tent->masklen = xn->masklen;
275 tent->subtype = AF_INET6;
276 tent->value = xn->value;
284 ta_find_radix_tentry(void *ta_state, struct table_info *ti,
285 ipfw_obj_tentry *tent)
287 struct radix_node_head *rnh;
291 if (tent->subtype == AF_INET) {
292 struct sockaddr_in sa;
293 KEY_LEN(sa) = KEY_LEN_INET;
294 sa.sin_addr.s_addr = tent->k.addr.s_addr;
295 rnh = (struct radix_node_head *)ti->state;
296 e = rnh->rnh_matchaddr(&sa, rnh);
299 KEY_LEN(sa6) = KEY_LEN_INET6;
300 memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
301 rnh = (struct radix_node_head *)ti->xstate;
302 e = rnh->rnh_matchaddr(&sa6, rnh);
306 ta_dump_radix_tentry(ta_state, ti, e, tent);
314 ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
317 struct radix_node_head *rnh;
319 rnh = (struct radix_node_head *)(ti->state);
320 rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
322 rnh = (struct radix_node_head *)(ti->xstate);
323 rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
329 ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
333 for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
335 *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
340 tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
341 struct sockaddr *ma, int *set_mask)
344 struct sockaddr_in *addr, *mask;
345 struct sa_in6 *addr6, *mask6;
350 if (tei->subtype == AF_INET) {
352 addr = (struct sockaddr_in *)sa;
353 mask = (struct sockaddr_in *)ma;
354 /* Set 'total' structure length */
355 KEY_LEN(*addr) = KEY_LEN_INET;
356 KEY_LEN(*mask) = KEY_LEN_INET;
357 addr->sin_family = AF_INET;
358 mask->sin_addr.s_addr =
359 htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
360 a4 = *((in_addr_t *)tei->paddr);
361 addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr;
368 } else if (tei->subtype == AF_INET6) {
370 addr6 = (struct sa_in6 *)sa;
371 mask6 = (struct sa_in6 *)ma;
372 /* Set 'total' structure length */
373 KEY_LEN(*addr6) = KEY_LEN_INET6;
374 KEY_LEN(*mask6) = KEY_LEN_INET6;
375 addr6->sin6_family = AF_INET6;
376 ipv6_writemask(&mask6->sin6_addr, mlen);
377 memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr));
378 APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr);
388 ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
391 struct ta_buf_cidr *tb;
392 struct radix_cidr_entry *ent;
393 struct radix_cidr_xentry *xent;
394 struct sockaddr *addr, *mask;
397 tb = (struct ta_buf_cidr *)ta_buf;
402 if (tei->subtype == AF_INET) {
406 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
407 ent->value = tei->value;
410 addr = (struct sockaddr *)&ent->addr;
411 mask = (struct sockaddr *)&tb->addr.a4.ma;
415 } else if (tei->subtype == AF_INET6) {
419 xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
420 xent->value = tei->value;
421 xent->masklen = mlen;
423 addr = (struct sockaddr *)&xent->addr6;
424 mask = (struct sockaddr *)&tb->addr.a6.ma;
428 /* Unknown CIDR type */
432 tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
442 ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
443 void *ta_buf, uint32_t *pnum)
445 struct radix_cfg *cfg;
446 struct radix_node_head *rnh;
447 struct radix_node *rn;
448 struct ta_buf_cidr *tb;
449 uint32_t *old_value, value;
451 cfg = (struct radix_cfg *)ta_state;
452 tb = (struct ta_buf_cidr *)ta_buf;
454 if (tei->subtype == AF_INET)
459 /* Search for an entry first */
460 rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh);
462 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
464 /* Record already exists. Update value if we're asked to */
465 if (tei->subtype == AF_INET)
466 old_value = &((struct radix_cidr_entry *)rn)->value;
468 old_value = &((struct radix_cidr_xentry *)rn)->value;
471 *old_value = tei->value;
474 /* Indicate that update has happened instead of addition */
475 tei->flags |= TEI_FLAGS_UPDATED;
481 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
484 rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr);
490 if (tei->subtype == AF_INET)
501 ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
504 struct ta_buf_cidr *tb;
505 struct sockaddr *addr, *mask;
508 tb = (struct ta_buf_cidr *)ta_buf;
513 if (tei->subtype == AF_INET) {
517 addr = (struct sockaddr *)&tb->addr.a4.sa;
518 mask = (struct sockaddr *)&tb->addr.a4.ma;
520 } else if (tei->subtype == AF_INET6) {
524 addr = (struct sockaddr *)&tb->addr.a6.sa;
525 mask = (struct sockaddr *)&tb->addr.a6.ma;
530 tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
539 ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
540 void *ta_buf, uint32_t *pnum)
542 struct radix_cfg *cfg;
543 struct radix_node_head *rnh;
544 struct radix_node *rn;
545 struct ta_buf_cidr *tb;
547 cfg = (struct radix_cfg *)ta_state;
548 tb = (struct ta_buf_cidr *)ta_buf;
550 if (tei->subtype == AF_INET)
555 rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh);
557 /* Save entry value to @tei */
558 if (tei->subtype == AF_INET)
559 tei->value = ((struct radix_cidr_entry *)rn)->value;
561 tei->value = ((struct radix_cidr_xentry *)rn)->value;
568 if (tei->subtype == AF_INET)
578 ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
581 struct ta_buf_cidr *tb;
583 tb = (struct ta_buf_cidr *)ta_buf;
585 if (tb->ent_ptr != NULL)
586 free(tb->ent_ptr, M_IPFW_TBL);
590 ta_has_space_radix(void *ta_state, struct table_info *ti, uint32_t count,
595 * radix does not require additional memory allocations
596 * other than nodes itself. Adding new masks to the tree do
597 * but we don't have any API to call (and we don't known which
603 struct table_algo cidr_radix = {
604 .name = "cidr:radix",
605 .type = IPFW_TABLE_CIDR,
606 .flags = TA_FLAG_DEFAULT,
607 .ta_buf_size = sizeof(struct ta_buf_cidr),
608 .init = ta_init_radix,
609 .destroy = ta_destroy_radix,
610 .prepare_add = ta_prepare_add_radix,
611 .prepare_del = ta_prepare_del_radix,
614 .flush_entry = ta_flush_radix_entry,
615 .foreach = ta_foreach_radix,
616 .dump_tentry = ta_dump_radix_tentry,
617 .find_tentry = ta_find_radix_tentry,
618 .dump_tinfo = ta_dump_radix_tinfo,
619 .has_space = ta_has_space_radix,
628 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
631 * inv.mask4: 32 - mask
633 * 1) _slow lookup: mask
634 * 2) _aligned: (128 - mask) / 8
645 SLIST_HEAD(chashbhead, chashentry);
648 struct chashbhead *head4;
649 struct chashbhead *head6;
659 SLIST_ENTRY(chashentry) next;
663 uint32_t a4; /* Host format */
664 struct in6_addr a6; /* Network format */
671 struct chashentry ent;
675 static __inline uint32_t
676 hash_ip(uint32_t addr, int hsize)
679 return (addr % (hsize - 1));
682 static __inline uint32_t
683 hash_ip6(struct in6_addr *addr6, int hsize)
687 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
688 addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
690 return (i % (hsize - 1));
694 static __inline uint16_t
695 hash_ip64(struct in6_addr *addr6, int hsize)
699 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
701 return (i % (hsize - 1));
705 static __inline uint32_t
706 hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
708 struct in6_addr mask6;
710 ipv6_writemask(&mask6, mask);
711 memcpy(addr6, key, sizeof(struct in6_addr));
712 APPLY_MASK(addr6, &mask6);
713 return (hash_ip6(addr6, hsize));
716 static __inline uint32_t
717 hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
721 paddr = (uint64_t *)addr6;
724 memcpy(addr6, key, mask);
725 return (hash_ip6(addr6, hsize));
729 ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
732 struct chashbhead *head;
733 struct chashentry *ent;
734 uint16_t hash, hsize;
737 if (keylen == sizeof(in_addr_t)) {
738 head = (struct chashbhead *)ti->state;
739 imask = ti->data >> 24;
740 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
742 a = ntohl(*((in_addr_t *)key));
744 hash = hash_ip(a, hsize);
745 SLIST_FOREACH(ent, &head[hash], next) {
746 if (ent->a.a4 == a) {
752 /* IPv6: worst scenario: non-round mask */
753 struct in6_addr addr6;
754 head = (struct chashbhead *)ti->xstate;
755 imask = (ti->data & 0xFF0000) >> 16;
756 hsize = 1 << (ti->data & 0xFF);
757 hash = hash_ip6_slow(&addr6, key, imask, hsize);
758 SLIST_FOREACH(ent, &head[hash], next) {
759 if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
770 ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
773 struct chashbhead *head;
774 struct chashentry *ent;
775 uint16_t hash, hsize;
778 if (keylen == sizeof(in_addr_t)) {
779 head = (struct chashbhead *)ti->state;
780 imask = ti->data >> 24;
781 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
783 a = ntohl(*((in_addr_t *)key));
785 hash = hash_ip(a, hsize);
786 SLIST_FOREACH(ent, &head[hash], next) {
787 if (ent->a.a4 == a) {
793 /* IPv6: aligned to 8bit mask */
794 struct in6_addr addr6;
795 uint64_t *paddr, *ptmp;
796 head = (struct chashbhead *)ti->xstate;
797 imask = (ti->data & 0xFF0000) >> 16;
798 hsize = 1 << (ti->data & 0xFF);
800 hash = hash_ip6_al(&addr6, key, imask, hsize);
801 paddr = (uint64_t *)&addr6;
802 SLIST_FOREACH(ent, &head[hash], next) {
803 ptmp = (uint64_t *)&ent->a.a6;
804 if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
815 ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
818 struct chashbhead *head;
819 struct chashentry *ent;
820 uint16_t hash, hsize;
823 if (keylen == sizeof(in_addr_t)) {
824 head = (struct chashbhead *)ti->state;
825 imask = ti->data >> 24;
826 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
828 a = ntohl(*((in_addr_t *)key));
830 hash = hash_ip(a, hsize);
831 SLIST_FOREACH(ent, &head[hash], next) {
832 if (ent->a.a4 == a) {
840 head = (struct chashbhead *)ti->xstate;
841 paddr = (uint64_t *)key;
842 hsize = 1 << (ti->data & 0xFF);
844 hash = hash_ip64((struct in6_addr *)key, hsize);
845 SLIST_FOREACH(ent, &head[hash], next) {
846 paddr = (uint64_t *)&ent->a.a6;
858 chash_parse_opts(struct chash_cfg *cfg, char *data)
860 char *pdel, *pend, *s;
868 if ((pdel = strchr(data, ' ')) == NULL)
872 if (strncmp(pdel, "masks=", 6) != 0)
874 if ((s = strchr(pdel, ' ')) != NULL)
881 mask4 = strtol(pdel, &pend, 10);
887 mask6 = strtol(pdel, &pend, 10);
890 } else if (*pend != '\0')
893 if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
903 ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
906 struct chash_cfg *cfg;
908 cfg = (struct chash_cfg *)ta_state;
910 if (cfg->mask4 != 32 || cfg->mask6 != 128)
911 snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash",
912 cfg->mask4, cfg->mask6);
914 snprintf(buf, bufsize, "%s", "cidr:hash");
931 * We assume 'data' to be either NULL or the following format:
932 * 'cidr:hash [masks=/32[,/128]]'
935 ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
936 char *data, uint8_t tflags)
940 struct chash_cfg *cfg;
942 cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
947 if ((error = chash_parse_opts(cfg, data)) != 0) {
955 cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW,
957 cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW,
959 for (i = 0; i < cfg->size4; i++)
960 SLIST_INIT(&cfg->head4[i]);
961 for (i = 0; i < cfg->size6; i++)
962 SLIST_INIT(&cfg->head6[i]);
966 ti->state = cfg->head4;
967 ti->xstate = cfg->head6;
969 /* Store data depending on v6 mask length */
970 hsize = log2(cfg->size4) << 8 | log2(cfg->size6);
971 if (cfg->mask6 == 64) {
972 ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16|
974 ti->lookup = ta_lookup_chash_64;
975 } else if ((cfg->mask6 % 8) == 0) {
976 ti->data = (32 - cfg->mask4) << 24 |
977 cfg->mask6 << 13 | hsize;
978 ti->lookup = ta_lookup_chash_aligned;
981 ti->data = (32 - cfg->mask4) << 24 |
982 cfg->mask6 << 16 | hsize;
983 ti->lookup = ta_lookup_chash_slow;
990 ta_destroy_chash(void *ta_state, struct table_info *ti)
992 struct chash_cfg *cfg;
993 struct chashentry *ent, *ent_next;
996 cfg = (struct chash_cfg *)ta_state;
998 for (i = 0; i < cfg->size4; i++)
999 SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1000 free(ent, M_IPFW_TBL);
1002 for (i = 0; i < cfg->size6; i++)
1003 SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1004 free(ent, M_IPFW_TBL);
1006 free(cfg->head4, M_IPFW);
1007 free(cfg->head6, M_IPFW);
1013 ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
1015 struct chash_cfg *cfg;
1017 cfg = (struct chash_cfg *)ta_state;
1019 tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
1020 tinfo->taclass4 = IPFW_TACLASS_HASH;
1021 tinfo->size4 = cfg->size4;
1022 tinfo->count4 = cfg->items4;
1023 tinfo->itemsize4 = sizeof(struct chashentry);
1024 tinfo->taclass6 = IPFW_TACLASS_HASH;
1025 tinfo->size6 = cfg->size6;
1026 tinfo->count6 = cfg->items6;
1027 tinfo->itemsize6 = sizeof(struct chashentry);
1031 ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
1032 ipfw_obj_tentry *tent)
1034 struct chash_cfg *cfg;
1035 struct chashentry *ent;
1037 cfg = (struct chash_cfg *)ta_state;
1038 ent = (struct chashentry *)e;
1040 if (ent->type == AF_INET) {
1041 tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4));
1042 tent->masklen = cfg->mask4;
1043 tent->subtype = AF_INET;
1044 tent->value = ent->value;
1047 memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
1048 tent->masklen = cfg->mask6;
1049 tent->subtype = AF_INET6;
1050 tent->value = ent->value;
1058 hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size)
1062 if (af == AF_INET) {
1063 hash = hash_ip(ent->a.a4, size);
1066 hash = hash_ip64(&ent->a.a6, size);
1068 hash = hash_ip6(&ent->a.a6, size);
1075 tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
1077 struct in6_addr mask6;
1081 mlen = tei->masklen;
1083 if (tei->subtype == AF_INET) {
1087 ent->type = AF_INET;
1089 /* Calculate masked address */
1090 ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1093 } else if (tei->subtype == AF_INET6) {
1097 ent->type = AF_INET6;
1099 ipv6_writemask(&mask6, mlen);
1100 memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1101 APPLY_MASK(&ent->a.a6, &mask6);
1104 /* Unknown CIDR type */
1107 ent->value = tei->value;
1113 ta_find_chash_tentry(void *ta_state, struct table_info *ti,
1114 ipfw_obj_tentry *tent)
1116 struct chash_cfg *cfg;
1117 struct chashbhead *head;
1118 struct chashentry ent, *tmp;
1119 struct tentry_info tei;
1123 cfg = (struct chash_cfg *)ta_state;
1125 memset(&ent, 0, sizeof(ent));
1126 memset(&tei, 0, sizeof(tei));
1128 if (tent->subtype == AF_INET) {
1129 tei.paddr = &tent->k.addr;
1130 tei.masklen = cfg->mask4;
1131 tei.subtype = AF_INET;
1133 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1137 hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4);
1138 /* Check for existence */
1139 SLIST_FOREACH(tmp, &head[hash], next) {
1140 if (tmp->a.a4 != ent.a.a4)
1143 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1147 tei.paddr = &tent->k.addr6;
1148 tei.masklen = cfg->mask6;
1149 tei.subtype = AF_INET6;
1151 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1155 hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6);
1156 /* Check for existence */
1157 SLIST_FOREACH(tmp, &head[hash], next) {
1158 if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
1160 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1169 ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
1172 struct chash_cfg *cfg;
1173 struct chashentry *ent, *ent_next;
1176 cfg = (struct chash_cfg *)ta_state;
1178 for (i = 0; i < cfg->size4; i++)
1179 SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1182 for (i = 0; i < cfg->size6; i++)
1183 SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1188 ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1191 struct ta_buf_chash *tb;
1192 struct chashentry *ent;
1195 tb = (struct ta_buf_chash *)ta_buf;
1197 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1199 error = tei_to_chash_ent(tei, ent);
1201 free(ent, M_IPFW_TBL);
1210 ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1211 void *ta_buf, uint32_t *pnum)
1213 struct chash_cfg *cfg;
1214 struct chashbhead *head;
1215 struct chashentry *ent, *tmp;
1216 struct ta_buf_chash *tb;
1218 uint32_t hash, value;
1220 cfg = (struct chash_cfg *)ta_state;
1221 tb = (struct ta_buf_chash *)ta_buf;
1222 ent = (struct chashentry *)tb->ent_ptr;
1226 if (tei->subtype == AF_INET) {
1227 if (tei->masklen != cfg->mask4)
1230 hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1232 /* Check for existence */
1233 SLIST_FOREACH(tmp, &head[hash], next) {
1234 if (tmp->a.a4 == ent->a.a4) {
1240 if (tei->masklen != cfg->mask6)
1243 hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1244 /* Check for existence */
1245 SLIST_FOREACH(tmp, &head[hash], next) {
1246 if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) {
1254 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1256 /* Record already exists. Update value if we're asked to */
1258 tmp->value = tei->value;
1260 /* Indicate that update has happened instead of addition */
1261 tei->flags |= TEI_FLAGS_UPDATED;
1264 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
1266 SLIST_INSERT_HEAD(&head[hash], ent, next);
1270 /* Update counters */
1271 if (tei->subtype == AF_INET)
1281 ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1284 struct ta_buf_chash *tb;
1286 tb = (struct ta_buf_chash *)ta_buf;
1288 return (tei_to_chash_ent(tei, &tb->ent));
1292 ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1293 void *ta_buf, uint32_t *pnum)
1295 struct chash_cfg *cfg;
1296 struct chashbhead *head;
1297 struct chashentry *tmp, *tmp_next, *ent;
1298 struct ta_buf_chash *tb;
1301 cfg = (struct chash_cfg *)ta_state;
1302 tb = (struct ta_buf_chash *)ta_buf;
1305 if (tei->subtype == AF_INET) {
1306 if (tei->masklen != cfg->mask4)
1309 hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1311 SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1312 if (tmp->a.a4 != ent->a.a4)
1315 SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1318 tei->value = tmp->value;
1323 if (tei->masklen != cfg->mask6)
1326 hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1327 SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1328 if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0)
1331 SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1334 tei->value = tmp->value;
1344 ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1347 struct ta_buf_chash *tb;
1349 tb = (struct ta_buf_chash *)ta_buf;
1351 if (tb->ent_ptr != NULL)
1352 free(tb->ent_ptr, M_IPFW_TBL);
1356 * Hash growing callbacks.
1360 ta_has_space_chash(void *ta_state, struct table_info *ti, uint32_t count,
1363 struct chash_cfg *cfg;
1367 * Since we don't know exact number of IPv4/IPv6 records in @count,
1368 * ignore non-zero @count value at all. Check current hash sizes
1369 * and return appropriate data.
1372 cfg = (struct chash_cfg *)ta_state;
1375 if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
1376 data |= (cfg->size4 * 2) << 16;
1377 if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
1378 data |= cfg->size6 * 2;
1389 * Allocate new, larger chash.
1392 ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags)
1394 struct mod_item *mi;
1395 struct chashbhead *head;
1398 mi = (struct mod_item *)ta_buf;
1400 memset(mi, 0, sizeof(struct mod_item));
1401 mi->size = (*pflags >> 16) & 0xFFFF;
1402 mi->size6 = *pflags & 0xFFFF;
1404 head = malloc(sizeof(struct chashbhead) * mi->size,
1405 M_IPFW, M_WAITOK | M_ZERO);
1406 for (i = 0; i < mi->size; i++)
1407 SLIST_INIT(&head[i]);
1408 mi->main_ptr = head;
1411 if (mi->size6 > 0) {
1412 head = malloc(sizeof(struct chashbhead) * mi->size6,
1413 M_IPFW, M_WAITOK | M_ZERO);
1414 for (i = 0; i < mi->size6; i++)
1415 SLIST_INIT(&head[i]);
1416 mi->main_ptr6 = head;
1423 * Copy data from old runtime array to new one.
1426 ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1430 /* In is not possible to do rehash if we're not holidng WLOCK. */
1435 * Switch old & new arrays.
1438 ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1441 struct mod_item *mi;
1442 struct chash_cfg *cfg;
1443 struct chashbhead *old_head, *new_head;
1444 struct chashentry *ent, *ent_next;
1447 size_t old_size, new_size;
1449 mi = (struct mod_item *)ta_buf;
1450 cfg = (struct chash_cfg *)ta_state;
1452 /* Check which hash we need to grow and do we still need that */
1453 if (mi->size > 0 && cfg->size4 < mi->size) {
1454 new_head = (struct chashbhead *)mi->main_ptr;
1455 new_size = mi->size;
1456 old_size = cfg->size4;
1457 old_head = ti->state;
1461 for (i = 0; i < old_size; i++) {
1462 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1463 nhash = hash_ent(ent, af, mlen, new_size);
1464 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1468 ti->state = new_head;
1469 cfg->head4 = new_head;
1470 cfg->size4 = mi->size;
1471 mi->main_ptr = old_head;
1474 if (mi->size6 > 0 && cfg->size6 < mi->size6) {
1475 new_head = (struct chashbhead *)mi->main_ptr6;
1476 new_size = mi->size6;
1477 old_size = cfg->size6;
1478 old_head = ti->xstate;
1482 for (i = 0; i < old_size; i++) {
1483 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1484 nhash = hash_ent(ent, af, mlen, new_size);
1485 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1489 ti->xstate = new_head;
1490 cfg->head6 = new_head;
1491 cfg->size6 = mi->size6;
1492 mi->main_ptr6 = old_head;
1495 /* Update lower 32 bits with new values */
1496 ti->data &= 0xFFFFFFFF00000000;
1497 ti->data |= log2(cfg->size4) << 8 | log2(cfg->size6);
1503 * Free unneded array.
1506 ta_flush_mod_chash(void *ta_buf)
1508 struct mod_item *mi;
1510 mi = (struct mod_item *)ta_buf;
1511 if (mi->main_ptr != NULL)
1512 free(mi->main_ptr, M_IPFW);
1513 if (mi->main_ptr6 != NULL)
1514 free(mi->main_ptr6, M_IPFW);
1517 struct table_algo cidr_hash = {
1518 .name = "cidr:hash",
1519 .type = IPFW_TABLE_CIDR,
1520 .ta_buf_size = sizeof(struct ta_buf_chash),
1521 .init = ta_init_chash,
1522 .destroy = ta_destroy_chash,
1523 .prepare_add = ta_prepare_add_chash,
1524 .prepare_del = ta_prepare_del_chash,
1525 .add = ta_add_chash,
1526 .del = ta_del_chash,
1527 .flush_entry = ta_flush_chash_entry,
1528 .foreach = ta_foreach_chash,
1529 .dump_tentry = ta_dump_chash_tentry,
1530 .find_tentry = ta_find_chash_tentry,
1531 .print_config = ta_print_chash_config,
1532 .dump_tinfo = ta_dump_chash_tinfo,
1533 .has_space = ta_has_space_chash,
1534 .prepare_mod = ta_prepare_mod_chash,
1535 .fill_mod = ta_fill_mod_chash,
1536 .modify = ta_modify_chash,
1537 .flush_mod = ta_flush_mod_chash,
1547 * - sorted array of "struct ifidx" pointed by ti->state.
1548 * Array is allocated with rounding up to IFIDX_CHUNK. Only existing
1549 * interfaces are stored in array, however its allocated size is
1550 * sufficient to hold all table records if needed.
1551 * - current array size is stored in ti->data
1554 * - "struct iftable_cfg" is allocated to store table state (ta_state).
1555 * - All table records are stored inside namedobj instance.
1568 struct named_object no;
1570 struct iftable_cfg *icfg;
1575 struct iftable_cfg {
1576 struct namedobj_instance *ii;
1577 struct ip_fw_chain *ch;
1578 struct table_info *ti;
1580 size_t size; /* Number of items allocated in array */
1581 size_t count; /* Number of all items */
1582 size_t used; /* Number of items _active_ now */
1587 struct ifentry *ife;
1591 int compare_ifidx(const void *k, const void *v);
1592 static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
1595 compare_ifidx(const void *k, const void *v)
1597 struct ifidx *ifidx;
1600 key = *((uint16_t *)k);
1601 ifidx = (struct ifidx *)v;
1603 if (key < ifidx->kidx)
1605 else if (key > ifidx->kidx)
1612 * Adds item @item with key @key into ascending-sorted array @base.
1613 * Assumes @base has enough additional storage.
1615 * Returns 1 on success, 0 on duplicate key.
1618 badd(const void *key, void *item, void *base, size_t nmemb,
1619 size_t size, int (*compar) (const void *, const void *))
1621 int min, max, mid, shift, res;
1625 memcpy(base, item, size);
1633 while (min <= max) {
1634 mid = (min + max) / 2;
1635 res = compar(key, (const void *)((caddr_t)base + mid * size));
1645 /* Item not found. */
1646 res = compar(key, (const void *)((caddr_t)base + mid * size));
1652 paddr = (caddr_t)base + shift * size;
1654 memmove(paddr + size, paddr, (nmemb - shift) * size);
1656 memcpy(paddr, item, size);
1662 * Deletes item with key @key from ascending-sorted array @base.
1664 * Returns 1 on success, 0 for non-existent key.
1667 bdel(const void *key, void *base, size_t nmemb, size_t size,
1668 int (*compar) (const void *, const void *))
1673 item = (caddr_t)bsearch(key, base, nmemb, size, compar);
1678 sz = (caddr_t)base + nmemb * size - item;
1681 memmove(item, item + size, sz);
1686 static struct ifidx *
1687 ifidx_find(struct table_info *ti, void *key)
1691 ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
1698 ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
1703 ifi = ifidx_find(ti, key);
1714 ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1715 char *data, uint8_t tflags)
1717 struct iftable_cfg *icfg;
1719 icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
1721 icfg->ii = ipfw_objhash_create(16);
1723 icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW,
1728 ti->state = icfg->main_ptr;
1729 ti->lookup = ta_lookup_ifidx;
1735 * Handle tableinfo @ti pointer change (on table array resize).
1738 ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
1740 struct iftable_cfg *icfg;
1742 icfg = (struct iftable_cfg *)ta_state;
1747 destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
1750 struct ifentry *ife;
1751 struct ip_fw_chain *ch;
1753 ch = (struct ip_fw_chain *)arg;
1754 ife = (struct ifentry *)no;
1756 ipfw_iface_del_notify(ch, &ife->ic);
1757 free(ife, M_IPFW_TBL);
1762 * Destroys table @ti
1765 ta_destroy_ifidx(void *ta_state, struct table_info *ti)
1767 struct iftable_cfg *icfg;
1768 struct ip_fw_chain *ch;
1770 icfg = (struct iftable_cfg *)ta_state;
1773 if (icfg->main_ptr != NULL)
1774 free(icfg->main_ptr, M_IPFW);
1776 ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
1778 ipfw_objhash_destroy(icfg->ii);
1784 * Provide algo-specific table info
1787 ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
1789 struct iftable_cfg *cfg;
1791 cfg = (struct iftable_cfg *)ta_state;
1793 tinfo->taclass4 = IPFW_TACLASS_ARRAY;
1794 tinfo->size4 = cfg->size;
1795 tinfo->count4 = cfg->used;
1796 tinfo->itemsize4 = sizeof(struct ifidx);
1800 * Prepare state to add to the table:
1801 * allocate ifentry and reference needed interface.
1804 ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1807 struct ta_buf_ifidx *tb;
1809 struct ifentry *ife;
1811 tb = (struct ta_buf_ifidx *)ta_buf;
1813 /* Check if string is terminated */
1814 ifname = (char *)tei->paddr;
1815 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1818 ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
1819 ife->value = tei->value;
1820 ife->ic.cb = if_notifier;
1821 ife->ic.cbdata = ife;
1823 if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0)
1826 /* Use ipfw_iface 'ifname' field as stable storage */
1827 ife->no.name = ife->ic.iface->ifname;
1835 ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1836 void *ta_buf, uint32_t *pnum)
1838 struct iftable_cfg *icfg;
1839 struct ifentry *ife, *tmp;
1840 struct ta_buf_ifidx *tb;
1841 struct ipfw_iface *iif;
1846 tb = (struct ta_buf_ifidx *)ta_buf;
1847 ifname = (char *)tei->paddr;
1848 icfg = (struct iftable_cfg *)ta_state;
1853 tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1856 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1859 /* Exchange values in @tmp and @tei */
1861 tmp->value = tei->value;
1864 iif = tmp->ic.iface;
1865 if (iif->resolved != 0) {
1866 /* We have to update runtime value, too */
1867 ifi = ifidx_find(ti, &iif->ifindex);
1868 ifi->value = ife->value;
1871 /* Indicate that update has happened instead of addition */
1872 tei->flags |= TEI_FLAGS_UPDATED;
1877 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
1880 /* Link to internal list */
1881 ipfw_objhash_add(icfg->ii, &ife->no);
1883 /* Link notifier (possible running its callback) */
1884 ipfw_iface_add_notify(icfg->ch, &ife->ic);
1894 * Prepare to delete key from table.
1895 * Do basic interface name checks.
1898 ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1901 struct ta_buf_ifidx *tb;
1904 tb = (struct ta_buf_ifidx *)ta_buf;
1906 /* Check if string is terminated */
1907 ifname = (char *)tei->paddr;
1908 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1915 * Remove key from both configuration list and
1916 * runtime array. Removed interface notification.
1919 ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1920 void *ta_buf, uint32_t *pnum)
1922 struct iftable_cfg *icfg;
1923 struct ifentry *ife;
1924 struct ta_buf_ifidx *tb;
1929 tb = (struct ta_buf_ifidx *)ta_buf;
1930 ifname = (char *)tei->paddr;
1931 icfg = (struct iftable_cfg *)ta_state;
1934 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1939 if (ife->linked != 0) {
1940 /* We have to remove item from runtime */
1941 ifindex = ife->ic.iface->ifindex;
1943 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
1944 sizeof(struct ifidx), compare_ifidx);
1946 KASSERT(res == 1, ("index %d does not exist", ifindex));
1948 ti->data = icfg->used;
1952 /* Unlink from local list */
1953 ipfw_objhash_del(icfg->ii, &ife->no);
1954 /* Unlink notifier */
1955 ipfw_iface_del_notify(icfg->ch, &ife->ic);
1958 tei->value = ife->value;
1967 * Flush deleted entry.
1968 * Drops interface reference and frees entry.
1971 ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1974 struct ta_buf_ifidx *tb;
1976 tb = (struct ta_buf_ifidx *)ta_buf;
1978 if (tb->ife != NULL) {
1980 ipfw_iface_unref(ch, &tb->ife->ic);
1981 free(tb->ife, M_IPFW_TBL);
1987 * Handle interface announce/withdrawal for particular table.
1988 * Every real runtime array modification happens here.
1991 if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
1993 struct ifentry *ife;
1995 struct iftable_cfg *icfg;
1996 struct table_info *ti;
1999 ife = (struct ifentry *)cbdata;
2003 KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
2005 if (ife->linked == 0 && ifindex != 0) {
2006 /* Interface announce */
2009 ifi.value = ife->value;
2010 res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
2011 sizeof(struct ifidx), compare_ifidx);
2012 KASSERT(res == 1, ("index %d already exists", ifindex));
2014 ti->data = icfg->used;
2016 } else if (ife->linked != 0 && ifindex == 0) {
2017 /* Interface withdrawal */
2018 ifindex = ife->ic.iface->ifindex;
2020 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
2021 sizeof(struct ifidx), compare_ifidx);
2023 KASSERT(res == 1, ("index %d does not exist", ifindex));
2025 ti->data = icfg->used;
2032 * Table growing callbacks.
2036 ta_has_space_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
2039 struct iftable_cfg *cfg;
2042 cfg = (struct iftable_cfg *)ta_state;
2045 while (size < cfg->count + count)
2048 if (size != cfg->size) {
2057 * Allocate ned, larger runtime ifidx array.
2060 ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
2062 struct mod_item *mi;
2064 mi = (struct mod_item *)ta_buf;
2066 memset(mi, 0, sizeof(struct mod_item));
2068 mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
2075 * Copy data from old runtime array to new one.
2078 ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2081 struct mod_item *mi;
2082 struct iftable_cfg *icfg;
2084 mi = (struct mod_item *)ta_buf;
2085 icfg = (struct iftable_cfg *)ta_state;
2087 /* Check if we still need to grow array */
2088 if (icfg->size >= mi->size) {
2093 memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
2099 * Switch old & new arrays.
2102 ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2105 struct mod_item *mi;
2106 struct iftable_cfg *icfg;
2109 mi = (struct mod_item *)ta_buf;
2110 icfg = (struct iftable_cfg *)ta_state;
2112 old_ptr = icfg->main_ptr;
2113 icfg->main_ptr = mi->main_ptr;
2114 icfg->size = mi->size;
2115 ti->state = icfg->main_ptr;
2117 mi->main_ptr = old_ptr;
2123 * Free unneded array.
2126 ta_flush_mod_ifidx(void *ta_buf)
2128 struct mod_item *mi;
2130 mi = (struct mod_item *)ta_buf;
2131 if (mi->main_ptr != NULL)
2132 free(mi->main_ptr, M_IPFW);
2136 ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
2137 ipfw_obj_tentry *tent)
2139 struct ifentry *ife;
2141 ife = (struct ifentry *)e;
2143 tent->masklen = 8 * IF_NAMESIZE;
2144 memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
2145 tent->value = ife->value;
2151 ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
2152 ipfw_obj_tentry *tent)
2154 struct iftable_cfg *icfg;
2155 struct ifentry *ife;
2158 icfg = (struct iftable_cfg *)ta_state;
2159 ifname = tent->k.iface;
2161 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2164 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2167 ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
2180 foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
2183 struct ifentry *ife;
2184 struct wa_ifidx *wa;
2186 ife = (struct ifentry *)no;
2187 wa = (struct wa_ifidx *)arg;
2189 wa->f(ife, wa->arg);
2193 ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2196 struct iftable_cfg *icfg;
2199 icfg = (struct iftable_cfg *)ta_state;
2204 ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
2207 struct table_algo iface_idx = {
2208 .name = "iface:array",
2209 .type = IPFW_TABLE_INTERFACE,
2210 .flags = TA_FLAG_DEFAULT,
2211 .ta_buf_size = sizeof(struct ta_buf_ifidx),
2212 .init = ta_init_ifidx,
2213 .destroy = ta_destroy_ifidx,
2214 .prepare_add = ta_prepare_add_ifidx,
2215 .prepare_del = ta_prepare_del_ifidx,
2216 .add = ta_add_ifidx,
2217 .del = ta_del_ifidx,
2218 .flush_entry = ta_flush_ifidx_entry,
2219 .foreach = ta_foreach_ifidx,
2220 .dump_tentry = ta_dump_ifidx_tentry,
2221 .find_tentry = ta_find_ifidx_tentry,
2222 .dump_tinfo = ta_dump_ifidx_tinfo,
2223 .has_space = ta_has_space_ifidx,
2224 .prepare_mod = ta_prepare_mod_ifidx,
2225 .fill_mod = ta_fill_mod_ifidx,
2226 .modify = ta_modify_ifidx,
2227 .flush_mod = ta_flush_mod_ifidx,
2228 .change_ti = ta_change_ti_ifidx,
2232 * Number array cmds.
2237 * - sorted array of "struct numarray" pointed by ti->state.
2238 * Array is allocated with rounding up to NUMARRAY_CHUNK.
2239 * - current array size is stored in ti->data
2248 struct numarray_cfg {
2250 size_t size; /* Number of items allocated in array */
2251 size_t used; /* Number of items _active_ now */
2254 struct ta_buf_numarray
2259 int compare_numarray(const void *k, const void *v);
2262 compare_numarray(const void *k, const void *v)
2264 struct numarray *na;
2267 key = *((uint32_t *)k);
2268 na = (struct numarray *)v;
2270 if (key < na->number)
2272 else if (key > na->number)
2278 static struct numarray *
2279 numarray_find(struct table_info *ti, void *key)
2281 struct numarray *ri;
2283 ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
2290 ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
2293 struct numarray *ri;
2295 ri = numarray_find(ti, key);
2306 ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2307 char *data, uint8_t tflags)
2309 struct numarray_cfg *cfg;
2311 cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
2314 cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
2318 ti->state = cfg->main_ptr;
2319 ti->lookup = ta_lookup_numarray;
2325 * Destroys table @ti
2328 ta_destroy_numarray(void *ta_state, struct table_info *ti)
2330 struct numarray_cfg *cfg;
2332 cfg = (struct numarray_cfg *)ta_state;
2334 if (cfg->main_ptr != NULL)
2335 free(cfg->main_ptr, M_IPFW);
2341 * Provide algo-specific table info
2344 ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2346 struct numarray_cfg *cfg;
2348 cfg = (struct numarray_cfg *)ta_state;
2350 tinfo->taclass4 = IPFW_TACLASS_ARRAY;
2351 tinfo->size4 = cfg->size;
2352 tinfo->count4 = cfg->used;
2353 tinfo->itemsize4 = sizeof(struct numarray);
2357 * Prepare for addition/deletion to an array.
2360 ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
2363 struct ta_buf_numarray *tb;
2365 tb = (struct ta_buf_numarray *)ta_buf;
2367 tb->na.number = *((uint32_t *)tei->paddr);
2368 tb->na.value = tei->value;
2374 ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2375 void *ta_buf, uint32_t *pnum)
2377 struct numarray_cfg *cfg;
2378 struct ta_buf_numarray *tb;
2379 struct numarray *ri;
2383 tb = (struct ta_buf_numarray *)ta_buf;
2384 cfg = (struct numarray_cfg *)ta_state;
2386 ri = numarray_find(ti, &tb->na.number);
2389 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2392 /* Exchange values between ri and @tei */
2394 ri->value = tei->value;
2396 /* Indicate that update has happened instead of addition */
2397 tei->flags |= TEI_FLAGS_UPDATED;
2402 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2405 res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
2406 sizeof(struct numarray), compare_numarray);
2408 KASSERT(res == 1, ("number %d already exists", tb->na.number));
2410 ti->data = cfg->used;
2417 * Remove key from both configuration list and
2418 * runtime array. Removed interface notification.
2421 ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2422 void *ta_buf, uint32_t *pnum)
2424 struct numarray_cfg *cfg;
2425 struct ta_buf_numarray *tb;
2426 struct numarray *ri;
2429 tb = (struct ta_buf_numarray *)ta_buf;
2430 cfg = (struct numarray_cfg *)ta_state;
2432 ri = numarray_find(ti, &tb->na.number);
2436 tei->value = ri->value;
2438 res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
2439 sizeof(struct numarray), compare_numarray);
2441 KASSERT(res == 1, ("number %u does not exist", tb->na.number));
2443 ti->data = cfg->used;
2450 ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2454 /* We don't have any state, do nothing */
2459 * Table growing callbacks.
2463 ta_has_space_numarray(void *ta_state, struct table_info *ti, uint32_t count,
2466 struct numarray_cfg *cfg;
2469 cfg = (struct numarray_cfg *)ta_state;
2472 while (size < cfg->used + count)
2475 if (size != cfg->size) {
2484 * Allocate new, larger runtime array.
2487 ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
2489 struct mod_item *mi;
2491 mi = (struct mod_item *)ta_buf;
2493 memset(mi, 0, sizeof(struct mod_item));
2495 mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
2502 * Copy data from old runtime array to new one.
2505 ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2508 struct mod_item *mi;
2509 struct numarray_cfg *cfg;
2511 mi = (struct mod_item *)ta_buf;
2512 cfg = (struct numarray_cfg *)ta_state;
2514 /* Check if we still need to grow array */
2515 if (cfg->size >= mi->size) {
2520 memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
2526 * Switch old & new arrays.
2529 ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2532 struct mod_item *mi;
2533 struct numarray_cfg *cfg;
2536 mi = (struct mod_item *)ta_buf;
2537 cfg = (struct numarray_cfg *)ta_state;
2539 old_ptr = cfg->main_ptr;
2540 cfg->main_ptr = mi->main_ptr;
2541 cfg->size = mi->size;
2542 ti->state = cfg->main_ptr;
2544 mi->main_ptr = old_ptr;
2550 * Free unneded array.
2553 ta_flush_mod_numarray(void *ta_buf)
2555 struct mod_item *mi;
2557 mi = (struct mod_item *)ta_buf;
2558 if (mi->main_ptr != NULL)
2559 free(mi->main_ptr, M_IPFW);
2563 ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
2564 ipfw_obj_tentry *tent)
2566 struct numarray *na;
2568 na = (struct numarray *)e;
2570 tent->k.key = na->number;
2571 tent->value = na->value;
2577 ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2578 ipfw_obj_tentry *tent)
2580 struct numarray_cfg *cfg;
2581 struct numarray *ri;
2583 cfg = (struct numarray_cfg *)ta_state;
2585 ri = numarray_find(ti, &tent->k.key);
2588 ta_dump_numarray_tentry(ta_state, ti, ri, tent);
2596 ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2599 struct numarray_cfg *cfg;
2600 struct numarray *array;
2603 cfg = (struct numarray_cfg *)ta_state;
2604 array = cfg->main_ptr;
2606 for (i = 0; i < cfg->used; i++)
2610 struct table_algo number_array = {
2611 .name = "number:array",
2612 .type = IPFW_TABLE_NUMBER,
2613 .ta_buf_size = sizeof(struct ta_buf_numarray),
2614 .init = ta_init_numarray,
2615 .destroy = ta_destroy_numarray,
2616 .prepare_add = ta_prepare_add_numarray,
2617 .prepare_del = ta_prepare_add_numarray,
2618 .add = ta_add_numarray,
2619 .del = ta_del_numarray,
2620 .flush_entry = ta_flush_numarray_entry,
2621 .foreach = ta_foreach_numarray,
2622 .dump_tentry = ta_dump_numarray_tentry,
2623 .find_tentry = ta_find_numarray_tentry,
2624 .dump_tinfo = ta_dump_numarray_tinfo,
2625 .has_space = ta_has_space_numarray,
2626 .prepare_mod = ta_prepare_mod_numarray,
2627 .fill_mod = ta_fill_mod_numarray,
2628 .modify = ta_modify_numarray,
2629 .flush_mod = ta_flush_mod_numarray,
2637 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
2640 * inv.mask4: 32 - mask
2642 * 1) _slow lookup: mask
2643 * 2) _aligned: (128 - mask) / 8
2654 SLIST_HEAD(fhashbhead, fhashentry);
2657 SLIST_ENTRY(fhashentry) next;
2667 struct fhashentry4 {
2668 struct fhashentry e;
2673 struct fhashentry6 {
2674 struct fhashentry e;
2675 struct in6_addr dip6;
2676 struct in6_addr sip6;
2680 struct fhashbhead *head;
2683 struct fhashentry4 fe4;
2684 struct fhashentry6 fe6;
2687 struct ta_buf_fhash {
2689 struct fhashentry6 fe6;
2693 cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
2697 ka = (uint64_t *)(&a->next + 1);
2698 kb = (uint64_t *)(&b->next + 1);
2700 if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0))
2706 static __inline uint32_t
2707 hash_flow4(struct fhashentry4 *f, int hsize)
2711 i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport);
2713 return (i % (hsize - 1));
2716 static __inline uint32_t
2717 hash_flow6(struct fhashentry6 *f, int hsize)
2721 i = (f->dip6.__u6_addr.__u6_addr32[2]) ^
2722 (f->dip6.__u6_addr.__u6_addr32[3]) ^
2723 (f->sip6.__u6_addr.__u6_addr32[2]) ^
2724 (f->sip6.__u6_addr.__u6_addr32[3]) ^
2725 (f->e.dport) ^ (f->e.sport);
2727 return (i % (hsize - 1));
2731 hash_flow_ent(struct fhashentry *ent, uint32_t size)
2735 if (ent->af == AF_INET) {
2736 hash = hash_flow4((struct fhashentry4 *)ent, size);
2738 hash = hash_flow6((struct fhashentry6 *)ent, size);
2745 ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
2748 struct fhashbhead *head;
2749 struct fhashentry *ent;
2750 struct fhashentry4 *m4;
2751 struct ipfw_flow_id *id;
2752 uint16_t hash, hsize;
2754 id = (struct ipfw_flow_id *)key;
2755 head = (struct fhashbhead *)ti->state;
2757 m4 = (struct fhashentry4 *)ti->xstate;
2759 if (id->addr_type == 4) {
2760 struct fhashentry4 f;
2762 /* Copy hash mask */
2765 f.dip.s_addr &= id->dst_ip;
2766 f.sip.s_addr &= id->src_ip;
2767 f.e.dport &= id->dst_port;
2768 f.e.sport &= id->src_port;
2769 f.e.proto &= id->proto;
2770 hash = hash_flow4(&f, hsize);
2771 SLIST_FOREACH(ent, &head[hash], next) {
2772 if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
2777 } else if (id->addr_type == 6) {
2778 struct fhashentry6 f;
2781 /* Copy hash mask */
2782 f = *((struct fhashentry6 *)(m4 + 1));
2784 /* Handle lack of __u6_addr.__u6_addr64 */
2785 fp = (uint64_t *)&f.dip6;
2786 idp = (uint64_t *)&id->dst_ip6;
2787 /* src IPv6 is stored after dst IPv6 */
2792 f.e.dport &= id->dst_port;
2793 f.e.sport &= id->src_port;
2794 f.e.proto &= id->proto;
2795 hash = hash_flow6(&f, hsize);
2796 SLIST_FOREACH(ent, &head[hash], next) {
2797 if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
2811 ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2812 char *data, uint8_t tflags)
2815 struct fhash_cfg *cfg;
2816 struct fhashentry4 *fe4;
2817 struct fhashentry6 *fe6;
2819 cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
2823 cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW,
2825 for (i = 0; i < cfg->size; i++)
2826 SLIST_INIT(&cfg->head[i]);
2828 /* Fill in fe masks based on @tflags */
2831 if (tflags & IPFW_TFFLAG_SRCIP) {
2832 memset(&fe4->sip, 0xFF, sizeof(fe4->sip));
2833 memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6));
2835 if (tflags & IPFW_TFFLAG_DSTIP) {
2836 memset(&fe4->dip, 0xFF, sizeof(fe4->dip));
2837 memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6));
2839 if (tflags & IPFW_TFFLAG_SRCPORT) {
2840 memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport));
2841 memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport));
2843 if (tflags & IPFW_TFFLAG_DSTPORT) {
2844 memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport));
2845 memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport));
2847 if (tflags & IPFW_TFFLAG_PROTO) {
2848 memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto));
2849 memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto));
2852 fe4->e.af = AF_INET;
2853 fe6->e.af = AF_INET6;
2856 ti->state = cfg->head;
2857 ti->xstate = &cfg->fe4;
2858 ti->data = cfg->size;
2859 ti->lookup = ta_lookup_fhash;
2865 ta_destroy_fhash(void *ta_state, struct table_info *ti)
2867 struct fhash_cfg *cfg;
2868 struct fhashentry *ent, *ent_next;
2871 cfg = (struct fhash_cfg *)ta_state;
2873 for (i = 0; i < cfg->size; i++)
2874 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
2875 free(ent, M_IPFW_TBL);
2877 free(cfg->head, M_IPFW);
2882 * Provide algo-specific table info
2885 ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2887 struct fhash_cfg *cfg;
2889 cfg = (struct fhash_cfg *)ta_state;
2891 tinfo->flags = IPFW_TATFLAGS_AFITEM;
2892 tinfo->taclass4 = IPFW_TACLASS_HASH;
2893 tinfo->size4 = cfg->size;
2894 tinfo->count4 = cfg->items;
2895 tinfo->itemsize4 = sizeof(struct fhashentry4);
2896 tinfo->itemsize6 = sizeof(struct fhashentry6);
2900 ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
2901 ipfw_obj_tentry *tent)
2903 struct fhash_cfg *cfg;
2904 struct fhashentry *ent;
2905 struct fhashentry4 *fe4;
2906 struct fhashentry6 *fe6;
2907 struct tflow_entry *tfe;
2909 cfg = (struct fhash_cfg *)ta_state;
2910 ent = (struct fhashentry *)e;
2911 tfe = &tent->k.flow;
2914 tfe->proto = ent->proto;
2915 tfe->dport = htons(ent->dport);
2916 tfe->sport = htons(ent->sport);
2917 tent->value = ent->value;
2918 tent->subtype = ent->af;
2920 if (ent->af == AF_INET) {
2921 fe4 = (struct fhashentry4 *)ent;
2922 tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr);
2923 tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr);
2927 fe6 = (struct fhashentry6 *)ent;
2928 tfe->a.a6.sip6 = fe6->sip6;
2929 tfe->a.a6.dip6 = fe6->dip6;
2930 tent->masklen = 128;
2938 tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
2940 struct fhashentry4 *fe4;
2941 struct fhashentry6 *fe6;
2942 struct tflow_entry *tfe;
2944 tfe = (struct tflow_entry *)tei->paddr;
2946 ent->af = tei->subtype;
2947 ent->proto = tfe->proto;
2948 ent->value = tei->value;
2949 ent->dport = ntohs(tfe->dport);
2950 ent->sport = ntohs(tfe->sport);
2952 if (tei->subtype == AF_INET) {
2954 fe4 = (struct fhashentry4 *)ent;
2955 fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr);
2956 fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr);
2959 } else if (tei->subtype == AF_INET6) {
2960 fe6 = (struct fhashentry6 *)ent;
2961 fe6->sip6 = tfe->a.a6.sip6;
2962 fe6->dip6 = tfe->a.a6.dip6;
2965 /* Unknown CIDR type */
2974 ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
2975 ipfw_obj_tentry *tent)
2977 struct fhash_cfg *cfg;
2978 struct fhashbhead *head;
2979 struct fhashentry *ent, *tmp;
2980 struct fhashentry6 fe6;
2981 struct tentry_info tei;
2986 cfg = (struct fhash_cfg *)ta_state;
2990 memset(&fe6, 0, sizeof(fe6));
2991 memset(&tei, 0, sizeof(tei));
2993 tei.paddr = &tent->k.flow;
2994 tei.subtype = tent->subtype;
2996 if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
3000 hash = hash_flow_ent(ent, cfg->size);
3002 if (tei.subtype == AF_INET)
3003 sz = 2 * sizeof(struct in_addr);
3005 sz = 2 * sizeof(struct in6_addr);
3007 /* Check for existence */
3008 SLIST_FOREACH(tmp, &head[hash], next) {
3009 if (cmp_flow_ent(tmp, ent, sz) != 0) {
3010 ta_dump_fhash_tentry(ta_state, ti, tmp, tent);
3019 ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3022 struct fhash_cfg *cfg;
3023 struct fhashentry *ent, *ent_next;
3026 cfg = (struct fhash_cfg *)ta_state;
3028 for (i = 0; i < cfg->size; i++)
3029 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3034 ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3037 struct ta_buf_fhash *tb;
3038 struct fhashentry *ent;
3042 tb = (struct ta_buf_fhash *)ta_buf;
3044 if (tei->subtype == AF_INET)
3045 sz = sizeof(struct fhashentry4);
3046 else if (tei->subtype == AF_INET6)
3047 sz = sizeof(struct fhashentry6);
3051 ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO);
3053 error = tei_to_fhash_ent(tei, ent);
3055 free(ent, M_IPFW_TBL);
3064 ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3065 void *ta_buf, uint32_t *pnum)
3067 struct fhash_cfg *cfg;
3068 struct fhashbhead *head;
3069 struct fhashentry *ent, *tmp;
3070 struct ta_buf_fhash *tb;
3072 uint32_t hash, value;
3075 cfg = (struct fhash_cfg *)ta_state;
3076 tb = (struct ta_buf_fhash *)ta_buf;
3077 ent = (struct fhashentry *)tb->ent_ptr;
3081 hash = hash_flow_ent(ent, cfg->size);
3083 if (tei->subtype == AF_INET)
3084 sz = 2 * sizeof(struct in_addr);
3086 sz = 2 * sizeof(struct in6_addr);
3088 /* Check for existence */
3089 SLIST_FOREACH(tmp, &head[hash], next) {
3090 if (cmp_flow_ent(tmp, ent, sz) != 0) {
3097 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
3099 /* Record already exists. Update value if we're asked to */
3100 /* Exchange values between tmp and @tei */
3102 tmp->value = tei->value;
3104 /* Indicate that update has happened instead of addition */
3105 tei->flags |= TEI_FLAGS_UPDATED;
3108 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
3111 SLIST_INSERT_HEAD(&head[hash], ent, next);
3115 /* Update counters and check if we need to grow hash */
3123 ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3126 struct ta_buf_fhash *tb;
3128 tb = (struct ta_buf_fhash *)ta_buf;
3130 return (tei_to_fhash_ent(tei, &tb->fe6.e));
3134 ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3135 void *ta_buf, uint32_t *pnum)
3137 struct fhash_cfg *cfg;
3138 struct fhashbhead *head;
3139 struct fhashentry *ent, *tmp;
3140 struct ta_buf_fhash *tb;
3144 cfg = (struct fhash_cfg *)ta_state;
3145 tb = (struct ta_buf_fhash *)ta_buf;
3149 hash = hash_flow_ent(ent, cfg->size);
3151 if (tei->subtype == AF_INET)
3152 sz = 2 * sizeof(struct in_addr);
3154 sz = 2 * sizeof(struct in6_addr);
3156 /* Check for existence */
3157 SLIST_FOREACH(tmp, &head[hash], next) {
3158 if (cmp_flow_ent(tmp, ent, sz) == 0)
3161 SLIST_REMOVE(&head[hash], tmp, fhashentry, next);
3162 tei->value = tmp->value;
3173 ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3176 struct ta_buf_fhash *tb;
3178 tb = (struct ta_buf_fhash *)ta_buf;
3180 if (tb->ent_ptr != NULL)
3181 free(tb->ent_ptr, M_IPFW_TBL);
3185 * Hash growing callbacks.
3189 ta_has_space_fhash(void *ta_state, struct table_info *ti, uint32_t count,
3192 struct fhash_cfg *cfg;
3194 cfg = (struct fhash_cfg *)ta_state;
3196 if (cfg->items > cfg->size && cfg->size < 65536) {
3197 *pflags = cfg->size * 2;
3205 * Allocate new, larger fhash.
3208 ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags)
3210 struct mod_item *mi;
3211 struct fhashbhead *head;
3214 mi = (struct mod_item *)ta_buf;
3216 memset(mi, 0, sizeof(struct mod_item));
3218 head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW,
3220 for (i = 0; i < mi->size; i++)
3221 SLIST_INIT(&head[i]);
3223 mi->main_ptr = head;
3229 * Copy data from old runtime array to new one.
3232 ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3236 /* In is not possible to do rehash if we're not holidng WLOCK. */
3241 * Switch old & new arrays.
3244 ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3247 struct mod_item *mi;
3248 struct fhash_cfg *cfg;
3249 struct fhashbhead *old_head, *new_head;
3250 struct fhashentry *ent, *ent_next;
3255 mi = (struct mod_item *)ta_buf;
3256 cfg = (struct fhash_cfg *)ta_state;
3258 /* Check which hash we need to grow and do we still need that */
3259 old_size = cfg->size;
3260 old_head = ti->state;
3262 if (old_size >= mi->size)
3265 new_head = (struct fhashbhead *)mi->main_ptr;
3266 for (i = 0; i < old_size; i++) {
3267 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
3268 nhash = hash_flow_ent(ent, mi->size);
3269 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
3273 ti->state = new_head;
3274 ti->data = mi->size;
3275 cfg->head = new_head;
3276 cfg->size = mi->size;
3278 mi->main_ptr = old_head;
3284 * Free unneded array.
3287 ta_flush_mod_fhash(void *ta_buf)
3289 struct mod_item *mi;
3291 mi = (struct mod_item *)ta_buf;
3292 if (mi->main_ptr != NULL)
3293 free(mi->main_ptr, M_IPFW);
3296 struct table_algo flow_hash = {
3297 .name = "flow:hash",
3298 .type = IPFW_TABLE_FLOW,
3299 .flags = TA_FLAG_DEFAULT,
3300 .ta_buf_size = sizeof(struct ta_buf_fhash),
3301 .init = ta_init_fhash,
3302 .destroy = ta_destroy_fhash,
3303 .prepare_add = ta_prepare_add_fhash,
3304 .prepare_del = ta_prepare_del_fhash,
3305 .add = ta_add_fhash,
3306 .del = ta_del_fhash,
3307 .flush_entry = ta_flush_fhash_entry,
3308 .foreach = ta_foreach_fhash,
3309 .dump_tentry = ta_dump_fhash_tentry,
3310 .find_tentry = ta_find_fhash_tentry,
3311 .dump_tinfo = ta_dump_fhash_tinfo,
3312 .has_space = ta_has_space_fhash,
3313 .prepare_mod = ta_prepare_mod_fhash,
3314 .fill_mod = ta_fill_mod_fhash,
3315 .modify = ta_modify_fhash,
3316 .flush_mod = ta_flush_mod_fhash,
3320 ipfw_table_algo_init(struct ip_fw_chain *ch)
3325 * Register all algorithms presented here.
3327 sz = sizeof(struct table_algo);
3328 ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx);
3329 ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx);
3330 ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
3331 ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
3332 ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
3336 ipfw_table_algo_destroy(struct ip_fw_chain *ch)
3339 ipfw_del_table_algo(ch, cidr_radix.idx);
3340 ipfw_del_table_algo(ch, cidr_hash.idx);
3341 ipfw_del_table_algo(ch, iface_idx.idx);
3342 ipfw_del_table_algo(ch, number_array.idx);
3343 ipfw_del_table_algo(ch, flow_hash.idx);