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