1 /* $OpenBSD: art.c,v 1.28 2019/03/31 19:29:27 tb Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Martin Pieuchot 5 * Copyright (c) 2001 Yoichi Hariguchi 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * Allotment Routing Table (ART). 22 * 23 * Yoichi Hariguchi paper can be found at: 24 * http://www.hariguchi.org/art/art.pdf 25 */ 26 27 #ifndef _KERNEL 28 #include "kern_compat.h" 29 #else 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/malloc.h> 33 #include <sys/pool.h> 34 #include <sys/task.h> 35 #include <sys/socket.h> 36 #endif 37 38 #include <net/art.h> 39 40 int art_bindex(struct art_table *, uint8_t *, int); 41 void art_allot(struct art_table *at, int, struct art_node *, 42 struct art_node *); 43 struct art_table *art_table_get(struct art_root *, struct art_table *, 44 int); 45 struct art_table *art_table_put(struct art_root *, struct art_table *); 46 struct art_node *art_table_insert(struct art_root *, struct art_table *, 47 int, struct art_node *); 48 struct art_node *art_table_delete(struct art_root *, struct art_table *, 49 int, struct art_node *); 50 struct art_table *art_table_ref(struct art_root *, struct art_table *); 51 int art_table_free(struct art_root *, struct art_table *); 52 int art_table_walk(struct art_root *, struct art_table *, 53 int (*f)(struct art_node *, void *), void *); 54 int art_walk_apply(struct art_root *, 55 struct art_node *, struct art_node *, 56 int (*f)(struct art_node *, void *), void *); 57 void art_table_gc(void *); 58 void art_gc(void *); 59 60 struct pool an_pool, at_pool, at_heap_4_pool, at_heap_8_pool; 61 62 struct art_table *art_table_gc_list = NULL; 63 struct mutex art_table_gc_mtx = MUTEX_INITIALIZER(IPL_SOFTNET); 64 struct task art_table_gc_task = 65 TASK_INITIALIZER(art_table_gc, NULL); 66 67 struct art_node *art_node_gc_list = NULL; 68 struct mutex art_node_gc_mtx = MUTEX_INITIALIZER(IPL_SOFTNET); 69 struct task art_node_gc_task = TASK_INITIALIZER(art_gc, NULL); 70 71 void 72 art_init(void) 73 { 74 pool_init(&an_pool, sizeof(struct art_node), 0, IPL_SOFTNET, 0, 75 "art_node", NULL); 76 pool_init(&at_pool, sizeof(struct art_table), 0, IPL_SOFTNET, 0, 77 "art_table", NULL); 78 pool_init(&at_heap_4_pool, AT_HEAPSIZE(4), 0, IPL_SOFTNET, 0, 79 "art_heap4", NULL); 80 pool_init(&at_heap_8_pool, AT_HEAPSIZE(8), 0, IPL_SOFTNET, 0, 81 "art_heap8", &pool_allocator_single); 82 } 83 84 /* 85 * Per routing table initialization API function. 86 */ 87 struct art_root * 88 art_alloc(unsigned int rtableid, unsigned int alen, unsigned int off) 89 { 90 struct art_root *ar; 91 int i; 92 93 ar = malloc(sizeof(*ar), M_RTABLE, M_NOWAIT|M_ZERO); 94 if (ar == NULL) 95 return (NULL); 96 97 switch (alen) { 98 case 32: 99 ar->ar_alen = 32; 100 ar->ar_nlvl = 7; 101 ar->ar_bits[0] = 8; 102 for (i = 1; i < ar->ar_nlvl; i++) 103 ar->ar_bits[i] = 4; 104 break; 105 case 128: 106 ar->ar_alen = 128; 107 ar->ar_nlvl = 32; 108 for (i = 0; i < ar->ar_nlvl; i++) 109 ar->ar_bits[i] = 4; 110 break; 111 default: 112 printf("%s: incorrect address length %u\n", __func__, alen); 113 free(ar, M_RTABLE, sizeof(*ar)); 114 return (NULL); 115 } 116 117 ar->ar_off = off; 118 ar->ar_rtableid = rtableid; 119 rw_init(&ar->ar_lock, "art"); 120 121 return (ar); 122 } 123 124 /* 125 * Return 1 if ``old'' and ``new`` are identical, 0 otherwise. 126 */ 127 static inline int 128 art_check_duplicate(struct art_root *ar, struct art_node *old, 129 struct art_node *new) 130 { 131 if (old == NULL) 132 return (0); 133 134 if (old->an_plen == new->an_plen) 135 return (1); 136 137 return (0); 138 } 139 140 /* 141 * Return the base index of the part of ``addr'' and ``plen'' 142 * corresponding to the range covered by the table ``at''. 143 * 144 * In other words, this function take the multi-level (complete) 145 * address ``addr'' and prefix length ``plen'' and return the 146 * single level base index for the table ``at''. 147 * 148 * For example with an address size of 32bit divided into four 149 * 8bit-long tables, there's a maximum of 4 base indexes if the 150 * prefix length is > 24. 151 */ 152 int 153 art_bindex(struct art_table *at, uint8_t *addr, int plen) 154 { 155 uint8_t boff, bend; 156 uint32_t k; 157 158 if (plen < at->at_offset || plen > (at->at_offset + at->at_bits)) 159 return (-1); 160 161 /* 162 * We are only interested in the part of the prefix length 163 * corresponding to the range of this table. 164 */ 165 plen -= at->at_offset; 166 167 /* 168 * Jump to the first byte of the address containing bits 169 * covered by this table. 170 */ 171 addr += (at->at_offset / 8); 172 173 /* ``at'' covers the bit range between ``boff'' & ``bend''. */ 174 boff = (at->at_offset % 8); 175 bend = (at->at_bits + boff); 176 177 KASSERT(bend <= 32); 178 179 if (bend > 24) { 180 k = (addr[0] & ((1 << (8 - boff)) - 1)) << (bend - 8); 181 k |= addr[1] << (bend - 16); 182 k |= addr[2] << (bend - 24); 183 k |= addr[3] >> (32 - bend); 184 } else if (bend > 16) { 185 k = (addr[0] & ((1 << (8 - boff)) - 1)) << (bend - 8); 186 k |= addr[1] << (bend - 16); 187 k |= addr[2] >> (24 - bend); 188 } else if (bend > 8) { 189 k = (addr[0] & ((1 << (8 - boff)) - 1)) << (bend - 8); 190 k |= addr[1] >> (16 - bend); 191 } else { 192 k = (addr[0] >> (8 - bend)) & ((1 << at->at_bits) - 1); 193 } 194 195 /* 196 * Single level base index formula: 197 */ 198 return ((k >> (at->at_bits - plen)) + (1 << plen)); 199 } 200 201 /* 202 * Single level lookup function. 203 * 204 * Return the fringe index of the part of ``addr'' 205 * corresponding to the range covered by the table ``at''. 206 */ 207 static inline int 208 art_findex(struct art_table *at, uint8_t *addr) 209 { 210 return art_bindex(at, addr, (at->at_offset + at->at_bits)); 211 } 212 213 /* 214 * (Non-perfect) lookup API function. 215 * 216 * Return the best existing match for a destination. 217 */ 218 struct art_node * 219 art_match(struct art_root *ar, void *addr, struct srp_ref *nsr) 220 { 221 struct srp_ref dsr, ndsr; 222 void *entry; 223 struct art_table *at; 224 struct art_node *dflt, *ndflt; 225 int j; 226 227 entry = srp_enter(nsr, &ar->ar_root); 228 at = entry; 229 230 if (at == NULL) 231 goto done; 232 233 /* 234 * Remember the default route of each table we visit in case 235 * we do not find a better matching route. 236 */ 237 dflt = srp_enter(&dsr, &at->at_default); 238 239 /* 240 * Iterate until we find a leaf. 241 */ 242 while (1) { 243 /* Do a single level route lookup. */ 244 j = art_findex(at, addr); 245 entry = srp_follow(nsr, &at->at_heap[j].node); 246 247 /* If this is a leaf (NULL is a leaf) we're done. */ 248 if (ISLEAF(entry)) 249 break; 250 251 at = SUBTABLE(entry); 252 253 ndflt = srp_enter(&ndsr, &at->at_default); 254 if (ndflt != NULL) { 255 srp_leave(&dsr); 256 dsr = ndsr; 257 dflt = ndflt; 258 } else 259 srp_leave(&ndsr); 260 } 261 262 if (entry == NULL) { 263 srp_leave(nsr); 264 *nsr = dsr; 265 KASSERT(ISLEAF(dflt)); 266 return (dflt); 267 } 268 269 srp_leave(&dsr); 270 done: 271 KASSERT(ISLEAF(entry)); 272 return (entry); 273 } 274 275 /* 276 * Perfect lookup API function. 277 * 278 * Return a perfect match for a destination/prefix-length pair or NULL if 279 * it does not exist. 280 */ 281 struct art_node * 282 art_lookup(struct art_root *ar, void *addr, int plen, struct srp_ref *nsr) 283 { 284 void *entry; 285 struct art_table *at; 286 int i, j; 287 288 KASSERT(plen >= 0 && plen <= ar->ar_alen); 289 290 entry = srp_enter(nsr, &ar->ar_root); 291 at = entry; 292 293 if (at == NULL) 294 goto done; 295 296 /* Default route */ 297 if (plen == 0) { 298 entry = srp_follow(nsr, &at->at_default); 299 goto done; 300 } 301 302 /* 303 * If the prefix length is smaller than the sum of 304 * the stride length at this level the entry must 305 * be in the current table. 306 */ 307 while (plen > (at->at_offset + at->at_bits)) { 308 /* Do a single level route lookup. */ 309 j = art_findex(at, addr); 310 entry = srp_follow(nsr, &at->at_heap[j].node); 311 312 /* A leaf is a match, but not a perfect one, or NULL */ 313 if (ISLEAF(entry)) 314 return (NULL); 315 316 at = SUBTABLE(entry); 317 } 318 319 i = art_bindex(at, addr, plen); 320 if (i == -1) 321 return (NULL); 322 323 entry = srp_follow(nsr, &at->at_heap[i].node); 324 if (!ISLEAF(entry)) 325 entry = srp_follow(nsr, &SUBTABLE(entry)->at_default); 326 327 done: 328 KASSERT(ISLEAF(entry)); 329 return (entry); 330 } 331 332 333 /* 334 * Insertion API function. 335 * 336 * Insert the given node or return an existing one if a node with the 337 * same destination/mask pair is already present. 338 */ 339 struct art_node * 340 art_insert(struct art_root *ar, struct art_node *an, void *addr, int plen) 341 { 342 struct art_table *at, *child; 343 struct art_node *node; 344 int i, j; 345 346 rw_assert_wrlock(&ar->ar_lock); 347 KASSERT(plen >= 0 && plen <= ar->ar_alen); 348 349 at = srp_get_locked(&ar->ar_root); 350 if (at == NULL) { 351 at = art_table_get(ar, NULL, -1); 352 if (at == NULL) 353 return (NULL); 354 355 srp_swap_locked(&ar->ar_root, at); 356 } 357 358 /* Default route */ 359 if (plen == 0) { 360 node = srp_get_locked(&at->at_default); 361 if (node != NULL) 362 return (node); 363 364 art_table_ref(ar, at); 365 srp_swap_locked(&at->at_default, an); 366 return (an); 367 } 368 369 /* 370 * If the prefix length is smaller than the sum of 371 * the stride length at this level the entry must 372 * be in the current table. 373 */ 374 while (plen > (at->at_offset + at->at_bits)) { 375 /* Do a single level route lookup. */ 376 j = art_findex(at, addr); 377 node = srp_get_locked(&at->at_heap[j].node); 378 379 /* 380 * If the node corresponding to the fringe index is 381 * a leaf we need to allocate a subtable. The route 382 * entry of this node will then become the default 383 * route of the subtable. 384 */ 385 if (ISLEAF(node)) { 386 child = art_table_get(ar, at, j); 387 if (child == NULL) 388 return (NULL); 389 390 art_table_ref(ar, at); 391 srp_swap_locked(&at->at_heap[j].node, ASNODE(child)); 392 at = child; 393 } else 394 at = SUBTABLE(node); 395 } 396 397 i = art_bindex(at, addr, plen); 398 if (i == -1) 399 return (NULL); 400 401 return (art_table_insert(ar, at, i, an)); 402 } 403 404 /* 405 * Single level insertion. 406 */ 407 struct art_node * 408 art_table_insert(struct art_root *ar, struct art_table *at, int i, 409 struct art_node *an) 410 { 411 struct art_node *prev, *node; 412 413 node = srp_get_locked(&at->at_heap[i].node); 414 if (!ISLEAF(node)) 415 prev = srp_get_locked(&SUBTABLE(node)->at_default); 416 else 417 prev = node; 418 419 if (art_check_duplicate(ar, prev, an)) 420 return (prev); 421 422 art_table_ref(ar, at); 423 424 /* 425 * If the index `i' of the route that we are inserting is not 426 * a fringe index, we need to allot this new route pointer to 427 * all the corresponding fringe indices. 428 */ 429 if (i < at->at_minfringe) 430 art_allot(at, i, prev, an); 431 else if (!ISLEAF(node)) 432 srp_swap_locked(&SUBTABLE(node)->at_default, an); 433 else 434 srp_swap_locked(&at->at_heap[i].node, an); 435 436 return (an); 437 } 438 439 440 /* 441 * Deletion API function. 442 */ 443 struct art_node * 444 art_delete(struct art_root *ar, struct art_node *an, void *addr, int plen) 445 { 446 struct art_table *at; 447 struct art_node *node; 448 int i, j; 449 450 rw_assert_wrlock(&ar->ar_lock); 451 KASSERT(plen >= 0 && plen <= ar->ar_alen); 452 453 at = srp_get_locked(&ar->ar_root); 454 if (at == NULL) 455 return (NULL); 456 457 /* Default route */ 458 if (plen == 0) { 459 node = srp_get_locked(&at->at_default); 460 srp_swap_locked(&at->at_default, NULL); 461 art_table_free(ar, at); 462 return (node); 463 } 464 465 /* 466 * If the prefix length is smaller than the sum of 467 * the stride length at this level the entry must 468 * be in the current table. 469 */ 470 while (plen > (at->at_offset + at->at_bits)) { 471 /* Do a single level route lookup. */ 472 j = art_findex(at, addr); 473 node = srp_get_locked(&at->at_heap[j].node); 474 475 /* If this is a leaf, there is no route to delete. */ 476 if (ISLEAF(node)) 477 return (NULL); 478 479 at = SUBTABLE(node); 480 } 481 482 i = art_bindex(at, addr, plen); 483 if (i == -1) 484 return (NULL); 485 486 return (art_table_delete(ar, at, i, an)); 487 } 488 489 /* 490 * Single level deletion. 491 */ 492 struct art_node * 493 art_table_delete(struct art_root *ar, struct art_table *at, int i, 494 struct art_node *an) 495 { 496 struct art_node *next, *node; 497 498 #ifdef DIAGNOSTIC 499 struct art_node *prev; 500 #endif 501 502 node = srp_get_locked(&at->at_heap[i].node); 503 #ifdef DIAGNOSTIC 504 if (!ISLEAF(node)) 505 prev = srp_get_locked(&SUBTABLE(node)->at_default); 506 else 507 prev = node; 508 509 KASSERT(prev == an); 510 #endif 511 512 /* Get the next most specific route for the index `i'. */ 513 if ((i >> 1) > 1) 514 next = srp_get_locked(&at->at_heap[i >> 1].node); 515 else 516 next = NULL; 517 518 /* 519 * If the index `i' of the route that we are removing is not 520 * a fringe index, we need to allot the next most specific 521 * route pointer to all the corresponding fringe indices. 522 */ 523 if (i < at->at_minfringe) 524 art_allot(at, i, an, next); 525 else if (!ISLEAF(node)) 526 srp_swap_locked(&SUBTABLE(node)->at_default, next); 527 else 528 srp_swap_locked(&at->at_heap[i].node, next); 529 530 /* We have removed an entry from this table. */ 531 art_table_free(ar, at); 532 533 return (an); 534 } 535 536 struct art_table * 537 art_table_ref(struct art_root *ar, struct art_table *at) 538 { 539 at->at_refcnt++; 540 return (at); 541 } 542 543 static inline int 544 art_table_rele(struct art_table *at) 545 { 546 if (at == NULL) 547 return (0); 548 549 return (--at->at_refcnt == 0); 550 } 551 552 int 553 art_table_free(struct art_root *ar, struct art_table *at) 554 { 555 if (art_table_rele(at)) { 556 /* 557 * Garbage collect this table and all its parents 558 * that are empty. 559 */ 560 do { 561 at = art_table_put(ar, at); 562 } while (art_table_rele(at)); 563 564 return (1); 565 } 566 567 return (0); 568 } 569 570 /* 571 * Iteration API function. 572 */ 573 int 574 art_walk(struct art_root *ar, int (*f)(struct art_node *, void *), void *arg) 575 { 576 struct srp_ref sr; 577 struct art_table *at; 578 struct art_node *node; 579 int error = 0; 580 581 rw_enter_write(&ar->ar_lock); 582 at = srp_get_locked(&ar->ar_root); 583 if (at != NULL) { 584 art_table_ref(ar, at); 585 586 /* 587 * The default route should be processed here because the root 588 * table does not have a parent. 589 */ 590 node = srp_enter(&sr, &at->at_default); 591 error = art_walk_apply(ar, node, NULL, f, arg); 592 srp_leave(&sr); 593 594 if (error == 0) 595 error = art_table_walk(ar, at, f, arg); 596 597 art_table_free(ar, at); 598 } 599 rw_exit_write(&ar->ar_lock); 600 601 return (error); 602 } 603 604 int 605 art_table_walk(struct art_root *ar, struct art_table *at, 606 int (*f)(struct art_node *, void *), void *arg) 607 { 608 struct srp_ref sr; 609 struct art_node *node, *next; 610 struct art_table *nat; 611 int i, j, error = 0; 612 uint32_t maxfringe = (at->at_minfringe << 1); 613 614 /* 615 * Iterate non-fringe nodes in ``natural'' order. 616 */ 617 for (j = 1; j < at->at_minfringe; j += 2) { 618 /* 619 * The default route (index 1) is processed by the 620 * parent table (where it belongs) otherwise it could 621 * be processed more than once. 622 */ 623 for (i = max(j, 2); i < at->at_minfringe; i <<= 1) { 624 next = srp_get_locked(&at->at_heap[i >> 1].node); 625 626 node = srp_enter(&sr, &at->at_heap[i].node); 627 error = art_walk_apply(ar, node, next, f, arg); 628 srp_leave(&sr); 629 630 if (error != 0) 631 return (error); 632 } 633 } 634 635 /* 636 * Iterate fringe nodes. 637 */ 638 for (i = at->at_minfringe; i < maxfringe; i++) { 639 next = srp_get_locked(&at->at_heap[i >> 1].node); 640 641 node = srp_enter(&sr, &at->at_heap[i].node); 642 if (!ISLEAF(node)) { 643 nat = art_table_ref(ar, SUBTABLE(node)); 644 node = srp_follow(&sr, &nat->at_default); 645 } else 646 nat = NULL; 647 648 error = art_walk_apply(ar, node, next, f, arg); 649 srp_leave(&sr); 650 651 if (error != 0) { 652 art_table_free(ar, nat); 653 return (error); 654 } 655 656 if (nat != NULL) { 657 error = art_table_walk(ar, nat, f, arg); 658 art_table_free(ar, nat); 659 if (error != 0) 660 return (error); 661 } 662 } 663 664 return (0); 665 } 666 667 int 668 art_walk_apply(struct art_root *ar, 669 struct art_node *an, struct art_node *next, 670 int (*f)(struct art_node *, void *), void *arg) 671 { 672 int error = 0; 673 674 if ((an != NULL) && (an != next)) { 675 rw_exit_write(&ar->ar_lock); 676 error = (*f)(an, arg); 677 rw_enter_write(&ar->ar_lock); 678 } 679 680 return (error); 681 } 682 683 684 /* 685 * Create a table and use the given index to set its default route. 686 * 687 * Note: This function does not modify the root or the parent. 688 */ 689 struct art_table * 690 art_table_get(struct art_root *ar, struct art_table *parent, int j) 691 { 692 struct art_table *at; 693 struct art_node *node; 694 void *at_heap; 695 uint32_t lvl; 696 697 KASSERT(j != 0 && j != 1); 698 KASSERT(parent != NULL || j == -1); 699 700 if (parent != NULL) 701 lvl = parent->at_level + 1; 702 else 703 lvl = 0; 704 705 KASSERT(lvl < ar->ar_nlvl); 706 707 at = pool_get(&at_pool, PR_NOWAIT|PR_ZERO); 708 if (at == NULL) 709 return (NULL); 710 711 switch (AT_HEAPSIZE(ar->ar_bits[lvl])) { 712 case AT_HEAPSIZE(4): 713 at_heap = pool_get(&at_heap_4_pool, PR_NOWAIT|PR_ZERO); 714 break; 715 case AT_HEAPSIZE(8): 716 at_heap = pool_get(&at_heap_8_pool, PR_NOWAIT|PR_ZERO); 717 break; 718 default: 719 panic("incorrect stride length %u", ar->ar_bits[lvl]); 720 } 721 722 if (at_heap == NULL) { 723 pool_put(&at_pool, at); 724 return (NULL); 725 } 726 727 at->at_parent = parent; 728 at->at_index = j; 729 at->at_minfringe = (1 << ar->ar_bits[lvl]); 730 at->at_level = lvl; 731 at->at_bits = ar->ar_bits[lvl]; 732 at->at_heap = at_heap; 733 at->at_refcnt = 0; 734 735 if (parent != NULL) { 736 node = srp_get_locked(&parent->at_heap[j].node); 737 /* node isn't being deleted, no srp_finalize needed */ 738 srp_swap_locked(&at->at_default, node); 739 at->at_offset = (parent->at_offset + parent->at_bits); 740 } 741 742 return (at); 743 } 744 745 746 /* 747 * Delete a table and use its index to restore its parent's default route. 748 * 749 * Note: Modify its parent to unlink the table from it. 750 */ 751 struct art_table * 752 art_table_put(struct art_root *ar, struct art_table *at) 753 { 754 struct art_table *parent = at->at_parent; 755 struct art_node *node; 756 uint32_t j = at->at_index; 757 758 KASSERT(at->at_refcnt == 0); 759 KASSERT(j != 0 && j != 1); 760 761 if (parent != NULL) { 762 KASSERT(j != -1); 763 KASSERT(at->at_level == parent->at_level + 1); 764 KASSERT(parent->at_refcnt >= 1); 765 766 /* Give the route back to its parent. */ 767 node = srp_get_locked(&at->at_default); 768 srp_swap_locked(&parent->at_heap[j].node, node); 769 } else { 770 KASSERT(j == -1); 771 KASSERT(at->at_level == 0); 772 srp_swap_locked(&ar->ar_root, NULL); 773 } 774 775 mtx_enter(&art_table_gc_mtx); 776 at->at_parent = art_table_gc_list; 777 art_table_gc_list = at; 778 mtx_leave(&art_table_gc_mtx); 779 780 task_add(systqmp, &art_table_gc_task); 781 782 return (parent); 783 } 784 785 void 786 art_table_gc(void *null) 787 { 788 struct art_table *at, *next; 789 790 mtx_enter(&art_table_gc_mtx); 791 at = art_table_gc_list; 792 art_table_gc_list = NULL; 793 mtx_leave(&art_table_gc_mtx); 794 795 while (at != NULL) { 796 next = at->at_parent; 797 798 if (at->at_level == 0) 799 srp_finalize(at, "arttfini"); 800 else 801 srp_finalize(ASNODE(at), "arttfini"); 802 803 switch (AT_HEAPSIZE(at->at_bits)) { 804 case AT_HEAPSIZE(4): 805 pool_put(&at_heap_4_pool, at->at_heap); 806 break; 807 case AT_HEAPSIZE(8): 808 pool_put(&at_heap_8_pool, at->at_heap); 809 break; 810 default: 811 panic("incorrect stride length %u", at->at_bits); 812 } 813 814 pool_put(&at_pool, at); 815 816 at = next; 817 } 818 } 819 820 /* 821 * Substitute a node by another in the subtree whose root index is given. 822 * 823 * This function iterates on the table ``at'' at index ``i'' until no 824 * more ``old'' node can be replaced by ``new''. 825 * 826 * This function was originally written by Don Knuth in CWEB. The 827 * complicated ``goto''s are the result of expansion of the two 828 * following recursions: 829 * 830 * art_allot(at, i, old, new) 831 * { 832 * int k = i; 833 * if (at->at_heap[k] == old) 834 * at->at_heap[k] = new; 835 * if (k >= at->at_minfringe) 836 * return; 837 * k <<= 1; 838 * art_allot(at, k, old, new); 839 * k++; 840 * art_allot(at, k, old, new); 841 * } 842 */ 843 void 844 art_allot(struct art_table *at, int i, struct art_node *old, 845 struct art_node *new) 846 { 847 struct art_node *node, *dflt; 848 int k = i; 849 850 KASSERT(i < at->at_minfringe); 851 852 again: 853 k <<= 1; 854 if (k < at->at_minfringe) 855 goto nonfringe; 856 857 /* Change fringe nodes. */ 858 while (1) { 859 node = srp_get_locked(&at->at_heap[k].node); 860 if (!ISLEAF(node)) { 861 dflt = srp_get_locked(&SUBTABLE(node)->at_default); 862 if (dflt == old) { 863 srp_swap_locked(&SUBTABLE(node)->at_default, 864 new); 865 } 866 } else if (node == old) { 867 srp_swap_locked(&at->at_heap[k].node, new); 868 } 869 if (k % 2) 870 goto moveup; 871 k++; 872 } 873 874 nonfringe: 875 node = srp_get_locked(&at->at_heap[k].node); 876 if (node == old) 877 goto again; 878 moveon: 879 if (k % 2) 880 goto moveup; 881 k++; 882 goto nonfringe; 883 moveup: 884 k >>= 1; 885 srp_swap_locked(&at->at_heap[k].node, new); 886 887 /* Change non-fringe node. */ 888 if (k != i) 889 goto moveon; 890 } 891 892 struct art_node * 893 art_get(void *dst, uint8_t plen) 894 { 895 struct art_node *an; 896 897 an = pool_get(&an_pool, PR_NOWAIT | PR_ZERO); 898 if (an == NULL) 899 return (NULL); 900 901 an->an_plen = plen; 902 SRPL_INIT(&an->an_rtlist); 903 904 return (an); 905 } 906 907 void 908 art_put(struct art_node *an) 909 { 910 KASSERT(SRPL_EMPTY_LOCKED(&an->an_rtlist)); 911 912 mtx_enter(&art_node_gc_mtx); 913 an->an_gc = art_node_gc_list; 914 art_node_gc_list = an; 915 mtx_leave(&art_node_gc_mtx); 916 917 task_add(systqmp, &art_node_gc_task); 918 } 919 920 void 921 art_gc(void *null) 922 { 923 struct art_node *an, *next; 924 925 mtx_enter(&art_node_gc_mtx); 926 an = art_node_gc_list; 927 art_node_gc_list = NULL; 928 mtx_leave(&art_node_gc_mtx); 929 930 while (an != NULL) { 931 next = an->an_gc; 932 933 srp_finalize(an, "artnfini"); 934 935 pool_put(&an_pool, an); 936 937 an = next; 938 } 939 } 940