alpm_lib_trie4.c (75360B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * File: trie.c 7 * Purpose: Custom Trie Data structure 8 * Requires: 9 */ 10 11 /* Implementation notes: 12 * Trie is a prefix based data strucutre. It is based on modification to digital search trie. 13 * This implementation is not a Path compressed Binary Trie (or) a Patricia Trie. 14 * It is a custom version which represents prefix on a digital search trie as following. 15 * A given node on the trie could be a Payload node or a Internal node. Each node is represented 16 * by <skip address, skip length> pair. Each node represents the given prefix it represents when 17 * the prefix is viewed from Right to Left. ie., Most significant bits to Least significant bits. 18 * Each node has a Right & Left child which branches based on bit on that position. 19 * There can be empty split node i.e, <0,0> just to host two of its children. 20 */ 21 #include <soc/types.h> 22 #include <soc/drv.h> 23 #include <shared/bsl.h> 24 25 #ifdef ALPM_ENABLE 26 27 #include <shared/util.h> 28 #include <sal/appl/sal.h> 29 #include <sal/core/libc.h> 30 #include <sal/core/time.h> 31 #include <bcm_int/esw/alpm_lib_trie.h> 32 33 extern void * alpm_util_alloc(unsigned int sz, char *s); 34 extern void alpm_util_free(void *addr); 35 36 /********************************************************/ 37 /* Get a chunk of bits from a key (MSB bit - on word0, lsb on word 1), pos is 1 based(msb bit position).. 38 */ 39 static uint32 _alpm_lib_key_get_bits(uint32 *key, uint32 pos, uint32 len) 40 { 41 uint32 val=0, delta=0, diff, bitpos; 42 43 bitpos = (pos-1) % _NUM_WORD_BITS_; 44 bitpos++; /* 1 based */ 45 46 if (bitpos >= len) { 47 diff = bitpos - len; 48 /* coverity[var_deref_op : FALSE] */ 49 val = TRIE_SHR(key[KEY48_BIT2IDX(pos)], diff, _NUM_WORD_BITS_); 50 val &= TRIE_MASK(len); 51 return val; 52 } else { 53 diff = len - bitpos; 54 /* coverity[var_deref_op : FALSE] */ 55 val = key[KEY48_BIT2IDX(pos)] & TRIE_MASK(bitpos); 56 val = TRIE_SHL(val, diff, _NUM_WORD_BITS_); 57 /* get bits from next word */ 58 delta = _alpm_lib_key_get_bits(key, pos-bitpos, diff); 59 return (delta | val); 60 } 61 } 62 63 /* 64 * Assumes the layout for 65 * 0 - most significant word 66 * MAX_KEY_WORDS - least significant word 67 * eg., for key size of 48, word0-[bits 48-32] word1-[bits31-0] 68 */ 69 static int _key_shift_left(uint32 *key, uint32 shift) 70 { 71 uint32 index=0; 72 for (index=KEY48_BIT2IDX(_MAX_KEY_LEN_48_); index < KEY48_BIT2IDX(1); index++) { 73 key[index] = TRIE_SHL(key[index], shift,_NUM_WORD_BITS_) | \ 74 TRIE_SHR(key[index+1],_NUM_WORD_BITS_-shift,_NUM_WORD_BITS_); 75 } 76 77 key[index] = TRIE_SHL(key[index], shift, _NUM_WORD_BITS_); 78 79 /* mask off snippets bit on MSW */ 80 key[0] &= _MASK(_MAX_KEY_LEN_48_ % _NUM_WORD_BITS_); 81 return SOC_E_NONE; 82 } 83 84 /* 85 * Assumes the layout for 86 * 0 - most significant word 87 * MAX_KEY_WORDS - least significant word 88 * eg., for key size of 48, word0-[bits 48-32] word1-[bits31-0] 89 */ 90 static int _key_shift_right(uint32 *key, uint32 shift) 91 { 92 uint32 index=0; 93 for(index=KEY48_BIT2IDX(1); index > KEY48_BIT2IDX(_MAX_KEY_LEN_48_); index--) { 94 key[index] = TRIE_SHR(key[index], shift,_NUM_WORD_BITS_) | \ 95 TRIE_SHL(key[index-1],_NUM_WORD_BITS_-shift,_NUM_WORD_BITS_); 96 } 97 98 key[index] = TRIE_SHR(key[index], shift, _NUM_WORD_BITS_); 99 100 /* mask off snippets bit on MSW */ 101 key[0] &= _MASK(_MAX_KEY_LEN_48_ % _NUM_WORD_BITS_); 102 return SOC_E_NONE; 103 } 104 105 106 /* 107 * Assumes the layout for 108 * 0 - most significant word 109 * MAX_KEY_WORDS - least significant word 110 * eg., for key size of 48, word0-[bits 48-32] word1-[bits31-0] 111 */ 112 static int _key_append(uint32 *key, 113 uint32 *length, 114 uint32 skip_addr, 115 uint32 skip_len) 116 { 117 int rv=SOC_E_NONE; 118 rv = _key_shift_left(key, skip_len); 119 if (SOC_SUCCESS(rv)) { 120 key[KEY48_BIT2IDX(1)] |= skip_addr; 121 *length += skip_len; 122 } 123 124 return rv; 125 } 126 127 /* 128 * Function: 129 * lcplen 130 * Purpose: 131 * returns longest common prefix length provided a key & skip address 132 */ 133 static uint32 134 lcplen(uint32 *key, uint32 len1, 135 uint32 skip_addr, uint32 len2) 136 { 137 uint32 diff; 138 uint32 lcp = len1 < len2 ? len1 : len2; 139 140 if (len1 == 0 || len2 == 0) return 0; 141 142 diff = _alpm_lib_key_get_bits(key, len1, lcp); 143 diff ^= (TRIE_SHR(skip_addr, len2 - lcp, _MAX_SKIP_LEN_) & TRIE_MASK(lcp)); 144 145 while (diff) { 146 diff >>= 1; 147 --lcp; 148 } 149 150 return lcp; 151 } 152 153 int _alpm_lib_print_trie_node(alpm_lib_trie_node_t *trie, void *datum) 154 { 155 if (trie != NULL) { 156 157 LOG_CLI((BSL_META("trie: %p, type %s, skip_addr 0x%x skip_len %d " 158 "count:%d Child[0]:%p Child[1]:%p\n"), 159 trie, (trie->type == trieNodeTypePayload)?"P":"I", 160 trie->skip_addr, trie->skip_len, 161 trie->count, trie->child[0], 162 trie->child[1])); 163 } 164 return SOC_E_NONE; 165 } 166 167 static int _trie_preorder_traverse(alpm_lib_trie_node_t *trie, alpm_lib_trie_callback_f cb, void *user_data) 168 { 169 int rv = SOC_E_NONE; 170 alpm_lib_trie_node_t *tmp1, *tmp2; 171 172 if (trie == NULL || !cb) { 173 return SOC_E_NONE; 174 } else { 175 /* make the node delete safe */ 176 tmp1 = trie->child[0]; 177 tmp2 = trie->child[1]; 178 rv = cb(trie, user_data); 179 } 180 181 if (SOC_SUCCESS(rv)) { 182 rv = _trie_preorder_traverse(tmp1, cb, user_data); 183 } 184 if (SOC_SUCCESS(rv)) { 185 rv = _trie_preorder_traverse(tmp2, cb, user_data); 186 } 187 return rv; 188 } 189 190 static int _trie_postorder_traverse(alpm_lib_trie_node_t *trie, alpm_lib_trie_callback_f cb, void *user_data) 191 { 192 int rv = SOC_E_NONE; 193 194 if (trie == NULL) { 195 return SOC_E_NONE; 196 } 197 198 if (SOC_SUCCESS(rv)) { 199 rv = _trie_postorder_traverse(trie->child[0], cb, user_data); 200 } 201 if (SOC_SUCCESS(rv)) { 202 rv = _trie_postorder_traverse(trie->child[1], cb, user_data); 203 } 204 if (SOC_SUCCESS(rv)) { 205 rv = cb(trie, user_data); 206 } 207 return rv; 208 } 209 210 static int _trie_inorder_traverse(alpm_lib_trie_node_t *trie, alpm_lib_trie_callback_f cb, void *user_data) 211 { 212 int rv = SOC_E_NONE; 213 alpm_lib_trie_node_t *tmp; 214 215 if (trie == NULL) { 216 return SOC_E_NONE; 217 } 218 219 if (SOC_SUCCESS(rv)) { 220 rv = _trie_inorder_traverse(trie->child[0], cb, user_data); 221 } 222 223 /* make the trie pointers delete safe */ 224 tmp = trie->child[1]; 225 226 if (SOC_SUCCESS(rv)) { 227 rv = cb(trie, user_data); 228 } 229 230 if (SOC_SUCCESS(rv)) { 231 rv = _trie_inorder_traverse(tmp, cb, user_data); 232 } 233 return rv; 234 } 235 236 static int _trie_traverse(alpm_lib_trie_node_t *trie, alpm_lib_trie_callback_f cb, 237 void *user_data, alpm_lib_trie_traverse_order_t order) 238 { 239 int rv = SOC_E_NONE; 240 241 switch(order) { 242 case trieTraverseOrderPre: 243 rv = _trie_preorder_traverse(trie, cb, user_data); 244 break; 245 case trieTraverseOrderPost: 246 rv = _trie_postorder_traverse(trie, cb, user_data); 247 break; 248 case trieTraverseOrderIn: 249 rv = _trie_inorder_traverse(trie, cb, user_data); 250 break; 251 default: 252 assert(0); 253 } 254 255 return rv; 256 } 257 258 /* 259 * Function: 260 * alpm_lib_trie_traverse 261 * Purpose: 262 * Traverse the trie & call the application callback with user data 263 */ 264 int alpm_lib_trie_traverse(alpm_lib_trie_t *trie, alpm_lib_trie_callback_f cb, 265 void *user_data, alpm_lib_trie_traverse_order_t order) 266 { 267 if (trie == NULL) { 268 return SOC_E_NONE; 269 } else { 270 return _trie_traverse(trie->trie, cb, user_data, order); 271 } 272 } 273 274 static int _trie_preorder_traverse2(alpm_lib_trie_node_t *ptrie, 275 alpm_lib_trie_node_t *trie, 276 alpm_lib_trie_traverse_state_t *state, 277 alpm_lib_trie_callback_ext_f cb, 278 void *user_data) 279 { 280 int rv = SOC_E_NONE; 281 alpm_lib_trie_node_t *lc, *rc; 282 283 if (trie == NULL || !cb) { 284 return SOC_E_NONE; 285 } else { 286 assert(!ptrie || ptrie->type == trieNodeTypePayload); 287 288 /* make the trie delete safe */ 289 lc = trie->child[0]; 290 rc = trie->child[1]; 291 if (trie->type == trieNodeTypePayload) { /* no need to callback on internal nodes */ 292 rv = cb(ptrie, trie, state, user_data); 293 TRIE_TRAVERSE_STOP(*state, rv); 294 295 /* Change the ptrie as trie if applicable */ 296 /* make the ptrie delete safe */ 297 if (*state != trieTraverseStateDel) { 298 ptrie = trie; 299 } 300 } 301 } 302 303 if (SOC_SUCCESS(rv)) { 304 rv = _trie_preorder_traverse2(ptrie, lc, state, cb, user_data); 305 TRIE_TRAVERSE_STOP(*state, rv); 306 } 307 if (SOC_SUCCESS(rv)) { 308 rv = _trie_preorder_traverse2(ptrie, rc, state, cb, user_data); 309 } 310 return rv; 311 } 312 313 static int _trie_postorder_traverse2(alpm_lib_trie_node_t *ptrie, 314 alpm_lib_trie_node_t *trie, 315 alpm_lib_trie_traverse_state_t *state, 316 alpm_lib_trie_callback_ext_f cb, 317 void *user_data) 318 { 319 int rv = SOC_E_NONE; 320 alpm_lib_trie_node_t *ori_ptrie = ptrie; 321 alpm_lib_trie_node_t *lc, *rc; 322 alpm_lib_trie_node_type_t trie_type; 323 if (trie == NULL) { 324 return SOC_E_NONE; 325 } 326 327 assert(!ptrie || ptrie->type == trieNodeTypePayload); 328 329 /* Change the ptrie as trie if applicable */ 330 if (trie->type == trieNodeTypePayload) { 331 ptrie = trie; 332 } 333 334 /* During the callback, a trie node can be deleted or inserted. 335 * For a deleted node, its internal parent could also be deleted, thus to 336 * make it safe we should record rc. 337 */ 338 trie_type = trie->type; 339 lc = trie->child[0]; 340 rc = trie->child[1]; 341 342 if (SOC_SUCCESS(rv)) { 343 rv = _trie_postorder_traverse2(ptrie, lc, state, cb, user_data); 344 TRIE_TRAVERSE_STOP(*state, rv); 345 } 346 if (SOC_SUCCESS(rv)) { 347 rv = _trie_postorder_traverse2(ptrie, rc, state, cb, user_data); 348 TRIE_TRAVERSE_STOP(*state, rv); 349 } 350 if (SOC_SUCCESS(rv)) { 351 if (trie_type == trieNodeTypePayload) { 352 rv = cb(ori_ptrie, trie, state, user_data); 353 } 354 } 355 return rv; 356 } 357 358 static int _trie_inorder_traverse2(alpm_lib_trie_node_t *ptrie, 359 alpm_lib_trie_node_t *trie, 360 alpm_lib_trie_traverse_state_t *state, 361 alpm_lib_trie_callback_ext_f cb, 362 void *user_data) 363 { 364 int rv = SOC_E_NONE; 365 alpm_lib_trie_node_t *rc = NULL; 366 alpm_lib_trie_node_t *ori_ptrie = ptrie; 367 368 if (trie == NULL) { 369 return SOC_E_NONE; 370 } 371 372 assert(!ptrie || ptrie->type == trieNodeTypePayload); 373 374 /* Change the ptrie as trie if applicable */ 375 if (trie->type == trieNodeTypePayload) { 376 ptrie = trie; 377 } 378 379 rv = _trie_inorder_traverse2(ptrie, trie->child[0], state, cb, user_data); 380 TRIE_TRAVERSE_STOP(*state, rv); 381 382 /* make the trie delete safe */ 383 rc = trie->child[1]; 384 385 if (SOC_SUCCESS(rv)) { 386 if (trie->type == trieNodeTypePayload) { 387 rv = cb(ptrie, trie, state, user_data); 388 TRIE_TRAVERSE_STOP(*state, rv); 389 /* make the ptrie delete safe */ 390 if (*state == trieTraverseStateDel) { 391 ptrie = ori_ptrie; 392 } 393 } 394 } 395 396 if (SOC_SUCCESS(rv)) { 397 rv = _trie_inorder_traverse2(ptrie, rc, state, cb, user_data); 398 } 399 return rv; 400 } 401 402 static int _trie_traverse2(alpm_lib_trie_node_t *trie, alpm_lib_trie_callback_ext_f cb, 403 void *user_data, alpm_lib_trie_traverse_order_t order, 404 alpm_lib_trie_traverse_state_t *state) 405 { 406 int rv = SOC_E_NONE; 407 408 switch(order) { 409 case trieTraverseOrderPre: 410 rv = _trie_preorder_traverse2(NULL, trie, state, cb, user_data); 411 break; 412 case trieTraverseOrderPost: 413 rv = _trie_postorder_traverse2(NULL, trie, state, cb, user_data); 414 break; 415 case trieTraverseOrderIn: 416 rv = _trie_inorder_traverse2(NULL, trie, state, cb, user_data); 417 break; 418 default: 419 assert(0); 420 } 421 422 return rv; 423 } 424 425 /* 426 * Function: 427 * alpm_lib_trie_traverse2 428 * Purpose: 429 * Traverse the trie (trieNodeTypePayload) & call the extended application callback 430 * which has current node's trieNodeTypePayload parent node with user data. 431 */ 432 int alpm_lib_trie_traverse2(alpm_lib_trie_t *trie, alpm_lib_trie_callback_ext_f cb, 433 void *user_data, alpm_lib_trie_traverse_order_t order) 434 { 435 alpm_lib_trie_traverse_state_t state = trieTraverseStateNone; 436 437 if (order < trieTraverseOrderPre || 438 order >= trieTraverseOrderMax || !cb) return SOC_E_PARAM; 439 440 if (trie == NULL) { 441 return SOC_E_NONE; 442 } else { 443 return _trie_traverse2(trie->trie, cb, user_data, order, &state); 444 } 445 } 446 447 static int _trie_dump(alpm_lib_trie_node_t *trie, alpm_lib_trie_callback_f cb, 448 void *user_data, uint32 level) 449 { 450 if (trie == NULL) { 451 return SOC_E_NONE; 452 } else { 453 uint32 lvl = level; 454 while(lvl) { 455 if (lvl == 1) { 456 LOG_CLI((BSL_META("|-"))); 457 } else { 458 LOG_CLI((BSL_META("| "))); 459 } 460 lvl--; 461 } 462 463 if (cb) { 464 cb(trie, user_data); 465 } else { 466 _alpm_lib_print_trie_node(trie, NULL); 467 } 468 } 469 470 _trie_dump(trie->child[0], cb, user_data, level+1); 471 _trie_dump(trie->child[1], cb, user_data, level+1); 472 return SOC_E_NONE; 473 } 474 475 /* 476 * Function: 477 * alpm_lib_trie_dump 478 * Purpose: 479 * Dumps the trie pre-order [root|left|child] 480 */ 481 int alpm_lib_trie_dump(alpm_lib_trie_t *trie, alpm_lib_trie_callback_f cb, void *user_data) 482 { 483 if (trie->trie) { 484 return _trie_dump(trie->trie, cb, user_data, 0); 485 } else { 486 return SOC_E_PARAM; 487 } 488 } 489 490 static int _trie_search(alpm_lib_trie_node_t *trie, 491 uint32 *key, 492 uint32 length, 493 alpm_lib_trie_node_t **payload, 494 uint32 *result_key, 495 uint32 *result_len, 496 uint32 dump, 497 uint32 find_pivot) 498 { 499 uint32 lcp=0; 500 int bit=0, rv=SOC_E_NONE; 501 502 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 503 504 if (dump) { 505 _alpm_lib_print_trie_node(trie, (uint32 *)1); 506 } 507 508 if (length > trie->skip_len) { 509 if (lcp == trie->skip_len) { 510 bit = (key[KEY48_BIT2IDX(length - lcp)] & \ 511 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 512 if (dump) { 513 LOG_CLI((BSL_META(" Length: %d Next-Bit[%d] \n"), length, bit)); 514 } 515 516 if (result_key) { 517 rv = _key_append(result_key, result_len, trie->skip_addr, trie->skip_len); 518 if (SOC_FAILURE(rv)) return rv; 519 } 520 521 /* based on next bit branch left or right */ 522 if (trie->child[bit]) { 523 524 if (result_key) { 525 rv = _key_append(result_key, result_len, bit, 1); 526 if (SOC_FAILURE(rv)) return rv; 527 } 528 529 return _trie_search(trie->child[bit], key, 530 length - lcp - 1, payload, 531 result_key, result_len, dump, find_pivot); 532 } else { 533 return SOC_E_NOT_FOUND; /* not found */ 534 } 535 } else { 536 return SOC_E_NOT_FOUND; /* not found */ 537 } 538 } else if (length == trie->skip_len) { 539 if (lcp == length) { 540 if (dump) { 541 LOG_CLI((BSL_META(": MATCH \n"))); 542 } 543 *payload = trie; 544 if (trie->type != trieNodeTypePayload && !find_pivot) { 545 /* no assert here, possible during dbucket search 546 * due to 1* and 0* bucket search 547 */ 548 return SOC_E_NOT_FOUND; 549 } 550 if (result_key) { 551 rv = _key_append(result_key, result_len, trie->skip_addr, trie->skip_len); 552 if (SOC_FAILURE(rv)) return rv; 553 } 554 return SOC_E_NONE; 555 } 556 else return SOC_E_NOT_FOUND; 557 } else { 558 if (lcp == length && find_pivot) { 559 *payload = trie; 560 if (result_key) { 561 rv = _key_append(result_key, result_len, trie->skip_addr, trie->skip_len); 562 if (SOC_FAILURE(rv)) return rv; 563 } 564 return SOC_E_NONE; 565 } 566 return SOC_E_NOT_FOUND; /* not found */ 567 } 568 } 569 570 /* 571 * Function: 572 * alpm_lib_trie_search 573 * Purpose: 574 * Search the given trie for exact match of provided prefix/length 575 * If dump is set to 1 it traces the path as it traverses the trie 576 */ 577 int alpm_lib_trie_search(alpm_lib_trie_t *trie, 578 uint32 *key, 579 uint32 length, 580 alpm_lib_trie_node_t **payload) 581 { 582 if (trie->trie) { 583 if (trie->v6_key) { 584 return _alpm_lib_trie_v6_search(trie->trie, key, length, payload, NULL, NULL, 0, 0); 585 } else { 586 return _trie_search(trie->trie, key, length, payload, NULL, NULL, 0, 0); 587 } 588 } else { 589 return SOC_E_NOT_FOUND; 590 } 591 } 592 593 /* 594 * Internal function for LPM match searching. 595 * callback on all payload nodes if cb != NULL. 596 */ 597 static int _trie_find_lpm(alpm_lib_trie_node_t *trie, 598 uint32 *key, 599 uint32 length, 600 alpm_lib_trie_node_t **payload, 601 alpm_lib_trie_callback_f cb, 602 void *user_data, 603 uint32 exclude_self) 604 { 605 uint32 lcp=0; 606 int bit=0, rv=SOC_E_NONE; 607 608 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 609 610 if ((length > trie->skip_len) && (lcp == trie->skip_len)) { 611 if (trie->type == trieNodeTypePayload) { 612 /* lpm cases */ 613 if (payload != NULL) { 614 /* update lpm result */ 615 *payload = trie; 616 } 617 618 if (cb != NULL) { 619 /* callback with any nodes which is shorter and matches the prefix */ 620 rv = cb(trie, user_data); 621 if (SOC_FAILURE(rv)) { 622 /* early bailout if there is error in callback handling */ 623 return rv; 624 } 625 } 626 } 627 628 bit = (key[KEY48_BIT2IDX(length - lcp)] & \ 629 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 630 631 /* based on next bit branch left or right */ 632 if (trie->child[bit]) { 633 return _trie_find_lpm(trie->child[bit], key, length - lcp - 1, 634 payload, cb, user_data, exclude_self); 635 } 636 } else if ((length == trie->skip_len) && (lcp == length)) { 637 if (trie->type == trieNodeTypePayload) { 638 /* exact match case */ 639 if (payload != NULL && !exclude_self) { 640 /* lpm is exact match */ 641 *payload = trie; 642 } 643 644 if (cb != NULL) { 645 /* callback with the exact match node */ 646 rv = cb(trie, user_data); 647 if (SOC_FAILURE(rv)) { 648 /* early bailout if there is error in callback handling */ 649 return rv; 650 } 651 } 652 } 653 } 654 return rv; 655 } 656 657 /* 658 * Function: 659 * alpm_lib_trie_find_lpm 660 * Purpose: 661 * Find the longest prefix matched with given prefix 662 */ 663 int alpm_lib_trie_find_lpm(alpm_lib_trie_t *trie, uint32 *key, uint32 length, alpm_lib_trie_node_t **payload) 664 { 665 int rv = SOC_E_NONE; 666 667 *payload = NULL; 668 669 if (trie->trie) { 670 if (trie->v6_key) { 671 rv = _alpm_lib_trie_v6_find_lpm(trie->trie, key, length, payload, 672 NULL, NULL, 0); 673 } else { 674 rv = _trie_find_lpm(trie->trie, key, length, payload, 675 NULL, NULL, 0); 676 } 677 if (*payload || (rv != SOC_E_NONE)) { 678 return rv; 679 } 680 } 681 682 return SOC_E_NOT_FOUND; 683 } 684 685 /* 686 * Function: 687 * _trie_skip_node_free 688 * Purpose: 689 * Destroy a chain of alpm_lib_trie_node_t that has the target node at the end. 690 * The target node is not necessarily trieNodeTypePayload type, but all nodes 691 * on the chain except for the end must have only one branch. 692 * Input: 693 * key -- target key 694 * length -- target key length 695 * free_end -- free 696 */ 697 static int _trie_skip_node_free(alpm_lib_trie_node_t *trie, uint32 *key, uint32 length) 698 { 699 uint32 lcp=0; 700 int bit=0, rv=SOC_E_NONE; 701 702 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 703 704 if (length > trie->skip_len) { 705 if (lcp == trie->skip_len) { 706 bit = (key[KEY48_BIT2IDX(length - lcp)] & \ 707 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 708 709 /* There should be only one branch on the chain until the end node */ 710 if (!trie->child[0] == !trie->child[1]) { 711 return SOC_E_PARAM; 712 } 713 714 /* based on next bit branch left or right */ 715 if (trie->child[bit]) { 716 rv = _trie_skip_node_free(trie->child[bit], key, 717 length - lcp - 1); 718 if (SOC_SUCCESS(rv)) { 719 assert(trie->type == trieNodeTypeInternal); 720 alpm_util_free(trie); 721 } 722 return rv; 723 } else { 724 return SOC_E_NOT_FOUND; /* not found */ 725 } 726 } else { 727 return SOC_E_NOT_FOUND; /* not found */ 728 } 729 } else if (length == trie->skip_len) { 730 if (lcp == length) { 731 /* the end node is not necessarily type payload. */ 732 /* Do not free the end */ 733 734 return SOC_E_NONE; 735 } 736 else return SOC_E_NOT_FOUND; 737 } else { 738 return SOC_E_NOT_FOUND; /* not found */ 739 } 740 } 741 742 743 744 /* 745 * Function: 746 * _trie_skip_node_alloc 747 * Purpose: 748 * create a chain of alpm_lib_trie_node_t that has the payload at the end. 749 * each node in the chain can skip upto _MAX_SKIP_LEN number of bits, 750 * while the child pointer in the chain represent 1 bit. So totally 751 * each node can absorb (_MAX_SKIP_LEN+1) bits. 752 * Input: 753 * key -- 754 * msb -- 755 * skip_len -- skip_len of the whole chain 756 * payload -- payload node we want to insert 757 * count -- child count 758 * Output: 759 * node -- return pointer of the starting node of the chain. 760 */ 761 static int _trie_skip_node_alloc(alpm_lib_trie_node_t **node, 762 uint32 *key, 763 uint32 msb, /* NOTE: valid msb position 1 based, 0 means skip0/0 node */ 764 uint32 skip_len, 765 alpm_lib_trie_node_t *payload, 766 uint32 count) /* payload count underneath - mostly 1 except some tricky cases */ 767 { 768 int lsb=0, msbpos=0, lsbpos=0, bit=0, index; 769 alpm_lib_trie_node_t *child = NULL, *skip_node = NULL; 770 771 /* calculate lsb bit position, also 1 based */ 772 lsb = ((msb)? msb + 1 - skip_len : msb); 773 774 if (msb) { 775 for (index = BITS2SKIPOFF(lsb), lsbpos = lsb - 1; index <= BITS2SKIPOFF(msb); index++) { 776 /* each loop process _MAX_SKIP_LEN number of bits?? */ 777 if (lsbpos == lsb-1) { 778 /* (lsbpos == lsb-1) is only true for first node (loop) here */ 779 skip_node = payload; 780 } else { 781 /* other nodes need to be created */ 782 skip_node = alpm_util_alloc(sizeof(alpm_lib_trie_node_t), "trie_node"); 783 } 784 785 /* init memory */ 786 sal_memset(skip_node, 0, sizeof(alpm_lib_trie_node_t)); 787 788 /* calculate msb bit position of current chunk of bits we are processing */ 789 msbpos = index * _MAX_SKIP_LEN_ - 1; 790 if (msbpos > msb-1) msbpos = msb-1; 791 792 /* calculate the skip_len of the created node */ 793 if (msbpos - lsbpos < _MAX_SKIP_LEN_) { 794 skip_node->skip_len = msbpos - lsbpos + 1; 795 } else { 796 skip_node->skip_len = _MAX_SKIP_LEN_; 797 } 798 799 /* calculate the skip_addr (skip_length number of bits). 800 * skip might be skipping bits on 2 different words 801 * if msb & lsb spawns 2 word boundary in worst case 802 */ 803 if (BITS2WORDS(msbpos+1) != BITS2WORDS(lsbpos+1)) { 804 /* pull snippets from the different words & fuse */ 805 skip_node->skip_addr = key[KEY48_BIT2IDX(msbpos+1)] & TRIE_MASK((msbpos+1) % _NUM_WORD_BITS_); 806 skip_node->skip_addr = _SHL(skip_node->skip_addr, skip_node->skip_len - ((msbpos+1) % _NUM_WORD_BITS_)); 807 skip_node->skip_addr |= _SHR(key[KEY48_BIT2IDX(lsbpos+1)],(lsbpos % _NUM_WORD_BITS_)); 808 } else { 809 skip_node->skip_addr = _SHR(key[KEY48_BIT2IDX(msbpos+1)], (lsbpos % _NUM_WORD_BITS_)); 810 } 811 812 /* set up the chain of child pointer, first node has no child since "child" was inited to NULL */ 813 if (child) { 814 skip_node->child[bit] = child; 815 } 816 817 /* calculate child pointer for next loop. NOTE: skip_addr has not been masked 818 * so we still have the child bit in the skip_addr here. 819 */ 820 bit = (skip_node->skip_addr & _SHL(1, skip_node->skip_len - 1)) ? 1:0; 821 822 /* calculate node type */ 823 if (lsbpos == lsb-1) { 824 /* first node is payload */ 825 skip_node->type = trieNodeTypePayload; 826 } else { 827 /* other nodes are internal nodes */ 828 skip_node->type = trieNodeTypeInternal; 829 } 830 831 /* all internal nodes will have the same "count" as the payload node */ 832 skip_node->count = count; 833 834 /* advance lsb to next word */ 835 lsbpos += skip_node->skip_len; 836 837 /* for all child nodes 0/1 is implicitly obsorbed on parent */ 838 if (msbpos != msb-1) { 839 /* msbpos == (msb-1) is only true for the first node */ 840 skip_node->skip_len--; 841 } 842 skip_node->skip_addr &= TRIE_MASK(skip_node->skip_len); 843 child = skip_node; 844 } 845 } else { 846 /* skip_len == 0 case, create a payload node with skip_len = 0 847 * bit 0 and bit "skip_len" are same bit (bit 0). 848 */ 849 skip_node = payload; 850 sal_memset(skip_node, 0, sizeof(alpm_lib_trie_node_t)); 851 skip_node->type = trieNodeTypePayload; 852 skip_node->count = count; 853 } 854 855 *node = skip_node; 856 return SOC_E_NONE; 857 } 858 859 static int _trie_insert(alpm_lib_trie_node_t *trie, 860 uint32 *key, 861 uint32 length, 862 alpm_lib_trie_node_t *payload, /* payload node */ 863 alpm_lib_trie_node_t **child, /* child pointer if the child is modified */ 864 int child_count) 865 { 866 uint32 lcp; 867 int rv=SOC_E_NONE, bit=0; 868 alpm_lib_trie_node_t *node = NULL; 869 870 *child = NULL; 871 872 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 873 874 /* insert cases: 875 * 1 - new key could be the parent of existing node 876 * 2 - new key could become the child of a existing node 877 * 3 - internal node could be inserted and the key becomes one of child 878 * 4 - internal node is converted to a payload node */ 879 880 /* if the new key qualifies as new root do the inserts here */ 881 if (lcp == length) { /* guaranteed: length < _MAX_SKIP_LEN_ */ 882 if (trie->skip_len == lcp) { 883 if (trie->type != trieNodeTypeInternal) { 884 /* duplicate */ 885 return SOC_E_EXISTS; 886 } else { 887 /* change the internal node to payload node */ 888 _TRIE_NODE_CLONE_(payload,trie); 889 alpm_util_free(trie); 890 payload->type = trieNodeTypePayload; 891 payload->count += child_count; 892 *child = payload; 893 return SOC_E_NONE; 894 } 895 } else { /* skip length can never be less than lcp implcitly here */ 896 /* this node is new parent for the old trie node */ 897 /* lcp is the new skip length */ 898 _TRIE_NODE_CLONE_(payload,trie); 899 *child = payload; 900 901 bit = (trie->skip_addr & _SHL(1, trie->skip_len - length - 1)) ? 1 : 0; 902 trie->skip_addr &= TRIE_MASK(trie->skip_len - length - 1); 903 trie->skip_len -= (length + 1); 904 905 payload->skip_addr = (length > 0) ? key[KEY48_BIT2IDX(length)] : 0; 906 payload->skip_addr &= TRIE_MASK(length); 907 payload->skip_len = length; 908 payload->child[bit] = trie; 909 payload->child[!bit] = NULL; 910 payload->type = trieNodeTypePayload; 911 payload->count += child_count; 912 } 913 } else if (lcp == trie->skip_len) { 914 /* key length is implictly greater than lcp here */ 915 /* decide based on key's next applicable bit */ 916 bit = (key[KEY48_BIT2IDX(length-lcp)] & 917 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 918 919 if (!trie->child[bit]) { 920 /* the key is going to be one of the child of existing node */ 921 /* should be the child */ 922 rv = _trie_skip_node_alloc(&node, key, 923 length-lcp-1, /* 0 based msbit position */ 924 length-lcp-1, 925 payload, child_count); 926 if (SOC_SUCCESS(rv)) { 927 trie->child[bit] = node; 928 trie->count += child_count; 929 } else { 930 LOG_CLI((BSL_META("\n Error on trie skip node allocaiton [%d]!!!!\n"), 931 rv)); 932 } 933 } else { 934 rv = _trie_insert(trie->child[bit], 935 key, length - lcp - 1, 936 payload, child, child_count); 937 if (SOC_SUCCESS(rv)) { 938 trie->count += child_count; 939 if (*child != NULL) { /* chande the old child pointer to new child */ 940 trie->child[bit] = *child; 941 *child = NULL; 942 } 943 } 944 } 945 } else { 946 alpm_lib_trie_node_t *newchild = NULL; 947 948 /* need to introduce internal nodes */ 949 node = alpm_util_alloc(sizeof(alpm_lib_trie_node_t), "trie-node"); 950 _TRIE_NODE_CLONE_(node, trie); 951 952 rv = _trie_skip_node_alloc(&newchild, key, 953 ((lcp)?length-lcp-1:length-1), 954 length - lcp - 1, 955 payload, child_count); 956 if (SOC_SUCCESS(rv)) { 957 bit = (key[KEY48_BIT2IDX(length-lcp)] & 958 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1: 0; 959 960 node->child[!bit] = trie; 961 node->child[bit] = newchild; 962 node->type = trieNodeTypeInternal; 963 node->skip_addr = _SHR(trie->skip_addr,trie->skip_len - lcp); 964 node->skip_len = lcp; 965 node->count += child_count; 966 967 *child = node; 968 969 trie->skip_addr &= TRIE_MASK(trie->skip_len - lcp - 1); 970 trie->skip_len -= (lcp + 1); 971 } else { 972 LOG_CLI((BSL_META("\n Error on trie skip node allocaiton [%d]!!!!\n"), rv)); 973 alpm_util_free(node); 974 } 975 } 976 977 return rv; 978 } 979 980 /* 981 * Function: 982 * alpm_lib_trie_insert 983 * Purpose: 984 * Inserts provided prefix/length in to the trie 985 */ 986 int alpm_lib_trie_insert(alpm_lib_trie_t *trie, 987 uint32 *key, 988 uint32 length, 989 alpm_lib_trie_node_t *payload) 990 { 991 int rv = SOC_E_NONE; 992 alpm_lib_trie_node_t *child=NULL; 993 994 if (!trie) return SOC_E_PARAM; 995 996 if (trie->trie == NULL) { 997 if (trie->v6_key) { 998 rv = _alpm_lib_trie_v6_skip_node_alloc(&trie->trie, key, length, length, payload, 1); 999 } else { 1000 rv = _trie_skip_node_alloc(&trie->trie, key, length, length, payload, 1); 1001 } 1002 } else { 1003 if (trie->v6_key) { 1004 rv = _alpm_lib_trie_v6_insert(trie->trie, key, length, payload, &child, 1); 1005 } else { 1006 rv = _trie_insert(trie->trie, key, length, payload, &child, 1); 1007 } 1008 if (child) { /* chande the old child pointer to new child */ 1009 trie->trie = child; 1010 } 1011 } 1012 1013 return rv; 1014 } 1015 1016 int _alpm_lib_trie_fuse_child(alpm_lib_trie_node_t *trie, int bit) 1017 { 1018 alpm_lib_trie_node_t *child = NULL; 1019 int rv = SOC_E_NONE; 1020 1021 if (trie->child[0] && trie->child[1]) { 1022 return SOC_E_PARAM; 1023 } 1024 1025 bit = (bit > 0)?1:0; 1026 child = trie->child[bit]; 1027 1028 if (child == NULL) { 1029 return SOC_E_PARAM; 1030 } else { 1031 if (trie->skip_len + child->skip_len + 1 <= _MAX_SKIP_LEN_) { 1032 1033 if (trie->skip_len == 0) trie->skip_addr = 0; 1034 1035 if (child->skip_len < _MAX_SKIP_LEN_) { 1036 trie->skip_addr = TRIE_SHL(trie->skip_addr,child->skip_len + 1,_MAX_SKIP_LEN_); 1037 } 1038 1039 trie->skip_addr |= _SHL(bit, child->skip_len); 1040 child->skip_addr |= trie->skip_addr; 1041 child->skip_len += trie->skip_len + 1; 1042 1043 /* do not free payload nodes as they are user managed */ 1044 if (trie->type == trieNodeTypeInternal) { 1045 alpm_util_free(trie); 1046 } 1047 } 1048 } 1049 1050 return rv; 1051 } 1052 1053 static int _trie_delete(alpm_lib_trie_node_t *trie, 1054 uint32 *key, 1055 uint32 length, 1056 alpm_lib_trie_node_t **payload, 1057 alpm_lib_trie_node_t **child) 1058 { 1059 uint32 lcp; 1060 int rv=SOC_E_NONE, bit=0; 1061 alpm_lib_trie_node_t *node = NULL; 1062 1063 /* our algorithm should return before the length < 0, so this means 1064 * something wrong with the trie structure. Internal error? 1065 */ 1066 if (!trie || (length && trie->skip_len && !key) || 1067 !payload || !child || (length > _MAX_KEY_LEN_48_)) { 1068 return SOC_E_PARAM; 1069 } 1070 1071 *child = NULL; 1072 1073 /* check a section of key, return the number of matched bits and value of next bit */ 1074 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1075 1076 if (length > trie->skip_len) { 1077 if (lcp == trie->skip_len) { 1078 bit = (key[KEY48_BIT2IDX(length-lcp)] & 1079 (1 << ((length - lcp -1) % _NUM_WORD_BITS_))) ? 1:0; 1080 1081 /* based on next bit branch left or right */ 1082 if (trie->child[bit]) { 1083 /* has child node, keep searching */ 1084 rv = _trie_delete(trie->child[bit], key, length - lcp - 1, payload, child); 1085 1086 if (rv == SOC_E_BUSY) { 1087 trie->child[bit] = NULL; /* alpm_util_free the child */ 1088 rv = SOC_E_NONE; 1089 trie->count--; 1090 1091 if (trie->type == trieNodeTypeInternal) { 1092 bit = (bit == 0) ? 1 : 0; 1093 if (trie->child[bit] == NULL) { 1094 /* parent and child connected, alpm_util_free the middle-node itself */ 1095 alpm_util_free(trie); 1096 rv = SOC_E_BUSY; 1097 } else { 1098 /* fuse the parent & child */ 1099 if (trie->skip_len + trie->child[bit]->skip_len + 1 <= 1100 _MAX_SKIP_LEN_) { 1101 *child = trie->child[bit]; 1102 rv = _alpm_lib_trie_fuse_child(trie, bit); 1103 if (rv != SOC_E_NONE) { 1104 *child = NULL; 1105 } 1106 } 1107 } 1108 } 1109 } else if (SOC_SUCCESS(rv)) { 1110 trie->count--; 1111 /* update child pointer if applicable */ 1112 if (*child != NULL) { 1113 trie->child[bit] = *child; 1114 *child = NULL; 1115 } 1116 } 1117 } else { 1118 /* no child node case 0: not found */ 1119 rv = SOC_E_NOT_FOUND; 1120 } 1121 1122 } else { 1123 /* some bits are not matching, case 0: not found */ 1124 rv = SOC_E_NOT_FOUND; 1125 } 1126 } else if (length == trie->skip_len) { 1127 /* when length equal to skip_len, unless this is a payload node 1128 * and it's an exact match (lcp == length), we can not found a match 1129 */ 1130 if (!((lcp == length) && (trie->type == trieNodeTypePayload))) { 1131 rv = SOC_E_NOT_FOUND; 1132 } else { 1133 /* payload node can be deleted */ 1134 /* if this node has 2 children update it to internal node */ 1135 rv = SOC_E_NONE; 1136 1137 if (trie->child[0] && trie->child[1] ) { 1138 /* the node has 2 children, update it to internal node */ 1139 node = alpm_util_alloc(sizeof(alpm_lib_trie_node_t), "trie_node"); 1140 _TRIE_NODE_CLONE_(node, trie); 1141 node->type = trieNodeTypeInternal; 1142 node->count--; 1143 *child = node; 1144 } else if (trie->child[0] || trie->child[1] ) { 1145 /* if this node has 1 children fuse the children with this node */ 1146 bit = (trie->child[0]) ? 0:1; 1147 trie->count--; 1148 if (trie->skip_len + trie->child[bit]->skip_len + 1 <= _MAX_SKIP_LEN_) { 1149 /* able to fuse the node with its child node */ 1150 *child = trie->child[bit]; 1151 rv = _alpm_lib_trie_fuse_child(trie, bit); 1152 if (rv != SOC_E_NONE) { 1153 *child = NULL; 1154 } 1155 } else { 1156 /* convert it to internal node, we need to alloc new memory for internal nodes 1157 * since the old payload node memory will be freed by caller 1158 */ 1159 node = alpm_util_alloc(sizeof(alpm_lib_trie_node_t), "trie_node"); 1160 _TRIE_NODE_CLONE_(node, trie); 1161 node->type = trieNodeTypeInternal; 1162 *child = node; 1163 } 1164 } else { 1165 rv = SOC_E_BUSY; 1166 } 1167 1168 *payload = trie; 1169 } 1170 } else { 1171 /* key length is shorter, no match if it's internal node, 1172 * will not exact match even if this is a payload node 1173 */ 1174 rv = SOC_E_NOT_FOUND; /* case 0: not found */ 1175 } 1176 1177 return rv; 1178 } 1179 1180 /* 1181 * Function: 1182 * alpm_lib_trie_delete 1183 * Purpose: 1184 * Deletes provided prefix/length in to the trie 1185 */ 1186 int alpm_lib_trie_delete(alpm_lib_trie_t *trie, 1187 uint32 *key, 1188 uint32 length, 1189 alpm_lib_trie_node_t **payload) 1190 { 1191 int rv = SOC_E_NONE; 1192 alpm_lib_trie_node_t *child = NULL; 1193 1194 if (trie->trie) { 1195 if (trie->v6_key) { 1196 rv = _alpm_lib_trie_v6_delete(trie->trie, key, length, payload, &child); 1197 } else { 1198 rv = _trie_delete(trie->trie, key, length, payload, &child); 1199 } 1200 if (rv == SOC_E_BUSY) { 1201 /* the head node of trie was deleted, reset trie pointer to null */ 1202 trie->trie = NULL; 1203 rv = SOC_E_NONE; 1204 } else if (rv == SOC_E_NONE && child != NULL) { 1205 trie->trie = child; 1206 } 1207 } else { 1208 rv = SOC_E_NOT_FOUND; 1209 } 1210 return rv; 1211 } 1212 1213 static INLINE int 1214 _trie_splitable(alpm_lib_trie_node_t *trie, alpm_lib_trie_node_t *child, 1215 alpm_lib_trie_callback_ext_f cb, void *user_data, 1216 int max_count, int max_split_count) 1217 { 1218 /* 1219 * NOTE: 1220 * ABS(trie->count * 2 - max_count) actually means 1221 * ABS(trie->count - (max_count - trie->count)) 1222 * which means the count's distance to half depth of the bucket 1223 */ 1224 int do_split = 0; 1225 int half_count = (max_count + 1) >> 1; 1226 1227 if (cb && cb(trie, child, NULL, user_data)) { 1228 do_split = 1; 1229 } else if (trie->count <= max_split_count && trie->count != max_count) { 1230 if (child == NULL) { 1231 do_split = 1; 1232 } else if (trie->count >= half_count && child->count <= half_count) { 1233 do_split = 1; 1234 } else if (ABS(child->count * 2 - max_count) > 1235 ABS(trie->count * 2 - max_count)) { 1236 do_split = 1; 1237 } 1238 } 1239 1240 return do_split; 1241 } 1242 1243 /* 1244 * Function: 1245 * _trie_split 1246 * Purpose: 1247 * Split the trie into 2 based on optimum pivot 1248 * NOTE: 1249 * max_split_len -- split will make sure the split point 1250 * has a length shorter or equal to the max_split_len 1251 * unless this will cause a no-split (all prefixs 1252 * stays below the split point) 1253 * split_to_pair -- used only when the split point will be 1254 * used to create a pair of tries later (i.e: dbucket 1255 * pair. we assume the split point itself will always be 1256 * put into 0* trie if itself is a payload/prefix) 1257 */ 1258 static int _trie_split(alpm_lib_trie_node_t *trie, uint32 *pivot, 1259 uint32 *length, uint32 *split_count, 1260 alpm_lib_trie_node_t **split_node, alpm_lib_trie_node_t **child, 1261 const uint32 max_count, const uint32 max_split_len, 1262 alpm_lib_trie_split_state_t *state, alpm_lib_trie_callback_ext_f cb, 1263 void *user_data, 1264 const int max_split_count) 1265 { 1266 int bit=0, rv=SOC_E_NONE; 1267 1268 if (trie->child[0] && trie->child[1]) { 1269 bit = (trie->child[0]->count > 1270 trie->child[1]->count) ? 0:1; 1271 } else { 1272 bit = (trie->child[0])?0:1; 1273 } 1274 1275 /* start building the pivot */ 1276 rv = _key_append(pivot, length, trie->skip_addr, trie->skip_len); 1277 if (SOC_FAILURE(rv)) return rv; 1278 1279 { 1280 /* 1281 * split logic to make sure the split length is shorter than the 1282 * requested max_split_len, unless we don't actully split the 1283 * tree if we stop here. 1284 * if (*length > max_split_len) && (trie->count != max_count) { 1285 * need to split at or above this node. might need to split the node in middle 1286 * } else if ((ABS(child count*2 - max_count) > ABS(count*2 - max_count)) || 1287 * ((*length == max_split_len) && (trie->count != max_count))) { 1288 * (the check above imply trie->count != max_count, so also imply *length < max_split_len) 1289 * need to split at this node. 1290 * } else { 1291 * keep searching, will be better split at longer pivot. 1292 * } 1293 */ 1294 if ((*length > max_split_len) && (trie->count != max_count)) { 1295 /* the pivot is getting too long, we better split at this node for 1296 * better bucket capacity efficiency if we can. We can split if 1297 * the trie node has a count != max_count, which means the 1298 * resulted new trie will not have all pivots (FULL) 1299 */ 1300 if ((trieSplitStatePayloadSplit == *state) && 1301 (trie->type == trieNodeTypeInternal)) { 1302 *state = trieSplitStatePayloadSplitDone; 1303 } else { 1304 if (((*length - max_split_len) > trie->skip_len) && (trie->skip_len == 0)) { 1305 /* the length is longer than max_split_len, and the trie->skip_len is 0, 1306 * so the best we can do is use the node as the split point 1307 */ 1308 *split_node = trie; 1309 *split_count = trie->count; 1310 1311 *state = trieSplitStatePruneNodes; 1312 return rv; 1313 } 1314 1315 /* we need to insert a node and use it as split point */ 1316 *split_node = alpm_util_alloc(sizeof(alpm_lib_trie_node_t), "trie_node"); 1317 sal_memset((*split_node), 0, sizeof(alpm_lib_trie_node_t)); 1318 (*split_node)->type = trieNodeTypeInternal; 1319 (*split_node)->count = trie->count; 1320 1321 if ((*length - max_split_len) > trie->skip_len) { 1322 /* the length is longer than the max_split_len, and the trie->skip_len is 1323 * shorter than the difference (max_split_len pivot is not covered by this 1324 * node but covered by its parent, the best we can do is split at the branch 1325 * lead to this node. we insert a skip_len=0 node and use it as split point 1326 */ 1327 (*split_node)->skip_len = 0; 1328 (*split_node)->skip_addr = 0; 1329 1330 if (_BITGET(trie->skip_addr, (trie->skip_len-1))) { 1331 (*split_node)->child[1] = trie; 1332 } else { 1333 (*split_node)->child[0] = trie; 1334 } 1335 1336 /* the split point is with length max_split_len */ 1337 *length -= trie->skip_len; 1338 1339 /* update the current node to reflect the node inserted */ 1340 trie->skip_len = trie->skip_len - 1; 1341 } else { 1342 /* the length is longer than the max_split_len, and the trie->skip_len is 1343 * longer than the difference (max_split_len pivot is covered by this 1344 * node, we insert a node with length = max_split_len and use it as split point 1345 */ 1346 (*split_node)->skip_len = trie->skip_len - (*length - max_split_len); 1347 (*split_node)->skip_addr = (trie->skip_addr >> (*length - max_split_len)); 1348 1349 if (_BITGET(trie->skip_addr, (*length-max_split_len-1))) { 1350 (*split_node)->child[1] = trie; 1351 } else { 1352 (*split_node)->child[0] = trie; 1353 } 1354 1355 /* update the current node to reflect the node inserted */ 1356 trie->skip_len = *length - max_split_len - 1; 1357 1358 /* the split point is with length max_split_len */ 1359 *length = max_split_len; 1360 } 1361 1362 trie->skip_addr = trie->skip_addr & BITMASK(trie->skip_len); 1363 1364 /* there is no need to update the parent node's child pointer 1365 * to the "trie" node since we will split here and the parent node's 1366 * child pointer will be set to NULL later 1367 */ 1368 *split_count = trie->count; 1369 1370 if (SOC_SUCCESS(rv)) { 1371 rv = _key_shift_right(pivot, trie->skip_len+1); 1372 } 1373 *state = trieSplitStatePruneNodes; 1374 return rv; 1375 } 1376 } else if ( ((*length == max_split_len) && (trie->count != max_count) && trie->count <= max_split_count) || 1377 _trie_splitable(trie, trie->child[bit], cb, user_data, max_count, max_split_count)) { 1378 /* 1379 * (1) when the node is at the max_split_len and if used as spliting point 1380 * the resulted trie will not have all pivots (FULL). we should split 1381 * at this node. 1382 * (2) when the node is at the max_split_len and if the resulted trie 1383 * will have all pivots (FULL), we fall through to keep searching 1384 * (3) when the node is shorter than the max_split_len and the node 1385 * has a more even pivot distribution compare to it's child, we 1386 * can split at this node. The split count must be less than or 1387 * equal to max_split_count. 1388 * (4) when the node's count is only 1, we must split at this point. 1389 * 1390 * NOTE : 1391 * when trie->count == max_count, the above check will be FALSE 1392 * so here it guarrantees *length < max_split_len. We don't 1393 * need to further split this node. 1394 */ 1395 *split_node = trie; 1396 *split_count = trie->count; 1397 1398 if ((trieSplitStatePayloadSplit == *state) && 1399 (trie->type == trieNodeTypeInternal)) { 1400 *state = trieSplitStatePayloadSplitDone; 1401 } else { 1402 *state = trieSplitStatePruneNodes; 1403 return rv; 1404 } 1405 } else { 1406 /* we can not split at this node, keep searching, it's better to 1407 * split at longer pivot 1408 */ 1409 rv = _key_append(pivot, length, bit, 1); 1410 if (SOC_FAILURE(rv)) return rv; 1411 1412 rv = _trie_split(trie->child[bit], 1413 pivot, length, 1414 split_count, split_node, 1415 child, max_count, max_split_len, 1416 state, cb, user_data, max_split_count); 1417 } 1418 } 1419 1420 /* free up internal nodes if applicable */ 1421 switch(*state) { 1422 case trieSplitStatePayloadSplitDone: 1423 if (trie->type == trieNodeTypePayload) { 1424 *state = trieSplitStatePruneNodes; 1425 *split_node = trie; 1426 *split_count = trie->count; 1427 } else { 1428 /* shift the pivot to right to ignore this internal node */ 1429 rv = _key_shift_right(pivot, trie->skip_len+1); 1430 assert(*length >= trie->skip_len + 1); 1431 *length -= (trie->skip_len + 1); 1432 } 1433 break; 1434 1435 case trieSplitStatePruneNodes: 1436 if (trie->count == *split_count) { 1437 /* if the split point has associate internal nodes they have to 1438 * be cleaned up */ 1439 assert(trie->type == trieNodeTypeInternal); 1440 assert(!(trie->child[0] && trie->child[1])); 1441 alpm_util_free(trie); 1442 } else { 1443 assert(*child == NULL); 1444 /* fuse with child if possible */ 1445 trie->child[bit] = NULL; 1446 bit = (bit==0)?1:0; 1447 trie->count -= *split_count; 1448 1449 /* optimize more */ 1450 if ((trie->type == trieNodeTypeInternal) && 1451 (trie->skip_len + 1452 trie->child[bit]->skip_len + 1 <= _MAX_SKIP_LEN_)) { 1453 *child = trie->child[bit]; 1454 rv = _alpm_lib_trie_fuse_child(trie, bit); 1455 if (rv != SOC_E_NONE) { 1456 *child = NULL; 1457 } 1458 } 1459 *state = trieSplitStateDone; 1460 } 1461 break; 1462 1463 case trieSplitStateDone: 1464 /* adjust parent's count */ 1465 assert(*split_count > 0); 1466 assert(trie->count >= *split_count); 1467 1468 /* update the child pointer if child was pruned */ 1469 if (*child != NULL) { 1470 trie->child[bit] = *child; 1471 *child = NULL; 1472 } 1473 trie->count -= *split_count; 1474 break; 1475 1476 default: 1477 break; 1478 } 1479 1480 return rv; 1481 } 1482 1483 /* 1484 * Function: 1485 * alpm_lib_trie_split 1486 * Purpose: 1487 * Split the trie into 2 based on optimum pivot 1488 * Note: 1489 * we need to make sure the length is shorter than 1490 * the max_split_len (for capacity optimization) if 1491 * possible. We should ignore the max_split_len 1492 * if that will result into trie not spliting 1493 */ 1494 int alpm_lib_trie_split(alpm_lib_trie_t *trie, 1495 const uint32 max_split_len, 1496 uint32 *pivot, 1497 uint32 *length, 1498 alpm_lib_trie_node_t **split_trie_root, 1499 uint8 payload_node_split, 1500 alpm_lib_trie_callback_ext_f cb, 1501 void *user_data, 1502 const int max_split_count) 1503 { 1504 int rv = SOC_E_NONE; 1505 uint32 split_count=0, max_count=0; 1506 alpm_lib_trie_node_t *child = NULL, *node=NULL, clone; 1507 alpm_lib_trie_split_state_t state = trieSplitStateNone; 1508 1509 if (!trie || !pivot || !length || !split_trie_root) return SOC_E_PARAM; 1510 *length = 0; 1511 1512 if (trie->trie) { 1513 if (payload_node_split) state = trieSplitStatePayloadSplit; 1514 max_count = trie->trie->count; 1515 1516 if (trie->v6_key) { 1517 sal_memset(pivot, 0, sizeof(uint32) * BITS2WORDS(_MAX_KEY_LEN_144_)); 1518 rv = _alpm_lib_trie_v6_split(trie->trie, pivot, length, &split_count, split_trie_root, 1519 &child, max_count, max_split_len, &state, cb, user_data, max_split_count); 1520 } else { 1521 sal_memset(pivot, 0, sizeof(uint32) * BITS2WORDS(_MAX_KEY_LEN_48_)); 1522 1523 rv = _trie_split(trie->trie, pivot, length, &split_count, split_trie_root, 1524 &child, max_count, max_split_len, &state, cb, user_data, max_split_count); 1525 } 1526 if (SOC_SUCCESS(rv) && (trieSplitStateDone == state)) { 1527 /* adjust parent's count */ 1528 assert(split_count > 0); 1529 if (trie->trie == NULL) { 1530 alpm_lib_trie_t *c1, *c2; 1531 alpm_lib_trie_init(48, &c1); 1532 alpm_lib_trie_init(48, &c2); 1533 c1->trie = child; 1534 c2->trie = *split_trie_root; 1535 LOG_ERROR(BSL_LS_SOC_ALPM, 1536 (BSL_META("dumping the 2 child trees\n"))); 1537 alpm_lib_trie_dump(c1, 0, 0); 1538 alpm_lib_trie_dump(c2, 0, 0); 1539 } 1540 /* update the child pointer if child was pruned */ 1541 if (child != NULL) { 1542 trie->trie = child; 1543 } 1544 assert(trie->trie->count >= split_count || (*split_trie_root)->count >= split_count); 1545 1546 sal_memcpy(&clone, *split_trie_root, sizeof(alpm_lib_trie_node_t)); 1547 child = *split_trie_root; 1548 1549 /* take advantage of thie function by passing in internal or payload node whatever 1550 * is the new root. If internal the function assumed it as payload node & changes type. 1551 * But this method is efficient to reuse the last internal or payload node possible to 1552 * implant the new pivot */ 1553 if (trie->v6_key) { 1554 rv = _alpm_lib_trie_v6_skip_node_alloc(&node, pivot, 1555 *length, *length, 1556 child, child->count); 1557 } else { 1558 rv = _trie_skip_node_alloc(&node, pivot, 1559 *length, *length, 1560 child, child->count); 1561 } 1562 1563 if (SOC_SUCCESS(rv)) { 1564 if (clone.type == trieNodeTypeInternal) { 1565 child->type = trieNodeTypeInternal; /* since skip alloc would have reset it to payload */ 1566 } 1567 child->child[0] = clone.child[0]; 1568 child->child[1] = clone.child[1]; 1569 *split_trie_root = node; 1570 } 1571 } else { 1572 LOG_CLI((BSL_META("!!!! Failed to split the trie error:%d state: %d trie_count %d!!!\n"), 1573 rv, state, max_count)); 1574 } 1575 } else { 1576 rv = SOC_E_PARAM; 1577 } 1578 1579 return rv; 1580 } 1581 1582 /* 1583 * Function: 1584 * _trie_merge 1585 * Purpose: 1586 * merge or fuse the child trie with parent trie 1587 */ 1588 static int 1589 _trie_merge(alpm_lib_trie_node_t *parent_trie, 1590 alpm_lib_trie_node_t *child_trie, 1591 uint32 *pivot, 1592 uint32 length, 1593 alpm_lib_trie_node_t **new_parent) 1594 { 1595 int rv, child_count; 1596 alpm_lib_trie_node_t *child = NULL, clone; 1597 uint32 child_pivot[BITS2WORDS(_MAX_KEY_LEN_48_)] = {0}; 1598 uint32 child_length = 0; 1599 1600 if (!parent_trie || length == 0 || !pivot || !new_parent || (length > _MAX_KEY_LEN_48_)) 1601 return SOC_E_PARAM; 1602 1603 /* 1604 * to do merge, there is one and only one condition: 1605 * parent must cover the child 1606 */ 1607 1608 /* 1609 * child pivot could be an internal node, i.e., NOT_FOUND on search 1610 * so check the out child instead of rv. 1611 */ 1612 _trie_search(child_trie, pivot, length, &child, child_pivot, &child_length, 0, 1); 1613 1614 /* The head of a bucket usually is the pivot of the bucket, 1615 * but for some cases, where the pivot is an trieNodeTypeInternal node, 1616 * and it is fused with its child, then the pivot can no longer 1617 * be found, but we can still search a head. The head can be 1618 * payload (if this is the only payload head), or internal (if 1619 * two payload head coexist). 1620 */ 1621 if (child == NULL) { 1622 return SOC_E_PARAM; 1623 } 1624 1625 _TRIE_NODE_CLONE_(&clone, child); 1626 1627 if (child != child_trie) { 1628 rv = _trie_skip_node_free(child_trie, child_pivot, child_length); 1629 if (rv < 0) { 1630 return SOC_E_PARAM; 1631 } 1632 } 1633 1634 /* Record the child count before being cleared */ 1635 child_count = child->count; 1636 1637 /* Clear the info before insert, mainly it is to prevent previous non-zero 1638 * count being erroneously included to calculation. 1639 */ 1640 sal_memset(child, 0, sizeof(*child)); 1641 1642 rv = _trie_insert(parent_trie, child_pivot, child_length, child, 1643 new_parent, child_count); 1644 if (rv < 0) { 1645 return SOC_E_PARAM; 1646 } 1647 1648 /* 1649 * child node, the inserted node, will be modified during insert, 1650 * and it must be a leaf node of the parent trie without any child. 1651 * The child node could be either payload or internal. 1652 */ 1653 if (child->child[0] || child->child[1]) { 1654 return SOC_E_PARAM; 1655 } 1656 if (clone.type == trieNodeTypeInternal) { 1657 child->type = trieNodeTypeInternal; 1658 } 1659 child->child[0] = clone.child[0]; 1660 child->child[1] = clone.child[1]; 1661 1662 return SOC_E_NONE; 1663 } 1664 1665 1666 /* 1667 * Function: 1668 * alpm_lib_trie_merge 1669 * Purpose: 1670 * merge or fuse the child trie with parent trie. 1671 */ 1672 int alpm_lib_trie_merge(alpm_lib_trie_t *parent_trie, 1673 alpm_lib_trie_node_t *child_trie, 1674 uint32 *child_pivot, 1675 uint32 length) 1676 { 1677 int rv=SOC_E_NONE; 1678 alpm_lib_trie_node_t *child=NULL; 1679 1680 if (!parent_trie) { 1681 return SOC_E_PARAM; 1682 } 1683 1684 if (!child_trie) { 1685 return SOC_E_NONE; 1686 } 1687 1688 if (parent_trie->trie == NULL) { 1689 parent_trie->trie = child_trie; 1690 } else { 1691 if (parent_trie->v6_key) { 1692 rv = _alpm_lib_trie_v6_merge(parent_trie->trie, child_trie, child_pivot, length, &child); 1693 } else { 1694 rv = _trie_merge(parent_trie->trie, child_trie, child_pivot, length, &child); 1695 } 1696 if (child) { 1697 /* The parent head can be changed if the new payload generates a 1698 * new internal node, which then becomes the new head. 1699 */ 1700 parent_trie->trie = child; 1701 } 1702 } 1703 1704 return rv; 1705 } 1706 1707 1708 /* 1709 * Function: 1710 * _trie_split2 1711 * Purpose: 1712 * Split the trie into 2 such that the new sub trie covers given prefix/length. 1713 * NOTE: 1714 * key, key_len -- The given prefix/length 1715 * max_split_count -- The sub trie's max allowed count. 1716 */ 1717 static int 1718 _trie_split2(alpm_lib_trie_node_t *trie, 1719 uint32 *key, 1720 uint32 key_len, 1721 uint32 *pivot, 1722 uint32 *pivot_len, 1723 uint32 *split_count, 1724 alpm_lib_trie_node_t **split_node, 1725 alpm_lib_trie_node_t **child, 1726 alpm_lib_trie_split2_state_t *state, 1727 const int max_split_count, 1728 const int exact_same) 1729 { 1730 uint32 lcp=0; 1731 int bit=0, rv=SOC_E_NONE; 1732 1733 /* start building the pivot */ 1734 rv = _key_append(pivot, pivot_len, trie->skip_addr, trie->skip_len); 1735 if (SOC_FAILURE(rv)) return rv; 1736 1737 1738 lcp = lcplen(key, key_len, trie->skip_addr, trie->skip_len); 1739 1740 if (lcp == trie->skip_len) { 1741 if (trie->count <= max_split_count && 1742 (!exact_same || (key_len - lcp) == 0)) { 1743 *split_node = trie; 1744 *split_count = trie->count; 1745 if (trie->count < max_split_count) { 1746 *state = trieSplit2StatePruneNodes; 1747 } 1748 return SOC_E_NONE; 1749 } 1750 if (key_len > lcp) { 1751 bit = (key[KEY48_BIT2IDX(key_len - lcp)] & \ 1752 (1 << ((key_len - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 1753 1754 /* based on next bit branch left or right */ 1755 if (trie->child[bit]) { 1756 /* we can not split at this node, keep searching, it's better to 1757 * split at longer pivot 1758 */ 1759 rv = _key_append(pivot, pivot_len, bit, 1); 1760 if (SOC_FAILURE(rv)) return rv; 1761 1762 rv = _trie_split2(trie->child[bit], 1763 key, key_len - lcp - 1, 1764 pivot, pivot_len, split_count, 1765 split_node, child, state, 1766 max_split_count, exact_same); 1767 if (SOC_FAILURE(rv)) return rv; 1768 } 1769 } 1770 } 1771 1772 /* free up internal nodes if applicable */ 1773 switch(*state) { 1774 case trieSplit2StateNone: /* fail to split */ 1775 break; 1776 1777 case trieSplit2StatePruneNodes: 1778 if (trie->count == *split_count) { 1779 /* if the split point has associate internal nodes they have to 1780 * be cleaned up */ 1781 assert(trie->type == trieNodeTypeInternal); 1782 /* at most one child */ 1783 assert(!(trie->child[0] && trie->child[1])); 1784 /* at least one child */ 1785 assert(trie->child[0] || trie->child[1]); 1786 alpm_util_free(trie); 1787 } else { 1788 assert(*child == NULL); 1789 /* fuse with child if possible */ 1790 trie->child[bit] = NULL; 1791 bit = (bit==0)?1:0; 1792 trie->count -= *split_count; 1793 1794 /* optimize more */ 1795 if ((trie->type == trieNodeTypeInternal) && 1796 (trie->skip_len + 1797 trie->child[bit]->skip_len + 1 <= _MAX_SKIP_LEN_)) { 1798 *child = trie->child[bit]; 1799 rv = _alpm_lib_trie_fuse_child(trie, bit); 1800 if (rv != SOC_E_NONE) { 1801 *child = NULL; 1802 } 1803 } 1804 *state = trieSplit2StateDone; 1805 } 1806 break; 1807 1808 case trieSplit2StateDone: 1809 /* adjust parent's count */ 1810 assert(*split_count > 0); 1811 assert(trie->count >= *split_count); 1812 1813 /* update the child pointer if child was pruned */ 1814 if (*child != NULL) { 1815 trie->child[bit] = *child; 1816 *child = NULL; 1817 } 1818 trie->count -= *split_count; 1819 break; 1820 1821 default: 1822 break; 1823 } 1824 1825 return rv; 1826 } 1827 1828 1829 1830 /* 1831 * Function: 1832 * alpm_lib_trie_split2 1833 * Purpose: 1834 * Split the trie such that the new sub trie covers given prefix/length. 1835 * Basically this is a reverse of alpm_lib_trie_merge. 1836 */ 1837 1838 int alpm_lib_trie_split2(alpm_lib_trie_t *trie, 1839 uint32 *key, 1840 uint32 key_len, 1841 uint32 *pivot, 1842 uint32 *pivot_len, 1843 alpm_lib_trie_node_t **split_trie_root, 1844 const int max_split_count, 1845 const int exact_same) 1846 { 1847 int rv = SOC_E_NONE; 1848 int msc = max_split_count; 1849 uint32 split_count=0; 1850 alpm_lib_trie_node_t *child = NULL, *node=NULL, clone; 1851 alpm_lib_trie_split2_state_t state = trieSplit2StateNone; 1852 1853 if (!trie || (key_len && !key) || !pivot || !pivot_len || 1854 !split_trie_root || max_split_count == 0) { 1855 return SOC_E_PARAM; 1856 } 1857 1858 *split_trie_root = NULL; 1859 *pivot_len = 0; 1860 1861 if (trie->trie) { 1862 if (max_split_count == 0xfffffff) { 1863 alpm_lib_trie_node_t *child2 = NULL; 1864 alpm_lib_trie_node_t *payload; 1865 payload = alpm_util_alloc(sizeof(alpm_lib_trie_node_t), "trie_node"); 1866 if (payload == NULL) { 1867 return SOC_E_MEMORY; 1868 } 1869 1870 if (trie->v6_key) { 1871 rv = _alpm_lib_trie_v6_insert(trie->trie, key, key_len, payload, &child2, 0); 1872 } else { 1873 rv = _trie_insert(trie->trie, key, key_len, payload, &child2, 0); 1874 } 1875 if (child2) { /* change the old child pointer to new child */ 1876 trie->trie = child2; 1877 } 1878 1879 if (SOC_SUCCESS(rv)) { 1880 payload->type = trieNodeTypeInternal; 1881 } else { 1882 alpm_util_free(payload); 1883 if (rv != SOC_E_EXISTS) { 1884 return rv; 1885 } 1886 } 1887 1888 msc = trie->trie->count; 1889 } 1890 if (trie->v6_key) { 1891 sal_memset(pivot, 0, sizeof(uint32) * BITS2WORDS(_MAX_KEY_LEN_144_)); 1892 rv = _alpm_lib_trie_v6_split2(trie->trie, key, key_len, pivot, pivot_len, 1893 &split_count, split_trie_root, &child, &state, 1894 msc, exact_same); 1895 } else { 1896 sal_memset(pivot, 0, sizeof(uint32) * BITS2WORDS(_MAX_KEY_LEN_48_)); 1897 rv = _trie_split2(trie->trie, key, key_len, pivot, pivot_len, 1898 &split_count, split_trie_root, &child, &state, 1899 msc, exact_same); 1900 } 1901 1902 if (SOC_SUCCESS(rv) && (trieSplit2StateDone == state)) { 1903 assert(split_count > 0); 1904 assert(*split_trie_root); 1905 if (max_split_count == 0xfffffff) { 1906 assert(*pivot_len == key_len); 1907 } else { 1908 assert(*pivot_len < key_len); 1909 } 1910 1911 /* update the child pointer if child was pruned */ 1912 if (child != NULL) { 1913 trie->trie = child; 1914 } 1915 1916 sal_memcpy(&clone, *split_trie_root, sizeof(alpm_lib_trie_node_t)); 1917 child = *split_trie_root; 1918 1919 /* take advantage of thie function by passing in internal or payload node whatever 1920 * is the new root. If internal the function assumed it as payload node & changes type. 1921 * But this method is efficient to reuse the last internal or payload node possible to 1922 * implant the new pivot */ 1923 if (trie->v6_key) { 1924 rv = _alpm_lib_trie_v6_skip_node_alloc(&node, pivot, 1925 *pivot_len, *pivot_len, 1926 child, child->count); 1927 } else { 1928 rv = _trie_skip_node_alloc(&node, pivot, 1929 *pivot_len, *pivot_len, 1930 child, child->count); 1931 } 1932 1933 if (SOC_SUCCESS(rv)) { 1934 if (clone.type == trieNodeTypeInternal) { 1935 child->type = trieNodeTypeInternal; /* since skip alloc would have reset it to payload */ 1936 } 1937 child->child[0] = clone.child[0]; 1938 child->child[1] = clone.child[1]; 1939 *split_trie_root = node; 1940 } 1941 } else if (SOC_SUCCESS(rv) && (max_split_count == 0xfffffff) && 1942 (split_count == trie->trie->count)) { 1943 /* take all */ 1944 *split_trie_root = trie->trie; 1945 trie->trie = NULL; 1946 } else { /* split2 is not like split which can always succeed */ 1947 LOG_INFO(BSL_LS_SOC_ALPM, 1948 (BSL_META("Failed to split the trie error:%d state: %d "\ 1949 "split_trie_root: %p !!!\n"), 1950 rv, state, *split_trie_root)); 1951 rv = SOC_E_NOT_FOUND; 1952 } 1953 } else { 1954 rv = SOC_E_PARAM; 1955 } 1956 1957 return rv; 1958 } 1959 1960 /* 1961 * Function: 1962 * _trie_ppg_prefix_validate 1963 * Purpose: 1964 * validate that the provided prefix is valid for propagation. 1965 * The added prefix which was member of a shorter pivot's domain 1966 * must never be more specific than another pivot encounter if any 1967 * in the path 1968 */ 1969 static int _trie_ppg_prefix_validate(alpm_lib_trie_node_t *trie, 1970 uint32 *pfx, 1971 uint32 len) 1972 { 1973 uint32 lcp=0, bit=0; 1974 1975 if (!trie || (len && trie->skip_len && !pfx)) return SOC_E_PARAM; 1976 1977 if (len == 0) return SOC_E_NONE; 1978 1979 lcp = lcplen(pfx, len, trie->skip_addr, trie->skip_len); 1980 1981 if (lcp == trie->skip_len) { 1982 if (trieNodeTypePayload == trie->type) return SOC_E_PARAM; 1983 if (len == lcp) return SOC_E_NONE; 1984 bit = _alpm_lib_key_get_bits(pfx, len-lcp, 1); 1985 if (!trie->child[bit]) return SOC_E_NONE; 1986 return _trie_ppg_prefix_validate(trie->child[bit], 1987 pfx, len-1-lcp); 1988 } 1989 1990 return SOC_E_NONE; 1991 } 1992 1993 /* 1994 * Function: 1995 * _trie_traverse_ppg_prefix 1996 * Purpose: 1997 * calls back applicable payload object is affected by prefix updates 1998 * NOTE: 1999 * other propagation code should always return SOC_E_NONE so that 2000 * callback will happen on all pivot. 2001 */ 2002 int _trie_traverse_ppg_prefix(alpm_lib_trie_node_t *trie, 2003 alpm_lib_trie_ppg_cb_f cb, 2004 alpm_lib_trie_bpm_cb_info_t *cb_info) 2005 { 2006 int rv = SOC_E_NONE, index=0; 2007 int rv1 = SOC_E_NONE; 2008 2009 if (!trie || !cb || !cb_info) { 2010 return SOC_E_PARAM; 2011 } 2012 2013 /* call back the payload object if applicable */ 2014 if (trieNodeTypePayload == trie->type) { 2015 rv = cb(trie, cb_info); 2016 if (SOC_FAILURE(rv)) { 2017 return rv; 2018 } 2019 } 2020 2021 for (index=0; index < 2; index++) { 2022 if (trie->child[index]) { 2023 rv = _trie_traverse_ppg_prefix( 2024 trie->child[index], cb, cb_info); 2025 /* Save first error, second error can overwrite if it's more severe 2026 than the first. SOC_E_LIMIT is considered as no severe error */ 2027 if (SOC_FAILURE(rv)) { 2028 if (rv1 == SOC_E_NONE || rv1 == SOC_E_LIMIT) { 2029 rv1 = rv; 2030 } 2031 } 2032 } 2033 } 2034 2035 return rv1; 2036 } 2037 2038 /* 2039 * Function: 2040 * _trie_ppg_prefix 2041 * Purpose: 2042 * If the propogation starts from intermediate pivot on 2043 * the trie, then the prefix length has to be appropriately adjusted or else 2044 * it will end up with ill updates. 2045 * Assumption: the prefix length is adjusted as per trie node on which 2046 * is starts from. 2047 * If node == head node then adjust is none 2048 * node == pivot, then prefix length = org len - pivot len 2049 */ 2050 static int _trie_ppg_prefix(alpm_lib_trie_node_t *trie, 2051 uint32 *pfx, 2052 uint32 len, 2053 alpm_lib_trie_ppg_cb_f cb, 2054 alpm_lib_trie_bpm_cb_info_t *cb_info) 2055 { 2056 int rv = SOC_E_NONE; /*, index;*/ 2057 uint32 bit = 0, lcp = 0; 2058 2059 if (!trie || (len && trie->skip_len && !pfx) || 2060 (len > _MAX_KEY_LEN_48_) || !cb || !cb_info) { 2061 return SOC_E_PARAM; 2062 } 2063 2064 if (len > 0) { 2065 lcp = lcplen(pfx, len, trie->skip_addr, trie->skip_len); 2066 /* if the lcp is less than prefix length the prefix is not applicable 2067 * for any propagation */ 2068 if (lcp < ((len>trie->skip_len) ? trie->skip_len : len)) { 2069 return SOC_E_NONE; 2070 } else { 2071 if (len > trie->skip_len) { 2072 bit = _alpm_lib_key_get_bits(pfx, len-lcp, 1); 2073 if (!trie->child[bit]) { 2074 return SOC_E_NONE; 2075 } 2076 rv = _trie_ppg_prefix( 2077 trie->child[bit], 2078 pfx, len-lcp-1, cb, cb_info); 2079 } else { 2080 /* pfx is <= trie skip len */ 2081 /* propagate if applicable */ 2082 rv = _trie_traverse_ppg_prefix(trie, cb, cb_info); 2083 if (SOC_E_LIMIT == rv) { 2084 rv = SOC_E_NONE; 2085 } 2086 } 2087 } 2088 } else { 2089 rv = _trie_traverse_ppg_prefix(trie, cb, cb_info); 2090 if (SOC_E_LIMIT == rv) { 2091 rv = SOC_E_NONE; 2092 } 2093 } 2094 2095 return rv; 2096 } 2097 2098 /* 2099 * Function: 2100 * _alpm_lib_trie_ppg_prefix 2101 * Purpose: 2102 * Propogate prefix from a given pivot. 2103 * Callback function to decide INSERT/DELETE propagation, 2104 * and decide to update bpm_len or not. 2105 */ 2106 int _alpm_lib_trie_ppg_prefix(alpm_lib_trie_node_t *pivot, 2107 uint32 pivot_len, 2108 uint32 *pfx, 2109 uint32 len, 2110 alpm_lib_trie_ppg_cb_f cb, 2111 alpm_lib_trie_bpm_cb_info_t *cb_info) 2112 { 2113 int rv = SOC_E_NONE; 2114 2115 len -= pivot_len; 2116 2117 if (len > 0) { 2118 uint32 bit = _alpm_lib_key_get_bits(pfx, len, 1); 2119 if (pivot->child[bit]) { 2120 /* validate if the pivot provided is correct */ 2121 rv = _trie_ppg_prefix_validate(pivot->child[bit], 2122 pfx, len-1); 2123 if (SOC_SUCCESS(rv)) { 2124 rv = _trie_ppg_prefix(pivot->child[bit], 2125 pfx, len-1, 2126 cb, cb_info); 2127 } 2128 } /* else nop, nothing to propagate on this path end */ 2129 } else { 2130 /* pivot == prefix */ 2131 rv = _trie_ppg_prefix(pivot, pfx, pivot->skip_len, 2132 cb, cb_info); 2133 } 2134 2135 return rv; 2136 } 2137 2138 int alpm_lib_trie_ppg(alpm_lib_trie_t *trie, uint32 pvt_len, 2139 uint32 *pfx, 2140 uint32 len, 2141 alpm_lib_trie_ppg_cb_f cb, 2142 alpm_lib_trie_bpm_cb_info_t *cb_info) 2143 { 2144 int rv = SOC_E_NONE, rv2 = SOC_E_NONE; 2145 alpm_lib_trie_node_t *payload; 2146 alpm_lib_trie_node_type_t payload_type = trieNodeTypeMax; 2147 2148 if (!pfx || !trie || !trie->trie || !cb || !cb_info) { 2149 return SOC_E_PARAM; 2150 } 2151 2152 payload = alpm_util_alloc(sizeof(alpm_lib_trie_node_t), "trie_node"); 2153 if (payload == NULL) { 2154 return SOC_E_MEMORY; 2155 } 2156 rv2 = alpm_lib_trie_insert(trie, pfx, len, payload); 2157 if (SOC_FAILURE(rv2)) { 2158 alpm_util_free(payload); 2159 if (rv2 != SOC_E_EXISTS) { 2160 return rv2; 2161 } 2162 rv = alpm_lib_trie_find_lpm(trie, pfx, len, &payload); 2163 if (SOC_FAILURE(rv)) { 2164 return rv; 2165 } 2166 } else { 2167 payload_type = payload->type; 2168 payload->type = trieNodeTypeInternalPpg; 2169 } 2170 2171 if (trie->v6_key) { 2172 rv = _alpm_lib_trie_v6_ppg_prefix(payload, len, pfx, len, 2173 cb, cb_info); 2174 } else { 2175 rv = _alpm_lib_trie_ppg_prefix(payload, len, pfx, len, 2176 cb, cb_info); 2177 } 2178 2179 if (payload_type != trieNodeTypeMax) { 2180 payload->type = payload_type; 2181 } 2182 2183 if (SOC_SUCCESS(rv2)) { 2184 alpm_lib_trie_delete(trie, pfx, len, &payload); 2185 alpm_util_free(payload); 2186 } 2187 2188 return rv; 2189 } 2190 2191 /* 2192 * Function: 2193 * alpm_lib_trie_init 2194 * Purpose: 2195 * allocates a trie & initializes it 2196 */ 2197 int alpm_lib_trie_init(uint32 max_key_len, alpm_lib_trie_t **ptrie) 2198 { 2199 alpm_lib_trie_t *trie = alpm_util_alloc(sizeof(alpm_lib_trie_t), "trie-node"); 2200 sal_memset(trie, 0, sizeof(alpm_lib_trie_t)); 2201 2202 if (max_key_len == _MAX_KEY_LEN_48_) { 2203 trie->v6_key = FALSE; 2204 } else if (max_key_len == _MAX_KEY_LEN_144_) { 2205 trie->v6_key = TRUE; 2206 } else { 2207 alpm_util_free(trie); 2208 return SOC_E_PARAM; 2209 } 2210 2211 trie->trie = NULL; /* means nothing is on teie */ 2212 *ptrie = trie; 2213 return SOC_E_NONE; 2214 } 2215 2216 /* 2217 * Function: 2218 * alpm_lib_trie_destroy 2219 * Purpose: 2220 * destroys a trie 2221 */ 2222 int alpm_lib_trie_destroy(alpm_lib_trie_t *trie) 2223 { 2224 if (trie != NULL) { 2225 alpm_util_free(trie); 2226 } 2227 return SOC_E_NONE; 2228 } 2229 2230 #endif /* ALPM_ENABLE */ 2231