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,
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, void *key,
225 uint32_t keylen, ipfw_obj_tentry *tent)
227 struct radix_node_head *rnh;
231 if (keylen == sizeof(in_addr_t)) {
232 struct sockaddr_in sa;
233 KEY_LEN(sa) = KEY_LEN_INET;
234 sa.sin_addr.s_addr = *((in_addr_t *)key);
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, key, 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);
269 struct sockaddr *addr_ptr;
270 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);
298 ta_prepare_add_cidr(struct ip_fw_chain *ch, struct tentry_info *tei,
301 struct ta_buf_cidr *tb;
302 struct radix_cidr_entry *ent;
303 struct radix_cidr_xentry *xent;
305 struct sockaddr_in *mask;
306 struct sa_in6 *mask6;
309 tb = (struct ta_buf_cidr *)ta_buf;
310 memset(tb, 0, sizeof(struct ta_buf_cidr));
314 if (tei->subtype == AF_INET) {
318 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
319 ent->value = tei->value;
320 mask = &tb->addr.a4.ma;
321 /* Set 'total' structure length */
322 KEY_LEN(ent->addr) = KEY_LEN_INET;
323 KEY_LEN(*mask) = KEY_LEN_INET;
324 ent->addr.sin_family = AF_INET;
325 mask->sin_addr.s_addr =
326 htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
327 addr = *((in_addr_t *)tei->paddr);
328 ent->addr.sin_addr.s_addr = addr & mask->sin_addr.s_addr;
332 tb->addr_ptr = (struct sockaddr *)&ent->addr;
334 tb->mask_ptr = (struct sockaddr *)mask;
337 } else if (tei->subtype == AF_INET6) {
341 xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
342 xent->value = tei->value;
343 mask6 = &tb->addr.a6.ma;
344 /* Set 'total' structure length */
345 KEY_LEN(xent->addr6) = KEY_LEN_INET6;
346 KEY_LEN(*mask6) = KEY_LEN_INET6;
347 xent->addr6.sin6_family = AF_INET6;
348 ipv6_writemask(&mask6->sin6_addr, mlen);
349 memcpy(&xent->addr6.sin6_addr, tei->paddr,
350 sizeof(struct in6_addr));
351 APPLY_MASK(&xent->addr6.sin6_addr, &mask6->sin6_addr);
352 xent->masklen = mlen;
355 tb->addr_ptr = (struct sockaddr *)&xent->addr6;
357 tb->mask_ptr = (struct sockaddr *)mask6;
360 /* Unknown CIDR type */
368 ta_add_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei,
369 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
371 struct radix_node_head *rnh;
372 struct radix_node *rn;
373 struct ta_buf_cidr *tb;
376 tb = (struct ta_buf_cidr *)ta_buf;
378 if (tei->subtype == AF_INET)
383 rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr);
386 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
388 /* Record already exists. Update value if we're asked to */
389 rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh);
393 * Radix may have failed addition for other reasons
394 * like failure in mask allocation code.
399 if (tei->subtype == AF_INET) {
401 value = ((struct radix_cidr_entry *)tb->ent_ptr)->value;
402 ((struct radix_cidr_entry *)rn)->value = value;
405 value = ((struct radix_cidr_xentry *)tb->ent_ptr)->value;
406 ((struct radix_cidr_xentry *)rn)->value = value;
409 /* Indicate that update has happened instead of addition */
410 tei->flags |= TEI_FLAGS_UPDATED;
423 ta_prepare_del_cidr(struct ip_fw_chain *ch, struct tentry_info *tei,
426 struct ta_buf_cidr *tb;
427 struct sockaddr_in sa, mask;
428 struct sa_in6 sa6, mask6;
432 tb = (struct ta_buf_cidr *)ta_buf;
433 memset(tb, 0, sizeof(struct ta_buf_cidr));
437 if (tei->subtype == AF_INET) {
440 memset(&sa, 0, sizeof(struct sockaddr_in));
441 memset(&mask, 0, sizeof(struct sockaddr_in));
442 /* Set 'total' structure length */
443 KEY_LEN(sa) = KEY_LEN_INET;
444 KEY_LEN(mask) = KEY_LEN_INET;
445 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
446 addr = *((in_addr_t *)tei->paddr);
447 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
449 tb->addr.a4.ma = mask;
450 tb->addr_ptr = (struct sockaddr *)&tb->addr.a4.sa;
452 tb->mask_ptr = (struct sockaddr *)&tb->addr.a4.ma;
454 } else if (tei->subtype == AF_INET6) {
457 memset(&sa6, 0, sizeof(struct sa_in6));
458 memset(&mask6, 0, sizeof(struct sa_in6));
459 /* Set 'total' structure length */
460 KEY_LEN(sa6) = KEY_LEN_INET6;
461 KEY_LEN(mask6) = KEY_LEN_INET6;
462 ipv6_writemask(&mask6.sin6_addr, mlen);
463 memcpy(&sa6.sin6_addr, tei->paddr,
464 sizeof(struct in6_addr));
465 APPLY_MASK(&sa6.sin6_addr, &mask6.sin6_addr);
466 tb->addr.a6.sa = sa6;
467 tb->addr.a6.ma = mask6;
468 tb->addr_ptr = (struct sockaddr *)&tb->addr.a6.sa;
470 tb->mask_ptr = (struct sockaddr *)&tb->addr.a6.ma;
479 ta_del_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei,
480 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
482 struct radix_node_head *rnh;
483 struct radix_node *rn;
484 struct ta_buf_cidr *tb;
486 tb = (struct ta_buf_cidr *)ta_buf;
488 if (tei->subtype == AF_INET)
493 rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh);
506 ta_flush_cidr_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
509 struct ta_buf_cidr *tb;
511 tb = (struct ta_buf_cidr *)ta_buf;
513 if (tb->ent_ptr != NULL)
514 free(tb->ent_ptr, M_IPFW_TBL);
517 struct table_algo cidr_radix = {
518 .name = "cidr:radix",
519 .type = IPFW_TABLE_CIDR,
520 .init = ta_init_radix,
521 .destroy = ta_destroy_radix,
522 .prepare_add = ta_prepare_add_cidr,
523 .prepare_del = ta_prepare_del_cidr,
526 .flush_entry = ta_flush_cidr_entry,
527 .foreach = ta_foreach_radix,
528 .dump_tentry = ta_dump_radix_tentry,
529 .find_tentry = ta_find_radix_tentry,
538 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
541 * inv.mask4: 32 - mask
543 * 1) _slow lookup: mask
544 * 2) _aligned: (128 - mask) / 8
550 SLIST_HEAD(chashbhead, chashentry);
553 struct chashbhead *head4;
554 struct chashbhead *head6;
563 SLIST_ENTRY(chashentry) next;
567 uint32_t a4; /* Host format */
568 struct in6_addr a6; /* Network format */
572 static __inline uint32_t
573 hash_ip(uint32_t addr, int hsize)
576 return (addr % (hsize - 1));
579 static __inline uint32_t
580 hash_ip6(struct in6_addr *addr6, int hsize)
584 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
585 addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
587 return (i % (hsize - 1));
591 static __inline uint16_t
592 hash_ip64(struct in6_addr *addr6, int hsize)
596 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
598 return (i % (hsize - 1));
602 static __inline uint32_t
603 hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
605 struct in6_addr mask6;
607 ipv6_writemask(&mask6, mask);
608 memcpy(addr6, key, sizeof(struct in6_addr));
609 APPLY_MASK(addr6, &mask6);
610 return (hash_ip6(addr6, hsize));
613 static __inline uint32_t
614 hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
618 paddr = (uint64_t *)addr6;
621 memcpy(addr6, key, mask);
622 return (hash_ip6(addr6, hsize));
626 ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
629 struct chashbhead *head;
630 struct chashentry *ent;
631 uint16_t hash, hsize;
634 if (keylen == sizeof(in_addr_t)) {
635 head = (struct chashbhead *)ti->state;
636 imask = ti->data >> 24;
637 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
639 a = ntohl(*((in_addr_t *)key));
641 hash = hash_ip(a, hsize);
642 SLIST_FOREACH(ent, &head[hash], next) {
643 if (ent->a.a4 == a) {
649 /* IPv6: worst scenario: non-round mask */
650 struct in6_addr addr6;
651 head = (struct chashbhead *)ti->xstate;
652 imask = (ti->data & 0xFF0000) >> 16;
653 hsize = 1 << (ti->data & 0xFF);
654 hash = hash_ip6_slow(&addr6, key, imask, hsize);
655 SLIST_FOREACH(ent, &head[hash], next) {
656 if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
667 ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
670 struct chashbhead *head;
671 struct chashentry *ent;
672 uint16_t hash, hsize;
675 if (keylen == sizeof(in_addr_t)) {
676 head = (struct chashbhead *)ti->state;
677 imask = ti->data >> 24;
678 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
680 a = ntohl(*((in_addr_t *)key));
682 hash = hash_ip(a, hsize);
683 SLIST_FOREACH(ent, &head[hash], next) {
684 if (ent->a.a4 == a) {
690 /* IPv6: aligned to 8bit mask */
691 struct in6_addr addr6;
692 uint64_t *paddr, *ptmp;
693 head = (struct chashbhead *)ti->xstate;
694 imask = (ti->data & 0xFF0000) >> 16;
695 hsize = 1 << (ti->data & 0xFF);
697 hash = hash_ip6_al(&addr6, key, imask, hsize);
698 paddr = (uint64_t *)&addr6;
699 SLIST_FOREACH(ent, &head[hash], next) {
700 ptmp = (uint64_t *)&ent->a.a6;
701 if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
712 ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
715 struct chashbhead *head;
716 struct chashentry *ent;
717 uint16_t hash, hsize;
720 if (keylen == sizeof(in_addr_t)) {
721 head = (struct chashbhead *)ti->state;
722 imask = ti->data >> 24;
723 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
725 a = ntohl(*((in_addr_t *)key));
727 hash = hash_ip(a, hsize);
728 SLIST_FOREACH(ent, &head[hash], next) {
729 if (ent->a.a4 == a) {
737 head = (struct chashbhead *)ti->xstate;
738 paddr = (uint64_t *)key;
739 hsize = 1 << (ti->data & 0xFF);
741 hash = hash_ip64((struct in6_addr *)key, hsize);
742 SLIST_FOREACH(ent, &head[hash], next) {
743 paddr = (uint64_t *)&ent->a.a6;
755 chash_parse_opts(struct chash_cfg *ccfg, char *data)
757 char *pdel, *pend, *s;
765 if ((pdel = strchr(data, ' ')) == NULL)
769 if (strncmp(pdel, "masks=", 6) != 0)
771 if ((s = strchr(pdel, ' ')) != NULL)
778 mask4 = strtol(pdel, &pend, 10);
784 mask6 = strtol(pdel, &pend, 10);
787 } else if (*pend != '\0')
790 if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
800 ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
803 struct chash_cfg *ccfg;
805 ccfg = (struct chash_cfg *)ta_state;
807 if (ccfg->mask4 != 32 || ccfg->mask6 != 128)
808 snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash",
809 ccfg->mask4, ccfg->mask6);
811 snprintf(buf, bufsize, "%s", "cidr:hash");
817 * We assume 'data' to be either NULL or the following format:
818 * 'cidr:hash [masks=/32[,/128]]'
821 ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
826 struct chash_cfg *ccfg;
828 ccfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
833 if ((error = chash_parse_opts(ccfg, data)) != 0) {
840 ccfg->size4 = 1 << v4;
841 ccfg->size6 = 1 << v6;
843 ccfg->head4 = malloc(sizeof(struct chashbhead) * ccfg->size4, M_IPFW,
845 ccfg->head6 = malloc(sizeof(struct chashbhead) * ccfg->size6, M_IPFW,
847 for (i = 0; i < ccfg->size4; i++)
848 SLIST_INIT(&ccfg->head4[i]);
849 for (i = 0; i < ccfg->size6; i++)
850 SLIST_INIT(&ccfg->head6[i]);
854 ti->state = ccfg->head4;
855 ti->xstate = ccfg->head6;
857 /* Store data depending on v6 mask length */
858 if (ccfg->mask6 == 64) {
859 ti->data = (32 - ccfg->mask4) << 24 | (128 - ccfg->mask6) << 16 |
861 ti->lookup = ta_lookup_chash_64;
862 } else if ((ccfg->mask6 % 8) == 0) {
863 ti->data = (32 - ccfg->mask4) << 24 |
864 ccfg->mask6 << 13 | v4 << 8 | v6;
865 ti->lookup = ta_lookup_chash_aligned;
868 ti->data = (32 - ccfg->mask4) << 24 |
869 ccfg->mask6 << 16 | v4 << 8 | v6;
870 ti->lookup = ta_lookup_chash_slow;
877 ta_destroy_chash(void *ta_state, struct table_info *ti)
879 struct chash_cfg *ccfg;
880 struct chashentry *ent, *ent_next;
883 ccfg = (struct chash_cfg *)ta_state;
885 for (i = 0; i < ccfg->size4; i++)
886 SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
887 free(ent, M_IPFW_TBL);
889 for (i = 0; i < ccfg->size6; i++)
890 SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
891 free(ent, M_IPFW_TBL);
893 free(ccfg->head4, M_IPFW);
894 free(ccfg->head6, M_IPFW);
898 ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
899 ipfw_obj_tentry *tent)
901 struct chash_cfg *ccfg;
902 struct chashentry *ent;
904 ccfg = (struct chash_cfg *)ta_state;
905 ent = (struct chashentry *)e;
907 if (ent->type == AF_INET) {
908 tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - ccfg->mask4));
909 tent->masklen = ccfg->mask4;
910 tent->subtype = AF_INET;
911 tent->value = ent->value;
914 memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
915 tent->masklen = ccfg->mask6;
916 tent->subtype = AF_INET6;
917 tent->value = ent->value;
925 ta_find_chash_tentry(void *ta_state, struct table_info *ti, void *key,
926 uint32_t keylen, ipfw_obj_tentry *tent)
929 struct radix_node_head *rnh;
933 if (keylen == sizeof(in_addr_t)) {
934 struct sockaddr_in sa;
935 KEY_LEN(sa) = KEY_LEN_INET;
936 sa.sin_addr.s_addr = *((in_addr_t *)key);
937 rnh = (struct radix_node_head *)ti->state;
938 e = rnh->rnh_matchaddr(&sa, rnh);
941 KEY_LEN(sa6) = KEY_LEN_INET6;
942 memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
943 rnh = (struct radix_node_head *)ti->xstate;
944 e = rnh->rnh_matchaddr(&sa6, rnh);
948 ta_dump_radix_tentry(ta_state, ti, e, tent);
956 ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
959 struct chash_cfg *ccfg;
960 struct chashentry *ent, *ent_next;
963 ccfg = (struct chash_cfg *)ta_state;
965 for (i = 0; i < ccfg->size4; i++)
966 SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
969 for (i = 0; i < ccfg->size6; i++)
970 SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
986 ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
989 struct ta_buf_chash *tb;
990 struct chashentry *ent;
992 struct in6_addr mask6;
994 tb = (struct ta_buf_chash *)ta_buf;
995 memset(tb, 0, sizeof(struct ta_buf_chash));
999 if (tei->subtype == AF_INET) {
1003 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1004 ent->value = tei->value;
1005 ent->type = AF_INET;
1007 /* Calculate mask */
1008 ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1012 } else if (tei->subtype == AF_INET6) {
1016 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1017 ent->value = tei->value;
1018 ent->type = AF_INET6;
1020 ipv6_writemask(&mask6, mlen);
1021 memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1022 APPLY_MASK(&ent->a.a6, &mask6);
1026 /* Unknown CIDR type */
1034 ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1035 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1037 struct chash_cfg *ccfg;
1038 struct chashbhead *head;
1039 struct chashentry *ent, *tmp;
1040 struct ta_buf_chash *tb;
1044 ccfg = (struct chash_cfg *)ta_state;
1045 tb = (struct ta_buf_chash *)ta_buf;
1046 ent = (struct chashentry *)tb->ent_ptr;
1050 if (tei->subtype == AF_INET) {
1051 if (tei->masklen != ccfg->mask4)
1054 hash = hash_ip(ent->a.a4, ccfg->size4);
1055 /* Check for existence */
1056 SLIST_FOREACH(tmp, &head[hash], next) {
1057 if (tmp->a.a4 == ent->a.a4) {
1063 if (tei->masklen != ccfg->mask6)
1066 if (tei->masklen == 64)
1067 hash = hash_ip64(&ent->a.a6, ccfg->size6);
1069 hash = hash_ip6(&ent->a.a6, ccfg->size6);
1070 /* Check for existence */
1071 SLIST_FOREACH(tmp, &head[hash], next) {
1072 if (memcmp(&tmp->a.a6, &ent->a.a6, 16)) {
1080 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1082 /* Record already exists. Update value if we're asked to */
1083 tmp->value = tei->value;
1084 /* Indicate that update has happened instead of addition */
1085 tei->flags |= TEI_FLAGS_UPDATED;
1088 SLIST_INSERT_HEAD(&head[hash], ent, next);
1097 ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1100 struct ta_buf_chash *tb;
1102 struct in6_addr mask6;
1104 tb = (struct ta_buf_chash *)ta_buf;
1105 memset(tb, 0, sizeof(struct ta_buf_chash));
1107 mlen = tei->masklen;
1109 if (tei->subtype == AF_INET) {
1115 /* Calculate masked address */
1116 tb->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1119 } else if (tei->subtype == AF_INET6) {
1123 tb->type = AF_INET6;
1125 ipv6_writemask(&mask6, mlen);
1126 memcpy(&tb->a.a6, tei->paddr, sizeof(struct in6_addr));
1127 APPLY_MASK(&tb->a.a6, &mask6);
1130 /* Unknown CIDR type */
1138 ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1139 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1141 struct chash_cfg *ccfg;
1142 struct chashbhead *head;
1143 struct chashentry *ent, *tmp_next;
1144 struct ta_buf_chash *tb;
1147 ccfg = (struct chash_cfg *)ta_state;
1148 tb = (struct ta_buf_chash *)ta_buf;
1150 if (tei->subtype == AF_INET) {
1151 if (tei->masklen != ccfg->mask4)
1154 hash = hash_ip(tb->a.a4, ccfg->size4);
1156 SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
1157 if (ent->a.a4 == tb->a.a4) {
1158 SLIST_REMOVE(&head[hash], ent, chashentry,next);
1164 if (tei->masklen != ccfg->mask6)
1167 if (tei->masklen == 64)
1168 hash = hash_ip64(&tb->a.a6, ccfg->size6);
1170 hash = hash_ip6(&tb->a.a6, ccfg->size6);
1172 SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
1173 if (memcmp(&ent->a.a6, &tb->a.a6, 16)) {
1174 SLIST_REMOVE(&head[hash], ent, chashentry,next);
1185 ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1188 struct ta_buf_chash *tb;
1190 tb = (struct ta_buf_chash *)ta_buf;
1192 if (tb->ent_ptr != NULL)
1193 free(tb->ent_ptr, M_IPFW_TBL);
1196 struct table_algo cidr_hash = {
1197 .name = "cidr:hash",
1198 .type = IPFW_TABLE_CIDR,
1199 .init = ta_init_chash,
1200 .destroy = ta_destroy_chash,
1201 .prepare_add = ta_prepare_add_chash,
1202 .prepare_del = ta_prepare_del_chash,
1203 .add = ta_add_chash,
1204 .del = ta_del_chash,
1205 .flush_entry = ta_flush_chash_entry,
1206 .foreach = ta_foreach_chash,
1207 .dump_tentry = ta_dump_chash_tentry,
1208 .find_tentry = ta_find_chash_tentry,
1209 .print_config = ta_print_chash_config,
1219 * - sorted array of "struct ifidx" pointed by ti->state.
1220 * Array is allocated with routing up to IFIDX_CHUNK. Only existing
1221 * interfaces are stored in array, however its allocated size is
1222 * sufficient to hold all table records if needed.
1223 * - current array size is stored in ti->data
1226 * - "struct iftable_cfg" is allocated to store table state (ta_state).
1227 * - All table records are stored inside namedobj instance.
1240 struct named_object no;
1242 struct iftable_cfg *icfg;
1247 struct iftable_cfg {
1248 struct namedobj_instance *ii;
1249 struct ip_fw_chain *ch;
1250 struct table_info *ti;
1252 size_t size; /* Number of items allocated in array */
1253 size_t count; /* Number of all items */
1254 size_t used; /* Number of items _active_ now */
1257 #define IFIDX_CHUNK 16
1259 int compare_ifidx(const void *k, const void *v);
1260 static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
1263 compare_ifidx(const void *k, const void *v)
1265 struct ifidx *ifidx;
1268 key = *((uint16_t *)k);
1269 ifidx = (struct ifidx *)v;
1271 if (key < ifidx->kidx)
1273 else if (key > ifidx->kidx)
1280 * Adds item @item with key @key into ascending-sorted array @base.
1281 * Assumes @base has enough additional storage.
1283 * Returns 1 on success, 0 on duplicate key.
1286 badd(const void *key, void *item, void *base, size_t nmemb,
1287 size_t size, int (*compar) (const void *, const void *))
1289 int min, max, mid, shift, res;
1293 memcpy(base, item, size);
1301 while (min <= max) {
1302 mid = (min + max) / 2;
1303 res = compar(key, (const void *)((caddr_t)base + mid * size));
1313 /* Item not found. */
1314 res = compar(key, (const void *)((caddr_t)base + mid * size));
1320 paddr = (caddr_t)base + shift * size;
1322 memmove(paddr + size, paddr, (nmemb - shift) * size);
1324 memcpy(paddr, item, size);
1330 * Deletes item with key @key from ascending-sorted array @base.
1332 * Returns 1 on success, 0 for non-existent key.
1335 bdel(const void *key, void *base, size_t nmemb, size_t size,
1336 int (*compar) (const void *, const void *))
1341 item = (caddr_t)bsearch(key, base, nmemb, size, compar);
1346 sz = (caddr_t)base + nmemb * size - item;
1349 memmove(item, item + size, sz);
1354 static struct ifidx *
1355 ifidx_find(struct table_info *ti, void *key)
1359 ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
1366 ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
1371 ifi = ifidx_find(ti, key);
1382 ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1385 struct iftable_cfg *icfg;
1387 icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
1389 icfg->ii = ipfw_objhash_create(16);
1390 icfg->main_ptr = malloc(sizeof(struct ifidx) * IFIDX_CHUNK, M_IPFW,
1392 icfg->size = IFIDX_CHUNK;
1396 ti->state = icfg->main_ptr;
1397 ti->lookup = ta_lookup_ifidx;
1403 * Handle tableinfo @ti pointer change (on table array resize).
1406 ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
1408 struct iftable_cfg *icfg;
1410 icfg = (struct iftable_cfg *)ta_state;
1415 destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
1418 struct ifentry *ife;
1419 struct ip_fw_chain *ch;
1421 ch = (struct ip_fw_chain *)arg;
1422 ife = (struct ifentry *)no;
1424 ipfw_iface_del_notify(ch, &ife->ic);
1425 free(ife, M_IPFW_TBL);
1430 * Destroys table @ti
1433 ta_destroy_ifidx(void *ta_state, struct table_info *ti)
1435 struct iftable_cfg *icfg;
1436 struct ip_fw_chain *ch;
1438 icfg = (struct iftable_cfg *)ta_state;
1441 if (icfg->main_ptr != NULL)
1442 free(icfg->main_ptr, M_IPFW);
1444 ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
1446 ipfw_objhash_destroy(icfg->ii);
1453 struct ifentry *ife;
1458 * Prepare state to add to the table:
1459 * allocate ifentry and reference needed interface.
1462 ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1465 struct ta_buf_ifidx *tb;
1467 struct ifentry *ife;
1469 tb = (struct ta_buf_ifidx *)ta_buf;
1470 memset(tb, 0, sizeof(struct ta_buf_ifidx));
1472 /* Check if string is terminated */
1473 ifname = (char *)tei->paddr;
1474 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1477 ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
1478 ife->value = tei->value;
1479 ife->ic.cb = if_notifier;
1480 ife->ic.cbdata = ife;
1482 if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0)
1485 /* Use ipfw_iface 'ifname' field as stable storage */
1486 ife->no.name = ife->ic.iface->ifname;
1494 ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1495 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1497 struct iftable_cfg *icfg;
1498 struct ifentry *ife, *tmp;
1499 struct ta_buf_ifidx *tb;
1500 struct ipfw_iface *iif;
1504 tb = (struct ta_buf_ifidx *)ta_buf;
1505 ifname = (char *)tei->paddr;
1506 icfg = (struct iftable_cfg *)ta_state;
1511 tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1514 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1517 /* We need to update value */
1518 iif = tmp->ic.iface;
1519 tmp->value = ife->value;
1521 if (iif->resolved != 0) {
1522 /* We need to update runtime value, too */
1523 ifi = ifidx_find(ti, &iif->ifindex);
1524 ifi->value = ife->value;
1527 /* Indicate that update has happened instead of addition */
1528 tei->flags |= TEI_FLAGS_UPDATED;
1533 /* Link to internal list */
1534 ipfw_objhash_add(icfg->ii, &ife->no);
1536 /* Link notifier (possible running its callback) */
1537 ipfw_iface_add_notify(icfg->ch, &ife->ic);
1540 if (icfg->count + 1 == icfg->size) {
1541 /* Notify core we need to grow */
1542 *pflags = icfg->size + IFIDX_CHUNK;
1552 * Prepare to delete key from table.
1553 * Do basic interface name checks.
1556 ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1559 struct ta_buf_ifidx *tb;
1562 tb = (struct ta_buf_ifidx *)ta_buf;
1563 memset(tb, 0, sizeof(struct ta_buf_ifidx));
1565 /* Check if string is terminated */
1566 ifname = (char *)tei->paddr;
1567 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1574 * Remove key from both configuration list and
1575 * runtime array. Removed interface notification.
1578 ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1579 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1581 struct iftable_cfg *icfg;
1582 struct ifentry *ife;
1583 struct ta_buf_ifidx *tb;
1588 tb = (struct ta_buf_ifidx *)ta_buf;
1589 ifname = (char *)tei->paddr;
1590 icfg = (struct iftable_cfg *)ta_state;
1593 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1598 if (ife->linked != 0) {
1599 /* We have to remove item from runtime */
1600 ifindex = ife->ic.iface->ifindex;
1602 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
1603 sizeof(struct ifidx), compare_ifidx);
1605 KASSERT(res == 1, ("index %d does not exist", ifindex));
1607 ti->data = icfg->used;
1611 /* Unlink from local list */
1612 ipfw_objhash_del(icfg->ii, &ife->no);
1613 /* Unlink notifier */
1614 ipfw_iface_del_notify(icfg->ch, &ife->ic);
1625 * Flush deleted entry.
1626 * Drops interface reference and frees entry.
1629 ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1632 struct ta_buf_ifidx *tb;
1634 tb = (struct ta_buf_ifidx *)ta_buf;
1636 if (tb->ife != NULL) {
1638 ipfw_iface_unref(ch, &tb->ife->ic);
1639 free(tb->ife, M_IPFW_TBL);
1645 * Handle interface announce/withdrawal for particular table.
1646 * Every real runtime array modification happens here.
1649 if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
1651 struct ifentry *ife;
1653 struct iftable_cfg *icfg;
1654 struct table_info *ti;
1657 ife = (struct ifentry *)cbdata;
1661 KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
1663 if (ife->linked == 0 && ifindex != 0) {
1664 /* Interface announce */
1667 ifi.value = ife->value;
1668 res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
1669 sizeof(struct ifidx), compare_ifidx);
1670 KASSERT(res == 1, ("index %d already exists", ifindex));
1672 ti->data = icfg->used;
1674 } else if (ife->linked != 0 && ifindex == 0) {
1675 /* Interface withdrawal */
1676 ifindex = ife->ic.iface->ifindex;
1678 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
1679 sizeof(struct ifidx), compare_ifidx);
1681 KASSERT(res == 1, ("index %d does not exist", ifindex));
1683 ti->data = icfg->used;
1690 * Table growing callbacks.
1699 * Allocate ned, larger runtime ifidx array.
1702 ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
1704 struct mod_ifidx *mi;
1706 mi = (struct mod_ifidx *)ta_buf;
1708 memset(mi, 0, sizeof(struct mod_ifidx));
1710 mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
1717 * Copy data from old runtime array to new one.
1720 ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
1723 struct mod_ifidx *mi;
1724 struct iftable_cfg *icfg;
1726 mi = (struct mod_ifidx *)ta_buf;
1727 icfg = (struct iftable_cfg *)ta_state;
1729 /* Check if we still need to grow array */
1730 if (icfg->size >= mi->size) {
1735 memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
1741 * Switch old & new arrays.
1744 ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
1747 struct mod_ifidx *mi;
1748 struct iftable_cfg *icfg;
1751 mi = (struct mod_ifidx *)ta_buf;
1752 icfg = (struct iftable_cfg *)ta_state;
1754 old_ptr = icfg->main_ptr;
1755 icfg->main_ptr = mi->main_ptr;
1756 icfg->size = mi->size;
1757 ti->state = icfg->main_ptr;
1759 mi->main_ptr = old_ptr;
1765 * Free unneded array.
1768 ta_flush_mod_ifidx(void *ta_buf)
1770 struct mod_ifidx *mi;
1772 mi = (struct mod_ifidx *)ta_buf;
1773 if (mi->main_ptr != NULL)
1774 free(mi->main_ptr, M_IPFW);
1778 ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
1779 ipfw_obj_tentry *tent)
1781 struct ifentry *ife;
1783 ife = (struct ifentry *)e;
1785 tent->masklen = 8 * IF_NAMESIZE;
1786 memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
1787 tent->value = ife->value;
1793 ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, void *key,
1794 uint32_t keylen, ipfw_obj_tentry *tent)
1796 struct iftable_cfg *icfg;
1797 struct ifentry *ife;
1800 icfg = (struct iftable_cfg *)ta_state;
1801 ifname = (char *)key;
1803 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1806 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1809 ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
1822 foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
1825 struct ifentry *ife;
1826 struct wa_ifidx *wa;
1828 ife = (struct ifentry *)no;
1829 wa = (struct wa_ifidx *)arg;
1831 wa->f(ife, wa->arg);
1835 ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
1838 struct iftable_cfg *icfg;
1841 icfg = (struct iftable_cfg *)ta_state;
1846 ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
1849 struct table_algo iface_idx = {
1850 .name = "iface:array",
1851 .type = IPFW_TABLE_INTERFACE,
1852 .init = ta_init_ifidx,
1853 .destroy = ta_destroy_ifidx,
1854 .prepare_add = ta_prepare_add_ifidx,
1855 .prepare_del = ta_prepare_del_ifidx,
1856 .add = ta_add_ifidx,
1857 .del = ta_del_ifidx,
1858 .flush_entry = ta_flush_ifidx_entry,
1859 .foreach = ta_foreach_ifidx,
1860 .dump_tentry = ta_dump_ifidx_tentry,
1861 .find_tentry = ta_find_ifidx_tentry,
1862 .prepare_mod = ta_prepare_mod_ifidx,
1863 .fill_mod = ta_fill_mod_ifidx,
1864 .modify = ta_modify_ifidx,
1865 .flush_mod = ta_flush_mod_ifidx,
1866 .change_ti = ta_change_ti_ifidx,
1870 ipfw_table_algo_init(struct ip_fw_chain *ch)
1875 * Register all algorithms presented here.
1877 sz = sizeof(struct table_algo);
1878 ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx);
1879 ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx);
1880 ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
1884 ipfw_table_algo_destroy(struct ip_fw_chain *ch)
1887 ipfw_del_table_algo(ch, cidr_radix.idx);
1888 ipfw_del_table_algo(ch, cidr_hash.idx);
1889 ipfw_del_table_algo(ch, iface_idx.idx);