openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

alpm_lib_trie4.c (75360B)


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