alpm_trie.c (152630B)
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 #ifdef ALPM_ENABLE 25 #ifdef BCM_TRIDENT2_SUPPORT 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 <soc/esw/trie.h> 32 #include <soc/esw/trie_util.h> 33 #include <soc/esw/alpm_trie_v6.h> 34 35 #define _MAX_SKIP_LEN_ (31) 36 #define _MAX_KEY_LEN_ (48) 37 38 #define _MAX_KEY_WORDS_ (BITS2WORDS(_MAX_KEY_LEN_)) 39 40 #define SHL(data, shift, max) \ 41 (((shift)>=(max))?0:((data)<<(shift))) 42 43 #define SHR(data, shift, max) \ 44 (((shift)>=(max))?0:((data)>>(shift))) 45 46 #define MASK(len) \ 47 (((len)>=32 || (len)==0)?0xFFFFFFFF:((1<<(len))-1)) 48 49 #define BITMASK(len) \ 50 (((len)>=32)?0xFFFFFFFF:((1<<(len))-1)) 51 52 #define ABS(n) ((((int)(n)) < 0) ? -(n) : (n)) 53 54 #define _NUM_WORD_BITS_ (32) 55 56 #define BITS2SKIPOFF(x) (((x) + _MAX_SKIP_LEN_-1) / _MAX_SKIP_LEN_) 57 58 /* key packing expetations: 59 * eg., 48 bit key 60 * - 10/8 -> key[0]=0, key[1]=8 61 * - 0x123456789a -> key[0] = 0x12 key[1] = 0x3456789a 62 * length - represents number of valid bits from farther to lower index ie., 1->0 63 */ 64 65 #define KEY_BIT2IDX(x) (((BITS2WORDS(_MAX_KEY_LEN_)*32) - (x))/32) 66 67 68 /* (internal) Generic operation macro on bit array _a, with bit _b */ 69 #define _BITOP(_a, _b, _op) \ 70 ((_a) _op (1U << ((_b) % _NUM_WORD_BITS_))) 71 72 /* Specific operations */ 73 #define _BITGET(_a, _b) _BITOP(_a, _b, &) 74 #define _BITSET(_a, _b) _BITOP(_a, _b, |=) 75 #define _BITCLR(_a, _b) _BITOP(_a, _b, &= ~) 76 77 /* get the bit position of the LSB set in bit 0 to bit "msb" of "data" 78 * (max 32 bits), "lsb" is set to -1 if no bit is set in "data". 79 */ 80 #define BITGETLSBSET(data, msb, lsb) \ 81 { \ 82 lsb = 0; \ 83 while ((lsb)<=(msb)) { \ 84 if ((data)&(1<<(lsb))) { \ 85 break; \ 86 } else { (lsb)++;} \ 87 } \ 88 lsb = ((lsb)>(msb))?-1:(lsb); \ 89 } 90 #define KEY_BIT2IDX(x) (((BITS2WORDS(_MAX_KEY_LEN_)*32) - (x))/32) 91 92 /********************************************************/ 93 /* Get a chunk of bits from a key (MSB bit - on word0, lsb on word 1).. 94 */ 95 unsigned int _key_get_bits(unsigned int *key, 96 unsigned int pos /* 1based, msb bit position */, 97 unsigned int len, 98 unsigned int skip_len_check) 99 { 100 unsigned int val=0, delta=0, diff, bitpos; 101 102 /* coverity[var_deref_op : FALSE] */ 103 if (!key || (pos < 1) || (pos > _MAX_KEY_LEN_) || 104 ((skip_len_check == 0) && (len > _MAX_SKIP_LEN_))) assert(0); 105 106 bitpos = (pos-1) % _NUM_WORD_BITS_; 107 bitpos++; /* 1 based */ 108 109 if (bitpos >= len) { 110 diff = bitpos - len; 111 /* coverity[var_deref_op : FALSE] */ 112 val = SHR(key[KEY_BIT2IDX(pos)], diff, _NUM_WORD_BITS_); 113 val &= MASK(len); 114 return val; 115 } else { 116 diff = len - bitpos; 117 if (skip_len_check==0) assert(diff <= _MAX_SKIP_LEN_); 118 /* coverity[var_deref_op : FALSE] */ 119 val = key[KEY_BIT2IDX(pos)] & MASK(bitpos); 120 val = SHL(val, diff, _NUM_WORD_BITS_); 121 /* get bits from next word */ 122 delta = _key_get_bits(key, pos-bitpos, diff, skip_len_check); 123 return (delta | val); 124 } 125 } 126 127 128 /* 129 * Assumes the layout for 130 * 0 - most significant word 131 * _MAX_KEY_WORDS_ - least significant word 132 * eg., for key size of 48, word0-[bits 48-32] word1-[bits31-0] 133 */ 134 int _key_shift_left(unsigned int *key, unsigned int shift) 135 { 136 unsigned int index=0; 137 138 if (!key || shift > _MAX_SKIP_LEN_) return SOC_E_PARAM; 139 140 for(index=KEY_BIT2IDX(_MAX_KEY_LEN_); index < KEY_BIT2IDX(1); index++) { 141 key[index] = SHL(key[index], shift,_NUM_WORD_BITS_) | \ 142 SHR(key[index+1],_NUM_WORD_BITS_-shift,_NUM_WORD_BITS_); 143 } 144 145 key[index] = SHL(key[index], shift, _NUM_WORD_BITS_); 146 147 /* mask off snippets bit on MSW */ 148 key[0] &= MASK(_MAX_KEY_LEN_ % _NUM_WORD_BITS_); 149 return SOC_E_NONE; 150 } 151 152 /* 153 * Assumes the layout for 154 * 0 - most significant word 155 * _MAX_KEY_WORDS_ - least significant word 156 * eg., for key size of 48, word0-[bits 48-32] word1-[bits31-0] 157 */ 158 int _key_shift_right(unsigned int *key, unsigned int shift) 159 { 160 unsigned int index=0; 161 162 if (!key || shift > _MAX_SKIP_LEN_) return SOC_E_PARAM; 163 164 for(index=KEY_BIT2IDX(1); index > KEY_BIT2IDX(_MAX_KEY_LEN_); index--) { 165 key[index] = SHR(key[index], shift,_NUM_WORD_BITS_) | \ 166 SHL(key[index-1],_NUM_WORD_BITS_-shift,_NUM_WORD_BITS_); 167 } 168 169 key[index] = SHR(key[index], shift, _NUM_WORD_BITS_); 170 171 /* mask off snippets bit on MSW */ 172 key[0] &= MASK(_MAX_KEY_LEN_ % _NUM_WORD_BITS_); 173 return SOC_E_NONE; 174 } 175 176 177 /* 178 * Assumes the layout for 179 * 0 - most significant word 180 * _MAX_KEY_WORDS_ - least significant word 181 * eg., for key size of 48, word0-[bits 48-32] word1-[bits31-0] 182 */ 183 int _key_append(unsigned int *key, 184 unsigned int *length, 185 unsigned int skip_addr, 186 unsigned int skip_len) 187 { 188 int rv=SOC_E_NONE; 189 190 if (!key || !length || (skip_len + *length > _MAX_KEY_LEN_) || skip_len > _MAX_SKIP_LEN_ ) return SOC_E_PARAM; 191 192 rv = _key_shift_left(key, skip_len); 193 if (SOC_SUCCESS(rv)) { 194 key[KEY_BIT2IDX(1)] |= skip_addr; 195 *length += skip_len; 196 } 197 198 return rv; 199 } 200 201 int _bpm_append(unsigned int *key, 202 unsigned int *length, 203 unsigned int skip_addr, 204 unsigned int skip_len) 205 { 206 int rv=SOC_E_NONE; 207 208 if (!key || !length || (skip_len + *length > _MAX_KEY_LEN_) || skip_len > (_MAX_SKIP_LEN_+1) ) return SOC_E_PARAM; 209 210 if (skip_len == 32) { 211 key[0] = key[1]; 212 key[1] = skip_addr; 213 *length += skip_len; 214 } else { 215 rv = _key_shift_left(key, skip_len); 216 if (SOC_SUCCESS(rv)) { 217 key[KEY_BIT2IDX(1)] |= skip_addr; 218 *length += skip_len; 219 } 220 } 221 222 return rv; 223 } 224 225 /* 226 * Function: 227 * lcplen 228 * Purpose: 229 * returns longest common prefix length provided a key & skip address 230 */ 231 unsigned int 232 lcplen(unsigned int *key, unsigned int len1, 233 unsigned int skip_addr, unsigned int len2) 234 { 235 unsigned int diff; 236 unsigned int lcp = len1 < len2 ? len1 : len2; 237 238 if ((len1 > _MAX_KEY_LEN_) || (len2 > _MAX_KEY_LEN_)) { 239 LOG_CLI((BSL_META("len1 %d or len2 %d is larger than %d\n"), 240 len1, len2, _MAX_KEY_LEN_)); 241 assert(0); 242 } 243 244 if (len1 == 0 || len2 == 0) return 0; 245 246 diff = _key_get_bits(key, len1, lcp, 0); 247 diff ^= (SHR(skip_addr, len2 - lcp, _MAX_SKIP_LEN_) & MASK(lcp)); 248 249 while (diff) { 250 diff >>= 1; 251 --lcp; 252 } 253 254 return lcp; 255 } 256 257 int _print_trie_node(trie_node_t *trie, void *datum) 258 { 259 if (trie != NULL) { 260 261 LOG_CLI((BSL_META("trie: %p, type %s, skip_addr 0x%x skip_len %d " 262 "count:%d bpm:0x%x Child[0]:%p Child[1]:%p\n"), 263 trie, (trie->type == PAYLOAD)?"P":"I", 264 trie->skip_addr, trie->skip_len, 265 trie->count, trie->bpm, trie->child[0].child_node, 266 trie->child[1].child_node)); 267 } 268 return SOC_E_NONE; 269 } 270 271 STATIC int _trie_preorder_traverse(trie_node_t *trie, trie_callback_f cb, void *user_data) 272 { 273 int rv = SOC_E_NONE; 274 trie_node_t *tmp1, *tmp2; 275 276 if (trie == NULL || !cb) { 277 return SOC_E_NONE; 278 } else { 279 /* make the node delete safe */ 280 tmp1 = trie->child[0].child_node; 281 tmp2 = trie->child[1].child_node; 282 rv = cb(trie, user_data); 283 } 284 285 if (SOC_SUCCESS(rv)) { 286 rv = _trie_preorder_traverse(tmp1, cb, user_data); 287 } 288 if (SOC_SUCCESS(rv)) { 289 rv = _trie_preorder_traverse(tmp2, cb, user_data); 290 } 291 return rv; 292 } 293 294 STATIC int _trie_postorder_traverse(trie_node_t *trie, trie_callback_f cb, void *user_data) 295 { 296 int rv = SOC_E_NONE; 297 298 if (trie == NULL) { 299 return SOC_E_NONE; 300 } 301 302 if (SOC_SUCCESS(rv)) { 303 rv = _trie_postorder_traverse(trie->child[0].child_node, cb, user_data); 304 } 305 if (SOC_SUCCESS(rv)) { 306 rv = _trie_postorder_traverse(trie->child[1].child_node, cb, user_data); 307 } 308 if (SOC_SUCCESS(rv)) { 309 rv = cb(trie, user_data); 310 } 311 return rv; 312 } 313 314 STATIC int _trie_inorder_traverse(trie_node_t *trie, trie_callback_f cb, void *user_data) 315 { 316 int rv = SOC_E_NONE; 317 trie_node_t *tmp = NULL; 318 319 if (trie == NULL) { 320 return SOC_E_NONE; 321 } 322 323 if (SOC_SUCCESS(rv)) { 324 rv = _trie_inorder_traverse(trie->child[0].child_node, cb, user_data); 325 } 326 327 /* make the trie pointers delete safe */ 328 tmp = trie->child[1].child_node; 329 330 if (SOC_SUCCESS(rv)) { 331 rv = cb(trie, user_data); 332 } 333 334 if (SOC_SUCCESS(rv)) { 335 rv = _trie_inorder_traverse(tmp, cb, user_data); 336 } 337 return rv; 338 } 339 340 STATIC int _trie_traverse(trie_node_t *trie, trie_callback_f cb, 341 void *user_data, trie_traverse_order_e_t order) 342 { 343 int rv = SOC_E_NONE; 344 345 switch(order) { 346 case _TRIE_PREORDER_TRAVERSE: 347 rv = _trie_preorder_traverse(trie, cb, user_data); 348 break; 349 case _TRIE_POSTORDER_TRAVERSE: 350 rv = _trie_postorder_traverse(trie, cb, user_data); 351 break; 352 case _TRIE_INORDER_TRAVERSE: 353 rv = _trie_inorder_traverse(trie, cb, user_data); 354 break; 355 default: 356 assert(0); 357 } 358 359 return rv; 360 } 361 362 /* 363 * Function: 364 * trie_traverse 365 * Purpose: 366 * Traverse the trie & call the application callback with user data 367 */ 368 int trie_traverse(trie_t *trie, trie_callback_f cb, 369 void *user_data, trie_traverse_order_e_t order) 370 { 371 if (order < _TRIE_PREORDER_TRAVERSE || 372 order >= _TRIE_TRAVERSE_MAX || !cb) return SOC_E_PARAM; 373 374 if (trie == NULL) { 375 return SOC_E_NONE; 376 } else { 377 return _trie_traverse(trie->trie, cb, user_data, order); 378 } 379 } 380 381 #define TRIE_TRAVERSE_STOP(state, rv) \ 382 {if (state == TRIE_TRAVERSE_STATE_DONE || rv < 0) {return rv;} } 383 384 STATIC int _trie_preorder_traverse2(trie_node_t *ptrie, 385 trie_node_t *trie, 386 trie_traverse_states_e_t *state, 387 trie_callback_ext_f cb, 388 void *user_data) 389 { 390 int rv = SOC_E_NONE; 391 trie_node_t *lc, *rc; 392 393 if (trie == NULL || !cb) { 394 return SOC_E_NONE; 395 } else { 396 assert(!ptrie || ptrie->type == PAYLOAD); 397 398 /* make the trie delete safe */ 399 lc = trie->child[0].child_node; 400 rc = trie->child[1].child_node; 401 if (trie->type == PAYLOAD) { /* no need to callback on internal nodes */ 402 rv = cb(ptrie, trie, state, user_data); 403 TRIE_TRAVERSE_STOP(*state, rv); 404 405 /* Change the ptrie as trie if applicable */ 406 /* make the ptrie delete safe */ 407 if (*state != TRIE_TRAVERSE_STATE_DELETED) { 408 ptrie = trie; 409 } 410 } 411 } 412 413 if (SOC_SUCCESS(rv)) { 414 rv = _trie_preorder_traverse2(ptrie, lc, state, cb, user_data); 415 TRIE_TRAVERSE_STOP(*state, rv); 416 } 417 if (SOC_SUCCESS(rv)) { 418 rv = _trie_preorder_traverse2(ptrie, rc, state, cb, user_data); 419 } 420 return rv; 421 } 422 423 STATIC int _trie_postorder_traverse2(trie_node_t *ptrie, 424 trie_node_t *trie, 425 trie_traverse_states_e_t *state, 426 trie_callback_ext_f cb, 427 void *user_data) 428 { 429 int rv = SOC_E_NONE; 430 trie_node_t *ori_ptrie = ptrie; 431 trie_node_t *lc, *rc; 432 node_type_e_t trie_type; 433 if (trie == NULL) { 434 return SOC_E_NONE; 435 } 436 437 assert(!ptrie || ptrie->type == PAYLOAD); 438 439 /* Change the ptrie as trie if applicable */ 440 if (trie->type == PAYLOAD) { 441 ptrie = trie; 442 } 443 444 /* During the callback, a trie node can be deleted or inserted. 445 * For a deleted node, its internal parent could also be deleted, thus to 446 * make it safe we should record rc. 447 */ 448 trie_type = trie->type; 449 lc = trie->child[0].child_node; 450 rc = trie->child[1].child_node; 451 452 if (SOC_SUCCESS(rv)) { 453 rv = _trie_postorder_traverse2(ptrie, lc, state, cb, user_data); 454 TRIE_TRAVERSE_STOP(*state, rv); 455 } 456 if (SOC_SUCCESS(rv)) { 457 rv = _trie_postorder_traverse2(ptrie, rc, state, cb, user_data); 458 TRIE_TRAVERSE_STOP(*state, rv); 459 } 460 if (SOC_SUCCESS(rv)) { 461 if (trie_type == PAYLOAD) { 462 rv = cb(ori_ptrie, trie, state, user_data); 463 } 464 } 465 return rv; 466 } 467 468 STATIC int _trie_inorder_traverse2(trie_node_t *ptrie, 469 trie_node_t *trie, 470 trie_traverse_states_e_t *state, 471 trie_callback_ext_f cb, 472 void *user_data) 473 { 474 int rv = SOC_E_NONE; 475 trie_node_t *rc = NULL; 476 trie_node_t *ori_ptrie = ptrie; 477 478 if (trie == NULL) { 479 return SOC_E_NONE; 480 } 481 482 assert(!ptrie || ptrie->type == PAYLOAD); 483 484 /* Change the ptrie as trie if applicable */ 485 if (trie->type == PAYLOAD) { 486 ptrie = trie; 487 } 488 489 rv = _trie_inorder_traverse2(ptrie, trie->child[0].child_node, state, cb, user_data); 490 TRIE_TRAVERSE_STOP(*state, rv); 491 492 /* make the trie delete safe */ 493 rc = trie->child[1].child_node; 494 495 if (SOC_SUCCESS(rv)) { 496 if (trie->type == PAYLOAD) { 497 rv = cb(ptrie, trie, state, user_data); 498 TRIE_TRAVERSE_STOP(*state, rv); 499 /* make the ptrie delete safe */ 500 if (*state == TRIE_TRAVERSE_STATE_DELETED) { 501 ptrie = ori_ptrie; 502 } 503 } 504 } 505 506 if (SOC_SUCCESS(rv)) { 507 rv = _trie_inorder_traverse2(ptrie, rc, state, cb, user_data); 508 } 509 return rv; 510 } 511 512 513 STATIC int _trie_traverse2(trie_node_t *trie, trie_callback_ext_f cb, 514 void *user_data, trie_traverse_order_e_t order, 515 trie_traverse_states_e_t *state) 516 { 517 int rv = SOC_E_NONE; 518 519 switch(order) { 520 case _TRIE_PREORDER_TRAVERSE: 521 rv = _trie_preorder_traverse2(NULL, trie, state, cb, user_data); 522 break; 523 case _TRIE_POSTORDER_TRAVERSE: 524 rv = _trie_postorder_traverse2(NULL, trie, state, cb, user_data); 525 break; 526 case _TRIE_INORDER_TRAVERSE: 527 rv = _trie_inorder_traverse2(NULL, trie, state, cb, user_data); 528 break; 529 default: 530 assert(0); 531 } 532 533 return rv; 534 } 535 536 /* 537 * Function: 538 * trie_traverse2 539 * Purpose: 540 * Traverse the trie (PAYLOAD) & call the extended application callback 541 * which has current node's PAYLOAD parent node with user data. 542 */ 543 int trie_traverse2(trie_t *trie, trie_callback_ext_f cb, 544 void *user_data, trie_traverse_order_e_t order) 545 { 546 trie_traverse_states_e_t state = TRIE_TRAVERSE_STATE_NONE; 547 548 if (order < _TRIE_PREORDER_TRAVERSE || 549 order >= _TRIE_TRAVERSE_MAX || !cb) return SOC_E_PARAM; 550 551 if (trie == NULL) { 552 return SOC_E_NONE; 553 } else { 554 return _trie_traverse2(trie->trie, cb, user_data, order, &state); 555 } 556 } 557 558 559 560 typedef struct trie_list_s { 561 trie_node_t *node; 562 struct trie_list_s *next; 563 } trie_list_t; 564 565 #ifdef REPART_DEBUG 566 int repart_debug = 0; 567 trie_t *repart_trie = (trie_t *) 0xFFFFFFFF; 568 #endif 569 570 STATIC int _trie_repartition(trie_node_t *ptrie, 571 trie_node_t *trie, 572 trie_traverse_states_e_t *state, 573 trie_repartition_callback_f cb, 574 void *user_data, 575 trie_list_t **ptrie_list_in_out, 576 int level, 577 int *repart_count, 578 int *merge_count) 579 { 580 int rv = SOC_E_NONE; 581 node_type_e_t curr_trie_type; 582 trie_node_t *rc = NULL; 583 trie_node_t *new_ptrie = NULL; /* new ptrie from callback, to be added to list. */ 584 trie_node_t *further_ptrie = NULL; /* ptrie for recursion */ 585 trie_node_t *latest_ptrie = NULL; /* ptrie for callback */ 586 trie_list_t *ptrie_list = NULL; /* always the update-to-date ptrie list */ 587 trie_list_t *ptrie_list_next = NULL; /* for delete safe */ 588 trie_list_t *new_ptrie_list = NULL; 589 trie_list_t *l_ptrie_list = NULL; /* ptrie list from left child */ 590 trie_list_t *r_ptrie_list = NULL; /* ptrie list from right child */ 591 trie_list_t *ptrie_tail = NULL; /* ptrie list tail */ 592 trie_list_t *r_ptrie_tail = NULL; /* right ptrie list tail */ 593 trie_list_t *l_ptrie_tail = NULL; /* left ptrie list tail */ 594 trie_list_t *ptrie_list_iter = NULL; 595 int curr_trie_count; 596 int trc = 0, lrc = 0, rrc = 0; /* repartition counts */ 597 int tmc = 0, lmc = 0, rmc = 0; /* merge counts */ 598 int tmp = 0; 599 #ifdef REPART_DEBUG 600 int lvl; 601 #endif 602 int l_prune_count = 0, r_prune_count = 0; /* pruning counts */ 603 int l_stay_count = 0, r_stay_count = 0; /* staying counts */ 604 if (trie == NULL) { 605 return SOC_E_NONE; 606 } 607 608 /* assert(!ptrie || ptrie->type == PAYLOAD); */ 609 610 /* During the callback, a trie node can be deleted or inserted. 611 * For a deleted node, its internal parent could also be deleted, thus to 612 * make it safe we should record rc. 613 */ 614 curr_trie_type = trie->type; 615 curr_trie_count = trie->count; 616 rc = trie->child[1].child_node; 617 618 if (ptrie_list_in_out) { 619 ptrie_list = *ptrie_list_in_out; 620 621 /* Set tail */ 622 ptrie_tail = ptrie_list; 623 if (ptrie_tail) { 624 while(ptrie_tail->next) { 625 ptrie_tail = ptrie_tail->next; 626 } 627 } 628 } 629 #ifdef REPART_DEBUG 630 if (repart_debug) { 631 lvl = level; 632 while(lvl) { 633 LOG_CLI((BSL_META("%x "),level - lvl)); 634 lvl--; 635 } 636 LOG_CLI(("#Ptrie %p, trie %p\n", ptrie, trie)); 637 } 638 #endif 639 640 #define KEEP_OP >= 641 #define PRUNE_OP < 642 643 if (curr_trie_type == PAYLOAD) { 644 further_ptrie = trie; 645 } else if (ptrie_list) { 646 further_ptrie = ptrie_tail->node; 647 /* assert(ptrie_tail->node->count <= ptrie->count); */ 648 } else { 649 further_ptrie = ptrie; 650 } 651 652 rv = _trie_repartition(further_ptrie, trie->child[0].child_node, 653 state, cb, user_data, 654 (curr_trie_type == PAYLOAD) ? NULL : &l_ptrie_list, level+1, &lrc, &lmc); 655 656 657 /* Note, the ptrie_list could be updated */ 658 TRIE_TRAVERSE_STOP(*state, rv); 659 660 /* Somehow, the _trie_repartition may get us some new payload nodes, 661 * these new payload nodes can be many, and they can be lower than the trie, 662 * or higher than it, but all must be lower than ptrie. The child cannot 663 * decide status of each, only the current node can. 664 */ 665 666 /* Prune unnecessary heads in the list (assuming the lower/longer comes first)*/ 667 tmc += lmc; 668 669 l_prune_count = 0; 670 l_stay_count = 0; 671 l_ptrie_tail = NULL; 672 ptrie_list_iter = l_ptrie_list; 673 #ifdef REPART_DEBUG 674 if (repart_debug) { 675 if (l_ptrie_list) { 676 lvl = level; 677 while(lvl) { 678 LOG_CLI((BSL_META("%x "),level - lvl)); 679 lvl--; 680 } 681 682 LOG_CLI(("After LC Pruning:")); 683 while (ptrie_list_iter) { 684 ptrie_list_next = ptrie_list_iter->next; 685 if (ptrie_list_iter->node->count KEEP_OP (curr_trie_count - tmc - l_stay_count)) { 686 l_ptrie_tail = ptrie_list_iter; 687 l_stay_count++; 688 assert(l_prune_count == 0); 689 } else { 690 l_prune_count++; 691 LOG_CLI(("%p ", ptrie_list_iter->node)); 692 sal_free(ptrie_list_iter); 693 694 } 695 ptrie_list_iter = ptrie_list_next; 696 } 697 if (l_ptrie_tail) { 698 l_ptrie_tail->next = NULL; 699 } else { 700 l_ptrie_list = NULL; 701 } 702 703 LOG_CLI(("\n")); 704 705 ptrie_list_iter = l_ptrie_list; 706 lvl = level; 707 while(lvl) { 708 LOG_CLI((BSL_META("%x "),level - lvl)); 709 lvl--; 710 } 711 LOG_CLI(("After LC Pruned: ")); 712 while(ptrie_list_iter) { 713 LOG_CLI(("%p -> ", ptrie_list_iter->node)); 714 ptrie_list_iter = ptrie_list_iter->next; 715 } 716 LOG_CLI(("NULL \n")); 717 } 718 } else 719 #endif 720 { 721 while (ptrie_list_iter) { 722 ptrie_list_next = ptrie_list_iter->next; 723 if (ptrie_list_iter->node->count KEEP_OP (curr_trie_count - tmc - l_stay_count)) { 724 l_ptrie_tail = ptrie_list_iter; 725 l_stay_count++; 726 /* assert(l_prune_count == 0); */ 727 } else { 728 l_prune_count++; 729 sal_free(ptrie_list_iter); 730 } 731 ptrie_list_iter = ptrie_list_next; 732 } 733 if (l_ptrie_tail) { 734 l_ptrie_tail->next = NULL; 735 } else { 736 l_ptrie_list = NULL; 737 } 738 } 739 740 lrc = lrc - l_prune_count; 741 /* assert(lrc == l_stay_count); */ 742 743 trc += lrc; 744 745 if (l_ptrie_list) { 746 if (ptrie_list) { 747 ptrie_tail->next = l_ptrie_list; 748 } else { 749 ptrie_list = l_ptrie_list; 750 } 751 752 /* Reset tail */ 753 ptrie_tail = l_ptrie_tail; 754 } 755 756 if (curr_trie_type == PAYLOAD) { 757 further_ptrie = trie; 758 } else if (ptrie_list) { 759 further_ptrie = ptrie_tail->node; 760 /* assert(ptrie_tail->node->count <= ptrie->count); */ 761 } else { 762 further_ptrie = ptrie; 763 } 764 765 /* One important thing to notice is that after done with left child trie, 766 * the current node (trie) could be deleted, but, the right child trie won't 767 * be deleted. It's because that the internal node are allcoated because of 768 * its children, not because of its parent. Despite of that, the skip length 769 * and skip addr of the right child could be modified. 770 */ 771 772 if (SOC_SUCCESS(rv)) { 773 rv = _trie_repartition(further_ptrie, rc, state, cb, user_data, 774 (curr_trie_type == PAYLOAD) ? NULL : &r_ptrie_list, 775 level+1, &rrc, &rmc); 776 777 TRIE_TRAVERSE_STOP(*state, rv); 778 tmc += rmc; 779 780 /* Prune unnecessary heads in the list (assuming the lower/longer comes first)*/ 781 r_prune_count = 0; 782 r_stay_count = 0; 783 r_ptrie_tail = NULL; 784 ptrie_list_iter = r_ptrie_list; 785 #ifdef REPART_DEBUG 786 if (repart_debug) { 787 if (r_ptrie_list) { 788 lvl = level; 789 while(lvl) { 790 LOG_CLI((BSL_META("%x "),level - lvl)); 791 lvl--; 792 } 793 794 LOG_CLI(("After RC Pruning:")); 795 while (ptrie_list_iter) { 796 ptrie_list_next = ptrie_list_iter->next; 797 if (ptrie_list_iter->node->count KEEP_OP 798 (curr_trie_count - tmc - lrc - r_stay_count)) { 799 r_ptrie_tail = ptrie_list_iter; 800 r_stay_count++; 801 assert(r_prune_count == 0); 802 } else { 803 r_prune_count++; 804 LOG_CLI(("%p ", ptrie_list_iter->node)); 805 sal_free(ptrie_list_iter); 806 } 807 ptrie_list_iter = ptrie_list_next; 808 } 809 if (r_ptrie_tail) { 810 r_ptrie_tail->next = NULL; 811 } else { 812 /* whole list cleared */ 813 r_ptrie_list = NULL; 814 } 815 816 LOG_CLI(("\n")); 817 818 ptrie_list_iter = r_ptrie_list; 819 lvl = level; 820 while(lvl) { 821 LOG_CLI((BSL_META("%x "),level - lvl)); 822 lvl--; 823 } 824 LOG_CLI(("After RC Pruned: ")); 825 while(ptrie_list_iter) { 826 LOG_CLI(("%p -> ", ptrie_list_iter->node)); 827 ptrie_list_iter = ptrie_list_iter->next; 828 } 829 LOG_CLI(("NULL \n")); 830 } 831 } else 832 #endif 833 { 834 while (ptrie_list_iter) { 835 ptrie_list_next = ptrie_list_iter->next; 836 if (ptrie_list_iter->node->count KEEP_OP 837 (curr_trie_count - tmc - lrc - r_stay_count)) { 838 r_ptrie_tail = ptrie_list_iter; 839 r_stay_count++; 840 /* assert(r_prune_count == 0); */ 841 } else { 842 r_prune_count++; 843 sal_free(ptrie_list_iter); 844 845 } 846 ptrie_list_iter = ptrie_list_next; 847 } 848 if (r_ptrie_tail) { 849 r_ptrie_tail->next = NULL; 850 } else { 851 /* whole list cleared */ 852 r_ptrie_list = NULL; 853 } 854 } 855 856 rrc = rrc - r_prune_count; 857 /* assert(rrc == r_stay_count); */ 858 859 trc += rrc; 860 861 if (r_ptrie_list) { 862 if (ptrie_list) { 863 ptrie_tail->next = r_ptrie_list; 864 } else { 865 ptrie_list = r_ptrie_list; 866 } 867 /* Reset tail */ 868 ptrie_tail = r_ptrie_tail; 869 } 870 871 } 872 873 if (SOC_SUCCESS(rv) && curr_trie_type == PAYLOAD) { 874 /* Get the latest ptrie, could be from the list or the orig ptre */ 875 if (ptrie_list) { 876 latest_ptrie = ptrie_tail->node; 877 /* assert(ptrie_tail->node->count <= ptrie->count); */ 878 } else { 879 latest_ptrie = ptrie; 880 } 881 882 /* If curr_trie_type is payload, then trie must not be deleted */ 883 rv = cb(latest_ptrie, trie, state, user_data, &new_ptrie); 884 885 /* a new ptrie generated, add to the list as tail */ 886 if (new_ptrie) { 887 new_ptrie_list = sal_alloc(sizeof(trie_list_t), "trie list"); 888 sal_memset(new_ptrie_list, 0, sizeof(trie_list_t)); 889 new_ptrie_list->node = new_ptrie; 890 891 if (ptrie_list) { 892 ptrie_tail->next = new_ptrie_list; 893 ptrie_tail = new_ptrie_list; 894 } else { 895 ptrie_list = new_ptrie_list; 896 } 897 898 #ifdef REPART_DEBUG 899 if (repart_debug) { 900 lvl = level; 901 while(lvl) { 902 LOG_CLI((BSL_META("%x "),level - lvl)); 903 lvl--; 904 } 905 906 LOG_CLI(("New Head %p. Now: ", new_ptrie)); 907 ptrie_list_iter = ptrie_list; 908 while(ptrie_list_iter) { 909 LOG_CLI(("%p -> ", ptrie_list_iter->node)); 910 ptrie_list_iter = ptrie_list_iter->next; 911 } 912 LOG_CLI(("NULL. Updated trie:\n")); 913 trie_dump(repart_trie, 0, 0); 914 } 915 #endif 916 trc++; 917 } else if (*state == TRIE_TRAVERSE_STATE_DELETED) { 918 #ifdef REPART_DEBUG 919 if (repart_debug) { 920 lvl = level; 921 while(lvl) { 922 LOG_CLI((BSL_META("%x "),level - lvl)); 923 lvl--; 924 } 925 926 LOG_CLI(("Node %p merged (deleted). Updated trie:\n", trie)); 927 trie_dump(repart_trie, 0, 0); 928 } 929 #endif 930 tmc++; 931 } 932 } 933 934 if (ptrie_list_in_out) { 935 *ptrie_list_in_out = ptrie_list; 936 } else { 937 /* Done with repartition, clear list if any */ 938 tmp = 0; 939 ptrie_list_iter = ptrie_list; 940 while (ptrie_list_iter) { 941 ptrie_list_next = ptrie_list_iter->next; 942 #ifdef REPART_DEBUG 943 if (repart_debug) { 944 lvl = level; 945 while(lvl) { 946 LOG_CLI((BSL_META("%x "),level - lvl)); 947 lvl--; 948 } 949 LOG_CLI((" Clear Prune %p . trc %d. \n", 950 ptrie_list_iter->node, trc)); 951 952 if (ptrie_list_iter->node->count != (curr_trie_count - tmc - tmp)) { 953 LOG_CLI((" Count %d . Curr %d tmc %d tmp %d. \n", 954 ptrie_list_iter->node->count, curr_trie_count, tmc, tmp)); 955 assert(0); 956 } 957 } 958 #endif 959 sal_free(ptrie_list_iter); 960 ptrie_list_iter = ptrie_list_next; 961 tmp++; 962 } 963 /* assert(trc == tmp); */ 964 trc = 0; 965 } 966 967 /* assert(trc >= 0 && tmc >= 0); */ 968 if (repart_count) { 969 *repart_count += trc; 970 } 971 if (merge_count) { 972 *merge_count += tmc; 973 } 974 return rv; 975 } 976 /* 977 * Function: 978 * trie_repartition 979 * Purpose: 980 * Traverse the trie (PAYLOAD) & call the extended application callback 981 * which has current node's PAYLOAD parent node with user data. 982 */ 983 int trie_repartition(trie_t *trie, trie_repartition_callback_f cb, 984 void *user_data, trie_traverse_order_e_t order) 985 { 986 trie_traverse_states_e_t state = TRIE_TRAVERSE_STATE_NONE; 987 988 if (order < _TRIE_PREORDER_TRAVERSE || 989 order >= _TRIE_TRAVERSE_MAX || !cb) return SOC_E_PARAM; 990 991 #ifdef REPART_DEBUG 992 if (repart_debug) { 993 repart_trie = trie; 994 LOG_CLI(("=====================\n")); 995 trie_dump(repart_trie, 0, 0); 996 } 997 #endif 998 if (trie == NULL) { 999 return SOC_E_NONE; 1000 } else { 1001 return _trie_repartition(NULL, trie->trie, &state, cb, user_data, NULL, 0, NULL, NULL); 1002 } 1003 } 1004 1005 1006 1007 STATIC int _trie_preorder_iter_get_first(trie_node_t *node, trie_node_t **payload) 1008 { 1009 int rv = SOC_E_NONE; 1010 1011 if (!payload) return SOC_E_PARAM; 1012 1013 if (*payload != NULL) return SOC_E_NONE; 1014 1015 if (node == NULL) { 1016 return SOC_E_NONE; 1017 } else { 1018 if (node->type == PAYLOAD) { 1019 *payload = node; 1020 return rv; 1021 } 1022 } 1023 1024 if (SOC_SUCCESS(rv)) { 1025 rv = _trie_preorder_iter_get_first(node->child[0].child_node, payload); 1026 } 1027 if (SOC_SUCCESS(rv)) { 1028 rv = _trie_preorder_iter_get_first(node->child[1].child_node, payload); 1029 } 1030 return rv; 1031 } 1032 1033 /* 1034 * Function: 1035 * trie_iter_get_first 1036 * Purpose: 1037 * Traverse the trie & return pointer to first payload node 1038 */ 1039 int trie_iter_get_first(trie_t *trie, trie_node_t **payload) 1040 { 1041 int rv = SOC_E_EMPTY; 1042 1043 if (!trie || !payload) return SOC_E_PARAM; 1044 1045 if (trie && trie->trie) { 1046 *payload = NULL; 1047 return _trie_preorder_iter_get_first(trie->trie, payload); 1048 } 1049 1050 return rv; 1051 } 1052 1053 STATIC int _trie_dump(trie_node_t *trie, trie_callback_f cb, 1054 void *user_data, unsigned int level) 1055 { 1056 if (trie == NULL) { 1057 return SOC_E_NONE; 1058 } else { 1059 unsigned int lvl = level; 1060 while(lvl) { 1061 if (lvl == 1) { 1062 LOG_CLI((BSL_META("|-"))); 1063 } else { 1064 LOG_CLI((BSL_META("| "))); 1065 } 1066 lvl--; 1067 } 1068 1069 if (cb) { 1070 cb(trie, user_data); 1071 } else { 1072 _print_trie_node(trie, NULL); 1073 } 1074 } 1075 1076 _trie_dump(trie->child[0].child_node, cb, user_data, level+1); 1077 _trie_dump(trie->child[1].child_node, cb, user_data, level+1); 1078 return SOC_E_NONE; 1079 } 1080 1081 /* 1082 * Function: 1083 * trie_dump 1084 * Purpose: 1085 * Dumps the trie pre-order [root|left|child] 1086 */ 1087 int trie_dump(trie_t *trie, trie_callback_f cb, void *user_data) 1088 { 1089 if (trie->trie) { 1090 return _trie_dump(trie->trie, cb, user_data, 0); 1091 } else { 1092 return SOC_E_PARAM; 1093 } 1094 } 1095 1096 STATIC int _trie_search(trie_node_t *trie, 1097 unsigned int *key, 1098 unsigned int length, 1099 trie_node_t **payload, 1100 unsigned int *result_key, 1101 unsigned int *result_len, 1102 unsigned int dump, 1103 unsigned int find_pivot) 1104 { 1105 unsigned int lcp=0; 1106 int bit=0, rv=SOC_E_NONE; 1107 1108 if (!trie || (length && trie->skip_len && !key)) return SOC_E_PARAM; 1109 if ((result_key && !result_len) || (!result_key && result_len)) return SOC_E_PARAM; 1110 1111 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1112 1113 if (dump) { 1114 _print_trie_node(trie, (unsigned int *)1); 1115 } 1116 1117 if (length > trie->skip_len) { 1118 if (lcp == trie->skip_len) { 1119 bit = (key[KEY_BIT2IDX(length - lcp)] & \ 1120 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 1121 if (dump) { 1122 LOG_CLI((BSL_META(" Length: %d Next-Bit[%d] \n"), length, bit)); 1123 } 1124 1125 if (result_key) { 1126 rv = _key_append(result_key, result_len, trie->skip_addr, trie->skip_len); 1127 if (SOC_FAILURE(rv)) return rv; 1128 } 1129 1130 /* based on next bit branch left or right */ 1131 if (trie->child[bit].child_node) { 1132 1133 if (result_key) { 1134 rv = _key_append(result_key, result_len, bit, 1); 1135 if (SOC_FAILURE(rv)) return rv; 1136 } 1137 1138 return _trie_search(trie->child[bit].child_node, key, 1139 length - lcp - 1, payload, 1140 result_key, result_len, dump, find_pivot); 1141 } else { 1142 return SOC_E_NOT_FOUND; /* not found */ 1143 } 1144 } else { 1145 return SOC_E_NOT_FOUND; /* not found */ 1146 } 1147 } else if (length == trie->skip_len) { 1148 if (lcp == length) { 1149 if (dump) { 1150 LOG_CLI((BSL_META(": MATCH \n"))); 1151 } 1152 *payload = trie; 1153 if (trie->type != PAYLOAD && !find_pivot) { 1154 /* no assert here, possible during dbucket search 1155 * due to 1* and 0* bucket search 1156 */ 1157 return SOC_E_NOT_FOUND; 1158 } 1159 if (result_key) { 1160 rv = _key_append(result_key, result_len, trie->skip_addr, trie->skip_len); 1161 if (SOC_FAILURE(rv)) return rv; 1162 } 1163 return SOC_E_NONE; 1164 } 1165 else return SOC_E_NOT_FOUND; 1166 } else { 1167 if (lcp == length && find_pivot) { 1168 *payload = trie; 1169 if (result_key) { 1170 rv = _key_append(result_key, result_len, trie->skip_addr, trie->skip_len); 1171 if (SOC_FAILURE(rv)) return rv; 1172 } 1173 return SOC_E_NONE; 1174 } 1175 return SOC_E_NOT_FOUND; /* not found */ 1176 } 1177 } 1178 1179 /* 1180 * Function: 1181 * trie_search 1182 * Purpose: 1183 * Search the given trie for exact match of provided prefix/length 1184 * If dump is set to 1 it traces the path as it traverses the trie 1185 */ 1186 int trie_search(trie_t *trie, 1187 unsigned int *key, 1188 unsigned int length, 1189 trie_node_t **payload) 1190 { 1191 if (trie->trie) { 1192 if (trie->v6_key) { 1193 return _trie_v6_search(trie->trie, key, length, payload, NULL, NULL, 0, 0); 1194 } else { 1195 return _trie_search(trie->trie, key, length, payload, NULL, NULL, 0, 0); 1196 } 1197 } else { 1198 return SOC_E_NOT_FOUND; 1199 } 1200 } 1201 1202 /* 1203 * Function: 1204 * trie_search_verbose 1205 * Purpose: 1206 * Search the given trie for provided prefix/length 1207 * If dump is set to 1 it traces the path as it traverses the trie 1208 */ 1209 int trie_search_verbose(trie_t *trie, 1210 unsigned int *key, 1211 unsigned int length, 1212 trie_node_t **payload, 1213 unsigned int *result_key, 1214 unsigned int *result_len) 1215 { 1216 if (trie->trie) { 1217 if (trie->v6_key) { 1218 return _trie_v6_search(trie->trie, key, length, payload, result_key, result_len, 0, 0); 1219 } else { 1220 return _trie_search(trie->trie, key, length, payload, result_key, result_len, 0, 0); 1221 } 1222 } else { 1223 return SOC_E_NOT_FOUND; 1224 } 1225 } 1226 1227 /* 1228 * Internal function for LPM match searching. 1229 * callback on all payload nodes if cb != NULL. 1230 */ 1231 STATIC int _trie_find_lpm(trie_node_t *trie, 1232 unsigned int *key, 1233 unsigned int length, 1234 trie_node_t **payload, 1235 trie_callback_f cb, 1236 void *user_data, 1237 unsigned int exclude_self) 1238 { 1239 unsigned int lcp=0; 1240 int bit=0, rv=SOC_E_NONE; 1241 1242 if (!trie || (length && trie->skip_len && !key)) return SOC_E_PARAM; 1243 1244 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1245 1246 if ((length > trie->skip_len) && (lcp == trie->skip_len)) { 1247 if (trie->type == PAYLOAD) { 1248 /* lpm cases */ 1249 if (payload != NULL) { 1250 /* update lpm result */ 1251 *payload = trie; 1252 } 1253 1254 if (cb != NULL) { 1255 /* callback with any nodes which is shorter and matches the prefix */ 1256 rv = cb(trie, user_data); 1257 if (SOC_FAILURE(rv)) { 1258 /* early bailout if there is error in callback handling */ 1259 return rv; 1260 } 1261 } 1262 } 1263 1264 bit = (key[KEY_BIT2IDX(length - lcp)] & \ 1265 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 1266 1267 /* based on next bit branch left or right */ 1268 if (trie->child[bit].child_node) { 1269 return _trie_find_lpm(trie->child[bit].child_node, key, length - lcp - 1, 1270 payload, cb, user_data, exclude_self); 1271 } 1272 } else if ((length == trie->skip_len) && (lcp == length)) { 1273 if (trie->type == PAYLOAD) { 1274 /* exact match case */ 1275 if (payload != NULL && !exclude_self) { 1276 /* lpm is exact match */ 1277 *payload = trie; 1278 } 1279 1280 if (cb != NULL) { 1281 /* callback with the exact match node */ 1282 rv = cb(trie, user_data); 1283 if (SOC_FAILURE(rv)) { 1284 /* early bailout if there is error in callback handling */ 1285 return rv; 1286 } 1287 } 1288 } 1289 } 1290 return rv; 1291 } 1292 1293 /* 1294 * Function: 1295 * trie_find_lpm 1296 * Purpose: 1297 * Find the longest prefix matched with given prefix 1298 */ 1299 int trie_find_lpm(trie_t *trie, 1300 unsigned int *key, 1301 unsigned int length, 1302 trie_node_t **payload) 1303 { 1304 int rv = SOC_E_NONE; 1305 1306 *payload = NULL; 1307 1308 if (trie->trie) { 1309 if (trie->v6_key) { 1310 rv = _trie_v6_find_lpm(trie->trie, key, length, payload, 1311 NULL, NULL, 0); 1312 } else { 1313 rv = _trie_find_lpm(trie->trie, key, length, payload, 1314 NULL, NULL, 0); 1315 } 1316 if (*payload || (rv != SOC_E_NONE)) { 1317 return rv; 1318 } 1319 } 1320 1321 return SOC_E_NOT_FOUND; 1322 } 1323 1324 1325 1326 /* 1327 * Function: 1328 * trie_find_lpm2 1329 * Purpose: 1330 * Find the longest prefix matched with given prefix 1331 */ 1332 int trie_find_lpm2(trie_t *trie, 1333 unsigned int *key, 1334 unsigned int length, 1335 trie_node_t **payload) 1336 { 1337 int rv = SOC_E_NONE; 1338 1339 *payload = NULL; 1340 1341 if (trie->trie) { 1342 if (trie->v6_key) { 1343 rv = _trie_v6_find_lpm(trie->trie, key, length, payload, 1344 NULL, NULL, 1); 1345 } else { 1346 rv = _trie_find_lpm(trie->trie, key, length, payload, 1347 NULL, NULL, 1); 1348 } 1349 if (*payload || (rv != SOC_E_NONE)) { 1350 return rv; 1351 } 1352 } 1353 1354 return SOC_E_NOT_FOUND; 1355 } 1356 1357 1358 /* 1359 * Function: 1360 * trie_find_pm 1361 * Purpose: 1362 * Find the prefix matched nodes with given prefix and callback 1363 * with specified callback funtion and user data 1364 */ 1365 int trie_find_pm(trie_t *trie, 1366 unsigned int *key, 1367 unsigned int length, 1368 trie_callback_f cb, 1369 void *user_data) 1370 { 1371 1372 if (trie->trie) { 1373 if (trie->v6_key) { 1374 return _trie_v6_find_lpm(trie->trie, key, length, NULL, cb, user_data, 0); 1375 } else { 1376 return _trie_find_lpm(trie->trie, key, length, NULL, cb, user_data, 0); 1377 } 1378 } 1379 1380 return SOC_E_NONE; 1381 } 1382 1383 /* trie->bpm format: 1384 * bit 0 is for the pivot itself (longest) 1385 * bit skip_len is for the trie branch leading to the pivot node (shortest) 1386 * bits (0-skip_len) is for the routes in the parent node's bucket 1387 */ 1388 int _trie_find_bpm(trie_node_t *trie, 1389 unsigned int *key, 1390 unsigned int length, 1391 int *bpm_length) 1392 { 1393 unsigned int lcp=0, local_bpm_mask=0; 1394 int bit=0, rv=SOC_E_NONE, local_bpm=0; 1395 1396 if (!trie || (length && trie->skip_len && !key) || 1397 (length > _MAX_KEY_LEN_)) return SOC_E_PARAM; 1398 1399 /* calculate number of matching msb bits */ 1400 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1401 1402 if (length > trie->skip_len) { 1403 if (lcp == trie->skip_len) { 1404 /* fully matched and more bits to check, go down the trie */ 1405 bit = (key[KEY_BIT2IDX(length - lcp)] & \ 1406 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 1407 1408 if (trie->child[bit].child_node) { 1409 rv = _trie_find_bpm(trie->child[bit].child_node, key, length - lcp - 1, bpm_length); 1410 /* on the way back, start bpm_length accumulation when encounter first non-0 bpm */ 1411 if (*bpm_length >= 0) { 1412 /* child node has non-zero bpm, just need to accumulate skip_len and branch bit */ 1413 *bpm_length += (trie->skip_len+1); 1414 return rv; 1415 } else if (trie->bpm & BITMASK(trie->skip_len+1)) { 1416 /* first non-zero bmp on the way back */ 1417 BITGETLSBSET(trie->bpm, trie->skip_len, local_bpm); 1418 if (local_bpm >= 0) { 1419 *bpm_length = trie->skip_len - local_bpm; 1420 } 1421 } 1422 /* on the way back, and so far all bpm are 0 */ 1423 return rv; 1424 } 1425 } 1426 } 1427 1428 /* no need to go further, we find whatever bits matched and 1429 * check that part of the bpm mask 1430 */ 1431 /* coverity[large_shift : FALSE] */ 1432 local_bpm_mask = trie->bpm & (~(BITMASK(trie->skip_len-lcp))); 1433 if (local_bpm_mask & BITMASK(trie->skip_len+1)) { 1434 /* first non-zero bmp on the way back */ 1435 BITGETLSBSET(local_bpm_mask, trie->skip_len, local_bpm); 1436 if (local_bpm >= 0) { 1437 *bpm_length = trie->skip_len - local_bpm; 1438 } 1439 } 1440 1441 return rv; 1442 } 1443 1444 /* 1445 * Function: 1446 * trie_find_prefix_bpm 1447 * Purpose: 1448 * Given a key/length return the Best prefix match length 1449 * key/bpm_pfx_len will be the BPM for the key/length 1450 * using the bpm info in the trie database 1451 */ 1452 int trie_find_prefix_bpm(trie_t *trie, 1453 unsigned int *key, 1454 unsigned int length, 1455 unsigned int *bpm_pfx_len) 1456 { 1457 /* Return: SOC_E_EMPTY is not bpm bit is found */ 1458 int rv = SOC_E_EMPTY, bpm=0; 1459 1460 if (!trie || !key || !bpm_pfx_len ) { 1461 return SOC_E_PARAM; 1462 } 1463 1464 bpm = -1; 1465 if (trie->trie) { 1466 if (trie->v6_key) { 1467 rv = _trie_v6_find_bpm(trie->trie, key, length, &bpm); 1468 } else { 1469 rv = _trie_find_bpm(trie->trie, key, length, &bpm); 1470 } 1471 1472 if (SOC_SUCCESS(rv)) { 1473 /* all bpm bits are 0 */ 1474 *bpm_pfx_len = (bpm < 0)? 0:(unsigned int)bpm; 1475 } 1476 } 1477 1478 return rv; 1479 } 1480 1481 STATIC int _trie_bpm_mask_get(trie_node_t *trie, 1482 unsigned int *key, 1483 unsigned int length, 1484 unsigned int *bpm_mask) 1485 { 1486 unsigned int lcp=0, scratch=0; 1487 int bit=0, rv=SOC_E_NONE; 1488 1489 if (!trie || (length > _MAX_KEY_LEN_)) return SOC_E_PARAM; 1490 1491 /* calculate number of matching msb bits */ 1492 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1493 1494 if (length > trie->skip_len) { 1495 if (lcp == trie->skip_len) { 1496 /* fully matched and more bits to check, go down the trie */ 1497 bit = (key[KEY_BIT2IDX(length - lcp)] & \ 1498 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 1499 1500 if (trie->child[bit].child_node) { 1501 _bpm_append(bpm_mask, &scratch, trie->bpm, trie->skip_len + 1); 1502 rv = _trie_bpm_mask_get(trie->child[bit].child_node, key, length - lcp - 1, bpm_mask); 1503 return rv; 1504 } 1505 } 1506 } 1507 1508 _bpm_append(bpm_mask, &scratch, trie->bpm, trie->skip_len + 1); 1509 return rv; 1510 } 1511 1512 /* 1513 * Function: 1514 * trie_bpm_mask_get 1515 * Purpose: 1516 * Get the bpm mask of target key. This key is already in the trie. 1517 */ 1518 int trie_bpm_mask_get(trie_t *trie, 1519 unsigned int *key, 1520 unsigned int length, 1521 unsigned int *bpm_mask) 1522 { 1523 int rv = SOC_E_NONE; 1524 1525 if (!trie || !key || !bpm_mask ) { 1526 return SOC_E_PARAM; 1527 } 1528 1529 if (trie->trie) { 1530 if (trie->v6_key) { 1531 rv = _trie_v6_bpm_mask_get(trie->trie, key, length, bpm_mask); 1532 } else { 1533 rv = _trie_bpm_mask_get(trie->trie, key, length, bpm_mask); 1534 } 1535 } 1536 return rv; 1537 } 1538 1539 /* 1540 * Function: 1541 * _trie_skip_node_free 1542 * Purpose: 1543 * Destroy a chain of trie_node_t that has the target node at the end. 1544 * The target node is not necessarily PAYLOAD type, but all nodes 1545 * on the chain except for the end must have only one branch. 1546 * Input: 1547 * key -- target key 1548 * length -- target key length 1549 * free_end -- free 1550 */ 1551 STATIC int _trie_skip_node_free(trie_node_t *trie, 1552 unsigned int *key, 1553 unsigned int length) 1554 { 1555 unsigned int lcp=0; 1556 int bit=0, rv=SOC_E_NONE; 1557 1558 if (!trie || (length && trie->skip_len && !key)) return SOC_E_PARAM; 1559 1560 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1561 1562 1563 if (length > trie->skip_len) { 1564 1565 if (lcp == trie->skip_len) { 1566 bit = (key[KEY_BIT2IDX(length - lcp)] & \ 1567 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 1568 1569 /* There should be only one branch on the chain until the end node */ 1570 if (!trie->child[0].child_node == !trie->child[1].child_node) { 1571 return SOC_E_PARAM; 1572 } 1573 1574 /* based on next bit branch left or right */ 1575 if (trie->child[bit].child_node) { 1576 rv = _trie_skip_node_free(trie->child[bit].child_node, key, 1577 length - lcp - 1); 1578 if (SOC_SUCCESS(rv)) { 1579 assert(trie->type == INTERNAL); 1580 sal_free(trie); 1581 } 1582 return rv; 1583 } else { 1584 return SOC_E_NOT_FOUND; /* not found */ 1585 } 1586 } else { 1587 return SOC_E_NOT_FOUND; /* not found */ 1588 } 1589 } else if (length == trie->skip_len) { 1590 if (lcp == length) { 1591 /* the end node is not necessarily type payload. */ 1592 /* Do not free the end */ 1593 1594 return SOC_E_NONE; 1595 } 1596 else return SOC_E_NOT_FOUND; 1597 } else { 1598 return SOC_E_NOT_FOUND; /* not found */ 1599 } 1600 } 1601 1602 1603 1604 /* 1605 * Function: 1606 * _trie_skip_node_alloc 1607 * Purpose: 1608 * create a chain of trie_node_t that has the payload at the end. 1609 * each node in the chain can skip upto _MAX_SKIP_LEN number of bits, 1610 * while the child pointer in the chain represent 1 bit. So totally 1611 * each node can absorb (_MAX_SKIP_LEN+1) bits. 1612 * Input: 1613 * key -- 1614 * bpm -- 1615 * msb -- 1616 * skip_len -- skip_len of the whole chain 1617 * payload -- payload node we want to insert 1618 * count -- child count 1619 * Output: 1620 * node -- return pointer of the starting node of the chain. 1621 */ 1622 STATIC int _trie_skip_node_alloc(trie_node_t **node, 1623 unsigned int *key, 1624 /* bpm bit map if bpm management is required, passing null skips bpm management */ 1625 unsigned int *bpm, 1626 unsigned int msb, /* NOTE: valid msb position 1 based, 0 means skip0/0 node */ 1627 unsigned int skip_len, 1628 trie_node_t *payload, 1629 unsigned int count) /* payload count underneath - mostly 1 except some tricky cases */ 1630 { 1631 int lsb=0, msbpos=0, lsbpos=0, bit=0, index; 1632 trie_node_t *child = NULL, *skip_node = NULL; 1633 1634 /* calculate lsb bit position, also 1 based */ 1635 lsb = ((msb)? msb + 1 - skip_len : msb); 1636 1637 assert(((int)msb >= 0) && (lsb >= 0)); 1638 1639 if (!node || !key || !payload || msb > _MAX_KEY_LEN_ || msb < skip_len) return SOC_E_PARAM; 1640 1641 if (msb) { 1642 for (index = BITS2SKIPOFF(lsb), lsbpos = lsb - 1; index <= BITS2SKIPOFF(msb); index++) { 1643 /* each loop process _MAX_SKIP_LEN number of bits?? */ 1644 if (lsbpos == lsb-1) { 1645 /* (lsbpos == lsb-1) is only true for first node (loop) here */ 1646 skip_node = payload; 1647 } else { 1648 /* other nodes need to be created */ 1649 skip_node = sal_alloc(sizeof(trie_node_t), "trie_node"); 1650 } 1651 1652 /* init memory */ 1653 sal_memset(skip_node, 0, sizeof(trie_node_t)); 1654 1655 /* calculate msb bit position of current chunk of bits we are processing */ 1656 msbpos = index * _MAX_SKIP_LEN_ - 1; 1657 if (msbpos > msb-1) msbpos = msb-1; 1658 1659 /* calculate the skip_len of the created node */ 1660 if (msbpos - lsbpos < _MAX_SKIP_LEN_) { 1661 skip_node->skip_len = msbpos - lsbpos + 1; 1662 } else { 1663 skip_node->skip_len = _MAX_SKIP_LEN_; 1664 } 1665 1666 /* calculate the skip_addr (skip_length number of bits). 1667 * skip might be skipping bits on 2 different words 1668 * if msb & lsb spawns 2 word boundary in worst case 1669 */ 1670 if (BITS2WORDS(msbpos+1) != BITS2WORDS(lsbpos+1)) { 1671 /* pull snippets from the different words & fuse */ 1672 skip_node->skip_addr = key[KEY_BIT2IDX(msbpos+1)] & MASK((msbpos+1) % _NUM_WORD_BITS_); 1673 skip_node->skip_addr = SHL(skip_node->skip_addr, 1674 skip_node->skip_len - ((msbpos+1) % _NUM_WORD_BITS_), 1675 _NUM_WORD_BITS_); 1676 skip_node->skip_addr |= SHR(key[KEY_BIT2IDX(lsbpos+1)],(lsbpos % _NUM_WORD_BITS_),_NUM_WORD_BITS_); 1677 } else { 1678 skip_node->skip_addr = SHR(key[KEY_BIT2IDX(msbpos+1)], (lsbpos % _NUM_WORD_BITS_),_NUM_WORD_BITS_); 1679 } 1680 1681 /* set up the chain of child pointer, first node has no child since "child" was inited to NULL */ 1682 if (child) { 1683 skip_node->child[bit].child_node = child; 1684 } 1685 1686 /* calculate child pointer for next loop. NOTE: skip_addr has not been masked 1687 * so we still have the child bit in the skip_addr here. 1688 */ 1689 bit = (skip_node->skip_addr & SHL(1, skip_node->skip_len - 1,_MAX_SKIP_LEN_)) ? 1:0; 1690 1691 /* calculate node type */ 1692 if (lsbpos == lsb-1) { 1693 /* first node is payload */ 1694 skip_node->type = PAYLOAD; 1695 } else { 1696 /* other nodes are internal nodes */ 1697 skip_node->type = INTERNAL; 1698 } 1699 1700 /* all internal nodes will have the same "count" as the payload node */ 1701 skip_node->count = count; 1702 1703 /* advance lsb to next word */ 1704 lsbpos += skip_node->skip_len; 1705 1706 /* calculate bpm of the skip_node */ 1707 if (bpm) { 1708 if (lsbpos == _MAX_KEY_LEN_) { 1709 /* parent node is 0/0, so there is no branch bit here */ 1710 skip_node->bpm = _key_get_bits(bpm, lsbpos, skip_node->skip_len, 1); 1711 } else { 1712 skip_node->bpm = _key_get_bits(bpm, lsbpos+1, skip_node->skip_len+1, 1); 1713 } 1714 } 1715 1716 /* for all child nodes 0/1 is implicitly obsorbed on parent */ 1717 if (msbpos != msb-1) { 1718 /* msbpos == (msb-1) is only true for the first node */ 1719 skip_node->skip_len--; 1720 } 1721 skip_node->bpm &= MASK(skip_node->skip_len + 1); 1722 skip_node->skip_addr &= MASK(skip_node->skip_len); 1723 child = skip_node; 1724 } 1725 } else { 1726 /* skip_len == 0 case, create a payload node with skip_len = 0 and bpm should be 1 bits only 1727 * bit 0 and bit "skip_len" are same bit (bit 0). 1728 */ 1729 skip_node = payload; 1730 sal_memset(skip_node, 0, sizeof(trie_node_t)); 1731 skip_node->type = PAYLOAD; 1732 skip_node->count = count; 1733 if (bpm) { 1734 skip_node->bpm = _key_get_bits(bpm,1,1,0); 1735 } 1736 } 1737 1738 *node = skip_node; 1739 return SOC_E_NONE; 1740 } 1741 1742 STATIC int _trie_insert(trie_node_t *trie, 1743 unsigned int *key, 1744 /* bpm bit map if bpm management is required, passing null skips bpm management */ 1745 unsigned int *bpm, 1746 unsigned int length, 1747 trie_node_t *payload, /* payload node */ 1748 trie_node_t **child, /* child pointer if the child is modified */ 1749 int child_count) 1750 { 1751 unsigned int lcp; 1752 int rv=SOC_E_NONE, bit=0; 1753 trie_node_t *node = NULL; 1754 1755 if (!trie || (length && trie->skip_len && !key) || 1756 !payload || !child || (length > _MAX_KEY_LEN_)) 1757 return SOC_E_PARAM; 1758 1759 *child = NULL; 1760 1761 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1762 1763 /* insert cases: 1764 * 1 - new key could be the parent of existing node 1765 * 2 - new key could become the child of a existing node 1766 * 3 - internal node could be inserted and the key becomes one of child 1767 * 4 - internal node is converted to a payload node */ 1768 1769 /* if the new key qualifies as new root do the inserts here */ 1770 if (lcp == length) { /* guaranteed: length < _MAX_SKIP_LEN_ */ 1771 if (trie->skip_len == lcp) { 1772 if (trie->type != INTERNAL) { 1773 /* duplicate */ 1774 return SOC_E_EXISTS; 1775 } else { 1776 /* change the internal node to payload node */ 1777 _CLONE_TRIE_NODE_(payload,trie); 1778 sal_free(trie); 1779 payload->type = PAYLOAD; 1780 payload->count += child_count; 1781 *child = payload; 1782 1783 if (bpm) { 1784 /* bpm at this internal mode must be same as the inserted pivot */ 1785 payload->bpm |= _key_get_bits(bpm, lcp+1, lcp+1, 1); 1786 /* implicity preserve the previous bpm & set bit 0 -myself bit */ 1787 } 1788 return SOC_E_NONE; 1789 } 1790 } else { /* skip length can never be less than lcp implcitly here */ 1791 /* this node is new parent for the old trie node */ 1792 /* lcp is the new skip length */ 1793 _CLONE_TRIE_NODE_(payload,trie); 1794 *child = payload; 1795 1796 bit = (trie->skip_addr & SHL(1,trie->skip_len - length - 1,_MAX_SKIP_LEN_)) ? 1 : 0; 1797 trie->skip_addr &= MASK(trie->skip_len - length - 1); 1798 trie->skip_len -= (length + 1); 1799 1800 if (bpm) { 1801 trie->bpm &= MASK(trie->skip_len+1); 1802 } 1803 1804 payload->skip_addr = (length > 0) ? key[KEY_BIT2IDX(length)] : 0; 1805 payload->skip_addr &= MASK(length); 1806 payload->skip_len = length; 1807 payload->child[bit].child_node = trie; 1808 payload->child[!bit].child_node = NULL; 1809 payload->type = PAYLOAD; 1810 payload->count += child_count; 1811 1812 if (bpm) { 1813 payload->bpm = SHR(payload->bpm, trie->skip_len + 1,_NUM_WORD_BITS_); 1814 payload->bpm |= _key_get_bits(bpm, payload->skip_len+1, payload->skip_len+1, 1); 1815 } 1816 } 1817 } else if (lcp == trie->skip_len) { 1818 /* key length is implictly greater than lcp here */ 1819 /* decide based on key's next applicable bit */ 1820 bit = (key[KEY_BIT2IDX(length-lcp)] & 1821 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 1822 1823 if (!trie->child[bit].child_node) { 1824 /* the key is going to be one of the child of existing node */ 1825 /* should be the child */ 1826 rv = _trie_skip_node_alloc(&node, key, bpm, 1827 length-lcp-1, /* 0 based msbit position */ 1828 length-lcp-1, 1829 payload, child_count); 1830 if (SOC_SUCCESS(rv)) { 1831 trie->child[bit].child_node = node; 1832 trie->count += child_count; 1833 } else { 1834 LOG_CLI((BSL_META("\n Error on trie skip node allocaiton [%d]!!!!\n"), 1835 rv)); 1836 } 1837 } else { 1838 rv = _trie_insert(trie->child[bit].child_node, 1839 key, bpm, length - lcp - 1, 1840 payload, child, child_count); 1841 if (SOC_SUCCESS(rv)) { 1842 trie->count += child_count; 1843 if (*child != NULL) { /* chande the old child pointer to new child */ 1844 trie->child[bit].child_node = *child; 1845 *child = NULL; 1846 } 1847 } 1848 } 1849 } else { 1850 trie_node_t *newchild = NULL; 1851 1852 /* need to introduce internal nodes */ 1853 node = sal_alloc(sizeof(trie_node_t), "trie-node"); 1854 _CLONE_TRIE_NODE_(node, trie); 1855 1856 rv = _trie_skip_node_alloc(&newchild, key, bpm, 1857 ((lcp)?length-lcp-1:length-1), 1858 length - lcp - 1, 1859 payload, child_count); 1860 if (SOC_SUCCESS(rv)) { 1861 bit = (key[KEY_BIT2IDX(length-lcp)] & 1862 (1 << ((length - lcp - 1) % _NUM_WORD_BITS_))) ? 1: 0; 1863 1864 node->child[!bit].child_node = trie; 1865 node->child[bit].child_node = newchild; 1866 node->type = INTERNAL; 1867 node->skip_addr = SHR(trie->skip_addr,trie->skip_len - lcp,_MAX_SKIP_LEN_); 1868 node->skip_len = lcp; 1869 node->count += child_count; 1870 if (bpm) { 1871 node->bpm = SHR(node->bpm, trie->skip_len - lcp, _MAX_SKIP_LEN_); 1872 } 1873 *child = node; 1874 1875 trie->skip_addr &= MASK(trie->skip_len - lcp - 1); 1876 trie->skip_len -= (lcp + 1); 1877 if (bpm) { 1878 trie->bpm &= MASK(trie->skip_len+1); 1879 } 1880 } else { 1881 LOG_CLI((BSL_META("\n Error on trie skip node allocaiton [%d]!!!!\n"), rv)); 1882 sal_free(node); 1883 } 1884 } 1885 1886 return rv; 1887 } 1888 1889 /* 1890 * Function: 1891 * trie_insert 1892 * Purpose: 1893 * Inserts provided prefix/length in to the trie 1894 */ 1895 int trie_insert(trie_t *trie, 1896 unsigned int *key, 1897 unsigned int *bpm, 1898 unsigned int length, 1899 trie_node_t *payload) 1900 { 1901 int rv = SOC_E_NONE; 1902 trie_node_t *child=NULL; 1903 1904 if (!trie) return SOC_E_PARAM; 1905 1906 if (trie->trie == NULL) { 1907 if (trie->v6_key) { 1908 rv = _trie_v6_skip_node_alloc(&trie->trie, key, bpm, length, length, payload, 1); 1909 } else { 1910 rv = _trie_skip_node_alloc(&trie->trie, key, bpm, length, length, payload, 1); 1911 } 1912 } else { 1913 if (trie->v6_key) { 1914 rv = _trie_v6_insert(trie->trie, key, bpm, length, payload, &child, 1); 1915 } else { 1916 rv = _trie_insert(trie->trie, key, bpm, length, payload, &child, 1); 1917 } 1918 if (child) { /* chande the old child pointer to new child */ 1919 trie->trie = child; 1920 } 1921 } 1922 1923 return rv; 1924 } 1925 1926 int _trie_fuse_child(trie_node_t *trie, int bit) 1927 { 1928 trie_node_t *child = NULL; 1929 int rv = SOC_E_NONE; 1930 1931 if (trie->child[0].child_node && trie->child[1].child_node) { 1932 return SOC_E_PARAM; 1933 } 1934 1935 bit = (bit > 0)?1:0; 1936 child = trie->child[bit].child_node; 1937 1938 if (child == NULL) { 1939 return SOC_E_PARAM; 1940 } else { 1941 if (trie->skip_len + child->skip_len + 1 <= _MAX_SKIP_LEN_) { 1942 1943 if (trie->skip_len == 0) trie->skip_addr = 0; 1944 1945 if (child->skip_len < _MAX_SKIP_LEN_) { 1946 trie->skip_addr = SHL(trie->skip_addr,child->skip_len + 1,_MAX_SKIP_LEN_); 1947 } 1948 1949 trie->skip_addr |= SHL(bit,child->skip_len,_MAX_SKIP_LEN_); 1950 child->skip_addr |= trie->skip_addr; 1951 child->bpm |= SHL(trie->bpm,child->skip_len+1,_MAX_SKIP_LEN_); 1952 child->skip_len += trie->skip_len + 1; 1953 1954 /* do not free payload nodes as they are user managed */ 1955 if (trie->type == INTERNAL) { 1956 sal_free(trie); 1957 } 1958 } 1959 } 1960 1961 return rv; 1962 } 1963 1964 STATIC int _trie_delete(trie_node_t *trie, 1965 unsigned int *key, 1966 unsigned int length, 1967 trie_node_t **payload, 1968 trie_node_t **child) 1969 { 1970 unsigned int lcp; 1971 int rv=SOC_E_NONE, bit=0; 1972 trie_node_t *node = NULL; 1973 1974 /* our algorithm should return before the length < 0, so this means 1975 * something wrong with the trie structure. Internal error? 1976 */ 1977 if (!trie || (length && trie->skip_len && !key) || 1978 !payload || !child || (length > _MAX_KEY_LEN_)) { 1979 return SOC_E_PARAM; 1980 } 1981 1982 *child = NULL; 1983 1984 /* check a section of key, return the number of matched bits and value of next bit */ 1985 lcp = lcplen(key, length, trie->skip_addr, trie->skip_len); 1986 1987 if (length > trie->skip_len) { 1988 1989 if (lcp == trie->skip_len) { 1990 1991 bit = (key[KEY_BIT2IDX(length-lcp)] & 1992 (1 << ((length - lcp -1) % _NUM_WORD_BITS_))) ? 1:0; 1993 1994 /* based on next bit branch left or right */ 1995 if (trie->child[bit].child_node) { 1996 1997 /* has child node, keep searching */ 1998 rv = _trie_delete(trie->child[bit].child_node, key, length - lcp - 1, payload, child); 1999 2000 if (rv == SOC_E_BUSY) { 2001 2002 trie->child[bit].child_node = NULL; /* sal_free the child */ 2003 rv = SOC_E_NONE; 2004 trie->count--; 2005 2006 if (trie->type == INTERNAL) { 2007 2008 bit = (bit==0)?1:0; 2009 2010 if (trie->child[bit].child_node == NULL) { 2011 /* parent and child connected, sal_free the middle-node itself */ 2012 sal_free(trie); 2013 rv = SOC_E_BUSY; 2014 } else { 2015 /* fuse the parent & child */ 2016 if (trie->skip_len + trie->child[bit].child_node->skip_len + 1 <= 2017 _MAX_SKIP_LEN_) { 2018 *child = trie->child[bit].child_node; 2019 rv = _trie_fuse_child(trie, bit); 2020 if (rv != SOC_E_NONE) { 2021 *child = NULL; 2022 } 2023 } 2024 } 2025 } 2026 } else if (SOC_SUCCESS(rv)) { 2027 trie->count--; 2028 /* update child pointer if applicable */ 2029 if (*child != NULL) { 2030 trie->child[bit].child_node = *child; 2031 *child = NULL; 2032 } 2033 } 2034 } else { 2035 /* no child node case 0: not found */ 2036 rv = SOC_E_NOT_FOUND; 2037 } 2038 2039 } else { 2040 /* some bits are not matching, case 0: not found */ 2041 rv = SOC_E_NOT_FOUND; 2042 } 2043 } else if (length == trie->skip_len) { 2044 /* when length equal to skip_len, unless this is a payload node 2045 * and it's an exact match (lcp == length), we can not found a match 2046 */ 2047 if (!((lcp == length) && (trie->type == PAYLOAD))) { 2048 rv = SOC_E_NOT_FOUND; 2049 } else { 2050 /* payload node can be deleted */ 2051 /* if this node has 2 children update it to internal node */ 2052 rv = SOC_E_NONE; 2053 2054 if (trie->child[0].child_node && trie->child[1].child_node ) { 2055 /* the node has 2 children, update it to internal node */ 2056 _BITCLR(trie->bpm, 0); 2057 node = sal_alloc(sizeof(trie_node_t), "trie_node"); 2058 _CLONE_TRIE_NODE_(node, trie); 2059 node->type = INTERNAL; 2060 node->count--; 2061 *child = node; 2062 } else if (trie->child[0].child_node || trie->child[1].child_node ) { 2063 /* if this node has 1 children fuse the children with this node */ 2064 bit = (trie->child[0].child_node) ? 0:1; 2065 trie->count--; 2066 if (trie->skip_len + trie->child[bit].child_node->skip_len + 1 <= _MAX_SKIP_LEN_) { 2067 /* we need to clear the bpm bit of itself before fusing with child */ 2068 _BITCLR(trie->bpm, 0); 2069 2070 /* able to fuse the node with its child node */ 2071 *child = trie->child[bit].child_node; 2072 rv = _trie_fuse_child(trie, bit); 2073 if (rv != SOC_E_NONE) { 2074 *child = NULL; 2075 } 2076 } else { 2077 /* convert it to internal node, we need to alloc new memory for internal nodes 2078 * since the old payload node memory will be freed by caller 2079 */ 2080 /* we need to clear the bpm bit of itself before converting */ 2081 _BITCLR(trie->bpm, 0); 2082 2083 node = sal_alloc(sizeof(trie_node_t), "trie_node"); 2084 _CLONE_TRIE_NODE_(node, trie); 2085 node->type = INTERNAL; 2086 *child = node; 2087 } 2088 } else { 2089 rv = SOC_E_BUSY; 2090 } 2091 2092 *payload = trie; 2093 } 2094 } else { 2095 /* key length is shorter, no match if it's internal node, 2096 * will not exact match even if this is a payload node 2097 */ 2098 rv = SOC_E_NOT_FOUND; /* case 0: not found */ 2099 } 2100 2101 return rv; 2102 } 2103 2104 /* 2105 * Function: 2106 * trie_delete 2107 * Purpose: 2108 * Deletes provided prefix/length in to the trie 2109 */ 2110 int trie_delete(trie_t *trie, 2111 unsigned int *key, 2112 unsigned int length, 2113 trie_node_t **payload) 2114 { 2115 int rv = SOC_E_NONE; 2116 trie_node_t *child = NULL; 2117 2118 if (trie->trie) { 2119 if (trie->v6_key) { 2120 rv = _trie_v6_delete(trie->trie, key, length, payload, &child); 2121 } else { 2122 rv = _trie_delete(trie->trie, key, length, payload, &child); 2123 } 2124 if (rv == SOC_E_BUSY) { 2125 /* the head node of trie was deleted, reset trie pointer to null */ 2126 trie->trie = NULL; 2127 rv = SOC_E_NONE; 2128 } else if (rv == SOC_E_NONE && child != NULL) { 2129 trie->trie = child; 2130 } 2131 } else { 2132 rv = SOC_E_NOT_FOUND; 2133 } 2134 return rv; 2135 } 2136 2137 STATIC INLINE int 2138 _trie_splitable(trie_node_t *trie, trie_node_t *child, int max_count, int max_split_count) 2139 { 2140 /* 2141 * NOTE: 2142 * ABS(trie->count * 2 - max_count) actually means 2143 * ABS(trie->count - (max_count - trie->count)) 2144 * which means the count's distance to half depth of the bucket 2145 */ 2146 int do_split = 0; 2147 int half_count = (max_count + 1) >> 1; 2148 2149 if (trie->count <= max_split_count && trie->count != max_count) { 2150 if (child == NULL) { 2151 do_split = 1; 2152 } else if (trie->count >= half_count && child->count < half_count) { 2153 do_split = 1; 2154 } else if (trie->count == half_count && child->count == half_count) { 2155 do_split = 1; 2156 } else if (ABS(child->count * 2 - max_count) > 2157 ABS(trie->count * 2 - max_count)) { 2158 do_split = 1; 2159 } 2160 } 2161 2162 return do_split; 2163 } 2164 2165 /* 2166 * Function: 2167 * trie_split 2168 * Purpose: 2169 * Split the trie into 2 based on optimum pivot 2170 * NOTE: 2171 * max_split_len -- split will make sure the split point 2172 * has a length shorter or equal to the max_split_len 2173 * unless this will cause a no-split (all prefixs 2174 * stays below the split point) 2175 * split_to_pair -- used only when the split point will be 2176 * used to create a pair of tries later (i.e: dbucket 2177 * pair. we assume the split point itself will always be 2178 * put into 0* trie if itself is a payload/prefix) 2179 */ 2180 STATIC int _trie_split(trie_node_t *trie, 2181 unsigned int *pivot, 2182 unsigned int *length, 2183 unsigned int *split_count, 2184 trie_node_t **split_node, 2185 trie_node_t **child, 2186 const unsigned int max_count, 2187 const unsigned int max_split_len, 2188 const int split_to_pair, 2189 unsigned int *bpm, 2190 trie_split_states_e_t *state, 2191 const int max_split_count) 2192 { 2193 int bit=0, rv=SOC_E_NONE; 2194 2195 if (!trie || !pivot || !length || !split_node || max_count == 0 || !state || max_split_count == 0) return SOC_E_PARAM; 2196 2197 if (trie->child[0].child_node && trie->child[1].child_node) { 2198 bit = (trie->child[0].child_node->count > 2199 trie->child[1].child_node->count) ? 0:1; 2200 } else { 2201 bit = (trie->child[0].child_node)?0:1; 2202 } 2203 2204 /* start building the pivot */ 2205 rv = _key_append(pivot, length, trie->skip_addr, trie->skip_len); 2206 if (SOC_FAILURE(rv)) return rv; 2207 2208 if (bpm) { 2209 unsigned int scratch=0; 2210 rv = _bpm_append(bpm, &scratch, trie->bpm, trie->skip_len+1); 2211 if (SOC_FAILURE(rv)) return rv; 2212 } 2213 2214 { 2215 /* 2216 * split logic to make sure the split length is shorter than the 2217 * requested max_split_len, unless we don't actully split the 2218 * tree if we stop here. 2219 * if (*length > max_split_len) && (trie->count != max_count) { 2220 * need to split at or above this node. might need to split the node in middle 2221 * } else if ((ABS(child count*2 - max_count) > ABS(count*2 - max_count)) || 2222 * ((*length == max_split_len) && (trie->count != max_count))) { 2223 * (the check above imply trie->count != max_count, so also imply *length < max_split_len) 2224 * need to split at this node. 2225 * } else { 2226 * keep searching, will be better split at longer pivot. 2227 * } 2228 */ 2229 if ((*length > max_split_len) && (trie->count != max_count)) { 2230 /* the pivot is getting too long, we better split at this node for 2231 * better bucket capacity efficiency if we can. We can split if 2232 * the trie node has a count != max_count, which means the 2233 * resulted new trie will not have all pivots (FULL) 2234 */ 2235 if ((TRIE_SPLIT_STATE_PAYLOAD_SPLIT == *state) && 2236 (trie->type == INTERNAL)) { 2237 *state = TRIE_SPLIT_STATE_PAYLOAD_SPLIT_DONE; 2238 } else { 2239 if (((*length - max_split_len) > trie->skip_len) && (trie->skip_len == 0)) { 2240 /* the length is longer than max_split_len, and the trie->skip_len is 0, 2241 * so the best we can do is use the node as the split point 2242 */ 2243 *split_node = trie; 2244 *split_count = trie->count; 2245 2246 *state = TRIE_SPLIT_STATE_PRUNE_NODES; 2247 return rv; 2248 } 2249 2250 /* we need to insert a node and use it as split point */ 2251 *split_node = sal_alloc(sizeof(trie_node_t), "trie_node"); 2252 sal_memset((*split_node), 0, sizeof(trie_node_t)); 2253 (*split_node)->type = INTERNAL; 2254 (*split_node)->count = trie->count; 2255 2256 if ((*length - max_split_len) > trie->skip_len) { 2257 /* the length is longer than the max_split_len, and the trie->skip_len is 2258 * shorter than the difference (max_split_len pivot is not covered by this 2259 * node but covered by its parent, the best we can do is split at the branch 2260 * lead to this node. we insert a skip_len=0 node and use it as split point 2261 */ 2262 (*split_node)->skip_len = 0; 2263 (*split_node)->skip_addr = 0; 2264 (*split_node)->bpm = (trie->bpm >> trie->skip_len); 2265 2266 if (_BITGET(trie->skip_addr, (trie->skip_len-1))) { 2267 (*split_node)->child[1].child_node = trie; 2268 } else { 2269 (*split_node)->child[0].child_node = trie; 2270 } 2271 2272 /* the split point is with length max_split_len */ 2273 *length -= trie->skip_len; 2274 2275 /* update the current node to reflect the node inserted */ 2276 trie->skip_len = trie->skip_len - 1; 2277 } else { 2278 /* the length is longer than the max_split_len, and the trie->skip_len is 2279 * longer than the difference (max_split_len pivot is covered by this 2280 * node, we insert a node with length = max_split_len and use it as split point 2281 */ 2282 (*split_node)->skip_len = trie->skip_len - (*length - max_split_len); 2283 (*split_node)->skip_addr = (trie->skip_addr >> (*length - max_split_len)); 2284 (*split_node)->bpm = (trie->bpm >> (*length - max_split_len)); 2285 2286 if (_BITGET(trie->skip_addr, (*length-max_split_len-1))) { 2287 (*split_node)->child[1].child_node = trie; 2288 } else { 2289 (*split_node)->child[0].child_node = trie; 2290 } 2291 2292 /* update the current node to reflect the node inserted */ 2293 trie->skip_len = *length - max_split_len - 1; 2294 2295 /* the split point is with length max_split_len */ 2296 *length = max_split_len; 2297 } 2298 2299 trie->skip_addr = trie->skip_addr & BITMASK(trie->skip_len); 2300 trie->bpm = trie->bpm & BITMASK(trie->skip_len + 1); 2301 2302 /* there is no need to update the parent node's child_node pointer 2303 * to the "trie" node since we will split here and the parent node's 2304 * child_node pointer will be set to NULL later 2305 */ 2306 *split_count = trie->count; 2307 if (bpm) { 2308 rv = _key_shift_right(bpm, trie->skip_len+1); 2309 } 2310 if (SOC_SUCCESS(rv)) { 2311 rv = _key_shift_right(pivot, trie->skip_len+1); 2312 } 2313 *state = TRIE_SPLIT_STATE_PRUNE_NODES; 2314 return rv; 2315 } 2316 } else if ( ((*length == max_split_len) && (trie->count != max_count) && trie->count <= max_split_count) || 2317 _trie_splitable(trie, trie->child[bit].child_node, max_count, max_split_count)) { 2318 /* 2319 * (1) when the node is at the max_split_len and if used as spliting point 2320 * the resulted trie will not have all pivots (FULL). we should split 2321 * at this node. 2322 * (2) when the node is at the max_split_len and if the resulted trie 2323 * will have all pivots (FULL), we fall through to keep searching 2324 * (3) when the node is shorter than the max_split_len and the node 2325 * has a more even pivot distribution compare to it's child, we 2326 * can split at this node. The split count must be less than or 2327 * equal to max_split_count. 2328 * (4) when the node's count is only 1, we must split at this point. 2329 * 2330 * NOTE : 2331 * when trie->count == max_count, the above check will be FALSE 2332 * so here it guarrantees *length < max_split_len. We don't 2333 * need to further split this node. 2334 */ 2335 *split_node = trie; 2336 *split_count = trie->count; 2337 2338 if ((TRIE_SPLIT_STATE_PAYLOAD_SPLIT == *state) && 2339 (trie->type == INTERNAL)) { 2340 *state = TRIE_SPLIT_STATE_PAYLOAD_SPLIT_DONE; 2341 } else { 2342 *state = TRIE_SPLIT_STATE_PRUNE_NODES; 2343 return rv; 2344 } 2345 } else { 2346 /* we can not split at this node, keep searching, it's better to 2347 * split at longer pivot 2348 */ 2349 rv = _key_append(pivot, length, bit, 1); 2350 if (SOC_FAILURE(rv)) return rv; 2351 2352 rv = _trie_split(trie->child[bit].child_node, 2353 pivot, length, 2354 split_count, split_node, 2355 child, max_count, max_split_len, 2356 split_to_pair, bpm, state, max_split_count); 2357 } 2358 } 2359 2360 /* free up internal nodes if applicable */ 2361 switch(*state) { 2362 case TRIE_SPLIT_STATE_PAYLOAD_SPLIT_DONE: 2363 if (trie->type == PAYLOAD) { 2364 *state = TRIE_SPLIT_STATE_PRUNE_NODES; 2365 *split_node = trie; 2366 *split_count = trie->count; 2367 } else { 2368 /* shift the pivot to right to ignore this internal node */ 2369 rv = _key_shift_right(pivot, trie->skip_len+1); 2370 assert(*length >= trie->skip_len + 1); 2371 *length -= (trie->skip_len + 1); 2372 } 2373 break; 2374 2375 case TRIE_SPLIT_STATE_PRUNE_NODES: 2376 if (trie->count == *split_count) { 2377 /* if the split point has associate internal nodes they have to 2378 * be cleaned up */ 2379 assert(trie->type == INTERNAL); 2380 assert(!(trie->child[0].child_node && trie->child[1].child_node)); 2381 sal_free(trie); 2382 } else { 2383 assert(*child == NULL); 2384 /* fuse with child if possible */ 2385 trie->child[bit].child_node = NULL; 2386 bit = (bit==0)?1:0; 2387 trie->count -= *split_count; 2388 2389 /* optimize more */ 2390 if ((trie->type == INTERNAL) && 2391 (trie->skip_len + 2392 trie->child[bit].child_node->skip_len + 1 <= _MAX_SKIP_LEN_)) { 2393 *child = trie->child[bit].child_node; 2394 rv = _trie_fuse_child(trie, bit); 2395 if (rv != SOC_E_NONE) { 2396 *child = NULL; 2397 } 2398 } 2399 *state = TRIE_SPLIT_STATE_DONE; 2400 } 2401 break; 2402 2403 case TRIE_SPLIT_STATE_DONE: 2404 /* adjust parent's count */ 2405 assert(*split_count > 0); 2406 assert(trie->count >= *split_count); 2407 2408 /* update the child pointer if child was pruned */ 2409 if (*child != NULL) { 2410 trie->child[bit].child_node = *child; 2411 *child = NULL; 2412 } 2413 trie->count -= *split_count; 2414 break; 2415 2416 default: 2417 break; 2418 } 2419 2420 return rv; 2421 } 2422 2423 /* 2424 * Function: 2425 * trie_split 2426 * Purpose: 2427 * Split the trie into 2 based on optimum pivot 2428 * Note: 2429 * we need to make sure the length is shorter than 2430 * the max_split_len (for capacity optimization) if 2431 * possible. We should ignore the max_split_len 2432 * if that will result into trie not spliting 2433 */ 2434 int trie_split(trie_t *trie, 2435 const unsigned int max_split_len, 2436 const int split_to_pair, 2437 unsigned int *pivot, 2438 unsigned int *length, 2439 trie_node_t **split_trie_root, 2440 unsigned int *bpm, 2441 uint8 payload_node_split, 2442 const int max_split_count) 2443 { 2444 int rv = SOC_E_NONE; 2445 unsigned int split_count=0, max_count=0; 2446 trie_node_t *child = NULL, *node=NULL, clone; 2447 trie_split_states_e_t state = TRIE_SPLIT_STATE_NONE; 2448 2449 if (!trie || !pivot || !length || !split_trie_root) return SOC_E_PARAM; 2450 2451 *length = 0; 2452 2453 if (trie->trie) { 2454 2455 if (payload_node_split) state = TRIE_SPLIT_STATE_PAYLOAD_SPLIT; 2456 2457 max_count = trie->trie->count; 2458 2459 if (trie->v6_key) { 2460 sal_memset(pivot, 0, sizeof(unsigned int) * BITS2WORDS(_MAX_KEY_LEN_144_)); 2461 if (bpm) { 2462 sal_memset(bpm, 0, sizeof(unsigned int) * BITS2WORDS(_MAX_KEY_LEN_144_)); 2463 } 2464 rv = _trie_v6_split(trie->trie, pivot, length, &split_count, split_trie_root, 2465 &child, max_count, max_split_len, split_to_pair, bpm, &state, max_split_count); 2466 } else { 2467 sal_memset(pivot, 0, sizeof(unsigned int) * BITS2WORDS(_MAX_KEY_LEN_48_)); 2468 if (bpm) { 2469 sal_memset(bpm, 0, sizeof(unsigned int) * BITS2WORDS(_MAX_KEY_LEN_48_)); 2470 } 2471 2472 rv = _trie_split(trie->trie, pivot, length, &split_count, split_trie_root, 2473 &child, max_count, max_split_len, split_to_pair, bpm, &state, max_split_count); 2474 } 2475 if (SOC_SUCCESS(rv) && (TRIE_SPLIT_STATE_DONE == state)) { 2476 /* adjust parent's count */ 2477 assert(split_count > 0); 2478 if (trie->trie == NULL) { 2479 trie_t *c1, *c2; 2480 trie_init(48, &c1); 2481 trie_init(48, &c2); 2482 c1->trie = child; 2483 c2->trie = *split_trie_root; 2484 LOG_ERROR(BSL_LS_SOC_ALPM, 2485 (BSL_META("dumping the 2 child trees\n"))); 2486 trie_dump(c1, 0, 0); 2487 trie_dump(c2, 0, 0); 2488 } 2489 /* update the child pointer if child was pruned */ 2490 if (child != NULL) { 2491 trie->trie = child; 2492 } 2493 assert(trie->trie->count >= split_count || (*split_trie_root)->count >= split_count); 2494 2495 sal_memcpy(&clone, *split_trie_root, sizeof(trie_node_t)); 2496 child = *split_trie_root; 2497 2498 /* take advantage of thie function by passing in internal or payload node whatever 2499 * is the new root. If internal the function assumed it as payload node & changes type. 2500 * But this method is efficient to reuse the last internal or payload node possible to 2501 * implant the new pivot */ 2502 if (trie->v6_key) { 2503 rv = _trie_v6_skip_node_alloc(&node, pivot, NULL, 2504 *length, *length, 2505 child, child->count); 2506 } else { 2507 rv = _trie_skip_node_alloc(&node, pivot, NULL, 2508 *length, *length, 2509 child, child->count); 2510 } 2511 2512 if (SOC_SUCCESS(rv)) { 2513 if (clone.type == INTERNAL) { 2514 child->type = INTERNAL; /* since skip alloc would have reset it to payload */ 2515 } 2516 child->child[0].child_node = clone.child[0].child_node; 2517 child->child[1].child_node = clone.child[1].child_node; 2518 *split_trie_root = node; 2519 } 2520 } else { 2521 LOG_CLI((BSL_META("!!!! Failed to split the trie error:%d state: %d trie_count %d!!!\n"), 2522 rv, state, max_count)); 2523 } 2524 } else { 2525 rv = SOC_E_PARAM; 2526 } 2527 2528 return rv; 2529 } 2530 2531 /* 2532 * Function: 2533 * _trie_merge 2534 * Purpose: 2535 * merge or fuse the child trie with parent trie 2536 */ 2537 static int 2538 _trie_merge(trie_node_t *parent_trie, 2539 trie_node_t *child_trie, 2540 unsigned int *pivot, 2541 unsigned int length, 2542 trie_node_t **new_parent) 2543 { 2544 int rv, child_count; 2545 trie_node_t *child = NULL, clone; 2546 unsigned int bpm[TAPS_MAX_KEY_SIZE_WORDS] = {0}; 2547 unsigned int child_pivot[BITS2WORDS(_MAX_KEY_LEN_)] = {0}; 2548 unsigned int child_length = 0; 2549 2550 if (!parent_trie || length == 0 || !pivot || !new_parent || (length > _MAX_KEY_LEN_)) 2551 return SOC_E_PARAM; 2552 2553 /* 2554 * to do merge, there is one and only one condition: 2555 * parent must cover the child 2556 */ 2557 2558 /* 2559 * child pivot could be an internal node, i.e., NOT_FOUND on search 2560 * so check the out child instead of rv. 2561 */ 2562 _trie_search(child_trie, pivot, length, &child, child_pivot, &child_length, 0, 1); 2563 2564 /* The head of a bucket usually is the pivot of the bucket, 2565 * but for some cases, where the pivot is an INTERNAL node, 2566 * and it is fused with its child, then the pivot can no longer 2567 * be found, but we can still search a head. The head can be 2568 * payload (if this is the only payload head), or internal (if 2569 * two payload head coexist). 2570 */ 2571 if (child == NULL) { 2572 return SOC_E_PARAM; 2573 } 2574 2575 _CLONE_TRIE_NODE_(&clone, child); 2576 2577 if (child->type == PAYLOAD && child->bpm) { 2578 _TAPS_SET_KEY_BIT(bpm, 0, TAPS_IPV4_KEY_SIZE); 2579 } 2580 2581 if (child != child_trie) { 2582 rv = _trie_skip_node_free(child_trie, child_pivot, child_length); 2583 if (rv < 0) { 2584 return SOC_E_PARAM; 2585 } 2586 } 2587 2588 /* Record the child count before being cleared */ 2589 child_count = child->count; 2590 2591 /* Clear the info before insert, mainly it is to prevent previous non-zero 2592 * count being erroneously included to calculation. 2593 */ 2594 sal_memset(child, 0, sizeof(*child)); 2595 2596 /* merge happens on bucket trie, which usually does not need bpm */ 2597 rv = _trie_insert(parent_trie, child_pivot, bpm, child_length, child, 2598 new_parent, child_count); 2599 if (rv < 0) { 2600 return SOC_E_PARAM; 2601 } 2602 2603 /* 2604 * child node, the inserted node, will be modified during insert, 2605 * and it must be a leaf node of the parent trie without any child. 2606 * The child node could be either payload or internal. 2607 */ 2608 if (child->child[0].child_node || child->child[1].child_node) { 2609 return SOC_E_PARAM; 2610 } 2611 if (clone.type == INTERNAL) { 2612 child->type = INTERNAL; 2613 } 2614 child->child[0].child_node = clone.child[0].child_node; 2615 child->child[1].child_node = clone.child[1].child_node; 2616 2617 return SOC_E_NONE; 2618 } 2619 2620 2621 /* 2622 * Function: 2623 * trie_merge 2624 * Purpose: 2625 * merge or fuse the child trie with parent trie. 2626 */ 2627 int trie_merge(trie_t *parent_trie, 2628 trie_node_t *child_trie, 2629 unsigned int *child_pivot, 2630 unsigned int length) 2631 { 2632 int rv=SOC_E_NONE; 2633 trie_node_t *child=NULL; 2634 2635 if (!parent_trie) { 2636 return SOC_E_PARAM; 2637 } 2638 2639 if (!child_trie) { 2640 return SOC_E_NONE; 2641 } 2642 2643 if (parent_trie->trie == NULL) { 2644 parent_trie->trie = child_trie; 2645 } else { 2646 if (parent_trie->v6_key) { 2647 rv = _trie_v6_merge(parent_trie->trie, child_trie, child_pivot, length, &child); 2648 } else { 2649 rv = _trie_merge(parent_trie->trie, child_trie, child_pivot, length, &child); 2650 } 2651 if (child) { 2652 /* The parent head can be changed if the new payload generates a 2653 * new internal node, which then becomes the new head. 2654 */ 2655 parent_trie->trie = child; 2656 } 2657 } 2658 2659 return rv; 2660 } 2661 2662 2663 /* 2664 * Function: 2665 * trie_split 2666 * Purpose: 2667 * Split the trie into 2 such that the new sub trie covers given prefix/length. 2668 * NOTE: 2669 * key, key_len -- The given prefix/length 2670 * max_split_count -- The sub trie's max allowed count. 2671 */ 2672 int 2673 _trie_split2(trie_node_t *trie, 2674 unsigned int *key, 2675 unsigned int key_len, 2676 unsigned int *pivot, 2677 unsigned int *pivot_len, 2678 unsigned int *split_count, 2679 trie_node_t **split_node, 2680 trie_node_t **child, 2681 trie_split2_states_e_t *state, 2682 const int max_split_count, 2683 const int exact_same) 2684 { 2685 unsigned int lcp=0; 2686 int bit=0, rv=SOC_E_NONE; 2687 2688 if (!trie || !pivot || !pivot_len || !split_node || !state || max_split_count == 0) return SOC_E_PARAM; 2689 /* start building the pivot */ 2690 rv = _key_append(pivot, pivot_len, trie->skip_addr, trie->skip_len); 2691 if (SOC_FAILURE(rv)) return rv; 2692 2693 2694 lcp = lcplen(key, key_len, trie->skip_addr, trie->skip_len); 2695 2696 if (lcp == trie->skip_len) { 2697 if (trie->count <= max_split_count && 2698 (!exact_same || (key_len - lcp) == 0)) { 2699 *split_node = trie; 2700 *split_count = trie->count; 2701 if (trie->count < max_split_count) { 2702 *state = TRIE_SPLIT2_STATE_PRUNE_NODES; 2703 } 2704 return SOC_E_NONE; 2705 } 2706 if (key_len > lcp) { 2707 bit = (key[KEY_BIT2IDX(key_len - lcp)] & \ 2708 (1 << ((key_len - lcp - 1) % _NUM_WORD_BITS_))) ? 1:0; 2709 2710 /* based on next bit branch left or right */ 2711 if (trie->child[bit].child_node) { 2712 /* we can not split at this node, keep searching, it's better to 2713 * split at longer pivot 2714 */ 2715 rv = _key_append(pivot, pivot_len, bit, 1); 2716 if (SOC_FAILURE(rv)) return rv; 2717 2718 rv = _trie_split2(trie->child[bit].child_node, 2719 key, key_len - lcp - 1, 2720 pivot, pivot_len, split_count, 2721 split_node, child, state, 2722 max_split_count, exact_same); 2723 if (SOC_FAILURE(rv)) return rv; 2724 } 2725 } 2726 } 2727 2728 /* free up internal nodes if applicable */ 2729 switch(*state) { 2730 case TRIE_SPLIT2_STATE_NONE: /* fail to split */ 2731 break; 2732 2733 case TRIE_SPLIT2_STATE_PRUNE_NODES: 2734 if (trie->count == *split_count) { 2735 /* if the split point has associate internal nodes they have to 2736 * be cleaned up */ 2737 assert(trie->type == INTERNAL); 2738 /* at most one child */ 2739 assert(!(trie->child[0].child_node && trie->child[1].child_node)); 2740 /* at least one child */ 2741 assert(trie->child[0].child_node || trie->child[1].child_node); 2742 sal_free(trie); 2743 } else { 2744 assert(*child == NULL); 2745 /* fuse with child if possible */ 2746 trie->child[bit].child_node = NULL; 2747 bit = (bit==0)?1:0; 2748 trie->count -= *split_count; 2749 2750 /* optimize more */ 2751 if ((trie->type == INTERNAL) && 2752 (trie->skip_len + 2753 trie->child[bit].child_node->skip_len + 1 <= _MAX_SKIP_LEN_)) { 2754 *child = trie->child[bit].child_node; 2755 rv = _trie_fuse_child(trie, bit); 2756 if (rv != SOC_E_NONE) { 2757 *child = NULL; 2758 } 2759 } 2760 *state = TRIE_SPLIT2_STATE_DONE; 2761 } 2762 break; 2763 2764 case TRIE_SPLIT2_STATE_DONE: 2765 /* adjust parent's count */ 2766 assert(*split_count > 0); 2767 assert(trie->count >= *split_count); 2768 2769 /* update the child pointer if child was pruned */ 2770 if (*child != NULL) { 2771 trie->child[bit].child_node = *child; 2772 *child = NULL; 2773 } 2774 trie->count -= *split_count; 2775 break; 2776 2777 default: 2778 break; 2779 } 2780 2781 return rv; 2782 } 2783 2784 2785 2786 /* 2787 * Function: 2788 * trie_split2 2789 * Purpose: 2790 * Split the trie such that the new sub trie covers given prefix/length. 2791 * Basically this is a reverse of trie_merge. 2792 */ 2793 2794 int trie_split2(trie_t *trie, 2795 unsigned int *key, 2796 unsigned int key_len, 2797 unsigned int *pivot, 2798 unsigned int *pivot_len, 2799 trie_node_t **split_trie_root, 2800 const int max_split_count, 2801 const int exact_same) 2802 { 2803 int rv = SOC_E_NONE; 2804 int msc = max_split_count; 2805 unsigned int split_count=0; 2806 trie_node_t *child = NULL, *node=NULL, clone; 2807 trie_split2_states_e_t state = TRIE_SPLIT2_STATE_NONE; 2808 2809 if (!trie || (key_len && !key) || !pivot || !pivot_len || 2810 !split_trie_root || max_split_count == 0) { 2811 return SOC_E_PARAM; 2812 } 2813 2814 *split_trie_root = NULL; 2815 *pivot_len = 0; 2816 2817 if (trie->trie) { 2818 if (max_split_count == 0xfffffff) { 2819 trie_node_t *child2 = NULL; 2820 trie_node_t *payload; 2821 payload = sal_alloc(sizeof(trie_node_t), "trie_node"); 2822 if (payload == NULL) { 2823 return SOC_E_MEMORY; 2824 } 2825 2826 if (trie->v6_key) { 2827 rv = _trie_v6_insert(trie->trie, key, NULL, key_len, payload, &child2, 0); 2828 } else { 2829 rv = _trie_insert(trie->trie, key, NULL, key_len, payload, &child2, 0); 2830 } 2831 if (child2) { /* change the old child pointer to new child */ 2832 trie->trie = child2; 2833 } 2834 2835 if (SOC_SUCCESS(rv)) { 2836 payload->type = INTERNAL; 2837 } else { 2838 sal_free(payload); 2839 if (rv != SOC_E_EXISTS) { 2840 return rv; 2841 } 2842 } 2843 2844 msc = trie->trie->count; 2845 } 2846 if (trie->v6_key) { 2847 sal_memset(pivot, 0, sizeof(unsigned int) * BITS2WORDS(_MAX_KEY_LEN_144_)); 2848 rv = _trie_v6_split2(trie->trie, key, key_len, pivot, pivot_len, 2849 &split_count, split_trie_root, &child, &state, 2850 msc, exact_same); 2851 } else { 2852 sal_memset(pivot, 0, sizeof(unsigned int) * BITS2WORDS(_MAX_KEY_LEN_48_)); 2853 rv = _trie_split2(trie->trie, key, key_len, pivot, pivot_len, 2854 &split_count, split_trie_root, &child, &state, 2855 msc, exact_same); 2856 } 2857 2858 if (SOC_SUCCESS(rv) && (TRIE_SPLIT2_STATE_DONE == state)) { 2859 assert(split_count > 0); 2860 assert(*split_trie_root); 2861 if (max_split_count == 0xfffffff) { 2862 assert(*pivot_len == key_len); 2863 } else { 2864 assert(*pivot_len < key_len); 2865 } 2866 2867 /* update the child pointer if child was pruned */ 2868 if (child != NULL) { 2869 trie->trie = child; 2870 } 2871 2872 sal_memcpy(&clone, *split_trie_root, sizeof(trie_node_t)); 2873 child = *split_trie_root; 2874 2875 /* take advantage of thie function by passing in internal or payload node whatever 2876 * is the new root. If internal the function assumed it as payload node & changes type. 2877 * But this method is efficient to reuse the last internal or payload node possible to 2878 * implant the new pivot */ 2879 if (trie->v6_key) { 2880 rv = _trie_v6_skip_node_alloc(&node, pivot, NULL, 2881 *pivot_len, *pivot_len, 2882 child, child->count); 2883 } else { 2884 rv = _trie_skip_node_alloc(&node, pivot, NULL, 2885 *pivot_len, *pivot_len, 2886 child, child->count); 2887 } 2888 2889 if (SOC_SUCCESS(rv)) { 2890 if (clone.type == INTERNAL) { 2891 child->type = INTERNAL; /* since skip alloc would have reset it to payload */ 2892 } 2893 child->child[0].child_node = clone.child[0].child_node; 2894 child->child[1].child_node = clone.child[1].child_node; 2895 *split_trie_root = node; 2896 } 2897 } else if (SOC_SUCCESS(rv) && (max_split_count == 0xfffffff) && 2898 (split_count == trie->trie->count)) { 2899 /* take all */ 2900 *split_trie_root = trie->trie; 2901 trie->trie = NULL; 2902 } else { /* split2 is not like split which can always succeed */ 2903 LOG_INFO(BSL_LS_SOC_ALPM, 2904 (BSL_META("Failed to split the trie error:%d state: %d "\ 2905 "split_trie_root: %p !!!\n"), 2906 rv, state, *split_trie_root)); 2907 rv = SOC_E_NOT_FOUND; 2908 } 2909 } else { 2910 rv = SOC_E_PARAM; 2911 } 2912 2913 return rv; 2914 } 2915 2916 2917 /* 2918 * Function: 2919 * _trie_traverse_propagate_prefix 2920 * Purpose: 2921 * calls back applicable payload object is affected by prefix updates 2922 * NOTE: 2923 * propagation stops once any callback funciton return something otherthan SOC_E_NONE 2924 * tcam propagation code should return !SOC_E_NONE so that callback only happen once. 2925 * 2926 * other propagation code should always return SOC_E_NONE so that callback will 2927 * happen on all pivot. 2928 */ 2929 int _trie_traverse_propagate_prefix(trie_node_t *trie, 2930 trie_propagate_cb_f cb, 2931 trie_bpm_cb_info_t *cb_info, 2932 unsigned int mask) 2933 { 2934 int rv = SOC_E_NONE, index=0; 2935 2936 if (!trie || !cb || !cb_info) return SOC_E_PARAM; 2937 2938 if ((trie->bpm & mask) == 0) { 2939 /* call back the payload object if applicable */ 2940 if (PAYLOAD == trie->type) { 2941 rv = cb(trie, cb_info); 2942 if (SOC_FAILURE(rv)) { 2943 /* callback stops once any callback function not returning SOC_E_NONE */ 2944 return rv; 2945 } 2946 } 2947 2948 for (index=0; index < _MAX_CHILD_ && SOC_SUCCESS(rv); index++) { 2949 if (trie->child[index].child_node && trie->child[index].child_node->bpm == 0) { 2950 /* coverity[large_shift : FALSE] */ 2951 rv = _trie_traverse_propagate_prefix(trie->child[index].child_node, 2952 cb, cb_info, MASK(32)); 2953 } 2954 2955 if (SOC_FAILURE(rv)) { 2956 /* callback stops once any callback function not returning SOC_E_NONE */ 2957 return rv; 2958 } 2959 } 2960 } 2961 2962 return rv; 2963 } 2964 2965 /* 2966 * Function: 2967 * _trie_propagate_prefix 2968 * Purpose: 2969 * Propogate prefix BPM. If the propogation starts from intermediate pivot on 2970 * the trie, then the prefix length has to be appropriately adjusted or else 2971 * it will end up with ill updates. 2972 * Assumption: the prefix length is adjusted as per trie node on which is starts from. 2973 * If node == head node then adjust is none 2974 * node == pivot, then prefix length = org len - pivot len 2975 */ 2976 STATIC int _trie_propagate_prefix(trie_node_t *trie, 2977 unsigned int *pfx, 2978 unsigned int len, 2979 unsigned int add, /* 0-del/1-add */ 2980 trie_propagate_cb_f cb, 2981 trie_bpm_cb_info_t *cb_info) 2982 { 2983 int rv = SOC_E_NONE; /*, index;*/ 2984 unsigned int bit=0, lcp=0; 2985 2986 if (!trie || (len && trie->skip_len && !pfx) || 2987 (len > _MAX_KEY_LEN_) || !cb || !cb_info) return SOC_E_PARAM; 2988 2989 if (len > 0) { 2990 /* BPM bit maps has to be updated before propagation */ 2991 lcp = lcplen(pfx, len, trie->skip_addr, trie->skip_len); 2992 /* if the lcp is less than prefix length the prefix is not applicable 2993 * for any propagation */ 2994 if (lcp < ((len>trie->skip_len)?trie->skip_len:len)) { 2995 return SOC_E_NONE; 2996 } else { 2997 if (len > trie->skip_len) { 2998 /* fully matched and more bits to check, go down the trie */ 2999 bit = _key_get_bits(pfx, len-lcp, 1, 0); 3000 if (!trie->child[bit].child_node) return SOC_E_NONE; 3001 rv = _trie_propagate_prefix(trie->child[bit].child_node, 3002 pfx, len-lcp-1, add, cb, cb_info); 3003 } else { 3004 /* given pfx exactly matched or covers trie node, this is the 3005 * point to propagate. 3006 */ 3007 /* pfx is <= trie skip len */ 3008 if (!add) { /* delete */ 3009 _BITCLR(trie->bpm, trie->skip_len - len); 3010 } 3011 3012 /* update bit map and propagate if applicable: 3013 * there is no longer bpm than this new prefix 3014 */ 3015 if ((trie->bpm & BITMASK(trie->skip_len - len)) == 0) { 3016 rv = _trie_traverse_propagate_prefix(trie, cb, 3017 cb_info, 3018 BITMASK(trie->skip_len - len)); 3019 if (SOC_E_LIMIT == rv) rv = SOC_E_NONE; 3020 } else if (add && _BITGET(trie->bpm, trie->skip_len - len)) { 3021 /* if adding, and bpm of this node is the specified prefix 3022 * also propagate. (this is really update case) 3023 */ 3024 rv = _trie_traverse_propagate_prefix(trie, cb, 3025 cb_info, 3026 BITMASK(trie->skip_len - len)); 3027 if (SOC_E_LIMIT == rv) rv = SOC_E_NONE; 3028 } 3029 3030 if (add && SOC_SUCCESS(rv)) { 3031 /* this is the case where child bit is the new prefix */ 3032 _BITSET(trie->bpm, trie->skip_len - len); 3033 } 3034 } 3035 } 3036 } else { 3037 if (!add) { /* delete */ 3038 _BITCLR(trie->bpm, trie->skip_len); 3039 } 3040 3041 if ((trie->bpm == 0) || 3042 (add && ((trie->bpm & BITMASK(trie->skip_len)) == 0))) { 3043 /* if adding, and bpm of this node is the specified prefix 3044 * also propagate. (this is really update case) 3045 */ 3046 rv = _trie_traverse_propagate_prefix(trie, cb, cb_info, BITMASK(trie->skip_len)); 3047 if (SOC_E_LIMIT == rv) rv = SOC_E_NONE; 3048 } 3049 3050 if (add && SOC_SUCCESS(rv)) { /* add */ 3051 /* this is the case where child bit is the new prefix */ 3052 _BITSET(trie->bpm, trie->skip_len); 3053 } 3054 } 3055 3056 return rv; 3057 } 3058 3059 /* 3060 * Function: 3061 * _trie_propagate_prefix_validate 3062 * Purpose: 3063 * validate that the provided prefix is valid for propagation. 3064 * The added prefix which was member of a shorter pivot's domain 3065 * must never be more specific than another pivot encounter if any 3066 * in the path 3067 */ 3068 STATIC int _trie_propagate_prefix_validate(trie_node_t *trie, 3069 unsigned int *pfx, 3070 unsigned int len) 3071 { 3072 unsigned int lcp=0, bit=0; 3073 3074 if (!trie || (len && trie->skip_len && !pfx)) return SOC_E_PARAM; 3075 3076 if (len == 0) return SOC_E_NONE; 3077 3078 lcp = lcplen(pfx, len, trie->skip_addr, trie->skip_len); 3079 3080 if (lcp == trie->skip_len) { 3081 if (PAYLOAD == trie->type) return SOC_E_PARAM; 3082 if (len == lcp) return SOC_E_NONE; 3083 bit = _key_get_bits(pfx, len-lcp, 1, 0); 3084 if (!trie->child[bit].child_node) return SOC_E_NONE; 3085 return _trie_propagate_prefix_validate(trie->child[bit].child_node, 3086 pfx, len-1-lcp); 3087 } 3088 3089 return SOC_E_NONE; 3090 } 3091 3092 int _trie_init_propagate_info(unsigned int *pfx, 3093 unsigned int len, 3094 trie_propagate_cb_f cb, 3095 trie_bpm_cb_info_t *cb_info) 3096 { 3097 cb_info->pfx = pfx; 3098 cb_info->len = len; 3099 return SOC_E_NONE; 3100 } 3101 3102 /* 3103 * Function: 3104 * trie_pivot_propagate_prefix 3105 * Purpose: 3106 * Propogate prefix BPM from a given pivot. 3107 */ 3108 int trie_pivot_propagate_prefix(trie_node_t *pivot, 3109 unsigned int pivot_len, 3110 unsigned int *pfx, 3111 unsigned int len, 3112 unsigned int add, /* 0-del/1-add */ 3113 trie_propagate_cb_f cb, 3114 trie_bpm_cb_info_t *cb_info) 3115 { 3116 int rv = SOC_E_NONE; 3117 3118 if (!pfx || !pivot || (len > _MAX_KEY_LEN_) || 3119 (pivot_len > _MAX_KEY_LEN_) || (len < pivot_len) || 3120 (pivot->type != PAYLOAD) || !cb || !cb_info || 3121 !cb_info->pfx) { 3122 return SOC_E_PARAM; 3123 } 3124 3125 _trie_init_propagate_info(pfx,len,cb,cb_info); 3126 len -= pivot_len; 3127 3128 if (len > 0) { 3129 unsigned int bit = _key_get_bits(pfx, len, 1, 0); 3130 3131 if (pivot->child[bit].child_node) { 3132 /* validate if the pivot provided is correct */ 3133 rv = _trie_propagate_prefix_validate(pivot->child[bit].child_node, 3134 pfx, len-1); 3135 if (SOC_SUCCESS(rv)) { 3136 rv = _trie_propagate_prefix(pivot->child[bit].child_node, 3137 pfx, len-1, 3138 add, cb, cb_info); 3139 } 3140 } /* else nop, nothing to propagate on this path end */ 3141 } else { 3142 /* pivot == prefix */ 3143 rv = _trie_propagate_prefix(pivot, pfx, pivot->skip_len, 3144 add, cb, cb_info); 3145 } 3146 3147 return rv; 3148 } 3149 3150 /* 3151 * Function: 3152 * _pvt_trie_traverse_propagate_prefix 3153 * Purpose: 3154 * calls back applicable payload object is affected by prefix updates 3155 * NOTE: 3156 * other propagation code should always return SOC_E_NONE so that 3157 * callback will happen on all pivot. 3158 */ 3159 int _pvt_trie_traverse_propagate_prefix(trie_node_t *trie, 3160 trie_propagate_cb_f cb, 3161 trie_bpm_cb_info_t *cb_info) 3162 { 3163 int rv = SOC_E_NONE, index=0; 3164 int rv1 = SOC_E_NONE; 3165 3166 if (!trie || !cb || !cb_info) { 3167 return SOC_E_PARAM; 3168 } 3169 3170 /* call back the payload object if applicable */ 3171 if (PAYLOAD == trie->type) { 3172 rv = cb(trie, cb_info); 3173 if (SOC_FAILURE(rv)) { 3174 return rv; 3175 } 3176 } 3177 3178 for (index=0; index < _MAX_CHILD_; index++) { 3179 if (trie->child[index].child_node) { 3180 rv = _pvt_trie_traverse_propagate_prefix( 3181 trie->child[index].child_node, cb, cb_info); 3182 /* Save first error, second error can overwrite if it's more severe 3183 than the first. SOC_E_LIMIT is considered as no severe error */ 3184 if (SOC_FAILURE(rv)) { 3185 if (rv1 == SOC_E_NONE || rv1 == SOC_E_LIMIT) { 3186 rv1 = rv; 3187 } 3188 } 3189 } 3190 } 3191 3192 return rv1; 3193 } 3194 3195 /* 3196 * Function: 3197 * _pvt_trie_propagate_prefix 3198 * Purpose: 3199 * If the propogation starts from intermediate pivot on 3200 * the trie, then the prefix length has to be appropriately adjusted or else 3201 * it will end up with ill updates. 3202 * Assumption: the prefix length is adjusted as per trie node on which 3203 * is starts from. 3204 * If node == head node then adjust is none 3205 * node == pivot, then prefix length = org len - pivot len 3206 */ 3207 STATIC int _pvt_trie_propagate_prefix(trie_node_t *trie, 3208 unsigned int *pfx, 3209 unsigned int len, 3210 trie_propagate_cb_f cb, 3211 trie_bpm_cb_info_t *cb_info) 3212 { 3213 int rv = SOC_E_NONE; /*, index;*/ 3214 unsigned int bit = 0, lcp = 0; 3215 3216 if (!trie || (len && trie->skip_len && !pfx) || 3217 (len > _MAX_KEY_LEN_) || !cb || !cb_info) { 3218 return SOC_E_PARAM; 3219 } 3220 3221 if (len > 0) { 3222 lcp = lcplen(pfx, len, trie->skip_addr, trie->skip_len); 3223 /* if the lcp is less than prefix length the prefix is not applicable 3224 * for any propagation */ 3225 if (lcp < ((len>trie->skip_len) ? trie->skip_len : len)) { 3226 return SOC_E_NONE; 3227 } else { 3228 if (len > trie->skip_len) { 3229 bit = _key_get_bits(pfx, len-lcp, 1, 0); 3230 if (!trie->child[bit].child_node) { 3231 return SOC_E_NONE; 3232 } 3233 rv = _pvt_trie_propagate_prefix( 3234 trie->child[bit].child_node, 3235 pfx, len-lcp-1, cb, cb_info); 3236 } else { 3237 /* pfx is <= trie skip len */ 3238 /* propagate if applicable */ 3239 rv = _pvt_trie_traverse_propagate_prefix(trie, cb, 3240 cb_info); 3241 if (SOC_E_LIMIT == rv) { 3242 rv = SOC_E_NONE; 3243 } 3244 } 3245 } 3246 } else { 3247 rv = _pvt_trie_traverse_propagate_prefix(trie, cb, cb_info); 3248 if (SOC_E_LIMIT == rv) { 3249 rv = SOC_E_NONE; 3250 } 3251 } 3252 3253 return rv; 3254 } 3255 3256 /* 3257 * Function: 3258 * pvt_trie_propagate_prefix 3259 * Purpose: 3260 * Propogate prefix from a given pivot. 3261 * Callback function to decide INSERT/DELETE propagation, 3262 * and decide to update bpm_len or not. 3263 */ 3264 int pvt_trie_propagate_prefix(trie_node_t *pivot, 3265 unsigned int pivot_len, 3266 unsigned int *pfx, 3267 unsigned int len, 3268 trie_propagate_cb_f cb, 3269 trie_bpm_cb_info_t *cb_info) 3270 { 3271 int rv = SOC_E_NONE; 3272 3273 if (!pfx || !pivot || (len > _MAX_KEY_LEN_) || 3274 (pivot_len > _MAX_KEY_LEN_) || (len < pivot_len) || 3275 (pivot->type != PAYLOAD) || !cb || !cb_info || 3276 !cb_info->pfx) { 3277 return SOC_E_PARAM; 3278 } 3279 3280 len -= pivot_len; 3281 3282 if (len > 0) { 3283 unsigned int bit = _key_get_bits(pfx, len, 1, 0); 3284 if (pivot->child[bit].child_node) { 3285 /* validate if the pivot provided is correct */ 3286 rv = _trie_propagate_prefix_validate(pivot->child[bit].child_node, 3287 pfx, len-1); 3288 if (SOC_SUCCESS(rv)) { 3289 rv = _pvt_trie_propagate_prefix(pivot->child[bit].child_node, 3290 pfx, len-1, 3291 cb, cb_info); 3292 } 3293 } /* else nop, nothing to propagate on this path end */ 3294 } else { 3295 /* pivot == prefix */ 3296 rv = _pvt_trie_propagate_prefix(pivot, pfx, pivot->skip_len, 3297 cb, cb_info); 3298 } 3299 3300 return rv; 3301 } 3302 3303 int trie_ppg_prefix(trie_t *trie, unsigned int pvt_len, 3304 unsigned int *pfx, 3305 unsigned int len, 3306 trie_propagate_cb_f cb, 3307 trie_bpm_cb_info_t *cb_info) 3308 { 3309 int rv = SOC_E_NONE, rv2 = SOC_E_NONE; 3310 trie_node_t *payload; 3311 3312 if (!pfx || !trie || !trie->trie || !cb || !cb_info) { 3313 return SOC_E_PARAM; 3314 } 3315 3316 payload = sal_alloc(sizeof(trie_node_t), "trie_node"); 3317 if (payload == NULL) { 3318 return SOC_E_MEMORY; 3319 } 3320 rv2 = trie_insert(trie, pfx, NULL, len, payload); 3321 if (SOC_FAILURE(rv2)) { 3322 sal_free(payload); 3323 if (rv2 != SOC_E_EXISTS) { 3324 return rv2; 3325 } 3326 rv = trie_find_lpm(trie, pfx, len, &payload); 3327 if (SOC_FAILURE(rv)) { 3328 return rv; 3329 } 3330 } else { 3331 payload->bpm = -1; 3332 } 3333 3334 if (trie->v6_key) { 3335 rv = pvt_trie_v6_propagate_prefix(payload, len, pfx, len, 3336 cb, cb_info); 3337 } else { 3338 rv = pvt_trie_propagate_prefix(payload, len, pfx, len, 3339 cb, cb_info); 3340 } 3341 3342 if (SOC_SUCCESS(rv2)) { 3343 trie_delete(trie, pfx, len, &payload); 3344 sal_free(payload); 3345 } 3346 3347 return rv; 3348 } 3349 3350 /* 3351 * Function: 3352 * trie_propagate_prefix 3353 * Purpose: 3354 * Propogate prefix BPM on a given trie. 3355 */ 3356 int trie_propagate_prefix(trie_t *trie, 3357 unsigned int *pfx, 3358 unsigned int len, 3359 unsigned int add, /* 0-del/1-add */ 3360 trie_propagate_cb_f cb, 3361 trie_bpm_cb_info_t *cb_info) 3362 { 3363 int rv=SOC_E_NONE; 3364 3365 if (!pfx || !trie || !trie->trie || !cb || !cb_info || !cb_info->pfx) { 3366 return SOC_E_PARAM; 3367 } 3368 3369 _trie_init_propagate_info(pfx,len,cb,cb_info); 3370 3371 if (SOC_SUCCESS(rv)) { 3372 if (trie->v6_key) { 3373 rv = _trie_v6_propagate_prefix(trie->trie, pfx, len, add, 3374 cb, cb_info); 3375 } else { 3376 rv = _trie_propagate_prefix(trie->trie, pfx, len, add, 3377 cb, cb_info); 3378 } 3379 } 3380 3381 return rv; 3382 } 3383 3384 3385 /* 3386 * Function: 3387 * trie_init 3388 * Purpose: 3389 * allocates a trie & initializes it 3390 */ 3391 int trie_init(unsigned int max_key_len, trie_t **ptrie) 3392 { 3393 trie_t *trie = sal_alloc(sizeof(trie_t), "trie-node"); 3394 sal_memset(trie, 0, sizeof(trie_t)); 3395 3396 if (max_key_len == _MAX_KEY_LEN_48_) { 3397 trie->v6_key = FALSE; 3398 } else if (max_key_len == _MAX_KEY_LEN_144_) { 3399 trie->v6_key = TRUE; 3400 } else { 3401 sal_free(trie); 3402 return SOC_E_PARAM; 3403 } 3404 3405 trie->trie = NULL; /* means nothing is on teie */ 3406 *ptrie = trie; 3407 return SOC_E_NONE; 3408 } 3409 3410 3411 /* 3412 * Function: 3413 * trie_delete_node_cb 3414 * Purpose: 3415 * Call back to delete a node 3416 */ 3417 int 3418 trie_delete_node_cb(trie_node_t *node, void *info) 3419 { 3420 if (node != NULL) { 3421 sal_free(node); 3422 } 3423 return SOC_E_NONE; 3424 } 3425 3426 /* 3427 * Function: 3428 * trie_destroy2 3429 * Purpose: 3430 * destroys a trie and its body 3431 */ 3432 int trie_destroy2(trie_t *trie) 3433 { 3434 int rv; 3435 rv = trie_traverse(trie, trie_delete_node_cb, NULL, 3436 _TRIE_POSTORDER_TRAVERSE); 3437 if (SOC_FAILURE(rv)) { 3438 return rv; 3439 } 3440 sal_free(trie); 3441 return SOC_E_NONE; 3442 } 3443 3444 3445 /* 3446 * Function: 3447 * trie_destroy 3448 * Purpose: 3449 * destroys a trie 3450 */ 3451 int trie_destroy(trie_t *trie) 3452 { 3453 if (trie != NULL) { 3454 sal_free(trie); 3455 } 3456 return SOC_E_NONE; 3457 } 3458 3459 3460 STATIC int _trie_clone(trie_node_t *ptrie, 3461 trie_node_t *trie, 3462 int bit, 3463 trie_traverse_states_e_t *state, 3464 trie_node_t *pnode, 3465 trie_t *clone_trie) 3466 { 3467 int rv = SOC_E_NONE; 3468 trie_node_t *lc, *rc; 3469 3470 if (trie == NULL) { 3471 return SOC_E_NONE; 3472 } else { 3473 /* make the trie delete safe */ 3474 lc = trie->child[0].child_node; 3475 rc = trie->child[1].child_node; 3476 { 3477 trie_node_t *clone_node = NULL; 3478 3479 /* assert(trie); */ 3480 clone_node = sal_alloc(sizeof(trie_node_t), "clone trie"); 3481 if (clone_node == NULL) { 3482 return SOC_E_MEMORY; 3483 } 3484 sal_memcpy(clone_node, trie, sizeof(trie_node_t)); 3485 3486 if (ptrie == NULL) { /* clone head */ 3487 /* assert(clone_trie); */ 3488 clone_trie->trie = clone_node; 3489 } else { /* clone body */ 3490 /* assert(pnode); */ 3491 pnode->child[bit].child_node = clone_node; 3492 } 3493 3494 pnode = clone_node; 3495 } 3496 TRIE_TRAVERSE_STOP(*state, rv); 3497 /* make the ptrie delete safe */ 3498 if (*state != TRIE_TRAVERSE_STATE_DELETED) { 3499 ptrie = trie; 3500 } 3501 } 3502 3503 if (SOC_SUCCESS(rv)) { 3504 rv = _trie_clone(ptrie, lc, 0, state, pnode, NULL); 3505 TRIE_TRAVERSE_STOP(*state, rv); 3506 } 3507 if (SOC_SUCCESS(rv)) { 3508 rv = _trie_clone(ptrie, rc, 1, state, pnode, NULL); 3509 } 3510 return rv; 3511 } 3512 3513 3514 int trie_clone(trie_t *trie_src, trie_t **trie_dst) 3515 { 3516 int rv; 3517 trie_traverse_states_e_t state = TRIE_TRAVERSE_STATE_NONE; 3518 3519 assert(trie_src && trie_dst); 3520 3521 rv = trie_init(trie_src->v6_key ? _MAX_KEY_LEN_144_ : _MAX_KEY_LEN_48_, 3522 trie_dst); 3523 if (SOC_FAILURE(rv)) { 3524 return rv; 3525 } 3526 3527 rv = _trie_clone(NULL, trie_src->trie, 0, &state, NULL, *trie_dst); 3528 if (SOC_FAILURE(rv)) { 3529 trie_destroy2(*trie_dst); 3530 *trie_dst = NULL; 3531 } 3532 return rv; 3533 } 3534 3535 3536 3537 STATIC int _trie_compare(trie_node_t *ptrie, 3538 trie_node_t *trie, 3539 int bit, 3540 trie_traverse_states_e_t *state, 3541 trie_node_t *ptrie_cmp, 3542 trie_node_t *trie_cmp, 3543 int *cmp_result) 3544 { 3545 int rv = SOC_E_NONE; 3546 trie_node_t *lc, *rc; 3547 3548 if (trie == NULL) { 3549 return SOC_E_NONE; 3550 } else { 3551 /* make the trie delete safe */ 3552 lc = trie->child[0].child_node; 3553 rc = trie->child[1].child_node; 3554 { 3555 3556 assert(trie && state); 3557 3558 if (ptrie == NULL) { /* compare head */ 3559 trie_cmp = trie_cmp; 3560 } else { /* compare body */ 3561 trie_cmp = ptrie_cmp->child[bit].child_node; 3562 } 3563 3564 /* When traverse against one trie, there is a possibility the other is 3565 * a super set of this one. To rule out that possibility, compare the child 3566 * pointer as well. 3567 */ 3568 if (/* trie_cmp->skip_len != trie->skip_len || 3569 (BITMASK(trie->skip_len) & trie_cmp->skip_addr) != 3570 (BITMASK(trie->skip_len) & trie->skip_addr) || */ 3571 trie_cmp->type != trie->type || 3572 trie_cmp->count != trie->count || 3573 trie_cmp->bpm != trie->bpm || 3574 !trie_cmp->child[0].child_node != !trie->child[0].child_node || 3575 !trie_cmp->child[1].child_node != !trie->child[1].child_node) { 3576 *cmp_result = 1; 3577 /* stop traverse on unequal */ 3578 *state = TRIE_TRAVERSE_STATE_DONE; 3579 } 3580 3581 /* In case of v6, the skip len not equal does not mean the two 3582 * tries are different, thus we print it and let user be aware 3583 * and then continue. 3584 */ 3585 if (trie_cmp->skip_len != trie->skip_len) { 3586 LOG_CLI(("AWARE:len %d - %d addr 0x%x - 0x%x\n", 3587 trie_cmp->skip_len, trie->skip_len, 3588 trie_cmp->skip_addr, trie->skip_addr)); 3589 } 3590 ptrie_cmp = trie_cmp; 3591 } 3592 TRIE_TRAVERSE_STOP(*state, rv); 3593 /* make the ptrie delete safe */ 3594 if (*state != TRIE_TRAVERSE_STATE_DELETED) { 3595 ptrie = trie; 3596 } 3597 } 3598 3599 if (SOC_SUCCESS(rv)) { 3600 rv = _trie_compare(ptrie, lc, 0, state, ptrie_cmp, NULL, cmp_result); 3601 TRIE_TRAVERSE_STOP(*state, rv); 3602 } 3603 if (SOC_SUCCESS(rv)) { 3604 rv = _trie_compare(ptrie, rc, 1, state, ptrie_cmp, NULL, cmp_result); 3605 } 3606 return rv; 3607 } 3608 3609 3610 int trie_compare(trie_t *trie_src, trie_t *trie_dst, int *equal) 3611 { 3612 trie_traverse_states_e_t state = TRIE_TRAVERSE_STATE_NONE; 3613 3614 assert(trie_src && trie_dst && equal); 3615 3616 *equal = 0; 3617 3618 return _trie_compare(NULL, trie_src->trie, 0, &state, NULL, trie_dst->trie, equal); 3619 } 3620 3621 #if 0 3622 /****************/ 3623 /** unit tests **/ 3624 /****************/ 3625 #define _NUM_KEY_ (4 * 1024) 3626 #define _VRF_LEN_ 16 3627 /*#define VERBOSE 3628 #define LOG*/ 3629 /* use the followign diag shell command to run this test: 3630 * tr c3sw test=tmu_trie_ut 3631 */ 3632 typedef struct _payload_s { 3633 trie_node_t node; /*trie node */ 3634 dq_t listnode; /* list node */ 3635 union { 3636 trie_t *trie; 3637 trie_node_t pfx_trie_node; 3638 } info; 3639 unsigned int key[BITS2WORDS(_MAX_KEY_LEN_)]; 3640 unsigned int len; 3641 } payload_t; 3642 3643 int ut_print_payload_node(trie_node_t *payload, void *datum) 3644 { 3645 payload_t *pyld; 3646 3647 if (payload && payload->type == PAYLOAD) { 3648 pyld = TRIE_ELEMENT_GET(payload_t*, payload, node); 3649 LOG_CLI((BSL_META(" key[0x%08x:0x%08x] Length:%d \n"), 3650 pyld->key[0], pyld->key[1], pyld->len)); 3651 } 3652 return SOC_E_NONE; 3653 } 3654 3655 int ut_print_prefix_payload_node(trie_node_t *payload, void *datum) 3656 { 3657 payload_t *pyld; 3658 3659 if (payload && payload->type == PAYLOAD) { 3660 pyld = TRIE_ELEMENT_GET(payload_t*, payload, info.pfx_trie_node); 3661 LOG_CLI((BSL_META(" key[0x%08x:0x%08x] Length:%d \n"), 3662 pyld->key[0], pyld->key[1], pyld->len)); 3663 } 3664 return SOC_E_NONE; 3665 } 3666 3667 int ut_check_duplicate(payload_t *pyld, int pyld_vector_size) 3668 { 3669 int i=0; 3670 3671 assert(pyld); 3672 3673 for (i=0; i < pyld_vector_size; i++) { 3674 if (pyld[i].len == pyld[pyld_vector_size].len && 3675 pyld[i].key[0] == pyld[pyld_vector_size].key[0] && 3676 pyld[i].key[1] == pyld[pyld_vector_size].key[1]) { 3677 break; 3678 } 3679 } 3680 3681 return ((i == pyld_vector_size)?0:1); 3682 } 3683 3684 3685 int tmu_taps_util_get_bpm_pfx_ut(void) 3686 { 3687 int rv; 3688 unsigned int pfx_len=0; 3689 unsigned int bpm[] = { 0x80, 0x00101010 }; /* 40th bit msb */ 3690 3691 /* v4 test */ 3692 rv = taps_get_bpm_pfx(&bpm[0], 48, _MAX_KEY_LEN_48_, &pfx_len); 3693 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3694 if (pfx_len != 48-4) return SOC_E_FAIL; 3695 3696 bpm[0] = 0; 3697 bpm[1] = 0x00010000; 3698 rv = taps_get_bpm_pfx(&bpm[0], 48, _MAX_KEY_LEN_48_, &pfx_len); 3699 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3700 if (pfx_len != 48-16) return SOC_E_FAIL; 3701 3702 bpm[0] = 0; 3703 bpm[1] = 0x80000000; 3704 rv = taps_get_bpm_pfx(&bpm[0], 48, _MAX_KEY_LEN_48_, &pfx_len); 3705 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3706 if (pfx_len != 48-31) return SOC_E_FAIL; 3707 3708 bpm[0] = 0x1; 3709 bpm[1] = 0x80000000; 3710 rv = taps_get_bpm_pfx(&bpm[0], 48, _MAX_KEY_LEN_48_, &pfx_len); 3711 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3712 if (pfx_len != 48-31) return SOC_E_FAIL; 3713 3714 bpm[0] = 0; 3715 bpm[1] = 0; 3716 rv = taps_get_bpm_pfx(&bpm[0], 48, _MAX_KEY_LEN_48_, &pfx_len); 3717 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3718 if (pfx_len != 0) return SOC_E_FAIL; 3719 3720 /* v6 test */ 3721 bpm[0] = 0x80; 3722 bpm[1] = 0x00101010; 3723 rv = taps_get_bpm_pfx(&bpm[0], 144, _MAX_KEY_LEN_144_, &pfx_len); 3724 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3725 if (pfx_len != 144-4) return SOC_E_FAIL; 3726 3727 bpm[0] = 0; 3728 bpm[1] = 0x00010000; 3729 rv = taps_get_bpm_pfx(&bpm[0], 144, _MAX_KEY_LEN_144_, &pfx_len); 3730 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3731 if (pfx_len != 144-16) return SOC_E_FAIL; 3732 3733 bpm[0] = 0; 3734 bpm[1] = 0x80000000; 3735 rv = taps_get_bpm_pfx(&bpm[0], 144, _MAX_KEY_LEN_144_, &pfx_len); 3736 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3737 if (pfx_len != 144-31) return SOC_E_FAIL; 3738 3739 bpm[0] = 0x1; 3740 bpm[1] = 0x80000000; 3741 rv = taps_get_bpm_pfx(&bpm[0], 144, _MAX_KEY_LEN_144_, &pfx_len); 3742 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3743 if (pfx_len != 144-31) return SOC_E_FAIL; 3744 3745 bpm[0] = 0; 3746 bpm[1] = 0; 3747 rv = taps_get_bpm_pfx(&bpm[0], 144, _MAX_KEY_LEN_144_, &pfx_len); 3748 if (SOC_FAILURE(rv)) return SOC_E_FAIL; 3749 if (pfx_len != 0) return SOC_E_FAIL; 3750 3751 return SOC_E_NONE; 3752 } 3753 3754 int tmu_taps_kshift_ut(void) 3755 { 3756 unsigned int key[] = { 0x1234, 0x12345678 }, length=0; 3757 3758 /* v4 tests */ 3759 _key_shift_left(key, 8); 3760 if (key[0] != 0x3412 && key[1] != 0x34567800) { 3761 return SOC_E_FAIL; 3762 } 3763 3764 key[0] = 0; 3765 key[1] = 0x12345678; 3766 _key_shift_left(key, 15); 3767 3768 if (key[0] != (0x12345678 >> 17) && key[1] != (0x12345678 << 15)) { 3769 return SOC_E_FAIL; 3770 } 3771 3772 key[0] = 0x1234; 3773 key[1] = 0xdeadbeef; 3774 _key_shift_left(key, 0); 3775 if (key[0] != 0x1234 && key[1] != 0xdeadbeef) { 3776 return SOC_E_FAIL; 3777 } 3778 3779 key[0] = 0; 3780 key[1] = 0; 3781 _key_append(key, &length, 0xba5e, 16); 3782 if (key[0] != 0 && key[1] != 0xba5e) { 3783 return SOC_E_FAIL; 3784 } 3785 3786 _key_append(key, &length, 0x3a5eba11, 31); 3787 if (key[0] != 0xba5e && key[1] != 0x3a5eba11) { 3788 return SOC_E_FAIL; 3789 } 3790 3791 /* v6 tests */ 3792 3793 return SOC_E_NONE; 3794 } 3795 3796 int tmu_trie_split_ut(unsigned int seed) 3797 { 3798 int index, rv = SOC_E_NONE, numkey=0, id=0; 3799 trie_t *trie, *newtrie; 3800 trie_node_t *newroot; 3801 payload_t *pyld = sal_alloc(_NUM_KEY_ * sizeof(payload_t), "unit-test"); 3802 trie_node_t *pyldptr = NULL; 3803 unsigned int pivot[_MAX_KEY_WORDS_], length; 3804 3805 for (id=0; id < 4; id++) { 3806 switch(id) { 3807 case 0: /* 1:1 split */ 3808 pyld[0].key[0] = 0; pyld[0].key[1] = 0x10; pyld[0].len = _VRF_LEN_ + 8; /* v=0 p=0x10000000/8 */ 3809 pyld[1].key[0] = 0; pyld[1].key[1] = 0x1000; pyld[1].len = _VRF_LEN_ + 16; /* v=0 p=0x10000000/16 */ 3810 pyld[2].key[0] = 0; pyld[2].key[1] = 0x100000; pyld[2].len = _VRF_LEN_ + 24; /* v=0 p=0x10000000/24 */ 3811 pyld[3].key[0] = 0; pyld[3].key[1] = 0x10000000; pyld[3].len = _VRF_LEN_ + 32; /* v=0 p=0x10000000/48 */ 3812 numkey = 4; 3813 break; 3814 case 1: /* 1:1 split */ 3815 pyld[0].key[0] = 0; pyld[0].key[1] = 0x10000000; pyld[0].len = _VRF_LEN_ + 32; /* v=0 p=0x10000000/32 */ 3816 pyld[1].key[0] = 0; pyld[1].key[1] = 0x10000001; pyld[1].len = _VRF_LEN_ + 32; /* v=0 p=0x10000001/32 */ 3817 pyld[2].key[0] = 0; pyld[2].key[1] = 0x10000002; pyld[2].len = _VRF_LEN_ + 32; /* v=0 p=0x10000002/32 */ 3818 pyld[3].key[0] = 0; pyld[3].key[1] = 0x10000003; pyld[3].len = _VRF_LEN_ + 32; /* v=0 p=0x10000002/32 */ 3819 pyld[4].key[0] = 0; pyld[4].key[1] = 0x10000004; pyld[4].len = _VRF_LEN_ + 32; /* v=0 p=0x10000002/32 */ 3820 pyld[5].key[0] = 0; pyld[5].key[1] = 0x10000005; pyld[5].len = _VRF_LEN_ + 32; /* v=0 p=0x10000002/32 */ 3821 numkey = 6; 3822 break; 3823 case 2: /* 2:5 split */ 3824 pyld[0].key[0] = 0; pyld[0].key[1] = 0x100; pyld[0].len = _VRF_LEN_ + 12; 3825 pyld[1].key[0] = 0; pyld[1].key[1] = 0x1011; pyld[1].len = _VRF_LEN_ + 16; 3826 pyld[2].key[0] = 0; pyld[2].key[1] = 0x100000; pyld[2].len = _VRF_LEN_ + 24; 3827 pyld[3].key[0] = 0; pyld[3].key[1] = 0x1000000; pyld[3].len = _VRF_LEN_ + 28; 3828 pyld[4].key[0] = 0; pyld[4].key[1] = 0x1001; pyld[4].len = _VRF_LEN_ + 16; 3829 pyld[5].key[0] = 0; pyld[5].key[1] = 0x10011; pyld[5].len = _VRF_LEN_ + 20; 3830 numkey = 6; 3831 break; 3832 3833 case 3: 3834 { 3835 int dup; 3836 3837 if (seed == 0) { 3838 seed = sal_time(); 3839 sal_srand(seed); 3840 } 3841 3842 index = 0; 3843 LOG_CLI((BSL_META("Random test: %d Seed: 0x%x \n"), id, seed)); 3844 do { 3845 do { 3846 pyld[index].key[1] = (unsigned int) sal_rand(); 3847 pyld[index].len = (unsigned int)sal_rand() % 32; 3848 pyld[index].len += _VRF_LEN_; 3849 3850 if (pyld[index].len <= 32) { 3851 pyld[index].key[0] = 0; 3852 pyld[index].key[1] &= MASK(pyld[index].len); 3853 } 3854 3855 if (pyld[index].len > 32) { 3856 pyld[index].key[0] = (unsigned int)sal_rand() % 16; 3857 pyld[index].key[0] &= MASK(pyld[index].len-32); 3858 } 3859 3860 dup = ut_check_duplicate(pyld, index); 3861 if (dup) { 3862 LOG_CLI((BSL_META("\n Duplicate at index[%d]:" 3863 "key[0x%08x:0x%08x] Retry!!!\n"), 3864 index, pyld[index].key[0], 3865 pyld[index].key[1])); 3866 } 3867 } while(dup > 0); 3868 } while(++index < _NUM_KEY_); 3869 3870 numkey = index; 3871 } 3872 break; 3873 3874 default: 3875 return SOC_E_PARAM; 3876 } 3877 3878 trie_init(_MAX_KEY_LEN_, &trie); 3879 trie_init(_MAX_KEY_LEN_, &newtrie); 3880 3881 for(index=0; index < numkey && rv == SOC_E_NONE; index++) { 3882 rv = trie_insert(trie, &pyld[index].key[0], NULL, pyld[index].len, &pyld[index].node); 3883 } 3884 3885 rv = trie_split(trie, _MAX_KEY_LEN_, FALSE, pivot, &length, &newroot, NULL, FALSE); 3886 if (SOC_SUCCESS(rv)) { 3887 LOG_CLI((BSL_META("\n Split Trie Pivot: 0x%08x 0x%08x " 3888 "Length: %d Root: %p \n"), 3889 pivot[0], pivot[1], length, newroot)); 3890 LOG_CLI((BSL_META(" $Payload Count Old Trie:%d New Trie:%d \n"), 3891 trie->trie->count, newroot->count)); 3892 3893 /* set new trie */ 3894 newtrie->trie = newroot; 3895 newtrie->v6_key = trie->v6_key; 3896 #ifdef VERBOSE 3897 LOG_CLI((BSL_META("\n OLD Trie Dump ############: \n"))); 3898 trie_dump(trie, NULL, NULL); 3899 LOG_CLI((BSL_META("\n SPLIT Trie Dump ############: \n"))); 3900 trie_dump(newtrie, NULL, NULL); 3901 #endif 3902 3903 for(index=0; index < numkey && rv == SOC_E_NONE; index++) { 3904 rv = trie_search(trie, &pyld[index].key[0], pyld[index].len, &pyldptr); 3905 if (rv != SOC_E_NONE) { 3906 rv = trie_search(newtrie, &pyld[index].key[0], pyld[index].len, &pyldptr); 3907 if (rv != SOC_E_NONE) { 3908 LOG_CLI((BSL_META("SEARCH: Key=0x%x 0x%x len %d SEARCH " 3909 "idx:%d failed on both trie!!!!\n"), 3910 pyld[index].key[0], pyld[index].key[1], 3911 pyld[index].len, index)); 3912 } else { 3913 assert(pyldptr == &pyld[index].node); 3914 } 3915 } 3916 } 3917 3918 } 3919 } 3920 3921 trie_destroy(trie); 3922 trie_destroy(newtrie); 3923 sal_free(pyld); 3924 return rv; 3925 } 3926 3927 int tmu_taps_trie_ut(int id, unsigned int seed) 3928 { 3929 int index, rv = SOC_E_NONE, numkey=0, num_deleted=0; 3930 trie_t *trie; 3931 payload_t *pyld = sal_alloc(_NUM_KEY_ * sizeof(payload_t), "unit-test"); 3932 trie_node_t *pyldptr = NULL; 3933 unsigned int result_len=0, result_key[_MAX_KEY_WORDS_]; 3934 3935 /* keys packed right to left (ie) most significant word starts at index 0*/ 3936 3937 switch(id) { 3938 case 0: 3939 pyld[0].key[0] = 0; pyld[0].key[1] = 0x10; pyld[0].len = _VRF_LEN_ + 8; /* v=0 p=0x10000000/8 */ 3940 pyld[1].key[0] = 0; pyld[1].key[1] = 0x1000; pyld[1].len = _VRF_LEN_ + 16; /* v=0 p=0x10000000/16 */ 3941 pyld[2].key[0] = 0; pyld[2].key[1] = 0x100000; pyld[2].len = _VRF_LEN_ + 24; /* v=0 p=0x10000000/24 */ 3942 pyld[3].key[0] = 0; pyld[3].key[1] = 0x10000000; pyld[3].len = _VRF_LEN_ + 32; /* v=0 p=0x10000000/48 */ 3943 numkey = 4; 3944 break; 3945 3946 case 1: 3947 pyld[0].key[0] = 0; pyld[0].key[1] = 0x123456; pyld[0].len = _VRF_LEN_ + 24; /* v=0 p=0x12345678/24 */ 3948 pyld[1].key[0] = 0; pyld[1].key[1] = 0x246; pyld[1].len = _VRF_LEN_ + 13; /* v=0 p=0x12345678/13 */ 3949 pyld[2].key[0] = 0; pyld[2].key[1] = 0x24; pyld[2].len = _VRF_LEN_ + 9; /* v=0 p=0x12345678/9 */ 3950 numkey = 3; 3951 break; 3952 3953 case 2: /* dup routes on another vrf */ 3954 pyld[0].key[0] = 0; pyld[0].key[1] = 0x1123456; pyld[0].len = _VRF_LEN_ + 24; /* v=1 p=0x12345678/24 */ 3955 pyld[1].key[0] = 0; pyld[1].key[1] = 0x2246; pyld[1].len = _VRF_LEN_ + 13; /* v=1 p=0x12345678/13 */ 3956 pyld[2].key[0] = 0; pyld[2].key[1] = 0x224; pyld[2].len = _VRF_LEN_ + 9; /* v=1 p=0x12345678/9 */ 3957 numkey = 3; 3958 break; 3959 3960 case 3: 3961 pyld[0].key[0] = 0; pyld[0].key[1] = 0x10000000; pyld[0].len = _VRF_LEN_ + 32; /* v=0 p=0x10000000/32 */ 3962 pyld[1].key[0] = 0; pyld[1].key[1] = 0x10000001; pyld[1].len = _VRF_LEN_ + 32; /* v=0 p=0x10000001/32 */ 3963 pyld[2].key[0] = 0; pyld[2].key[1] = 0x10000002; pyld[2].len = _VRF_LEN_ + 32; /* v=0 p=0x10000002/32 */ 3964 numkey = 3; 3965 break; 3966 3967 case 4: 3968 pyld[0].key[0] = 0; pyld[0].key[1] = 0x12345670; pyld[0].len = _VRF_LEN_ + 32; /* v=0 p=0x12345670/32 */ 3969 pyld[1].key[0] = 0; pyld[1].key[1] = 0x12345671; pyld[1].len = _VRF_LEN_ + 32; /* v=0 p=0x12345671/32 */ 3970 pyld[2].key[0] = 0; pyld[2].key[1] = 0x91a2b38; pyld[2].len = _VRF_LEN_ + 31; /* v=0 p=0x12345670/31 */ 3971 numkey = 3; 3972 break; 3973 3974 case 5: 3975 pyld[0].key[0] = 0; pyld[0].key[1] = 0x20; pyld[0].len = _VRF_LEN_ + 8; /* v=0 p=0x20000000/8 */ 3976 pyld[1].key[0] = 0; pyld[1].key[1] = 0x8000; pyld[1].len = _VRF_LEN_ + 16; /* v=0 p=0x80000000/16 */ 3977 pyld[2].key[0] = 0; pyld[2].key[1] = 0; pyld[2].len = _VRF_LEN_ + 0; /* v=0 p=0/0 */ 3978 numkey = 3; 3979 break; 3980 3981 case 6: 3982 { 3983 int dup; 3984 3985 if (seed == 0) { 3986 seed = sal_time(); 3987 sal_srand(seed); 3988 } 3989 index = 0; 3990 LOG_CLI((BSL_META("Random test: %d Seed: 0x%x \n"), id, seed)); 3991 do { 3992 do { 3993 pyld[index].key[1] = (unsigned int) sal_rand(); 3994 pyld[index].len = (unsigned int)sal_rand() % 32; 3995 pyld[index].len += _VRF_LEN_; 3996 3997 if (pyld[index].len <= 32) { 3998 pyld[index].key[0] = 0; 3999 pyld[index].key[1] &= MASK(pyld[index].len); 4000 } 4001 4002 if (pyld[index].len > 32) { 4003 pyld[index].key[0] = (unsigned int)sal_rand() % 16; 4004 pyld[index].key[0] &= MASK(pyld[index].len-32); 4005 } 4006 4007 dup = ut_check_duplicate(pyld, index); 4008 if (dup) { 4009 LOG_CLI((BSL_META("\n Duplicate at index[%d]:" 4010 "key[0x%08x:0x%08x] Retry!!!\n"), 4011 index, pyld[index].key[0], 4012 pyld[index].key[1])); 4013 } 4014 } while(dup > 0); 4015 } while(++index < _NUM_KEY_); 4016 4017 numkey = index; 4018 } 4019 break; 4020 4021 default: 4022 sal_free(pyld); 4023 return -1; 4024 } 4025 4026 trie_init(_MAX_KEY_LEN_, &trie); 4027 LOG_CLI((BSL_META("\n Num keys to test= %d \n"), numkey)); 4028 4029 for(index=0; index < numkey && rv == SOC_E_NONE; index++) { 4030 unsigned int vrf=0, i; 4031 vrf = (pyld[index].len - _VRF_LEN_ == 32) ? 0:pyld[index].key[1] >> (pyld[index].len - _VRF_LEN_); 4032 vrf |= pyld[index].key[0] << (32 - (pyld[index].len - _VRF_LEN_)); 4033 4034 #ifdef LOG 4035 LOG_CLI((BSL_META("+ Inserted Key=0x%x 0x%x vpn=0x%x pfx=0x%x " 4036 "Len=%d idx:%d\n"), 4037 pyld[index].key[0], pyld[index].key[1], vrf, 4038 pyld[index].key[1] & MASK(pyld[index].len - _VRF_LEN_), 4039 pyld[index].len, index)); 4040 #endif 4041 rv = trie_insert(trie, &pyld[index].key[0], NULL, pyld[index].len, &pyld[index].node); 4042 if (rv != SOC_E_NONE) { 4043 LOG_CLI((BSL_META("FAILED to Insert Key=0x%x 0x%x vpn=0x%x " 4044 "pfx=0x%x Len=%d idx:%d\n"), 4045 pyld[index].key[0], pyld[index].key[1], vrf, 4046 pyld[index].key[1] & MASK(pyld[index].len - _VRF_LEN_), 4047 pyld[index].len, index)); 4048 } 4049 #define _VERBOSE_SEARCH_ 4050 /* search all keys & figure out breakage right away */ 4051 for (i=0; i <= index && rv == SOC_E_NONE; i++) { 4052 #ifdef _VERBOSE_SEARCH_ 4053 result_key[0] = 0; 4054 result_key[1] = 0; 4055 result_len = 0; 4056 rv = trie_search_verbose(trie, &pyld[index].key[0], pyld[index].len, 4057 &pyldptr, &result_key[0], &result_len); 4058 #else 4059 rv = trie_search(trie, &pyld[index].key[0], pyld[index].len, &pyldptr); 4060 #endif 4061 if (rv != SOC_E_NONE) { 4062 LOG_CLI((BSL_META("SEARCH: Key=0x%x 0x%x len %d SEARCH " 4063 "idx:%d failed!!!!\n"), 4064 pyld[index].key[0], pyld[index].key[1], 4065 pyld[index].len, index)); 4066 break; 4067 } else { 4068 assert(pyldptr == &pyld[index].node); 4069 #ifdef _VERBOSE_SEARCH_ 4070 if (pyld[index].key[0] != result_key[0] || 4071 pyld[index].key[1] != result_key[1] || 4072 pyld[index].len != result_len) { 4073 LOG_CLI((BSL_META(" Found key mismatches with the " 4074 "expected Key !!!! \n"))); 4075 rv = SOC_E_FAIL; 4076 } 4077 #ifdef VERBOSE 4078 LOG_CLI((BSL_META("Lkup[%d] key/len: 0x%x 0x%x/%d " 4079 "Found Key/len: 0x%x 0x%x/%d \n"), 4080 index ,pyld[index].key[0], pyld[index].key[1], 4081 pyld[index].len, 4082 result_key[0], result_key[1], result_len)); 4083 #endif 4084 #endif 4085 } 4086 } 4087 } 4088 4089 #ifdef VERBOSE 4090 LOG_CLI((BSL_META("\n============== TRIE DUMP ================\n"))); 4091 trie_dump(trie, NULL, NULL); 4092 LOG_CLI((BSL_META("\n=========================================\n"))); 4093 #endif 4094 4095 /* randomly pickup prefix & delete */ 4096 while(num_deleted < numkey && rv == SOC_E_NONE) { 4097 index = sal_rand() % numkey; 4098 if (pyld[index].len != 0xFFFFFFFF) { 4099 rv = trie_search(trie, &pyld[index].key[0], pyld[index].len, &pyldptr); 4100 if (rv == SOC_E_NONE) { 4101 assert(pyldptr == &pyld[index].node); 4102 rv = trie_delete(trie, &pyld[index].key[0], pyld[index].len, &pyldptr); 4103 4104 #ifdef VERBOSE 4105 LOG_CLI((BSL_META("\n============== TRIE DUMP ================\n"))); 4106 trie_dump(trie, NULL, NULL); 4107 #endif 4108 if (rv == SOC_E_NONE) { 4109 #ifdef LOG 4110 LOG_CLI((BSL_META("Deleted Key=0x%x 0x%x Len=%d idx:%d " 4111 "Num-Key:%d\n"), 4112 pyld[index].key[0], pyld[index].key[1], 4113 pyld[index].len, index, num_deleted)); 4114 #endif 4115 pyld[index].len = 0xFFFFFFFF; 4116 num_deleted++; 4117 4118 /* search all keys & figure out breakage right away */ 4119 for (index=0; index < numkey; index++) { 4120 if (pyld[index].len == 0xFFFFFFFF) continue; 4121 4122 rv = trie_search(trie, &pyld[index].key[0], pyld[index].len, &pyldptr); 4123 if (rv != SOC_E_NONE) { 4124 LOG_CLI((BSL_META("ALL SEARCH after delete: " 4125 "Key=0x%x 0x%x len %d SEARCH " 4126 "idx:%d failed!!!!\n"), 4127 pyld[index].key[0], pyld[index].key[1], 4128 pyld[index].len, index)); 4129 break; 4130 } else { 4131 assert(pyldptr == &pyld[index].node); 4132 } 4133 } 4134 } else { 4135 LOG_CLI((BSL_META("Deleted Key=0x%x 0x%x Len=%d idx:%d " 4136 "FAILED!!!\n"), 4137 pyld[index].key[0], pyld[index].key[1], 4138 pyld[index].len, index)); 4139 break; 4140 } 4141 } else { 4142 LOG_CLI((BSL_META("SEARCH: Key=0x%x 0x%x len %d SEARCH " 4143 "idx:%d failed!!!!\n"), 4144 pyld[index].key[0], pyld[index].key[1], 4145 pyld[index].len, index)); 4146 break; 4147 } 4148 } 4149 } 4150 4151 if (rv == SOC_E_NONE) { 4152 LOG_CLI((BSL_META("\n TEST ID %d passed \n"), id)); 4153 } 4154 else { 4155 LOG_CLI((BSL_META("\n TEST ID %d Failed Num Delete:%d !!!!!!!!\n"), 4156 id, num_deleted)); 4157 } 4158 4159 sal_free(pyld); 4160 trie_destroy(trie); 4161 return rv; 4162 } 4163 4164 /**********************************************/ 4165 /* BPM unit tests */ 4166 /* test cases: 4167 * 1 - insert pivot's with bpm bit masks 4168 * 2 - propagate updated prefix bpm (add/del) 4169 * 3 - fuse node bpm verification 4170 * 4 - split bpm - nop 4171 * 5 - */ 4172 4173 typedef struct _expect_datum_s { 4174 dq_t list; 4175 payload_t *pfx; 4176 trie_t *pfx_trie; 4177 } expect_datum_t; 4178 4179 int ut_bpm_build_expect_list(trie_node_t *payload, void *user_data) 4180 { 4181 int rv=SOC_E_NONE; 4182 4183 if (payload && payload->type == PAYLOAD) { 4184 trie_node_t *pyldptr; 4185 payload_t *pivot; 4186 expect_datum_t *datum = (expect_datum_t*)user_data; 4187 4188 pivot = TRIE_ELEMENT_GET(payload_t*, payload, node); 4189 /* if the inserted prefix is a best prefix, add the pivot to expected list */ 4190 rv = trie_find_lpm(datum->pfx_trie, &pivot->key[0], pivot->len, &pyldptr); 4191 assert(rv == SOC_E_NONE); 4192 if (pyldptr == &datum->pfx->info.pfx_trie_node) { 4193 /* if pivot is not equal to prefix add to expect list */ 4194 if (!(pivot->key[0] == datum->pfx->key[0] && 4195 pivot->key[1] == datum->pfx->key[1] && 4196 pivot->len == datum->pfx->len)) { 4197 DQ_INSERT_HEAD(&datum->list, &pivot->listnode); 4198 } 4199 } 4200 } 4201 4202 return SOC_E_NONE; 4203 } 4204 4205 int ut_bpm_propagate_cb(trie_node_t *payload, trie_bpm_cb_info_t *cbinfo) 4206 { 4207 if (payload && cbinfo && payload->type == PAYLOAD) { 4208 payload_t *pivot; 4209 dq_p_t elem; 4210 expect_datum_t *datum = (expect_datum_t*)cbinfo->user_data; 4211 4212 pivot = TRIE_ELEMENT_GET(payload_t*, payload, node); 4213 DQ_TRAVERSE(&datum->list, elem) { 4214 payload_t *velem = DQ_ELEMENT_GET(payload_t*, elem, listnode); 4215 if (velem == pivot) { 4216 DQ_REMOVE(&pivot->listnode); 4217 break; 4218 } 4219 } DQ_TRAVERSE_END(&datum->list, elem); 4220 } 4221 4222 return SOC_E_NONE; 4223 } 4224 4225 int ut_bpm_propagate_empty_cb(trie_node_t *payload, trie_bpm_cb_info_t *cbinfo) 4226 { 4227 /* do nothing */ 4228 return SOC_E_NONE; 4229 } 4230 4231 void ut_bpm_dump_expect_list(expect_datum_t *datum, char *str) 4232 { 4233 dq_p_t elem; 4234 if (datum) { 4235 /* dump expected list */ 4236 LOG_CLI((BSL_META("%s \n"), str)); 4237 DQ_TRAVERSE(&datum->list, elem) { 4238 payload_t *velem = DQ_ELEMENT_GET(payload_t*, elem, listnode); 4239 LOG_CLI((BSL_META(" Pivot: 0x%x 0x%x Len: %d \n"), 4240 velem->key[0], velem->key[1], velem->len)); 4241 } DQ_TRAVERSE_END(&datum->list, elem); 4242 } 4243 } 4244 4245 #define _MAX_TEST_PIVOTS_ (10) 4246 #define _MAX_BKT_PFX_ (20) 4247 #define _MAX_NUM_PICK (30) 4248 4249 int tmu_taps_bpm_trie_ut(int id, unsigned int seed) 4250 { 4251 int rv = SOC_E_NONE, pivot=0, pfx=0, index=0, dup=0, domain=0; 4252 trie_t *pfx_trie, *trie; 4253 payload_t *pyld = sal_alloc(_MAX_BKT_PFX_ * _MAX_TEST_PIVOTS_ * sizeof(payload_t), "bpm-unit-test"); 4254 payload_t *pivot_pyld = sal_alloc(_MAX_TEST_PIVOTS_ * sizeof(payload_t), "bpm-unit-test"); 4255 trie_node_t *pyldptr = NULL, *newroot; 4256 unsigned int bpm[BITS2WORDS(_MAX_KEY_LEN_)]; 4257 expect_datum_t datum; 4258 trie_bpm_cb_info_t cbinfo; 4259 int num_pick, bpm_pfx_len; 4260 4261 sal_memset(pyld, 0, _MAX_BKT_PFX_ * _MAX_TEST_PIVOTS_ * sizeof(payload_t)); 4262 sal_memset(pivot_pyld, 0, _MAX_TEST_PIVOTS_ * sizeof(payload_t)); 4263 4264 if (seed == 0) { 4265 seed = sal_time(); 4266 sal_srand(seed); 4267 } 4268 4269 trie_init(_MAX_KEY_LEN_, &trie); 4270 trie_init(_MAX_KEY_LEN_, &pfx_trie); 4271 4272 /* populate a random pivot / prefix trie */ 4273 LOG_CLI((BSL_META("Random test: %d Seed: 0x%x \n"), id, seed)); 4274 4275 /* insert a vrf=0,* pivot */ 4276 pivot = 0; 4277 pfx = 0; 4278 pivot_pyld[pivot].key[1] = 0; 4279 pivot_pyld[pivot].key[0] = 0; 4280 pivot_pyld[pivot].len = 0; 4281 trie_init(_MAX_KEY_LEN_, &pivot_pyld[pivot].info.trie); 4282 sal_memset(&bpm[0], 0, BITS2WORDS(_MAX_KEY_LEN_) * sizeof(unsigned int)); 4283 4284 do { 4285 rv = trie_insert(trie, &pivot_pyld[pivot].key[0], &bpm[0], 4286 pivot_pyld[pivot].len, &pivot_pyld[pivot].node); 4287 if (rv != SOC_E_NONE) { 4288 LOG_CLI((BSL_META("FAILED to Insert PIVOT Key=0x%x 0x%x Len=%d idx:%d\n"), 4289 pivot_pyld[pivot].key[0], pivot_pyld[pivot].key[1], 4290 pivot_pyld[pivot].len, pivot)); 4291 } else { 4292 if (pivot > 0) { 4293 /* choose a random pivot bucket to fill & split */ 4294 domain = ((unsigned int) sal_rand()) % pivot; 4295 } else { 4296 domain = 0; 4297 } 4298 4299 index = 0; 4300 sal_memset(&bpm[0], 0, BITS2WORDS(_MAX_KEY_LEN_) * sizeof(unsigned int)); 4301 4302 do { 4303 do { 4304 /* add prefix such that lpm of the prefix is the pivot to ensure 4305 * it goes into specific pivot domain */ 4306 pyld[pfx+index].key[1] = (unsigned int) sal_rand(); 4307 pyld[pfx+index].len = (unsigned int)sal_rand() % 32; 4308 pyld[pfx+index].len += _VRF_LEN_; 4309 4310 if (pyld[pfx+index].len <= 32) { 4311 pyld[pfx+index].key[0] = 0; 4312 pyld[pfx+index].key[1] &= MASK(pyld[pfx+index].len); 4313 } 4314 4315 if (pyld[pfx+index].len > 32) { 4316 pyld[pfx+index].key[0] = (unsigned int)sal_rand() % 16; 4317 pyld[pfx+index].key[0] &= MASK(pyld[pfx+index].len-32); 4318 } 4319 4320 dup = ut_check_duplicate(pyld, pfx+index); 4321 if (!dup) { 4322 rv = trie_find_lpm(trie, &pyld[pfx+index].key[0], pyld[pfx+index].len, &pyldptr); 4323 if (SOC_FAILURE(rv)) { 4324 LOG_CLI((BSL_META("\n !! Failed to find LPM pivot for " 4325 "index[%d]:key[0x%08x:0x%08x] !!!!\n"), 4326 pfx, pyld[pfx+index].key[0], 4327 pyld[pfx+index].key[1])); 4328 } 4329 } 4330 } while ((dup || (pyldptr != &pivot_pyld[domain].node)) && SOC_SUCCESS(rv)); 4331 4332 if (SOC_SUCCESS(rv)) { 4333 rv = trie_insert(pivot_pyld[domain].info.trie, 4334 &pyld[pfx+index].key[0], NULL, 4335 pyld[pfx+index].len, &pyld[pfx+index].node); 4336 if (SOC_FAILURE(rv)) { 4337 LOG_CLI((BSL_META("\n !! Failed insert prefix into pivot trie" 4338 " index[%d]:key[0x%08x:0x%08x] !!!!\n"), 4339 pfx+index, pyld[pfx+index].key[0], 4340 pyld[pfx+index].key[1])); 4341 } else { 4342 rv = trie_insert(pfx_trie, 4343 &pyld[pfx+index].key[0], NULL, 4344 pyld[pfx+index].len, &pyld[pfx+index].info.pfx_trie_node); 4345 if (SOC_FAILURE(rv)) { 4346 LOG_CLI((BSL_META("\n !! Failed insert prefix into " 4347 "prefix trie" 4348 " index[%d]:key[0x%08x:0x%08x] !!!!\n"), 4349 pfx+index, pyld[pfx+index].key[0], 4350 pyld[pfx+index].key[1])); 4351 } else { 4352 index++; 4353 } 4354 } 4355 } 4356 4357 } while(index < (_MAX_BKT_PFX_/2 - 1) && SOC_SUCCESS(rv)); 4358 4359 /* try to populate prefix where p == v */ 4360 if (pivot > 0) { 4361 /* 25% probability */ 4362 if (((unsigned int) sal_rand() % 4) == 0) { 4363 } 4364 } 4365 4366 #ifdef VERBOSE 4367 LOG_CLI((BSL_META("### Split Domain ID: %d \n"), domain)); 4368 for (i=0; i <= pivot; i++) { 4369 LOG_CLI((BSL_META("\n --- TRIE domain dump: Pivot: 0x%x 0x%x " 4370 "len=%d ----- \n"), 4371 pivot_pyld[i].key[0], pivot_pyld[i].key[1], 4372 pivot_pyld[i].len)); 4373 trie_dump(pivot_pyld[i].info.trie, ut_print_payload_node, NULL); 4374 } 4375 #endif 4376 4377 if (SOC_SUCCESS(rv) && ++pivot < _MAX_TEST_PIVOTS_) { 4378 pfx += index; 4379 trie_init(_MAX_KEY_LEN_, &pivot_pyld[pivot].info.trie); 4380 /* split the domain & insert a new pivot */ 4381 rv = trie_split(pivot_pyld[domain].info.trie, 4382 _MAX_KEY_LEN_, FALSE, 4383 &pivot_pyld[pivot].key[0], 4384 &pivot_pyld[pivot].len, &newroot, 4385 &bpm[0], FALSE); 4386 if (SOC_SUCCESS(rv)) { 4387 pivot_pyld[pivot].info.trie->trie = newroot; 4388 pivot_pyld[pivot].info.trie->v6_key = pivot_pyld[domain].info.trie->v6_key; 4389 LOG_CLI((BSL_META("BPM for split pivot: 0x%x 0x%x / " 4390 "%d = [0x%x 0x%x] \n"), 4391 pivot_pyld[pivot].key[0], 4392 pivot_pyld[pivot].key[1], 4393 pivot_pyld[pivot].len, bpm[0], bpm[1])); 4394 } else { 4395 LOG_CLI((BSL_META("\n !!! Failed to split domain trie for " 4396 "domain: %d !!!\n"), domain)); 4397 } 4398 } 4399 } 4400 } while(pivot < _MAX_TEST_PIVOTS_ && SOC_SUCCESS(rv)); 4401 4402 /* pick up the root node on pivot trie & add a prefix shorter than the nearest child. 4403 * This is ripple & create huge propagation */ 4404 /* insert *\/1 into the * bucket so huge propagation kicks in */ 4405 pyld[pfx].key[1] = (unsigned int) sal_rand() % 1; 4406 pyld[pfx].key[0] = 0; 4407 pyld[pfx].len = 1; 4408 do { 4409 dup = ut_check_duplicate(pyld, pfx); 4410 if (!dup) { 4411 rv = trie_find_lpm(trie, &pyld[pfx].key[0], pyld[pfx].len, &pyldptr); 4412 if (SOC_FAILURE(rv)) { 4413 LOG_CLI((BSL_META("\n !! Failed to find LPM pivot for " 4414 "index[%d]:key[0x%08x:0x%08x] !!!!\n"), 4415 pfx, pyld[pfx].key[0], pyld[pfx].key[1])); 4416 } 4417 } else { 4418 pyld[pfx].len++; 4419 } 4420 } while(dup && SOC_SUCCESS(rv)); 4421 4422 if (SOC_SUCCESS(rv)) { 4423 rv = trie_insert(pfx_trie, 4424 &pyld[pfx].key[0], NULL, 4425 pyld[pfx].len, &pyld[pfx].info.pfx_trie_node); 4426 if (SOC_FAILURE(rv)) { 4427 LOG_CLI((BSL_META("\n !! Failed insert prefix into pivot trie" 4428 " index[%d]:key[0x%08x:0x%08x] !!!!\n"), 4429 pfx, pyld[pfx].key[0], pyld[pfx].key[1])); 4430 } else { 4431 DQ_INIT(&datum.list); 4432 datum.pfx = &pyld[pfx]; 4433 datum.pfx_trie = pfx_trie; 4434 /* create expected list of pivot to be propagated */ 4435 trie_traverse(trie, ut_bpm_build_expect_list, &datum, _TRIE_PREORDER_TRAVERSE); 4436 4437 /* dump expected list */ 4438 ut_bpm_dump_expect_list(&datum, "-- Expected Propagation List --"); 4439 } 4440 } 4441 4442 sal_memset(&cbinfo, 0, sizeof(trie_bpm_cb_info_t)); 4443 cbinfo.user_data = &datum; 4444 cbinfo.pfx = &pyld[pfx].key[0]; 4445 cbinfo.len = pyld[pfx].len; 4446 if (pyldptr == NULL) { 4447 assert(0); /* check here for coverity */ 4448 } 4449 rv = trie_pivot_propagate_prefix(pyldptr, 4450 (TRIE_ELEMENT_GET(payload_t*, pyldptr, node))->len, 4451 &pyld[pfx].key[0], pyld[pfx].len, 4452 1, ut_bpm_propagate_cb, &cbinfo); 4453 if (DQ_EMPTY(&datum.list)) { 4454 LOG_CLI((BSL_META("++ Propagation Test Passed \n"))); 4455 } else { 4456 LOG_CLI((BSL_META("!!!!! Propagation Test FAILED !!!!!\n"))); 4457 rv = SOC_E_FAIL; 4458 ut_bpm_dump_expect_list(&datum, "!! Zombies on Propagation List !!"); 4459 assert(0); 4460 } 4461 4462 /* propagate a shorter prefix of an existing pivot 4463 * we should find the bpm 4464 */ 4465 pfx++; 4466 num_pick = 0; 4467 do { 4468 /* randomly pick a pivot */ 4469 index = ((unsigned int) sal_rand()) % pivot; 4470 4471 /* create a prefix shorter */ 4472 pyld[pfx].len = ((unsigned int) sal_rand()) % pivot_pyld[index].len; 4473 pyld[pfx].key[1] = pivot_pyld[index].key[1]>>(pivot_pyld[index].len - pyld[pfx].len); 4474 pyld[pfx].key[0] = 0; 4475 4476 if (pyld[pfx].len >= 1) { 4477 /* propagate add len=0 */ 4478 rv = trie_pivot_propagate_prefix(trie->trie, 4479 (TRIE_ELEMENT_GET(payload_t*, trie->trie, node))->len, 4480 &pyld[pfx].key[0], 0, 4481 1, ut_bpm_propagate_empty_cb, 4482 &cbinfo); 4483 4484 if (SOC_FAILURE(rv)) { 4485 LOG_CLI((BSL_META("!!!!! BPM search Test FAILED to propagate " 4486 "add len=0!!!!!\n"))); 4487 assert(0); 4488 } 4489 4490 /* propagate add */ 4491 rv = trie_pivot_propagate_prefix(trie->trie, 4492 (TRIE_ELEMENT_GET(payload_t*, trie->trie, node))->len, 4493 &pyld[pfx].key[0], pyld[pfx].len, 4494 1, ut_bpm_propagate_empty_cb, 4495 &cbinfo); 4496 if (SOC_FAILURE(rv)) { 4497 LOG_CLI((BSL_META("!!!!! BPM search Test FAILED to propagate add \n" 4498 " index[%d]:key[0x%08x:0x%08x] len=%d!!!!\n"), 4499 pfx, pyld[pfx].key[0], pyld[pfx].key[1], pyld[pfx].len)); 4500 assert(0); 4501 } 4502 4503 /* perform bpm lookup on the pivot, we should find the pyld[pfx].len */ 4504 rv = trie_find_prefix_bpm(trie, (unsigned int *)&(pivot_pyld[index].key[0]), 4505 pivot_pyld[index].len, (unsigned int *)&bpm_pfx_len); 4506 if (SOC_FAILURE(rv) || (bpm_pfx_len != pyld[pfx].len)) { 4507 LOG_CLI((BSL_META("!!!!! BPM search Test FAILDED after propagate " 4508 "add !!!!!\n"))); 4509 assert(0); 4510 } 4511 4512 /* propagate delete */ 4513 rv = trie_pivot_propagate_prefix(trie->trie, 4514 (TRIE_ELEMENT_GET(payload_t*, trie->trie, node))->len, 4515 &pyld[pfx].key[0], pyld[pfx].len, 4516 0, ut_bpm_propagate_empty_cb, 4517 &cbinfo); 4518 4519 if (SOC_FAILURE(rv)) { 4520 LOG_CLI((BSL_META("!!!!! BPM search Test FAILED to propagate add \n" 4521 " index[%d]:key[0x%08x:0x%08x] len=%d!!!!\n"), 4522 pfx, pyld[pfx].key[0], pyld[pfx].key[1], pyld[pfx].len)); 4523 assert(0); 4524 } 4525 4526 /* perform bpm lookup on the pivot, we should find the len==0 */ 4527 rv = trie_find_prefix_bpm(trie, (unsigned int *)&(pivot_pyld[index].key[0]), 4528 pivot_pyld[index].len, (unsigned int *)&bpm_pfx_len); 4529 if (SOC_FAILURE(rv) || (bpm_pfx_len != 0)) { 4530 LOG_CLI((BSL_META("!!!!! BPM search Test FAILDED after propagate " 4531 "delete !!!!!\n"))); 4532 assert(0); 4533 } 4534 4535 num_pick = _MAX_NUM_PICK+1; 4536 } 4537 num_pick++; 4538 } while(num_pick<_MAX_NUM_PICK); 4539 4540 if (num_pick <= _MAX_NUM_PICK) { 4541 LOG_CLI((BSL_META("!!!!! BPM search Test 2 Skipped after " 4542 "tried %d times!!!!!\n"), _MAX_NUM_PICK)); 4543 } else { 4544 LOG_CLI((BSL_META("!!!!! BPM search Test 2 Passed!!!!!\n"))); 4545 } 4546 4547 #ifdef VERBOSE 4548 LOG_CLI((BSL_META("\n ----- Prefix Trie dump ----- \n"))); 4549 trie_dump(pfx_trie, ut_print_prefix_payload_node, NULL); 4550 #endif 4551 4552 LOG_CLI((BSL_META("\n ++++++++ Trie dump ++++++++ \n"))); 4553 trie_dump(trie, ut_print_payload_node, NULL); 4554 4555 /* clean up */ 4556 for (index=0; index < pivot; index++) { 4557 #ifdef VERBOSE 4558 LOG_CLI((BSL_META("\n ddddddd dump dddddddd \n"))); 4559 trie_dump(pivot_pyld[index].info.trie, ut_print_payload_node, NULL); 4560 #endif 4561 trie_destroy(pivot_pyld[index].info.trie); 4562 } 4563 4564 sal_free(pyld); 4565 sal_free(pivot_pyld); 4566 trie_destroy(trie); 4567 trie_destroy(pfx_trie); 4568 return rv; 4569 } 4570 4571 /**********************************************/ 4572 #endif 4573 4574 #endif /* BCM_TRIDENT2_SUPPORT */ 4575 #endif /* ALPM_ENABLE */ 4576