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

nat.c (153043B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * NAT - Broadcom StrataSwitch NAT API.
      8  */
      9 
     10 #include <sal/core/libc.h>
     11 #include <soc/defs.h>
     12 #if defined(INCLUDE_L3) 
     13 
     14 #include <soc/drv.h>
     15 #include <bcm/error.h>
     16 
     17 #include <bcm/l3.h>
     18 #include <bcm/nat.h>
     19 #include <bcm/tunnel.h>
     20 #include <bcm/debug.h>
     21 #include <bcm/error.h>
     22 
     23 #include <bcm_int/esw/firebolt.h>
     24 #include <bcm_int/esw/trident2.h>
     25 #include <bcm_int/esw/flex_ctr.h>
     26 #include <bcm_int/esw_dispatch.h>
     27 #include <bcm_int/esw/nat.h>
     28 #include <bcm_int/esw/trx.h>
     29 
     30 #include <soc/mem.h>
     31 #include <soc/profile_mem.h>
     32 #include <soc/debug.h>
     33 #include <soc/drv.h>
     34 #include <soc/trident2.h>
     35 #include <soc/trident3.h>
     36 #ifdef BCM_TRIDENT3_SUPPORT
     37 #include <soc/esw/cancun.h>
     38 #include <soc/esw/cancun_enums.h>
     39 #endif /* BCM_TRIDENT3_SUPPORT */
     40 
     41 _bcm_l3_nat_state_t *_bcm_l3_nat_state[BCM_MAX_NUM_UNITS];
     42 
     43 #define BCM_NAT_EGRESS_ID_MIN(unit) (SOC_IS_TRIDENT3X(unit) ? 1 : 0)
     44 
     45 #ifdef BCM_TRIDENT2_SUPPORT
     46 int 
     47 _bcm_esw_l3_nat_lock(int unit)
     48 {
     49     if (NULL != _bcm_l3_nat_state[unit]->lock) {
     50         return sal_mutex_take(_bcm_l3_nat_state[unit]->lock, 
     51                               sal_mutex_FOREVER);
     52     }
     53     return (BCM_E_NONE);
     54 }
     55 
     56 int 
     57 _bcm_esw_l3_nat_unlock(int unit)
     58 {
     59     if (NULL != _bcm_l3_nat_state[unit]->lock) {
     60         return sal_mutex_give(_bcm_l3_nat_state[unit]->lock);
     61     }
     62     return (BCM_E_NONE);
     63 }
     64 #endif /* BCM_TRIDENT2_SUPPORT */
     65 
     66 #ifdef BCM_TRIDENT2_SUPPORT
     67 /* DMA one of the memories specified by mem */
     68 int
     69 _bcm_td2_l3_nat_read_mem(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz,
     70                          char *descr, char **res_ptr, int *entry_count)
     71 {
     72     int alloc_size;
     73     char *buffer;
     74     int tbl_size;
     75 
     76     /* Input parameters sanity check. */
     77     if ((NULL == res_ptr) || (NULL == descr)) {
     78         return (BCM_E_PARAM);
     79     }
     80 
     81     /* If entry size is not deterministic. reject. */
     82 #if 0
     83     if (tbl_entry_sz == BCM_XGS3_L3_INVALID_ENT_SZ) {
     84         return (BCM_E_UNAVAIL);
     85     }
     86 #endif
     87 
     88     if (INVALIDm == tbl_mem) {
     89         return (BCM_E_NOT_FOUND);
     90     }
     91 
     92     /* Calculate table size. */
     93     tbl_size =  soc_mem_index_count(unit, tbl_mem);
     94     if (!tbl_size) {
     95         return (BCM_E_NOT_FOUND);
     96     } else if (NULL != entry_count) {
     97         *entry_count = tbl_size;
     98     }
     99     alloc_size = tbl_entry_sz * tbl_size;
    100 
    101     /* Allocate memory buffer. */
    102     buffer = soc_cm_salloc(unit, alloc_size, descr);
    103     if (buffer == NULL) {
    104         return (BCM_E_MEMORY);
    105     }
    106 
    107     /* Reset allocated buffer. */
    108     sal_memset(buffer, 0, alloc_size);
    109 
    110     /* Read table to the buffer. */
    111     if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY,
    112                            soc_mem_index_min(unit, tbl_mem),
    113                            soc_mem_index_max(unit, tbl_mem), buffer) < 0) {
    114         soc_cm_sfree(unit, buffer);
    115         return (BCM_E_INTERNAL);
    116     }
    117 
    118     *res_ptr = buffer;
    119     return (BCM_E_NONE);
    120 }
    121 
    122 #ifdef BCM_WARM_BOOT_SUPPORT
    123 
    124 STATIC int 
    125 _bcm_td2_l3_nat_warmboot_tblcnt_update(int unit, int idx,
    126                                        bcm_l3_nat_ingress_t *nat_info,
    127                                        void *user_data)
    128 {
    129     int tbl;
    130     soc_mem_t mem;
    131     bcm_l3_nat_ingress_cb_context_t *user_context;
    132     user_context = (bcm_l3_nat_ingress_cb_context_t *) user_data;
    133     mem = user_context->mem;
    134 
    135     switch (mem) {
    136       case L3_ENTRY_IPV4_MULTICASTm:
    137 #ifdef BCM_TRIDENT3_SUPPORT
    138       case L3_ENTRY_DOUBLEm:
    139 #endif 
    140         tbl = BCM_L3_NAT_INGRESS_DNAT_CNT;
    141         break;
    142       case ING_SNATm:
    143         tbl = BCM_L3_NAT_INGRESS_SNAT_CNT;
    144         break;
    145       case ING_DNAT_ADDRESS_TYPEm:
    146         tbl = BCM_L3_NAT_INGRESS_POOL_CNT;
    147         break;
    148       default :
    149         tbl = BCM_L3_NAT_INGRESS_DNAT_CNT;
    150         break;
    151     }
    152     BCM_L3_NAT_INGRESS_INFO((unit)).tbl_cnts[(tbl)]++;
    153 
    154     return BCM_E_NONE;
    155 }
    156 
    157 /*
    158  * Function:
    159  *      _bcm_esw_nat_reinit
    160  * Purpose:
    161  *      Warm boot recovery for the NAT module
    162  * Parameters:
    163  *      unit     - Device Number
    164  * Returns:
    165  *      BCM_E_XXX
    166  */
    167 STATIC int 
    168 _bcm_esw_nat_reinit(int unit)
    169 {
    170     soc_mem_t mem;
    171     bcm_l3_nat_ingress_cb_context_t user_context;
    172     int tbl, i, idx_min, idx_max;
    173     uint32 key_type, valid0, valid1, flags, egr_nat_id;
    174     soc_field_t egr_nat_validf[2] = {VALIDf, VALID_0f}, key_typef = KEY_TYPE_0f;
    175     soc_mem_t egr_nat_tbl[2] = {ING_SNATm, L3_ENTRY_IPV4_MULTICASTm};
    176     soc_field_t egr_nat_idxf[2] = {NAT_PACKET_EDIT_IDXf, NAT__PACKET_EDIT_IDXf};
    177     soc_field_t egr_nat_self_idxf[2] = {NAT_PACKET_EDIT_ENTRY_SELf,
    178                                         NAT__PACKET_EDIT_ENTRY_SELf};
    179     char   *ing_snat_tbl_ptr   = NULL;
    180     char   *nat_tbl_ptr        = NULL;
    181     uint32 *pkt_edit_entry_ptr = NULL;
    182     int     rv                 = BCM_E_NONE;
    183     uint32  *egr_nat_entry     = NULL;
    184     char   *egr_nh_buf         = NULL;
    185 #ifdef BCM_MONTEREY_SUPPORT
    186     char   *ing_dnat_address_type_tbl_ptr   = NULL;
    187     if (SOC_IS_MONTEREY(unit)) {
    188         rv = _bcm_td2_l3_nat_read_mem(unit, ING_DNAT_ADDRESS_TYPEm,
    189                 sizeof(ing_dnat_address_type_entry_t),
    190                 "ing_dnat_address_type_tbl", &ing_dnat_address_type_tbl_ptr, NULL);
    191         if (BCM_FAILURE(rv)) {
    192             goto cleanup;
    193         }
    194     }
    195 #endif
    196     rv = _bcm_td2_l3_nat_read_mem(unit, ING_SNATm,
    197                                   sizeof(ing_snat_entry_t),
    198                                   "ing_snat_tbl", &ing_snat_tbl_ptr, NULL);
    199     if (BCM_FAILURE(rv)) {
    200         goto cleanup;
    201     }
    202 
    203     if (SOC_IS_TRIDENT3X(unit)) {
    204         rv = _bcm_td2_l3_nat_read_mem(unit, L3_ENTRY_DOUBLEm,
    205                                       sizeof(l3_entry_double_entry_t),
    206                                       "nat_tbl", &nat_tbl_ptr, NULL);
    207     } else {
    208         rv = _bcm_td2_l3_nat_read_mem(unit, L3_ENTRY_IPV4_MULTICASTm,
    209                                       sizeof(l3_entry_ipv4_multicast_entry_t),
    210                                       "nat_tbl", &nat_tbl_ptr, NULL);
    211     }
    212 
    213     if (BCM_FAILURE(rv)) {
    214         goto cleanup;
    215     }
    216 
    217     if (SOC_IS_TRIDENT3X(unit)) {
    218         egr_nat_tbl[1] = L3_ENTRY_DOUBLEm;
    219         egr_nat_validf[1] = BASE_VALID_0f;
    220         key_typef = KEY_TYPEf;
    221     }
    222 
    223     /* Recover egress nat state */
    224     for (tbl = 0; tbl < 2; tbl++) {
    225         idx_min = BCM_NAT_EGRESS_ID_MIN(unit);
    226         idx_max = soc_mem_index_max(unit, egr_nat_tbl[tbl]);
    227 
    228         for (i = idx_min; i <= idx_max; i++) {
    229             if (0 == tbl) {
    230                 egr_nat_entry =
    231                     soc_mem_table_idx_to_pointer(unit, egr_nat_tbl[tbl],
    232                                                  uint32 *,
    233                                                  ing_snat_tbl_ptr, i);
    234             } else {
    235                 egr_nat_entry =
    236                     soc_mem_table_idx_to_pointer(unit, egr_nat_tbl[tbl],
    237                                                  uint32 *, nat_tbl_ptr, i);
    238 
    239             }
    240             if (soc_mem_field32_get(unit, egr_nat_tbl[tbl],
    241                 egr_nat_entry, egr_nat_validf[tbl]) == 0) {
    242                 continue;
    243             }
    244 
    245             if (tbl) {
    246                 key_type = soc_mem_field32_get(unit, egr_nat_tbl[tbl],
    247                            egr_nat_entry, key_typef);
    248                 if ((key_type != 18) && (key_type != 19)) {
    249                     continue; /* Not NAT entry */
    250                 }
    251             }
    252 
    253             egr_nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET(
    254                              soc_mem_field32_get(unit, egr_nat_tbl[tbl],
    255                              egr_nat_entry, egr_nat_idxf[tbl]),
    256                              soc_mem_field32_get(unit, egr_nat_tbl[tbl],
    257                              egr_nat_entry, egr_nat_self_idxf[tbl]));
    258             BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, egr_nat_id, 1);
    259         }
    260     }
    261 
    262     if (nat_tbl_ptr) {
    263         soc_cm_sfree(unit, nat_tbl_ptr);
    264         nat_tbl_ptr = NULL;
    265     }
    266 
    267     mem = EGR_NAT_PACKET_EDIT_INFOm ;
    268     idx_min = BCM_NAT_EGRESS_ID_MIN(unit);
    269     idx_max = soc_mem_index_max(unit, mem);
    270     rv = _bcm_td2_l3_nat_read_mem(unit, mem,
    271                                   sizeof(egr_nat_packet_edit_info_entry_t),
    272                                   "nat_tbl", &nat_tbl_ptr, NULL);
    273     if (BCM_FAILURE(rv)) {
    274         goto cleanup;
    275     }
    276 
    277     for (i = idx_min; i <= idx_max; i++) {
    278 
    279         pkt_edit_entry_ptr =
    280             soc_mem_table_idx_to_pointer(unit, mem, uint32 *,
    281                                          nat_tbl_ptr, i);
    282 
    283         valid0 = soc_mem_field32_get(unit, mem, pkt_edit_entry_ptr, VALID_0f);
    284         valid1 = soc_mem_field32_get(unit, mem, pkt_edit_entry_ptr, VALID_1f);
    285 
    286         if (!(valid0 || valid1)) {
    287             continue;
    288         }
    289         
    290         if (valid0) {
    291             SHR_BITSET(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap,
    292             (i << 1));
    293             egr_nat_id = (i << 1);
    294             BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, egr_nat_id, 1);
    295         }
    296 
    297         if (valid1) {
    298             SHR_BITSET(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap,
    299             ((i << 1) + 1));
    300             egr_nat_id = ((i << 1) + 1);
    301             BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, egr_nat_id, 1);
    302         }
    303     }
    304 
    305     /* Recover ingress nat state */
    306     if (SOC_IS_TRIDENT3X(unit)) {
    307         mem = L3_ENTRY_DOUBLEm;
    308     } else {
    309         mem = L3_ENTRY_IPV4_MULTICASTm;
    310     }
    311     flags = BCM_L3_NAT_INGRESS_DNAT;
    312     user_context.mem = mem;
    313 
    314     rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, soc_mem_index_min(unit, mem),
    315                                      soc_mem_index_max(unit, mem),
    316                                      _bcm_td2_l3_nat_warmboot_tblcnt_update,
    317                                      (void *) &user_context);
    318     if (BCM_FAILURE(rv)) {
    319         goto cleanup;
    320     }
    321     mem = ING_DNAT_ADDRESS_TYPEm;
    322     flags = BCM_L3_NAT_INGRESS_DNAT | BCM_L3_NAT_INGRESS_DNAT_POOL;
    323     user_context.mem = mem;
    324     
    325     rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, soc_mem_index_min(unit, mem),
    326                                      soc_mem_index_max(unit, mem), 
    327                                      _bcm_td2_l3_nat_warmboot_tblcnt_update,
    328                                      (void *) &user_context);
    329     if (BCM_FAILURE(rv)) {
    330         goto cleanup;
    331     }
    332 
    333 #ifdef BCM_MONTEREY_SUPPORT
    334     if (SOC_IS_MONTEREY(unit)) {
    335         idx_min = soc_mem_index_min(unit, ING_DNAT_ADDRESS_TYPEm);
    336         idx_max = soc_mem_index_max(unit, ING_DNAT_ADDRESS_TYPEm);
    337         for (i = idx_min; i <= idx_max; i++) {
    338             egr_nat_entry =
    339                 soc_mem_table_idx_to_pointer(unit, ING_DNAT_ADDRESS_TYPEm,
    340                         uint32 *, ing_dnat_address_type_tbl_ptr, i);
    341             if (soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, egr_nat_entry, VALIDf) == 0) {
    342                 BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) = i;
    343                 break;
    344             }
    345         }
    346         if (i > idx_max) {
    347             BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) = i;
    348         }
    349     }
    350 #endif
    351     mem = ING_SNATm;
    352     flags = 0;
    353     user_context.mem = mem;
    354 
    355     rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, BCM_NAT_EGRESS_ID_MIN(unit),
    356                                      soc_mem_index_max(unit, mem),
    357                                      _bcm_td2_l3_nat_warmboot_tblcnt_update,
    358                                      (void *) &user_context);
    359     if (BCM_FAILURE(rv)) {
    360         goto cleanup;
    361     }
    362 
    363     idx_min = BCM_NAT_EGRESS_ID_MIN(unit);
    364     idx_max = soc_mem_index_max(unit, ING_SNATm);
    365     for (i = idx_min; i <= idx_max; i++) {
    366         egr_nat_entry =
    367             soc_mem_table_idx_to_pointer(unit, ING_SNATm,
    368                                          uint32 *, ing_snat_tbl_ptr, i);
    369         if (soc_ING_SNATm_field32_get(unit, egr_nat_entry, VALIDf) == 0) {
    370             BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) = i;
    371             break;
    372         }
    373     }
    374 
    375     for (i = idx_max; i >= idx_min; i--) {
    376         egr_nat_entry =
    377             soc_mem_table_idx_to_pointer(unit, ING_SNATm, uint32 *,
    378                                          ing_snat_tbl_ptr, i);
    379         if (soc_ING_SNATm_field32_get(unit, egr_nat_entry, VALIDf) == 0) {
    380             BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) = i;
    381             break;
    382         }
    383     }
    384 #if defined(BCM_TRIDENT3_SUPPORT)
    385     if (soc_feature(unit, soc_feature_large_scale_nat)) {
    386         /* recover mac-da profile reference count from EGR NH table */
    387         int i, index_min, index_max;
    388         uint32 entry_type = 0;
    389         egr_l3_next_hop_entry_t *egr_nh_entry;
    390 
    391         egr_nh_buf = soc_cm_salloc(unit,
    392                 SOC_MEM_TABLE_BYTES(unit, EGR_L3_NEXT_HOPm), "Egr Next Hop buffer");
    393 
    394         if (NULL == egr_nh_buf) {
    395             rv = BCM_E_MEMORY;
    396             goto cleanup;
    397         }
    398         index_min = soc_mem_index_min(unit, EGR_L3_NEXT_HOPm);
    399         index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOPm);
    400         rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    401                 index_min, index_max, egr_nh_buf);
    402 
    403         if (SOC_FAILURE(rv)) {
    404             goto cleanup;
    405         }
    406 
    407         for (i = index_min; i <= index_max; i++) {
    408             egr_nh_entry = soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm,
    409                     egr_l3_next_hop_entry_t *, egr_nh_buf, i);
    410 
    411             /* Check entry type */
    412             entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
    413                     DATA_TYPEf);
    414 
    415             if ((entry_type == 7) &&    /* IPMC */
    416                 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh_entry,
    417                 L3MC__USE_MAC_DA_PROFILEf)) {
    418                 uint32 macda_idx;
    419                 macda_idx = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh_entry,
    420                     L3MC__MAC_DA_PROFILE_INDEXf);
    421 
    422                 _bcm_common_profile_mem_ref_cnt_update(
    423                     unit, EGR_MAC_DA_PROFILEm, macda_idx, 1);
    424             }
    425         }
    426     }
    427 #endif
    428 cleanup:
    429     if (ing_snat_tbl_ptr) {
    430         soc_cm_sfree(unit, ing_snat_tbl_ptr);
    431     }
    432     if (nat_tbl_ptr) {
    433         soc_cm_sfree(unit, nat_tbl_ptr);
    434     }
    435     if (egr_nh_buf) {
    436         soc_cm_sfree(unit, egr_nh_buf);
    437     }
    438 #ifdef BCM_MONTEREY_SUPPORT
    439     if (SOC_IS_MONTEREY(unit)) {
    440         if (ing_dnat_address_type_tbl_ptr) {
    441             soc_cm_sfree(unit, ing_dnat_address_type_tbl_ptr);
    442         }
    443     }
    444 #endif
    445     return rv;
    446 }
    447 #endif /* BCM_WARM_BOOT_SUPPORT */
    448 
    449 /*
    450  * Function:
    451  *      _bcm_esw_l3_nat_free_resource
    452  * Purpose:
    453  *      Free all allocated software resources
    454  * Parameters:
    455  *      unit - SOC unit number
    456  * Returns:
    457  *      Nothing
    458  */
    459 void
    460 _bcm_esw_l3_nat_free_resource(int unit) 
    461 {
    462     if (soc_feature(unit, soc_feature_nat)) {
    463         if (_bcm_l3_nat_state[unit] != NULL) {
    464             if (BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap != NULL) {
    465                 sal_free(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap);
    466                 BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap = NULL;
    467             }
    468         
    469             if (_bcm_l3_nat_state[unit]->lock != NULL) {
    470                 sal_mutex_destroy(_bcm_l3_nat_state[unit]->lock);
    471                 _bcm_l3_nat_state[unit]->lock = NULL;
    472             }
    473             sal_free(_bcm_l3_nat_state[unit]);
    474             _bcm_l3_nat_state[unit] = NULL;
    475         }
    476     }
    477 }
    478 
    479 int
    480 _bcm_esw_l3_nat_init(int unit) 
    481 {
    482     int rv = BCM_E_UNAVAIL;
    483 
    484     if (soc_feature(unit, soc_feature_nat)) {
    485         int mem_sz;
    486         int refcount_sz = 0;
    487 
    488         /* allocate ingress and egress state */
    489         if (NULL == _bcm_l3_nat_state[unit]) {
    490             _bcm_l3_nat_state[unit] = sal_alloc(sizeof(_bcm_l3_nat_state_t), 
    491                                             "nat_state");
    492             
    493             if (NULL == _bcm_l3_nat_state[unit]) {
    494                 return BCM_E_RESOURCE;
    495             } 
    496             sal_memset(_bcm_l3_nat_state[unit], 0, sizeof(_bcm_l3_nat_state_t));
    497         }
    498 
    499         /* initialize nat_id bitmap, nat_id_refcount */
    500         mem_sz = SHR_BITALLOCSIZE(soc_mem_index_count(unit, 
    501                                              EGR_NAT_PACKET_EDIT_INFOm) * 2);
    502         if (NULL == BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap) {
    503             BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap = sal_alloc(mem_sz,
    504                                                                "nat_id bitmap");
    505         }
    506         if (NULL == BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap) {
    507             _bcm_esw_l3_nat_free_resource(unit);
    508             return BCM_E_RESOURCE;
    509         }
    510         sal_memset(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, 0, mem_sz);
    511         refcount_sz = sizeof(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_refcount);
    512         sal_memset(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_refcount, 0, refcount_sz);
    513 
    514         /* initialize tbl_cnts, free indexes */
    515         BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, BCM_L3_NAT_INGRESS_POOL_CNT);
    516         BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, BCM_L3_NAT_INGRESS_DNAT_CNT);
    517         BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, BCM_L3_NAT_INGRESS_SNAT_CNT);
    518         BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) = soc_mem_index_max(unit,
    519                                                                     ING_SNATm);
    520         BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) = BCM_NAT_EGRESS_ID_MIN(unit);
    521 #ifdef BCM_MONTEREY_SUPPORT
    522         if (SOC_IS_MONTEREY(unit)) {
    523             BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) = soc_mem_index_min(unit,
    524                     ING_DNAT_ADDRESS_TYPEm);
    525         }
    526 #endif
    527         /* allocate and initialize mutex */
    528         _bcm_l3_nat_state[unit]->lock = sal_mutex_create("NAT module mutex");
    529         if (NULL == _bcm_l3_nat_state[unit]->lock) {
    530             _bcm_esw_l3_nat_free_resource(unit);
    531             return BCM_E_RESOURCE;
    532         }
    533         rv = BCM_E_NONE;
    534 
    535 #ifdef BCM_WARM_BOOT_SUPPORT
    536     if (SOC_WARM_BOOT(unit)) {
    537         rv = _bcm_esw_nat_reinit(unit);
    538         if (BCM_FAILURE(rv)) {
    539             _bcm_esw_l3_nat_free_resource(unit);
    540             return rv;
    541         }
    542     } else
    543 #endif /* BCM_WARM_BOOT_SUPPORT */
    544     {
    545         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
    546 
    547         /* Clear Ingress DNAT Address Type table */
    548         rv = soc_mem_clear(unit, ING_DNAT_ADDRESS_TYPEm, COPYNO_ALL, 1);
    549         if (!SOC_SUCCESS(rv)) {
    550             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    551             return BCM_E_INTERNAL;
    552         }
    553 
    554         /* Clear Ingress SNAT Lookup table */
    555         rv = soc_mem_clear(unit, ING_SNATm, COPYNO_ALL, 1);
    556         if (!SOC_SUCCESS(rv)) {
    557             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    558             return BCM_E_INTERNAL;
    559         }
    560 
    561         /* Clear Egress NAT packet edit entry */
    562         rv = soc_mem_clear(unit, EGR_NAT_PACKET_EDIT_INFOm, COPYNO_ALL, 1);
    563         if (!SOC_SUCCESS(rv)) {
    564             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    565             return BCM_E_INTERNAL;
    566         }
    567         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    568     }
    569 
    570     }
    571     return rv;
    572 }
    573 
    574 /*
    575  * Function:
    576  *      _bcm_esw_l3_nat_cleanup
    577  * Purpose:
    578  *      DeInit  L3NAT software module
    579  * Parameters:
    580  *      unit     - Device Number
    581  * Returns:
    582  *      BCM_E_XXX
    583  */
    584 int
    585 _bcm_esw_l3_nat_cleanup(int unit) 
    586 {
    587     int rv = BCM_E_UNAVAIL;
    588 
    589     _bcm_esw_l3_nat_free_resource(unit);
    590     return rv;
    591 }
    592 #endif /* BCM_TRIDENT2_SUPPORT */
    593 
    594 #ifdef BCM_TRIDENT2_SUPPORT
    595 /* populate the entry using nat_info */
    596 static int  _bcm_td2_nat_egress_sw_to_hw(int unit, int nat_idx, 
    597                                         bcm_l3_nat_egress_t *nat_info, 
    598                                         void *hw_buf)
    599 {
    600     int rv, hw_idx, hw_half;
    601     int bit_count;
    602     int twice_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(nat_info->flags);
    603     int twice_nat_val = 0;
    604     soc_field_t modify_src_or_dst;
    605     soc_field_t ip_address;
    606     soc_field_t modify_l4_port_or_prefix;
    607     soc_field_t l4_port_or_prefix;
    608     soc_field_t valid;
    609 
    610     /* translate to hw index */
    611     BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_idx, hw_idx, hw_half);
    612     
    613     if (hw_half) {
    614         modify_src_or_dst = MODIFY_SRC_OR_DST_1f;
    615         ip_address = IP_ADDRESS_1f;
    616         modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_1f;
    617         l4_port_or_prefix = L4_PORT_OR_PREFIX_1f;
    618         valid = VALID_1f;
    619     } else {
    620         modify_src_or_dst = MODIFY_SRC_OR_DST_0f;
    621         ip_address = IP_ADDRESS_0f;
    622         modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_0f;
    623         l4_port_or_prefix = L4_PORT_OR_PREFIX_0f;
    624         valid = VALID_0f;
    625     }
    626     if (nat_info->flags & BCM_L3_NAT_EGRESS_SNAT) {
    627         if (twice_nat) {
    628             /* override field selections */
    629             modify_src_or_dst = MODIFY_SRC_OR_DST_0f;
    630             ip_address = IP_ADDRESS_0f;
    631             modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_0f;
    632             l4_port_or_prefix = L4_PORT_OR_PREFIX_0f;
    633             valid = VALID_0f;
    634             twice_nat_val = 1;
    635         } else {
    636             /* first read the entry */
    637             rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 
    638                                                 hw_buf);
    639             SOC_IF_ERROR_RETURN(rv);
    640         }
    641         soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 
    642                             modify_src_or_dst, 0); /* SIP */
    643         soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, ip_address, 
    644                                                   nat_info->sip_addr);
    645         if (nat_info->flags & BCM_L3_NAT_EGRESS_NAPT) {
    646             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf,
    647                                             modify_l4_port_or_prefix, 0);
    648             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 
    649                                 l4_port_or_prefix, nat_info->src_port);
    650         } else {
    651             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf,
    652                                             modify_l4_port_or_prefix, 1);
    653             /* coverity[callee_ptr_arith : FALSE] */
    654             SHR_BITCOUNT_RANGE(&nat_info->sip_addr_mask, bit_count, 0, 32);
    655             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf,
    656                                                 l4_port_or_prefix, bit_count);
    657         }
    658         soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, valid, 1);
    659 
    660         /* protect against errors: */
    661         if (!twice_nat) {
    662             return BCM_E_NONE;
    663         }
    664     } 
    665     if (nat_info->flags & BCM_L3_NAT_EGRESS_DNAT) {
    666         if (twice_nat) {
    667             /* override field selections */
    668             modify_src_or_dst = MODIFY_SRC_OR_DST_1f;
    669             ip_address = IP_ADDRESS_1f;
    670             modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_1f;
    671             l4_port_or_prefix = L4_PORT_OR_PREFIX_1f;
    672             valid = VALID_1f;
    673             twice_nat_val = 1;
    674         } else {
    675             /* first read the entry */
    676             rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 
    677                                                 hw_buf);
    678             SOC_IF_ERROR_RETURN(rv);
    679         }
    680         soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 
    681                             modify_src_or_dst, 1); /* DIP */
    682         soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, ip_address, 
    683                                                   nat_info->dip_addr); 
    684         if (nat_info->flags & BCM_L3_NAT_EGRESS_NAPT) {
    685             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 
    686                                             modify_l4_port_or_prefix, 0);
    687             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 
    688                                 l4_port_or_prefix, nat_info->dst_port);
    689         } else {
    690             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 
    691                                             modify_l4_port_or_prefix, 1);
    692             /* coverity[callee_ptr_arith : FALSE] */
    693             SHR_BITCOUNT_RANGE(&nat_info->dip_addr_mask, bit_count, 0, 32);
    694             soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 
    695                                     l4_port_or_prefix, bit_count);
    696         }
    697         soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, valid, 1);
    698     }
    699     soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, TWICE_NATf, 
    700                                               twice_nat_val);
    701 
    702     return BCM_E_NONE;
    703 }
    704 
    705 static int
    706 _bcm_td2_nat_egress_hw_to_sw(int unit, void *hw_buf, 
    707                              bcm_l3_nat_egress_t *nat_info, int hw_half)
    708 {
    709     int full_nat, valid0, valid1, tmp;
    710     tmp = nat_info->nat_id;
    711     sal_memset(nat_info, 0, sizeof(*nat_info));
    712     nat_info->nat_id = tmp;
    713 
    714     /* decide twice_nat or not first */
    715     full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, hw_buf, 
    716                                                          TWICE_NATf);
    717     valid0 = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, hw_buf, 
    718                                                          VALID_0f);
    719     valid1 = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, hw_buf, 
    720                                                          VALID_1f);
    721     if (full_nat) {
    722         nat_info->flags |= (BCM_L3_NAT_EGRESS_SNAT | BCM_L3_NAT_EGRESS_DNAT);
    723         /* populate SNAT into entry 0 and DNAT into entry 1 */
    724         if (!valid0 || !valid1) {
    725             return BCM_E_EMPTY;
    726         }
    727         BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 0f);
    728         BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 1f);
    729     } else {
    730         /* figure out which half to parse */
    731         if (hw_half) {
    732             /* fill from ENTRY_1 */
    733             if (!valid1) return BCM_E_EMPTY;
    734             BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 1f);
    735         } else {
    736             if (!valid0) return BCM_E_EMPTY;
    737             BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 0f);
    738         }
    739     }
    740     return BCM_E_NONE;
    741 }
    742 #endif /* BCM_TRIDENT2_SUPPORT */    
    743 
    744 /* allocate either a half or full-nat egress translate entry */
    745 int
    746 _bcm_td2_nat_egress_id_alloc(int unit, uint32 flags, int *id, int *count)
    747 {
    748     int full_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(flags);
    749     int i = 0, num_ids, step_count, used, min_idx;
    750 
    751     num_ids = soc_mem_index_count(unit, EGR_NAT_PACKET_EDIT_INFOm) *
    752               BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX;
    753     step_count = full_nat ? 2 : 1;
    754 
    755     min_idx = BCM_NAT_EGRESS_ID_MIN(unit) * BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX;
    756 
    757     if (flags & BCM_L3_NAT_EGRESS_WITH_ID) {
    758         /* for full nat make sure proper id is used. Even for full nat, any
    759            for half nat */
    760         if (*id % step_count) {
    761             return BCM_E_PARAM;
    762         }
    763         /* make sure it is unused */
    764         SHR_BITTEST_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, *id, 
    765                                                             step_count, used);
    766         if (flags & BCM_L3_NAT_EGRESS_REPLACE) {
    767             /* make sure it is used */
    768             if (1 == used) {       
    769                 *count = step_count;
    770                 return BCM_E_NONE;
    771             } else {
    772                 return BCM_E_NOT_FOUND;
    773             }
    774         }
    775         /* make sure it is unused without BCM_L3_NAT_EGRESS_REPLACE */
    776         if (0 == used) {       
    777             SHR_BITSET_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, *id, 
    778                              step_count);
    779             *count = step_count;
    780             return BCM_E_NONE;
    781         }
    782         /* if it is in use then flag error */
    783         return BCM_E_RESOURCE;
    784     } else if (flags & BCM_L3_NAT_EGRESS_REPLACE) {
    785         return BCM_E_PARAM;
    786     }
    787 
    788     for (i = min_idx; i < num_ids; i += step_count) {
    789         SHR_BITTEST_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, i, 
    790                                                             step_count, used);
    791         if (0 == used) {       
    792             break;
    793         }
    794     }
    795     if (i == num_ids) {
    796         return BCM_E_RESOURCE;
    797     }
    798     SHR_BITSET_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, i, step_count);
    799     *count = step_count;
    800     *id = i;
    801     return BCM_E_NONE;
    802 }
    803 
    804 int
    805 _bcm_td2_nat_egress_id_free(int unit, int nat_id, int count)
    806 {
    807     int used;
    808     SHR_BITTEST_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, nat_id, count,
    809                       used); 
    810     if (!used) {
    811         return BCM_E_RESOURCE;
    812     }
    813     SHR_BITCLR_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, nat_id, count);
    814     return BCM_E_NONE;
    815 }
    816 
    817 /*
    818  * Function:
    819  * _bcm_td2_l3_nat_egress_inc_refcount
    820  * Description:
    821  *  Increasements the reference count for the entry.
    822  * Parameters:
    823  *  unit    - (IN) Device number.
    824  *  nat_id  - (IN) Index of egress nat to be increased.
    825  */
    826 int
    827 _bcm_td2_l3_nat_egress_inc_refcount(
    828     int unit,
    829     bcm_l3_nat_id_t nat_id)
    830 {
    831 #ifdef BCM_TRIDENT2_SUPPORT
    832     int rv = BCM_E_NONE, hw_idx, hw_half, full_nat=0;
    833     egr_nat_packet_edit_info_entry_t hw_buf;
    834 
    835     if (soc_feature(unit, soc_feature_nat)) {
    836         /* read entry at nat_id */
    837         BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half);
    838         COMPILER_REFERENCE(hw_half);
    839 
    840         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
    841         rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx,
    842                                             (void *)&hw_buf);
    843         if (!SOC_SUCCESS(rv)) {
    844             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    845             return BCM_E_INTERNAL;
    846         }
    847 
    848         /* check twice_nat field */
    849         full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(
    850                        unit, (void *)&hw_buf, TWICE_NATf);
    851 
    852         /* Increasement refcount */
    853         BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_id, 1);
    854         if (full_nat) {
    855             BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_id + 1, 1);
    856         }
    857 
    858         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    859         return BCM_E_NONE;
    860     }
    861 #endif /* BCM_TRIDENT2_SUPPORT */
    862     return BCM_E_UNAVAIL;
    863 }
    864 
    865 /*
    866  * Function:
    867  * _bcm_td2_l3_nat_egress_dec_refcount
    868  * Description:
    869  *  Decrements the reference count for the entry.
    870  * Parameters:
    871  *  unit    - (IN) Device number.
    872  *  nat_id  - (IN) Index of egress nat to be decreased.
    873  */
    874 int
    875 _bcm_td2_l3_nat_egress_dec_refcount(
    876     int unit,
    877     bcm_l3_nat_id_t nat_id)
    878 {
    879 #ifdef BCM_TRIDENT2_SUPPORT
    880     int rv = BCM_E_NONE, hw_idx, hw_half, full_nat=0;
    881     egr_nat_packet_edit_info_entry_t hw_buf;
    882 
    883     if (soc_feature(unit, soc_feature_nat)) {
    884         /* read entry at nat_id */
    885         BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half);
    886         COMPILER_REFERENCE(hw_half);
    887 
    888         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
    889         rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx,
    890                                             (void *)&hw_buf);
    891         if (!SOC_SUCCESS(rv)) {
    892             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    893             return BCM_E_INTERNAL;
    894         }
    895 
    896         if (BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) == 0) {
    897             /* already deleted */
    898             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    899             return BCM_E_EMPTY;
    900         }
    901 
    902         /* check twice_nat field */
    903         full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(
    904                        unit, (void *)&hw_buf, TWICE_NATf);
    905 
    906         /* Decrement refcount */
    907         BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id);
    908         if (full_nat) {
    909             BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id + 1);
    910         }
    911 
    912         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    913         return BCM_E_NONE;
    914     }
    915 #endif /* BCM_TRIDENT2_SUPPORT */
    916     return BCM_E_UNAVAIL;
    917 }
    918 
    919 #if defined (BCM_TRIDENT2_SUPPORT)
    920 /*
    921  * Function: _bcm_esw_nat_egress_ref_count_update
    922  *
    923  * Purpose: Update the reference count for the Egress Nat
    924  *
    925  * Parameters:
    926  * unit       - (IN) Device number.
    927  * nat_id     - (IN) Index of the Nat entry to be updated.
    928  * incr       - (IN) Increment/Decrement.
    929  *
    930  * Returns:
    931  * BCM_E_XXX
    932  */
    933 int _bcm_esw_nat_egress_ref_count_update(int unit, uint32 nat_id, int incr) {
    934     if (incr) {
    935         BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_inc_refcount(unit, nat_id));
    936     }
    937     else {
    938         BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_dec_refcount 
    939                 (unit, nat_id));
    940     }
    941     return (BCM_E_NONE);
    942 }
    943 #endif
    944 
    945 /*
    946  * Function:
    947  *  bcm_esw_l3_nat_egress_add
    948  * Description:
    949  *	Add a NAT translation entry to the egress NAT xlate table.
    950  * Parameters:
    951  *	unit - (IN) Device number. 
    952  *  nat_info - (IN/OUT)
    953  *      IN: packet edit info: original IP/ports and translated IP/ports
    954  *      OUT: nat_id field is populated with the index of the xlate table where
    955  *           this translation entry was added.
    956  * Returns:
    957  *	BCM_E_XXX
    958  */
    959 
    960 int
    961 bcm_esw_l3_nat_egress_add(int unit, bcm_l3_nat_egress_t *nat_info)
    962 {
    963 #ifdef BCM_TRIDENT2_SUPPORT
    964     int rv = BCM_E_NONE, nat_id, count, hw_idx, hw_half;
    965     egr_nat_packet_edit_info_entry_t  hw_buf;
    966 
    967     if (soc_feature(unit, soc_feature_nat)) {
    968        /* validate input */
    969         if (NULL == nat_info) {
    970             return BCM_E_PARAM;
    971         }
    972         if (!(nat_info->flags & (BCM_L3_NAT_EGRESS_SNAT | BCM_L3_NAT_EGRESS_DNAT))) {
    973             /* must specify at least one of SNAT and DNAT */
    974             return BCM_E_PARAM;
    975         }
    976         /* if WITH_ID is specified, attempt is made to allocate this one, if
    977            it is free
    978          */
    979         nat_id = nat_info->nat_id;
    980 
    981         if (SOC_IS_TRIDENT3X(unit) && (nat_info->flags & BCM_L3_NAT_EGRESS_WITH_ID)) {
    982             if (nat_id < (BCM_NAT_EGRESS_ID_MIN(unit) *
    983                           BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX)) {
    984                 return BCM_E_PARAM;
    985             }
    986         }
    987 
    988         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
    989 
    990         /* allocate index: For twice nat nat_id and nat_id + 1 are allocated */
    991         rv = _bcm_td2_nat_egress_id_alloc(unit, nat_info->flags, &nat_id,
    992                                               &count);
    993         if (BCM_FAILURE(rv)) {
    994             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
    995             return BCM_E_RESOURCE;
    996         }
    997 
    998         /* populate the entry using nat_info */
    999         sal_memset(&hw_buf, 0, sizeof(hw_buf));
   1000         rv = _bcm_td2_nat_egress_sw_to_hw(unit, nat_id, nat_info, (void *)&hw_buf);
   1001         if (rv < 0) {
   1002             _bcm_td2_nat_egress_id_free(unit, nat_id, count);
   1003             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1004             return BCM_E_PARAM;
   1005         }
   1006 
   1007         BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half);
   1008         COMPILER_REFERENCE(hw_half);
   1009 
   1010         /* write the hardware entry */
   1011         rv = WRITE_EGR_NAT_PACKET_EDIT_INFOm(unit, MEM_BLOCK_ALL, hw_idx, 
   1012                                             (void *)&hw_buf); 
   1013         if (rv < 0) {
   1014             _bcm_td2_nat_egress_id_free(unit, nat_id, count);
   1015             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1016             return BCM_E_INTERNAL;
   1017         }
   1018         /* increment refcount except the case of replacement */
   1019         if (!(nat_info->flags & BCM_L3_NAT_EGRESS_REPLACE)) {
   1020             BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_id, count);
   1021         }
   1022         nat_info->nat_id = nat_id;
   1023             
   1024         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1025         return BCM_E_NONE;
   1026     }
   1027 #endif /* BCM_TRIDENT2_SUPPORT */    
   1028     return BCM_E_UNAVAIL;
   1029 }
   1030 
   1031 /* Function:
   1032  *  bcm_esw_l3_nat_delete
   1033  * Description:
   1034  *  Delete the egress NAT packet edit entry at the specified index. Decrements
   1035  *  the reference count for the entry. When refcount falls to one it is 
   1036  *  removed from the table.
   1037  * Parameters:
   1038  *  unit    - (IN) Device number.
   1039  *  nat_id  - IN Index of entry to be deleted.
   1040  */ 
   1041 int 
   1042 bcm_esw_l3_nat_egress_delete(
   1043     int unit, 
   1044     bcm_l3_nat_id_t nat_id)
   1045 {
   1046 #ifdef BCM_TRIDENT2_SUPPORT
   1047     int rv = BCM_E_NONE, hw_idx, hw_half, full_nat=0;
   1048     egr_nat_packet_edit_info_entry_t hw_buf;
   1049 
   1050     if (soc_feature(unit, soc_feature_nat)) {
   1051         
   1052         /* read entry at nat_id */
   1053         BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half);
   1054 
   1055         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   1056         rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 
   1057                                             (void *)&hw_buf);
   1058         if (!SOC_SUCCESS(rv)) {
   1059             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1060             return BCM_E_INTERNAL; 
   1061         }
   1062 		
   1063         if (BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) == 0) {
   1064             /* already deleted */
   1065             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1066             return BCM_E_EMPTY;
   1067         }
   1068 
   1069         if (1 < BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id)) {
   1070             /* If nat is in-use - reject deletion */
   1071             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1072             return BCM_E_BUSY;
   1073         }
   1074 		
   1075         /* check twice_nat field */
   1076         
   1077         full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, (void *)&hw_buf, 
   1078                                                                 TWICE_NATf);
   1079 
   1080         /* Decrement refcount */
   1081         BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id);
   1082         if (full_nat) {
   1083             BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id + 1);
   1084         }
   1085 
   1086         if (BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) > 0) {
   1087             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1088             return BCM_E_NONE;
   1089         }
   1090 		
   1091         /* clear valid bit for either 1 half or both halves if full nat */
   1092         if (full_nat) {
   1093             /* clear both halves */
   1094             sal_memset(&hw_buf, 0, sizeof(hw_buf));
   1095         } else {
   1096             if (hw_half) {
   1097                 /* clear ENTRY_1 valid bit */
   1098                 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, &hw_buf, 
   1099                                                           VALID_1f, 0);
   1100             } else {
   1101                 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, &hw_buf, 
   1102                                                           VALID_0f, 0);
   1103             }
   1104         }
   1105         rv = WRITE_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ALL, hw_idx, 
   1106                                             (void *) &hw_buf);
   1107         if (!SOC_SUCCESS(rv)) {
   1108             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1109             return BCM_E_INTERNAL;
   1110         }
   1111         /* free nat_id and nat_id + 1 */ 
   1112         rv = _bcm_td2_nat_egress_id_free(unit, nat_id, full_nat + 1);
   1113         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1114         return rv;
   1115     }
   1116 #endif /* BCM_TRIDENT2_SUPPORT */    
   1117     return BCM_E_UNAVAIL;
   1118 }
   1119 
   1120 /* Function:
   1121  *  bcm_esw_l3_nat_egress_get
   1122  * Description:
   1123  *  Retrieve the egress NAT packet edit entry at the specified index 
   1124  * Parameters:
   1125  *  unit    - (IN) Device number.
   1126  *  nat_id  - IN Index of entry to get.
   1127  */
   1128 int bcm_esw_l3_nat_egress_get(
   1129     int unit, 
   1130     bcm_l3_nat_egress_t *nat_info)
   1131 {
   1132 #ifdef BCM_TRIDENT2_SUPPORT
   1133     int rv = BCM_E_NONE, hw_idx, hw_half;
   1134     egr_nat_packet_edit_info_entry_t hw_buf;
   1135 
   1136     if (soc_feature(unit, soc_feature_nat)) {
   1137         if (NULL == nat_info) {
   1138             return BCM_E_PARAM;
   1139         }
   1140         /* validate the index */
   1141         BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_info->nat_id, hw_idx, hw_half);
   1142         if ((hw_idx < BCM_NAT_EGRESS_ID_MIN(unit)) ||
   1143             (hw_idx > soc_mem_index_max(unit, EGR_NAT_PACKET_EDIT_INFOm))) {
   1144             return BCM_E_PARAM;
   1145         }
   1146 
   1147         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   1148 
   1149         /* read entry at index nat_id. */
   1150         rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 
   1151                                             &hw_buf);
   1152         if (!SOC_SUCCESS(rv)) {
   1153             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1154             return BCM_E_INTERNAL;
   1155         }
   1156         rv = _bcm_td2_nat_egress_hw_to_sw(unit, (void *)&hw_buf, nat_info, 
   1157                                           hw_half);
   1158         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1159         return rv;
   1160     }
   1161 #endif /* BCM_TRIDENT2_SUPPORT */    
   1162     return BCM_E_UNAVAIL;
   1163 }
   1164 
   1165 /* Function:
   1166  *  bcm_esw_l3_nat_egress_traverse
   1167  * Description:
   1168  *  Traverse all valid NAT packet edit entries in the egress translate table
   1169  *  and call the supplied callback routine for each.
   1170  * Parameters:
   1171  *  unit    - (IN) Device number.
   1172  *  nat_id  - IN Index of entry to get.
   1173  */
   1174 int bcm_esw_l3_nat_egress_traverse(
   1175     int unit,
   1176     uint32 flags, 
   1177     uint32 start, 
   1178     uint32 end, 
   1179     bcm_l3_nat_egress_traverse_cb cb, 
   1180     void *user_data)
   1181 {
   1182 #ifdef BCM_TRIDENT2_SUPPORT
   1183 
   1184     int rv = BCM_E_NONE, i;
   1185     int idx_max, full_nat;
   1186     egr_nat_packet_edit_info_entry_t hw_buf;
   1187     bcm_l3_nat_egress_t nat_info;
   1188 
   1189     if (!soc_feature(unit, soc_feature_nat)) {
   1190         return BCM_E_UNAVAIL;
   1191     }
   1192     if (NULL == cb) {
   1193         return BCM_E_NONE;
   1194     }
   1195     idx_max = soc_mem_index_max(unit, EGR_NAT_PACKET_EDIT_INFOm);
   1196     /* Input indexes sanity */
   1197     if ((start > (uint32)idx_max) || ((end > (uint32)idx_max) 
   1198         && (end != 0xffffffff)) || (start > end)) {
   1199         return BCM_E_PARAM;
   1200     }
   1201 
   1202     /* End value according to real table size */
   1203     if (end == 0xffffffff) {
   1204         end = (uint32)idx_max;
   1205     }
   1206 
   1207     BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   1208 
   1209     for (i = start; i <= end; i++) {
   1210         /* traverse either one or 2 entries depending on half or full nat */
   1211         rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, i, 
   1212                                             &hw_buf);
   1213         if (!SOC_SUCCESS(rv)) {
   1214             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1215             return BCM_E_INTERNAL;
   1216         }
   1217 
   1218         /* assume full nat entry first */
   1219         nat_info.nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET(i, 0);
   1220         rv = _bcm_td2_nat_egress_hw_to_sw(unit, (void *)&hw_buf, &nat_info, 0);
   1221         if (rv != BCM_E_EMPTY) {
   1222             if (flags && (flags != nat_info.flags)) {
   1223                 continue;
   1224             }
   1225             /* call callback fn */
   1226             rv = (*cb) (unit, i, &nat_info, user_data);
   1227 #ifdef BCM_CB_ABORT_ON_ERR
   1228             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   1229                 break;
   1230             }
   1231 #endif
   1232         }
   1233 
   1234         /* confirm if full nat or not */
   1235         full_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(nat_info.flags);
   1236 
   1237         if (full_nat) {
   1238             continue;
   1239         } 
   1240         nat_info.nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET(i, 1);
   1241         rv = _bcm_td2_nat_egress_hw_to_sw(unit, (void *)&hw_buf, &nat_info, 1);
   1242         if (rv != BCM_E_EMPTY) {
   1243             if (flags && (flags != nat_info.flags)) {
   1244                 continue;
   1245             }
   1246             /* call callback fn */
   1247             rv = cb(unit, i, &nat_info, user_data);
   1248 #ifdef BCM_CB_ABORT_ON_ERR
   1249             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   1250                 break;
   1251             }
   1252 #endif
   1253         }
   1254 
   1255     }
   1256     BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1257     return BCM_E_NONE;
   1258 #endif /* BCM_TRIDENT2_SUPPORT */    
   1259     return BCM_E_UNAVAIL;
   1260 }
   1261 
   1262 /*
   1263  * Function:
   1264  *      _bcm_esw_l3_nat_egress_reference_get
   1265  * Description:
   1266  *      Get the reference count of the egress nat.
   1267  *
   1268  * Parameters:
   1269  *      unit       - (IN) bcm device.
   1270  *      nat_id     - (IN) egress nat id.
   1271  *      ref_count  - (OUT) The number of references to egress nat.
   1272  * Returns:
   1273  *      BCM_E_XXX
   1274  */
   1275 int
   1276 _bcm_esw_l3_nat_egress_reference_get(int unit, bcm_l3_nat_id_t nat_id,
   1277                                  uint32 *ref_count)
   1278 {
   1279 #ifdef BCM_TRIDENT2_SUPPORT
   1280     int num_ids;
   1281 
   1282     if (soc_feature(unit, soc_feature_nat)) {
   1283         num_ids = soc_mem_index_count(unit, EGR_NAT_PACKET_EDIT_INFOm) *
   1284                   BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX;
   1285         if (nat_id > num_ids) {
   1286             return BCM_E_PARAM;
   1287         }
   1288 
   1289         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   1290         *ref_count = BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) - 1;
   1291         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   1292 
   1293         return BCM_E_NONE;
   1294     }
   1295 #endif
   1296     return BCM_E_UNAVAIL;
   1297 }
   1298 
   1299 /*
   1300  * FLEX STAT FUNCTIONS for L3 NAT
   1301  *
   1302  * This following functions implements flex stat routines to attach, detach and get/set
   1303  * flex counter functions.
   1304  * 
   1305  * FLEX ATTACH 
   1306  *   The function allocates flex counter from the counter pool and configures
   1307  *   attributes to set the base counter index and base offset. Flex counter pool,
   1308  *   base index and offset is associated to the table index request for the
   1309  *   module identifiers like, vpn, port, vp Additionally the reference counter
   1310  *   for the flex counter is incremented for multple references of the counter.
   1311  *
   1312  * FLEX DETACH 
   1313  *   The function disassociates flex counter details assigned during flex attach
   1314  *   and decrements the reference counter.
   1315  *
   1316  * FLEX COUNTER GET/SET 
   1317  *   The function read/set the associate counter values. Set is required for the
   1318  *   purpose of clearing the counter.
   1319  *
   1320  *
   1321  * FLEX COUNTER MULTI GET/SET
   1322  *   The function reads/sets multiple flex stats and returns the counter arrays. 
   1323  *
   1324  * FLEX STAT ID
   1325  *   The funciton retrieves the stat id for the given module identifiers. The
   1326  *   flex counter stat id has the following format.
   1327  *
   1328  *          (8 modes)  (32 groups) (16 pools)  (32 objIds)  (64K index)
   1329  *         +---------+------------+----------+-----------+-----------------+ 
   1330  *         |         |            |          |           |                 | 
   1331  *         | ModeId  |  GroupMode |   PoolId | Account   |  Base Index     |
   1332  *         |         |            |          | objectId  |                 |
   1333  *         +---------+------------+----------+-----------+-----------------+
   1334  *        (31)    (29)(28)     (24)(23)   (20)(19)    (15)(14)            (0)
   1335  *
   1336  *
   1337  *   PoolId      : Counter pool no. 
   1338  *                 ( TD2: Ingress(8 pool x 4k counters)
   1339  *                        Egress (4 pool x 4k counters)
   1340  *   GroupMode   : Attribute group mode determines base offset and no. of counters
   1341  *   ModeId      : Ingress/Egress Modes
   1342  *   Base Idx    : Index into counter block of 256 counters
   1343  *   Account Obj : Flexible accounting objects
   1344  */
   1345 
   1346 
   1347 #if defined(BCM_TRIDENT2_SUPPORT)
   1348 /*
   1349  * Function:
   1350  *      _bcm_td2_l3_route_stat_attach
   1351  * Description:
   1352  *      Attach counters entries to the given  l3 route defip index . Allocate
   1353  *      flex counter and assign counter index and offset for the index pointed
   1354  *      by l3 defip index
   1355  *
   1356  * Parameters:
   1357  *      unit             - (IN) unit number
   1358  *      info			 - (IN) L3 Route Info
   1359  *      stat_counter_id  - (IN) Stat Counter ID.
   1360  *
   1361  * Return Value:
   1362  *      BCM_E_XXX
   1363  * Notes:
   1364  */
   1365 
   1366 /*
   1367  * Function:
   1368  *      _bcm_td2_l3_nat_egress_stat_get_table_info
   1369  * Description:
   1370  *      Provides relevant flex table information(table-name,index with
   1371  *      direction)  for given ingress interface.
   1372  *
   1373  * Parameters:
   1374  *      unit             - (IN) unit number
   1375  *      info			 - (IN) Egress Nat Info
   1376  *      num_of_tables    - (OUT) Number of flex counter tables
   1377  *      table_info       - (OUT) Flex counter tables information
   1378  *
   1379  * Return Value:
   1380  *      BCM_E_XXX
   1381  * Notes:
   1382  */
   1383 static 
   1384 bcm_error_t  _bcm_td2_l3_nat_egress_stat_get_table_info(
   1385             int                        unit,
   1386             bcm_l3_nat_egress_t	       *info,
   1387             uint32                     *num_of_tables,
   1388             bcm_stat_flex_table_info_t *table_info)
   1389 {
   1390     int rv;
   1391     int index = 0;
   1392 
   1393     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
   1394         return BCM_E_UNAVAIL;
   1395     }
   1396 
   1397     /* Validate L3 EGRESS NAT Info */
   1398     rv = bcm_esw_l3_nat_egress_get(unit, info);  
   1399     if (!BCM_SUCCESS(rv)) {
   1400         return rv;
   1401     }
   1402     index = info->nat_id;
   1403 
   1404     /* Ingress L3 Egress NAT */
   1405     table_info[*num_of_tables].table=EGR_NAT_PACKET_EDIT_INFOm;
   1406     table_info[*num_of_tables].index=index;
   1407     table_info[*num_of_tables].direction=bcmStatFlexDirectionEgress;
   1408     (*num_of_tables)++;
   1409 
   1410     return BCM_E_NONE;
   1411 }
   1412 
   1413 
   1414 
   1415 /*
   1416  * Function:
   1417  *      _bcm_td2_l3_nat_egress_stat_attach
   1418  * Description:
   1419  *      Attach counters entries to the given  egress nat (egr nat packet edit
   1420  *      info).  Allocate flex counter and assign counter index and offset for
   1421  *      the index pointed by egr nat info ( packet edit index)
   1422  *
   1423  * Parameters:
   1424  *      unit             - (IN) unit number
   1425  *      info			 - (IN) Egress Nat Info
   1426  *      stat_counter_id  - (IN) Stat Counter ID.
   1427  *
   1428  * Return Value:
   1429  *      BCM_E_XXX
   1430  * Notes:
   1431  */
   1432     
   1433 int  _bcm_td2_l3_nat_egress_stat_attach (
   1434                             int                 unit,
   1435                             bcm_l3_nat_egress_t	*info,
   1436                             uint32              stat_counter_id)
   1437 {
   1438     int                        rv = BCM_E_NONE;
   1439     int                        counter_flag = 0;
   1440     soc_mem_t                  table = 0;
   1441     bcm_stat_flex_direction_t  direction = bcmStatFlexDirectionIngress;
   1442     uint32                     pool_number = 0;
   1443     uint32                     base_index = 0;
   1444     bcm_stat_flex_mode_t       offset_mode = 0;
   1445     bcm_stat_object_t          object = bcmStatObjectIngPort;
   1446     bcm_stat_group_mode_t      group_mode = bcmStatGroupModeSingle;
   1447     uint32                     count = 0;
   1448     uint32                     actual_num_tables = 0;
   1449     uint32                     num_of_tables = 0;
   1450     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1451 
   1452 
   1453     /* Get pool, base index group mode and offset modes from stat counter id */
   1454     _bcm_esw_stat_get_counter_id_info(
   1455                   unit, stat_counter_id,
   1456                   &group_mode, &object, &offset_mode, &pool_number, &base_index);
   1457 
   1458     /* Validate object and group mode */
   1459     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction));
   1460     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit, group_mode));
   1461 
   1462     /* Get Table index to attach flexible counter */
   1463     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   1464                         unit, object, 1, &actual_num_tables, &table, &direction));
   1465     BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info(
   1466                         unit, info, &num_of_tables, &table_info[0]));
   1467 
   1468     for (count = 0; count < num_of_tables; count++) {
   1469          if ((table_info[count].direction == direction) &&
   1470              (table_info[count].table == table) ) {
   1471               if (direction == bcmStatFlexDirectionIngress) {
   1472                   counter_flag = 1;
   1473                   rv = _bcm_esw_stat_flex_attach_ingress_table_counters(
   1474                          unit,
   1475                          table_info[count].table,
   1476                          table_info[count].index,
   1477                          offset_mode,
   1478                          base_index,
   1479                          pool_number);
   1480                   if(BCM_FAILURE(rv)) {
   1481                         break;
   1482                   }
   1483               } else {
   1484                   counter_flag = 1;
   1485                   rv = _bcm_esw_stat_flex_attach_egress_table_counters(
   1486                          unit,
   1487                          table_info[count].table,
   1488                          table_info[count].index,
   1489                          0,
   1490                          offset_mode,
   1491                          base_index,
   1492                          pool_number);
   1493 
   1494                 if(BCM_FAILURE(rv)) {
   1495                         break;
   1496                   }
   1497               } 
   1498          }
   1499     }
   1500 
   1501     if (counter_flag == 0) {
   1502         rv = BCM_E_NOT_FOUND;
   1503     }
   1504 
   1505     return rv;
   1506 }
   1507 
   1508 
   1509 /*
   1510  * Function:
   1511  *      _bcm_td2_l3_nat_egress_stat_detach
   1512  * Description:
   1513  *      Detach counter entries to the given  l3 egress nat index. 
   1514  *
   1515  * Parameters:
   1516  *      unit             - (IN) unit number
   1517  *      info		     - (IN) Egress Nat Info
   1518  *
   1519  * Return Value:
   1520  *      BCM_E_XXX
   1521  * Notes:
   1522  */
   1523 int  _bcm_td2_l3_nat_egress_stat_detach (
   1524                             int                 unit,
   1525                             bcm_l3_nat_egress_t	*info)
   1526 {
   1527     uint32                     count = 0;
   1528     uint32                     num_of_tables = 0;
   1529     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1530     bcm_error_t                rv = BCM_E_NONE;
   1531     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE};
   1532 
   1533     /* Get the table index to be detached */
   1534     BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info(
   1535                         unit, info, &num_of_tables, &table_info[0]));
   1536 
   1537     for (count = 0; count < num_of_tables; count++) {
   1538          if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   1539              rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   1540                         unit, table_info[count].table, table_info[count].index);
   1541              if (BCM_E_NONE != rv &&
   1542                     BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   1543                     err_code[bcmStatFlexDirectionIngress] = rv;
   1544              }
   1545          } else {
   1546              rv = _bcm_esw_stat_flex_detach_egress_table_counters(
   1547                         unit, 0, table_info[count].table, table_info[count].index);
   1548              if (BCM_E_NONE != rv &&
   1549                     BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   1550                     err_code[bcmStatFlexDirectionEgress] = rv;
   1551              }
   1552          }
   1553     }
   1554 
   1555     BCM_STAT_FLEX_DETACH_RETURN(err_code)
   1556 }
   1557 
   1558 /*
   1559  * Function:
   1560  *      _bcm_td2_l3_nat_egress_stat_counter_get
   1561  *
   1562  * Description:
   1563  *  Get l3 egress nat counter value for specified l3 egress nat index
   1564  *  if sync_mode is set, sync the sw accumulated count
   1565  *  with hw count value first, else return sw count.  
   1566  *
   1567  * Parameters:
   1568  *      unit             - (IN) unit number
   1569  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   1570  *      info			 - (IN)  Egress Nat Info
   1571  *      stat             - (IN) l3 egress nat counter stat types
   1572  *      num_entries      - (IN) Number of counter Entries
   1573  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1574  *      counter_values   - (OUT) Pointer to counter values
   1575  *
   1576  * Return Value:
   1577  *      BCM_E_XXX
   1578  * Notes:
   1579  */
   1580 int  _bcm_td2_l3_nat_egress_stat_counter_get(
   1581                             int                 unit, 
   1582                             int                 sync_mode, 
   1583                             bcm_l3_nat_egress_t	*info,
   1584                             bcm_l3_nat_egress_stat_t    stat, 
   1585                             uint32              num_entries, 
   1586                             uint32              *counter_indexes, 
   1587                             bcm_stat_value_t    *counter_values)
   1588 {
   1589     uint32                     table_count = 0;
   1590     uint32                     index_count = 0;
   1591     uint32                     num_of_tables = 0;
   1592     bcm_stat_flex_direction_t  direction = bcmStatFlexDirectionIngress;
   1593     uint32                     byte_flag = 0;
   1594     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1595 
   1596     /* Get the flex counter direction - ingress/egress */
   1597     if ((stat == bcmL3NatOutPackets) ||
   1598         (stat == bcmL3NatOutBytes)) {
   1599          direction = bcmStatFlexDirectionEgress;
   1600     } else {
   1601         /* direction = bcmStatFlexDirectionIngress;*/
   1602         return BCM_E_UNAVAIL;
   1603     }
   1604     if (stat == bcmL3NatOutPackets) {
   1605         byte_flag=0;
   1606     } else {
   1607         byte_flag=1;
   1608     }
   1609    
   1610     /*  Get Table index to read the flex counter */
   1611     BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info(
   1612                         unit, info, &num_of_tables, &table_info[0]));
   1613 
   1614     /* Get the flex counter for the attached table index */
   1615     for (table_count = 0; table_count < num_of_tables ; table_count++) {
   1616          if (table_info[table_count].direction == direction) {
   1617              for (index_count = 0; index_count < num_entries ; index_count++) {
   1618                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   1619                                       unit, sync_mode,
   1620                                       table_info[table_count].index,
   1621                                       table_info[table_count].table,
   1622                                       0,
   1623                                       byte_flag,
   1624                                       counter_indexes[index_count],
   1625                                       &counter_values[index_count]));
   1626              }
   1627          }
   1628     }
   1629 
   1630     return BCM_E_NONE;
   1631 }
   1632 
   1633 /*
   1634  * Function:
   1635  *      _bcm_td2_l3_nat_egress_stat_counter_set
   1636  *
   1637  * Description:
   1638  *  Set l3 egress nat counter value for specified l3 egress nat index
   1639  *
   1640  * Parameters:
   1641  *      unit             - (IN) unit number
   1642  *      info			 - (IN) Egress Nat Info
   1643  *      stat             - (IN) l3 egress nat counter stat types
   1644  *      num_entries      - (IN) Number of counter Entries
   1645  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1646  *      counter_values   - (OUT) Pointer to counter values
   1647  *
   1648  * Return Value:
   1649  *      BCM_E_XXX
   1650  * Notes:
   1651  */
   1652  int  _bcm_td2_l3_nat_egress_stat_counter_set(
   1653                             int                 unit, 
   1654                             bcm_l3_nat_egress_t	*info,
   1655                             bcm_l3_nat_egress_stat_t  stat, 
   1656                             uint32              num_entries, 
   1657                             uint32              *counter_indexes, 
   1658                             bcm_stat_value_t    *counter_values)
   1659 {
   1660     uint32                     table_count=0;
   1661     uint32                     index_count=0;
   1662     uint32                     num_of_tables=0;
   1663     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   1664     uint32                     byte_flag=0;
   1665     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1666 
   1667     /* Get the flex counter direction - ingress/egress */
   1668     if ((stat == bcmL3NatOutPackets) ||
   1669         (stat == bcmL3NatOutBytes)) {
   1670          direction = bcmStatFlexDirectionEgress;
   1671     } else {
   1672         /* direction = bcmStatFlexDirectionIngress;*/
   1673         return BCM_E_UNAVAIL;
   1674     }
   1675     if (stat == bcmL3NatOutPackets) {
   1676         byte_flag=0;
   1677     } else {
   1678         byte_flag=1;
   1679     }
   1680    
   1681     /*  Get Table index to read the flex counter */
   1682     BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info(
   1683                         unit, info, &num_of_tables, &table_info[0]));
   1684 
   1685     /* Get the flex counter for the attached table index */
   1686     for (table_count = 0; table_count < num_of_tables ; table_count++) {
   1687          if (table_info[table_count].direction == direction) {
   1688              for (index_count = 0; index_count < num_entries; index_count++) {
   1689                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   1690                                       unit,
   1691                                       table_info[table_count].index,
   1692                                       table_info[table_count].table,
   1693                                       0,
   1694                                       byte_flag,
   1695                                       counter_indexes[index_count],
   1696                                       &counter_values[index_count]));
   1697              }
   1698          }
   1699     }
   1700     return BCM_E_NONE;
   1701 }
   1702 
   1703 /*
   1704  * Function:
   1705  *      _bcm_td2_l3_nat_egress_stat_multi_get
   1706  *
   1707  * Description:
   1708  *  Get Multiple l3 egress nat counter value for specified l3 egress nat index for multiple stat
   1709  *  types
   1710  *
   1711  * Parameters:
   1712  *      unit             - (IN) unit number
   1713  *      info			 - (IN) Egress Nat Info
   1714  *      nstat            - (IN) Number of elements in stat array
   1715  *      stat_arr         - (IN) Collected statistics descriptors array
   1716  *      value_arr        - (OUT) Collected counters values
   1717  *
   1718  * Return Value:
   1719  *      BCM_E_XXX
   1720  * Notes:
   1721  */
   1722 
   1723     
   1724 int  _bcm_td2_l3_nat_egress_stat_multi_get(
   1725                             int                 unit, 
   1726                             bcm_l3_nat_egress_t	*info,
   1727                             int                 nstat, 
   1728                             bcm_l3_nat_egress_stat_t  *stat_arr,
   1729                             uint64              *value_arr)
   1730 {
   1731     int              rv = BCM_E_NONE;
   1732     int              idx;
   1733     uint32           counter_indexes = 0;
   1734     bcm_stat_value_t counter_values = {0};
   1735     int              sync_mode = 0;
   1736 
   1737     /* Iterate of all stats array to retrieve flex counter values */
   1738     for (idx = 0; idx < nstat ;idx++) {
   1739          BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_get( 
   1740                              unit, sync_mode, info, stat_arr[idx], 
   1741                              1, &counter_indexes, &counter_values));
   1742          if ((stat_arr[idx] == bcmL3NatOutPackets)) {
   1743              COMPILER_64_SET(value_arr[idx],
   1744                              COMPILER_64_HI(counter_values.packets64),
   1745                              COMPILER_64_LO(counter_values.packets64));
   1746          } else {
   1747              COMPILER_64_SET(value_arr[idx],
   1748                              COMPILER_64_HI(counter_values.bytes),
   1749                              COMPILER_64_LO(counter_values.bytes));
   1750          }
   1751     }
   1752     return rv;
   1753 }
   1754 
   1755 /*
   1756  * Function:
   1757  *      _bcm_td2_l3_nat_egress_stat_multi_get32
   1758  *
   1759  * Description:
   1760  *  Get 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat
   1761  *  types
   1762  *
   1763  * Parameters:
   1764  *      unit             - (IN) unit number
   1765  *      info		 	 - (IN) Egress Nat Info
   1766  *      nstat            - (IN) Number of elements in stat array
   1767  *      stat_arr         - (IN) Collected statistics descriptors array
   1768  *      value_arr        - (OUT) Collected counters values
   1769  *
   1770  * Return Value:
   1771  *      BCM_E_XXX
   1772  * Notes:
   1773  */
   1774 int  _bcm_td2_l3_nat_egress_stat_multi_get32(
   1775                             int                 unit, 
   1776                             bcm_l3_nat_egress_t	*info,
   1777                             int                 nstat, 
   1778                             bcm_l3_nat_egress_stat_t  *stat_arr,
   1779                             uint32              *value_arr)
   1780 {
   1781     int              rv = BCM_E_NONE;
   1782     int              idx;
   1783     uint32           counter_indexes = 0;
   1784     bcm_stat_value_t counter_values = {0};
   1785     int              sync_mode = 0;
   1786 
   1787     /* Iterate of all stats array to retrieve flex counter values */
   1788     for (idx = 0; idx < nstat ;idx++) {
   1789          BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_get( 
   1790                              unit, sync_mode, info, stat_arr[idx], 
   1791                              1, &counter_indexes, &counter_values));
   1792          if ((stat_arr[idx] == bcmL3NatOutPackets)) {
   1793                 value_arr[idx] = counter_values.packets;
   1794          } else {
   1795              value_arr[idx] = COMPILER_64_LO(counter_values.bytes);
   1796          }
   1797     }
   1798     return rv;
   1799 }
   1800 
   1801 /*
   1802  * Function:
   1803  *      _bcm_td2_l3_nat_egress_stat_multi_set
   1804  *
   1805  * Description:
   1806  *  Set l3 egress nat counter value for specified l3 egress nat index for multiple stat
   1807  *  types
   1808  *
   1809  * Parameters:
   1810  *      unit             - (IN) unit number
   1811  *      info			 - (IN) Egress Nat Info
   1812  *      stat             - (IN) l3 egress nat counter stat types
   1813  *      num_entries      - (IN) Number of counter Entries
   1814  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1815  *      counter_values   - (OUT) Pointer to counter values
   1816  *
   1817  * Return Value:
   1818  *      BCM_E_XXX
   1819  * Notes:
   1820  */
   1821 int  _bcm_td2_l3_nat_egress_stat_multi_set(
   1822                             int                 unit, 
   1823                             bcm_l3_nat_egress_t	*info,
   1824                             int                 nstat, 
   1825                             bcm_l3_nat_egress_stat_t    *stat_arr,
   1826                             uint64              *value_arr)
   1827 {
   1828     int              rv = BCM_E_NONE;
   1829     int              idx;
   1830     uint32           counter_indexes = 0;
   1831     bcm_stat_value_t counter_values = {0};
   1832 
   1833     /* Iterate f all stats array to retrieve flex counter values */
   1834     for (idx = 0; idx < nstat ;idx++) {
   1835          if ((stat_arr[idx] == bcmL3NatOutPackets)) {
   1836              counter_values.packets = COMPILER_64_LO(value_arr[idx]);
   1837          } else {
   1838              COMPILER_64_SET(counter_values.bytes,
   1839                              COMPILER_64_HI(value_arr[idx]),
   1840                              COMPILER_64_LO(value_arr[idx]));
   1841          }
   1842           BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_set( 
   1843                              unit, info, stat_arr[idx], 
   1844                              1, &counter_indexes, &counter_values));
   1845     }
   1846     return rv;
   1847 }
   1848 
   1849 /*
   1850  * Function:
   1851  *      _bcm_td2_l3_nat_egress_stat_multi_set32
   1852  *
   1853  * Description:
   1854  *  Set 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat
   1855  *  types
   1856  *
   1857  * Parameters:
   1858  *      unit             - (IN) unit number
   1859  *      info			 - (IN) Egress Nat Info
   1860  *      stat             - (IN) l3 egress nat counter stat types
   1861  *      num_entries      - (IN) Number of counter Entries
   1862  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1863  *      counter_values   - (OUT) Pointer to counter values
   1864  *
   1865  * Return Value:
   1866  *      BCM_E_XXX
   1867  * Notes:
   1868  */
   1869 
   1870 int  _bcm_td2_l3_nat_egress_stat_multi_set32(
   1871                             int                 unit, 
   1872                             bcm_l3_nat_egress_t	*info,
   1873                             int                 nstat, 
   1874                             bcm_l3_nat_egress_stat_t    *stat_arr,
   1875                             uint32              *value_arr)
   1876 {
   1877     int              rv = BCM_E_NONE;
   1878     int              idx;
   1879     uint32           counter_indexes = 0;
   1880     bcm_stat_value_t counter_values = {0};
   1881 
   1882     /* Iterate of all stats array to retrieve flex counter values */
   1883     for (idx = 0; idx < nstat ;idx++) {
   1884          if ((stat_arr[idx] == bcmL3NatOutPackets)) {
   1885              counter_values.packets = value_arr[idx];
   1886          } else {
   1887              COMPILER_64_SET(counter_values.bytes,0,value_arr[idx]);
   1888          }
   1889 
   1890          BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_set( 
   1891                              unit, info, stat_arr[idx], 
   1892                              1, &counter_indexes, &counter_values));
   1893     }
   1894     return rv;
   1895 }
   1896 
   1897 /*
   1898  * Function: 
   1899  *      _bcm_td2_l3_nat_egress_stat_id_get
   1900  *
   1901  * Description: 
   1902  *      Get Stat Counter if associated with given l3 egress nat index
   1903  *
   1904  * Parameters: 
   1905  *      unit             - (IN) bcm device
   1906  *      info			 - (IN) Egress Nat Info
   1907  *      stat             - (IN) l3 egress nat counter stat types
   1908  *      stat_counter_id  - (IN) Stat Counter ID.
   1909  *
   1910  * Returns:
   1911  *      BCM_E_NONE - Success
   1912  *      BCM_E_XXX
   1913  * Notes:
   1914  */
   1915 
   1916 int  _bcm_td2_l3_nat_egress_stat_id_get(
   1917                             int                 unit,
   1918                             bcm_l3_nat_egress_t	*info,
   1919                             bcm_l3_nat_egress_stat_t    stat, 
   1920                             uint32              *stat_counter_id) 
   1921 {
   1922     bcm_stat_flex_direction_t  direction = bcmStatFlexDirectionIngress;
   1923     uint32                     num_of_tables = 0;
   1924     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1925     uint32                     index = 0;
   1926     uint32                     num_stat_counter_ids = 0;
   1927 
   1928     if ((stat == bcmL3NatOutPackets) ||
   1929         (stat == bcmL3NatOutBytes)) {
   1930          direction = bcmStatFlexDirectionEgress;
   1931     } else {
   1932         /* direction = bcmStatFlexDirectionIngress;*/
   1933         return BCM_E_UNAVAIL;
   1934     }
   1935 
   1936     /*  Get Tables, for which flex counter are attached  */
   1937     BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info(
   1938                         unit, info, &num_of_tables, &table_info[0]));
   1939 
   1940     /* Retrieve stat counter id */
   1941     for (index = 0; index < num_of_tables ; index++) {
   1942          if (table_info[index].direction == direction)
   1943              return _bcm_esw_stat_flex_get_counter_id(
   1944                                   unit, 1, &table_info[index],
   1945                                   &num_stat_counter_ids, stat_counter_id);
   1946     }
   1947     return BCM_E_NOT_FOUND;
   1948 }
   1949 #endif /* BCM_TRIDENT2_SUPPORT */
   1950 /*
   1951  * Function:
   1952  *      bcm_esw_l3_nat_egress_stat_attach
   1953  * Description:
   1954  *      Attach counters entries to the given  egress nat (egr nat packet edit
   1955  *      info).  Allocate flex counter and assign counter index and offset for
   1956  *      the index pointed by egr nat info ( packet edit index)
   1957  *
   1958  * Parameters:
   1959  *      unit             - (IN) unit number
   1960  *      info			 - (IN) Egress Nat Info
   1961  *      stat_counter_id  - (IN) Stat Counter ID.
   1962  *
   1963  * Return Value:
   1964  *      BCM_E_XXX
   1965  * Notes:
   1966  */
   1967     
   1968 int  bcm_esw_l3_nat_egress_stat_attach (
   1969                             int                 unit,
   1970                             bcm_l3_nat_egress_t	*info,
   1971                             uint32              stat_counter_id)
   1972 {
   1973 int     rv = BCM_E_UNAVAIL;
   1974 
   1975 #if defined(BCM_TRIDENT2_SUPPORT)
   1976     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   1977         rv = _bcm_td2_l3_nat_egress_stat_attach (
   1978                     unit, info, stat_counter_id);
   1979     } 
   1980 #endif
   1981     return rv;
   1982 }
   1983 
   1984 
   1985 /*
   1986  * Function:
   1987  *      bcm_esw_l3_nat_egress_stat_detach
   1988  * Description:
   1989  *      Detach counter entries to the given  l3 egress nat index. 
   1990  *
   1991  * Parameters:
   1992  *      unit             - (IN) unit number
   1993  *      info		     - (IN) Egress Nat Info
   1994  *
   1995  * Return Value:
   1996  *      BCM_E_XXX
   1997  * Notes:
   1998  */
   1999 int  bcm_esw_l3_nat_egress_stat_detach (
   2000                             int                 unit,
   2001                             bcm_l3_nat_egress_t	*info)
   2002 {
   2003 int     rv = BCM_E_UNAVAIL;
   2004 
   2005 #if defined(BCM_TRIDENT2_SUPPORT)
   2006     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2007         rv = _bcm_td2_l3_nat_egress_stat_detach (unit, info);
   2008     } 
   2009 #endif
   2010     return rv;
   2011 }
   2012 
   2013 /*
   2014  * Function:
   2015  *      _bcm_esw_l3_nat_egress_stat_counter_get
   2016  *
   2017  * Description:
   2018  *  Get l3 egress nat counter value for specified l3 egress nat index
   2019  *  if sync_mode is set, sync the sw accumulated count
   2020  *  with hw count value first, else return sw count.  
   2021  *
   2022  * Parameters:
   2023  *      unit             - (IN) unit number
   2024  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   2025  *      info			 - (IN)  Egress Nat Info
   2026  *      stat             - (IN) l3 egress nat counter stat types
   2027  *      num_entries      - (IN) Number of counter Entries
   2028  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   2029  *      counter_values   - (OUT) Pointer to counter values
   2030  *
   2031  * Return Value:
   2032  *      BCM_E_XXX
   2033  * Notes:
   2034  */
   2035  bcm_error_t  
   2036  _bcm_esw_l3_nat_egress_stat_counter_get(int                 unit, 
   2037                                          int                 sync_mode, 
   2038                                          bcm_l3_nat_egress_t	*info,
   2039                                          bcm_l3_nat_egress_stat_t    stat, 
   2040                                          uint32              num_entries, 
   2041                                          uint32              *counter_indexes, 
   2042                                          bcm_stat_value_t    *counter_values)
   2043 {
   2044 int     rv = BCM_E_UNAVAIL;
   2045 
   2046 #if defined(BCM_TRIDENT2_SUPPORT)
   2047     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2048         rv = _bcm_td2_l3_nat_egress_stat_counter_get(unit, sync_mode,
   2049                                                      info, stat, num_entries, 
   2050                                                      counter_indexes, 
   2051                                                      counter_values);
   2052     } 
   2053 #endif
   2054     return rv;
   2055 }
   2056 
   2057 /*
   2058  * Function:
   2059  *      bcm_esw_l3_nat_egress_stat_counter_get
   2060  *
   2061  * Description:
   2062  *  Get l3 egress nat counter value for specified l3 egress nat index
   2063  *
   2064  * Parameters:
   2065  *      unit             - (IN) unit number
   2066  *      info			 - (IN)  Egress Nat Info
   2067  *      stat             - (IN) l3 egress nat counter stat types
   2068  *      num_entries      - (IN) Number of counter Entries
   2069  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   2070  *      counter_values   - (OUT) Pointer to counter values
   2071  *
   2072  * Return Value:
   2073  *      BCM_E_XXX
   2074  * Notes:
   2075  */
   2076  int  
   2077  bcm_esw_l3_nat_egress_stat_counter_get(int                 unit, 
   2078                                         bcm_l3_nat_egress_t	*info,
   2079                                         bcm_l3_nat_egress_stat_t    stat, 
   2080                                         uint32              num_entries, 
   2081                                         uint32              *counter_indexes, 
   2082                                         bcm_stat_value_t    *counter_values)
   2083 {
   2084     return _bcm_esw_l3_nat_egress_stat_counter_get(unit, 0, info, 
   2085                                                    stat, num_entries, 
   2086                                                    counter_indexes, 
   2087                                                    counter_values);
   2088 }
   2089 
   2090 /*
   2091  * Function:
   2092  *      bcm_esw_l3_nat_egress_stat_counter_sync_get
   2093  *
   2094  * Description:
   2095  *  Get l3 egress nat counter value for specified l3 egress nat index
   2096  *  sw accumulated counters synced with hw count.
   2097  *
   2098  * Parameters:
   2099  *      unit             - (IN) unit number
   2100  *      info			 - (IN)  Egress Nat Info
   2101  *      stat             - (IN) l3 egress nat counter stat types
   2102  *      num_entries      - (IN) Number of counter Entries
   2103  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   2104  *      counter_values   - (OUT) Pointer to counter values
   2105  *
   2106  * Return Value:
   2107  *      BCM_E_XXX
   2108  * Notes:
   2109  */
   2110  int  
   2111  bcm_esw_l3_nat_egress_stat_counter_sync_get(int                 unit, 
   2112                                             bcm_l3_nat_egress_t	*info,
   2113                                             bcm_l3_nat_egress_stat_t stat, 
   2114                                             uint32           num_entries, 
   2115                                             uint32           *counter_indexes, 
   2116                                             bcm_stat_value_t *counter_values)
   2117 {
   2118     return _bcm_esw_l3_nat_egress_stat_counter_get(unit, 1, info, 
   2119                                                    stat, num_entries, 
   2120                                                    counter_indexes, 
   2121                                                    counter_values);
   2122 }
   2123 
   2124 /*
   2125  * Function:
   2126  *      bcm_esw_l3_nat_egress_stat_counter_set
   2127  *
   2128  * Description:
   2129  *  Set l3 egress nat counter value for specified l3 egress nat index
   2130  *
   2131  * Parameters:
   2132  *      unit             - (IN) unit number
   2133  *      info			 - (IN) Egress Nat Info
   2134  *      stat             - (IN) l3 egress nat counter stat types
   2135  *      num_entries      - (IN) Number of counter Entries
   2136  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   2137  *      counter_values   - (OUT) Pointer to counter values
   2138  *
   2139  * Return Value:
   2140  *      BCM_E_XXX
   2141  * Notes:
   2142  */
   2143 int  bcm_esw_l3_nat_egress_stat_counter_set(
   2144                             int                 unit, 
   2145                             bcm_l3_nat_egress_t	*info,
   2146                             bcm_l3_nat_egress_stat_t  stat, 
   2147                             uint32              num_entries, 
   2148                             uint32              *counter_indexes, 
   2149                             bcm_stat_value_t    *counter_values)
   2150 {
   2151 int     rv = BCM_E_UNAVAIL;
   2152 
   2153 #if defined(BCM_TRIDENT2_SUPPORT)
   2154     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2155         rv = _bcm_td2_l3_nat_egress_stat_counter_set (
   2156                     unit, info, stat, num_entries, 
   2157                     counter_indexes, counter_values);
   2158     } 
   2159 #endif
   2160     return rv;
   2161 }
   2162 
   2163 /*
   2164  * Function:
   2165  *      bcm_esw_l3_nat_egress_stat_multi_get
   2166  *
   2167  * Description:
   2168  *  Get Multiple l3 egress nat counter value for specified l3 egress nat index for multiple stat
   2169  *  types
   2170  *
   2171  * Parameters:
   2172  *      unit             - (IN) unit number
   2173  *      info			 - (IN) Egress Nat Info
   2174  *      nstat            - (IN) Number of elements in stat array
   2175  *      stat_arr         - (IN) Collected statistics descriptors array
   2176  *      value_arr        - (OUT) Collected counters values
   2177  *
   2178  * Return Value:
   2179  *      BCM_E_XXX
   2180  * Notes:
   2181  */
   2182 
   2183     
   2184 int  bcm_esw_l3_nat_egress_stat_multi_get(
   2185                             int                 unit, 
   2186                             bcm_l3_nat_egress_t	*info,
   2187                             int                 nstat, 
   2188                             bcm_l3_nat_egress_stat_t  *stat_arr,
   2189                             uint64              *value_arr)
   2190 {
   2191 int     rv = BCM_E_UNAVAIL;
   2192 
   2193 #if defined(BCM_TRIDENT2_SUPPORT)
   2194     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2195         rv = _bcm_td2_l3_nat_egress_stat_multi_get (
   2196                     unit, info, nstat, stat_arr, value_arr);
   2197     } 
   2198 #endif
   2199     return rv;
   2200 }
   2201 
   2202 /*
   2203  * Function:
   2204  *      bcm_esw_l3_nat_egress_stat_multi_get32
   2205  *
   2206  * Description:
   2207  *  Get 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat
   2208  *  types
   2209  *
   2210  * Parameters:
   2211  *      unit             - (IN) unit number
   2212  *      info		 	 - (IN) Egress Nat Info
   2213  *      nstat            - (IN) Number of elements in stat array
   2214  *      stat_arr         - (IN) Collected statistics descriptors array
   2215  *      value_arr        - (OUT) Collected counters values
   2216  *
   2217  * Return Value:
   2218  *      BCM_E_XXX
   2219  * Notes:
   2220  */
   2221 int  bcm_esw_l3_nat_egress_stat_multi_get32(
   2222                             int                 unit, 
   2223                             bcm_l3_nat_egress_t	*info,
   2224                             int                 nstat, 
   2225                             bcm_l3_nat_egress_stat_t  *stat_arr,
   2226                             uint32              *value_arr)
   2227 {
   2228 int     rv = BCM_E_UNAVAIL;
   2229 
   2230 #if defined(BCM_TRIDENT2_SUPPORT)
   2231     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2232        rv = _bcm_td2_l3_nat_egress_stat_multi_get32 (
   2233                     unit, info, nstat, stat_arr, value_arr);
   2234     } 
   2235 #endif
   2236     return rv;
   2237 }
   2238 
   2239 /*
   2240  * Function:
   2241  *      bcm_esw_l3_nat_egress_stat_multi_set
   2242  *
   2243  * Description:
   2244  *  Set l3 egress nat counter value for specified l3 egress nat index for multiple stat
   2245  *  types
   2246  *
   2247  * Parameters:
   2248  *      unit             - (IN) unit number
   2249  *      info			 - (IN) Egress Nat Info
   2250  *      stat             - (IN) l3 egress nat counter stat types
   2251  *      num_entries      - (IN) Number of counter Entries
   2252  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   2253  *      counter_values   - (OUT) Pointer to counter values
   2254  *
   2255  * Return Value:
   2256  *      BCM_E_XXX
   2257  * Notes:
   2258  */
   2259 int  bcm_esw_l3_nat_egress_stat_multi_set(
   2260                             int                 unit, 
   2261                             bcm_l3_nat_egress_t	*info,
   2262                             int                 nstat, 
   2263                             bcm_l3_nat_egress_stat_t    *stat_arr,
   2264                             uint64              *value_arr)
   2265 {
   2266 int     rv = BCM_E_UNAVAIL;
   2267 
   2268 #if defined(BCM_TRIDENT2_SUPPORT)
   2269     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2270         rv = _bcm_td2_l3_nat_egress_stat_multi_set (
   2271                     unit, info, nstat, stat_arr, value_arr);
   2272     } 
   2273 #endif
   2274     return rv;
   2275 }
   2276 
   2277 /*
   2278  * Function:
   2279  *      bcm_esw_l3_nat_egress_stat_multi_set32
   2280  *
   2281  * Description:
   2282  *  Set 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat
   2283  *  types
   2284  *
   2285  * Parameters:
   2286  *      unit             - (IN) unit number
   2287  *      info			 - (IN) Egress Nat Info
   2288  *      stat             - (IN) l3 egress nat counter stat types
   2289  *      num_entries      - (IN) Number of counter Entries
   2290  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   2291  *      counter_values   - (OUT) Pointer to counter values
   2292  *
   2293  * Return Value:
   2294  *      BCM_E_XXX
   2295  * Notes:
   2296  */
   2297 
   2298 int  bcm_esw_l3_nat_egress_stat_multi_set32(
   2299                             int                 unit, 
   2300                             bcm_l3_nat_egress_t	*info,
   2301                             int                 nstat, 
   2302                             bcm_l3_nat_egress_stat_t    *stat_arr,
   2303                             uint32              *value_arr)
   2304 {
   2305 int     rv = BCM_E_UNAVAIL;
   2306 
   2307 #if defined(BCM_TRIDENT2_SUPPORT)
   2308     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2309         rv = _bcm_td2_l3_nat_egress_stat_multi_set32 (
   2310                     unit, info, nstat, stat_arr, value_arr);
   2311     } 
   2312 #endif
   2313     return rv;
   2314 }
   2315 
   2316 /*
   2317  * Function: 
   2318  *      bcm_esw_l3_nat_egress_stat_id_get
   2319  *
   2320  * Description: 
   2321  *      Get Stat Counter if associated with given l3 egress nat index
   2322  *
   2323  * Parameters: 
   2324  *      unit             - (IN) bcm device
   2325  *      info			 - (IN) Egress Nat Info
   2326  *      stat             - (IN) l3 egress nat counter stat types
   2327  *      stat_counter_id  - (IN) Stat Counter ID.
   2328  *
   2329  * Returns:
   2330  *      BCM_E_NONE - Success
   2331  *      BCM_E_XXX
   2332  * Notes:
   2333  */
   2334 
   2335 int  bcm_esw_l3_nat_egress_stat_id_get(
   2336                             int                 unit,
   2337                             bcm_l3_nat_egress_t	*info,
   2338                             bcm_l3_nat_egress_stat_t    stat, 
   2339                             uint32              *stat_counter_id) 
   2340 {
   2341 int     rv = BCM_E_UNAVAIL;
   2342 
   2343 #if defined(BCM_TRIDENT2_SUPPORT)
   2344     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   2345         rv = _bcm_td2_l3_nat_egress_stat_id_get (
   2346                     unit, info, stat, stat_counter_id);
   2347     } 
   2348 #endif
   2349     return rv;
   2350 }
   2351 
   2352 #if defined(BCM_TRIDENT2_SUPPORT)
   2353 /* Convert from hw to sw representation of memory based on the type of ingress
   2354  * NAT table 
   2355  */
   2356 static int
   2357 _bcm_td2_l3_nat_ingress_hw_to_sw(int unit, soc_mem_t mem, void *key, 
   2358                                  bcm_l3_nat_ingress_t *result)
   2359 {
   2360     int keyt0, keyt1;
   2361     uint32 dest_type = 0;
   2362 
   2363     if (NULL == result) {
   2364         return BCM_E_PARAM;
   2365     }
   2366     sal_memset(result, 0, sizeof(*result));
   2367 
   2368     switch (mem) {
   2369     case ING_DNAT_ADDRESS_TYPEm:
   2370         if (soc_feature(unit, soc_feature_base_valid)) {
   2371             if (!soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, BASE_VALIDf)) {
   2372                 return BCM_E_EMPTY;
   2373             }
   2374         } else {
   2375         if (!soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, VALIDf)) {
   2376             return BCM_E_EMPTY;
   2377         }
   2378         }
   2379         result->flags |= (BCM_L3_NAT_INGRESS_DNAT | BCM_L3_NAT_INGRESS_DNAT_POOL);
   2380         result->ip_addr = 
   2381             soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, DEST_IPV4_ADDRf);
   2382         result->vrf = 
   2383             soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, VRFf);
   2384         if (soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, POOL_ADDRESS_TYPEf))
   2385         {
   2386             result->flags |= BCM_L3_NAT_INGRESS_TYPE_NAPT;
   2387         }
   2388         break;
   2389 
   2390     case ING_SNATm:
   2391         if (!soc_ING_SNATm_field32_get(unit, key, VALIDf)) {
   2392             return BCM_E_EMPTY;
   2393         }
   2394         result->ip_addr =
   2395                  soc_ING_SNATm_field32_get(unit, key, IP_ADDRESSf);
   2396         result->vrf =
   2397                  soc_ING_SNATm_field32_get(unit, key, VRFf);
   2398         if (soc_mem_field32_get(unit, mem, key, NAT_TYPE_NAPTf)) {
   2399             if (soc_ING_SNATm_field32_get(unit, key, L4_VALIDf)) {
   2400                 /* assume other fields are correctly masked */
   2401                 result->flags |= BCM_L3_NAT_INGRESS_TYPE_NAPT;
   2402                 result->l4_port = 
   2403                     soc_ING_SNATm_field32_get(unit, key, L4_SRC_PORTf);
   2404                 result->ip_proto = 
   2405                     soc_ING_SNATm_field32_get(unit, key, IP_PROTOf);
   2406             } else {
   2407                 /* something wrong with the entry */
   2408                 return BCM_E_INTERNAL;
   2409             }
   2410         }
   2411         result->nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET(
   2412                         soc_ING_SNATm_field32_get(unit, key, NAT_PACKET_EDIT_IDXf),
   2413                   soc_ING_SNATm_field32_get(unit, key, NAT_PACKET_EDIT_ENTRY_SELf));
   2414         if (soc_ING_SNATm_field32_get(unit, key, HITf)) {
   2415             result->flags |= BCM_L3_NAT_INGRESS_HIT;
   2416         }
   2417         break;
   2418 
   2419     case L3_ENTRY_IPV4_MULTICASTm:
   2420     case L3_ENTRY_DOUBLEm: 
   2421         if (soc_feature(unit, soc_feature_base_valid)) {
   2422             if (!(soc_L3_ENTRY_DOUBLEm_field32_get(unit, key, BASE_VALID_0f) &&
   2423                 soc_L3_ENTRY_DOUBLEm_field32_get(unit, key, BASE_VALID_1f))) {
   2424                 return BCM_E_EMPTY;
   2425             }
   2426         } else {
   2427             if (!(soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, key, VALID_0f) &&
   2428                 soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, key, VALID_1f))) {
   2429                 return BCM_E_EMPTY;
   2430             }
   2431         }
   2432         
   2433         /* check key type also. Needs to be either NAT or NAPT */
   2434 
   2435         if ( mem == L3_ENTRY_DOUBLEm) {
   2436             keyt0 = soc_mem_field32_get(unit, mem, key, KEY_TYPEf);
   2437             keyt1 = soc_mem_field32_get(unit, mem, key, KEY_TYPEf);
   2438         } else {
   2439             keyt0 = soc_mem_field32_get(unit, mem, key, KEY_TYPE_0f);
   2440             keyt1 = soc_mem_field32_get(unit, mem, key,KEY_TYPE_1f);
   2441         }
   2442         result->flags |= BCM_L3_NAT_INGRESS_DNAT;
   2443         result->ip_addr =
   2444                  soc_mem_field32_get(unit, mem, key, NAT__IP_ADDRf);
   2445         result->vrf = 
   2446                  soc_mem_field32_get(unit, mem, key, NAT__VRF_IDf);
   2447         if (soc_mem_field32_get(unit, mem, key, NAT__L4_VALIDf)) {
   2448             if ((keyt0 != TD2_L3_HASH_KEY_TYPE_DST_NAPT) ||
   2449                 (keyt1 != TD2_L3_HASH_KEY_TYPE_DST_NAPT)) {
   2450                 return BCM_E_EMPTY;
   2451             }
   2452             result->flags |= BCM_L3_NAT_INGRESS_TYPE_NAPT;
   2453             
   2454             result->l4_port = 
   2455                  soc_mem_field32_get(unit, mem, key, NAT__L4_DEST_PORTf);
   2456             result->ip_proto = 
   2457                  soc_mem_field32_get(unit, mem, key, NAT__IP_PROTOf);
   2458         } else {
   2459             if ((keyt0 != TD2_L3_HASH_KEY_TYPE_DST_NAT) ||
   2460                 (keyt1 != TD2_L3_HASH_KEY_TYPE_DST_NAT)) {
   2461                 return BCM_E_EMPTY;
   2462             }
   2463         }
   2464         if (soc_mem_field32_get(unit, mem, key, HIT_0f) &&
   2465             soc_mem_field32_get(unit, mem, key, HIT_1f)) {
   2466             result->flags |= BCM_L3_NAT_INGRESS_HIT;
   2467         }
   2468 
   2469         if (soc_feature(unit, soc_feature_generic_dest)) {
   2470             result->nexthop = soc_mem_field32_dest_get(unit, mem, key, NAT__DESTINATIONf,
   2471                               &dest_type) ;
   2472             if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   2473                 result->flags |= BCM_L3_NAT_INGRESS_MULTIPATH;
   2474                 result->nexthop += BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   2475             } else {
   2476                 result->nexthop += BCM_XGS3_EGRESS_IDX_MIN(unit);
   2477             }
   2478         } else {
   2479             if (soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, key, NAT__ECMPf)) {
   2480                 result->flags |= BCM_L3_NAT_INGRESS_MULTIPATH;
   2481                 result->nexthop = soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, 
   2482                               key, NAT__ECMP_PTRf)
   2483                               + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   2484             } else {
   2485                 result->nexthop = soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, 
   2486                               key, NAT__NEXT_HOP_INDEXf)
   2487                               + BCM_XGS3_EGRESS_IDX_MIN(unit);
   2488             }
   2489         }
   2490         if (soc_mem_field32_get(unit, mem, key, NAT__DST_DISCARDf)) {
   2491             result->flags |= BCM_L3_NAT_INGRESS_DST_DISCARD;
   2492         }
   2493         
   2494         if (soc_mem_field32_get(unit, mem, key, NAT__RPEf)) {
   2495             result->flags |= BCM_L3_NAT_INGRESS_RPE;
   2496             result->pri = soc_mem_field32_get(unit, mem,  key, NAT__PRIf); 
   2497         }
   2498         result->class_id = soc_mem_field32_get(unit, mem, key, NAT__CLASS_IDf);
   2499         result->nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET(
   2500                 soc_mem_field32_get(unit, mem, key, NAT__PACKET_EDIT_IDXf),
   2501                 soc_mem_field32_get(unit, mem, key, NAT__PACKET_EDIT_ENTRY_SELf));
   2502         break;
   2503 
   2504     default:
   2505         return BCM_E_PARAM;
   2506     }
   2507     return BCM_E_NONE;
   2508 }
   2509 
   2510 static int
   2511 _bcm_td2_l3_nat_ingress_hit_update(int unit, soc_mem_t mem, int index, 
   2512                                  bcm_l3_nat_ingress_t *result)
   2513 {
   2514     uint32 hit;
   2515     ing_snat_hit_only_x_entry_t snat_hit_x;
   2516     ing_snat_hit_only_y_entry_t snat_hit_y;
   2517     l3_entry_hit_only_x_entry_t l3_hit_x;
   2518     l3_entry_hit_only_y_entry_t l3_hit_y;
   2519     l3_entry_hit_only_entry_t l3_hit_default;
   2520     int idx, idx_max, idx_offset, hit_idx_shift;
   2521     soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f};
   2522 
   2523     switch (mem) {
   2524     case ING_DNAT_ADDRESS_TYPEm:
   2525         break;
   2526 
   2527     case ING_SNATm:
   2528         BCM_IF_ERROR_RETURN(
   2529             BCM_XGS3_MEM_READ(unit, ING_SNAT_HIT_ONLY_Xm,
   2530                                       index, &snat_hit_x));
   2531         BCM_IF_ERROR_RETURN(
   2532             BCM_XGS3_MEM_READ(unit, ING_SNAT_HIT_ONLY_Ym,
   2533                                       index, &snat_hit_y));
   2534         if (soc_ING_SNAT_HIT_ONLY_Xm_field32_get(unit, &snat_hit_x, HITf) ||
   2535             soc_ING_SNAT_HIT_ONLY_Ym_field32_get(unit, &snat_hit_y, HITf)) {
   2536             result->flags |= BCM_L3_NAT_INGRESS_HIT;
   2537         }
   2538         break;
   2539 
   2540     case L3_ENTRY_IPV4_MULTICASTm:
   2541     case L3_ENTRY_DOUBLEm: 
   2542         idx_max = 2;
   2543         hit_idx_shift = 1;
   2544         idx_offset = (index & 0x1) << 1;
   2545 
   2546         if (soc_feature(unit, soc_feature_two_ingress_pipes)) {
   2547             BCM_IF_ERROR_RETURN(
   2548                 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Xm,
   2549                                   (index >> hit_idx_shift), &l3_hit_x));
   2550             BCM_IF_ERROR_RETURN(
   2551                 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Ym,
   2552                                   (index >> hit_idx_shift), &l3_hit_y));
   2553 
   2554             hit = 0;
   2555             for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
   2556                 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Xm,
   2557                                            &l3_hit_x, hitf[idx]);
   2558             }
   2559 
   2560             for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
   2561                 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Ym,
   2562                                            &l3_hit_y, hitf[idx]);
   2563             }
   2564         } else {
   2565             BCM_IF_ERROR_RETURN(
   2566                 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm,
   2567                                   (index >> hit_idx_shift), &l3_hit_default));
   2568 
   2569             hit = 0;
   2570             for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
   2571                 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm,
   2572                                            &l3_hit_default, hitf[idx]);
   2573             }
   2574         }
   2575         if (hit) {
   2576             result->flags |= BCM_L3_NAT_INGRESS_HIT;
   2577         }
   2578         break;
   2579 
   2580     default:
   2581         return BCM_E_PARAM;
   2582     }
   2583 
   2584     return BCM_E_NONE;
   2585 }
   2586 
   2587 static int
   2588 _bcm_td2_l3_nat_ingress_set_nexthop(int unit, soc_mem_t mem, void *hw_buf,
   2589                                     bcm_l3_nat_ingress_t *nat_info) 
   2590 {
   2591     int rv = BCM_E_NONE, nh_idx;
   2592     uint32 mpath_flag = 0;
   2593 
   2594     /* figure out hw index from egress object */
   2595     rv = bcm_xgs3_get_nh_from_egress_object(unit, nat_info->nexthop,
   2596                                         &mpath_flag, 0, &nh_idx);
   2597     
   2598     if (BCM_FAILURE(rv)) {
   2599         return rv;
   2600     }
   2601     /* make sure mpath setting is consistent with input */
   2602     if (nat_info->flags & BCM_L3_NAT_INGRESS_MULTIPATH) {
   2603         if (!mpath_flag) {
   2604             return BCM_E_PARAM;
   2605         }
   2606 
   2607         if (soc_feature(unit, soc_feature_generic_dest)) {
   2608             soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf, 
   2609                            NAT__DESTINATIONf, SOC_MEM_FIF_DEST_ECMP, nh_idx);
   2610         } else {
   2611             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__ECMPf, 
   2612                                                 1);
   2613             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__ECMP_PTRf,
   2614                                                 nh_idx);
   2615        }
   2616     } else {
   2617         if (mpath_flag) {
   2618             return BCM_E_PARAM;
   2619         }
   2620         if (nh_idx != BCM_XGS3_L3_INVALID_INDEX ) {
   2621             if (soc_feature(unit, soc_feature_generic_dest)) {
   2622                 soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf,
   2623                               NAT__DESTINATIONf, SOC_MEM_FIF_DEST_NEXTHOP, nh_idx);
   2624             } else {
   2625                 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__ECMPf, 
   2626                                                      0);
   2627                 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__NEXT_HOP_INDEXf, 
   2628                                                      nh_idx);
   2629             }
   2630         } else {
   2631             return BCM_E_PARAM; 
   2632         }
   2633     }
   2634     return rv;
   2635 }
   2636 
   2637 static int
   2638 _bcm_td2_l3_nat_ingress_sw_to_hw(int unit, soc_mem_t mem, void *hw_buf, 
   2639                                  bcm_l3_nat_ingress_t *nat_info)
   2640 {
   2641     /* Fill out key depending on the memory type */
   2642     uint32 mask_len, mask; 
   2643     int hw_idx, hw_half, key_type,data_type;
   2644     
   2645     if ((NULL == hw_buf) || (NULL == nat_info)) {
   2646         return BCM_E_PARAM;
   2647     }
   2648 
   2649     if (nat_info->nat_id > (NAT_ID_MAX(unit)-1)) {
   2650         return BCM_E_PARAM;
   2651     }
   2652 
   2653     switch (mem) {
   2654     case ING_DNAT_ADDRESS_TYPEm:
   2655         sal_memset(hw_buf, 0, sizeof(ing_dnat_address_type_entry_t));
   2656         soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, DEST_IPV4_ADDRf, 
   2657                                                 nat_info->ip_addr);
   2658         soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, VRFf, 
   2659                                                 nat_info->vrf);
   2660 #ifdef BCM_MONTEREY_SUPPORT
   2661         if (SOC_IS_MONTEREY(unit)) {
   2662             soc_mem_field32_set(unit, mem, hw_buf, DEST_IPV4_ADDR_MASKf,
   2663                     0xffffffff);
   2664 
   2665             soc_ING_SNATm_field32_set(unit, hw_buf, VRFf, nat_info->vrf);
   2666             mask_len = soc_mem_field_length(unit, ING_DNAT_ADDRESS_TYPEm, VRFf);
   2667             mask = (1 << mask_len) - 1;
   2668             soc_mem_field32_set(unit, mem, hw_buf, VRF_MASKf, mask);
   2669         }
   2670 #endif
   2671         /* data portion */
   2672         soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, POOL_ADDRESS_TYPEf,
   2673                         nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT ? 1 : 0);
   2674 
   2675         
   2676         if (soc_feature(unit, soc_feature_base_valid)) {
   2677             soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, BASE_VALIDf, 1);
   2678         } else {
   2679             soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, VALIDf, 1);
   2680         }
   2681         break;
   2682     case ING_SNATm:
   2683         sal_memset(hw_buf, 0, sizeof(ing_snat_entry_t));
   2684         soc_ING_SNATm_field32_set(unit, hw_buf, IP_ADDRESSf, nat_info->ip_addr);
   2685 
   2686         soc_mem_field32_set(unit, mem, hw_buf, IP_ADDRESS_MASKf, 
   2687                                  0xffffffff);
   2688 
   2689         soc_ING_SNATm_field32_set(unit, hw_buf, VRFf, nat_info->vrf);
   2690         mask_len = soc_mem_field_length(unit, ING_SNATm, VRFf);
   2691         mask = (1 << mask_len) - 1;
   2692         soc_mem_field32_set(unit, mem, hw_buf, VRF_MASKf, mask);
   2693 
   2694         if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) {
   2695             soc_ING_SNATm_field32_set(unit, hw_buf, IP_PROTOf, 
   2696                                       nat_info->ip_proto);
   2697             mask_len = soc_mem_field_length(unit, ING_SNATm, IP_PROTOf);
   2698             mask = (1 << mask_len) - 1;
   2699             soc_mem_field32_set(unit, mem, hw_buf, IP_PROTO_MASKf, mask);
   2700 
   2701             soc_ING_SNATm_field32_set(unit, hw_buf, L4_SRC_PORTf,
   2702                                       nat_info->l4_port);
   2703             mask_len = soc_mem_field_length(unit, ING_SNATm, L4_SRC_PORTf);
   2704             mask = (1 << mask_len) - 1;
   2705             soc_mem_field32_set(unit, mem, hw_buf, L4_SRC_PORT_MASKf, 
   2706                                      mask);
   2707 
   2708             soc_ING_SNATm_field32_set(unit, hw_buf, L4_VALIDf, 1);
   2709             mask_len = soc_mem_field_length(unit, ING_SNATm, L4_VALIDf);
   2710             mask = (1 << mask_len) - 1;
   2711             soc_mem_field32_set(unit, mem, hw_buf, L4_VALID_MASKf, mask);
   2712             
   2713             /* data part */
   2714             soc_ING_SNATm_field32_set(unit, hw_buf, NAT_TYPE_NAPTf, 1);
   2715         }
   2716 
   2717         /* data portion */
   2718         BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_info->nat_id, hw_idx, hw_half);
   2719         soc_ING_SNATm_field32_set(unit, hw_buf, NAT_PACKET_EDIT_ENTRY_SELf, 
   2720                                   hw_half);
   2721         soc_ING_SNATm_field32_set(unit, hw_buf, NAT_PACKET_EDIT_IDXf, hw_idx);
   2722         soc_ING_SNATm_field32_set(unit, hw_buf, HITf, 
   2723                          nat_info->flags & BCM_L3_NAT_INGRESS_HIT ? 1 : 0);
   2724         
   2725         soc_ING_SNATm_field32_set(unit, hw_buf, VALIDf, 1);
   2726         
   2727         break;
   2728     case L3_ENTRY_IPV4_MULTICASTm:
   2729 #ifdef BCM_TRIDENT3_SUPPORT
   2730     case L3_ENTRY_DOUBLEm: 
   2731 #endif
   2732         sal_memset(hw_buf, 0, sizeof(l3_entry_only_double_entry_t));
   2733         soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__IP_ADDRf, 
   2734                                                  nat_info->ip_addr);
   2735         soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__VRF_IDf, 
   2736                                                  nat_info->vrf);
   2737         key_type = TD2_L3_HASH_KEY_TYPE_DST_NAT;
   2738         data_type = TD3_L3_HASH_DATA_TYPE_DST_NAT;
   2739 
   2740         if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) {
   2741             soc_mem_field32_set(unit, mem,  (uint32 *)hw_buf, 
   2742                                                      NAT__IP_PROTOf, 
   2743                                                      nat_info->ip_proto);
   2744             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 
   2745                                                      NAT__L4_DEST_PORTf, 
   2746                                                      nat_info->l4_port);
   2747             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 
   2748                                                      NAT__L4_VALIDf, 1);
   2749             key_type = TD2_L3_HASH_KEY_TYPE_DST_NAPT;
   2750             data_type = TD3_L3_HASH_DATA_TYPE_DST_NAPT;
   2751         }
   2752 
   2753         /* data portion */
   2754         if (nat_info->flags & BCM_L3_NAT_INGRESS_DST_DISCARD) {
   2755             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 
   2756                                                 NAT__DST_DISCARDf, 1);
   2757         }
   2758         
   2759         if (nat_info->flags & BCM_L3_NAT_INGRESS_RPE) {
   2760             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__RPEf,1);
   2761             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__PRIf, 
   2762                                                     nat_info->pri);
   2763         }
   2764         soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__CLASS_IDf,
   2765                                                             nat_info->class_id);
   2766         BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_info->nat_id, hw_idx, hw_half);
   2767         soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 
   2768                                     NAT__PACKET_EDIT_ENTRY_SELf, hw_half);
   2769         soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 
   2770                                             NAT__PACKET_EDIT_IDXf, hw_idx);
   2771 
   2772         if (mem == L3_ENTRY_DOUBLEm) {
   2773             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, KEY_TYPEf, 
   2774                                                  key_type);
   2775             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, BASE_VALID_0f, 3);
   2776             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, BASE_VALID_1f, 4);
   2777             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, DATA_TYPEf,
   2778                                                  data_type);
   2779         } else {
   2780             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, KEY_TYPE_0f, 
   2781                                                  key_type);
   2782             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, KEY_TYPE_1f, 
   2783                                                  key_type);
   2784             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, VALID_0f, 1);
   2785             soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, VALID_1f, 1);
   2786         }
   2787         
   2788 
   2789         soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, HIT_0f,
   2790                           nat_info->flags & BCM_L3_NAT_INGRESS_HIT ? 1 : 0);
   2791         soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, HIT_1f, 
   2792                           nat_info->flags & BCM_L3_NAT_INGRESS_HIT ? 1 : 0);
   2793 
   2794         if (soc_feature(unit, soc_feature_generic_dest)) {
   2795             if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, nat_info->nexthop) &&
   2796                    nat_info->flags & BCM_L3_NAT_INGRESS_MULTIPATH) {
   2797                 soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf, NAT__DESTINATIONf,
   2798                                SOC_MEM_FIF_DEST_ECMP, nat_info->nexthop - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit));
   2799             } else if(BCM_XGS3_L3_EGRESS_IDX_VALID(unit, nat_info->nexthop)){
   2800                 soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf, NAT__DESTINATIONf,
   2801                                                      SOC_MEM_FIF_DEST_NEXTHOP,
   2802                                                      nat_info->nexthop - BCM_XGS3_EGRESS_IDX_MIN(unit));
   2803             }
   2804         } else {
   2805             if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, nat_info->nexthop) &&
   2806                       nat_info->flags & BCM_L3_NAT_INGRESS_MULTIPATH) {
   2807                 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, hw_buf, NAT__ECMPf, 1);
   2808                 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, hw_buf, NAT__ECMP_PTRf,
   2809                                                      nat_info->nexthop -
   2810                                                      BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit));
   2811             } else if(BCM_XGS3_L3_EGRESS_IDX_VALID(unit, nat_info->nexthop)){
   2812                 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, hw_buf, NAT__NEXT_HOP_INDEXf,
   2813                                                      nat_info->nexthop -
   2814                                                      BCM_XGS3_EGRESS_IDX_MIN(unit));
   2815            }
   2816         }
   2817         break;
   2818     default:
   2819         return BCM_E_PARAM;
   2820     }
   2821     return BCM_E_NONE;
   2822 }
   2823 #ifdef BCM_MONTEREY_SUPPORT
   2824 
   2825 /* helper function that compares the int_dnat_address_type entries */
   2826 static int
   2827 _bcm_mn_l3_nat_ing_dnat_address_type_cmp(int unit, bcm_l3_nat_ingress_t *snat_entry,
   2828                                           bcm_l3_nat_ingress_t *hw_snat_entry)
   2829 {
   2830     if (snat_entry->ip_addr != hw_snat_entry->ip_addr) {
   2831         return BCM_E_FAIL;
   2832     }
   2833     if (snat_entry->vrf != hw_snat_entry->vrf) {
   2834         return BCM_E_FAIL;
   2835     }
   2836     return BCM_E_NONE;
   2837 }
   2838 
   2839 /* helper function that lookup an entry in the int_dnat_address_type table */
   2840 static int
   2841 _bcm_mn_l3_nat_ing_dnat_address_type_lookup(int unit, bcm_l3_nat_ingress_t *nat_info,
   2842                                              void *key, int *index, void *result)
   2843 {
   2844     ing_dnat_address_type_entry_t *dnat_address_type_entryp;
   2845     bcm_l3_nat_ingress_t hw_nat_info;
   2846     soc_mem_t   mem = ING_DNAT_ADDRESS_TYPEm;
   2847     char *tbl = NULL;
   2848     int start_idx, end_idx, i, rv, tbl_count;
   2849 
   2850     dnat_address_type_entryp = (ing_dnat_address_type_entry_t *) key;
   2851 
   2852     /* dma memory */
   2853     rv = _bcm_td2_l3_nat_read_mem(unit, mem, sizeof(*dnat_address_type_entryp), "ing dnat address type",
   2854                                   &tbl, &tbl_count);
   2855 
   2856     /* search NAT part */
   2857     start_idx = soc_mem_index_min(unit, mem);
   2858     end_idx = BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit);
   2859 
   2860     for (i = start_idx; i < end_idx; i++) {
   2861         dnat_address_type_entryp = soc_mem_table_idx_to_pointer(unit, mem,
   2862                                                    ing_dnat_address_type_entry_t *, tbl, i);
   2863         /* compare the dmaed entry with input key */
   2864         rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, (void *) dnat_address_type_entryp,
   2865                                               &hw_nat_info);
   2866         if (!BCM_SUCCESS(rv)) {
   2867             /* had trouble converting. Likely a mismatch anyway */
   2868             continue;
   2869         }
   2870         rv = _bcm_mn_l3_nat_ing_dnat_address_type_cmp(unit, nat_info, &hw_nat_info);
   2871         if (BCM_SUCCESS(rv)) {
   2872             break;
   2873         }
   2874     }
   2875     if (i == end_idx) {
   2876         rv =  BCM_E_NOT_FOUND;
   2877     } else {
   2878         rv = BCM_E_NONE;
   2879     }
   2880     *index = i;
   2881     /* copy entry into result pointer */
   2882     if (BCM_SUCCESS(rv)) {
   2883         sal_memcpy(result, dnat_address_type_entryp, sizeof(*dnat_address_type_entryp));
   2884     }
   2885     /* free dmaed table memory */
   2886     soc_cm_sfree(unit, tbl);
   2887 
   2888     return rv;
   2889 }
   2890 /* Just do plain addition. Replacement already done in caller. */
   2891 static int
   2892 _bcm_mn_l3_nat_ing_dnat_address_type_entry_add(int unit, soc_mem_t mem,
   2893                                                 bcm_l3_nat_ingress_t *nat_info,
   2894                                                 ing_dnat_address_type_entry_t *entryp)
   2895 {
   2896     int rv;
   2897     int idx, new_idx, *idx_ptr;
   2898 
   2899     /* New entry. Not duplicate. */
   2900     /* check if space is available */
   2901     if (BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) >
   2902         soc_mem_index_max(unit, ING_DNAT_ADDRESS_TYPEm))  {
   2903         return BCM_E_FULL;
   2904     }
   2905 
   2906     BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, entryp,
   2907                                                          nat_info));
   2908 
   2909     idx = BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit);
   2910     idx_ptr = &BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit);
   2911     new_idx = idx + 1;
   2912     /* coverity[negative_returns : FALSE] */
   2913     rv = soc_mem_write(unit, mem, COPYNO_ALL, idx, entryp);
   2914     if (SOC_SUCCESS(rv)) {
   2915         *idx_ptr = new_idx;
   2916         return BCM_E_NONE;
   2917     }
   2918     return BCM_E_FAIL;
   2919 }
   2920 
   2921 /* helper function that deletes an entry from the int_dnat_address_type table */
   2922 static int
   2923 _bcm_mn_l3_nat_ing_dnat_address_type_entry_delete(int unit, soc_mem_t mem,
   2924                                                    bcm_l3_nat_ingress_t *nat_info,
   2925                                                    void *key)
   2926 {
   2927     int index = -1, rv;
   2928     int last_idx, *idx_ptr;
   2929     ing_dnat_address_type_entry_t last_entry;
   2930 
   2931     /* lookup entry. */
   2932     rv = _bcm_mn_l3_nat_ing_dnat_address_type_lookup(unit, nat_info, key, &index, key);
   2933 
   2934     if (!BCM_SUCCESS(rv)) {
   2935         return rv;
   2936     }
   2937 
   2938     /* copy last valid entry into this entry index */
   2939     /* get last ing_dnat_address_type entry index */
   2940     last_idx = BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) - 1;
   2941     idx_ptr = &BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit);
   2942 
   2943     /* read last entry */
   2944     rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, last_idx, &last_entry);
   2945 
   2946     if (!SOC_SUCCESS(rv)) {
   2947         return BCM_E_INTERNAL;
   2948     }
   2949 
   2950     /* write it into the entry to be deleted */
   2951     /* coverity[negative_returns : FALSE] */
   2952     rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &last_entry);
   2953     if (!SOC_SUCCESS(rv)) {
   2954         return BCM_E_INTERNAL;
   2955     }
   2956 
   2957     /* delete last entry */
   2958     sal_memset(&last_entry, 0, sizeof(last_entry));
   2959     rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, last_idx, &last_entry);
   2960     if (!SOC_SUCCESS(rv)) {
   2961         return BCM_E_INTERNAL;
   2962     }
   2963 
   2964     /* update free index */
   2965     *idx_ptr = last_idx;
   2966     return BCM_E_NONE;
   2967 }
   2968 #endif
   2969 static int
   2970 _bcm_td2_l3_nat_ing_snat_cmp(int unit, bcm_l3_nat_ingress_t *snat_entry, 
   2971                              bcm_l3_nat_ingress_t *hw_snat_entry)
   2972 {
   2973     /* filter out flags which are not relevant for match */
   2974     if ((snat_entry->flags & ~(BCM_L3_NAT_INGRESS_HIT | BCM_L3_NAT_INGRESS_REPLACE))
   2975        != (hw_snat_entry->flags & ~BCM_L3_NAT_INGRESS_HIT)) {
   2976         return BCM_E_FAIL;
   2977     }
   2978     if (snat_entry->ip_addr != hw_snat_entry->ip_addr) {
   2979         return BCM_E_FAIL;
   2980     }
   2981     if (snat_entry->vrf != hw_snat_entry->vrf) {
   2982         return BCM_E_FAIL;
   2983     }
   2984     if (snat_entry->vrf != hw_snat_entry->vrf) {
   2985         return BCM_E_FAIL;
   2986     }
   2987     if (!(snat_entry->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT)) {
   2988         return BCM_E_NONE;
   2989     }
   2990     if (snat_entry->ip_proto != hw_snat_entry->ip_proto) {
   2991         return BCM_E_FAIL;
   2992     }
   2993     if (snat_entry->l4_port != hw_snat_entry->l4_port) {
   2994         return BCM_E_FAIL;
   2995     }
   2996     return BCM_E_NONE;
   2997 }
   2998 
   2999 
   3000 
   3001 static int
   3002 _bcm_td2_l3_nat_ing_snat_lookup(int unit, bcm_l3_nat_ingress_t *nat_info, 
   3003                                 void *key, int *index, void *result)
   3004 {
   3005     ing_snat_entry_t *snat_entryp;
   3006     bcm_l3_nat_ingress_t hw_nat_info;
   3007     soc_mem_t   mem = ING_SNATm;
   3008     char *tbl = NULL;
   3009     int start_idx, end_idx, i, rv, tbl_count;
   3010 
   3011     snat_entryp = (ing_snat_entry_t *) key;
   3012 #if 0
   3013     /* already done in caller */
   3014     rv = _bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, &snat_entry, nat_info);
   3015 #endif
   3016 
   3017     /* dma memory */
   3018     rv = _bcm_td2_l3_nat_read_mem(unit, mem, sizeof(*snat_entryp), "ing snat", 
   3019                                   &tbl, &tbl_count);
   3020 
   3021     if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) {
   3022         /* search NAPT part */
   3023         start_idx = BCM_NAT_EGRESS_ID_MIN(unit);
   3024         end_idx = BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit);
   3025     } else {
   3026         /* search NAT part */
   3027         start_idx = BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) + 1;
   3028         end_idx = soc_mem_index_max(unit, mem) + 1;
   3029     }  
   3030     for (i = start_idx; i < end_idx; i++) {
   3031         snat_entryp = soc_mem_table_idx_to_pointer(unit, mem, 
   3032                                                    ing_snat_entry_t *, tbl, i);
   3033         /* compare the dmaed entry with input key */
   3034         rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, (void *) snat_entryp, 
   3035                                               &hw_nat_info);
   3036         if (!BCM_SUCCESS(rv)) {
   3037             /* had trouble converting. Likely a mismatch anyway */
   3038             continue;
   3039         }
   3040         rv = _bcm_td2_l3_nat_ing_snat_cmp(unit, nat_info, &hw_nat_info); 
   3041         if (BCM_SUCCESS(rv)) {
   3042             break;
   3043         }
   3044     }
   3045     if (i == end_idx) {
   3046         rv =  BCM_E_NOT_FOUND;
   3047     } else {
   3048         rv = BCM_E_NONE;
   3049     }
   3050     *index = i;
   3051     /* copy entry into result pointer */
   3052     if (BCM_SUCCESS(rv)) {
   3053         sal_memcpy(result, snat_entryp, sizeof(*snat_entryp));
   3054     }
   3055     /* free dmaed table memory */
   3056     soc_cm_sfree(unit, tbl);
   3057 
   3058     return rv;
   3059 }
   3060 static int
   3061 _bcm_td2_l3_nat_search_ing_mems(int unit, soc_mem_t mem, 
   3062                                 bcm_l3_nat_ingress_t *nat_info, 
   3063                                 int *index, void *key, void *result)
   3064 {
   3065     int rv = 0;
   3066     
   3067     if (NULL == key || NULL == result) {
   3068         return BCM_E_PARAM;
   3069     }
   3070     
   3071     rv = _bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, key, nat_info);
   3072     if (!BCM_SUCCESS(rv)) {
   3073         return rv;
   3074     }
   3075 
   3076     /* launch lookup */
   3077     if (mem == ING_SNATm) {
   3078         rv = _bcm_td2_l3_nat_ing_snat_lookup(unit, nat_info, key, index, result);
   3079     } else {
   3080 #ifdef BCM_MONTEREY_SUPPORT
   3081         if (SOC_IS_MONTEREY(unit) &&
   3082                 (mem == ING_DNAT_ADDRESS_TYPEm)) {
   3083             rv = _bcm_mn_l3_nat_ing_dnat_address_type_lookup(unit, nat_info, key, index, result);
   3084         } else
   3085 #endif
   3086         {
   3087             rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, index, key, result, 0);
   3088             if (rv != SOC_E_NONE) {
   3089                 return BCM_E_NOT_FOUND;
   3090             }
   3091         }
   3092     }
   3093     return rv;
   3094 }
   3095 
   3096 
   3097 
   3098 /* helper function that deletes entries from the ingress SNAT/DNAT table. Just
   3099    an intermediary function to all the delete api function */
   3100 int
   3101 _bcm_td2_l3_nat_ingress_delete_entry(int unit, int idx, 
   3102                                           bcm_l3_nat_ingress_t *nat_info, 
   3103                                           void *user_data)
   3104 {
   3105     return bcm_esw_l3_nat_ingress_delete(unit, nat_info);
   3106 }
   3107 
   3108 int
   3109 _bcm_td2_l3_nat_ingress_age_entry(int unit, int idx, 
   3110                                   bcm_l3_nat_ingress_t *nat_info,
   3111                                   void *user_data)
   3112 {
   3113     /* Extract original user data */   
   3114     bcm_l3_nat_ingress_cb_context_t *user_context;
   3115     int rv = BCM_E_NONE;
   3116     uint32              hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   3117 
   3118 
   3119     sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   3120 
   3121     if ((NULL == nat_info) || (NULL == user_data)) {
   3122         return BCM_E_PARAM;
   3123     }
   3124 
   3125     user_context = (bcm_l3_nat_ingress_cb_context_t *) user_data;
   3126 
   3127     
   3128     /* if HIT bit set then clear it */
   3129     if (nat_info->flags & BCM_L3_NAT_INGRESS_HIT) {
   3130         nat_info->flags &= (~BCM_L3_NAT_INGRESS_HIT);
   3131         rv = _bcm_td2_l3_nat_ingress_sw_to_hw(unit, user_context->mem, hw_buf, 
   3132                                               nat_info);
   3133         if (!BCM_SUCCESS(rv)) {
   3134             return rv;
   3135         }
   3136         /* write entry with cleared hit bit to hw */
   3137         rv = soc_mem_write(unit, user_context->mem, COPYNO_ALL, idx, hw_buf);
   3138     } else {
   3139         /* hit bit already cleared. Delete it */
   3140         rv =  bcm_esw_l3_nat_ingress_delete(unit, nat_info);
   3141     } 
   3142 
   3143     /* call user callback */
   3144     if ((BCM_SUCCESS(rv)) && (user_context->user_cb)) {
   3145         rv = (*(user_context->user_cb))(unit, idx, nat_info, 
   3146                                         user_context->user_data);
   3147     }
   3148 
   3149     return rv; 
   3150 }
   3151 
   3152 
   3153 /* Just do plain addition. Replacement already done in caller. */
   3154 static int
   3155 _bcm_td2_l3_nat_ingress_snat_entry_add(int unit, soc_mem_t mem, 
   3156                                        bcm_l3_nat_ingress_t *nat_info,
   3157                                        ing_snat_entry_t *snat_entryp)
   3158 {
   3159     int rv;
   3160     int idx, new_idx, *idx_ptr;
   3161 
   3162     /* NAPT entries occupy upper side of table, NAT entries occupy lower side
   3163        to ensure NAPT gets higher priority match */
   3164     /* New entry. Not duplicate. */
   3165     /* check if space is available */
   3166     if (BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) > 
   3167         BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit))  {
   3168         return BCM_E_FULL;
   3169     }
   3170 
   3171     if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) {
   3172         idx = BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit);
   3173         idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit);
   3174         new_idx = idx + 1;
   3175     } else {
   3176         idx = BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit);
   3177         idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit);
   3178         new_idx = idx - 1;
   3179     }
   3180     rv = soc_mem_write(unit, mem, COPYNO_ALL, idx, snat_entryp);
   3181     if (SOC_SUCCESS(rv)) {
   3182         *idx_ptr = new_idx;
   3183         return BCM_E_NONE;
   3184     }
   3185     return BCM_E_FAIL;
   3186 }
   3187 #endif /* BCM_TRIDENT2_SUPPORT */
   3188 
   3189 /* 
   3190  * Function:
   3191  *      bcm_esw_l3_nat_ingress_add
   3192  *
   3193  * Description:
   3194  *      Add an ingress NAT table entry. Depending on the flags settings an
   3195  *      entry is added to either the ingress DNAT pool table, DNAT session
   3196  *      table or SNAT session table.
   3197  *
   3198  * Parameters:
   3199  *      unit        - (IN) bcm device
   3200  *      nat_info    - (IN) ingress nat_info
   3201  */
   3202 int 
   3203 bcm_esw_l3_nat_ingress_add(int unit, bcm_l3_nat_ingress_t *nat_info)
   3204 {
   3205     int rv = BCM_E_UNAVAIL;
   3206 
   3207 #if defined(BCM_TRIDENT2_SUPPORT)
   3208     soc_mem_t mem;
   3209     bcm_l3_nat_egress_t tmp_nat;
   3210     bcm_l3_nat_ingress_t tmp_ing_nat;
   3211     ing_dnat_address_type_entry_t pool;
   3212     ing_snat_entry_t snat;
   3213     int mem_counter;
   3214     int index;
   3215     int max_int_pri = 15;
   3216     void *result;
   3217     int hw_idx, hw_half;
   3218     ing_dnat_address_type_entry_t old_pool;
   3219     ing_snat_entry_t old_snat;
   3220     uint32              dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   3221     uint32              old_dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   3222     void *old_result;
   3223     int full_nat, count;
   3224 
   3225     sal_memset(dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   3226     sal_memset(old_dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   3227     if (soc_feature(unit, soc_feature_nat)) {
   3228         if (NULL == nat_info) {
   3229             return BCM_E_PARAM;
   3230         }
   3231 
   3232         if ((nat_info->vrf > SOC_VRF_MAX(unit)) ||
   3233             (nat_info->vrf <  BCM_L3_VRF_DEFAULT)) {
   3234             return BCM_E_PARAM;
   3235         }
   3236 
   3237         full_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(nat_info->flags);
   3238         count = full_nat ? 2 : 1;
   3239         /* figure out which mem to operate on */
   3240         BCM_L3_NAT_INGRESS_GET_MEM_POINTER(unit, nat_info, mem, pool, dnat, 
   3241                                            snat, result, mem_counter);
   3242         /* figure out which old mem to operate on */
   3243         BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, nat_info, mem, old_pool,
   3244                                         old_dnat, old_snat, old_result);
   3245 
   3246         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   3247 
   3248         /* validate info in nat_info structure: */
   3249         if (mem != ING_DNAT_ADDRESS_TYPEm) {
   3250             if ((mem == L3_ENTRY_IPV4_MULTICASTm) && 
   3251                 (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) {         
   3252                 if ((nat_info->pri < BCM_PRIO_MIN) || 
   3253                     (nat_info->pri > max_int_pri)) {
   3254                     BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3255                     return BCM_E_PARAM;
   3256                 }
   3257             }else if ((mem == L3_ENTRY_DOUBLEm) &&
   3258                (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) {
   3259                 if ((nat_info->pri < BCM_PRIO_MIN) ||
   3260                     (nat_info->pri > max_int_pri)) {
   3261                     BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3262                     return BCM_E_PARAM;
   3263                 }
   3264             }
   3265             /* DNAT and SNAT entries should have valid pkt edit idx */
   3266             /* check if provided nat_id is valid */
   3267             tmp_nat.nat_id = nat_info->nat_id;
   3268             rv = bcm_esw_l3_nat_egress_get(unit, &tmp_nat);
   3269             
   3270             
   3271             if (!BCM_SUCCESS(rv)) {
   3272                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3273                 return rv;
   3274             }
   3275         }
   3276         /* check if entry already exists in the specified table */
   3277         rv = _bcm_td2_l3_nat_search_ing_mems(unit, mem, nat_info,
   3278                                              &index, result, old_result);
   3279 
   3280         /* if found, if replace flag set then replace entry. Otherwise declare error
   3281          */
   3282         if (rv == BCM_E_NONE) {
   3283             if (nat_info->flags & BCM_L3_NAT_INGRESS_REPLACE) {
   3284                 if (mem == L3_ENTRY_IPV4_MULTICASTm) {
   3285                     /* set nexthop correctly */
   3286                     rv = _bcm_td2_l3_nat_ingress_set_nexthop(unit, mem, result,
   3287                                     nat_info) ;
   3288                     if (!BCM_SUCCESS(rv)) {
   3289                         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3290                         return rv;
   3291                     }
   3292                 }
   3293                 if (mem == L3_ENTRY_DOUBLEm) {
   3294                     /* set nexthop correctly */
   3295                     rv = _bcm_td2_l3_nat_ingress_set_nexthop(unit, mem, result,
   3296                                     nat_info) ;
   3297                     if (!BCM_SUCCESS(rv)) {
   3298                         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3299                         return rv;
   3300                     }
   3301                 }
   3302 
   3303                 /* if nat_id is different, then delete original nat_id */
   3304                 if (mem != ING_DNAT_ADDRESS_TYPEm) {
   3305                     /* convert result to sw format to get nat_id */
   3306                     rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, old_result, 
   3307                                                           &tmp_ing_nat);
   3308                     if (!BCM_SUCCESS(rv)) {
   3309                         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3310                         return BCM_E_INTERNAL;
   3311                     }
   3312                     if (tmp_ing_nat.nat_id != nat_info->nat_id) {
   3313                         /* delete the original nat id */
   3314                         rv = _bcm_td2_l3_nat_egress_dec_refcount(unit,
   3315                                  tmp_ing_nat.nat_id);
   3316                         if (!BCM_SUCCESS(rv)) {
   3317                             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3318                             return BCM_E_INTERNAL;
   3319                         }
   3320 
   3321                         BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_info->nat_id,
   3322                                                         count);
   3323 
   3324                         /* Update data portion */
   3325                         BCM_L3_NAT_EGRESS_HW_IDX_GET
   3326                             (nat_info->nat_id, hw_idx, hw_half);
   3327                         if (mem == ING_SNATm) {
   3328                             soc_ING_SNATm_field32_set
   3329                                 (unit, result, NAT_PACKET_EDIT_ENTRY_SELf,
   3330                                  hw_half);
   3331                             soc_ING_SNATm_field32_set
   3332                                 (unit, result, NAT_PACKET_EDIT_IDXf, hw_idx);
   3333                         } else if (mem == L3_ENTRY_IPV4_MULTICASTm) {
   3334                             soc_L3_ENTRY_IPV4_MULTICASTm_field32_set
   3335                                 (unit, result, NAT__PACKET_EDIT_ENTRY_SELf,
   3336                                  hw_half);
   3337                             soc_L3_ENTRY_IPV4_MULTICASTm_field32_set
   3338                                 (unit, result, NAT__PACKET_EDIT_IDXf, hw_idx);
   3339                         }
   3340 #ifdef BCM_TRIDENT3_SUPPORT
   3341                         else if (mem == L3_ENTRY_DOUBLEm) {
   3342                             soc_L3_ENTRY_DOUBLEm_field32_set
   3343                                 (unit, result, NAT__PACKET_EDIT_ENTRY_SELf,
   3344                                  hw_half);
   3345                             soc_L3_ENTRY_DOUBLEm_field32_set
   3346                                 (unit, result, NAT__PACKET_EDIT_IDXf, hw_idx);
   3347                         }
   3348 #endif
   3349                     }
   3350                 }
   3351                 /* overwrite entry with this one */
   3352                 rv = soc_mem_write(unit, mem, COPYNO_ALL, index, result);
   3353                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3354                 return rv;
   3355             } else {
   3356                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3357                 return BCM_E_EXISTS;
   3358             }
   3359         } else if (rv == BCM_E_NOT_FOUND) {
   3360             if (nat_info->flags & BCM_L3_NAT_INGRESS_REPLACE) {
   3361                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3362                 return rv;
   3363             }
   3364         } else {
   3365             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3366             return rv;
   3367         }
   3368         
   3369         /* new entry. Insert into relevant table */
   3370         if (mem != ING_SNATm) {
   3371             if (mem == L3_ENTRY_IPV4_MULTICASTm || mem == L3_ENTRY_DOUBLEm) {
   3372                 /* set nexthop correctly */
   3373                 rv = _bcm_td2_l3_nat_ingress_set_nexthop(unit, mem, result,
   3374                                                          nat_info) ;
   3375                 if (!BCM_SUCCESS(rv)) {
   3376                     BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3377                     return rv;
   3378                 }
   3379             }
   3380 #ifdef BCM_MONTEREY_SUPPORT
   3381             if (SOC_IS_MONTEREY(unit) &&
   3382                     (mem == ING_DNAT_ADDRESS_TYPEm)) {
   3383                 rv = _bcm_mn_l3_nat_ing_dnat_address_type_entry_add(unit, mem, nat_info,
   3384                                                                      (ing_dnat_address_type_entry_t*)result);
   3385             } else
   3386 #endif
   3387             {
   3388                 rv = soc_mem_insert(unit, mem, COPYNO_ALL, result);
   3389             }
   3390             if (rv == SOC_E_FULL) {
   3391                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3392                 return BCM_E_FULL;
   3393             }
   3394             if (rv != SOC_E_NONE) {
   3395                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3396                 return BCM_E_INTERNAL;
   3397             }
   3398         } else {
   3399             rv = _bcm_td2_l3_nat_ingress_snat_entry_add(unit, mem, nat_info, 
   3400                                                    (ing_snat_entry_t *)result);
   3401             if (!BCM_SUCCESS(rv)) {
   3402                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3403                 return rv;
   3404             }
   3405         }
   3406 
   3407         /* Increment Egress ref count */
   3408         if (mem != ING_DNAT_ADDRESS_TYPEm) {
   3409                 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_info->nat_id, count);
   3410         }
   3411 
   3412         /* increment table count */
   3413         BCM_L3_NAT_INGRESS_INC_TBL_CNT(unit, mem_counter);
   3414         rv = BCM_E_NONE;
   3415         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3416     }
   3417 #endif
   3418     return rv;
   3419 }
   3420 
   3421 #ifdef BCM_TRIDENT2_SUPPORT
   3422 
   3423 static int
   3424 _bcm_td2_l3_nat_ingress_snat_entry_delete(int unit, soc_mem_t mem, 
   3425                                           bcm_l3_nat_ingress_t *nat_info, 
   3426                                           void *key)
   3427 {
   3428     int index = -1, rv;
   3429     int last_idx, *idx_ptr;
   3430     ing_snat_entry_t last_snat;
   3431 
   3432     /* lookup entry. */
   3433     rv = _bcm_td2_l3_nat_ing_snat_lookup(unit, nat_info, key, &index, key);
   3434 
   3435     if (!BCM_SUCCESS(rv)) {
   3436         return rv;
   3437     }
   3438     
   3439     /* copy last valid entry into this entry index */
   3440     if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) {
   3441         /* get last napt entry index */
   3442         last_idx = BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) - 1;
   3443         idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit);
   3444     } else {
   3445         last_idx = BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) + 1;
   3446         idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit);
   3447     }
   3448 
   3449     /* read last entry */
   3450     rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, last_idx, &last_snat);
   3451 
   3452     if (!SOC_SUCCESS(rv)) {
   3453         return BCM_E_INTERNAL;
   3454     }
   3455 
   3456     /* write it into the entry to be deleted */
   3457     rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &last_snat);
   3458     if (!SOC_SUCCESS(rv)) {
   3459         return BCM_E_INTERNAL;
   3460     }
   3461 
   3462     /* delete last entry */
   3463     sal_memset(&last_snat, 0, sizeof(last_snat));
   3464     rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, last_idx, &last_snat);
   3465     if (!SOC_SUCCESS(rv)) {
   3466         return BCM_E_INTERNAL;
   3467     }
   3468 
   3469     /* update free index */
   3470     *idx_ptr = last_idx;
   3471     return BCM_E_NONE;
   3472 }
   3473 #endif /* BCM_TRIDENT2_SUPPORT */
   3474 
   3475 /* 
   3476  * Function:
   3477  *      bcm_esw_l3_nat_ingress_delete
   3478  *
   3479  * Description:
   3480  *      Delete an ingress NAT table entry. Depending on the flags settings an
   3481  *      entry is deleted from  either the ingress DNAT pool table, DNAT session
   3482  *      table or SNAT session table.
   3483  *
   3484  * Parameters:
   3485  *      unit        - (IN) bcm device
   3486  *      nat_info    - (IN) ingress nat_info
   3487  */
   3488 int 
   3489 bcm_esw_l3_nat_ingress_delete(
   3490     int unit, 
   3491     bcm_l3_nat_ingress_t *nat_info)
   3492 {
   3493     int rv = BCM_E_UNAVAIL;
   3494 
   3495 #if defined(BCM_TRIDENT2_SUPPORT)
   3496     soc_mem_t mem;
   3497     ing_dnat_address_type_entry_t pool, old_pool;
   3498     ing_snat_entry_t snat;
   3499     bcm_l3_nat_ingress_t tmp_ing_nat;
   3500     ing_snat_entry_t old_snat;
   3501     void *result;
   3502     void *old_result;
   3503     int mem_counter, index;
   3504     uint32              dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   3505     uint32              old_dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   3506 
   3507     sal_memset(dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   3508     sal_memset(old_dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   3509 
   3510 
   3511     if (soc_feature(unit, soc_feature_nat)) {
   3512         /* validate input */
   3513         if (NULL == nat_info) {
   3514             return BCM_E_PARAM;
   3515         }
   3516 
   3517         if ((nat_info->vrf > SOC_VRF_MAX(unit)) ||
   3518             (nat_info->vrf <  BCM_L3_VRF_DEFAULT)) {
   3519             return BCM_E_PARAM;
   3520         }
   3521         BCM_L3_NAT_INGRESS_GET_MEM_POINTER(unit, nat_info, mem, pool, dnat, 
   3522                                            snat, result, mem_counter);
   3523         /* figure out which old mem to operate on */
   3524         BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, nat_info, mem, old_pool,
   3525                                         old_dnat, old_snat, old_result);
   3526         BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, result, 
   3527                             nat_info));
   3528         /* Clean PRIf to avoid illegal pri */
   3529         if ((mem ==  L3_ENTRY_IPV4_MULTICASTm) && 
   3530             (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) {
   3531             soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, result, 
   3532                                                      NAT__PRIf, 0);
   3533         } else if ((mem ==  L3_ENTRY_DOUBLEm) && 
   3534             (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) {
   3535             soc_L3_ENTRY_DOUBLEm_field32_set(unit, result, 
   3536                                                      NAT__PRIf, 0);
   3537         }
   3538 
   3539         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   3540 
   3541         if (mem != ING_SNATm) {
   3542             if (mem == L3_ENTRY_IPV4_MULTICASTm || mem == L3_ENTRY_DOUBLEm) {
   3543                 rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &index, result,
   3544                                     old_result, 0);
   3545                 if (rv != SOC_E_NONE) {
   3546                     return BCM_E_NOT_FOUND;
   3547                 }
   3548                 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, old_result,
   3549                                                  &tmp_ing_nat);
   3550                 if (!BCM_SUCCESS(rv)) {
   3551                     return BCM_E_INTERNAL;
   3552                 }
   3553                 nat_info->nat_id = tmp_ing_nat.nat_id;
   3554             }
   3555             /* delete entry from table */
   3556 #ifdef BCM_MONTEREY_SUPPORT
   3557             if (SOC_IS_MONTEREY(unit) &&
   3558                 (mem == ING_DNAT_ADDRESS_TYPEm)) {
   3559                 rv = _bcm_mn_l3_nat_ing_dnat_address_type_entry_delete(unit, mem, nat_info,
   3560                                                                result);
   3561             } else
   3562 #endif
   3563             {
   3564                 rv = soc_mem_delete(unit, mem, COPYNO_ALL, result);
   3565             }
   3566             if (SOC_FAILURE(rv)) {
   3567                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3568                 return rv;
   3569             }
   3570         } else {
   3571             rv = _bcm_td2_l3_nat_ingress_snat_entry_delete(unit, mem, nat_info,
   3572                                                            result);
   3573             if (rv != BCM_E_NONE) {
   3574                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3575                 return rv;
   3576             }
   3577         }
   3578 
   3579         if (mem != ING_DNAT_ADDRESS_TYPEm) {
   3580             /* decrement refcount for the egress nat_id */
   3581             rv = _bcm_td2_l3_nat_egress_dec_refcount(unit, nat_info->nat_id);
   3582 
   3583             if (rv != BCM_E_NONE) {
   3584                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3585                 return rv;
   3586             }
   3587         }
   3588         /* decrement table count */
   3589         BCM_L3_NAT_INGRESS_DEC_TBL_CNT(unit, mem_counter);
   3590         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3591         return BCM_E_NONE;
   3592     }
   3593 #endif /* BCM_TRIDENT_SUPPORT */
   3594     return rv;
   3595 }
   3596 
   3597 /* 
   3598  * Function:
   3599  *      bcm_esw_l3_nat_ingress_traverse
   3600  *
   3601  * Description:
   3602  *      Traverse through the ingress NAT table specified by flags and invoke a
   3603  *      user provided callback for each valid entry, that matches the flags.
   3604  *
   3605  * Parameters:
   3606  *      unit        - (IN) bcm device
   3607  *      flags       - (IN) Flags to match during traverse
   3608  *      start       - (IN) First index to read
   3609  *      end         - (IN) Last index to read
   3610  *      cb          - (IN) Caller notification callback
   3611  *      user_data   - (IN) User cookie which should be returned in cb
   3612  */
   3613 int bcm_esw_l3_nat_ingress_traverse(int unit, uint32 flags, uint32 start, 
   3614                                     uint32 end, bcm_l3_nat_ingress_traverse_cb cb, 
   3615                                     void *user_data)
   3616 {
   3617     int rv = BCM_E_UNAVAIL;
   3618 
   3619 #if defined(BCM_TRIDENT2_SUPPORT)
   3620     soc_mem_t mem;
   3621     bcm_l3_nat_ingress_t tmp_nat;
   3622     ing_dnat_address_type_entry_t *pool;
   3623     ing_snat_entry_t *snat;
   3624     l3_entry_ipv4_multicast_entry_t *dnat;
   3625     l3_entry_double_entry_t *dnatdouble;
   3626     int pool_sz = sizeof(ing_dnat_address_type_entry_t);
   3627     int dnat_sz = sizeof(l3_entry_ipv4_multicast_entry_t);
   3628 #ifdef BCM_TRIDENT3_SUPPORT
   3629     int dnat_sz1 = sizeof(l3_entry_double_entry_t);
   3630 #endif
   3631     int snat_sz = sizeof(ing_snat_entry_t);
   3632     int *result, idx, tbl_size;
   3633     char *buffer = NULL;
   3634     void *entry_ptr;
   3635     uint32 tmp_flags = BCM_L3_NAT_INGRESS_HIT
   3636            | BCM_L3_NAT_INGRESS_MULTIPATH | BCM_L3_NAT_INGRESS_RPE
   3637            | BCM_L3_NAT_INGRESS_DST_DISCARD | BCM_L3_NAT_INGRESS_REPLACE;   
   3638 
   3639     if (soc_feature(unit, soc_feature_nat)) {
   3640         /* pick memory */
   3641         /* make macro-compatible: */
   3642         tmp_nat.flags = flags;
   3643 #ifdef BCM_TRIDENT3_SUPPORT
   3644     if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) {
   3645         BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, &tmp_nat, mem, pool_sz, dnat_sz1, 
   3646                                         snat_sz, result);
   3647     } else 
   3648 #endif
   3649     {
   3650         BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, &tmp_nat, mem, pool_sz, dnat_sz, 
   3651                                         snat_sz, result);
   3652     } 
   3653         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   3654 
   3655         /* dma memory */
   3656         rv = _bcm_td2_l3_nat_read_mem(unit, mem, *result, "l3 nat ingress", &buffer,
   3657                                       &tbl_size);
   3658         if (!BCM_SUCCESS(rv)) {
   3659             /* free memory */
   3660             if (buffer != NULL) {
   3661                 soc_cm_sfree(unit, buffer);
   3662             }
   3663             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3664             return rv;
   3665         }
   3666 
   3667         /* Input indexes sanity */
   3668         if (start >= (uint32)tbl_size || (end >= (uint32)tbl_size 
   3669             && end != 0xffffffff) || start > end) {
   3670             BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3671             return (BCM_E_NOT_FOUND);
   3672         }
   3673         /* End value according to real table size */
   3674         if (end == 0xffffffff) {
   3675             end = (uint32)tbl_size - 1;
   3676         }
   3677         
   3678         /* walk from start to end, matching flags */
   3679         for (idx = start; idx <= end; idx++) {
   3680             /* read entry at index */
   3681             switch (mem) {
   3682             case ING_DNAT_ADDRESS_TYPEm:
   3683                 pool = soc_mem_table_idx_to_pointer(unit, mem, 
   3684                                      ing_dnat_address_type_entry_t *, buffer, idx);
   3685                 entry_ptr = (void *) pool;
   3686                 break;
   3687             case ING_SNATm:
   3688                 snat = soc_mem_table_idx_to_pointer(unit, mem, 
   3689                                      ing_snat_entry_t *, buffer, idx);
   3690                 entry_ptr = (void *) snat;
   3691                 break;
   3692             case L3_ENTRY_IPV4_MULTICASTm:
   3693                 dnat = soc_mem_table_idx_to_pointer(unit, mem, 
   3694                                    l3_entry_ipv4_multicast_entry_t *, buffer, idx);
   3695                 entry_ptr = (void *) dnat;
   3696                 break;
   3697             case L3_ENTRY_DOUBLEm:
   3698                 dnatdouble  = soc_mem_table_idx_to_pointer(unit, mem, 
   3699                                    l3_entry_double_entry_t *, buffer, idx);
   3700                 entry_ptr = (void *) dnatdouble;
   3701                 break;
   3702             /* coverity[dead_error_begin] */
   3703             default:
   3704                 soc_cm_sfree(unit, buffer);
   3705                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3706                 return BCM_E_PARAM;
   3707             }
   3708             rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, entry_ptr, 
   3709                                                   &tmp_nat);
   3710             /* no valid entry */
   3711             if (BCM_E_EMPTY == rv) {
   3712                 continue;
   3713             }
   3714             (void)_bcm_td2_l3_nat_ingress_hit_update(unit, mem, idx, 
   3715                                                   &tmp_nat);
   3716 
   3717             if ((flags & BCM_L3_NAT_INGRESS_HIT)
   3718                 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_HIT))) {
   3719                 continue;
   3720             }
   3721 
   3722             if ((flags & BCM_L3_NAT_INGRESS_MULTIPATH)
   3723                 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_MULTIPATH))) {
   3724                 continue;
   3725             }
   3726 
   3727             if ((flags & BCM_L3_NAT_INGRESS_RPE)
   3728                 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_RPE))) {
   3729                 continue;
   3730             }
   3731 
   3732             if ((flags & BCM_L3_NAT_INGRESS_DST_DISCARD)
   3733                 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_DST_DISCARD))) {
   3734                 continue;
   3735             }
   3736 
   3737             if ((flags & (~tmp_flags)) != (tmp_nat.flags & (~tmp_flags))) {
   3738                 continue;
   3739             }
   3740 
   3741             /* call callback */
   3742             rv = (*cb)(unit, idx, &tmp_nat, user_data);
   3743 #ifdef BCM_CB_ABORT_ON_ERR
   3744             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   3745                 break;
   3746             }
   3747 #endif
   3748         }
   3749         if (idx > end) {
   3750             /* broke out at end of loop */
   3751             rv = BCM_E_NONE;
   3752         }
   3753     }
   3754     if (buffer)  {
   3755         soc_cm_sfree(unit, buffer);
   3756     }
   3757     BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3758 #endif /* BCM_TRIDENT_SUPPORT */
   3759     return rv;
   3760 }
   3761 
   3762 /* 
   3763  * Function:
   3764  *      bcm_esw_l3_nat_ingress_find
   3765  *
   3766  * Description:
   3767  *      Find an ingress NAT table entry. Depending on the flags settings an
   3768  *      entry is search for in either the ingress DNAT pool table, DNAT session
   3769  *      table or SNAT session table.
   3770  *
   3771  * Parameters:
   3772  *      unit        - (IN) bcm device
   3773  *      nat_info    - (IN/OUT) ingress nat_info
   3774  */
   3775 int 
   3776 bcm_esw_l3_nat_ingress_find(
   3777     int unit, 
   3778     bcm_l3_nat_ingress_t *nat_info)
   3779 {
   3780     int rv = BCM_E_UNAVAIL;
   3781 
   3782 #if defined(BCM_TRIDENT2_SUPPORT)
   3783     soc_mem_t mem;
   3784     ing_dnat_address_type_entry_t pool;
   3785     ing_snat_entry_t snat;
   3786     void *result;
   3787     int idx;
   3788     uint32              dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   3789 
   3790     sal_memset(dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   3791 
   3792     if (soc_feature(unit, soc_feature_nat)) {
   3793         if (NULL == nat_info) {
   3794             return BCM_E_PARAM;
   3795         }
   3796         
   3797         if ((nat_info->vrf > SOC_VRF_MAX(unit)) ||
   3798             (nat_info->vrf <  BCM_L3_VRF_DEFAULT)) {
   3799             return BCM_E_PARAM;
   3800         }
   3801         /* search for the entry */
   3802         BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, nat_info, mem, pool, dnat, 
   3803                                            snat, result);
   3804         BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, result, 
   3805                             nat_info));
   3806 
   3807         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   3808         if (mem != ING_SNATm) {
   3809 #ifdef BCM_MONTEREY_SUPPORT
   3810             if (SOC_IS_MONTEREY(unit) &&
   3811                 (mem == ING_DNAT_ADDRESS_TYPEm)) {
   3812                 rv = _bcm_mn_l3_nat_ing_dnat_address_type_lookup(unit, nat_info, result, &idx,
   3813                                                                   result);
   3814             } else
   3815 #endif
   3816             {
   3817                 rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &idx, result,
   3818                                     result, 0);
   3819             }
   3820             if (rv != SOC_E_NONE) {
   3821                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3822                 return BCM_E_NOT_FOUND;
   3823             }
   3824         } else {
   3825             rv = _bcm_td2_l3_nat_ing_snat_lookup(unit, nat_info, result, &idx,
   3826                                                  result);
   3827             if (rv != BCM_E_NONE) {
   3828                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3829                 return BCM_E_NOT_FOUND;
   3830             }
   3831         }
   3832         rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, result, nat_info);
   3833         (void)_bcm_td2_l3_nat_ingress_hit_update(unit, mem, idx, nat_info);
   3834 
   3835         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3836         return rv;
   3837     }
   3838 #endif /* BCM_TRIDENT_SUPPORT */
   3839     return rv;
   3840 }
   3841 
   3842 /* 
   3843  * Function:
   3844  *      bcm_esw_l3_nat_ingress_delete_all
   3845  *
   3846  * Description:
   3847  *      Traverse through the ingress NAT table specified by flags and invoke a
   3848  *      user provided callback for each valid entry, that matches the flags.
   3849  *
   3850  * Parameters:
   3851  *      unit            - (IN) bcm device
   3852  *      nat_info        - (IN) Only flags field is valid. These are used to figure
   3853  *                             out which table to clear 
   3854  */
   3855 int bcm_esw_l3_nat_ingress_delete_all(
   3856     int unit, 
   3857     bcm_l3_nat_ingress_t *nat_info)
   3858 {
   3859     int rv = BCM_E_UNAVAIL;
   3860 
   3861 #if defined(BCM_TRIDENT2_SUPPORT)
   3862     soc_mem_t   mem;
   3863     int mem_counter;
   3864     if (soc_feature(unit, soc_feature_nat)) {
   3865         if (NULL == nat_info) {
   3866             return BCM_E_PARAM;
   3867         }
   3868     
   3869         /* figure out which memory to clear */
   3870         if (nat_info->flags & (BCM_L3_NAT_INGRESS_DNAT)) {
   3871             if (nat_info->flags & BCM_L3_NAT_INGRESS_DNAT_POOL) {
   3872                 mem = ING_DNAT_ADDRESS_TYPEm;
   3873                 mem_counter = BCM_L3_NAT_INGRESS_POOL_CNT;
   3874             } else {
   3875                 if (SOC_MEM_IS_VALID( unit, L3_ENTRY_DOUBLEm)) {
   3876                     mem = L3_ENTRY_DOUBLEm;
   3877                 } else {
   3878                     mem = L3_ENTRY_IPV4_MULTICASTm; 
   3879                 }
   3880                 mem_counter = BCM_L3_NAT_INGRESS_DNAT_CNT;
   3881             }
   3882         } else {
   3883             mem = ING_SNATm;
   3884             mem_counter = BCM_L3_NAT_INGRESS_SNAT_CNT;
   3885         } 
   3886 
   3887         /* if not shared table just clear it */
   3888         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit));
   3889         if (mem == ING_DNAT_ADDRESS_TYPEm) {
   3890 #ifdef BCM_MONTEREY_SUPPORT
   3891             if (SOC_IS_MONTEREY(unit)) {
   3892                 rv = bcm_esw_l3_nat_ingress_traverse(unit, nat_info->flags,
   3893                         soc_mem_index_min(unit, mem), soc_mem_index_max(unit, mem),
   3894                         _bcm_td2_l3_nat_ingress_delete_entry, NULL);
   3895             } else
   3896 #endif
   3897             {
   3898                 rv = soc_mem_clear(unit, mem, COPYNO_ALL, 1);
   3899             }
   3900             if (!SOC_SUCCESS(rv)) {
   3901                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3902                 return BCM_E_INTERNAL;
   3903             }
   3904         } else {
   3905             /* if shared table, traverse and delete individual entries */
   3906             rv = bcm_esw_l3_nat_ingress_traverse(unit, nat_info->flags,
   3907                     soc_mem_index_min(unit, mem), soc_mem_index_max(unit, mem),
   3908                     _bcm_td2_l3_nat_ingress_delete_entry, NULL);
   3909             if (BCM_FAILURE(rv)) {
   3910                 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3911                 return rv;
   3912             }
   3913         }
   3914         /* clear table count to 0 */
   3915         BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, mem_counter);
   3916         BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit));
   3917         return BCM_E_NONE;
   3918     }
   3919 #endif /* BCM_TRIDENT2_SUPPORT */
   3920     return rv;
   3921 }
   3922 
   3923 /* 
   3924  * Function:
   3925  *      bcm_esw_l3_nat_ingress_age
   3926  *
   3927  * Description:
   3928  *      Run aging on either DNAT session or SNAT session table as specified
   3929  *      by the flags. Clear the hit bit for the entry or if it is already cleared
   3930  *      delete the entry.
   3931  *
   3932  * Parameters:
   3933  *      unit            - (IN) bcm device
   3934  *      flags           - (IN) flags to match to identify entry to act upon.
   3935  *      age_cb          - (IN) user provided callback fn to call for each entry
   3936  *      user_data       - (IN) parameter to user provided callback
   3937  */
   3938 int bcm_esw_l3_nat_ingress_age(int unit, uint32 flags, 
   3939                                bcm_l3_nat_ingress_traverse_cb age_cb, 
   3940                                void *user_data)
   3941 {
   3942     int rv = BCM_E_UNAVAIL;
   3943 
   3944 #if defined(BCM_TRIDENT2_SUPPORT)
   3945     soc_mem_t   mem;
   3946     bcm_l3_nat_ingress_cb_context_t user_context;
   3947 
   3948     if (soc_feature(unit, soc_feature_nat)) {
   3949         /* validate flags. Aging supported only on DNAT or SNAT session tables */
   3950         if (flags & BCM_L3_NAT_INGRESS_DNAT_POOL) {
   3951             return BCM_E_PARAM;   
   3952         }
   3953         /* call traversal function with an ager callback */
   3954         if (flags & BCM_L3_NAT_INGRESS_DNAT) {
   3955             mem = L3_ENTRY_IPV4_MULTICASTm;
   3956             if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) {
   3957                 mem = L3_ENTRY_DOUBLEm;
   3958             }
   3959         } else {
   3960             mem = ING_SNATm;
   3961         }
   3962         /* pass original user callback info to intermediate callback function */
   3963         user_context.user_cb = age_cb;
   3964         user_context.user_data = user_data;
   3965         user_context.mem = mem;
   3966         rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, BCM_NAT_EGRESS_ID_MIN(unit),
   3967                                          soc_mem_index_max(unit, mem),
   3968                                          _bcm_td2_l3_nat_ingress_age_entry,
   3969                                          (void *) &user_context);
   3970         return rv;
   3971        
   3972     }
   3973 #endif /* BCM_TRIDENT2_SUPPORT */
   3974     return rv;
   3975 }
   3976 
   3977 /*
   3978  * Function:
   3979  *  bcm_esw_l3_large_nat_egress_add
   3980  * Description:
   3981  *	Add a NAT translation entry to the egress NAT xlate table.
   3982  * Parameters:
   3983  *	unit - (IN) Device number.
   3984  *  nat_info - (IN)
   3985  *      IN: packet edit info: original IP/ports and translated IP/ports
   3986  * Returns:
   3987  *	BCM_E_XXX
   3988  */
   3989 int
   3990 bcm_esw_l3_large_nat_egress_add(
   3991     int unit,
   3992     bcm_l3_large_nat_egress_t *nat_info)
   3993 {
   3994 #if defined(BCM_TRIDENT3_SUPPORT)
   3995     if (soc_feature(unit, soc_feature_large_scale_nat)) {
   3996         /* validate input */
   3997         if (NULL == nat_info) {
   3998             return BCM_E_PARAM;
   3999         }
   4000 
   4001         /* must specify at least one of SNAT or DNAT */
   4002         if (!(nat_info->flags & (BCM_L3_LARGE_NAT_EGRESS_SNAT |
   4003                                  BCM_L3_LARGE_NAT_EGRESS_DNAT))) {
   4004             return BCM_E_PARAM;
   4005         }
   4006 
   4007         if ((nat_info->flags & BCM_L3_LARGE_NAT_EGRESS_MACDA_UPDATE) &&
   4008             !(nat_info->flags & BCM_L3_LARGE_NAT_EGRESS_MULTICAST)) {
   4009             return BCM_E_PARAM;
   4010         }
   4011 
   4012         /* validate nat class id */
   4013         if (nat_info->nat_class_id <= 0 ||
   4014             nat_info->nat_class_id > 0xffff) {
   4015             return BCM_E_PARAM;
   4016         }
   4017 
   4018         /* validate l3 interface class id if supplied */
   4019         if (nat_info->intf_class_id < 0 ||
   4020             nat_info->intf_class_id > 0xfff) {
   4021             return BCM_E_PARAM;
   4022         }
   4023 
   4024         /* validate replication id if supplied */
   4025         if (nat_info->replication_id < 0 ||
   4026             nat_info->replication_id > 0xffff) {
   4027             return BCM_E_PARAM;
   4028         }
   4029 
   4030         return _bcm_td3_large_nat_egress_add(unit, nat_info);
   4031     }
   4032 #endif /* BCM_TRIDENT3_SUPPORT */
   4033     return BCM_E_UNAVAIL;
   4034 }
   4035 
   4036 /* Function:
   4037  *  bcm_esw_l3_large_nat_delete
   4038  * Description:
   4039  *  Delete the egress NAT entry from EVXLT table.
   4040  * Parameters:
   4041  *  unit     - (IN) Device number.
   4042  *  nat_info - (IN) key fields to be deleted.
   4043  */
   4044 int
   4045 bcm_esw_l3_large_nat_egress_delete(
   4046     int unit,
   4047     bcm_l3_large_nat_egress_t *nat_info)
   4048 {
   4049 #if defined(BCM_TRIDENT3_SUPPORT)
   4050     soc_mem_t mem = EGR_VLAN_XLATE_2_DOUBLEm;
   4051     uint32 entry[SOC_MAX_MEM_WORDS];
   4052     int nat_key;
   4053 
   4054     if (soc_feature(unit, soc_feature_large_scale_nat)) {
   4055         /* validate input */
   4056         if (NULL == nat_info) {
   4057             return BCM_E_PARAM;
   4058         }
   4059 
   4060         /* validate nat class id */
   4061         if (nat_info->nat_class_id <= 0 ||
   4062             nat_info->nat_class_id > 0xffff) {
   4063             return BCM_E_PARAM;
   4064         }
   4065 
   4066         /* validate l3 interface class id if supplied */
   4067         if (nat_info->intf_class_id < 0 ||
   4068             nat_info->intf_class_id > 0xfff) {
   4069             return BCM_E_PARAM;
   4070         }
   4071         /* validate replication id if supplied */
   4072         if (nat_info->replication_id < 0 ||
   4073             nat_info->replication_id > 0xffff) {
   4074             return BCM_E_PARAM;
   4075         }
   4076 
   4077         sal_memset(entry, 0, sizeof(entry));
   4078 
   4079         BCM_IF_ERROR_RETURN(
   4080             _bcm_td3_large_nat_egress_key_set(unit,
   4081                  mem, nat_info, &nat_key, entry));
   4082 
   4083         BCM_IF_ERROR_RETURN(soc_mem_delete(unit,
   4084                  mem, MEM_BLOCK_ANY, entry));
   4085 
   4086         return BCM_E_NONE;
   4087     }
   4088 #endif /* BCM_TRIDENT3_SUPPORT */
   4089 
   4090     return BCM_E_UNAVAIL;
   4091 }
   4092 
   4093 /* Function:
   4094  *  bcm_esw_l3_large_nat_egress_get
   4095  * Description:
   4096  *  Retrieve the egress NAT packet edit entry at the specified index
   4097  * Parameters:
   4098  *  unit    - (IN) Device number.
   4099  *  nat_id  - IN Index of entry to get.
   4100  */
   4101 int bcm_esw_l3_large_nat_egress_get(
   4102     int unit,
   4103     bcm_l3_large_nat_egress_t *nat_info)
   4104 {
   4105 #if defined(BCM_TRIDENT3_SUPPORT)
   4106     soc_mem_t mem = EGR_VLAN_XLATE_2_DOUBLEm;
   4107     uint32 entry[SOC_MAX_MEM_WORDS];
   4108     int nat_key;
   4109 
   4110     if (soc_feature(unit, soc_feature_large_scale_nat)) {
   4111         /* validate input */
   4112         if (NULL == nat_info) {
   4113             return BCM_E_PARAM;
   4114         }
   4115 
   4116         /* validate nat class id */
   4117         if (nat_info->nat_class_id <= 0 ||
   4118             nat_info->nat_class_id > 0xffff) {
   4119             return BCM_E_PARAM;
   4120         }
   4121 
   4122         /* validate l3 interface class id if supplied */
   4123         if (nat_info->intf_class_id < 0 ||
   4124             nat_info->intf_class_id > 0xfff) {
   4125             return BCM_E_PARAM;
   4126         }
   4127 
   4128         /* validate replication id if supplied */
   4129         if (nat_info->replication_id < 0 ||
   4130             nat_info->replication_id > 0xffff) {
   4131             return BCM_E_PARAM;
   4132         }
   4133 
   4134         sal_memset(entry, 0, sizeof(entry));
   4135 
   4136         BCM_IF_ERROR_RETURN(
   4137             _bcm_td3_large_nat_egress_key_set(unit,
   4138                  mem, nat_info, &nat_key, entry));
   4139 
   4140         BCM_IF_ERROR_RETURN(
   4141             _bcm_td3_large_nat_egress_entry_get(unit,
   4142                 mem, entry, nat_key, nat_info));
   4143 
   4144         return BCM_E_NONE;
   4145     }
   4146 #endif /* BCM_TRIDENT3_SUPPORT */
   4147     return BCM_E_UNAVAIL;
   4148 }
   4149 
   4150 /* Function:
   4151  *  bcm_esw_l3_large_nat_egress_traverse
   4152  *
   4153  * Description:
   4154  *  Traverse all valid NAT entries in the egress translate table
   4155  *  and call the supplied callback routine for each.
   4156  *
   4157  * Parameters:
   4158  *  unit    - (IN) Device number.
   4159  *  cb      - (IN) User call-back function
   4160  */
   4161 int bcm_esw_l3_large_nat_egress_traverse(
   4162     int unit,
   4163     bcm_l3_large_nat_egress_traverse_cb cb,
   4164     void *user_data)
   4165 {
   4166 #if defined(BCM_TRIDENT3_SUPPORT)
   4167     if (soc_feature(unit, soc_feature_large_scale_nat)) {
   4168         /* validate input */
   4169         if (NULL == cb) {
   4170             return BCM_E_NONE;
   4171         }
   4172 
   4173         return _bcm_td3_large_nat_egress_traverse(unit,
   4174                           EGR_VLAN_XLATE_2_DOUBLEm, cb, user_data);
   4175     }
   4176 #endif /* BCM_TRIDENT3_SUPPORT */
   4177     return BCM_E_UNAVAIL;
   4178 }
   4179 
   4180 
   4181 #if 0
   4182 #if defined(BCM_TRIDENT2_SUPPORT)
   4183 int
   4184 _bcm_td2_l3_nat_ingress_key_match(int unit, soc_mem_t mem, void *hw_buf)
   4185 {
   4186     if (mem == ING_DNAT_ADDRESS_TYPEm) {
   4187         return 1;
   4188     }
   4189     if (mem == L3_ENTRY_IPV4_MULTICASTm) {
   4190           return ((soc_mem_field32_get(unit, mem, hw_buf, KEY_TYPEf) == 
   4191                                                   TD2_L3_HASH_KEY_TYPE_DST_NAT) || 
   4192                   (soc_mem_field32_get(unit, mem, hw_buf, KEY_TYPEf) == 
   4193                                                   TD2_L3_HASH_KEY_TYPE_DST_NAPT));
   4194     }
   4195     return 0;
   4196 }
   4197 int
   4198 _bcm_td2_l3_nat_ingress_conflict_get(int unit, bcm_l3_nat_ingress_t *nat_info, 
   4199                                     bcm_l3_nat_ingress_t *cf_array, int cf_max, 
   4200                                     int *cf_count)
   4201 {
   4202     uint32 valid, *bufp;      /* Hardware buffer ptr     */
   4203     soc_mem_t mem = L3_ENTRY_IPV4_MULTICASTm;            
   4204     int index, rv = BCM_E_NONE;      /* Operation status.       */
   4205     uint32 hw_buf[SOC_MAX_MEM_WORDS];    
   4206     uint8 i, bidx, num_ent, shared_l3_banks, start_bidx, end_bidx;
   4207     l3_entry_ipv4_multicast_entry_t l3v4_ext_entry;    
   4208     ing_dnat_address_type_entry_t dnat_pool;
   4209 
   4210     
   4211 
   4212     /* Input parameters check. */
   4213     if ((NULL == nat_info) || (NULL == cf_count) || 
   4214         (NULL == cf_array) || (cf_max <= 0)) {
   4215         return (BCM_E_PARAM);
   4216     }
   4217 
   4218     if (nat_info->flags & BCM_L3_NAT_INGRESS_DNAT) {
   4219         if (nat_info->flags & BCM_L3_NAT_INGRESS_DNAT_POOL) { 
   4220             mem = ING_DNAT_ADDRESS_TYPEm;
   4221             /* Set the valid field */
   4222             valid = VALIDf;
   4223             start_bidx = 0;
   4224             end_bidx = 1;
   4225             bufp =  (void *) &dnat_pool;
   4226         } else {
   4227             mem = L3_ENTRY_IPV4_MULTICASTm;
   4228             /* Set the valid field */
   4229             valid = VALID_0f;
   4230             /* get number of shared L3 banks */
   4231             shared_l3_banks = (soc_mem_index_count(unit, L3_ENTRY_ONLYm) - 
   4232                                                           16 * 1024) / (64 * 1024);
   4233             if (shared_l3_banks > 3) {
   4234                 return BCM_E_NOT_FOUND;
   4235             }
   4236             start_bidx = (6 - shared_l3_banks);
   4237             end_bidx = 9;
   4238             bufp =  (void *) &l3v4_ext_entry;
   4239         }
   4240     } else {
   4241         /* Not support for SNAT table */
   4242         return BCM_E_PARAM;
   4243     }
   4244 
   4245     /* Translate lookup key to hw format. */
   4246     BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, bufp, 
   4247                         nat_info));
   4248     
   4249     
   4250 #if 0
   4251     /* Set table fields */
   4252     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   4253 
   4254     /* Assign entry buf based on table being used */
   4255     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, bufp,
   4256                                     l3v4_entry,
   4257                                     l3v4_ext_entry,
   4258                                     l3v6_entry,
   4259                                     l3v6_ext_entry);
   4260     /* Prepare host entry for addition. */
   4261     BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, &l3cfg, bufp));
   4262 #endif
   4263 
   4264 
   4265     *cf_count = 0;
   4266 
   4267 #if 0
   4268     /* get number of shared L3 banks */
   4269     shared_l3_banks = (soc_mem_index_count(unit, L3_ENTRY_ONLYm) - 16 * 1024) /
   4270                       (64 * 1024);
   4271 
   4272     if (shared_l3_banks > 3) {
   4273         return BCM_E_NOT_FOUND;
   4274     }
   4275 #endif
   4276 
   4277     /* bank 9 to 6 are dedicated L3 banks, 5 to 3 are dedicated, depends on
   4278      * mode how many shared banks are assigned to l3 
   4279      */
   4280     for (bidx = start_bidx; bidx <= end_bidx; bidx++) {
   4281 
   4282         num_ent = 4; /* 4 entries per bucket */
   4283 
   4284         BCM_TD2_NAT_INGRESS_BANK_ENTRY_HASH(mem, unit, bidx, bufp, index);
   4285         if (index == 0) { 
   4286             return BCM_E_INTERNAL;
   4287         }
   4288 
   4289         for (i = 0; (i < num_ent) && (*cf_count < cf_max); i++) {
   4290             rv = soc_mem_read(unit, mem, COPYNO_ALL, index + i, hw_buf);
   4291             if (SOC_FAILURE(rv)) {
   4292                 return BCM_E_MEMORY;
   4293             }
   4294             if (soc_mem_field32_get(unit, mem, hw_buf, valid) &&
   4295                 _bcm_td2_l3_nat_ingress_key_match(unit, mem, hw_buf)) {
   4296                 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, hw_buf, 
   4297                                                             cf_array + (*cf_count));
   4298                 BCM_IF_ERROR_RETURN(rv);
   4299                 if ((++(*cf_count)) >= cf_max) {
   4300                     break;
   4301                 }
   4302             }
   4303         }
   4304     } 
   4305     return BCM_E_NONE;
   4306 }
   4307 #endif /* BCM_TRIDENT2_SUPPORT */
   4308 
   4309 /* 
   4310  * Function:
   4311  *      bcm_esw_l3_nat_ingress_conflict_get
   4312  *
   4313  * Description:
   4314  *      Given a DNAT or DNAT pool table key, return conflicts in the corresponding
   4315  *      table.
   4316  *
   4317  * Parameters:
   4318  *      unit            - (IN) bcm device
   4319  *      nat_info        - (IN) Destination NAT/NAPT lookup key
   4320  *      cf_array        - (OUT) array of conflicting addresses (at most 4)
   4321  *      cf_max          - (IN) max number of conflicts to return.
   4322  *      cf_count        - (OUT) actual number of conflicting entries.
   4323  * Returns:
   4324  *      BCM_E_XXX
   4325  */
   4326 int
   4327 bcm_esw_l3_nat_ingress_conflict_get(int unit, bcm_l3_nat_ingress_t *nat_info, 
   4328                                     bcm_l3_nat_ingress_t *cf_array, int cf_max, 
   4329                                     int *cf_count)
   4330 {
   4331     int rv = BCM_E_UNAVAIL;
   4332 
   4333 #if defined(BCM_TRIDENT2_SUPPORT)
   4334     if (soc_feature(unit, soc_feature_nat)) {
   4335         return _bcm_td2_l3_nat_ingress_conflict_get(unit, nat_info, cf_array, 
   4336                                                     cf_max, cf_count);
   4337     }
   4338 #endif /* BCM_TRIDENT2_SUPPORT */
   4339 
   4340     return rv;
   4341 }
   4342 #endif /* 0 */
   4343 
   4344 #endif /* INCLUDE_L3 */