1/* $NetBSD: radix_ipf.c,v 1.6 2015/12/15 12:30:34 christos Exp $ */
2
3/*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#include <sys/types.h>
9#include <sys/time.h>
10#include <sys/socket.h>
11#include <sys/param.h>
12#include <netinet/in.h>
13#include <net/if.h>
14#if !defined(_KERNEL)
15# include <stddef.h>
16# include <stdlib.h>
17# include <strings.h>
18# include <string.h>
19#endif
20#include "netinet/ip_compat.h"
21#include "netinet/ip_fil.h"
22#ifdef RDX_DEBUG
23# include <arpa/inet.h>
24# include <stdlib.h>
25# include <stdio.h>
26#endif
27#include "netinet/radix_ipf.h"
28
29#define ADF_OFF offsetof(addrfamily_t, adf_addr)
30#define ADF_OFF_BITS ((ADF_OFF << 3) & 0xffff)
31
32static ipf_rdx_node_t *ipf_rx_insert(ipf_rdx_head_t *,
33 ipf_rdx_node_t nodes[2], int *);
34static void ipf_rx_attach_mask(ipf_rdx_node_t *, ipf_rdx_mask_t *);
35static int count_mask_bits(addrfamily_t *, u_32_t **);
36static void buildnodes(addrfamily_t *, addrfamily_t *,
37 ipf_rdx_node_t n[2]);
38static ipf_rdx_node_t *ipf_rx_find_addr(ipf_rdx_node_t *, u_32_t *);
39static ipf_rdx_node_t *ipf_rx_lookup(ipf_rdx_head_t *, addrfamily_t *,
40 addrfamily_t *);
41static ipf_rdx_node_t *ipf_rx_match(ipf_rdx_head_t *, addrfamily_t *);
42
43/*
44 * Foreword.
45 * ---------
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.
52 */
53
54/* ------------------------------------------------------------------------ */
55/* Function: count_mask_bits */
56/* Returns: number of consecutive bits starting at "mask". */
57/* */
58/* Count the number of bits set in the address section of addrfamily_t and */
59/* return both that number and a pointer to the last word with a bit set if */
60/* lastp is not NULL. The bit count is performed using network byte order */
61/* as the guide for which bit is the most significant bit. */
62/* ------------------------------------------------------------------------ */
63static int
64count_mask_bits(addrfamily_t *mask, u_32_t **lastp)
65{
66 u_32_t *mp = (u_32_t *)&mask->adf_addr;
67 u_32_t m;
68 int count = 0;
69 int mlen;
70
71 mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
72 for (; mlen > 0; mlen -= 4, mp++) {
73 if ((m = ntohl(*mp)) == 0)
74 break;
75 if (lastp != NULL)
76 *lastp = mp;
77 for (; m & 0x80000000; m <<= 1)
78 count++;
79 }
80
81 return count;
82}
83
84
85/* ------------------------------------------------------------------------ */
86/* Function: buildnodes */
87/* Returns: Nil */
88/* Parameters: addr(I) - network address for this radix node */
89/* mask(I) - netmask associated with the above address */
90/* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
91/* associated with addr and mask. */
92/* */
93/* Initialise the fields in a pair of radix tree nodes according to the */
94/* data supplied in the paramters "addr" and "mask". It is expected that */
95/* "mask" will contain a consecutive string of bits set. Masks with gaps in */
96/* the middle are not handled by this implementation. */
97/* ------------------------------------------------------------------------ */
98static void
99buildnodes(addrfamily_t *addr, addrfamily_t *mask, ipf_rdx_node_t nodes[2])
100{
101 u_32_t maskbits;
102 u_32_t lastmask;
103 u_32_t *last;
104 int masklen;
105
106 last = NULL;
107 maskbits = count_mask_bits(mask, &last);
108 if (last == NULL) {
109 masklen = 0;
110 lastmask = 0;
111 } else {
112 masklen = last - (u_32_t *)mask;
113 lastmask = *last;
114 }
115
116 bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
117 nodes[0].maskbitcount = maskbits;
118 nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
119 nodes[0].addrkey = (u_32_t *)addr;
120 nodes[0].maskkey = (u_32_t *)mask;
121 nodes[0].addroff = nodes[0].addrkey + masklen;
122 nodes[0].maskoff = nodes[0].maskkey + masklen;
123 nodes[0].parent = &nodes[1];
124 nodes[0].offset = masklen;
125 nodes[0].lastmask = lastmask;
126 nodes[1].offset = masklen;
127 nodes[1].left = &nodes[0];
128 nodes[1].maskbitcount = maskbits;
129#ifdef RDX_DEBUG
130 (void) strcpy(nodes[0].name, "_BUILD.0");
131 (void) strcpy(nodes[1].name, "_BUILD.1");
132#endif
133}
134
135
136/* ------------------------------------------------------------------------ */
137/* Function: ipf_rx_find_addr */
138/* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */
139/* Parameters: tree(I) - pointer to first right node in tree to search */
140/* addr(I) - pointer to address to match */
141/* */
142/* Walk the radix tree given by "tree", looking for a leaf node that is a */
143/* match for the address given by "addr". */
144/* ------------------------------------------------------------------------ */
145static ipf_rdx_node_t *
146ipf_rx_find_addr(ipf_rdx_node_t *tree, u_32_t *addr)
147{
148 ipf_rdx_node_t *cur;
149
150 for (cur = tree; cur->index >= 0;) {
151 if (cur->bitmask & addr[cur->offset]) {
152 cur = cur->right;
153 } else {
154 cur = cur->left;
155 }
156 }
157
158 return (cur);
159}
160
161
162/* ------------------------------------------------------------------------ */
163/* Function: ipf_rx_match */
164/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
165/* added to the tree. */
166/* Paramters: head(I) - pointer to tree head to search */
167/* addr(I) - pointer to address to find */
168/* */
169/* Search the radix tree for the best match to the address pointed to by */
170/* "addr" and return a pointer to that node. This search will not match the */
171/* address information stored in either of the root leaves as neither of */
172/* them are considered to be part of the tree of data being stored. */
173/* ------------------------------------------------------------------------ */
174static ipf_rdx_node_t *
175ipf_rx_match(ipf_rdx_head_t *head, addrfamily_t *addr)
176{
177 ipf_rdx_mask_t *masknode;
178 ipf_rdx_node_t *prev;
179 ipf_rdx_node_t *node;
180 ipf_rdx_node_t *cur;
181 u_32_t *data;
182 u_32_t *mask;
183 u_32_t *key;
184 u_32_t *end;
185 int len;
186 int i;
187
188 len = addr->adf_len;
189 end = (u_32_t *)((u_char *)addr + len);
190 node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
191
192 /*
193 * Search the dupkey list for a potential match.
194 */
195 for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
196 i = cur[0].addroff - cur[0].addrkey;
197 data = cur[0].addrkey + i;
198 mask = cur[0].maskkey + i;
199 key = (u_32_t *)addr + i;
200 for (; key < end; data++, key++, mask++)
201 if ((*key & *mask) != *data)
202 break;
203 if ((end == key) && (cur->root == 0))
204 return (cur); /* Equal keys */
205 }
206 prev = node->parent;
207 key = (u_32_t *)addr;
208
209 for (node = prev; node->root == 0; node = node->parent) {
210 /*
211 * We know that the node hasn't matched so therefore only
212 * the entries in the mask list are searched, not the top
213 * node nor the dupkey list.
214 */
215 masknode = node->masks;
216 for (; masknode != NULL; masknode = masknode->next) {
217 if (masknode->maskbitcount > node->maskbitcount)
218 continue;
219 cur = masknode->node;
220 for (i = ADF_OFF >> 2; i <= node->offset; i++) {
221 if ((key[i] & masknode->mask[i]) ==
222 cur->addrkey[i])
223 return (cur);
224 }
225 }
226 }
227
228 return NULL;
229}
230
231
232/* ------------------------------------------------------------------------ */
233/* Function: ipf_rx_lookup */
234/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
235/* added to the tree. */
236/* Paramters: head(I) - pointer to tree head to search */
237/* addr(I) - address part of the key to match */
238/* mask(I) - netmask part of the key to match */
239/* */
240/* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */
241/* is to see if a given key is in the tree, not to see if a route exists. */
242/* ------------------------------------------------------------------------ */
243ipf_rdx_node_t *
244ipf_rx_lookup(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask)
245{
246 ipf_rdx_node_t *found;
247 ipf_rdx_node_t *node;
248 u_32_t *akey;
249 int count;
250
251 found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
252 if (found->root == 1)
253 return NULL;
254
255 /*
256 * It is possible to find a matching address in the tree but for the
257 * netmask to not match. If the netmask does not match and there is
258 * no list of alternatives present at dupkey, return a failure.
259 */
260 count = count_mask_bits(mask, NULL);
261 if (count != found->maskbitcount && found->dupkey == NULL)
262 return (NULL);
263
264 akey = (u_32_t *)addr;
265 if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
266 akey[found->offset])
267 return NULL;
268
269 if (found->dupkey != NULL) {
270 node = found;
271 while (node != NULL && node->maskbitcount != count)
272 node = node->dupkey;
273 if (node == NULL)
274 return (NULL);
275 found = node;
276 }
277 return found;
278}
279
280
281/* ------------------------------------------------------------------------ */
282/* Function: ipf_rx_attach_mask */
283/* Returns: Nil */
284/* Parameters: node(I) - pointer to a radix tree node */
285/* mask(I) - pointer to mask structure to add */
286/* */
287/* Add the netmask to the given node in an ordering where the most specific */
288/* netmask is at the top of the list. */
289/* ------------------------------------------------------------------------ */
290static void
291ipf_rx_attach_mask(ipf_rdx_node_t *node, ipf_rdx_mask_t *mask)
292{
293 ipf_rdx_mask_t **pm;
294 ipf_rdx_mask_t *m;
295
296 for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
297 if (m->maskbitcount < mask->maskbitcount)
298 break;
299 mask->next = *pm;
300 *pm = mask;
301}
302
303
304/* ------------------------------------------------------------------------ */
305/* Function: ipf_rx_insert */
306/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
307/* added to the tree. */
308/* Paramters: head(I) - pointer to tree head to add nodes to */
309/* nodes(I) - pointer to radix nodes to be added */
310/* dup(O) - set to 1 if node is a duplicate, else 0. */
311/* */
312/* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
313/* If there is already a matching key in the table, "dup" will be set to 1 */
314/* and the existing node pointer returned if there is a complete key match. */
315/* A complete key match is a matching of all key data that is presented by */
316/* by the netmask. */
317/* ------------------------------------------------------------------------ */
318static ipf_rdx_node_t *
319ipf_rx_insert(ipf_rdx_head_t *head, ipf_rdx_node_t nodes[2], int *dup)
320{
321 ipf_rdx_mask_t **pmask;
322 ipf_rdx_node_t *node;
323 ipf_rdx_node_t *prev;
324 ipf_rdx_mask_t *mask;
325 ipf_rdx_node_t *cur;
326 u_32_t nodemask;
327 u_32_t *addr;
328 u_32_t *data;
329 int nodebits;
330 u_32_t *key;
331 u_32_t *end;
332 u_32_t bits;
333 int nodekey;
334 int nodeoff;
335 int nlen;
336 int len;
337
338 addr = nodes[0].addrkey;
339
340 node = ipf_rx_find_addr(head->root, addr);
341 len = ((addrfamily_t *)addr)->adf_len;
342 key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
343 data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
344 end = (u_32_t *)((u_char *)addr + len);
345 for (nlen = 0; key < end; data++, key++, nlen += 32)
346 if (*key != *data)
347 break;
348 if (end == data) {
349 *dup = 1;
350 return (node); /* Equal keys */
351 }
352 *dup = 0;
353
354 bits = (ntohl(*data) ^ ntohl(*key));
355 for (; bits != 0; nlen++) {
356 if ((bits & 0x80000000) != 0)
357 break;
358 bits <<= 1;
359 }
360 nlen += ADF_OFF_BITS;
361 nodes[1].index = nlen;
362 nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
363 nodes[0].offset = nlen / 32;
364 nodes[1].offset = nlen / 32;
365
366 /*
367 * Walk through the tree and look for the correct place to attach
368 * this node. ipf_rx_fin_addr is not used here because the place
369 * to attach this node may be an internal node (same key, different
370 * netmask.) Additionally, the depth of the search is forcibly limited
371 * here to not exceed the netmask, so that a short netmask will be
372 * added higher up the tree even if there are lower branches.
373 */
374 cur = head->root;
375 key = nodes[0].addrkey;
376 do {
377 prev = cur;
378 if (key[cur->offset] & cur->bitmask) {
379 cur = cur->right;
380 } else {
381 cur = cur->left;
382 }
383 } while (nlen > (unsigned)cur->index);
384
385 if ((key[prev->offset] & prev->bitmask) == 0) {
386 prev->left = &nodes[1];
387 } else {
388 prev->right = &nodes[1];
389 }
390 cur->parent = &nodes[1];
391 nodes[1].parent = prev;
392 if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) {
393 nodes[1].right = cur;
394 } else {
395 nodes[1].right = &nodes[0];
396 nodes[1].left = cur;
397 }
398
399 nodeoff = nodes[0].offset;
400 nodekey = nodes[0].addrkey[nodeoff];
401 nodemask = nodes[0].lastmask;
402 nodebits = nodes[0].maskbitcount;
403 prev = NULL;
404 /*
405 * Find the node up the tree with the largest pattern that still
406 * matches the node being inserted to see if this mask can be
407 * moved there.
408 */
409 for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
410 if (cur->maskbitcount <= nodebits)
411 break;
412 if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
413 break;
414 prev = cur;
415 }
416
417 KMALLOC(mask, ipf_rdx_mask_t *);
418 if (mask == NULL)
419 return NULL;
420 bzero(mask, sizeof(*mask));
421 mask->next = NULL;
422 mask->node = &nodes[0];
423 mask->maskbitcount = nodebits;
424 mask->mask = nodes[0].maskkey;
425 nodes[0].mymask = mask;
426
427 if (prev != NULL) {
428 ipf_rdx_mask_t *m;
429
430 for (pmask = &prev->masks; (m = *pmask) != NULL;
431 pmask = &m->next) {
432 if (m->maskbitcount < nodebits)
433 break;
434 }
435 } else {
436 /*
437 * No higher up nodes qualify, so attach mask locally.
438 */
439 pmask = &nodes[0].masks;
440 }
441 mask->next = *pmask;
442 *pmask = mask;
443
444 /*
445 * Search the mask list on each child to see if there are any masks
446 * there that can be moved up to this newly inserted node.
447 */
448 cur = nodes[1].right;
449 if (cur->root == 0) {
450 for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
451 if (mask->maskbitcount < nodebits) {
452 *pmask = mask->next;
453 ipf_rx_attach_mask(&nodes[0], mask);
454 } else {
455 pmask = &mask->next;
456 }
457 }
458 }
459 cur = nodes[1].left;
460 if (cur->root == 0 && cur != &nodes[0]) {
461 for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
462 if (mask->maskbitcount < nodebits) {
463 *pmask = mask->next;
464 ipf_rx_attach_mask(&nodes[0], mask);
465 } else {
466 pmask = &mask->next;
467 }
468 }
469 }
470 return (&nodes[0]);
471}
472
473/* ------------------------------------------------------------------------ */
474/* Function: ipf_rx_addroute */
475/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
476/* added to the tree. */
477/* Paramters: head(I) - pointer to tree head to search */
478/* addr(I) - address portion of "route" to add */
479/* mask(I) - netmask portion of "route" to add */
480/* nodes(I) - radix tree data nodes inside allocate structure */
481/* */
482/* Attempt to add a node to the radix tree. The key for the node is the */
483/* (addr,mask). No memory allocation for the radix nodes themselves is */
484/* performed here, the data structure that this radix node is being used to */
485/* find is expected to house the node data itself however the call to */
486/* ipf_rx_insert() will attempt to allocate memory in order for netmask to */
487/* be promoted further up the tree. */
488/* In this case, the ip_pool_node_t structure from ip_pool.h contains both */
489/* the key material (addr,mask) and the radix tree nodes[]. */
490/* */
491/* The mechanics of inserting the node into the tree is handled by the */
492/* function ipf_rx_insert() above. Here, the code deals with the case */
493/* where the data to be inserted is a duplicate. */
494/* ------------------------------------------------------------------------ */
495ipf_rdx_node_t *
496ipf_rx_addroute(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask,
497 ipf_rdx_node_t *nodes)
498{
499 ipf_rdx_node_t *node;
500 ipf_rdx_node_t *prev;
501 ipf_rdx_node_t *x;
502 int dup;
503
504 buildnodes(addr, mask, nodes);
505 x = ipf_rx_insert(head, nodes, &dup);
506 if (x == NULL)
507 return NULL;
508
509 if (dup == 1) {
510 node = &nodes[0];
511 prev = NULL;
512 /*
513 * The duplicate list is kept sorted with the longest
514 * mask at the top, meaning that the most specific entry
515 * in the listis found first. This list thus allows for
516 * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
517 */
518 while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
519 prev = x;
520 x = x->dupkey;
521 }
522
523 /*
524 * Is it a complete duplicate? If so, return NULL and
525 * fail the insert. Otherwise, insert it into the list
526 * of netmasks active for this key.
527 */
528 if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
529 return (NULL);
530
531 if (prev != NULL) {
532 nodes[0].dupkey = x;
533 prev->dupkey = &nodes[0];
534 nodes[0].parent = prev;
535 if (x != NULL)
536 x->parent = &nodes[0];
537 } else {
538 nodes[0].dupkey = x->dupkey;
539 prev = x->parent;
540 nodes[0].parent = prev;
541 x->parent = &nodes[0];
542 if (prev->left == x)
543 prev->left = &nodes[0];
544 else
545 prev->right = &nodes[0];
546 }
547 }
548
549 return &nodes[0];
550}
551
552
553/* ------------------------------------------------------------------------ */
554/* Function: ipf_rx_delete */
555/* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */
556/* the tree. */
557/* Paramters: head(I) - pointer to tree head to search */
558/* addr(I) - pointer to the address part of the key */
559/* mask(I) - pointer to the netmask part of the key */
560/* */
561/* Search for an entry in the radix tree that is an exact match for (addr, */
562/* mask) and remove it if it exists. In the case where (addr,mask) is a not */
563/* a unique key, the tree structure itself is not changed - only the list */
564/* of duplicate keys. */
565/* ------------------------------------------------------------------------ */
566ipf_rdx_node_t *
567ipf_rx_delete(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask)
568{
569 ipf_rdx_mask_t **pmask;
570 ipf_rdx_node_t *parent;
571 ipf_rdx_node_t *found;
572 ipf_rdx_node_t *prev;
573 ipf_rdx_node_t *node;
574 ipf_rdx_node_t *cur;
575 ipf_rdx_mask_t *m;
576 int count;
577
578 found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
579 if (found == NULL)
580 return NULL;
581 if (found->root == 1)
582 return NULL;
583 count = count_mask_bits(mask, NULL);
584 parent = found->parent;
585 if (found->dupkey != NULL) {
586 node = found;
587 while (node != NULL && node->maskbitcount != count)
588 node = node->dupkey;
589 if (node == NULL)
590 return (NULL);
591 if (node != found) {
592 /*
593 * Remove from the dupkey list. Here, "parent" is
594 * the previous node on the list (rather than tree)
595 * and "dupkey" is the next node on the list.
596 */
597 parent = node->parent;
598 parent->dupkey = node->dupkey;
599 node->dupkey->parent = parent;
600 } else {
601 /*
602 *
603 * When removing the top node of the dupkey list,
604 * the pointers at the top of the list that point
605 * to other tree nodes need to be preserved and
606 * any children must have their parent updated.
607 */
608 node = node->dupkey;
609 node->parent = found->parent;
610 node->right = found->right;
611 node->left = found->left;
612 found->right->parent = node;
613 found->left->parent = node;
614 if (parent->left == found)
615 parent->left = node;
616 else
617 parent->right= node;
618 }
619 } else {
620 if (count != found->maskbitcount)
621 return (NULL);
622 /*
623 * Remove the node from the tree and reconnect the subtree
624 * below.
625 */
626 /*
627 * If there is a tree to the left, look for something to
628 * attach in place of "found".
629 */
630 prev = found + 1;
631 cur = parent->parent;
632 if (parent != found + 1) {
633 if ((found + 1)->parent->right == found + 1)
634 (found + 1)->parent->right = parent;
635 else
636 (found + 1)->parent->left = parent;
637 if (cur->right == parent) {
638 if (parent->left == found) {
639 cur->right = parent->right;
640 } else if (parent->left != parent - 1) {
641 cur->right = parent->left;
642 } else {
643 cur->right = parent - 1;
644 }
645 cur->right->parent = cur;
646 } else {
647 if (parent->right == found) {
648 cur->left = parent->left;
649 } else if (parent->right != parent - 1) {
650 cur->left = parent->right;
651 } else {
652 cur->left = parent - 1;
653 }
654 cur->left->parent = cur;
655 }
656 parent->left = (found + 1)->left;
657 if ((found + 1)->right != parent)
658 parent->right = (found + 1)->right;
659 parent->left->parent = parent;
660 parent->right->parent = parent;
661 parent->parent = (found + 1)->parent;
662
663 parent->bitmask = prev->bitmask;
664 parent->offset = prev->offset;
665 parent->index = prev->index;
666 } else {
667 /*
668 * We found an edge node.
669 */
670 cur = parent->parent;
671 if (cur->left == parent) {
672 if (parent->left == found) {
673 cur->left = parent->right;
674 parent->right->parent = cur;
675 } else {
676 cur->left = parent->left;
677 parent->left->parent = cur;
678 }
679 } else {
680 if (parent->right != found) {
681 cur->right = parent->right;
682 parent->right->parent = cur;
683 } else {
684 cur->right = parent->left;
685 prev->left->parent = cur;
686 }
687 }
688 }
689 }
690
691 /*
692 * Remove mask associated with this node.
693 */
694 for (cur = parent; cur->root == 0; cur = cur->parent) {
695 ipf_rdx_mask_t **pm;
696
697 if (cur->maskbitcount <= found->maskbitcount)
698 break;
699 if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
700 found->addrkey[found->offset])
701 break;
702 for (pm = &cur->masks; (m = *pm) != NULL; )
703 if (m->node == cur) {
704 *pm = m->next;
705 break;
706 } else {
707 pm = &m->next;
708 }
709 }
710 KFREE(found->mymask);
711
712 /*
713 * Masks that have been brought up to this node from below need to
714 * be sent back down.
715 */
716 for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
717 *pmask = m->next;
718 cur = m->node;
719 if (cur == found)
720 continue;
721 if (found->addrkey[cur->offset] & cur->lastmask) {
722 ipf_rx_attach_mask(parent->right, m);
723 } else if (parent->left != found) {
724 ipf_rx_attach_mask(parent->left, m);
725 }
726 }
727
728 return (found);
729}
730
731
732/* ------------------------------------------------------------------------ */
733/* Function: ipf_rx_walktree */
734/* Returns: Nil */
735/* Paramters: head(I) - pointer to tree head to search */
736/* walker(I) - function to call for each node in the tree */
737/* arg(I) - parameter to pass to walker, in addition to the */
738/* node pointer */
739/* */
740/* A standard tree walking function except that it is iterative, rather */
741/* than recursive and tracks the next node in case the "walker" function */
742/* should happen to delete and free the current node. It thus goes without */
743/* saying that the "walker" function is not permitted to cause any change */
744/* in the validity of the data found at either the left or right child. */
745/* ------------------------------------------------------------------------ */
746void
747ipf_rx_walktree(ipf_rdx_head_t *head, radix_walk_func_t walker, void *arg)
748{
749 ipf_rdx_node_t *next;
750 ipf_rdx_node_t *node = head->root;
751 ipf_rdx_node_t *base;
752
753 while (node->index >= 0)
754 node = node->left;
755
756 for (;;) {
757 base = node;
758 while ((node->parent->right == node) && (node->root == 0))
759 node = node->parent;
760
761 for (node = node->parent->right; node->index >= 0; )
762 node = node->left;
763 next = node;
764
765 for (node = base; node != NULL; node = base) {
766 base = node->dupkey;
767 if (node->root == 0)
768 walker(node, arg);
769 }
770 node = next;
771 if (node->root)
772 return;
773 }
774}
775
776
777/* ------------------------------------------------------------------------ */
778/* Function: ipf_rx_inithead */
779/* Returns: int - 0 = success, else failure */
780/* Paramters: softr(I) - pointer to radix context */
781/* headp(O) - location for where to store allocated tree head */
782/* */
783/* This function allocates and initialises a radix tree head structure. */
784/* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
785/* "2" is used as the all ones sentinel, leaving node "1" as the root from */
786/* which the tree is hung with node "0" on its left and node "2" to the */
787/* right. The context, "softr", is used here to provide a common source of */
788/* the zeroes and ones data rather than have one per head. */
789/* ------------------------------------------------------------------------ */
790int
791ipf_rx_inithead(radix_softc_t *softr, ipf_rdx_head_t **headp)
792{
793 ipf_rdx_head_t *ptr;
794 ipf_rdx_node_t *node;
795
796 KMALLOC(ptr, ipf_rdx_head_t *);
797 *headp = ptr;
798 if (ptr == NULL)
799 return -1;
800 bzero(ptr, sizeof(*ptr));
801 node = ptr->nodes;
802 ptr->root = node + 1;
803 node[0].index = ADF_OFF_BITS;
804 node[0].index = -1 - node[0].index;
805 node[1].index = ADF_OFF_BITS;
806 node[2].index = node[0].index;
807 node[0].parent = node + 1;
808 node[1].parent = node + 1;
809 node[2].parent = node + 1;
810 node[1].bitmask = htonl(0x80000000);
811 node[0].root = 1;
812 node[1].root = 1;
813 node[2].root = 1;
814 node[0].offset = ADF_OFF_BITS >> 5;
815 node[1].offset = ADF_OFF_BITS >> 5;
816 node[2].offset = ADF_OFF_BITS >> 5;
817 node[1].left = &node[0];
818 node[1].right = &node[2];
819 node[0].addrkey = (u_32_t *)softr->zeros;
820 node[2].addrkey = (u_32_t *)softr->ones;
821#ifdef RDX_DEBUG
822 (void) strcpy(node[0].name, "0_ROOT");
823 (void) strcpy(node[1].name, "1_ROOT");
824 (void) strcpy(node[2].name, "2_ROOT");
825#endif
826
827 ptr->addaddr = ipf_rx_addroute;
828 ptr->deladdr = ipf_rx_delete;
829 ptr->lookup = ipf_rx_lookup;
830 ptr->matchaddr = ipf_rx_match;
831 ptr->walktree = ipf_rx_walktree;
832 return 0;
833}
834
835
836/* ------------------------------------------------------------------------ */
837/* Function: ipf_rx_freehead */
838/* Returns: Nil */
839/* Paramters: head(I) - pointer to tree head to free */
840/* */
841/* This function simply free's up the radix tree head. Prior to calling */
842/* this function, it is expected that the tree will have been emptied. */
843/* ------------------------------------------------------------------------ */
844void
845ipf_rx_freehead(ipf_rdx_head_t *head)
846{
847 KFREE(head);
848}
849
850
851/* ------------------------------------------------------------------------ */
852/* Function: ipf_rx_create */
853/* Parameters: Nil */
854/* */
855/* ------------------------------------------------------------------------ */
856void *
857ipf_rx_create(void)
858{
859 radix_softc_t *softr;
860
861 KMALLOC(softr, radix_softc_t *);
862 if (softr == NULL)
863 return NULL;
864 bzero((char *)softr, sizeof(*softr));
865
866 KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
867 if (softr->zeros == NULL) {
868 KFREE(softr);
869 return (NULL);
870 }
871 softr->ones = softr->zeros + sizeof(addrfamily_t);
872
873 return softr;
874}
875
876
877/* ------------------------------------------------------------------------ */
878/* Function: ipf_rx_init */
879/* Returns: int - 0 = success (always) */
880/* */
881/* ------------------------------------------------------------------------ */
882int
883ipf_rx_init(void *ctx)
884{
885 radix_softc_t *softr = ctx;
886
887 memset(softr->zeros, 0, 3 * sizeof(addrfamily_t));
888 memset(softr->ones, 0xff, sizeof(addrfamily_t));
889
890 return (0);
891}
892
893
894/* ------------------------------------------------------------------------ */
895/* Function: ipf_rx_destroy */
896/* Returns: Nil */
897/* */
898/* ------------------------------------------------------------------------ */
899void
900ipf_rx_destroy(void *ctx)
901{
902 radix_softc_t *softr = ctx;
903
904 if (softr->zeros != NULL)
905 KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
906 KFREE(softr);
907}
908
909/* ====================================================================== */
910
911#ifdef RDX_DEBUG
912/*
913 * To compile this file as a standalone test unit, use -DRDX_DEBUG=1
914 */
915#define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name)
916#define GNAME(y) ((y) == NULL ? "NULL" : NAME(y))
917
918typedef struct myst {
919 struct ipf_rdx_node nodes[2];
920 addrfamily_t dst;
921 addrfamily_t mask;
922 struct myst *next;
923 int printed;
924} myst_t;
925
926typedef struct tabe_s {
927 char *host;
928 char *mask;
929 char *what;
930} tabe_t;
931
932tabe_t builtin[] = {
933#if 1
934 { "192:168:100::0", "48", "d" },
935 { "192:168:100::2", "128", "d" },
936#else
937 { "127.192.0.0", "255.255.255.0", "d" },
938 { "127.128.0.0", "255.255.255.0", "d" },
939 { "127.96.0.0", "255.255.255.0", "d" },
940 { "127.80.0.0", "255.255.255.0", "d" },
941 { "127.72.0.0", "255.255.255.0", "d" },
942 { "127.64.0.0", "255.255.255.0", "d" },
943 { "127.56.0.0", "255.255.255.0", "d" },
944 { "127.48.0.0", "255.255.255.0", "d" },
945 { "127.40.0.0", "255.255.255.0", "d" },
946 { "127.32.0.0", "255.255.255.0", "d" },
947 { "127.24.0.0", "255.255.255.0", "d" },
948 { "127.16.0.0", "255.255.255.0", "d" },
949 { "127.8.0.0", "255.255.255.0", "d" },
950 { "124.0.0.0", "255.0.0.0", "d" },
951 { "125.0.0.0", "255.0.0.0", "d" },
952 { "126.0.0.0", "255.0.0.0", "d" },
953 { "127.0.0.0", "255.0.0.0", "d" },
954 { "10.0.0.0", "255.0.0.0", "d" },
955 { "128.250.0.0", "255.255.0.0", "d" },
956 { "192.168.0.0", "255.255.0.0", "d" },
957 { "192.168.1.0", "255.255.255.0", "d" },
958#endif
959 { NULL, NULL, NULL }
960};
961
962char *mtable[][1] = {
963#if 1
964 { "192:168:100::2" },
965 { "192:168:101::2" },
966#else
967 { "9.0.0.0" },
968 { "9.0.0.1" },
969 { "11.0.0.0" },
970 { "11.0.0.1" },
971 { "127.0.0.1" },
972 { "127.0.1.0" },
973 { "255.255.255.0" },
974 { "126.0.0.1" },
975 { "128.251.0.0" },
976 { "128.251.0.1" },
977 { "128.251.255.255" },
978 { "129.250.0.0" },
979 { "129.250.0.1" },
980 { "192.168.255.255" },
981#endif
982 { NULL }
983};
984
985
986int forder[22] = {
987 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8,
988 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21
989};
990
991static int nodecount = 0;
992myst_t *myst_top = NULL;
993tabe_t *ttable = NULL;
994
995void add_addr(ipf_rdx_head_t *, int , int);
996void checktree(ipf_rdx_head_t *);
997void delete_addr(ipf_rdx_head_t *rnh, int item);
998void dumptree(ipf_rdx_head_t *rnh);
999void nodeprinter(ipf_rdx_node_t *, void *);
1000void printroots(ipf_rdx_head_t *);
1001void random_add(ipf_rdx_head_t *);
1002void random_delete(ipf_rdx_head_t *);
1003void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int);
1004
1005
1006static void
1007ipf_rx_freenode(node, arg)
1008 ipf_rdx_node_t *node;
1009 void *arg;
1010{
1011 ipf_rdx_head_t *head = arg;
1012 ipf_rdx_node_t *rv;
1013 myst_t *stp;
1014
1015 stp = (myst_t *)node;
1016 rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
1017 if (rv != NULL) {
1018 free(rv);
1019 }
1020}
1021
1022
1023const char *
1024addrname(ap)
1025 addrfamily_t *ap;
1026{
1027 static char name[80];
1028 const char *txt;
1029
1030 bzero((char *)name, sizeof(name));
1031 txt = inet_ntop(ap->adf_family, &ap->adf_addr, name,
1032 sizeof(name));
1033 return txt;
1034}
1035
1036
1037void
1038fill6bits(bits, msk)
1039 int bits;
1040 u_int *msk;
1041{
1042 if (bits == 0) {
1043 msk[0] = 0;
1044 msk[1] = 0;
1045 msk[2] = 0;
1046 msk[3] = 0;
1047 return;
1048 }
1049
1050 msk[0] = 0xffffffff;
1051 msk[1] = 0xffffffff;
1052 msk[2] = 0xffffffff;
1053 msk[3] = 0xffffffff;
1054
1055 if (bits == 128)
1056 return;
1057 if (bits > 96) {
1058 msk[3] = htonl(msk[3] << (128 - bits));
1059 } else if (bits > 64) {
1060 msk[3] = 0;
1061 msk[2] = htonl(msk[2] << (96 - bits));
1062 } else if (bits > 32) {
1063 msk[3] = 0;
1064 msk[2] = 0;
1065 msk[1] = htonl(msk[1] << (64 - bits));
1066 } else {
1067 msk[3] = 0;
1068 msk[2] = 0;
1069 msk[1] = 0;
1070 msk[0] = htonl(msk[0] << (32 - bits));
1071 }
1072}
1073
1074
1075void
1076setaddr(afp, str)
1077 addrfamily_t *afp;
1078 char *str;
1079{
1080
1081 bzero((char *)afp, sizeof(*afp));
1082
1083 if (strchr(str, ':') == NULL) {
1084 afp->adf_family = AF_INET;
1085 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1086 } else {
1087 afp->adf_family = AF_INET6;
1088 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
1089 }
1090 inet_pton(afp->adf_family, str, &afp->adf_addr);
1091}
1092
1093
1094void
1095setmask(afp, str)
1096 addrfamily_t *afp;
1097 char *str;
1098{
1099 if (strchr(str, '.') != NULL) {
1100 afp->adf_addr.in4.s_addr = inet_addr(str);
1101 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1102 } else if (afp->adf_family == AF_INET) {
1103 afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str)));
1104 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1105 } else if (afp->adf_family == AF_INET6) {
1106 fill6bits(atoi(str), afp->adf_addr.i6);
1107 afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
1108 }
1109}
1110
1111
1112void
1113nodeprinter(node, arg)
1114 ipf_rdx_node_t *node;
1115 void *arg;
1116{
1117 myst_t *stp = (myst_t *)node;
1118
1119 printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
1120 node[0].name,
1121 GNAME(node[1].left), GNAME(node[1].right),
1122 GNAME(node[0].parent), GNAME(node[1].parent),
1123 addrname(&stp->dst), node[0].maskbitcount);
1124 if (stp->printed == -1)
1125 printf("!!! %d\n", stp->printed);
1126 else
1127 stp->printed = 1;
1128}
1129
1130
1131void
1132printnode(stp)
1133 myst_t *stp;
1134{
1135 ipf_rdx_node_t *node = &stp->nodes[0];
1136
1137 if (stp->nodes[0].index > 0)
1138 stp = (myst_t *)&stp->nodes[-1];
1139
1140 printf("Node %-9.9s ", node[0].name);
1141 printf("L %-9.9s ", GNAME(node[1].left));
1142 printf("R %-9.9s ", GNAME(node[1].right));
1143 printf("P %9.9s", GNAME(node[0].parent));
1144 printf("/%-9.9s ", GNAME(node[1].parent));
1145 printf("%s P%d\n", addrname(&stp->dst), stp->printed);
1146}
1147
1148
1149void
1150buildtab(void)
1151{
1152 char line[80], *s;
1153 tabe_t *tab;
1154 int lines;
1155 FILE *fp;
1156
1157 lines = 0;
1158 fp = fopen("hosts", "r");
1159
1160 while (fgets(line, sizeof(line), fp) != NULL) {
1161 s = strchr(line, '\n');
1162 if (s != NULL)
1163 *s = '\0';
1164 lines++;
1165 if (lines == 1)
1166 tab = malloc(sizeof(*tab) * 2);
1167 else
1168 tab = realloc(tab, (lines + 1) * sizeof(*tab));
1169 tab[lines - 1].host = strdup(line);
1170 s = strchr(tab[lines - 1].host, '/');
1171 *s++ = '\0';
1172 tab[lines - 1].mask = s;
1173 tab[lines - 1].what = "d";
1174 }
1175 fclose(fp);
1176
1177 tab[lines].host = NULL;
1178 tab[lines].mask = NULL;
1179 tab[lines].what = NULL;
1180 ttable = tab;
1181}
1182
1183
1184void
1185printroots(rnh)
1186 ipf_rdx_head_t *rnh;
1187{
1188 printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1189 GNAME(&rnh->nodes[0]),
1190 rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
1191 GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
1192 printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1193 GNAME(&rnh->nodes[1]),
1194 rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
1195 GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
1196 printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1197 GNAME(&rnh->nodes[2]),
1198 rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
1199 GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
1200}
1201
1202
1203int
1204main(int argc, char *argv[])
1205{
1206 addrfamily_t af;
1207 ipf_rdx_head_t *rnh;
1208 radix_softc_t *ctx;
1209 int j;
1210 int i;
1211
1212 rnh = NULL;
1213
1214 buildtab();
1215 ctx = ipf_rx_create();
1216 ipf_rx_init(ctx);
1217 ipf_rx_inithead(ctx, &rnh);
1218
1219 printf("=== ADD-0 ===\n");
1220 for (i = 0; ttable[i].host != NULL; i++) {
1221 add_addr(rnh, i, i);
1222 checktree(rnh);
1223 }
1224 printroots(rnh);
1225 ipf_rx_walktree(rnh, nodeprinter, NULL);
1226 printf("=== DELETE-0 ===\n");
1227 for (i = 0; ttable[i].host != NULL; i++) {
1228 delete_addr(rnh, i);
1229 printroots(rnh);
1230 ipf_rx_walktree(rnh, nodeprinter, NULL);
1231 }
1232 printf("=== ADD-1 ===\n");
1233 for (i = 0; ttable[i].host != NULL; i++) {
1234 setaddr(&af, ttable[i].host);
1235 add_addr(rnh, i, i); /*forder[i]); */
1236 checktree(rnh);
1237 }
1238 dumptree(rnh);
1239 ipf_rx_walktree(rnh, nodeprinter, NULL);
1240 printf("=== TEST-1 ===\n");
1241 for (i = 0; ttable[i].host != NULL; i++) {
1242 setaddr(&af, ttable[i].host);
1243 test_addr(rnh, i, &af, -1);
1244 }
1245
1246 printf("=== TEST-2 ===\n");
1247 for (i = 0; mtable[i][0] != NULL; i++) {
1248 setaddr(&af, mtable[i][0]);
1249 test_addr(rnh, i, &af, -1);
1250 }
1251 printf("=== DELETE-1 ===\n");
1252 for (i = 0; ttable[i].host != NULL; i++) {
1253 if (ttable[i].what[0] != 'd')
1254 continue;
1255 delete_addr(rnh, i);
1256 for (j = 0; ttable[j].host != NULL; j++) {
1257 setaddr(&af, ttable[j].host);
1258 test_addr(rnh, i, &af, 3);
1259 }
1260 printroots(rnh);
1261 ipf_rx_walktree(rnh, nodeprinter, NULL);
1262 }
1263
1264 dumptree(rnh);
1265
1266 printf("=== ADD-2 ===\n");
1267 random_add(rnh);
1268 checktree(rnh);
1269 dumptree(rnh);
1270 ipf_rx_walktree(rnh, nodeprinter, NULL);
1271 printf("=== DELETE-2 ===\n");
1272 random_delete(rnh);
1273 checktree(rnh);
1274 dumptree(rnh);
1275
1276 ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
1277
1278 return 0;
1279}
1280
1281
1282void
1283dumptree(rnh)
1284 ipf_rdx_head_t *rnh;
1285{
1286 myst_t *stp;
1287
1288 printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
1289 printroots(rnh);
1290 for (stp = myst_top; stp; stp = stp->next)
1291 printnode(stp);
1292 printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
1293}
1294
1295
1296void
1297test_addr(rnh, pref, addr, limit)
1298 ipf_rdx_head_t *rnh;
1299 int pref;
1300 addrfamily_t *addr;
1301{
1302 static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
1303 15, 16, 19, 255, 256, 65535, 65536
1304 };
1305 ipf_rdx_node_t *rn;
1306 addrfamily_t af;
1307 char name[80];
1308 myst_t *stp;
1309 int i;
1310
1311 memset(&af, 0, sizeof(af));
1312#if 0
1313 if (limit < 0 || limit > 14)
1314 limit = 14;
1315
1316 for (i = 0; i < limit; i++) {
1317 if (ttable[i].host == NULL)
1318 break;
1319 setaddr(&af, ttable[i].host);
1320 printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af));
1321 rn = ipf_rx_match(rnh, &af);
1322 stp = (myst_t *)rn;
1323 printf(" = %s (%s/%d)\n", GNAME(rn),
1324 rn ? addrname(&stp->dst) : "NULL",
1325 rn ? rn->maskbitcount : 0);
1326 }
1327#else
1328 printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr));
1329 rn = ipf_rx_match(rnh, addr);
1330 stp = (myst_t *)rn;
1331 printf(" = %s (%s/%d)\n", GNAME(rn),
1332 rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0);
1333#endif
1334}
1335
1336
1337void
1338delete_addr(rnh, item)
1339 ipf_rdx_head_t *rnh;
1340 int item;
1341{
1342 ipf_rdx_node_t *rn;
1343 addrfamily_t mask;
1344 addrfamily_t af;
1345 myst_t **pstp;
1346 myst_t *stp;
1347
1348 memset(&af, 0, sizeof(af));
1349 memset(&mask, 0, sizeof(mask));
1350 setaddr(&af, ttable[item].host);
1351 mask.adf_family = af.adf_family;
1352 setmask(&mask, ttable[item].mask);
1353
1354 printf("DELETE(%s)\n", addrname(&af));
1355 rn = ipf_rx_delete(rnh, &af, &mask);
1356 if (rn == NULL) {
1357 printf("FAIL LOOKUP DELETE\n");
1358 checktree(rnh);
1359 for (stp = myst_top; stp != NULL; stp = stp->next)
1360 if (stp->printed != -1)
1361 stp->printed = -2;
1362 ipf_rx_walktree(rnh, nodeprinter, NULL);
1363 dumptree(rnh);
1364 abort();
1365 }
1366 printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn));
1367
1368 for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
1369 if (stp == (myst_t *)rn)
1370 break;
1371 stp->printed = -1;
1372 stp->nodes[0].parent = &stp->nodes[0];
1373 stp->nodes[1].parent = &stp->nodes[1];
1374 *pstp = stp->next;
1375 free(stp);
1376 nodecount--;
1377 checktree(rnh);
1378}
1379
1380
1381void
1382add_addr(rnh, n, item)
1383 ipf_rdx_head_t *rnh;
1384 int n, item;
1385{
1386 ipf_rdx_node_t *rn;
1387 myst_t *stp;
1388
1389 stp = calloc(1, sizeof(*stp));
1390 rn = (ipf_rdx_node_t *)stp;
1391 setaddr(&stp->dst, ttable[item].host);
1392 stp->mask.adf_family = stp->dst.adf_family;
1393 setmask(&stp->mask, ttable[item].mask);
1394 stp->next = myst_top;
1395 myst_top = stp;
1396 (void) snprintf(rn[0].name, sizeof(rn[0].name), "_BORN.0");
1397 (void) snprintf(rn[1].name, sizeof(rn[1].name), "_BORN.1");
1398 rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
1399 (void) snprintf(rn[0].name, sizeof(rn[0].name), "%d_NODE.0", item);
1400 (void) snprintf(rn[1].name, sizeof(rn[1].name), "%d_NODE.1", item);
1401 printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
1402 nodecount++;
1403 checktree(rnh);
1404}
1405
1406
1407void
1408checktree(ipf_rdx_head_t *head)
1409{
1410 myst_t *s1;
1411 ipf_rdx_node_t *rn;
1412
1413 if (nodecount <= 1)
1414 return;
1415
1416 for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
1417 int fault = 0;
1418 if (s1->printed == -1)
1419 continue;
1420 rn = &s1->nodes[1];
1421 if (rn->right->parent != rn)
1422 fault |= 1;
1423 if (rn->left->parent != rn)
1424 fault |= 2;
1425 if (rn->parent->left != rn && rn->parent->right != rn)
1426 fault |= 4;
1427 if (fault != 0) {
1428 printf("FAULT %#x %s\n", fault, rn->name);
1429 dumptree(head);
1430 ipf_rx_walktree(head, nodeprinter, NULL);
1431 fflush(stdout);
1432 fflush(stderr);
1433 printf("--\n");
1434 abort();
1435 }
1436 }
1437}
1438
1439
1440int *
1441randomize(int *pnitems)
1442{
1443 int *order;
1444 int nitems;
1445 int choice;
1446 int j;
1447 int i;
1448
1449 nitems = sizeof(ttable) / sizeof(ttable[0]);
1450 *pnitems = nitems;
1451 order = calloc(nitems, sizeof(*order));
1452 srandom(getpid() * time(NULL));
1453 memset(order, 0xff, nitems * sizeof(*order));
1454 order[21] = 21;
1455 for (i = 0; i < nitems - 1; i++) {
1456 do {
1457 choice = rand() % (nitems - 1);
1458 for (j = 0; j < nitems; j++)
1459 if (order[j] == choice)
1460 break;
1461 } while (j != nitems);
1462 order[i] = choice;
1463 }
1464
1465 return order;
1466}
1467
1468
1469void
1470random_add(rnh)
1471 ipf_rdx_head_t *rnh;
1472{
1473 int *order;
1474 int nitems;
1475 int i;
1476
1477 order = randomize(&nitems);
1478
1479 for (i = 0; i < nitems - 1; i++) {
1480 add_addr(rnh, i, order[i]);
1481 checktree(rnh);
1482 }
1483
1484 free(order);
1485}
1486
1487
1488void
1489random_delete(rnh)
1490 ipf_rdx_head_t *rnh;
1491{
1492 int *order;
1493 int nitems;
1494 int i;
1495
1496 order = randomize(&nitems);
1497
1498 for (i = 0; i < nitems - 1; i++) {
1499 delete_addr(rnh, i);
1500 checktree(rnh);
1501 }
1502
1503 free(order);
1504}
1505#endif /* RDX_DEBUG */
1506