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

external_lpm.c (73000B)


      1 /* 
      2  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      3  * 
      4  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      5  *
      6  * Triumph LPM TCAM table insert/delete/lookup routines
      7  * _bcm_tr_ext_lpm_init - Called from bcm_l3_init
      8  * _bcm_tr_ext_lpm_insert - Insert/Update an IPv4/IPV6 route entry into LPM table
      9  * _bcm_tr_ext_lpm_delete - Delete an IPv4/IPV6 route entry from LPM table
     10  * _bcm_tr_ext_lpm_match  - (Exact match for the key. Will match both IP address
     11  *                      and mask)
     12  *
     13  * Hit bit preservation - May loose HIT bit state when entries are moved
     14  * around due to race condition. This happens if the HIT bit gets set in
     15  * hardware after reading the entry to be moved and before the move is
     16  * completed. If the HIT bit for an entry is already set when the move is
     17  * initiated then it is preserved.
     18  */
     19 
     20 #include <soc/defs.h>
     21 
     22 #include <assert.h>
     23 #include <shared/bsl.h>
     24 #include <sal/core/libc.h>
     25 #if defined(BCM_TRIUMPH_SUPPORT)  && defined(INCLUDE_L3)
     26 
     27 #include <shared/util.h>
     28 #include <soc/mem.h>
     29 #include <soc/cm.h>
     30 #include <soc/drv.h>
     31 #include <soc/register.h>
     32 #include <soc/memory.h>
     33 #include <soc/l3x.h>
     34 #include <soc/er_tcam.h>
     35 
     36 #include <bcm/l3.h>
     37 #include <bcm/tunnel.h>
     38 #include <bcm/debug.h>
     39 #include <bcm/error.h>
     40 #include <bcm/stack.h>
     41 
     42 #include <bcm_int/esw/mbcm.h>
     43 #include <bcm_int/esw/firebolt.h>
     44 #include <bcm_int/esw/triumph.h>
     45 #include <bcm_int/esw/l3.h>
     46 #include <bcm_int/esw/xgs3.h>
     47 #include <bcm_int/esw_dispatch.h>
     48 
     49 /*
     50  * TCAM based LPM implementation. Each table entry can hold two IPV4 entries or
     51  * one IPV6 entry. VRF independent routes placed at the beginning or 
     52  * at the end of table based on application provided entry vrf id 
     53  * (BCM_L3_VRF_OVERRIDE/BCM_L3_VRF_GLOBAL).   
     54  *
     55  *              _TR_LPM_PREFIX_MAX
     56  *
     57  * lpm_prefix_index[96].begin ---> ===============================
     58  *                                 ==                           ==
     59  *                                 ==    IPV4  Prefix Len = 32  ==
     60  *                                 ==    VRF OVERRIDE ROUTES    ==
     61  * lpm_prefix_index[95].end   ---> ===============================
     62  *
     63  *
     64  *
     65  * lpm_prefix_index[64].begin ---> ===============================
     66  *                                 ==                           ==
     67  *                                 ==    IPV4  Prefix Len = 0   ==
     68  *                                 ==    VRF OVERRIDE ROUTES    ==
     69  * lpm_prefix_index[64].end   ---> ===============================
     70  *
     71  *
     72  *
     73  * lpm_prefix_index[63].begin ---> ===============================
     74  *                                 ==                           ==
     75  *                                 ==    IPV4  Prefix Len = 32  ==
     76  *                                 ==    VRF SPECIFIC ROUTES    ==
     77  * lpm_prefix_index[63].end   ---> ===============================
     78  *
     79  *
     80  *
     81  * lpm_prefix_index[32].begin ---> ===============================
     82  *                                 ==                           ==
     83  *                                 ==    IPV4  Prefix Len = 0   ==
     84  *                                 ==    VRF SPECIFIC ROUTES    ==
     85  * lpm_prefix_index[32].end   ---> ===============================
     86  *
     87  *
     88  *
     89  * lpm_prefix_index[31].begin ---> ===============================
     90  *                                 ==                           ==
     91  *                                 ==    IPV4  Prefix Len = 32  ==
     92  *                                 ==    VRF GLOBAL ROUTES      ==
     93  * lpm_prefix_index[31].end   ---> ===============================
     94  *
     95  *
     96  *
     97  * lpm_prefix_index[0].begin --->  ===============================
     98  *                                 ==                           ==
     99  *                                 ==    IPV4  Prefix Len = 0   ==
    100  *                                 ==    VRF GLOBAL ROUTES      ==
    101  * lpm_prefix_index[0].end   --->  ===============================
    102  */
    103 
    104 typedef struct _tr_ext_lpm_state_s {
    105     int start;  /* start index for this prefix length */
    106     int end;    /* End index for this prefix length */
    107     int prev;   /* Previous (Lo to Hi) prefix length with non zero entry count*/
    108     int next;   /* Next (Hi to Lo) prefix length with non zero entry count */
    109     int vent;   /* valid entries */
    110     int fent;   /* free entries */
    111 } _tr_ext_lpm_state_t, *_tr_ext_lpm_state_p;
    112 
    113 #define SOC_MEM_COMPARE_RETURN(a, b) {          \
    114         if ((a) < (b)) { return -1; }           \
    115         if ((a) > (b)) { return  1; }           \
    116 }
    117 
    118 #define _TR_LPM_IPV4  (0)
    119 #define _TR_LPM_IPV6  (1)
    120 #define _TR_LPM_IP_VERSIONS (2)
    121 
    122 #define _TR_LPM_BLOCK_SZ (0x200)
    123 
    124 #define _TR_LPM_ROUTE_IS_V6(_entry_)        \
    125        (((_entry_)->defip_flags & BCM_L3_IP6) ?  _TR_LPM_IPV6 : _TR_LPM_IPV4)
    126 
    127 
    128 static _tr_ext_lpm_state_p _tr_lpm_state[_TR_LPM_IP_VERSIONS][SOC_MAX_NUM_DEVICES];
    129 
    130 #define _TR_LPM_INIT_CHECK(_u_, _v_) \
    131                     (_tr_lpm_state[(_v_)][(_u_)] != NULL)
    132 #define _TR_LPM_STATE(_u_, _v_)  \
    133                     (_tr_lpm_state[(_v_)][(_u_)]) 
    134 #define _TR_LPM_STATE_START(_u_, _v_, _pfx_) \
    135                     (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).start 
    136 #define _TR_LPM_STATE_END(_u_, _v_, _pfx_) \
    137                     (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).end
    138 #define _TR_LPM_STATE_PREV(_u_, _v_, _pfx_)  \
    139                     (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).prev
    140 #define _TR_LPM_STATE_NEXT(_u_, _v_, _pfx_) \
    141                     (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).next
    142 #define _TR_LPM_STATE_VENT(_u_, _v_, _pfx_) \
    143                     (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).vent
    144 #define _TR_LPM_STATE_FENT(_u_, _v_, _pfx_) \
    145                     (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).fent
    146 #define _TR_LPM_PREFIX_COUNT(_mem_) \
    147             (((_mem_) == EXT_IPV4_DEFIPm) ?  33 :  \
    148               ((_mem_) == EXT_IPV6_64_DEFIPm) ?  65 : 129)
    149 /* 1 set for VRF_OVERRIDE, 1 set for VRF DEPENDENT, 1 set for VRF_GLOBAL */
    150 #define _TR_LPM_PREFIX_MAX(_mem_) (3 * _TR_LPM_PREFIX_COUNT(_mem_))
    151                  
    152 #define _TR_LPM_PREFIX_MAX_INDEX(_mem_) (_TR_LPM_PREFIX_MAX(_mem_) - 1)
    153 
    154 /* IPv4 tcam software entry. */
    155 typedef struct _tr_lpm_v4_key_s {
    156     uint32      addr;           /* IPv4 address. */
    157     uint32      vrf;            /* Vrf id.                             */ 
    158     uint32      next_entry:21;  /* Next entry producing identical hash.*/
    159 } _tr_lpm_v4_key_t;
    160 
    161 /* IPv6 tcam software entry. */
    162 typedef struct _tr_lpm_v6_key_s {
    163     uint8       addr[16];        /* IPv6 address.                        */
    164     uint32      vrf;             /* VRF id.                              */
    165     uint32      next_entry:21;   /* Next entry producing identical hash. */
    166 } _tr_lpm_v6_key_t;
    167 
    168 /* IPv6 tcam software image. */
    169 typedef struct _tr_lpm_sw_image_s {
    170     int         unit;
    171     int         hash_size;      /* Number entries in hash table       */
    172     int         *hash_table;    /* Hash table with 16 bit index.      */
    173     soc_mem_t   mem;            /* Combined route table view memory.  */
    174     soc_mem_t   data_mem;       /* Memory route data resides in.      */
    175     soc_mem_t   hit_bit_mem;    /* Memory route hit_bit resides in.   */
    176     _tr_lpm_v4_key_t *fib4;     /* Sw image of ipv4 route table.   */
    177     _tr_lpm_v6_key_t *fib6;     /* Sw image of ipv6 route table.   */
    178 } _tr_lpm_sw_image_t, *_tr_lpm_sw_image_p;
    179 
    180 
    181 static _tr_lpm_sw_image_p _lpm_sw_image[_TR_LPM_IP_VERSIONS][SOC_MAX_NUM_DEVICES];
    182 
    183 #define _TR_LPM_SW_IMAGE(_u_, _v_) (_lpm_sw_image[(_v_)][(_u_)])
    184 #define _TR_LPM_MEM(_u_, _v_) (_TR_LPM_SW_IMAGE((_u_), (_v_))->mem)
    185 #define _TR_LPM_DATA_MEM(_u_, _v_) (_TR_LPM_SW_IMAGE((_u_), (_v_))->data_mem)
    186 #define _TR_LPM_HIT_BIT_MEM(_u_, _v_) \
    187                    (_TR_LPM_SW_IMAGE((_u_), (_v_))->hit_bit_mem)
    188 #define _TR_LPM_FIB4(_u_) (_TR_LPM_SW_IMAGE((_u_), (_TR_LPM_IPV4))->fib4)
    189 #define _TR_LPM_FIB6(_u_) (_TR_LPM_SW_IMAGE((_u_), (_TR_LPM_IPV6))->fib6)
    190 
    191 
    192 #define _TR_LPM_HASH_INDEX_NULL  (0x1FFFFF)
    193 #define _TR_LPM_HASH_SZ   (5)
    194 typedef uint32 _tr_ext_lpm_hash_entry_t[_TR_LPM_HASH_SZ];
    195 #define _TR_LPM_HASH_ENTRY_IPV6_GET(_entry_, _odata_)                    \
    196     sal_memcpy((_odata_), (_entry_)->defip_ip6_addr, sizeof(bcm_ip6_t)); \
    197     _odata_[4] = (_entry_)->defip_vrf
    198 
    199 #define _TR_LPM_HASH_ENTRY_IPV4_GET(_entry_, _odata_)                   \
    200     sal_memset((_odata_), 0, _TR_LPM_HASH_SZ * sizeof(uint32));         \
    201     sal_memcpy((_odata_), &(_entry_)->defip_ip_addr, sizeof(bcm_ip_t)); \
    202     _odata_[4] = (_entry_)->defip_vrf
    203 
    204 
    205 /* 
    206  * Function:
    207  *      _tr_lpm_sw_image_create
    208  * Purpose:
    209  *      Create an sw image of external lpm table.
    210  * Parameters:
    211  *      unit   - (IN) Device unit
    212  *      v6     - (IN) IPv6 sw image indicator. 
    213  *      mem    - (IN) Memory route table resides in.
    214  * Returns:
    215  *      BCM_E_XXX
    216  */
    217 
    218 STATIC int 
    219 _tr_lpm_sw_image_create(int unit, int v6, soc_mem_t mem) 
    220 {
    221     _tr_lpm_sw_image_p sw_image;     /* Allocated sw image.       */
    222     int     index;                   /* Sw image iteration index. */  
    223     int     mem_size;                /* Allocate memory size.     */
    224 
    225     /* 
    226      * Allocate software image. 
    227      */
    228     sw_image = sal_alloc(sizeof(_tr_lpm_sw_image_t), "External lpm sw image");
    229     if (sw_image == NULL) {
    230         return (BCM_E_MEMORY);
    231     }
    232 
    233     sal_memset(sw_image, 0, sizeof(_tr_lpm_sw_image_t));
    234 
    235     /*
    236      *  Initialize sw image properties (unit, hash size, memory size).
    237      */
    238     sw_image->unit = unit;
    239     sw_image->hash_size = (1 << BYTES2BITS(sizeof(uint16)));
    240     switch(mem) {
    241       case EXT_IPV4_DEFIPm:
    242           sw_image->mem = EXT_IPV4_DEFIPm;
    243           sw_image->data_mem = EXT_DEFIP_DATA_IPV4m;
    244           sw_image->hit_bit_mem = EXT_DST_HIT_BITS_IPV4m;
    245           break;
    246       case EXT_IPV6_64_DEFIPm:
    247           sw_image->mem = EXT_IPV6_64_DEFIPm;
    248           sw_image->data_mem = EXT_DEFIP_DATA_IPV6_64m;
    249           sw_image->hit_bit_mem = EXT_DST_HIT_BITS_IPV6_64m;
    250           break;
    251       case EXT_IPV6_128_DEFIPm:
    252           sw_image->mem = EXT_IPV6_128_DEFIPm;
    253           sw_image->data_mem = EXT_DEFIP_DATA_IPV6_128m;
    254           sw_image->hit_bit_mem = EXT_DST_HIT_BITS_IPV6_128m;
    255           break;
    256       default:
    257           sal_free(sw_image);
    258           return (BCM_E_PARAM);
    259     }
    260 
    261     /*
    262      * Pre-allocate the hash table storage.
    263      */
    264     mem_size = sw_image->hash_size * sizeof(int);
    265     sw_image->hash_table = sal_alloc(mem_size, "External lpm hash table");
    266     if (NULL == sw_image->hash_table) {
    267         sal_free(sw_image);
    268         return (BCM_E_MEMORY);
    269     }
    270 
    271     /*
    272      * Pre-allocate a complete sw view of installed entries.
    273      */
    274     if (v6) {
    275         mem_size = soc_mem_index_count(unit, sw_image->mem) *  \
    276                    sizeof(_tr_lpm_v6_key_t); 
    277         sw_image->fib6 = sal_alloc(mem_size, "External lpm fib");
    278         if (NULL == sw_image->fib6) {
    279             sal_free(sw_image->hash_table);
    280             sal_free(sw_image);
    281             return (BCM_E_MEMORY);
    282         }
    283         sal_memset(sw_image->fib6, 0, mem_size);
    284     } else {
    285         mem_size = soc_mem_index_count(unit, sw_image->mem) *  \
    286                    sizeof(_tr_lpm_v4_key_t); 
    287         sw_image->fib4 = sal_alloc(mem_size, "External lpm fib");
    288         if (NULL == sw_image->fib4) {
    289             sal_free(sw_image->hash_table);
    290             sal_free(sw_image);
    291             return (BCM_E_MEMORY);
    292         }
    293         sal_memset(sw_image->fib4, 0, mem_size);
    294     }
    295 
    296 
    297     /*
    298      * Set the entries in the hash table to _TR_LPM_HASH_INDEX_NULL
    299      * Link the entries beyond hash->index_max for handling collisions
    300      */
    301     for(index = 0; index < sw_image->hash_size; index++) {
    302         sw_image->hash_table[index] = _TR_LPM_HASH_INDEX_NULL;
    303     }
    304 
    305     for(index = 0; index < soc_mem_index_count(unit,sw_image->mem); index++) {
    306         if (v6) { 
    307             sw_image->fib6[index].next_entry = _TR_LPM_HASH_INDEX_NULL;
    308         } else {
    309             sw_image->fib4[index].next_entry = _TR_LPM_HASH_INDEX_NULL;
    310         }
    311     }
    312 
    313     _TR_LPM_SW_IMAGE(unit, v6) = sw_image;
    314 
    315     return (BCM_E_NONE);
    316 }
    317 
    318 /* 
    319  * Function:
    320  *      _tr_lpm_sw_image_destroy
    321  * Purpose:
    322  *      Destroy the sw image table
    323  * Parameters:
    324  *      unit - (IN) BCM device nu
    325  *      v6   - (IN) IP version. 
    326  * Returns:
    327  *      BCM_E_XXX
    328  */
    329 STATIC int 
    330 _tr_lpm_sw_image_destroy(int unit, int v6)
    331 {
    332     if (NULL != _TR_LPM_SW_IMAGE(unit, v6)) {
    333         if (NULL != _TR_LPM_SW_IMAGE(unit, v6)->hash_table)  {
    334             sal_free(_TR_LPM_SW_IMAGE(unit, v6)->hash_table);
    335         }
    336 
    337         if ((v6) && (NULL != _TR_LPM_FIB6(unit))) {
    338             sal_free(_TR_LPM_FIB6(unit));
    339         } 
    340         
    341         if ((!v6) &&  (NULL != _TR_LPM_FIB4(unit))) {
    342             sal_free(_TR_LPM_FIB4(unit));
    343         }
    344         sal_free(_TR_LPM_SW_IMAGE(unit, v6));
    345     }
    346 
    347     _TR_LPM_SW_IMAGE(unit, v6) = NULL;
    348     return (BCM_E_NONE);
    349 }
    350 
    351 
    352 /* 
    353  * Function:
    354  *      _tr_ext_lpm_hash_compute
    355  * Purpose:
    356  *      Compute CRC hash for key data.
    357  * Parameters:
    358  *      data - (IN) Key data
    359  *      hash - (OUT)Computed 16 bit hash
    360  * Returns:
    361  *      BCM_E_XXX
    362  */
    363 STATIC int 
    364 _tr_ext_lpm_hash_compute(_bcm_defip_cfg_t *data, uint16 *hash)
    365 {
    366     bcm_ip6_t v6_mask;                 /* IPv6 subnet mask. */
    367     uint32  v4_mask;                   /* IPv4 subnet mask. */
    368     _tr_ext_lpm_hash_entry_t buf;      /* Scratch buffer.   */
    369 
    370     if ((NULL == data) || (NULL == hash)) {
    371         return (BCM_E_PARAM);
    372     }
    373 
    374     if (_TR_LPM_ROUTE_IS_V6(data)) {
    375         /* Create mask from prefix length. */
    376         bcm_ip6_mask_create(v6_mask, data->defip_sub_len);
    377         /* Apply prefix mask. */
    378         bcm_xgs3_l3_mask6_apply(v6_mask, data->defip_ip6_addr);
    379         /* Extract buffer for hash */
    380         _TR_LPM_HASH_ENTRY_IPV6_GET(data, buf); 
    381 
    382     } else {
    383         /* Create mask from prefix length. */
    384         v4_mask = BCM_IP4_MASKLEN_TO_ADDR(data->defip_sub_len);
    385         /* Apply prefix mask. */
    386         data->defip_ip_addr &= v4_mask;
    387         /* Extract buffer for hash */
    388         _TR_LPM_HASH_ENTRY_IPV4_GET(data, buf); 
    389     }
    390 
    391     /* Calculate hash value. */
    392     *hash = _shr_crc16b(0, (void *)buf, BYTES2BITS(_TR_LPM_HASH_SZ * sizeof(uint32)));
    393 
    394     return (BCM_E_NONE);
    395 }
    396 
    397 /* 
    398  * Function:
    399  *      _tr_ext_lpm_sw_entry_reset
    400  * Purpose:
    401  *      Reset software  entry.
    402  * Parameters:
    403  *      unit       - (IN) BCM device number. 
    404  *      v6         - (IN) IPv6 entry flag.
    405  *      index      - (IN) SW entry index. 
    406  * Returns:
    407  *      BCM_E_XXX
    408  */
    409 static INLINE int
    410 _tr_ext_lpm_sw_entry_reset(int unit, int v6, int index)
    411 {
    412     if (v6) {
    413         sal_memset(_TR_LPM_FIB6(unit) + index, 0, sizeof (_tr_lpm_v6_key_t));
    414         _TR_LPM_FIB6(unit)[index].next_entry = _TR_LPM_HASH_INDEX_NULL;
    415     } else {
    416         sal_memset(_TR_LPM_FIB4(unit) + index, 0, sizeof (_tr_lpm_v4_key_t));
    417         _TR_LPM_FIB4(unit)[index].next_entry = _TR_LPM_HASH_INDEX_NULL;
    418     }
    419     return (BCM_E_NONE);
    420 }
    421 
    422 /* 
    423  * Function:
    424  *      _tr_ext_lpm_key_compare
    425  * Purpose:
    426  *      Compare API provided route entry with entry in sw image.
    427  * Parameters:
    428  *      unit        - (IN) Bcm device number.
    429  *      index       - (IN) SW image entry index.
    430  *      data        - (IN) Route entry. 
    431  * Returns:
    432  *      BCM_E_XXX
    433  */
    434 STATIC int 
    435 _tr_ext_lpm_key_compare(int unit, int index, _bcm_defip_cfg_t *data)
    436 {
    437     bcm_ip6_t v6_mask;                 /* IPv6 subnet mask.    */
    438     int        result;                 /* Comparison result.   */
    439     int            v6;                 /* IPv6 route indicator.*/         
    440 
    441     if (NULL == data)  {
    442         return (BCM_E_PARAM);
    443     }
    444 
    445     v6 = _TR_LPM_ROUTE_IS_V6(data);
    446 
    447     /* Perform index range sanity check. */
    448     if ((index < 0) || 
    449         (index >= soc_mem_index_count(unit, _TR_LPM_MEM(unit, v6)))) {
    450         return (BCM_E_PARAM);
    451     }
    452 
    453 
    454     /* Prefix comparison. */
    455     if (v6) {
    456         /* Vrf comparison. */
    457         if (data->defip_vrf != _TR_LPM_FIB6(unit)[index].vrf) {
    458             return (-1);
    459         } 
    460         /* IPv6 Create mask from prefix length. */
    461         bcm_ip6_mask_create(v6_mask, data->defip_sub_len);
    462         /* Apply prefix mask. */
    463         bcm_xgs3_l3_mask6_apply(v6_mask, data->defip_ip6_addr);
    464         /* Compare prefixes */
    465         result = sal_memcmp(data->defip_ip6_addr, 
    466                             _TR_LPM_FIB6(unit)[index].addr, 
    467                             sizeof(bcm_ip6_t));
    468     }  else {
    469         /* Vrf comparison. */
    470         if (data->defip_vrf != _TR_LPM_FIB4(unit)[index].vrf) {
    471             return (-1);
    472         } 
    473         /* Apply prefix mask. */
    474         data->defip_ip_addr &= BCM_IP4_MASKLEN_TO_ADDR(data->defip_sub_len);
    475         /* Compare prefixes */
    476         result = sal_memcmp(&data->defip_ip_addr, 
    477                             &_TR_LPM_FIB4(unit)[index].addr, sizeof(bcm_ip_t));
    478     }
    479 
    480     return (result);
    481 }
    482 /*
    483  * Function:
    484  *      _tr_ext_lpm_prefix_length_get
    485  * Purpose:
    486  *      Extract vrf weighted prefix length from the route entry.
    487  * Parameters:
    488  *      unit    - (IN)BCM device number.
    489  *      entry   - (IN)Lookup key. 
    490  *      pfx_len     - (OUT)Prefix length.
    491  * Returns:
    492  *      BCM_E_XXX
    493  */
    494 STATIC int
    495 _tr_ext_lpm_prefix_length_get(int unit, _bcm_defip_cfg_t *entry, int *pfx_len)
    496 {
    497     soc_mem_t   mem;      /* Route table memory.   */
    498     int          v6;      /* IPv6 entry indicator. */ 
    499 
    500     /* Input parameters check. */
    501     if ((NULL == entry) || (NULL == pfx_len)) {
    502         return (BCM_E_PARAM);
    503     }
    504 
    505     v6  = _TR_LPM_ROUTE_IS_V6(entry);
    506     mem = _TR_LPM_MEM(unit, v6);
    507 
    508     switch (entry->defip_vrf) { 
    509       case BCM_L3_VRF_GLOBAL:
    510           *pfx_len = entry->defip_sub_len;
    511           break;
    512       case BCM_L3_VRF_OVERRIDE:
    513           *pfx_len = entry->defip_sub_len + 2 * _TR_LPM_PREFIX_COUNT(mem);
    514           break;
    515       default:   
    516           *pfx_len = entry->defip_sub_len + _TR_LPM_PREFIX_COUNT(mem);
    517           break;
    518     }
    519     return (BCM_E_NONE);
    520 }
    521 
    522 
    523 /*
    524  * Function:
    525  *      _tr_ext_lpm_reset
    526  * Purpose:
    527  *      Flush  an entry from external route table.
    528  * Parameters:
    529  *      unit       - (IN) BCM unit number.
    530  *      v6         - (IN) IPv6 entry indicator. 
    531  *      index      - (IN) Entry index.  
    532  * Returns:
    533  *      BCM_E_XXX
    534  */
    535 STATIC int
    536 _tr_ext_lpm_reset(int unit, int v6, int index)
    537 {
    538     soc_mem_t       mem;                       /* Route table memory.    */ 
    539 
    540     /* Get memory name. */
    541     mem = _TR_LPM_MEM(unit, v6);
    542 
    543     /* Check index range. */
    544     if ((index > soc_mem_index_max(unit, mem)) || 
    545         (index < soc_mem_index_min(unit, mem))) {
    546         return (BCM_E_PARAM); 
    547     }
    548 
    549     return soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, 
    550                          &soc_mem_entry_null(unit, mem));
    551 }
    552 
    553 
    554 /*
    555  * Function:
    556  *      _tr_ext_lpm_write
    557  * Purpose:
    558  *      Get an entry from external route table.
    559  * Parameters:
    560  *      unit           - (IN) BCM unit number.
    561  *      data           - (IN) Entry data. 
    562  *      nh_ecmp_idx    - (IN) Next hop ecmp group index.
    563  * Returns:
    564  *      BCM_E_XXX
    565  */
    566 STATIC int
    567 _tr_ext_lpm_write(int unit, _bcm_defip_cfg_t *data, int nh_ecmp_idx)
    568                
    569 {
    570     uint32 buf[SOC_MAX_MEM_FIELD_WORDS];       /* Buffer for HW entry.   */
    571     soc_mem_t       mem;                       /* Route table memory.    */ 
    572     bcm_ip6_t   v6_mask;                       /* IPv6 route mask.       */
    573     int          vrf_id;                       /* VRF id.                */
    574     int        vrf_mask;                       /* VRF mask.              */
    575     int       field_len;                       /* Vrf field length.      */
    576     uint32   field_mask;                       /* Vrf field mask.        */
    577     int              v6;                       /* IPv6 route indicator.  */
    578 
    579     /* Input parameters check. */
    580     if (NULL == data) {
    581         return (BCM_E_PARAM);
    582     }
    583 
    584     v6  = _TR_LPM_ROUTE_IS_V6(data);
    585     mem = _TR_LPM_MEM(unit, v6);
    586 
    587     /* Entry index sanity check. */
    588     if ((data->defip_index > soc_mem_index_max(unit, mem)) ||
    589         (data->defip_index < soc_mem_index_min(unit, mem))) {
    590         return (BCM_E_PARAM);
    591     }
    592 
    593     /* Extract entry vrf id & vrf mask. */
    594     BCM_IF_ERROR_RETURN
    595         (bcm_xgs3_internal_lpm_vrf_calc(unit, data, &vrf_id, &vrf_mask));
    596 
    597     /* Reset hw buffer first. */
    598     sal_memset(buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    599 
    600     /* Set valid bit. */
    601     soc_mem_field32_set(unit, mem, buf, VALIDf, 0x1);
    602 
    603     /* Check if entry points to ecmp group. */
    604     if (data->defip_flags & BCM_L3_MULTIPATH) {  
    605         /* Mark entry as ECMP & set ecmp group id. */
    606         soc_mem_field32_set(unit, mem, buf, ECMPf, 0x1);
    607         soc_mem_field32_set(unit, mem, buf, ECMP_PTRf, nh_ecmp_idx);
    608     } else {
    609         soc_mem_field32_set(unit, mem, buf, NEXT_HOP_INDEXf, nh_ecmp_idx);
    610     }
    611 
    612     /* Set priority override bit & entry priority. */
    613     if (data->defip_flags & BCM_L3_RPE) {
    614         soc_mem_field32_set(unit, mem, buf, RPEf, 0x1);
    615         /* Set entry priority. */
    616         soc_mem_field32_set(unit, mem, buf, PRIf, data->defip_prio);
    617     }
    618 
    619     /* Set destination discard flag. */
    620     if (data->defip_flags & BCM_L3_DST_DISCARD) {
    621         soc_mem_field32_set(unit, mem, buf, DST_DISCARDf, 0x1);
    622     }
    623 
    624     /* Set classification group id. */
    625     soc_mem_field32_set(unit, mem, buf, CLASS_IDf, 
    626                         data->defip_lookup_class);
    627 
    628     /* Set hit bit . */
    629     if (data->defip_flags & BCM_L3_HIT) {
    630         soc_mem_field32_set(unit, mem, buf, DST_HITf, 0x1);
    631     }
    632 
    633     /* Set default route indication. */
    634     if (0 == data->defip_sub_len) {
    635         soc_mem_field32_set(unit, mem, buf, DEFAULTROUTEf, 0x1);
    636     }
    637 
    638     /* Set Global route flag. */
    639     if (BCM_L3_VRF_GLOBAL == data->defip_vrf) { 
    640         soc_mem_field32_set(unit, mem, buf, GLOBAL_ROUTEf, 0x1);
    641     }
    642 
    643     /* Set vrf id. */
    644     field_len = soc_mem_field_length(unit, mem, VRF_LOf);
    645     field_mask = (1 << field_len) - 1;
    646 
    647     soc_mem_field32_set(unit, mem, buf, VRF_LOf, vrf_id & field_mask);
    648     soc_mem_mask_field32_set(unit, mem, buf, MASK_VRF_LOf, 
    649                              vrf_mask & field_mask);
    650 
    651     if (SOC_MEM_FIELD_VALID(unit, mem, VRF_HIf)) {
    652         soc_mem_field32_set(unit, mem, buf, VRF_HIf, vrf_id >> field_len);
    653         soc_mem_mask_field32_set(unit, mem, buf, MASK_VRF_HIf, 
    654                                  vrf_mask >> field_len);
    655     }
    656 
    657     /* Set ip address. */
    658     if (v6) {
    659         bcm_ip6_mask_create(v6_mask, data->defip_sub_len);
    660         bcm_xgs3_l3_mask6_apply(v6_mask, data->defip_ip6_addr);
    661 
    662         if (SOC_MEM_FIELD_VALID(unit, mem, IP_ADDRf)) {
    663             /* Set address upper part (0-63). */
    664             soc_mem_ip6_addr_set(unit, mem, buf, IP_ADDRf, 
    665                                  data->defip_ip6_addr, SOC_MEM_IP6_UPPER_ONLY);
    666             /* Set address mask upper part (0-63). */
    667             soc_mem_ip6_addr_mask_set(unit, mem, buf, MASK_IP_ADDRf, 
    668                                       v6_mask, SOC_MEM_IP6_UPPER_ONLY);
    669         } else {
    670             /* Set address upper part (0-63). */
    671             soc_mem_ip6_addr_set(unit, mem, buf, IP_ADDR_HIf, 
    672                                  data->defip_ip6_addr, SOC_MEM_IP6_UPPER_ONLY);
    673             /* Set address mask upper part (0-63). */
    674             soc_mem_ip6_addr_mask_set(unit, mem, buf, MASK_IP_ADDR_HIf, 
    675                                       v6_mask, SOC_MEM_IP6_UPPER_ONLY);
    676 
    677             /* Set address lower part (64-127). */
    678             soc_mem_ip6_addr_set(unit, mem, buf, IP_ADDR_LOf, 
    679                                  data->defip_ip6_addr, SOC_MEM_IP6_LOWER_ONLY);
    680             /* Set address mask upper part (64-127). */
    681             soc_mem_ip6_addr_mask_set(unit, mem, buf, MASK_IP_ADDR_LOf, 
    682                                       v6_mask, SOC_MEM_IP6_LOWER_ONLY);
    683         }
    684     } else {
    685         /* Set ip  address. */
    686         soc_mem_field32_set(unit, mem, buf, IP_ADDRf, data->defip_ip_addr);
    687         /* Set ip  address mask. */
    688         soc_mem_mask_field32_set(unit, mem, buf, MASK_IP_ADDRf,
    689                                  BCM_IP4_MASKLEN_TO_ADDR(data->defip_sub_len));
    690     }
    691 
    692     /* Mask reserved bits as "don't compare" */
    693     if (SOC_MEM_FIELD_VALID(unit, mem, MASK_RESERVEDf)) {
    694         soc_mem_mask_field32_set(unit, mem, buf, MASK_RESERVEDf, 0);
    695     }
    696 
    697     /* Write entry to the hardware. */
    698     BCM_IF_ERROR_RETURN (soc_mem_write(unit, mem, MEM_BLOCK_ALL,
    699                                        data->defip_index, buf));
    700 
    701     return (BCM_E_NONE);
    702 }
    703 
    704 /*
    705  * Function:
    706  *      _tr_ext_lpm_parse_route_data
    707  * Purpose:
    708  *      Parse  an entry from external route table.
    709  * Parameters:
    710  *      unit           - (IN)  SOC unit number.
    711  *      v6             - (IN)  IPv6 route indicator.
    712  *      index          - (IN)  Entry index to read.
    713  *      sub_net_length - (IN)  Subnet prefix length.
    714  *      data_buf       - (IN)  filled EXT_DATA_MEMORY buffer.
    715  *      data           - (OUT) Entry data. 
    716  *      nh_ecmp_idx    - (OUT) Next hop ecmp group index.
    717  * Returns:
    718  *      BCM_E_XXX
    719  */
    720 STATIC int
    721 _tr_ext_lpm_parse_route_data(int unit, int v6, int index,
    722                              int sub_net_length, uint32 *buf, 
    723                              uint32 *usage_buf, _bcm_defip_cfg_t *data, 
    724                              int *nh_ecmp_idx)
    725 {
    726     soc_mem_t data_mem;                        /* Route data memory.         */
    727     soc_mem_t hit_bit_mem;                     /* Route data memory.         */
    728     uint32 hit_bit_word;                       /* Hit bit for 32 entries.    */
    729     int clear_hit;                             /* Clear hit bit.             */
    730 
    731     /* Input parameters check. */
    732     if ((NULL == data) || (NULL == buf) || (NULL == usage_buf)) {
    733         return (BCM_E_PARAM);
    734     }
    735 
    736     /* Get data/hit_bit memory . */
    737     data_mem = _TR_LPM_DATA_MEM(unit, v6);
    738     hit_bit_mem = _TR_LPM_HIT_BIT_MEM(unit, v6);
    739     clear_hit = data->defip_flags & BCM_L3_HIT_CLEAR;
    740 
    741     /* Reset destination buffer. */
    742     sal_memset(data, 0, sizeof(_bcm_defip_cfg_t));
    743 
    744     /* Set route index in the tcam. */
    745     data->defip_index = index;
    746 
    747     /* Parse buffer fields. */
    748     data->defip_flags = (v6) ? BCM_L3_IP6 : 0;
    749 
    750     /* Check if entry points to ecmp group. */
    751     if (soc_mem_field32_get(unit, data_mem, buf, ECMPf)) {
    752         /* Mark entry as ecmp */
    753         data->defip_ecmp = 1;
    754         data->defip_flags |= BCM_L3_MULTIPATH;
    755 
    756         /* Get ecmp group id. */
    757         if (nh_ecmp_idx) {
    758             *nh_ecmp_idx =
    759                 soc_mem_field32_get(unit, data_mem, buf, ECMP_PTRf); 
    760         }
    761     } else {
    762         /* Mark entry as non-ecmp. */
    763         data->defip_ecmp = 0;
    764 
    765         /* Reset ecmp group next hop count. */
    766         data->defip_ecmp_count = 0;
    767 
    768         /* Get next hop index. */
    769         if (nh_ecmp_idx) {
    770             *nh_ecmp_idx = soc_mem_field32_get(unit, data_mem, buf,
    771                                                 NEXT_HOP_INDEXf); 
    772         }
    773     }
    774     /* Get entry priority. */
    775     data->defip_prio = soc_mem_field32_get(unit, data_mem, buf, PRIf);
    776 
    777     /* Get priority override bit. */
    778     if (soc_mem_field32_get(unit, data_mem, buf, RPEf)) {
    779         data->defip_flags |= BCM_L3_RPE;
    780     }
    781 
    782     /* Get destination discard flag. */
    783     if(soc_mem_field32_get(unit, data_mem, buf, DST_DISCARDf)) {
    784         data->defip_flags |= BCM_L3_DST_DISCARD;
    785     }
    786 
    787     /* Set classification group id. */
    788     data->defip_lookup_class = 
    789         soc_mem_field32_get(unit, data_mem, buf, CLASS_IDf);
    790 
    791     /* Vrf id. */
    792 
    793     /* Subnet address */
    794     if (v6) {
    795         data->defip_vrf = _TR_LPM_FIB6(unit)[index].vrf;
    796         sal_memcpy(data->defip_ip6_addr, 
    797                 _TR_LPM_FIB6(unit)[index].addr, sizeof(bcm_ip6_t));
    798     } else {
    799         data->defip_vrf = _TR_LPM_FIB4(unit)[index].vrf;
    800         data->defip_ip_addr = _TR_LPM_FIB4(unit)[index].addr;
    801     }
    802 
    803     /* Sub net prefix length. */
    804     data->defip_sub_len = sub_net_length;
    805 
    806     /* Get hit bit. */    
    807     hit_bit_word = soc_mem_field32_get(unit, hit_bit_mem, 
    808                                        usage_buf, DST_HITf);
    809     if ((hit_bit_word >> (index % 32)) & 0x1) {
    810         data->defip_flags |= BCM_L3_HIT;
    811     }
    812     /* Clear hit bit if required. */
    813     if (clear_hit) {
    814         hit_bit_word &= ~(0x1 << (index % 32));
    815         soc_mem_field32_set(unit, hit_bit_mem, usage_buf, DST_HITf, hit_bit_word);
    816         BCM_IF_ERROR_RETURN
    817             (soc_mem_write(unit, hit_bit_mem, MEM_BLOCK_ALL, 
    818                            (index >> 5), usage_buf));
    819     }
    820     return (BCM_E_NONE);
    821 } 
    822 
    823 /*
    824  * Function:
    825  *      _tr_ext_lpm_read_route_data
    826  * Purpose:
    827  *      Get an entry from external route table.
    828  * Parameters:
    829  *      unit           - (IN)  SOC unit number.
    830  *      v6             - (IN)  IPv6 route indicator.
    831  *      index          - (IN)  Entry index to read.
    832  *      sub_net_length - (IN)  Subnet prefix length.
    833  *      data           - (OUT) Entry data. 
    834  *      nh_ecmp_idx    - (OUT) Next hop ecmp group index.
    835  * Returns:
    836  *      BCM_E_XXX
    837  */
    838 STATIC int
    839 _tr_ext_lpm_read_route_data(int unit, int v6, int index, int sub_net_length, 
    840                  _bcm_defip_cfg_t *data, int *nh_ecmp_idx)
    841 {
    842     soc_mem_t data_mem;                        /* Route data memory.         */
    843     soc_mem_t hit_bit_mem;                     /* Route data memory.         */
    844     uint32 buf[SOC_MAX_MEM_FIELD_WORDS];       /* Buffer for HW entry.       */
    845     uint32 usage_buf[2];                       /* Buffer for hit bit.        */
    846 
    847     /* Input parameters check. */
    848     if (NULL == data) {
    849         return (BCM_E_PARAM);
    850     }
    851 
    852     /* Get data/hit_bit memory . */
    853     data_mem = _TR_LPM_DATA_MEM(unit, v6);
    854     hit_bit_mem = _TR_LPM_HIT_BIT_MEM(unit, v6);
    855 
    856     /* Read buffer from HW. */
    857     BCM_IF_ERROR_RETURN
    858         (soc_mem_read(unit, data_mem, MEM_BLOCK_ANY, index, buf));
    859 
    860     /* Read hit bit buffer from HW. */
    861     BCM_IF_ERROR_RETURN
    862         (soc_mem_read(unit, hit_bit_mem, MEM_BLOCK_ANY, (index >> 5),
    863                       usage_buf));
    864 
    865     return  _tr_ext_lpm_parse_route_data(unit, v6, index, sub_net_length, 
    866                                          buf, usage_buf, data, nh_ecmp_idx);
    867 
    868 }
    869 
    870 /*
    871  * Function:
    872  *      _tr_ext_lpm_match
    873  * Purpose:
    874  *      Get an entry from external route table.
    875  * Parameters:
    876  *      unit        - (IN)  SOC unit number.
    877  *      key         - (IN)  Lookup key. 
    878  *      pfx         - (IN)  VRF weighted prefix length.
    879  *      result      - (OUT) Matching entry index.
    880  * Returns:
    881  *      BCM_E_XXX
    882  */
    883 STATIC int
    884 _tr_ext_lpm_match(int unit, _bcm_defip_cfg_t *key, int pfx, int *result)
    885                
    886 {
    887     uint16     hash_val;   /* Entry lookup hash.                     */
    888     int              v6;   /* Entry is IPv6 flag.                    */
    889     int           index;   /* Same hash linked list iteration index. */
    890 
    891 
    892     /* Input parameters check. */
    893     if ((NULL == key) || (NULL == result)) {
    894         return (BCM_E_PARAM);
    895     }
    896 
    897     v6 = _TR_LPM_ROUTE_IS_V6(key);
    898 
    899     /* Check if any entry with this prefix length present in sw table. */
    900     if (0 == _TR_LPM_STATE_VENT(unit, v6, pfx)) {
    901         return (BCM_E_NOT_FOUND);
    902     }
    903 
    904     /* Compute route entry hash value. */
    905     BCM_IF_ERROR_RETURN(_tr_ext_lpm_hash_compute(key, &hash_val));
    906     hash_val %= _TR_LPM_SW_IMAGE(unit, v6)->hash_size;
    907 
    908     /* Get first route table entry matching the hash. */
    909     index = _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val];
    910 
    911     while(index != _TR_LPM_HASH_INDEX_NULL) {
    912 
    913         /* Skip indexes with not matching prefix length. */
    914         if ((index < _TR_LPM_STATE_START(unit, v6, pfx)) ||  
    915             (index > _TR_LPM_STATE_END(unit, v6, pfx))) {
    916             if (v6) {
    917                 index = _TR_LPM_FIB6(unit)[index].next_entry;
    918             } else {
    919                 index = _TR_LPM_FIB4(unit)[index].next_entry;
    920             }
    921             continue;
    922         }
    923 
    924         /* Compare entry itself. */
    925         if (!_tr_ext_lpm_key_compare(unit, index,  key)) {
    926             break;
    927         }
    928 
    929         /* Continue to the next entry if no match found. */
    930         if (v6) {
    931             index = _TR_LPM_FIB6(unit)[index].next_entry;
    932         } else {
    933             index = _TR_LPM_FIB4(unit)[index].next_entry;
    934         }
    935     }
    936 
    937     /* Check lookup result. */
    938     if (_TR_LPM_HASH_INDEX_NULL == index) {
    939         return (BCM_E_NOT_FOUND);
    940     }
    941 
    942     *result = index;
    943     return (BCM_E_NONE);
    944 }
    945 
    946 
    947 /* 
    948  * Function:
    949  *      _tr_ext_lpm_sw_entry_delete
    950  * Purpose:
    951  *      Remove a route entry from sw image. 
    952  * Parameters:
    953  *      unit  - (IN) BCM device number. 
    954  *      key   - (IN) Route entry.
    955  * Returns:
    956  *      BCM_E_XXX
    957  */
    958 STATIC int
    959 _tr_ext_lpm_sw_entry_delete(int unit, _bcm_defip_cfg_t *key)
    960 {
    961     int              v6;   /* Entry is IPv6 flag.                    */
    962     int           index;   /* Same hash linked list iteration index. */
    963     uint16     hash_val;   /* Entry lookup hash.                     */
    964     int      prev_index;   /* Same hash linked list iteration index. */
    965     
    966 
    967     /* Input parameters check */
    968     if (NULL == key) {
    969         return (BCM_E_PARAM);
    970     }
    971 
    972     v6 = _TR_LPM_ROUTE_IS_V6(key);
    973 
    974     /* Compute route entry hash value. */
    975     BCM_IF_ERROR_RETURN(_tr_ext_lpm_hash_compute(key, &hash_val));
    976     hash_val %= _TR_LPM_SW_IMAGE(unit, v6)->hash_size;
    977 
    978     /* Linked list deletion procedure. */
    979     index =  _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val];
    980     prev_index = _TR_LPM_HASH_INDEX_NULL;
    981 
    982     while(index != _TR_LPM_HASH_INDEX_NULL) {
    983         if (key->defip_index == index) {
    984             if (prev_index == _TR_LPM_HASH_INDEX_NULL) {
    985                 /* Delete from head of the list. */
    986                 if (v6) {
    987                     _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val] = \
    988                         _TR_LPM_FIB6(unit)[index].next_entry;
    989                 } else {
    990                     _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val] = \
    991                         _TR_LPM_FIB4(unit)[index].next_entry;
    992                 }
    993             } else {
    994                 /* Delete from the middle/end of the list. */
    995                 if (v6) {
    996                     _TR_LPM_FIB6(unit)[prev_index].next_entry =  \
    997                         _TR_LPM_FIB6(unit)[index].next_entry;
    998                 } else {
    999                     _TR_LPM_FIB4(unit)[prev_index].next_entry =  \
   1000                         _TR_LPM_FIB4(unit)[index].next_entry;
   1001                 }
   1002             }
   1003             break;
   1004         }
   1005         /* Check next entry in the linked list. */
   1006         prev_index = index;
   1007         if (v6) {
   1008             index = _TR_LPM_FIB6(unit)[index].next_entry;
   1009         } else {
   1010             index = _TR_LPM_FIB4(unit)[index].next_entry;
   1011         }
   1012     }
   1013 
   1014     /* Check if index was found. */
   1015     if (_TR_LPM_HASH_INDEX_NULL == index) {
   1016         return(BCM_E_NOT_FOUND);
   1017     }
   1018 
   1019     /* Reset original sw entry.  */
   1020     BCM_IF_ERROR_RETURN (_tr_ext_lpm_sw_entry_reset(unit, v6, index)); 
   1021     return (BCM_E_NONE);
   1022 }
   1023 
   1024 /* 
   1025  * Function:
   1026  *      _tr_ext_lpm_sw_entry_insert
   1027  * Purpose:
   1028  *      Insert a route entry to sw image. 
   1029  * Parameters:
   1030  *      unit  - (IN) BCM device number. 
   1031  *      key   - (IN) Route entry.
   1032  * Returns:
   1033  *      BCM_E_XXX
   1034  */
   1035 STATIC int
   1036 _tr_ext_lpm_sw_entry_insert(int unit, _bcm_defip_cfg_t *key)
   1037 {
   1038     int              v6;   /* Entry is IPv6 flag.                    */
   1039     int           index;   /* Same hash linked list iteration index. */
   1040     uint16     hash_val;   /* Entry lookup hash.                     */
   1041     
   1042 
   1043     /* Input parameters check */
   1044     if (NULL == key) {
   1045         return (BCM_E_PARAM);
   1046     }
   1047 
   1048     v6 = _TR_LPM_ROUTE_IS_V6(key);
   1049     index = key->defip_index;
   1050 
   1051     /* Compute route entry hash value. */
   1052     BCM_IF_ERROR_RETURN(_tr_ext_lpm_hash_compute(key, &hash_val));
   1053     hash_val %= _TR_LPM_SW_IMAGE(unit, v6)->hash_size;
   1054 
   1055     if (v6) {
   1056         /* Point entry next to the head of linked list. */
   1057         _TR_LPM_FIB6(unit)[index].next_entry = \
   1058             _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val];
   1059         /* Set prefix subnet ip. */
   1060         sal_memcpy(_TR_LPM_FIB6(unit)[index].addr, 
   1061                    key->defip_ip6_addr, sizeof(bcm_ip6_t));
   1062         /* Set prefix vrf. */
   1063         _TR_LPM_FIB6(unit)[index].vrf = key->defip_vrf;
   1064     } else {
   1065         /* Point entry next to the head of linked list. */
   1066         _TR_LPM_FIB4(unit)[index].next_entry = \
   1067             _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val];
   1068         /* Set prefix subnet ip. */
   1069         _TR_LPM_FIB4(unit)[index].addr = key->defip_ip_addr;
   1070         /* Set prefix vrf. */
   1071         _TR_LPM_FIB4(unit)[index].vrf = key->defip_vrf;
   1072     }
   1073 
   1074     /* Point hash linked list head to the entry. */
   1075     _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val] = index;
   1076 
   1077     return (BCM_E_NONE);
   1078 }
   1079 
   1080 
   1081 /* 
   1082  * Function:
   1083  *      _tr_lpm_ext_entry_shift
   1084  * Purpose:
   1085  *      Move an entry in external route table  
   1086  * Parameters:
   1087  *      unit      - (IN) BCM device number. 
   1088  *      v6        - (IN) IPv6 indicator.  
   1089  *      from_ent  - (IN) Source entry index. 
   1090  *      to_ent    - (IN) Destination entry index.
   1091  * Returns:
   1092  *      BCM_E_XXX
   1093  */
   1094 STATIC int 
   1095 _tr_lpm_ext_entry_shift(int unit, int v6, int pfx, int from_ent, int to_ent)
   1096 {
   1097     int    nh_ecmp_idx;               /* Next hop/ecmp group index. */
   1098     _bcm_defip_cfg_t data;            /* Route data.                */
   1099 
   1100     sal_memset(&data, 0, sizeof(_bcm_defip_cfg_t));
   1101 
   1102     pfx %= _TR_LPM_PREFIX_COUNT(_TR_LPM_MEM(unit, v6));
   1103 
   1104     if (to_ent != from_ent) {
   1105         BCM_IF_ERROR_RETURN 
   1106             (_tr_ext_lpm_read_route_data(unit, v6, from_ent, pfx,
   1107                                          &data, &nh_ecmp_idx));
   1108 
   1109         BCM_IF_ERROR_RETURN(_tr_ext_lpm_sw_entry_delete(unit, &data)); 
   1110         data.defip_index = to_ent;
   1111 
   1112         BCM_IF_ERROR_RETURN(_tr_ext_lpm_write(unit, &data, nh_ecmp_idx));
   1113         BCM_IF_ERROR_RETURN(_tr_ext_lpm_sw_entry_insert(unit, &data)); 
   1114     }
   1115 
   1116     return (BCM_E_NONE);
   1117 }
   1118 
   1119 
   1120 
   1121 /* 
   1122  * Function:
   1123  *      _tr_lpm_ext_shift_pfx_up
   1124  * Purpose:
   1125  *      Ripple prefixes 1 entry  up. 
   1126  * Parameters:
   1127  *      unit      - (IN)  BCM device number. 
   1128  *      v6        - (IN)  IPv6 indicator.  
   1129  *      pfx       - (IN)  Prefix subnet length. 
   1130  * Returns:
   1131  *      BCM_E_XXX
   1132  */
   1133 STATIC int 
   1134 _tr_lpm_ext_shift_pfx_up(int unit, int v6, int pfx)
   1135 {
   1136     int         from_ent;
   1137     int         to_ent;
   1138 
   1139     to_ent = _TR_LPM_STATE_END(unit, v6, pfx) + 1;
   1140 
   1141     from_ent = _TR_LPM_STATE_START(unit, v6, pfx);
   1142     if(from_ent != to_ent) {
   1143         BCM_IF_ERROR_RETURN
   1144             (_tr_lpm_ext_entry_shift(unit, v6, pfx, from_ent, to_ent));
   1145     }
   1146     _TR_LPM_STATE_START(unit, v6, pfx) += 1;
   1147     _TR_LPM_STATE_END(unit, v6, pfx) += 1;
   1148     return (BCM_E_NONE);
   1149 }
   1150 
   1151 
   1152 /* 
   1153  * Function:
   1154  *      _tr_lpm_ext_shift_pfx_down
   1155  * Purpose:
   1156  *      Ripple prefixes 1 entry  down. 
   1157  * Parameters:
   1158  *      unit      - (IN)  BCM device number. 
   1159  *      v6        - (IN)  IPv6 indicator.  
   1160  *      pfx       - (IN)  Prefix subnet length. 
   1161  * Returns:
   1162  *      BCM_E_XXX
   1163  */
   1164 STATIC int 
   1165 _tr_lpm_ext_shift_pfx_down(int unit, int v6, int pfx)
   1166 {
   1167     int         from_ent;
   1168     int         to_ent;
   1169 
   1170     to_ent = _TR_LPM_STATE_START(unit, v6, pfx) - 1;
   1171 
   1172     /* Don't move empty prefix . */
   1173     if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) {
   1174         _TR_LPM_STATE_START(unit, v6, pfx) = to_ent;
   1175         _TR_LPM_STATE_END(unit, v6, pfx) = to_ent - 1;
   1176         return (BCM_E_NONE);
   1177     }
   1178 
   1179     to_ent   = _TR_LPM_STATE_START(unit, v6, pfx) - 1;
   1180     from_ent = _TR_LPM_STATE_END(unit, v6, pfx);
   1181     BCM_IF_ERROR_RETURN
   1182         (_tr_lpm_ext_entry_shift(unit, v6, pfx, from_ent, to_ent));
   1183 
   1184     _TR_LPM_STATE_START(unit, v6, pfx) -= 1;
   1185     _TR_LPM_STATE_END(unit, v6, pfx) -= 1;
   1186 
   1187     return (BCM_E_NONE);
   1188 }
   1189 
   1190 /* 
   1191  * Function:
   1192  *      _tr_ext_lpm_free_slot_create
   1193  * Purpose:
   1194  *      Create a slot for the new entry rippling the entries if required.
   1195  * Parameters:
   1196  *      unit      - (IN)  BCM device number. 
   1197  *      v6        - (IN)  IPv6 indicator.  
   1198  *      pfx       - (IN)  Prefix subnet length. 
   1199  *      free_slot - (OUT) Free slot index.
   1200  * Returns:
   1201  *      BCM_E_XXX
   1202  */
   1203 STATIC int 
   1204 _tr_ext_lpm_free_slot_create(int unit, int v6, int pfx, int *free_slot)
   1205 {
   1206     int         prev_pfx;         /* Prefixes iteration index.     */
   1207     int         next_pfx;         /* Prefixes iteration index.     */
   1208     int         free_pfx;         /* Prefix that has free entries. */        
   1209     int         curr_pfx;         /* Prefixes iteration index.     */
   1210     soc_mem_t   mem;              /* Route table entry.            */
   1211 
   1212     mem = _TR_LPM_MEM(unit, v6);
   1213 
   1214     if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) {
   1215         /*
   1216          * Find the  prefix position. Only prefix with valid
   1217          * entries are in the list.
   1218          * next -> high to low prefix. low to high index
   1219          * prev -> low to high prefix. high to low index
   1220          * Unused prefix length MAX_PFX_INDEX is the head of the
   1221          * list and is node corresponding to this is always
   1222          * present.
   1223          */
   1224         curr_pfx = _TR_LPM_PREFIX_MAX_INDEX(mem);
   1225         while (_TR_LPM_STATE_NEXT(unit, v6, curr_pfx) > pfx) {
   1226             curr_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx);
   1227         }
   1228         /* Insert the new prefix */
   1229         next_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx);
   1230         if (next_pfx != -1) {
   1231             _TR_LPM_STATE_PREV(unit, v6, next_pfx) = pfx;
   1232         }
   1233         _TR_LPM_STATE_NEXT(unit, v6, pfx) = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx);
   1234         _TR_LPM_STATE_PREV(unit, v6, pfx) = curr_pfx;
   1235         _TR_LPM_STATE_NEXT(unit, v6, curr_pfx) = pfx;
   1236 
   1237         _TR_LPM_STATE_FENT(unit, v6, pfx) =  (_TR_LPM_STATE_FENT(unit, v6, curr_pfx) + 1) / 2;
   1238         _TR_LPM_STATE_FENT(unit, v6, curr_pfx) -= _TR_LPM_STATE_FENT(unit, v6, pfx);
   1239         _TR_LPM_STATE_START(unit, v6, pfx) =  _TR_LPM_STATE_END(unit, v6, curr_pfx) +
   1240                                        _TR_LPM_STATE_FENT(unit, v6, curr_pfx) + 1;
   1241         _TR_LPM_STATE_END(unit, v6, pfx) = _TR_LPM_STATE_START(unit, v6, pfx) - 1;
   1242         _TR_LPM_STATE_VENT(unit, v6, pfx) = 0;
   1243     } 
   1244 
   1245     free_pfx = pfx;
   1246     while(_TR_LPM_STATE_FENT(unit, v6, free_pfx) == 0) {
   1247         free_pfx = _TR_LPM_STATE_NEXT(unit, v6, free_pfx);
   1248         if (free_pfx == -1) {
   1249             /* No free entries on this side try the other side */
   1250             free_pfx = pfx;
   1251             break;
   1252         }
   1253     }
   1254 
   1255     while(_TR_LPM_STATE_FENT(unit, v6, free_pfx) == 0) {
   1256         free_pfx = _TR_LPM_STATE_PREV(unit, v6, free_pfx);
   1257         if (free_pfx == -1) {
   1258             if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) {
   1259                 /* We failed to allocate entries for a newly allocated prefix.*/
   1260                 prev_pfx = _TR_LPM_STATE_PREV(unit, v6, pfx);
   1261                 next_pfx = _TR_LPM_STATE_NEXT(unit, v6, pfx);
   1262                 if (-1 != prev_pfx) {
   1263                     _TR_LPM_STATE_NEXT(unit, v6, prev_pfx) = next_pfx;
   1264                 }
   1265                 if (-1 != next_pfx) {
   1266                     _TR_LPM_STATE_PREV(unit, v6, next_pfx) = prev_pfx;
   1267                 }
   1268             }
   1269             return(BCM_E_FULL);
   1270         }
   1271     }
   1272 
   1273     /*
   1274      * Ripple entries to create free space
   1275      */
   1276     while (free_pfx > pfx) {
   1277         next_pfx = _TR_LPM_STATE_NEXT(unit, v6, free_pfx); 
   1278         BCM_IF_ERROR_RETURN(_tr_lpm_ext_shift_pfx_down(unit, v6, next_pfx));
   1279         _TR_LPM_STATE_FENT(unit, v6, free_pfx) -= 1;
   1280         _TR_LPM_STATE_FENT(unit, v6, next_pfx) += 1;
   1281         free_pfx = next_pfx;
   1282     }
   1283 
   1284     while (free_pfx < pfx) {
   1285         BCM_IF_ERROR_RETURN(_tr_lpm_ext_shift_pfx_up(unit, v6, free_pfx));
   1286         _TR_LPM_STATE_FENT(unit, v6, free_pfx) -= 1;
   1287         prev_pfx = _TR_LPM_STATE_PREV(unit, v6, free_pfx); 
   1288         _TR_LPM_STATE_FENT(unit, v6, prev_pfx) += 1;
   1289         free_pfx = prev_pfx;
   1290     }
   1291 
   1292     _TR_LPM_STATE_VENT(unit, v6, pfx) += 1;
   1293     _TR_LPM_STATE_FENT(unit, v6, pfx) -= 1;
   1294     _TR_LPM_STATE_END(unit, v6, pfx) += 1;
   1295 
   1296     *free_slot = _TR_LPM_STATE_END(unit, v6, pfx);
   1297     return(BCM_E_NONE);
   1298 }
   1299 
   1300 /* 
   1301  * Function:
   1302  *      _tr_ext_lpm_free_slot_delete
   1303  * Purpose:
   1304  *      Delete entry matching prefix, vrf in external route table.
   1305  * Parameters:
   1306  *      unit  -  (IN) BCM device number. 
   1307  *      v6    -  (IN) IPv6 indicator.  
   1308  *      pfx   -  (IN) Prefix subnet length. 
   1309  *      slot  -  (IN) Deleted entry index.
   1310  * Returns:
   1311  *      BCM_E_XXX
   1312  */
   1313 STATIC int 
   1314 _tr_ext_lpm_free_slot_delete (int unit, int v6, int pfx, int slot)
   1315 {
   1316     int              prev_pfx;       /* Prefixes iteration index.  */
   1317     int              next_pfx;       /* Prefixes iteration index.  */ 
   1318     int              from_ent;       /* Entry source index.        */
   1319     int              to_ent;         /* Entry destination index.   */
   1320 
   1321     from_ent = _TR_LPM_STATE_END(unit, v6, pfx);
   1322     to_ent = slot;
   1323 
   1324     _TR_LPM_STATE_VENT(unit, v6, pfx) -= 1;
   1325     _TR_LPM_STATE_FENT(unit, v6, pfx) += 1;
   1326     _TR_LPM_STATE_END(unit,  v6, pfx) -= 1;
   1327 
   1328     if (to_ent != from_ent) {
   1329         BCM_IF_ERROR_RETURN 
   1330             (_tr_lpm_ext_entry_shift(unit, v6, pfx, from_ent, to_ent));
   1331     }
   1332 
   1333     BCM_IF_ERROR_RETURN(_tr_ext_lpm_reset(unit, v6, from_ent));
   1334 
   1335     if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) {
   1336         /* remove from the list */
   1337         prev_pfx = _TR_LPM_STATE_PREV(unit, v6, pfx); /* Always present */
   1338         next_pfx = _TR_LPM_STATE_NEXT(unit, v6, pfx);
   1339         _TR_LPM_STATE_NEXT(unit, v6, prev_pfx) = next_pfx;
   1340         _TR_LPM_STATE_FENT(unit, v6, prev_pfx) += _TR_LPM_STATE_FENT(unit, v6, pfx);
   1341         _TR_LPM_STATE_FENT(unit, v6, pfx) = 0;
   1342         if (next_pfx != -1) {
   1343             _TR_LPM_STATE_PREV(unit, v6, next_pfx) = prev_pfx;
   1344         }
   1345         _TR_LPM_STATE_NEXT(unit, v6, pfx) = -1;
   1346         _TR_LPM_STATE_PREV(unit, v6, pfx) = -1;
   1347         _TR_LPM_STATE_START(unit, v6, pfx) = -1;
   1348         _TR_LPM_STATE_END(unit, v6, pfx) = -1;
   1349     }
   1350 
   1351     return(BCM_E_NONE);
   1352 }
   1353 
   1354 
   1355 
   1356 /*
   1357  * Function:
   1358  *      _bcm_tr_ext_lpm_init
   1359  * Purpose:
   1360  *      Initialize external route table sw image. 
   1361  * Parameters:
   1362  *      unit        - (IN)SOC unit number.
   1363  *      mem         - (IN)External route table memory name. 
   1364  * Returns:
   1365  *      BCM_E_XXX
   1366  */
   1367 int
   1368 _bcm_tr_ext_lpm_init(int unit, soc_mem_t mem)
   1369 {
   1370     int num_prefixes;     /* Number of different prefixes.     */
   1371     int pfx_state_size;   /* Prefix state tracking array size. */
   1372     int defip_table_size; /* Route table size.                 */
   1373     int index;            /* Iteration index.                  */
   1374     int v6;               /* IP version.                       */ 
   1375     
   1376      /* Calculate sw image type & number of prefixes based on memory name. */
   1377      v6 = (EXT_IPV4_DEFIPm == mem) ? _TR_LPM_IPV4 : _TR_LPM_IPV6; 
   1378      num_prefixes =  _TR_LPM_PREFIX_MAX(mem);
   1379 
   1380      /* Allocate prefix tracking table. */
   1381      pfx_state_size = sizeof(_tr_ext_lpm_state_t) * (num_prefixes);
   1382      if (!_TR_LPM_INIT_CHECK(unit, v6)) {
   1383          _TR_LPM_STATE(unit, v6) = (_tr_ext_lpm_state_t *)sal_alloc(pfx_state_size, "LPM prefix info");
   1384          if (NULL == _TR_LPM_STATE(unit, v6)) {
   1385              return (BCM_E_MEMORY);
   1386          }
   1387      }
   1388 
   1389     /* Initialize prefix tracking table. */
   1390     sal_memset(_TR_LPM_STATE(unit, v6), 0, pfx_state_size);
   1391 
   1392     for(index = 0; index < num_prefixes; index++) {
   1393         _TR_LPM_STATE_START(unit, v6, index) = -1;
   1394         _TR_LPM_STATE_END(unit,   v6, index) = -1;
   1395         _TR_LPM_STATE_PREV(unit,  v6, index) = -1;
   1396         _TR_LPM_STATE_NEXT(unit,  v6, index) = -1;
   1397         _TR_LPM_STATE_VENT(unit,  v6, index) = 0;
   1398         _TR_LPM_STATE_FENT(unit,  v6, index) = 0;
   1399     }
   1400 
   1401     /* Allocate sw image based on number of entries in the memory. */
   1402     defip_table_size = soc_mem_index_count(unit, mem);
   1403     _TR_LPM_STATE_FENT(unit, v6, num_prefixes - 1) = defip_table_size;
   1404 
   1405     /* If image was previously allocated free it. */
   1406     if (_TR_LPM_SW_IMAGE(unit, v6) != NULL) {
   1407         if (BCM_FAILURE(_tr_lpm_sw_image_destroy(unit, v6))) {
   1408             return (BCM_E_INTERNAL);
   1409         }
   1410     }
   1411 
   1412     /* Allocate  sw image. */
   1413     if (_tr_lpm_sw_image_create(unit, v6, mem)) { 
   1414         return (BCM_E_MEMORY);
   1415     }
   1416 
   1417     return(BCM_E_NONE);
   1418 }
   1419 
   1420 /*
   1421  * Function:
   1422  *      _bcm_tr_ext_lpm_deinit
   1423  * Purpose:
   1424  *      De-initialize external route table sw image. 
   1425  * Parameters:
   1426  *      unit        - (IN)SOC unit number.
   1427  *      mem         - (IN)External route table memory name. 
   1428  * Returns:
   1429  *      BCM_E_XXX
   1430  */
   1431 int
   1432 _bcm_tr_ext_lpm_deinit(int unit, soc_mem_t mem)
   1433 {
   1434     int rv;       /* Operation return status. */
   1435     int v6;       /* IP version.              */ 
   1436     
   1437     v6 = (EXT_IPV4_DEFIPm == mem) ? _TR_LPM_IPV4 : _TR_LPM_IPV6;
   1438 
   1439     rv = _tr_lpm_sw_image_destroy(unit, v6);
   1440 
   1441     if (_TR_LPM_STATE(unit, v6) != NULL) {
   1442         sal_free(_TR_LPM_STATE(unit, v6));
   1443         _TR_LPM_STATE(unit, v6) = NULL;
   1444     }
   1445     return(rv);
   1446 }
   1447 
   1448 #if defined(BCM_WARM_BOOT_SUPPORT)
   1449 /*
   1450  * Function:
   1451  *      _bcm_tr_ext_lpm_reinit_done
   1452  * Purpose:
   1453  *      Re-initialize external route table sw image 
   1454  *      prefix ranges completion call. 
   1455  * Parameters:
   1456  *      unit        - (IN)SOC unit number.
   1457  *      mem         - (IN)External route table memory name. 
   1458  * Returns:
   1459  *      BCM_E_XXX
   1460  */
   1461 STATIC int
   1462 _bcm_tr_ext_lpm_reinit_done(int unit, soc_mem_t mem)
   1463 {
   1464     int idx;              /* Prefix length iteration index.  */
   1465     int num_prefixes;     /* Number of different prefixes.   */
   1466     int prev_idx;         /* Prefix length iteration index.  */
   1467     int defip_table_size; /* Entry count in route table.     */
   1468     int v6;               /* IPv6 route indicator.           */
   1469 
   1470     num_prefixes = _TR_LPM_PREFIX_MAX_INDEX(mem);
   1471     prev_idx = num_prefixes;
   1472     defip_table_size = soc_mem_index_count(unit, mem);
   1473     v6 = (EXT_IPV4_DEFIPm != mem);
   1474 
   1475     _TR_LPM_STATE_PREV(unit, v6, num_prefixes) = -1;
   1476 
   1477     for (idx = num_prefixes; idx > 0 ; idx--) {
   1478         if (-1 == _TR_LPM_STATE_START(unit, v6, idx)) {
   1479             continue;
   1480         }
   1481 
   1482         _TR_LPM_STATE_PREV(unit, v6, idx) = prev_idx;
   1483         _TR_LPM_STATE_NEXT(unit, v6, prev_idx) = idx;
   1484 
   1485         _TR_LPM_STATE_FENT(unit, v6, prev_idx) =                    \
   1486                           _TR_LPM_STATE_START(unit, v6, idx) -      \
   1487                           _TR_LPM_STATE_END(unit, v6, prev_idx) - 1;
   1488         prev_idx = idx;
   1489         
   1490     }
   1491 
   1492     _TR_LPM_STATE_NEXT(unit, v6, prev_idx) = -1;
   1493     _TR_LPM_STATE_FENT(unit, v6, prev_idx) =                   \
   1494                           defip_table_size -                   \
   1495                           _TR_LPM_STATE_END(unit, v6, prev_idx) - 1;
   1496 
   1497     return (BCM_E_NONE);
   1498 }
   1499 
   1500 /*
   1501  * Function:
   1502  *      _bcm_tr_ext_lpm_reinit
   1503  * Purpose:
   1504  *      Re-initialize external route table sw image. 
   1505  * Parameters:
   1506  *      unit        - (IN)SOC unit number.
   1507  *      mem         - (IN)External route table memory name. 
   1508  *      idx         - (IN)Entry index.
   1509  *      lpm_cfg     - (IN)Entry index.
   1510  * Returns:
   1511  *      BCM_E_XXX
   1512  */
   1513 STATIC int
   1514 _bcm_tr_ext_lpm_reinit(int unit, soc_mem_t mem, 
   1515                        int idx, _bcm_defip_cfg_t *lpm_cfg)
   1516 {
   1517     int pfx_len;
   1518     int v6;
   1519 
   1520     if (NULL == lpm_cfg) {
   1521         return (BCM_E_PARAM);
   1522     }
   1523 
   1524     v6 = (lpm_cfg->defip_flags & BCM_L3_IP6) ? 1 : 0;
   1525 
   1526     BCM_IF_ERROR_RETURN
   1527         (_tr_ext_lpm_prefix_length_get(unit, lpm_cfg, &pfx_len));
   1528 
   1529     if (_TR_LPM_STATE_VENT(unit, v6, pfx_len) == 0) {
   1530         _TR_LPM_STATE_START(unit, v6, pfx_len) = idx;
   1531         _TR_LPM_STATE_END(unit, v6, pfx_len) = idx;
   1532     } else {
   1533         _TR_LPM_STATE_END(unit, v6, pfx_len) = idx;
   1534     }
   1535 
   1536     _TR_LPM_STATE_VENT(unit, v6, pfx_len)++;
   1537 
   1538     return (BCM_E_NONE);
   1539 }
   1540 #endif /* BCM_WARM_BOOT_SUPPORT */
   1541 
   1542 /* 
   1543  * Function:
   1544  *      _bcm_tr_ext_lpm_add
   1545  * Purpose:
   1546  *      Insert prefix, vrf in external route table.
   1547  * Parameters:
   1548  *      unit         - (IN) BCM device number. 
   1549  *      data         - (IN) Inserted entry.   
   1550  *      nh_ecmp_idx  - (IN) Next hop ecmp index.
   1551  * Returns:
   1552  *      BCM_E_XXX
   1553  */
   1554 int
   1555 _bcm_tr_ext_lpm_add(int unit, _bcm_defip_cfg_t *data, int nh_ecmp_idx)
   1556 {
   1557     int        rv;       /* Operation return status. */
   1558     int        v6;       /* IP protocol version.       */
   1559     int        pfx;      /* VRF weighted prefix length.*/
   1560 
   1561     /* Input parameters sanitcy check */
   1562     if (NULL == data) {
   1563         return (BCM_E_PARAM);
   1564     }
   1565 
   1566     v6 = _TR_LPM_ROUTE_IS_V6(data);
   1567 
   1568     /* Calculate vrf weighted prefix lengh. */
   1569     _tr_ext_lpm_prefix_length_get(unit, data, &pfx);
   1570 
   1571     rv = _tr_ext_lpm_match(unit, data, pfx, &data->defip_index);
   1572     if (BCM_SUCCESS(rv)) {
   1573         /* Entry already present. Update the entry */
   1574         rv = _tr_ext_lpm_write(unit, data, nh_ecmp_idx);
   1575     } else if (rv == BCM_E_NOT_FOUND) {
   1576 
   1577 
   1578         /* Allocate free slot for entry.  */
   1579         rv = _tr_ext_lpm_free_slot_create(unit, v6, pfx,
   1580                                           &data->defip_index);
   1581         if (BCM_SUCCESS(rv)) {
   1582             rv = _tr_ext_lpm_write(unit, data, nh_ecmp_idx);
   1583             if (BCM_SUCCESS(rv)) {
   1584                 rv = _tr_ext_lpm_sw_entry_insert(unit, data); 
   1585             }
   1586             if (BCM_SUCCESS(rv)) {
   1587                 BCM_XGS3_L3_DEFIP_CNT_INC(unit, v6);
   1588             }
   1589         }
   1590     }
   1591     return(rv);
   1592 }
   1593 
   1594 /* 
   1595  * Function:
   1596  *      _bcm_tr_ext_lpm_delete
   1597  * Purpose:
   1598  *      Delete entry matching prefix, vrf in external route table.
   1599  * Parameters:
   1600  *      unit  -     (IN) BCM device number. 
   1601  *      key   -     (IN) Lookup key.   
   1602  * Returns:
   1603  *      BCM_E_XXX
   1604  */
   1605 int
   1606 _bcm_tr_ext_lpm_delete(int unit, _bcm_defip_cfg_t *key)
   1607 {
   1608     int        rv;       /* Operation return status. */
   1609     int        v6;       /* IP protocol version.     */
   1610     int       pfx;       /* VRF weighted prefix length.*/
   1611 
   1612     /* Input parameters sanitcy check */
   1613     if (NULL == key) {
   1614         return (BCM_E_PARAM);
   1615     }
   1616 
   1617     v6 = _TR_LPM_ROUTE_IS_V6(key);
   1618     /* Calculate vrf weighted prefix lengh. */
   1619     _tr_ext_lpm_prefix_length_get(unit, key, &pfx);
   1620 
   1621     rv = _tr_ext_lpm_match(unit, key, pfx, &key->defip_index);
   1622 
   1623     if (BCM_SUCCESS(rv)) {
   1624         _tr_ext_lpm_sw_entry_delete(unit, key);
   1625 
   1626         rv = _tr_ext_lpm_free_slot_delete(unit, v6, pfx, key->defip_index);
   1627 
   1628         if (BCM_SUCCESS(rv)) {
   1629             BCM_XGS3_L3_DEFIP_CNT_DEC(unit, v6);
   1630         }
   1631     }
   1632     return(rv);
   1633 }
   1634 
   1635 /* 
   1636  * Function:
   1637  *      _bcm_tr_ext_lpm_match
   1638  * Purpose:
   1639  *      Find entry matching prefix, vrf in external route table.
   1640  * Parameters:
   1641  *      unit  -     (IN) BCM device number. 
   1642  *      key   -     (IN/OUT) (IN)Lookup key (OUT) Entry data if found.   
   1643  *      index -     (OUT) Next hop index.
   1644  * Returns:
   1645  *      BCM_E_XXX
   1646  */
   1647 int
   1648 _bcm_tr_ext_lpm_match(int unit, _bcm_defip_cfg_t *key, int *next_hop_index) 
   1649 {
   1650     int        rv;       /* Operation return status.   */
   1651     int        v6;       /* IP protocol version.       */
   1652     int     index;       /* Entry index if found.      */
   1653     int       pfx;       /* VRF weighted prefix length.*/
   1654 
   1655 
   1656     /* Input parameters sanitcy check */
   1657     if (NULL == key) {
   1658         return (BCM_E_PARAM);
   1659     }
   1660 
   1661     v6 = _TR_LPM_ROUTE_IS_V6(key);
   1662     /* Calculate vrf weighted prefix lengh. */
   1663     _tr_ext_lpm_prefix_length_get(unit, key, &pfx);
   1664 
   1665     rv = _tr_ext_lpm_match(unit, key, pfx, &index);
   1666     if (BCM_SUCCESS(rv)) {
   1667         rv = _tr_ext_lpm_read_route_data(unit, v6, index, key->defip_sub_len,
   1668                                          key, next_hop_index);
   1669     }
   1670     return(rv);
   1671 }
   1672 
   1673 #ifdef BCM_WARM_BOOT_SUPPORT
   1674 /* 
   1675  * Function:
   1676  *      _tr_ext_lpm_ip6_mask_len
   1677  * Purpose:
   1678  *      Return ipv6 mask length given ipv6 mask.
   1679  * Parameters:
   1680  *      bcm_ip6_t: ip6mask
   1681  * Returns:
   1682  *      int: ipv6 mask length
   1683  */
   1684 STATIC int
   1685 _tr_ext_lpm_ip6_mask_len(bcm_ip6_t ip6mask)
   1686 {
   1687     int idx, tempcount, masklen = 0;
   1688     uint32 maskbits;
   1689     
   1690     for (idx = 0; idx < 16; idx++) {
   1691         maskbits = ip6mask[idx];
   1692         for( tempcount = 0; maskbits; tempcount++) {
   1693             maskbits &= (maskbits - 1);     
   1694         }
   1695         masklen += tempcount;
   1696     }
   1697     return masklen;
   1698 }
   1699 
   1700 /* 
   1701  * Function:
   1702  *      _bcm_tr_ext_lpm_state_recover
   1703  * Purpose:
   1704  *      Reconstruct LPM s/w state from ESM. 
   1705  *      Reconstruct s/w FIB4 and FIB6 state from ESM. 
   1706  * Parameters:
   1707  *      unit  - (IN) BCM device number. 
   1708  *      v6    - Flag to indicate entry is ipv4/ipv6.
   1709  * Returns:
   1710  *      BCM_E_XXX
   1711  */
   1712 STATIC int 
   1713 _bcm_tr_ext_lpm_state_recover(int unit, int v6)
   1714 {
   1715     int       rv, idx;
   1716     int       nh_ecmp_idx, vrf_fld_len;  
   1717     uint32    usage_buf[2];    
   1718     uint32    v4_mask, vrf_fld_mask,  prfx = 0;
   1719     soc_mem_t mem, data_mem, hit_bit_mem;
   1720     uint32    buf[SOC_MAX_MEM_FIELD_WORDS];   
   1721     uint32    data_buf[SOC_MAX_MEM_FIELD_WORDS];   
   1722     bcm_ip6_t v6_64_mask, v6_128_mask;
   1723     ip6_addr_t v6_addr;
   1724     bcm_vrf_t vrf, vrf_hi, vrf_mask, vrf_mask_hi;
   1725     _bcm_defip_cfg_t *lpm_cfg;
   1726 
   1727     lpm_cfg = sal_alloc(sizeof(_bcm_defip_cfg_t), "TR route table");
   1728     if (NULL == lpm_cfg) {
   1729         return (BCM_E_MEMORY);
   1730     }
   1731     sal_memset(lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   1732 
   1733     /* Get table memory. */
   1734     mem = _TR_LPM_MEM(unit, v6);
   1735     data_mem = _TR_LPM_DATA_MEM(unit, v6);
   1736     hit_bit_mem = _TR_LPM_HIT_BIT_MEM(unit, v6);
   1737 
   1738     for (idx = 0; idx < soc_mem_index_count(unit, mem); idx++) {
   1739 
   1740         rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, buf);
   1741         if (!BCM_SUCCESS(rv)) {
   1742             sal_free(lpm_cfg);
   1743             return rv;
   1744         }
   1745         
   1746         if (soc_mem_field32_get(unit, mem, buf, VALIDf) == 0) {
   1747             continue;
   1748         }
   1749         
   1750         if (v6) { /*Ipv6 entries */
   1751 
   1752             if (SOC_MEM_FIELD_VALID(unit, mem, IP_ADDRf)) {
   1753                 /* EXT_IPV6_64_DEFIPm */
   1754                 soc_mem_ip6_addr_get(unit, mem, buf, IP_ADDRf, v6_addr,
   1755                                       SOC_MEM_IP6_UPPER_ONLY); 
   1756                 sal_memcpy(_TR_LPM_FIB6(unit)[idx].addr, v6_addr,
   1757                                          sizeof(ip6_addr_t));
   1758                 bcm_ip6_mask_create(v6_64_mask, 0);
   1759                 soc_mem_ip6_addr_mask_get(unit, mem, buf, MASK_IP_ADDRf,
   1760                                           v6_64_mask, SOC_MEM_IP6_UPPER_ONLY);
   1761                 prfx = _tr_ext_lpm_ip6_mask_len(v6_64_mask);
   1762             } else { /* EXT_IPV6_128_DEFIPm */
   1763                 soc_mem_ip6_addr_get(unit, mem, buf, IP_ADDR_HIf, v6_addr,
   1764                                       SOC_MEM_IP6_UPPER_ONLY); 
   1765                 soc_mem_ip6_addr_get(unit, mem, buf, IP_ADDR_LOf, v6_addr,
   1766                                       SOC_MEM_IP6_LOWER_ONLY); 
   1767                 sal_memcpy(_TR_LPM_FIB6(unit)[idx].addr, v6_addr,
   1768                                          sizeof(ip6_addr_t));
   1769     
   1770                 bcm_ip6_mask_create(v6_128_mask, 0);
   1771                 soc_mem_ip6_addr_mask_get(unit, mem, buf, MASK_IP_ADDR_HIf,
   1772                                           v6_128_mask, SOC_MEM_IP6_UPPER_ONLY);
   1773                 soc_mem_ip6_addr_mask_get(unit, mem, buf, MASK_IP_ADDR_LOf,
   1774                                           v6_128_mask, SOC_MEM_IP6_LOWER_ONLY);
   1775                 prfx = _tr_ext_lpm_ip6_mask_len(v6_128_mask);
   1776             }
   1777         } else { /* Ipv4 entries - EXT_IPV4_DEFIPm */
   1778             
   1779             _TR_LPM_FIB4(unit)[idx].addr = 
   1780                 soc_mem_field32_get(unit, mem, buf, IP_ADDRf);
   1781             v4_mask = soc_mem_field32_get(unit, mem, buf, MASK_IP_ADDRf);
   1782             for( prfx = 0; v4_mask; prfx++) {
   1783                 v4_mask &= (v4_mask - 1);     
   1784             }
   1785             prfx = _TR_LPM_PREFIX_COUNT(mem) - prfx - 1;
   1786         }
   1787 
   1788         /* Common to IPv4 and IPv6 */
   1789         vrf_fld_len = soc_mem_field_length(unit, mem, VRF_LOf);
   1790         vrf_fld_mask = (1 << vrf_fld_len) - 1;        
   1791         vrf = vrf_fld_mask & soc_mem_field32_get(unit, mem, buf, VRF_LOf);
   1792         if (SOC_MEM_FIELD_VALID(unit, mem, VRF_HIf)) {
   1793             vrf_hi = soc_mem_field32_get(unit, mem, buf, VRF_HIf);
   1794             vrf |= vrf_hi << vrf_fld_len;
   1795         }
   1796 
   1797         vrf_mask = vrf_fld_mask & soc_mem_mask_field32_get(unit, mem, buf,
   1798                 MASK_VRF_LOf);
   1799         if (SOC_MEM_FIELD_VALID(unit, mem, VRF_HIf)) {
   1800             vrf_mask_hi = soc_mem_field32_get(unit, mem, buf, 
   1801                     MASK_VRF_HIf);
   1802             vrf_mask |= vrf_mask_hi << vrf_fld_len;
   1803         }
   1804 
   1805 
   1806         if (v6) { 
   1807             _TR_LPM_FIB6(unit)[idx].vrf = bcm_ext_lpm_vrf_get( unit, vrf,
   1808                     vrf_mask, soc_mem_field32_get(unit, mem, buf, 
   1809                         GLOBAL_ROUTEf));
   1810         } else {
   1811             _TR_LPM_FIB4(unit)[idx].vrf = bcm_ext_lpm_vrf_get( unit, vrf,
   1812                     vrf_mask, soc_mem_field32_get(unit, mem, buf, 
   1813                         GLOBAL_ROUTEf));
   1814         }
   1815 
   1816         rv = soc_mem_read(unit, data_mem, MEM_BLOCK_ANY, idx, data_buf);
   1817         if (!BCM_SUCCESS(rv)) {
   1818             sal_free(lpm_cfg);
   1819             return rv;
   1820         }
   1821         
   1822         rv = soc_mem_read(unit, hit_bit_mem, MEM_BLOCK_ANY,
   1823                                          (idx >> 5), usage_buf);
   1824         if (!BCM_SUCCESS(rv)) {
   1825             sal_free(lpm_cfg);
   1826             return rv;
   1827         }
   1828 
   1829         _tr_ext_lpm_parse_route_data(unit, v6, idx, prfx, data_buf,
   1830                                        usage_buf, lpm_cfg, &nh_ecmp_idx);
   1831         _tr_ext_lpm_sw_entry_insert(unit, lpm_cfg);
   1832         _bcm_tr_ext_lpm_reinit(unit, mem, idx, lpm_cfg);
   1833     }
   1834 
   1835     _bcm_tr_ext_lpm_reinit_done(unit, mem);
   1836 
   1837     sal_free(lpm_cfg);
   1838     return BCM_E_NONE;
   1839 }
   1840 #endif /* BCM_WARM_BOOT_SUPPORT */
   1841 
   1842 /*
   1843  * Function:
   1844  *      _bcm_tr_ext_defip_traverse
   1845  * Purpose:
   1846  *      Traverse all LPM entries, call back the test
   1847  *      function and save entries which pass.  After a configuration number
   1848  *      of entries are saved, call back the operation function on each.
   1849  *      Repeat from beginning of table after operations are complete.
   1850  *      Continue until the no entries test TRUE.
   1851  * Parameters:
   1852  *      unit      - BCM device number.
   1853  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
   1854  * Notes:
   1855  *      The test function must not perform any changes to the
   1856  *      table.  Also, it must know how to exclude entries which have
   1857  *      already been processed by the operation function.  Otherwise, the
   1858  *      loop may never terminate.
   1859  *      The operation function may update the table.
   1860  *      We require to pass table index so caller can acccess entry hit 
   1861  *      information for traverse & aging functionalities.
   1862  *      Table index is not available during op callback and should be ignored.
   1863  */
   1864 int
   1865 _bcm_tr_defip_traverse(int unit, _bcm_l3_trvrs_data_t *trv_data)
   1866 {
   1867     _bcm_defip_cfg_t *search_data_array;
   1868     int              *nh_array;
   1869     uint32           *lpm_data;
   1870     uint32           *usage_data;
   1871     int              dma_start;
   1872     int              alloc_sz;
   1873     char             *dma_ptr;
   1874     char             *usage_dma_ptr;
   1875     int              dma_end;
   1876     int              idx;
   1877     soc_mem_t        mem;
   1878     int              curr_pfx;
   1879     int              v6;
   1880     int              array_index;
   1881     int              rv=SOC_E_NONE;
   1882     int              cmp_result = BCM_L3_CMP_NOT_EQUAL; 
   1883 
   1884 
   1885     v6 = (trv_data->flags & BCM_L3_IP6) ? 1 : 0 ;
   1886 
   1887     alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(_bcm_defip_cfg_t);
   1888     search_data_array = sal_alloc(alloc_sz, "TR route table");
   1889     if (NULL == search_data_array) {
   1890         return (BCM_E_MEMORY);
   1891     }
   1892     sal_memset(search_data_array, 0, alloc_sz);
   1893 
   1894     alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(int);
   1895     nh_array = sal_alloc(alloc_sz, "TR route table");
   1896     if (NULL == nh_array) {
   1897         sal_free(search_data_array);
   1898         return (BCM_E_MEMORY);
   1899     }
   1900     sal_memset(nh_array, 0, alloc_sz);
   1901 
   1902     alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(ext_defip_data_entry_t);
   1903     dma_ptr = soc_cm_salloc(unit, alloc_sz, "TR route table dma");
   1904     if (NULL == dma_ptr) {
   1905         sal_free(nh_array);
   1906         sal_free(search_data_array);
   1907         return (BCM_E_MEMORY);
   1908     }
   1909 
   1910     alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(ext_dst_hit_bits_entry_t);
   1911     usage_dma_ptr = soc_cm_salloc(unit, alloc_sz, "TR route table hit bits");
   1912     if (NULL == usage_dma_ptr) {
   1913         sal_free(nh_array);
   1914         sal_free(search_data_array);
   1915         soc_cm_sfree(unit, dma_ptr);
   1916         return (BCM_E_MEMORY);
   1917     }
   1918 
   1919     /* Get table memory. */
   1920     mem = _TR_LPM_MEM(unit, v6);
   1921 
   1922 #ifdef BCM_WARM_BOOT_SUPPORT
   1923     /* Reconstruct EXT LPM s/w state */
   1924     if (SOC_WARM_BOOT(unit)) {
   1925         _bcm_tr_ext_lpm_state_recover(unit, v6);
   1926     }
   1927 #endif /* BCM_WARM_BOOT_SUPPORT */
   1928 
   1929     while (1) {
   1930         array_index = 0;
   1931         curr_pfx = _TR_LPM_PREFIX_MAX_INDEX(mem);
   1932 
   1933         /* Iterate over prefixes to fill search data. */
   1934         while (curr_pfx != -1) {
   1935 
   1936             /* Skip empty prefixes. */
   1937             if (0 == _TR_LPM_STATE_VENT(unit, v6, curr_pfx)) {
   1938                 curr_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx);
   1939                 continue;
   1940             }
   1941 
   1942             /* Read entries for current prefix. */
   1943             for(dma_start = _TR_LPM_STATE_START(unit, v6, curr_pfx);
   1944                 dma_start <= _TR_LPM_STATE_END(unit, v6, curr_pfx);
   1945                 dma_start += _TR_LPM_BLOCK_SZ) {
   1946 
   1947                 dma_end = dma_start + _TR_LPM_BLOCK_SZ - 1;
   1948                 if (dma_end > _TR_LPM_STATE_END(unit, v6, curr_pfx)) {
   1949                     dma_end = _TR_LPM_STATE_END(unit, v6, curr_pfx);
   1950                 }
   1951                 rv = soc_mem_read_range(unit, _TR_LPM_DATA_MEM(unit, v6),
   1952                                         MEM_BLOCK_ANY, dma_start, dma_end,
   1953                                         dma_ptr);
   1954                 if (rv < 0) {  
   1955                     soc_cm_sfree(unit, dma_ptr);
   1956                     soc_cm_sfree(unit, usage_dma_ptr);
   1957                     sal_free(search_data_array);
   1958                     sal_free(nh_array);
   1959                     return (rv);
   1960                 }
   1961 
   1962                 rv = soc_mem_read_range(unit, _TR_LPM_HIT_BIT_MEM(unit, v6),
   1963                                         MEM_BLOCK_ANY, (dma_start >> 5),
   1964                                         (dma_end >> 5), usage_dma_ptr);
   1965                 if (BCM_FAILURE(rv)) {  
   1966                     soc_cm_sfree(unit, dma_ptr);
   1967                     soc_cm_sfree(unit, usage_dma_ptr);
   1968                     sal_free(search_data_array);
   1969                     sal_free(nh_array);
   1970                     return (rv);
   1971                 }
   1972 
   1973                 for(idx = (dma_end - dma_start); idx >= 0; idx--) {
   1974                     /* Calculate entry offset. */
   1975                     lpm_data = soc_mem_table_idx_to_pointer
   1976                         (unit, _TR_LPM_DATA_MEM(unit, v6),
   1977                          uint32 *, dma_ptr, idx);
   1978 
   1979                     /* Calculate hit bit entry offset. */
   1980                     usage_data = soc_mem_table_idx_to_pointer
   1981                         (unit, _TR_LPM_HIT_BIT_MEM(unit, v6),
   1982                          uint32 *, usage_dma_ptr, (idx >> 5));
   1983 
   1984                     /* Parse route entry. */
   1985                     _tr_ext_lpm_parse_route_data(unit, v6, 
   1986                                                  dma_start +  idx,
   1987                                                  (curr_pfx % _TR_LPM_PREFIX_COUNT(mem)),
   1988                                                  lpm_data, usage_data,
   1989                                                  (search_data_array + array_index), 
   1990                                                  (nh_array + array_index));
   1991 
   1992                     /* Execute test routine if any. */
   1993                     if (NULL != trv_data->cmp_cb) {
   1994                         rv = (*trv_data->cmp_cb) (unit, (void *)trv_data,
   1995                                                   (void *)(search_data_array + array_index),
   1996                                                   (void *)(nh_array + array_index),
   1997                                                   &cmp_result);
   1998                         if (BCM_FAILURE(rv)) {
   1999                             soc_cm_sfree(unit, dma_ptr);
   2000                             soc_cm_sfree(unit, usage_dma_ptr);
   2001                             sal_free(nh_array);
   2002                             sal_free(search_data_array);
   2003                             return rv;
   2004                         }
   2005                     } 
   2006 
   2007                     if ((BCM_L3_CMP_EQUAL == cmp_result) ||
   2008                         (NULL == trv_data->cmp_cb)) {
   2009                         array_index++;
   2010                         if (array_index >= _TR_LPM_BLOCK_SZ) {
   2011                             break;
   2012                         }
   2013                     }
   2014                 }
   2015                 if (array_index >= _TR_LPM_BLOCK_SZ) {
   2016                     break;
   2017                 }
   2018             }
   2019             if (array_index >= _TR_LPM_BLOCK_SZ) {
   2020                 break;
   2021             }
   2022             curr_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx);
   2023         }
   2024 
   2025         for (idx = 0; idx < array_index; idx++) {
   2026             /* Execute operation routine if any. */
   2027             if (NULL != trv_data->op_cb) {
   2028                 rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   2029                                          (void *)(search_data_array + idx),
   2030                                          (void *)(nh_array + idx), &cmp_result);
   2031                 if (rv < 0) {
   2032                     soc_cm_sfree(unit, dma_ptr);
   2033                     soc_cm_sfree(unit, usage_dma_ptr);
   2034                     sal_free(nh_array);
   2035                     sal_free(search_data_array);
   2036                     return (rv);
   2037                 }
   2038             }
   2039         }
   2040 
   2041         if (0 == array_index) {
   2042             break;
   2043         }
   2044     }
   2045 
   2046     soc_cm_sfree(unit, dma_ptr);
   2047     soc_cm_sfree(unit, usage_dma_ptr);
   2048     sal_free(search_data_array);
   2049     sal_free(nh_array);
   2050     return (rv);
   2051 }
   2052 
   2053 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   2054 /*
   2055  * Function:
   2056  *     tr_ext_lpm_sw_dump
   2057  * Purpose:
   2058  *     Displays ESM LPM information maintained by software.
   2059  * Parameters:
   2060  *     unit - Device unit number
   2061  * Returns:
   2062  *     None
   2063  */
   2064 void
   2065 _bcm_tr_ext_lpm_sw_dump(int unit)
   2066 {
   2067     soc_mem_t           mem;
   2068     int                 i;
   2069     _tr_lpm_sw_image_p v4, v6;
   2070   
   2071     v4 = _TR_LPM_SW_IMAGE(unit, _TR_LPM_IPV4);
   2072     v6 = _TR_LPM_SW_IMAGE(unit, _TR_LPM_IPV6);
   2073 
   2074     LOG_CLI((BSL_META_U(unit,
   2075                         "\n TRIUMPH External LPM State -\n")));
   2076     if ((NULL == v4) && (NULL == v6)) {
   2077         LOG_CLI((BSL_META_U(unit,
   2078                             " ESM not present!\n")));
   2079         return;
   2080     }
   2081 
   2082     if (NULL != v4) {
   2083         LOG_CLI((BSL_META_U(unit,
   2084                             "  IPv4 Prefix entries:\n")));
   2085         mem = _TR_LPM_MEM(unit, _TR_LPM_IPV4);
   2086 
   2087         for (i = 0; i <  _TR_LPM_PREFIX_MAX(mem); i++) {
   2088             if (_TR_LPM_STATE_VENT(unit, _TR_LPM_IPV4, i) != 0) {
   2089                 LOG_CLI((BSL_META_U(unit,
   2090                                     "   Prefix length (bits): %d\n"),
   2091                          (i%_TR_LPM_PREFIX_COUNT(mem))));
   2092                 LOG_CLI((BSL_META_U(unit,
   2093                                     "    Start : %d\n"),  
   2094                          _TR_LPM_STATE_START(unit, _TR_LPM_IPV4, i)));
   2095                 LOG_CLI((BSL_META_U(unit,
   2096                                     "    End   : %d\n"),  
   2097                          _TR_LPM_STATE_END(unit, _TR_LPM_IPV4, i)));
   2098                 LOG_CLI((BSL_META_U(unit,
   2099                                     "    Prev  : %d\n"), 
   2100                          _TR_LPM_STATE_PREV(unit, _TR_LPM_IPV4, i)));
   2101                 LOG_CLI((BSL_META_U(unit,
   2102                                     "    Next  : %d\n"), 
   2103                          _TR_LPM_STATE_NEXT(unit, _TR_LPM_IPV4, i)));
   2104                 LOG_CLI((BSL_META_U(unit,
   2105                                     "    Valid Entries : %d\n"), 
   2106                          _TR_LPM_STATE_VENT(unit, _TR_LPM_IPV4, i)));
   2107                 LOG_CLI((BSL_META_U(unit,
   2108                                     "    Free  Entries : %d\n"), 
   2109                          _TR_LPM_STATE_FENT(unit, _TR_LPM_IPV4, i)));
   2110             }
   2111         }
   2112     }
   2113 
   2114     if (NULL != v6) {
   2115         LOG_CLI((BSL_META_U(unit,
   2116                             "\n  IPv6 Prefix entries: \n" )));
   2117         mem = _TR_LPM_MEM(unit, _TR_LPM_IPV6);
   2118                
   2119         for (i = 0; i <  _TR_LPM_PREFIX_MAX(mem); i++) {
   2120             if (_TR_LPM_STATE_VENT(unit, _TR_LPM_IPV6, i) != 0) {
   2121                 LOG_CLI((BSL_META_U(unit,
   2122                                     "   Prefix length (bits): %d\n"),
   2123                          (i%_TR_LPM_PREFIX_COUNT(mem))));
   2124                 LOG_CLI((BSL_META_U(unit,
   2125                                     "    Start : %d\n"),  
   2126                          _TR_LPM_STATE_START(unit, _TR_LPM_IPV6, i)));
   2127                 LOG_CLI((BSL_META_U(unit,
   2128                                     "    End   : %d\n"),  
   2129                          _TR_LPM_STATE_END(unit, _TR_LPM_IPV6, i)));
   2130                 LOG_CLI((BSL_META_U(unit,
   2131                                     "    Prev  : %d\n"), 
   2132                          _TR_LPM_STATE_PREV(unit, _TR_LPM_IPV6, i)));
   2133                 LOG_CLI((BSL_META_U(unit,
   2134                                     "    Next  : %d\n"), 
   2135                          _TR_LPM_STATE_NEXT(unit, _TR_LPM_IPV6, i)));
   2136                 LOG_CLI((BSL_META_U(unit,
   2137                                     "    Valid Entries : %d\n"), 
   2138                          _TR_LPM_STATE_VENT(unit, _TR_LPM_IPV6, i)));
   2139                 LOG_CLI((BSL_META_U(unit,
   2140                                     "    Free  Entries : %d\n"), 
   2141                          _TR_LPM_STATE_FENT(unit, _TR_LPM_IPV6, i)));
   2142             }
   2143         }
   2144     }
   2145     return;
   2146 }
   2147 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
   2148 
   2149 
   2150 
   2151 #else /* BCM_TRIUMPH_SUPPORT && INCLUDE_L3 */
   2152 int bcm_esw_triumph_external_lpm_not_empty;
   2153 #endif /* BCM_TRIUMPH_SUPPORT && INCLUDE_L3 */
   2154