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 (66794B)


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