2 * Copyright (C) 2012 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
8 #include <sys/socket.h>
10 #include <netinet/in.h>
13 #include <sys/systm.h>
20 #include "netinet/ip_compat.h"
21 #include "netinet/ip_fil.h"
23 # include <arpa/inet.h>
27 #include "netinet/radix_ipf.h"
29 #define ADF_OFF offsetof(addrfamily_t, adf_addr)
30 #define ADF_OFF_BITS (ADF_OFF << 3)
32 static ipf_rdx_node_t *ipf_rx_insert(ipf_rdx_head_t *,
33 ipf_rdx_node_t nodes[2], int *);
34 static void ipf_rx_attach_mask(ipf_rdx_node_t *, ipf_rdx_mask_t *);
35 static int count_mask_bits(addrfamily_t *, u_32_t **);
36 static void buildnodes(addrfamily_t *, addrfamily_t *,
38 static ipf_rdx_node_t *ipf_rx_find_addr(ipf_rdx_node_t *, u_32_t *);
39 static ipf_rdx_node_t *ipf_rx_lookup(ipf_rdx_head_t *, addrfamily_t *,
41 static ipf_rdx_node_t *ipf_rx_match(ipf_rdx_head_t *, addrfamily_t *);
46 * The code in this file has been written to target using the addrfamily_t
47 * data structure to house the address information and no other. Thus there
48 * are certain aspects of thise code (such as offsets to the address itself)
49 * that are hard coded here whilst they might be more variable elsewhere.
50 * Similarly, this code enforces no maximum key length as that's implied by
51 * all keys needing to be stored in addrfamily_t.
54 /* ------------------------------------------------------------------------ */
55 /* Function: count_mask_bits */
56 /* Returns: number of consecutive bits starting at "mask". */
57 /* Parameters: mask(I) - netmask */
58 /* lastp(I) - pointer to last word with a bit set */
60 /* Count the number of bits set in the address section of addrfamily_t and */
61 /* return both that number and a pointer to the last word with a bit set if */
62 /* lastp is not NULL. The bit count is performed using network byte order */
63 /* as the guide for which bit is the most significant bit. */
64 /* ------------------------------------------------------------------------ */
66 count_mask_bits(addrfamily_t *mask, u_32_t **lastp)
68 u_32_t *mp = (u_32_t *)&mask->adf_addr;
73 mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
74 for (; mlen > 0; mlen -= 4, mp++) {
75 if ((m = ntohl(*mp)) == 0)
79 for (; m & 0x80000000; m <<= 1)
87 /* ------------------------------------------------------------------------ */
88 /* Function: buildnodes */
90 /* Parameters: addr(I) - network address for this radix node */
91 /* mask(I) - netmask associated with the above address */
92 /* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
93 /* associated with addr and mask. */
95 /* Initialise the fields in a pair of radix tree nodes according to the */
96 /* data supplied in the parameters "addr" and "mask". It is expected that */
97 /* "mask" will contain a consecutive string of bits set. Masks with gaps in */
98 /* the middle are not handled by this implementation. */
99 /* ------------------------------------------------------------------------ */
101 buildnodes(addrfamily_t *addr, addrfamily_t *mask, ipf_rdx_node_t nodes[2])
109 maskbits = count_mask_bits(mask, &last);
114 masklen = last - (u_32_t *)mask;
118 bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
119 nodes[0].maskbitcount = maskbits;
120 nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
121 nodes[0].addrkey = (u_32_t *)addr;
122 nodes[0].maskkey = (u_32_t *)mask;
123 nodes[0].addroff = nodes[0].addrkey + masklen;
124 nodes[0].maskoff = nodes[0].maskkey + masklen;
125 nodes[0].parent = &nodes[1];
126 nodes[0].offset = masklen;
127 nodes[0].lastmask = lastmask;
128 nodes[1].offset = masklen;
129 nodes[1].left = &nodes[0];
130 nodes[1].maskbitcount = maskbits;
132 (void) strcpy(nodes[0].name, "_BUILD.0");
133 (void) strcpy(nodes[1].name, "_BUILD.1");
138 /* ------------------------------------------------------------------------ */
139 /* Function: ipf_rx_find_addr */
140 /* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */
141 /* Parameters: tree(I) - pointer to first right node in tree to search */
142 /* addr(I) - pointer to address to match */
144 /* Walk the radix tree given by "tree", looking for a leaf node that is a */
145 /* match for the address given by "addr". */
146 /* ------------------------------------------------------------------------ */
147 static ipf_rdx_node_t *
148 ipf_rx_find_addr(ipf_rdx_node_t *tree, u_32_t *addr)
152 for (cur = tree; cur->index >= 0;) {
153 if (cur->bitmask & addr[cur->offset]) {
164 /* ------------------------------------------------------------------------ */
165 /* Function: ipf_rx_match */
166 /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
167 /* added to the tree. */
168 /* Paramters: head(I) - pointer to tree head to search */
169 /* addr(I) - pointer to address to find */
171 /* Search the radix tree for the best match to the address pointed to by */
172 /* "addr" and return a pointer to that node. This search will not match the */
173 /* address information stored in either of the root leaves as neither of */
174 /* them are considered to be part of the tree of data being stored. */
175 /* ------------------------------------------------------------------------ */
176 static ipf_rdx_node_t *
177 ipf_rx_match(ipf_rdx_head_t *head, addrfamily_t *addr)
179 ipf_rdx_mask_t *masknode;
180 ipf_rdx_node_t *prev;
181 ipf_rdx_node_t *node;
191 end = (u_32_t *)((u_char *)addr + len);
192 node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
195 * Search the dupkey list for a potential match.
197 for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
198 i = cur[0].addroff - cur[0].addrkey;
199 data = cur[0].addrkey + i;
200 mask = cur[0].maskkey + i;
201 key = (u_32_t *)addr + i;
202 for (; key < end; data++, key++, mask++)
203 if ((*key & *mask) != *data)
205 if ((end == key) && (cur->root == 0))
206 return (cur); /* Equal keys */
209 key = (u_32_t *)addr;
211 for (node = prev; node->root == 0; node = node->parent) {
213 * We know that the node hasn't matched so therefore only
214 * the entries in the mask list are searched, not the top
215 * node nor the dupkey list.
217 masknode = node->masks;
218 for (; masknode != NULL; masknode = masknode->next) {
219 if (masknode->maskbitcount > node->maskbitcount)
221 cur = masknode->node;
222 for (i = ADF_OFF >> 2; i <= node->offset; i++) {
223 if ((key[i] & masknode->mask[i]) ==
234 /* ------------------------------------------------------------------------ */
235 /* Function: ipf_rx_lookup */
236 /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
237 /* added to the tree. */
238 /* Paramters: head(I) - pointer to tree head to search */
239 /* addr(I) - address part of the key to match */
240 /* mask(I) - netmask part of the key to match */
242 /* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */
243 /* is to see if a given key is in the tree, not to see if a route exists. */
244 /* ------------------------------------------------------------------------ */
246 ipf_rx_lookup(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask)
248 ipf_rdx_node_t *found;
249 ipf_rdx_node_t *node;
253 found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
254 if (found->root == 1)
258 * It is possible to find a matching address in the tree but for the
259 * netmask to not match. If the netmask does not match and there is
260 * no list of alternatives present at dupkey, return a failure.
262 count = count_mask_bits(mask, NULL);
263 if (count != found->maskbitcount && found->dupkey == NULL)
266 akey = (u_32_t *)addr;
267 if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
271 if (found->dupkey != NULL) {
273 while (node != NULL && node->maskbitcount != count)
283 /* ------------------------------------------------------------------------ */
284 /* Function: ipf_rx_attach_mask */
286 /* Parameters: node(I) - pointer to a radix tree node */
287 /* mask(I) - pointer to mask structure to add */
289 /* Add the netmask to the given node in an ordering where the most specific */
290 /* netmask is at the top of the list. */
291 /* ------------------------------------------------------------------------ */
293 ipf_rx_attach_mask(ipf_rdx_node_t *node, ipf_rdx_mask_t *mask)
298 for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
299 if (m->maskbitcount < mask->maskbitcount)
306 /* ------------------------------------------------------------------------ */
307 /* Function: ipf_rx_insert */
308 /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
309 /* added to the tree. */
310 /* Paramters: head(I) - pointer to tree head to add nodes to */
311 /* nodes(I) - pointer to radix nodes to be added */
312 /* dup(O) - set to 1 if node is a duplicate, else 0. */
314 /* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
315 /* If there is already a matching key in the table, "dup" will be set to 1 */
316 /* and the existing node pointer returned if there is a complete key match. */
317 /* A complete key match is a matching of all key data that is presented by */
318 /* by the netmask. */
319 /* ------------------------------------------------------------------------ */
320 static ipf_rdx_node_t *
321 ipf_rx_insert(ipf_rdx_head_t *head, ipf_rdx_node_t *nodes, int *dup)
323 ipf_rdx_mask_t **pmask;
324 ipf_rdx_node_t *node;
325 ipf_rdx_node_t *prev;
326 ipf_rdx_mask_t *mask;
340 addr = nodes[0].addrkey;
342 node = ipf_rx_find_addr(head->root, addr);
343 len = ((addrfamily_t *)addr)->adf_len;
344 key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
345 data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
346 end = (u_32_t *)((u_char *)addr + len);
347 for (nlen = 0; key < end; data++, key++, nlen += 32)
352 return (node); /* Equal keys */
356 bits = (ntohl(*data) ^ ntohl(*key));
357 for (; bits != 0; nlen++) {
358 if ((bits & 0x80000000) != 0)
362 nlen += ADF_OFF_BITS;
363 nodes[1].index = nlen;
364 nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
365 nodes[0].offset = nlen / 32;
366 nodes[1].offset = nlen / 32;
369 * Walk through the tree and look for the correct place to attach
370 * this node. ipf_rx_fin_addr is not used here because the place
371 * to attach this node may be an internal node (same key, different
372 * netmask.) Additionally, the depth of the search is forcibly limited
373 * here to not exceed the netmask, so that a short netmask will be
374 * added higher up the tree even if there are lower branches.
377 key = nodes[0].addrkey;
380 if (key[cur->offset] & cur->bitmask) {
385 } while (nlen > (unsigned)cur->index);
387 if ((key[prev->offset] & prev->bitmask) == 0) {
388 prev->left = &nodes[1];
390 prev->right = &nodes[1];
392 cur->parent = &nodes[1];
393 nodes[1].parent = prev;
394 if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) {
395 nodes[1].right = cur;
397 nodes[1].right = &nodes[0];
401 nodeoff = nodes[0].offset;
402 nodekey = nodes[0].addrkey[nodeoff];
403 nodemask = nodes[0].lastmask;
404 nodebits = nodes[0].maskbitcount;
407 * Find the node up the tree with the largest pattern that still
408 * matches the node being inserted to see if this mask can be
411 for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
412 if (cur->maskbitcount <= nodebits)
414 if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
419 KMALLOC(mask, ipf_rdx_mask_t *);
422 bzero(mask, sizeof(*mask));
424 mask->node = &nodes[0];
425 mask->maskbitcount = nodebits;
426 mask->mask = nodes[0].maskkey;
427 nodes[0].mymask = mask;
432 for (pmask = &prev->masks; (m = *pmask) != NULL;
434 if (m->maskbitcount < nodebits)
439 * No higher up nodes qualify, so attach mask locally.
441 pmask = &nodes[0].masks;
447 * Search the mask list on each child to see if there are any masks
448 * there that can be moved up to this newly inserted node.
450 cur = nodes[1].right;
451 if (cur->root == 0) {
452 for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
453 if (mask->maskbitcount < nodebits) {
455 ipf_rx_attach_mask(&nodes[0], mask);
462 if (cur->root == 0 && cur != &nodes[0]) {
463 for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
464 if (mask->maskbitcount < nodebits) {
466 ipf_rx_attach_mask(&nodes[0], mask);
475 /* ------------------------------------------------------------------------ */
476 /* Function: ipf_rx_addroute */
477 /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
478 /* added to the tree. */
479 /* Paramters: head(I) - pointer to tree head to search */
480 /* addr(I) - address portion of "route" to add */
481 /* mask(I) - netmask portion of "route" to add */
482 /* nodes(I) - radix tree data nodes inside allocate structure */
484 /* Attempt to add a node to the radix tree. The key for the node is the */
485 /* (addr,mask). No memory allocation for the radix nodes themselves is */
486 /* performed here, the data structure that this radix node is being used to */
487 /* find is expected to house the node data itself however the call to */
488 /* ipf_rx_insert() will attempt to allocate memory in order for netmask to */
489 /* be promoted further up the tree. */
490 /* In this case, the ip_pool_node_t structure from ip_pool.h contains both */
491 /* the key material (addr,mask) and the radix tree nodes[]. */
493 /* The mechanics of inserting the node into the tree is handled by the */
494 /* function ipf_rx_insert() above. Here, the code deals with the case */
495 /* where the data to be inserted is a duplicate. */
496 /* ------------------------------------------------------------------------ */
498 ipf_rx_addroute(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask,
499 ipf_rdx_node_t *nodes)
501 ipf_rdx_node_t *node;
502 ipf_rdx_node_t *prev;
506 buildnodes(addr, mask, nodes);
507 x = ipf_rx_insert(head, nodes, &dup);
515 * The duplicate list is kept sorted with the longest
516 * mask at the top, meaning that the most specific entry
517 * in the listis found first. This list thus allows for
518 * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
520 while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
526 * Is it a complete duplicate? If so, return NULL and
527 * fail the insert. Otherwise, insert it into the list
528 * of netmasks active for this key.
530 if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
535 prev->dupkey = &nodes[0];
536 nodes[0].parent = prev;
538 x->parent = &nodes[0];
540 nodes[0].dupkey = x->dupkey;
542 nodes[0].parent = prev;
543 x->parent = &nodes[0];
545 prev->left = &nodes[0];
547 prev->right = &nodes[0];
555 /* ------------------------------------------------------------------------ */
556 /* Function: ipf_rx_delete */
557 /* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */
559 /* Paramters: head(I) - pointer to tree head to search */
560 /* addr(I) - pointer to the address part of the key */
561 /* mask(I) - pointer to the netmask part of the key */
563 /* Search for an entry in the radix tree that is an exact match for (addr, */
564 /* mask) and remove it if it exists. In the case where (addr,mask) is a not */
565 /* a unique key, the tree structure itself is not changed - only the list */
566 /* of duplicate keys. */
567 /* ------------------------------------------------------------------------ */
569 ipf_rx_delete(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask)
571 ipf_rdx_mask_t **pmask;
572 ipf_rdx_node_t *parent;
573 ipf_rdx_node_t *found;
574 ipf_rdx_node_t *prev;
575 ipf_rdx_node_t *node;
580 found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
583 if (found->root == 1)
585 count = count_mask_bits(mask, NULL);
586 parent = found->parent;
587 if (found->dupkey != NULL) {
589 while (node != NULL && node->maskbitcount != count)
595 * Remove from the dupkey list. Here, "parent" is
596 * the previous node on the list (rather than tree)
597 * and "dupkey" is the next node on the list.
599 parent = node->parent;
600 parent->dupkey = node->dupkey;
601 node->dupkey->parent = parent;
604 * When removing the top node of the dupkey list,
605 * the pointers at the top of the list that point
606 * to other tree nodes need to be preserved and
607 * any children must have their parent updated.
610 node->parent = found->parent;
611 node->right = found->right;
612 node->left = found->left;
613 found->right->parent = node;
614 found->left->parent = node;
615 if (parent->left == found)
621 if (count != found->maskbitcount)
624 * Remove the node from the tree and reconnect the subtree
628 * If there is a tree to the left, look for something to
629 * attach in place of "found".
632 cur = parent->parent;
633 if (parent != found + 1) {
634 if ((found + 1)->parent->right == found + 1)
635 (found + 1)->parent->right = parent;
637 (found + 1)->parent->left = parent;
638 if (cur->right == parent) {
639 if (parent->left == found) {
640 cur->right = parent->right;
641 } else if (parent->left != parent - 1) {
642 cur->right = parent->left;
644 cur->right = parent - 1;
646 cur->right->parent = cur;
648 if (parent->right == found) {
649 cur->left = parent->left;
650 } else if (parent->right != parent - 1) {
651 cur->left = parent->right;
653 cur->left = parent - 1;
655 cur->left->parent = cur;
657 parent->left = (found + 1)->left;
658 if ((found + 1)->right != parent)
659 parent->right = (found + 1)->right;
660 parent->left->parent = parent;
661 parent->right->parent = parent;
662 parent->parent = (found + 1)->parent;
664 parent->bitmask = prev->bitmask;
665 parent->offset = prev->offset;
666 parent->index = prev->index;
669 * We found an edge node.
671 cur = parent->parent;
672 if (cur->left == parent) {
673 if (parent->left == found) {
674 cur->left = parent->right;
675 parent->right->parent = cur;
677 cur->left = parent->left;
678 parent->left->parent = cur;
681 if (parent->right != found) {
682 cur->right = parent->right;
683 parent->right->parent = cur;
685 cur->right = parent->left;
686 prev->left->parent = cur;
693 * Remove mask associated with this node.
695 for (cur = parent; cur->root == 0; cur = cur->parent) {
698 if (cur->maskbitcount <= found->maskbitcount)
700 if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
701 found->addrkey[found->offset])
703 for (pm = &cur->masks; (m = *pm) != NULL; )
704 if (m->node == cur) {
711 KFREE(found->mymask);
714 * Masks that have been brought up to this node from below need to
717 for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
722 if (found->addrkey[cur->offset] & cur->lastmask) {
723 ipf_rx_attach_mask(parent->right, m);
724 } else if (parent->left != found) {
725 ipf_rx_attach_mask(parent->left, m);
733 /* ------------------------------------------------------------------------ */
734 /* Function: ipf_rx_walktree */
736 /* Paramters: head(I) - pointer to tree head to search */
737 /* walker(I) - function to call for each node in the tree */
738 /* arg(I) - parameter to pass to walker, in addition to the */
741 /* A standard tree walking function except that it is iterative, rather */
742 /* than recursive and tracks the next node in case the "walker" function */
743 /* should happen to delete and free the current node. It thus goes without */
744 /* saying that the "walker" function is not permitted to cause any change */
745 /* in the validity of the data found at either the left or right child. */
746 /* ------------------------------------------------------------------------ */
748 ipf_rx_walktree(ipf_rdx_head_t *head, radix_walk_func_t walker, void *arg)
750 ipf_rdx_node_t *next;
751 ipf_rdx_node_t *node = head->root;
752 ipf_rdx_node_t *base;
754 while (node->index >= 0)
759 while ((node->parent->right == node) && (node->root == 0))
762 for (node = node->parent->right; node->index >= 0; )
766 for (node = base; node != NULL; node = base) {
778 /* ------------------------------------------------------------------------ */
779 /* Function: ipf_rx_inithead */
780 /* Returns: int - 0 = success, else failure */
781 /* Paramters: softr(I) - pointer to radix context */
782 /* headp(O) - location for where to store allocated tree head */
784 /* This function allocates and initialises a radix tree head structure. */
785 /* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
786 /* "2" is used as the all ones sentinel, leaving node "1" as the root from */
787 /* which the tree is hung with node "0" on its left and node "2" to the */
788 /* right. The context, "softr", is used here to provide a common source of */
789 /* the zeroes and ones data rather than have one per head. */
790 /* ------------------------------------------------------------------------ */
792 ipf_rx_inithead(radix_softc_t *softr, ipf_rdx_head_t **headp)
795 ipf_rdx_node_t *node;
797 KMALLOC(ptr, ipf_rdx_head_t *);
801 bzero(ptr, sizeof(*ptr));
803 ptr->root = node + 1;
804 node[0].index = ADF_OFF_BITS;
805 node[0].index = -1 - node[0].index;
806 node[1].index = ADF_OFF_BITS;
807 node[2].index = node[0].index;
808 node[0].parent = node + 1;
809 node[1].parent = node + 1;
810 node[2].parent = node + 1;
811 node[1].bitmask = htonl(0x80000000);
815 node[0].offset = ADF_OFF_BITS >> 5;
816 node[1].offset = ADF_OFF_BITS >> 5;
817 node[2].offset = ADF_OFF_BITS >> 5;
818 node[1].left = &node[0];
819 node[1].right = &node[2];
820 node[0].addrkey = (u_32_t *)softr->zeros;
821 node[2].addrkey = (u_32_t *)softr->ones;
823 (void) strcpy(node[0].name, "0_ROOT");
824 (void) strcpy(node[1].name, "1_ROOT");
825 (void) strcpy(node[2].name, "2_ROOT");
828 ptr->addaddr = ipf_rx_addroute;
829 ptr->deladdr = ipf_rx_delete;
830 ptr->lookup = ipf_rx_lookup;
831 ptr->matchaddr = ipf_rx_match;
832 ptr->walktree = ipf_rx_walktree;
837 /* ------------------------------------------------------------------------ */
838 /* Function: ipf_rx_freehead */
840 /* Paramters: head(I) - pointer to tree head to free */
842 /* This function simply free's up the radix tree head. Prior to calling */
843 /* this function, it is expected that the tree will have been emptied. */
844 /* ------------------------------------------------------------------------ */
846 ipf_rx_freehead(ipf_rdx_head_t *head)
852 /* ------------------------------------------------------------------------ */
853 /* Function: ipf_rx_create */
854 /* Parameters: Nil */
856 /* ------------------------------------------------------------------------ */
860 radix_softc_t *softr;
862 KMALLOC(softr, radix_softc_t *);
865 bzero((char *)softr, sizeof(*softr));
867 KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
868 if (softr->zeros == NULL) {
872 softr->ones = softr->zeros + sizeof(addrfamily_t);
878 /* ------------------------------------------------------------------------ */
879 /* Function: ipf_rx_init */
880 /* Returns: int - 0 = success (always) */
882 /* ------------------------------------------------------------------------ */
884 ipf_rx_init(void *ctx)
886 radix_softc_t *softr = ctx;
888 memset(softr->zeros, 0, 3 * sizeof(addrfamily_t));
889 memset(softr->ones, 0xff, sizeof(addrfamily_t));
895 /* ------------------------------------------------------------------------ */
896 /* Function: ipf_rx_destroy */
899 /* ------------------------------------------------------------------------ */
901 ipf_rx_destroy(void *ctx)
903 radix_softc_t *softr = ctx;
905 if (softr->zeros != NULL)
906 KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
910 /* ====================================================================== */
914 * To compile this file as a standalone test unit, use -DRDX_DEBUG=1
916 #define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name)
917 #define GNAME(y) ((y) == NULL ? "NULL" : NAME(y))
919 typedef struct myst {
920 struct ipf_rdx_node nodes[2];
927 typedef struct tabe_s {
935 { "192:168:100::0", "48", "d" },
936 { "192:168:100::2", "128", "d" },
938 { "127.192.0.0", "255.255.255.0", "d" },
939 { "127.128.0.0", "255.255.255.0", "d" },
940 { "127.96.0.0", "255.255.255.0", "d" },
941 { "127.80.0.0", "255.255.255.0", "d" },
942 { "127.72.0.0", "255.255.255.0", "d" },
943 { "127.64.0.0", "255.255.255.0", "d" },
944 { "127.56.0.0", "255.255.255.0", "d" },
945 { "127.48.0.0", "255.255.255.0", "d" },
946 { "127.40.0.0", "255.255.255.0", "d" },
947 { "127.32.0.0", "255.255.255.0", "d" },
948 { "127.24.0.0", "255.255.255.0", "d" },
949 { "127.16.0.0", "255.255.255.0", "d" },
950 { "127.8.0.0", "255.255.255.0", "d" },
951 { "124.0.0.0", "255.0.0.0", "d" },
952 { "125.0.0.0", "255.0.0.0", "d" },
953 { "126.0.0.0", "255.0.0.0", "d" },
954 { "127.0.0.0", "255.0.0.0", "d" },
955 { "10.0.0.0", "255.0.0.0", "d" },
956 { "128.250.0.0", "255.255.0.0", "d" },
957 { "192.168.0.0", "255.255.0.0", "d" },
958 { "192.168.1.0", "255.255.255.0", "d" },
963 char *mtable[][1] = {
965 { "192:168:100::2" },
966 { "192:168:101::2" },
978 { "128.251.255.255" },
981 { "192.168.255.255" },
988 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8,
989 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21
992 static int nodecount = 0;
993 myst_t *myst_top = NULL;
994 tabe_t *ttable = NULL;
996 void add_addr(ipf_rdx_head_t *, int , int);
997 void checktree(ipf_rdx_head_t *);
998 void delete_addr(ipf_rdx_head_t *rnh, int item);
999 void dumptree(ipf_rdx_head_t *rnh);
1000 void nodeprinter(ipf_rdx_node_t *, void *);
1001 void printroots(ipf_rdx_head_t *);
1002 void random_add(ipf_rdx_head_t *);
1003 void random_delete(ipf_rdx_head_t *);
1004 void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int);
1008 ipf_rx_freenode(ipf_rdx_node_t *node, void *arg)
1010 ipf_rdx_head_t *head = arg;
1014 stp = (myst_t *)node;
1015 rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
1023 addrname(addrfamily_t *ap)
1025 static char name[80];
1028 bzero((char *)name, sizeof(name));
1029 txt = inet_ntop(ap->adf_family, &ap->adf_addr, name,
1036 fill6bits(int bits, u_int *msk)
1046 msk[0] = 0xffffffff;
1047 msk[1] = 0xffffffff;
1048 msk[2] = 0xffffffff;
1049 msk[3] = 0xffffffff;
1054 msk[3] = htonl(msk[3] << (128 - bits));
1055 } else if (bits > 64) {
1057 msk[2] = htonl(msk[2] << (96 - bits));
1058 } else if (bits > 32) {
1061 msk[1] = htonl(msk[1] << (64 - bits));
1066 msk[0] = htonl(msk[0] << (32 - bits));
1072 setaddr(addrfamily_t *afp, char *str)
1075 bzero((char *)afp, sizeof(*afp));
1077 if (strchr(str, ':') == NULL) {
1078 afp->adf_family = AF_INET;
1079 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1081 afp->adf_family = AF_INET6;
1082 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
1084 inet_pton(afp->adf_family, str, &afp->adf_addr);
1089 setmask(addrfamily_t *afp, char *str)
1091 if (strchr(str, '.') != NULL) {
1092 afp->adf_addr.in4.s_addr = inet_addr(str);
1093 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1094 } else if (afp->adf_family == AF_INET) {
1095 afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str)));
1096 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1097 } else if (afp->adf_family == AF_INET6) {
1098 fill6bits(atoi(str), afp->adf_addr.i6);
1099 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
1105 nodeprinter(ipf_rdx_node_t *node, void *arg)
1107 myst_t *stp = (myst_t *)node;
1109 printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
1111 GNAME(node[1].left), GNAME(node[1].right),
1112 GNAME(node[0].parent), GNAME(node[1].parent),
1113 addrname(&stp->dst), node[0].maskbitcount);
1114 if (stp->printed == -1)
1115 printf("!!! %d\n", stp->printed);
1122 printnode(myst_t *stp)
1124 ipf_rdx_node_t *node = &stp->nodes[0];
1126 if (stp->nodes[0].index > 0)
1127 stp = (myst_t *)&stp->nodes[-1];
1129 printf("Node %-9.9s ", node[0].name);
1130 printf("L %-9.9s ", GNAME(node[1].left));
1131 printf("R %-9.9s ", GNAME(node[1].right));
1132 printf("P %9.9s", GNAME(node[0].parent));
1133 printf("/%-9.9s ", GNAME(node[1].parent));
1134 printf("%s P%d\n", addrname(&stp->dst), stp->printed);
1147 fp = fopen("hosts", "r");
1149 while (fgets(line, sizeof(line), fp) != NULL) {
1150 s = strchr(line, '\n');
1155 tab = malloc(sizeof(*tab) * 2);
1157 tab = realloc(tab, (lines + 1) * sizeof(*tab));
1158 tab[lines - 1].host = strdup(line);
1159 s = strchr(tab[lines - 1].host, '/');
1161 tab[lines - 1].mask = s;
1162 tab[lines - 1].what = "d";
1166 tab[lines].host = NULL;
1167 tab[lines].mask = NULL;
1168 tab[lines].what = NULL;
1174 printroots(ipf_rdx_head_t *rnh)
1176 printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1177 GNAME(&rnh->nodes[0]),
1178 rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
1179 GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
1180 printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1181 GNAME(&rnh->nodes[1]),
1182 rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
1183 GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
1184 printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1185 GNAME(&rnh->nodes[2]),
1186 rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
1187 GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
1192 main(int argc, char *argv[])
1195 ipf_rdx_head_t *rnh;
1203 ctx = ipf_rx_create();
1205 ipf_rx_inithead(ctx, &rnh);
1207 printf("=== ADD-0 ===\n");
1208 for (i = 0; ttable[i].host != NULL; i++) {
1209 add_addr(rnh, i, i);
1213 ipf_rx_walktree(rnh, nodeprinter, NULL);
1214 printf("=== DELETE-0 ===\n");
1215 for (i = 0; ttable[i].host != NULL; i++) {
1216 delete_addr(rnh, i);
1218 ipf_rx_walktree(rnh, nodeprinter, NULL);
1220 printf("=== ADD-1 ===\n");
1221 for (i = 0; ttable[i].host != NULL; i++) {
1222 setaddr(&af, ttable[i].host);
1223 add_addr(rnh, i, i); /*forder[i]); */
1227 ipf_rx_walktree(rnh, nodeprinter, NULL);
1228 printf("=== TEST-1 ===\n");
1229 for (i = 0; ttable[i].host != NULL; i++) {
1230 setaddr(&af, ttable[i].host);
1231 test_addr(rnh, i, &af, -1);
1234 printf("=== TEST-2 ===\n");
1235 for (i = 0; mtable[i][0] != NULL; i++) {
1236 setaddr(&af, mtable[i][0]);
1237 test_addr(rnh, i, &af, -1);
1239 printf("=== DELETE-1 ===\n");
1240 for (i = 0; ttable[i].host != NULL; i++) {
1241 if (ttable[i].what[0] != 'd')
1243 delete_addr(rnh, i);
1244 for (j = 0; ttable[j].host != NULL; j++) {
1245 setaddr(&af, ttable[j].host);
1246 test_addr(rnh, i, &af, 3);
1249 ipf_rx_walktree(rnh, nodeprinter, NULL);
1254 printf("=== ADD-2 ===\n");
1258 ipf_rx_walktree(rnh, nodeprinter, NULL);
1259 printf("=== DELETE-2 ===\n");
1264 ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
1271 dumptree(ipf_rdx_head_t *rnh)
1275 printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
1277 for (stp = myst_top; stp; stp = stp->next)
1279 printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
1284 test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *addr, int limit)
1286 static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
1287 15, 16, 19, 255, 256, 65535, 65536
1295 memset(&af, 0, sizeof(af));
1297 if (limit < 0 || limit > 14)
1300 for (i = 0; i < limit; i++) {
1301 if (ttable[i].host == NULL)
1303 setaddr(&af, ttable[i].host);
1304 printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af));
1305 rn = ipf_rx_match(rnh, &af);
1307 printf(" = %s (%s/%d)\n", GNAME(rn),
1308 rn ? addrname(&stp->dst) : "NULL",
1309 rn ? rn->maskbitcount : 0);
1312 printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr));
1313 rn = ipf_rx_match(rnh, addr);
1315 printf(" = %s (%s/%d)\n", GNAME(rn),
1316 rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0);
1322 delete_addr(ipf_rdx_head_t *rnh, int item)
1330 memset(&af, 0, sizeof(af));
1331 memset(&mask, 0, sizeof(mask));
1332 setaddr(&af, ttable[item].host);
1333 mask.adf_family = af.adf_family;
1334 setmask(&mask, ttable[item].mask);
1336 printf("DELETE(%s)\n", addrname(&af));
1337 rn = ipf_rx_delete(rnh, &af, &mask);
1339 printf("FAIL LOOKUP DELETE\n");
1341 for (stp = myst_top; stp != NULL; stp = stp->next)
1342 if (stp->printed != -1)
1344 ipf_rx_walktree(rnh, nodeprinter, NULL);
1348 printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn));
1350 for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
1351 if (stp == (myst_t *)rn)
1354 stp->nodes[0].parent = &stp->nodes[0];
1355 stp->nodes[1].parent = &stp->nodes[1];
1364 add_addr(ipf_rdx_head_t *rnh, int n, int item)
1369 stp = calloc(1, sizeof(*stp));
1370 rn = (ipf_rdx_node_t *)stp;
1371 setaddr(&stp->dst, ttable[item].host);
1372 stp->mask.adf_family = stp->dst.adf_family;
1373 setmask(&stp->mask, ttable[item].mask);
1374 stp->next = myst_top;
1377 (void) snprintf(rn[0].name, sizeof(ipf_rdx_node.name), "_BORN.0");
1378 (void) snprintf(rn[1].name, sizeof(ipf_rdx_node.name), "_BORN.1");
1379 rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
1380 (void) snprintf(rn[0].name, sizeof(ipf_rdx_node.name), "%d_NODE.0", item);
1381 (void) snprintf(rn[1].name, sizeof(ipf_rdx_node.name), "%d_NODE.1", item);
1382 printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
1390 checktree(ipf_rdx_head_t *head)
1398 for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
1400 if (s1->printed == -1)
1403 if (rn->right->parent != rn)
1405 if (rn->left->parent != rn)
1407 if (rn->parent->left != rn && rn->parent->right != rn)
1410 printf("FAULT %#x %s\n", fault, rn->name);
1412 ipf_rx_walktree(head, nodeprinter, NULL);
1423 randomize(int *pnitems)
1431 nitems = sizeof(ttable) / sizeof(ttable[0]);
1433 order = calloc(nitems, sizeof(*order));
1434 srandom(getpid() * time(NULL));
1435 memset(order, 0xff, nitems * sizeof(*order));
1437 for (i = 0; i < nitems - 1; i++) {
1439 choice = rand() % (nitems - 1);
1440 for (j = 0; j < nitems; j++)
1441 if (order[j] == choice)
1443 } while (j != nitems);
1452 random_add(ipf_rdx_head_t *rnh)
1458 order = randomize(&nitems);
1460 for (i = 0; i < nitems - 1; i++) {
1461 add_addr(rnh, i, order[i]);
1470 random_delete(ipf_rdx_head_t *rnh)
1476 order = randomize(&nitems);
1478 for (i = 0; i < nitems - 1; i++) {
1479 delete_addr(rnh, i);
1485 #endif /* RDX_DEBUG */