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 .init = ta_init_radix,
520 .destroy = ta_destroy_radix,
521 .prepare_add = ta_prepare_add_cidr,
522 .prepare_del = ta_prepare_del_cidr,
525 .flush_entry = ta_flush_cidr_entry,
526 .foreach = ta_foreach_radix,
527 .dump_tentry = ta_dump_radix_tentry,
528 .find_tentry = ta_find_radix_tentry,
537 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
540 * inv.mask4: 32 - mask
542 * 1) _slow lookup: mask
543 * 2) _aligned: (128 - mask) / 8
549 SLIST_HEAD(chashbhead, chashentry);
552 struct chashbhead *head4;
553 struct chashbhead *head6;
562 SLIST_ENTRY(chashentry) next;
566 uint32_t a4; /* Host format */
567 struct in6_addr a6; /* Network format */
571 static __inline uint32_t
572 hash_ip(uint32_t addr, int hsize)
575 return (addr % (hsize - 1));
578 static __inline uint32_t
579 hash_ip6(struct in6_addr *addr6, int hsize)
583 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
584 addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
586 return (i % (hsize - 1));
590 static __inline uint16_t
591 hash_ip64(struct in6_addr *addr6, int hsize)
595 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
597 return (i % (hsize - 1));
601 static __inline uint32_t
602 hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
604 struct in6_addr mask6;
606 ipv6_writemask(&mask6, mask);
607 memcpy(addr6, key, sizeof(struct in6_addr));
608 APPLY_MASK(addr6, &mask6);
609 return (hash_ip6(addr6, hsize));
612 static __inline uint32_t
613 hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
617 paddr = (uint64_t *)addr6;
620 memcpy(addr6, key, mask);
621 return (hash_ip6(addr6, hsize));
625 ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
628 struct chashbhead *head;
629 struct chashentry *ent;
630 uint16_t hash, hsize;
633 if (keylen == sizeof(in_addr_t)) {
634 head = (struct chashbhead *)ti->state;
635 imask = ti->data >> 24;
636 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
638 a = ntohl(*((in_addr_t *)key));
640 hash = hash_ip(a, hsize);
641 SLIST_FOREACH(ent, &head[hash], next) {
642 if (ent->a.a4 == a) {
648 /* IPv6: worst scenario: non-round mask */
649 struct in6_addr addr6;
650 head = (struct chashbhead *)ti->xstate;
651 imask = (ti->data & 0xFF0000) >> 16;
652 hsize = 1 << (ti->data & 0xFF);
653 hash = hash_ip6_slow(&addr6, key, imask, hsize);
654 SLIST_FOREACH(ent, &head[hash], next) {
655 if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
666 ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
669 struct chashbhead *head;
670 struct chashentry *ent;
671 uint16_t hash, hsize;
674 if (keylen == sizeof(in_addr_t)) {
675 head = (struct chashbhead *)ti->state;
676 imask = ti->data >> 24;
677 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
679 a = ntohl(*((in_addr_t *)key));
681 hash = hash_ip(a, hsize);
682 SLIST_FOREACH(ent, &head[hash], next) {
683 if (ent->a.a4 == a) {
689 /* IPv6: aligned to 8bit mask */
690 struct in6_addr addr6;
691 uint64_t *paddr, *ptmp;
692 head = (struct chashbhead *)ti->xstate;
693 imask = (ti->data & 0xFF0000) >> 16;
694 hsize = 1 << (ti->data & 0xFF);
696 hash = hash_ip6_al(&addr6, key, imask, hsize);
697 paddr = (uint64_t *)&addr6;
698 SLIST_FOREACH(ent, &head[hash], next) {
699 ptmp = (uint64_t *)&ent->a.a6;
700 if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
711 ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
714 struct chashbhead *head;
715 struct chashentry *ent;
716 uint16_t hash, hsize;
719 if (keylen == sizeof(in_addr_t)) {
720 head = (struct chashbhead *)ti->state;
721 imask = ti->data >> 24;
722 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
724 a = ntohl(*((in_addr_t *)key));
726 hash = hash_ip(a, hsize);
727 SLIST_FOREACH(ent, &head[hash], next) {
728 if (ent->a.a4 == a) {
736 head = (struct chashbhead *)ti->xstate;
737 paddr = (uint64_t *)key;
738 hsize = 1 << (ti->data & 0xFF);
740 hash = hash_ip64((struct in6_addr *)key, hsize);
741 SLIST_FOREACH(ent, &head[hash], next) {
742 paddr = (uint64_t *)&ent->a.a6;
754 chash_parse_opts(struct chash_cfg *ccfg, char *data)
756 char *pdel, *pend, *s;
764 if ((pdel = strchr(data, ' ')) == NULL)
768 if (strncmp(pdel, "masks=", 6) != 0)
770 if ((s = strchr(pdel, ' ')) != NULL)
777 mask4 = strtol(pdel, &pend, 10);
783 mask6 = strtol(pdel, &pend, 10);
786 } else if (*pend != '\0')
789 if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
799 ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
802 struct chash_cfg *ccfg;
804 ccfg = (struct chash_cfg *)ta_state;
806 if (ccfg->mask4 != 32 || ccfg->mask6 != 128)
807 snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash",
808 ccfg->mask4, ccfg->mask6);
810 snprintf(buf, bufsize, "%s", "cidr:hash");
816 * We assume 'data' to be either NULL or the following format:
817 * 'cidr:hash [masks=/32[,/128]]'
820 ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
825 struct chash_cfg *ccfg;
827 ccfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
832 if ((error = chash_parse_opts(ccfg, data)) != 0) {
839 ccfg->size4 = 1 << v4;
840 ccfg->size6 = 1 << v6;
842 ccfg->head4 = malloc(sizeof(struct chashbhead) * ccfg->size4, M_IPFW,
844 ccfg->head6 = malloc(sizeof(struct chashbhead) * ccfg->size6, M_IPFW,
846 for (i = 0; i < ccfg->size4; i++)
847 SLIST_INIT(&ccfg->head4[i]);
848 for (i = 0; i < ccfg->size6; i++)
849 SLIST_INIT(&ccfg->head6[i]);
853 ti->state = ccfg->head4;
854 ti->xstate = ccfg->head6;
856 /* Store data depending on v6 mask length */
857 if (ccfg->mask6 == 64) {
858 ti->data = (32 - ccfg->mask4) << 24 | (128 - ccfg->mask6) << 16 |
860 ti->lookup = ta_lookup_chash_64;
861 } else if ((ccfg->mask6 % 8) == 0) {
862 ti->data = (32 - ccfg->mask4) << 24 |
863 ccfg->mask6 << 13 | v4 << 8 | v6;
864 ti->lookup = ta_lookup_chash_aligned;
867 ti->data = (32 - ccfg->mask4) << 24 |
868 ccfg->mask6 << 16 | v4 << 8 | v6;
869 ti->lookup = ta_lookup_chash_slow;
876 ta_destroy_chash(void *ta_state, struct table_info *ti)
878 struct chash_cfg *ccfg;
879 struct chashentry *ent, *ent_next;
882 ccfg = (struct chash_cfg *)ta_state;
884 for (i = 0; i < ccfg->size4; i++)
885 SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
886 free(ent, M_IPFW_TBL);
888 for (i = 0; i < ccfg->size6; i++)
889 SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
890 free(ent, M_IPFW_TBL);
892 free(ccfg->head4, M_IPFW);
893 free(ccfg->head6, M_IPFW);
897 ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
898 ipfw_obj_tentry *tent)
900 struct chash_cfg *ccfg;
901 struct chashentry *ent;
903 ccfg = (struct chash_cfg *)ta_state;
904 ent = (struct chashentry *)e;
906 if (ent->type == AF_INET) {
907 tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - ccfg->mask4));
908 tent->masklen = ccfg->mask4;
909 tent->subtype = AF_INET;
910 tent->value = ent->value;
913 memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
914 tent->masklen = ccfg->mask6;
915 tent->subtype = AF_INET6;
916 tent->value = ent->value;
924 ta_find_chash_tentry(void *ta_state, struct table_info *ti, void *key,
925 uint32_t keylen, ipfw_obj_tentry *tent)
928 struct radix_node_head *rnh;
932 if (keylen == sizeof(in_addr_t)) {
933 struct sockaddr_in sa;
934 KEY_LEN(sa) = KEY_LEN_INET;
935 sa.sin_addr.s_addr = *((in_addr_t *)key);
936 rnh = (struct radix_node_head *)ti->state;
937 e = rnh->rnh_matchaddr(&sa, rnh);
940 KEY_LEN(sa6) = KEY_LEN_INET6;
941 memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
942 rnh = (struct radix_node_head *)ti->xstate;
943 e = rnh->rnh_matchaddr(&sa6, rnh);
947 ta_dump_radix_tentry(ta_state, ti, e, tent);
955 ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
958 struct chash_cfg *ccfg;
959 struct chashentry *ent, *ent_next;
962 ccfg = (struct chash_cfg *)ta_state;
964 for (i = 0; i < ccfg->size4; i++)
965 SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
968 for (i = 0; i < ccfg->size6; i++)
969 SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
985 ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
988 struct ta_buf_chash *tb;
989 struct chashentry *ent;
991 struct in6_addr mask6;
993 tb = (struct ta_buf_chash *)ta_buf;
994 memset(tb, 0, sizeof(struct ta_buf_chash));
998 if (tei->subtype == AF_INET) {
1002 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1003 ent->value = tei->value;
1004 ent->type = AF_INET;
1006 /* Calculate mask */
1007 ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1011 } else if (tei->subtype == AF_INET6) {
1015 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1016 ent->value = tei->value;
1017 ent->type = AF_INET6;
1019 ipv6_writemask(&mask6, mlen);
1020 memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1021 APPLY_MASK(&ent->a.a6, &mask6);
1025 /* Unknown CIDR type */
1033 ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1034 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1036 struct chash_cfg *ccfg;
1037 struct chashbhead *head;
1038 struct chashentry *ent, *tmp;
1039 struct ta_buf_chash *tb;
1043 ccfg = (struct chash_cfg *)ta_state;
1044 tb = (struct ta_buf_chash *)ta_buf;
1045 ent = (struct chashentry *)tb->ent_ptr;
1049 if (tei->subtype == AF_INET) {
1050 if (tei->masklen != ccfg->mask4)
1053 hash = hash_ip(ent->a.a4, ccfg->size4);
1054 /* Check for existence */
1055 SLIST_FOREACH(tmp, &head[hash], next) {
1056 if (tmp->a.a4 == ent->a.a4) {
1062 if (tei->masklen != ccfg->mask6)
1065 if (tei->masklen == 64)
1066 hash = hash_ip64(&ent->a.a6, ccfg->size6);
1068 hash = hash_ip6(&ent->a.a6, ccfg->size6);
1069 /* Check for existence */
1070 SLIST_FOREACH(tmp, &head[hash], next) {
1071 if (memcmp(&tmp->a.a6, &ent->a.a6, 16)) {
1079 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1081 /* Record already exists. Update value if we're asked to */
1082 tmp->value = tei->value;
1083 /* Indicate that update has happened instead of addition */
1084 tei->flags |= TEI_FLAGS_UPDATED;
1087 SLIST_INSERT_HEAD(&head[hash], ent, next);
1096 ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1099 struct ta_buf_chash *tb;
1101 struct in6_addr mask6;
1103 tb = (struct ta_buf_chash *)ta_buf;
1104 memset(tb, 0, sizeof(struct ta_buf_chash));
1106 mlen = tei->masklen;
1108 if (tei->subtype == AF_INET) {
1114 /* Calculate masked address */
1115 tb->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1118 } else if (tei->subtype == AF_INET6) {
1122 tb->type = AF_INET6;
1124 ipv6_writemask(&mask6, mlen);
1125 memcpy(&tb->a.a6, tei->paddr, sizeof(struct in6_addr));
1126 APPLY_MASK(&tb->a.a6, &mask6);
1129 /* Unknown CIDR type */
1137 ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1138 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1140 struct chash_cfg *ccfg;
1141 struct chashbhead *head;
1142 struct chashentry *ent, *tmp_next;
1143 struct ta_buf_chash *tb;
1146 ccfg = (struct chash_cfg *)ta_state;
1147 tb = (struct ta_buf_chash *)ta_buf;
1149 if (tei->subtype == AF_INET) {
1150 if (tei->masklen != ccfg->mask4)
1153 hash = hash_ip(tb->a.a4, ccfg->size4);
1155 SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
1156 if (ent->a.a4 == tb->a.a4) {
1157 SLIST_REMOVE(&head[hash], ent, chashentry,next);
1163 if (tei->masklen != ccfg->mask6)
1166 if (tei->masklen == 64)
1167 hash = hash_ip64(&tb->a.a6, ccfg->size6);
1169 hash = hash_ip6(&tb->a.a6, ccfg->size6);
1171 SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
1172 if (memcmp(&ent->a.a6, &tb->a.a6, 16)) {
1173 SLIST_REMOVE(&head[hash], ent, chashentry,next);
1184 ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1187 struct ta_buf_chash *tb;
1189 tb = (struct ta_buf_chash *)ta_buf;
1191 if (tb->ent_ptr != NULL)
1192 free(tb->ent_ptr, M_IPFW_TBL);
1195 struct table_algo cidr_hash = {
1196 .name = "cidr:hash",
1197 .init = ta_init_chash,
1198 .destroy = ta_destroy_chash,
1199 .prepare_add = ta_prepare_add_chash,
1200 .prepare_del = ta_prepare_del_chash,
1201 .add = ta_add_chash,
1202 .del = ta_del_chash,
1203 .flush_entry = ta_flush_chash_entry,
1204 .foreach = ta_foreach_chash,
1205 .dump_tentry = ta_dump_chash_tentry,
1206 .find_tentry = ta_find_chash_tentry,
1207 .print_config = ta_print_chash_config,
1217 * - sorted array of "struct ifidx" pointed by ti->state.
1218 * Array is allocated with routing up to IFIDX_CHUNK. Only existing
1219 * interfaces are stored in array, however its allocated size is
1220 * sufficient to hold all table records if needed.
1221 * - current array size is stored in ti->data
1224 * - "struct iftable_cfg" is allocated to store table state (ta_state).
1225 * - All table records are stored inside namedobj instance.
1238 struct named_object no;
1240 struct iftable_cfg *icfg;
1245 struct iftable_cfg {
1246 struct namedobj_instance *ii;
1247 struct ip_fw_chain *ch;
1248 struct table_info *ti;
1250 size_t size; /* Number of items allocated in array */
1251 size_t count; /* Number of all items */
1252 size_t used; /* Number of items _active_ now */
1255 #define IFIDX_CHUNK 16
1257 int compare_ifidx(const void *k, const void *v);
1258 static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
1261 compare_ifidx(const void *k, const void *v)
1263 struct ifidx *ifidx;
1266 key = *((uint16_t *)k);
1267 ifidx = (struct ifidx *)v;
1269 if (key < ifidx->kidx)
1271 else if (key > ifidx->kidx)
1278 * Adds item @item with key @key into ascending-sorted array @base.
1279 * Assumes @base has enough additional storage.
1281 * Returns 1 on success, 0 on duplicate key.
1284 badd(const void *key, void *item, void *base, size_t nmemb,
1285 size_t size, int (*compar) (const void *, const void *))
1287 int min, max, mid, shift, res;
1291 memcpy(base, item, size);
1299 while (min <= max) {
1300 mid = (min + max) / 2;
1301 res = compar(key, (const void *)((caddr_t)base + mid * size));
1311 /* Item not found. */
1312 res = compar(key, (const void *)((caddr_t)base + mid * size));
1318 paddr = (caddr_t)base + shift * size;
1320 memmove(paddr + size, paddr, (nmemb - shift) * size);
1322 memcpy(paddr, item, size);
1328 * Deletes item with key @key from ascending-sorted array @base.
1330 * Returns 1 on success, 0 for non-existent key.
1333 bdel(const void *key, void *base, size_t nmemb, size_t size,
1334 int (*compar) (const void *, const void *))
1339 item = (caddr_t)bsearch(key, base, nmemb, size, compar);
1344 sz = (caddr_t)base + nmemb * size - item;
1347 memmove(item, item + size, sz);
1352 static struct ifidx *
1353 ifidx_find(struct table_info *ti, void *key)
1357 ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
1364 ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
1369 ifi = ifidx_find(ti, key);
1380 ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1383 struct iftable_cfg *icfg;
1385 icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
1387 icfg->ii = ipfw_objhash_create(16);
1388 icfg->main_ptr = malloc(sizeof(struct ifidx) * IFIDX_CHUNK, M_IPFW,
1390 icfg->size = IFIDX_CHUNK;
1394 ti->state = icfg->main_ptr;
1395 ti->lookup = ta_lookup_ifidx;
1401 * Handle tableinfo @ti pointer change (on table array resize).
1404 ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
1406 struct iftable_cfg *icfg;
1408 icfg = (struct iftable_cfg *)ta_state;
1413 destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
1416 struct ifentry *ife;
1417 struct ip_fw_chain *ch;
1419 ch = (struct ip_fw_chain *)arg;
1420 ife = (struct ifentry *)no;
1422 ipfw_iface_del_notify(ch, &ife->ic);
1423 free(ife, M_IPFW_TBL);
1428 * Destroys table @ti
1431 ta_destroy_ifidx(void *ta_state, struct table_info *ti)
1433 struct iftable_cfg *icfg;
1434 struct ip_fw_chain *ch;
1436 icfg = (struct iftable_cfg *)ta_state;
1439 if (icfg->main_ptr != NULL)
1440 free(icfg->main_ptr, M_IPFW);
1442 ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
1444 ipfw_objhash_destroy(icfg->ii);
1451 struct ifentry *ife;
1456 * Prepare state to add to the table:
1457 * allocate ifentry and reference needed interface.
1460 ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1463 struct ta_buf_ifidx *tb;
1465 struct ifentry *ife;
1467 tb = (struct ta_buf_ifidx *)ta_buf;
1468 memset(tb, 0, sizeof(struct ta_buf_ifidx));
1470 /* Check if string is terminated */
1471 ifname = (char *)tei->paddr;
1472 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1475 ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
1476 ife->value = tei->value;
1477 ife->ic.cb = if_notifier;
1478 ife->ic.cbdata = ife;
1480 if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0)
1483 /* Use ipfw_iface 'ifname' field as stable storage */
1484 ife->no.name = ife->ic.iface->ifname;
1492 ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1493 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1495 struct iftable_cfg *icfg;
1496 struct ifentry *ife, *tmp;
1497 struct ta_buf_ifidx *tb;
1498 struct ipfw_iface *iif;
1502 tb = (struct ta_buf_ifidx *)ta_buf;
1503 ifname = (char *)tei->paddr;
1504 icfg = (struct iftable_cfg *)ta_state;
1509 tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1512 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1515 /* We need to update value */
1516 iif = tmp->ic.iface;
1517 tmp->value = ife->value;
1519 if (iif->resolved != 0) {
1520 /* We need to update runtime value, too */
1521 ifi = ifidx_find(ti, &iif->ifindex);
1522 ifi->value = ife->value;
1525 /* Indicate that update has happened instead of addition */
1526 tei->flags |= TEI_FLAGS_UPDATED;
1531 /* Link to internal list */
1532 ipfw_objhash_add(icfg->ii, &ife->no);
1534 /* Link notifier (possible running its callback) */
1535 ipfw_iface_add_notify(icfg->ch, &ife->ic);
1538 if (icfg->count + 1 == icfg->size) {
1539 /* Notify core we need to grow */
1540 *pflags = icfg->size + IFIDX_CHUNK;
1550 * Prepare to delete key from table.
1551 * Do basic interface name checks.
1554 ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1557 struct ta_buf_ifidx *tb;
1560 tb = (struct ta_buf_ifidx *)ta_buf;
1561 memset(tb, 0, sizeof(struct ta_buf_ifidx));
1563 /* Check if string is terminated */
1564 ifname = (char *)tei->paddr;
1565 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1572 * Remove key from both configuration list and
1573 * runtime array. Removed interface notification.
1576 ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1577 void *ta_buf, uint64_t *pflags, uint32_t *pnum)
1579 struct iftable_cfg *icfg;
1580 struct ifentry *ife;
1581 struct ta_buf_ifidx *tb;
1586 tb = (struct ta_buf_ifidx *)ta_buf;
1587 ifname = (char *)tei->paddr;
1588 icfg = (struct iftable_cfg *)ta_state;
1591 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1596 if (ife->linked != 0) {
1597 /* We have to remove item from runtime */
1598 ifindex = ife->ic.iface->ifindex;
1600 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
1601 sizeof(struct ifidx), compare_ifidx);
1603 KASSERT(res == 1, ("index %d does not exist", ifindex));
1605 ti->data = icfg->used;
1609 /* Unlink from local list */
1610 ipfw_objhash_del(icfg->ii, &ife->no);
1611 /* Unlink notifier */
1612 ipfw_iface_del_notify(icfg->ch, &ife->ic);
1623 * Flush deleted entry.
1624 * Drops interface reference and frees entry.
1627 ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1630 struct ta_buf_ifidx *tb;
1632 tb = (struct ta_buf_ifidx *)ta_buf;
1634 if (tb->ife != NULL) {
1636 ipfw_iface_unref(ch, &tb->ife->ic);
1637 free(tb->ife, M_IPFW_TBL);
1643 * Handle interface announce/withdrawal for particular table.
1644 * Every real runtime array modification happens here.
1647 if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
1649 struct ifentry *ife;
1651 struct iftable_cfg *icfg;
1652 struct table_info *ti;
1655 ife = (struct ifentry *)cbdata;
1659 KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
1661 if (ife->linked == 0 && ifindex != 0) {
1662 /* Interface announce */
1665 ifi.value = ife->value;
1666 res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
1667 sizeof(struct ifidx), compare_ifidx);
1668 KASSERT(res == 1, ("index %d already exists", ifindex));
1670 ti->data = icfg->used;
1672 } else if (ife->linked != 0 && ifindex == 0) {
1673 /* Interface withdrawal */
1674 ifindex = ife->ic.iface->ifindex;
1676 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
1677 sizeof(struct ifidx), compare_ifidx);
1679 KASSERT(res == 1, ("index %d does not exist", ifindex));
1681 ti->data = icfg->used;
1688 * Table growing callbacks.
1697 * Allocate ned, larger runtime ifidx array.
1700 ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
1702 struct mod_ifidx *mi;
1704 mi = (struct mod_ifidx *)ta_buf;
1706 memset(mi, 0, sizeof(struct mod_ifidx));
1708 mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
1715 * Copy data from old runtime array to new one.
1718 ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
1721 struct mod_ifidx *mi;
1722 struct iftable_cfg *icfg;
1724 mi = (struct mod_ifidx *)ta_buf;
1725 icfg = (struct iftable_cfg *)ta_state;
1727 /* Check if we still need to grow array */
1728 if (icfg->size >= mi->size) {
1733 memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
1739 * Switch old & new arrays.
1742 ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
1745 struct mod_ifidx *mi;
1746 struct iftable_cfg *icfg;
1749 mi = (struct mod_ifidx *)ta_buf;
1750 icfg = (struct iftable_cfg *)ta_state;
1752 old_ptr = icfg->main_ptr;
1753 icfg->main_ptr = mi->main_ptr;
1754 icfg->size = mi->size;
1755 ti->state = icfg->main_ptr;
1757 mi->main_ptr = old_ptr;
1763 * Free unneded array.
1766 ta_flush_mod_ifidx(void *ta_buf)
1768 struct mod_ifidx *mi;
1770 mi = (struct mod_ifidx *)ta_buf;
1771 if (mi->main_ptr != NULL)
1772 free(mi->main_ptr, M_IPFW);
1776 ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
1777 ipfw_obj_tentry *tent)
1779 struct ifentry *ife;
1781 ife = (struct ifentry *)e;
1783 tent->masklen = 8 * IF_NAMESIZE;
1784 memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
1785 tent->value = ife->value;
1791 ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, void *key,
1792 uint32_t keylen, ipfw_obj_tentry *tent)
1794 struct iftable_cfg *icfg;
1795 struct ifentry *ife;
1798 icfg = (struct iftable_cfg *)ta_state;
1799 ifname = (char *)key;
1801 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
1804 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
1807 ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
1820 foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
1823 struct ifentry *ife;
1824 struct wa_ifidx *wa;
1826 ife = (struct ifentry *)no;
1827 wa = (struct wa_ifidx *)arg;
1829 wa->f(ife, wa->arg);
1833 ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
1836 struct iftable_cfg *icfg;
1839 icfg = (struct iftable_cfg *)ta_state;
1844 ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
1847 struct table_algo iface_idx = {
1848 .name = "iface:array",
1849 .init = ta_init_ifidx,
1850 .destroy = ta_destroy_ifidx,
1851 .prepare_add = ta_prepare_add_ifidx,
1852 .prepare_del = ta_prepare_del_ifidx,
1853 .add = ta_add_ifidx,
1854 .del = ta_del_ifidx,
1855 .flush_entry = ta_flush_ifidx_entry,
1856 .foreach = ta_foreach_ifidx,
1857 .dump_tentry = ta_dump_ifidx_tentry,
1858 .find_tentry = ta_find_ifidx_tentry,
1859 .prepare_mod = ta_prepare_mod_ifidx,
1860 .fill_mod = ta_fill_mod_ifidx,
1861 .modify = ta_modify_ifidx,
1862 .flush_mod = ta_flush_mod_ifidx,
1863 .change_ti = ta_change_ti_ifidx,
1867 ipfw_table_algo_init(struct ip_fw_chain *ch)
1872 * Register all algorithms presented here.
1874 sz = sizeof(struct table_algo);
1875 ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx);
1876 ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx);
1877 ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
1881 ipfw_table_algo_destroy(struct ip_fw_chain *ch)
1884 ipfw_del_table_algo(ch, cidr_radix.idx);
1885 ipfw_del_table_algo(ch, cidr_hash.idx);
1886 ipfw_del_table_algo(ch, iface_idx.idx);