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

l3.c (452673B)


      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  * File:    l3.c
      8  * Purpose: Manages L3 interface table, forwarding table, routing table
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <soc/defs.h>
     14 #include <bcm/error.h>
     15 #ifdef INCLUDE_L3
     16 #include <sal/core/libc.h>
     17 #include <soc/drv.h>
     18 #include <soc/scache.h>
     19 #include <soc/util.h>
     20 #include <soc/l3x.h>
     21 #include <soc/hash.h>
     22 #include <soc/mem.h>
     23 
     24 #if defined BCM_METROLITE_SUPPORT
     25 #include <soc/katana2.h>
     26 #endif
     27 
     28 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
     29 #include <soc/esw/ecmp.h>
     30 #endif /*  SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
     31 #ifdef CANCUN_SUPPORT
     32 #include <soc/esw/cancun.h>
     33 #endif /* CANCUN_SUPPORT */
     34 
     35 #include <bcm/l3.h>
     36 #include <bcm/debug.h>
     37 
     38 #include <bcm_int/esw/mbcm.h>
     39 #include <bcm_int/esw/l3.h>
     40 #include <bcm_int/esw/vlan.h>
     41 #include <bcm_int/esw/virtual.h>
     42 
     43 #ifdef  BCM_XGS_SWITCH_SUPPORT
     44 #include <bcm_int/esw/firebolt.h>
     45 #if defined(BCM_TRIUMPH_SUPPORT)
     46 #include <bcm_int/esw/triumph.h>
     47 #endif /* BCM_TRIUMPH_SUPPORT */
     48 #if defined(BCM_TRIUMPH2_SUPPORT)
     49 #include <bcm_int/esw/triumph2.h>
     50 #endif /* BCM_TRIUMPH2_SUPPORT */
     51 #if defined(BCM_TRIUMPH3_SUPPORT)
     52 #include <bcm_int/esw/triumph3.h>
     53 #endif /* BCM_TRIUMPH3_SUPPORT */
     54 #endif  /* BCM_XGS_SWITCH_SUPPORT */
     55 #ifdef BCM_WARM_BOOT_SUPPORT
     56 #include <bcm_int/esw/switch.h>
     57 #endif /* BCM_WARM_BOOT_SUPPORT */
     58 #if defined(BCM_TRIDENT2_SUPPORT)
     59 #include <bcm_int/esw/trident2.h>
     60 #endif /* BCM_TRIDENT2_SUPPORT */
     61 #if defined(BCM_TRIDENT3_SUPPORT)
     62 #include <bcm_int/esw/trident3.h>
     63 #include <soc/trident3.h>
     64 #endif /* BCM_TRIDENT3_SUPPORT */
     65 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 
     66 #include <bcm_int/esw/trident2plus.h>
     67 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
     68 #if defined(BCM_KATANA2_SUPPORT)
     69 #include <bcm_int/esw/katana2.h>
     70 #endif /* BCM_KATANA2_SUPPORT */
     71 #if defined(BCM_TOMAHAWK_SUPPORT)
     72 #include <bcm_int/esw/tomahawk.h>
     73 #endif /* BCM_TOMAHAWK_SUPPORT */
     74 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
     75 #include <bcm_int/esw/tomahawk2.h>
     76 #endif /* BCM_TOMAHAWK2_SUPPORT */
     77 #if defined(BCM_HGPROXY_COE_SUPPORT)
     78 #include <bcm_int/esw/xgs5.h>
     79 #endif /* BCM_HGPROXY_COE_SUPPORT */
     80 #if defined(BCM_TOMAHAWK3_SUPPORT)
     81 #include <bcm_int/esw/alpm.h>
     82 #include <bcm_int/esw/tomahawk3.h>
     83 #endif /* BCM_TOMAHAWK3_SUPPORT */
     84 
     85 #include <bcm_int/esw_dispatch.h>
     86 #include <bcm_int/esw/flex_ctr.h>
     87 #include <bcm_int/esw/switch.h>
     88 #include <bcm_int/common/multicast.h>
     89 #include <bcm_int/esw/multicast.h>
     90 
     91 /*
     92  * Special IP addresses
     93  */
     94 #define INADDR_ANY        (uint32)0x00000000
     95 #define INADDR_LOOPBACK   (uint32)0x7F000001
     96 #define INADDR_NONE       (uint32)0xffffffff
     97 
     98 #ifdef BCM_KATANA_SUPPORT
     99 #define _BCM_QOS_MAP_TYPE_MASK                     0x3ff
    100 #define _BCM_QOS_MAP_SHIFT                            10
    101 #define _BCM_QOS_MAP_TYPE_ING_QUEUE_OFFSET_MAP_TABLE   5
    102 #define _BCM_QOS_MAP_ING_QUEUE_OFFSET_MAX              7
    103 #endif
    104 /*
    105  * L3 book keeping global info
    106  */
    107 
    108 _bcm_l3_bookkeeping_t   _bcm_l3_bk_info[BCM_MAX_NUM_UNITS];
    109 static int              l3_internal_initialized = 0;
    110 
    111 #if defined(BCM_TOMAHAWK_SUPPORT)
    112 int ecmp_mode_hierarchical = TH_ECMP_MODE_HIERARCHICAL;
    113 int ecmp_mode_single = TH_ECMP_MODE_SINGLE;
    114 #endif
    115 
    116 #ifdef BCM_TOMAHAWK3_SUPPORT
    117 extern int ecmp_mode_hierarchical;
    118 #endif
    119 #define L3_INIT(unit) \
    120     if (!soc_feature(unit, soc_feature_l3)) { \
    121         return BCM_E_UNAVAIL; \
    122     } else if (!l3_internal_initialized) { \
    123         return BCM_E_DISABLED; \
    124     } else  { \
    125         if (!_bcm_l3_bk_info[unit].l3_initialized) { return BCM_E_INIT; } \
    126     }
    127 
    128 #if defined(BCM_TRIDENT3_SUPPORT)
    129 int bcmi_l3_init_check(int unit)
    130 {
    131     if (!soc_feature(unit, soc_feature_l3)) {
    132         return BCM_E_UNAVAIL;
    133     } else if (!soc_property_get(unit, spn_L3_ENABLE, 1)) {
    134         return BCM_E_DISABLED;
    135     } else  {
    136         if (!_bcm_l3_bk_info[unit].l3_initialized) { return BCM_E_INIT; }
    137     }
    138 
    139     return BCM_E_NONE;
    140 }
    141 #endif /*BCM_TRIDENT3_SUPPORT */
    142 
    143 int _bcm_l3_reinit(int unit)
    144 {
    145     _bcm_l3_bookkeeping_t *l3;
    146   
    147     l3 = &_bcm_l3_bk_info[unit];
    148    
    149     if (soc_property_get(unit, spn_L3_DISABLE_ADD_TO_ARL, 0)) {
    150         BCM_L3_BK_FLAG_SET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL);
    151     }
    152 
    153     if (soc_property_get(unit, spn_EMBEDDED_NH_VP_SUPPORT, 0)) {
    154 #ifdef BCM_TOMAHAWK_SUPPORT
    155         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
    156             BCM_L3_BK_FLAG_SET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE);
    157         }
    158 #endif /* BCM_TOMAHAWK_SUPPORT */
    159     }
    160 
    161 #ifdef BCM_XGS3_SWITCH_SUPPORT
    162     if ((SOC_IS_FB_FX_HX(unit) && !SOC_IS_RAPTOR(unit)) ||
    163         SOC_IS_TR_VL(unit) || SOC_IS_HB_GW(unit) || 
    164         SOC_IS_SC_CQ(unit)) {
    165         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_reinit(unit));
    166     }
    167 #endif
    168 
    169     l3->l3_initialized = 1;
    170     return BCM_E_NONE;
    171 }
    172 
    173 
    174 /*
    175  * Function:
    176  *      _bcm_esw_l3_gport_construct
    177  * Purpose:
    178  *      Constructs a gport out of given parameter for L3 Module.
    179  * Parameters:
    180  *      unit - SOC device unit number
    181  *      port_tgid - Physical port 
    182  *      modid - Module ID
    183  *      tgid  - Trunk group ID
    184  *      flags  - L3 Flags
    185  *      gport  - (Out) gport constructed from given arguments
    186  * Returns:
    187  *      BCM_E_XXX              
    188  */
    189 
    190 int
    191 _bcm_esw_l3_gport_construct(int unit, bcm_port_t port, bcm_module_t modid,
    192                             bcm_trunk_t tgid, uint32 flags, bcm_port_t *gport) 
    193 {
    194     int                 isGport, rv;
    195     _bcm_gport_dest_t   dest;
    196     bcm_module_t        mymodid;
    197 #if defined(BCM_KATANA2_SUPPORT)
    198     bcm_port_t          pp_port;
    199     int                 min_subport = SOC_INFO(unit).pp_port_index_min;
    200     int                 max_subport = SOC_INFO(unit).pp_port_index_max;
    201 #endif
    202 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
    203     int                 is_local_subport = 0;
    204 #endif
    205 
    206     if (NULL == gport) {
    207         return BCM_E_PARAM;
    208     }
    209 
    210     if (flags & BCM_L3_TGID) {
    211         if (BCM_FAILURE(_bcm_trunk_id_validate(unit, tgid))) {
    212             return BCM_E_PARAM;
    213         }
    214     } else if ((port < 0) && (modid < 0)){
    215         return BCM_E_PARAM;
    216     }
    217 
    218     BCM_IF_ERROR_RETURN(
    219         bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport));
    220 
    221     /* if output should not be gport then do nothing*/
    222     if (!isGport) {
    223         return BCM_E_NONE;
    224     }
    225 
    226     if (BCM_GPORT_IS_WLAN_PORT(port)) {
    227         return BCM_E_NONE;
    228     } 
    229 
    230 #if defined(BCM_HGPROXY_COE_SUPPORT)
    231     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe)) {
    232 
    233         if(_bcm_xgs5_subport_coe_mod_port_local(unit, modid, port)) {
    234             is_local_subport = 1;
    235 
    236             /* Encode our outgoing parameter as GPORT_SUBPORT type and
    237                fill in the associated (mod,port) */
    238             _BCM_SUBPORT_COE_PORT_ID_SET(*gport, modid, port);
    239 
    240             /* Set the bit on the outgoing param indicating this is subtag type */
    241             _BCM_SUBPORT_COE_PORT_TYPE_SET(*gport, _BCM_SUBPORT_COE_TYPE_SUBTAG);
    242         }
    243     }
    244 #endif
    245 #if defined(BCM_KATANA2_SUPPORT)
    246     if (soc_feature(unit, soc_feature_linkphy_coe) ||
    247         soc_feature(unit, soc_feature_subtag_coe)) {
    248         /* For LinkPHY/SubportPktTag pp_ports, check if the mod is a valid one */
    249         if ((_bcm_kt2_mod_is_coe_mod_check(unit, modid) == BCM_E_NONE)
    250                 && !(flags & BCM_L3_TGID)) {
    251             BCM_IF_ERROR_RETURN(_bcm_kt2_modport_to_pp_port_get(unit,
    252                 modid, port, &pp_port));
    253             /*For KT2, pp_port >=42 are used for LinkPHY/SubportPktTag subport.
    254             * Get the subport info associated with the pp_port and form the
    255             * subport_gport */
    256 #if defined BCM_METROLITE_SUPPORT
    257             if (soc_feature(unit, soc_feature_discontinuous_pp_port)) {
    258                 if (_SOC_IS_PP_PORT_LINKPHY_SUBTAG(unit, pp_port)) {
    259                     is_local_subport = 1;
    260                     /* construct LinkPHY/SubportPkttag subport gport */
    261                     _BCM_KT2_SUBPORT_PORT_ID_SET(*gport, pp_port);
    262                     if (BCM_PBMP_MEMBER(
    263                                 SOC_INFO(unit).linkphy_pp_port_pbm, pp_port)) {
    264                         _BCM_KT2_SUBPORT_PORT_TYPE_SET(*gport,
    265                                 _BCM_KT2_SUBPORT_TYPE_LINKPHY);
    266                     } else if (BCM_PBMP_MEMBER(
    267                                 SOC_INFO(unit).subtag_pp_port_pbm, pp_port)) {
    268                         _BCM_KT2_SUBPORT_PORT_TYPE_SET(*gport,
    269                                 _BCM_KT2_SUBPORT_TYPE_SUBTAG);
    270                     } else {
    271                         return BCM_E_PORT;
    272                     }
    273                 }
    274             } else
    275 #endif
    276             {
    277                 if ((pp_port >= min_subport) &&
    278                     (pp_port <= max_subport)) {
    279                     is_local_subport = 1;
    280                     /* construct LinkPHY/SubportPkttag subport gport */
    281                     _BCM_KT2_SUBPORT_PORT_ID_SET(*gport, pp_port);
    282                     if (BCM_PBMP_MEMBER(
    283                                 SOC_INFO(unit).linkphy_pp_port_pbm, pp_port)) {
    284                         _BCM_KT2_SUBPORT_PORT_TYPE_SET(*gport,
    285                                 _BCM_KT2_SUBPORT_TYPE_LINKPHY);
    286                     } else if (BCM_PBMP_MEMBER(
    287                                 SOC_INFO(unit).subtag_pp_port_pbm, pp_port)) {
    288                         _BCM_KT2_SUBPORT_PORT_TYPE_SET(*gport,
    289                                 _BCM_KT2_SUBPORT_TYPE_SUBTAG);
    290                     } else {
    291                         return BCM_E_PORT;
    292                     }
    293                 }
    294             }
    295         }
    296     }
    297 #endif
    298 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
    299     if (is_local_subport) {
    300         /* gport assigned above */
    301     } else
    302 #endif
    303     {
    304         _bcm_gport_dest_t_init(&dest);
    305 
    306         if (flags & BCM_L3_TGID) {
    307             dest.tgid = tgid;
    308             dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
    309         } else {
    310             /* Stacking ports should be encoded as devport */
    311             if (IS_ST_PORT(unit, port)) {
    312                 rv = bcm_esw_stk_my_modid_get(unit, &mymodid);
    313                 if (BCM_E_UNAVAIL == rv) {
    314                     dest.gport_type = _SHR_GPORT_TYPE_DEVPORT;
    315                 } else {
    316                     dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    317                     dest.modid = modid;
    318                 }
    319             } else {
    320                 dest.modid = modid;
    321                 dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    322             }
    323             dest.port = port;
    324         }
    325         BCM_IF_ERROR_RETURN(
    326             _bcm_esw_gport_construct(unit, &dest, gport));
    327     }
    328 
    329     return BCM_E_NONE;
    330 }
    331 
    332 
    333 /*
    334  * Function:
    335  *      _bcm_esw_l3_gport_resolve
    336  * Purpose:
    337  *      Resolves a gport for L3 Module.
    338  * Parameters:
    339  *      unit - SOC device unit number
    340  *      gport - gport provided 
    341  *      port  - (Out) Physical port decoded from gport
    342  *      modid - (Out) Module ID decodec from gport 
    343  *      tgid  - (Out) Trunk group ID decoded from gport
    344  *      gport  - (Out) gport constructed from given arguments
    345  * Returns:
    346  *      BCM_E_XXX              
    347  */
    348 int
    349 _bcm_esw_l3_gport_resolve(int unit, bcm_gport_t gport, bcm_port_t *port, 
    350                           bcm_module_t *modid, bcm_trunk_t *tgid, uint32 *flags)
    351 {
    352     int id;
    353     bcm_trunk_t     local_tgid;
    354     bcm_module_t    local_modid;
    355     bcm_port_t      local_port;
    356 
    357     if ((NULL == port) || (NULL == modid) || (NULL == tgid) || 
    358         (NULL == flags)) {
    359         return BCM_E_PARAM;
    360     }
    361    
    362     /*
    363      * if incoming port is an acceptable virtual port
    364      * for RIOT then use the port as it is.
    365      */
    366     if ((BCM_GPORT_IS_BLACK_HOLE(gport))  
    367 #ifdef BCM_RIOT_SUPPORT 
    368         || ((BCMI_RIOT_IS_ENABLED(unit))
    369             && (_bcm_vp_is_vfi_type(unit, gport))) 
    370 #endif
    371        ) {
    372         
    373          *port = gport;
    374          return BCM_E_NONE;
    375     } else {
    376         BCM_IF_ERROR_RETURN(
    377             _bcm_esw_gport_resolve(unit, gport,
    378             &local_modid, &local_port, &local_tgid, &id));
    379     }
    380 
    381 #if defined(BCM_HGPROXY_COE_SUPPORT)
    382     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
    383 		BCM_GPORT_IS_SET(gport) &&
    384         _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, gport)) {
    385     } else
    386 #endif
    387 #if defined(BCM_KATANA2_SUPPORT)
    388     if (BCM_GPORT_IS_SET(gport) &&
    389         _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT (unit, gport)) {
    390     } else
    391 #endif
    392     if (-1 != id) {
    393         return BCM_E_PARAM;
    394     }
    395 #ifdef BCM_KATANA_SUPPORT
    396     if (SOC_IS_KATANAX(unit) &&
    397        ((BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) ||
    398         (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(gport)) ||
    399         (BCM_GPORT_IS_MCAST_SUBSCRIBER_QUEUE_GROUP(gport)))) {
    400         *modid = local_modid;
    401         *port = local_port;
    402         *tgid = local_tgid; /* overlaying extended queue id in tgid */
    403     } else
    404 #endif 
    405     if (BCM_TRUNK_INVALID != local_tgid) {
    406         *flags |= BCM_L3_TGID;
    407         *tgid = local_tgid;
    408     } else {
    409         *modid = local_modid;
    410         *port = local_port;
    411     }
    412 
    413     return BCM_E_NONE;
    414 }
    415 
    416 #if defined(BCM_XGS3_SWITCH_SUPPORT)
    417 #ifdef BCM_WARM_BOOT_SUPPORT
    418 
    419 #define BCM_WB_PART_DEFAULT               0 /* L3 default warmboot state partition. */
    420 #define BCM_WB_PART_SOC_ECMP_STATE        1 /* SOC ECMP warmboot state partition. */
    421 
    422 #define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
    423 #define BCM_WB_VERSION_1_2                SOC_SCACHE_VERSION(1,2)
    424 #define BCM_WB_VERSION_1_3                SOC_SCACHE_VERSION(1,3)
    425 #define BCM_WB_VERSION_1_4                SOC_SCACHE_VERSION(1,4)
    426 #define BCM_WB_VERSION_1_5                SOC_SCACHE_VERSION(1,5)
    427 #define BCM_WB_VERSION_1_6                SOC_SCACHE_VERSION(1,6)
    428 #define BCM_WB_VERSION_1_7                SOC_SCACHE_VERSION(1,7)
    429 #define BCM_WB_VERSION_1_8                SOC_SCACHE_VERSION(1,8)
    430 #define BCM_WB_VERSION_1_9                SOC_SCACHE_VERSION(1,9)
    431 #define BCM_WB_VERSION_1_10               SOC_SCACHE_VERSION(1,10)
    432 #define BCM_WB_VERSION_1_11               SOC_SCACHE_VERSION(1,11)
    433 #define BCM_WB_VERSION_1_12               SOC_SCACHE_VERSION(1,12)
    434 #define BCM_WB_VERSION_1_13               SOC_SCACHE_VERSION(1,13)
    435 #define BCM_WB_VERSION_1_14               SOC_SCACHE_VERSION(1,14)
    436 #define BCM_WB_VERSION_1_15               SOC_SCACHE_VERSION(1,15)
    437 #define BCM_WB_VERSION_1_16               SOC_SCACHE_VERSION(1,16)
    438 #define BCM_WB_VERSION_1_17               SOC_SCACHE_VERSION(1,17)
    439 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_17
    440 
    441 
    442 /*
    443  * Function:
    444  *      _bcm_esw_l3_sync
    445  * Purpose:
    446  *      Record L3 module persisitent info for Level 2 Warm Boot
    447  * Parameters:
    448  *      unit - StrataSwitch unit number.
    449  * Returns:
    450  *      BCM_E_XXX
    451  */
    452 
    453 int
    454 _bcm_esw_l3_sync(int unit)
    455 {
    456     soc_scache_handle_t scache_handle;
    457     uint8 *l3_scache_ptr;
    458     int alloc_sz = 2 * sizeof(int32); /* Egress, HostAdd mode */
    459     int32 l3EgressMode = 0;
    460     int32 l3HostAddMode = 0;
    461     int alloc_size = 0;
    462     SHR_BITDCL *ecmp_flags = NULL;
    463 #ifdef BCM_TRIUMPH_SUPPORT
    464     int32 l3IntfMapMode = 0;
    465     int32 l3IngressMode = 0;
    466 #endif /* BCM_TRIUMPH_SUPPORT */
    467 #ifdef BCM_TRIUMPH2_SUPPORT
    468     int idx;
    469 #endif
    470 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
    471     int l3_flags_synced = 0;
    472     int l3_flags_alloced = 0;
    473     int i;
    474     uint8 flag = 0;
    475 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
    476 #ifdef BCM_TRIDENT2_SUPPORT
    477     _bcm_l3_tbl_t *ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
    478 #endif
    479 #ifdef BCM_TOMAHAWK_SUPPORT   
    480     int j;
    481     SHR_BITDCL *ecmp_l1_flags = NULL;
    482     SHR_BITDCL *ecmp_l2_flags = NULL;
    483 #endif /* BCM_TOMAHAWK_SUPPORT */
    484 #ifdef BCM_TRIUMPH_SUPPORT
    485     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
    486         alloc_sz  += sizeof(int32); /* Ingress mode */
    487         alloc_sz  += sizeof(int32); /* Interface Map mode */
    488     }
    489 #endif /* BCM_TRIUMPH_SUPPORT */
    490 
    491 #ifdef BCM_TRIUMPH2_SUPPORT
    492     /* For extended scache warmboot mode (level-2) only */
    493     if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
    494         BCM_XGS3_L3_MAX_ECMP_MODE(unit)                      &&
    495         !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    496         alloc_sz += sizeof(uint16) *
    497                     BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
    498     }
    499 #endif
    500 
    501 #ifdef BCM_TRIUMPH3_SUPPORT
    502     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
    503         int ecmp_dlb_alloc_sz = 0;
    504 
    505 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined (BCM_TRIDENT3_SUPPORT)
    506         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
    507             BCM_IF_ERROR_RETURN
    508                 (bcm_th2_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz));
    509         } else
    510 #endif /* BCM_TOMAHAWK2_SUPPORT */
    511         {
    512             BCM_IF_ERROR_RETURN
    513                 (bcm_tr3_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz));
    514         }
    515         alloc_sz += ecmp_dlb_alloc_sz;
    516     }
    517 #endif /* BCM_TRIUMPH3_SUPPORT */
    518 
    519 #ifdef BCM_TRIUMPH2_SUPPORT
    520         if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
    521                 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
    522             int wb_alloc_sz;
    523 
    524             BCM_IF_ERROR_RETURN
    525                 (bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get(unit,
    526                                                                      &wb_alloc_sz));
    527             alloc_sz += wb_alloc_sz;
    528         }
    529 #endif /* BCM_TRIUMPH2_SUPPORT */
    530 
    531 #ifdef BCM_TRIDENT2_SUPPORT
    532     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_6) {
    533         if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
    534             int wb_alloc_sz;
    535             BCM_IF_ERROR_RETURN
    536                 (_bcm_td2_l3_ip4_options_profile_scache_len_get(unit, &wb_alloc_sz));
    537                 alloc_sz += wb_alloc_sz;
    538         }
    539     }
    540 
    541 #endif /* BCM_TRIDENT2_SUPPORT */
    542 
    543 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\
    544     defined(BCM_HURRICANE3_SUPPORT)
    545     if (soc_feature(unit, soc_feature_l3_ingress_interface) &&
    546         !soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
    547         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
    548     }
    549 #endif /* defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||
    550         * defined(BCM_HURRICANE3_SUPPORT)
    551         */
    552     /* ECMP max paths info */
    553     alloc_sz += sizeof(int);
    554 
    555     /* Determine ECMP_GROUP entry number in 32-bits words */
    556     if (soc_feature(unit, soc_feature_l3)) {
    557         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
    558     }
    559 
    560 #ifdef BCM_TOMAHAWK_SUPPORT
    561     /* Determine Hierarchical ECMP Level flags */
    562     if (soc_feature(unit, soc_feature_l3) &&
    563         soc_feature(unit, soc_feature_hierarchical_ecmp)) {
    564         /* ECMP Level 1 flags */
    565         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
    566         /* ECMP Level 2 flags */
    567         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
    568     }
    569 #endif /* BCM_TOMAHAWK_SUPPORT */
    570 
    571 #ifdef BCM_TRIDENT2_SUPPORT
    572     /* Determine ECMP_GROUP resorting flags*/
    573     if (soc_feature(unit, soc_feature_l3)) {
    574         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
    575     }
    576 #endif
    577 #ifdef BCM_TRIUMPH3_SUPPORT
    578    if (soc_feature(unit, soc_feature_l2gre)) {
    579        alloc_sz +=  BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
    580        l3_flags_alloced = 1;
    581    }
    582 #endif /* BCM_TRIUMPH3_SUPPORT */
    583 #ifdef BCM_TRIDENT_SUPPORT
    584    if (soc_feature(unit, soc_feature_trill)) {
    585        if (!l3_flags_alloced) {
    586            alloc_sz +=  BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
    587            l3_flags_alloced = 1;
    588        }
    589    }
    590 #endif /* BCM_TRIDENT_SUPPORT */
    591 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
    592     if (soc_feature(unit, soc_feature_vxlan) ||
    593         soc_feature(unit, soc_feature_vxlan_lite)) {
    594         if (!l3_flags_alloced) {
    595             alloc_sz += BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
    596             l3_flags_alloced = 1;
    597         }
    598     }
    599 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
    600 #ifdef BCM_TOMAHAWK_SUPPORT
    601     /* Determine ECMP_GROUP RH members */
    602     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
    603         /* ECMP RH max paths */
    604         alloc_sz += sizeof(int);
    605         /* ECMP max paths info per RH group */
    606         alloc_sz += sizeof(uint16) *
    607                     BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
    608         /* Group, member tuples */
    609         alloc_sz += (RH_ECMP_MEMBER_TBL_MAX(unit) *
    610                        (sizeof(int16) + sizeof(bcm_if_t)));
    611     }
    612     if (SOC_IS_TOMAHAWKX(unit)) {
    613         /* This space is reserved for TH L3 extended view */
    614         bcm_th_l3_extended_required_scache_size_get(unit, &alloc_sz);
    615     }
    616 
    617 #endif /* BCM_TOMAHAWK_SUPPORT */
    618 
    619     /* memory needed for multi level prot s/w state */
    620     if (soc_feature(unit, soc_feature_l3) &&
    621         (soc_feature(unit, soc_feature_hierarchical_protection))) {
    622 
    623         alloc_sz +=  (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
    624     }
    625 
    626 #ifdef BCM_TRIDENT_SUPPORT
    627    if (soc_feature(unit, soc_feature_nh_for_ifp_actions)) {
    628        if (!l3_flags_alloced) {
    629            alloc_sz +=  BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
    630        }
    631    }
    632 #endif /* BCM_TRIDENT_SUPPORT */
    633 
    634 #if defined(BCM_RIOT_SUPPORT)
    635     if (soc_feature(unit, soc_feature_riot)) {
    636         /* This space is reserved for TD2P L3 extended view */
    637         bcm_td2p_l3_extended_required_scache_size_get(unit, &alloc_sz);
    638     }
    639 #endif /* BCM_RIOT_SUPPORT */
    640 
    641 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
    642     if (soc_feature(unit, soc_feature_dgm)) {
    643         alloc_sz += sizeof(uint16) *
    644                     BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
    645     }
    646 #endif /* BCM_TOMAHAWK2_SUPPORT */
    647     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_15) {
    648         /* Space reserved to store Maximum VRF IDs on the device */
    649         alloc_sz += sizeof(uint16);
    650     }
    651     if (!(BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL))
    652           && (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_16)) {
    653         /* arl interface bitamp */
    654         alloc_sz += SHR_BITALLOCSIZE(soc_mem_index_count(unit,  EGR_L3_INTFm));
    655     }
    656 
    657 #if defined(BCM_TRX_SUPPORT)
    658     if (soc_feature(unit, soc_feature_l3_ingress_interface) &&
    659         soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
    660         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
    661     }
    662 #endif /* BCM_TRX_SUPPORT */
    663 
    664     L3_INIT(unit);
    665 
    666     SOC_SCACHE_HANDLE_SET(scache_handle,  unit, BCM_MODULE_L3, 0);
    667     BCM_IF_ERROR_RETURN
    668         (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
    669                                  alloc_sz, &l3_scache_ptr, 
    670                                  BCM_WB_DEFAULT_VERSION, NULL));
    671 
    672     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_egress_mode_get(unit, &l3EgressMode));
    673     sal_memcpy(l3_scache_ptr, &l3EgressMode, sizeof(l3EgressMode));
    674     l3_scache_ptr += sizeof(l3EgressMode);
    675 
    676 #ifdef BCM_TRIUMPH_SUPPORT
    677     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
    678         BCM_IF_ERROR_RETURN(bcm_xgs3_l3_ingress_mode_get(unit, &l3IngressMode));
    679         sal_memcpy(l3_scache_ptr, &l3IngressMode, sizeof(l3IngressMode));
    680         l3_scache_ptr += sizeof(l3IngressMode);
    681     }
    682 #endif /* BCM_TRIUMPH_SUPPORT */
    683 
    684     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_host_as_route_return_get(unit, &l3HostAddMode));
    685     sal_memcpy(l3_scache_ptr, &l3HostAddMode, sizeof(l3HostAddMode));
    686     l3_scache_ptr += sizeof(l3HostAddMode);
    687 
    688 #ifdef BCM_TRIUMPH_SUPPORT
    689     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
    690        BCM_IF_ERROR_RETURN(bcm_xgs3_l3_ingress_intf_map_get(unit, &l3IntfMapMode));
    691        sal_memcpy(l3_scache_ptr, &l3IntfMapMode,  sizeof(l3IntfMapMode));
    692        l3_scache_ptr += sizeof(l3IntfMapMode);
    693     }
    694 #endif /* BCM_TRIUMPH_SUPPORT */
    695 
    696 #ifdef BCM_TRIUMPH2_SUPPORT
    697     /* For extended scache warmboot mode (level-2) only */
    698     if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
    699         BCM_XGS3_L3_MAX_ECMP_MODE(unit)                      &&
    700         !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    701         for(idx=0; idx<BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); idx++) {
    702             sal_memcpy(l3_scache_ptr,
    703                        &(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[idx]),
    704                        sizeof(uint16));
    705             l3_scache_ptr += sizeof(uint16);
    706         }
    707     }
    708 #endif
    709 
    710 #ifdef BCM_TRIUMPH3_SUPPORT
    711     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
    712 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined (BCM_TRIDENT3_SUPPORT)
    713         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
    714             BCM_IF_ERROR_RETURN
    715                 (bcm_th2_ecmp_dlb_sync(unit, &l3_scache_ptr));
    716         } else
    717 #endif /* BCM_TOMAHAWK2_SUPPORT */
    718         {
    719             BCM_IF_ERROR_RETURN(bcm_tr3_ecmp_dlb_sync(unit, &l3_scache_ptr));
    720         }
    721     }
    722 #endif /* BCM_TRIUMPH3_SUPPORT */
    723 
    724 #ifdef BCM_TRIUMPH2_SUPPORT
    725     if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
    726             soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
    727         if (!soc_feature(unit, soc_feature_l3_no_ecmp)) {
    728             BCM_IF_ERROR_RETURN
    729                 (bcm_tr2_l3_ecmp_defragment_buffer_sync(unit, &l3_scache_ptr));
    730         }
    731     }
    732 #endif /* BCM_TRIUMPH2_SUPPORT */
    733 
    734 #ifdef BCM_TRIDENT2_SUPPORT
    735     if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
    736         BCM_IF_ERROR_RETURN(_bcm_td2_l3_ip4_options_sync(unit, &l3_scache_ptr));
    737     }
    738 
    739 #endif /* BCM_TRIDENT2_SUPPORT */
    740 
    741     sal_memcpy(l3_scache_ptr, &BCM_XGS3_L3_ECMP_MAX_PATHS(unit), sizeof(int));
    742     l3_scache_ptr += sizeof(int);
    743 
    744     /* Store ECMP_GRP valid/invalid bit to Scache */
    745     if (soc_feature(unit, soc_feature_l3) && !soc_feature(unit, soc_feature_l3_no_ecmp)) {
    746         int i;
    747         _bcm_l3_tbl_t *ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
    748         alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
    749         ecmp_flags = sal_alloc(alloc_size, "ECMP flags");
    750         if (ecmp_flags == NULL) {
    751             return SOC_E_MEMORY;
    752         }
    753         sal_memset(ecmp_flags, 0, alloc_size);
    754 
    755         for (i = 0; i <= ecmp_tbl_ptr->idx_max; i++) {
    756 #ifdef BCM_TOMAHAWK3_SUPPORT
    757             if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
    758                 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
    759                                                 ecmp_mode_hierarchical) &&
    760                 (i < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
    761                 _bcm_l3_tbl_t *hecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
    762                 if (BCM_XGS3_L3_ENT_REF_CNT(hecmp_tbl_ptr, i) > 0) {
    763                     SHR_BITSET(ecmp_flags, i);
    764                 }
    765                 continue;
    766             }
    767 #endif
    768 
    769             if (BCM_XGS3_L3_ENT_REF_CNT(ecmp_tbl_ptr, i) > 0) {
    770                 SHR_BITSET(ecmp_flags, i);
    771             }
    772         }
    773         sal_memcpy(l3_scache_ptr, ecmp_flags, alloc_size);
    774         l3_scache_ptr += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
    775         sal_free(ecmp_flags);
    776     }
    777 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\
    778     defined(BCM_HURRICANE3_SUPPORT)
    779     if (soc_feature(unit, soc_feature_l3_ingress_interface) &&
    780         !soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
    781         sal_memcpy(l3_scache_ptr, BCM_XGS3_L3_ING_IF_INUSE(unit), 
    782             SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)));
    783         l3_scache_ptr += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
    784     }
    785 #endif /* defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||
    786         * defined(BCM_HURRICANE3_SUPPORT)
    787         */
    788     
    789 #ifdef BCM_TRIDENT2_SUPPORT
    790     if (soc_feature(unit, soc_feature_l3) && !soc_feature(unit, soc_feature_l3_no_ecmp)) {
    791         alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
    792         ecmp_flags = sal_alloc(alloc_size, "ECMP flags");
    793         if (ecmp_flags == NULL) {
    794             return SOC_E_MEMORY;
    795         }
    796         sal_memset(ecmp_flags, 0, alloc_size);
    797 
    798         for (i = 0; i <= ecmp_tbl_ptr->idx_max; i++) {
    799             if (BCM_XGS3_L3_ENT_REF_CNT(ecmp_tbl_ptr, i) > 0 &&
    800                  (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, i,
    801                            BCM_L3_ECMP_PATH_NO_SORTING))) {
    802                 SHR_BITSET(ecmp_flags, i);
    803             }
    804         }
    805         sal_memcpy(l3_scache_ptr, ecmp_flags, alloc_size);
    806         l3_scache_ptr += alloc_size;
    807         sal_free(ecmp_flags);
    808     }
    809 #endif
    810 #ifdef BCM_TRIUMPH3_SUPPORT
    811     if (soc_feature(unit, soc_feature_l2gre)) {
    812         for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
    813             flag = BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), i);
    814             sal_memcpy(l3_scache_ptr, &flag, sizeof(uint8));
    815             l3_scache_ptr += sizeof(uint8);
    816         }  
    817         l3_flags_synced = 1;
    818     }
    819 #endif /* BCM_TRIUMPH3_SUPPORT */
    820 #ifdef BCM_TRIDENT_SUPPORT
    821     if (soc_feature(unit, soc_feature_trill)) {
    822         if (!l3_flags_synced) {
    823             for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
    824                 flag = BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), i);
    825                 sal_memcpy(l3_scache_ptr, &flag, sizeof(uint8));
    826                 l3_scache_ptr += sizeof(uint8);
    827             }  
    828             l3_flags_synced = 1;
    829         }
    830     }
    831 #endif /* BCM_TRIDENT_SUPPORT */       
    832 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
    833     if (soc_feature(unit, soc_feature_vxlan) ||
    834         soc_feature(unit, soc_feature_vxlan_lite)) {
    835         if (!l3_flags_synced) {
    836             for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
    837                 flag = BCM_XGS3_L3_ENT_FLAG(
    838                     BCM_XGS3_L3_TBL_PTR(unit, next_hop), i);
    839                 sal_memcpy(l3_scache_ptr, &flag, sizeof(uint8));
    840                 l3_scache_ptr += sizeof(uint8);
    841             }
    842             l3_flags_synced = 1;
    843         }
    844     }
    845 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
    846 #ifdef BCM_TOMAHAWK_SUPPORT
    847     if (soc_feature(unit, soc_feature_l3) &&
    848         soc_feature(unit, soc_feature_hierarchical_ecmp)) {
    849         alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
    850         ecmp_l1_flags = sal_alloc(alloc_size, "ECMP level1 flags");
    851         if (ecmp_l1_flags == NULL) {
    852             return SOC_E_MEMORY;
    853         }
    854         ecmp_l2_flags = sal_alloc(alloc_size, "ECMP level2 flags");
    855         if (ecmp_l2_flags == NULL) {
    856             sal_free(ecmp_l1_flags);
    857             return SOC_E_MEMORY;
    858         }
    859         sal_memset(ecmp_l1_flags, 0, alloc_size);
    860         sal_memset(ecmp_l2_flags, 0, alloc_size);
    861         for (j = 0; j <= ecmp_tbl_ptr->idx_max; j++) {
    862             if (BCM_XGS3_L3_ENT_REF_CNT(ecmp_tbl_ptr, j) > 0 &&
    863                 (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, j,
    864                                BCM_L3_ECMP_OVERLAY))) {
    865                 SHR_BITSET(ecmp_l1_flags, j);
    866             }
    867             if (BCM_XGS3_L3_ENT_REF_CNT(ecmp_tbl_ptr, j) > 0 &&
    868                 (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, j,
    869                                BCM_L3_ECMP_UNDERLAY))) {
    870                 SHR_BITSET(ecmp_l2_flags, j);
    871             }
    872         }
    873         sal_memcpy(l3_scache_ptr, ecmp_l1_flags, alloc_size);
    874         l3_scache_ptr += alloc_size;
    875         sal_memcpy(l3_scache_ptr, ecmp_l2_flags, alloc_size);
    876         l3_scache_ptr += alloc_size;
    877         sal_free(ecmp_l1_flags);
    878         sal_free(ecmp_l2_flags);
    879     }
    880     if (soc_feature(unit, soc_feature_l3) &&
    881         soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
    882         /* save interface count for each ecmp group */
    883         BCM_IF_ERROR_RETURN
    884             (bcm_opt_l3_ecmp_rh_member_sync(unit, &l3_scache_ptr));
    885     }
    886     if (SOC_IS_TOMAHAWKX(unit)) {
    887         BCM_IF_ERROR_RETURN
    888             (bcm_th_l3_extended_view_sync(unit, &l3_scache_ptr));
    889     }
    890 #endif /* BCM_TOMAHAWK_SUPPORT */
    891 
    892     if (soc_feature(unit, soc_feature_l3) &&
    893         (soc_feature(unit, soc_feature_hierarchical_protection))) {
    894 
    895         sal_memcpy(l3_scache_ptr, BCM_XGS3_L3_NH_MULTI_COUNT(unit),
    896             BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
    897         l3_scache_ptr += (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
    898     }
    899 
    900 #ifdef BCM_TRIDENT_SUPPORT
    901     if (soc_feature(unit, soc_feature_nh_for_ifp_actions)) {
    902         if (!l3_flags_synced) {
    903             for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
    904                 flag = BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), i);
    905                 sal_memcpy(l3_scache_ptr, &flag, sizeof(uint8));
    906                 l3_scache_ptr += sizeof(uint8);
    907             }
    908         }
    909     }
    910 #endif /* BCM_TRIDENT_SUPPORT */
    911 #if defined(BCM_RIOT_SUPPORT)
    912     if (soc_feature(unit, soc_feature_riot)) {
    913         BCM_IF_ERROR_RETURN
    914             (bcm_td2p_l3_extended_view_sync(unit, &l3_scache_ptr));
    915     }
    916 #endif /* BCM_RIOT_SUPPORT */
    917 
    918 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
    919     if (soc_feature(unit, soc_feature_dgm)) {
    920         for (idx = 0; idx < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); idx++) {
    921             sal_memcpy(l3_scache_ptr,
    922                        &(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[idx]),
    923                        sizeof(uint16));
    924             l3_scache_ptr += sizeof(uint16);
    925         }
    926     }
    927 #endif
    928     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_15) {
    929         /* Maximum VRF Ids on the device */
    930         sal_memcpy(l3_scache_ptr, &(SOC_VRF_MAX(unit)), sizeof(uint16));
    931         l3_scache_ptr += sizeof(uint16);
    932     }
    933     if (!(BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL))
    934           && (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_16)) {
    935         /* arl interface bit map */
    936         sal_memcpy(l3_scache_ptr, BCM_XGS3_L3_IF_ADD2ARL(unit),
    937                    SHR_BITALLOCSIZE(soc_mem_index_count(unit,  EGR_L3_INTFm)));
    938         l3_scache_ptr +=  SHR_BITALLOCSIZE(soc_mem_index_count(unit,  EGR_L3_INTFm));
    939     }
    940 
    941 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
    942     if (soc_feature(unit, soc_feature_ecmp_dlb) &&
    943         soc_feature(unit, soc_feature_ecmp_dlb_optimized) &&
    944         !soc_feature(unit, soc_feature_th3_style_dlb)) {
    945         BCM_IF_ERROR_RETURN(
    946             bcm_th2_ecmp_dlb_member_sync(unit, &l3_scache_ptr));
    947     }
    948 #endif /* BCM_TOMAHAWK2_SUPPORT */
    949 
    950 #if defined(BCM_TRX_SUPPORT)
    951     if (soc_feature(unit, soc_feature_l3_ingress_interface) &&
    952         soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
    953         sal_memcpy(l3_scache_ptr, BCM_XGS3_L3_ING_IF_INUSE(unit),
    954                 SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)));
    955         l3_scache_ptr += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
    956     }
    957 #endif
    958 
    959 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
    960     if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) {
    961         /* Sync ecmp protected warmboot state (separate partition). */
    962         BCM_IF_ERROR_RETURN(soc_esw_ecmp_protected_state_warmboot_sync(unit));
    963     }
    964 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
    965 
    966     return BCM_E_NONE;
    967 }
    968 
    969 /*
    970  * Function:
    971  *      _bcm_esw_l3_warm_boot_alloc
    972  * Purpose:
    973  *      Allocate persistent info memory for L3 module - Level 2 Warm Boot
    974  * Parameters:
    975  *      unit - StrataSwitch unit number.
    976  * Returns:
    977  *      BCM_E_XXX
    978  */
    979 STATIC int
    980 _bcm_esw_l3_warm_boot_alloc(int unit)
    981 {
    982     int rv;
    983     int alloc_sz = 2 * sizeof(int32); /* Egress, Host modes */
    984     uint8 *l3_scache_ptr;
    985     soc_scache_handle_t scache_handle;
    986 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
    987     int l3_flags_alloced = 0;
    988 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
    989 
    990 #ifdef BCM_TRIUMPH2_SUPPORT
    991     BCM_XGS3_L3_MAX_ECMP_MODE(unit) = (SOC_IS_TRIUMPH3(unit)) ? TRUE :
    992                            soc_property_get(unit, spn_L3_MAX_ECMP_MODE, 0);
    993 #endif
    994 
    995     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_1) {
    996 #ifdef BCM_TRIUMPH_SUPPORT 
    997         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
    998             alloc_sz += sizeof(int32); /* Ingress mode */
    999         }
   1000 #endif /* BCM_TRIUMPH_SUPPORT */
   1001     }
   1002     
   1003     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_2) {
   1004 #ifdef BCM_TRIUMPH_SUPPORT 
   1005         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   1006             alloc_sz += sizeof(int32); /* intfMap mode */
   1007         }
   1008 #endif /* BCM_TRIUMPH_SUPPORT */
   1009     }
   1010     
   1011     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_3) {
   1012 #ifdef BCM_TRIUMPH2_SUPPORT
   1013         /* For extended scache warmboot mode (level-2) only */
   1014         if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
   1015             BCM_XGS3_L3_MAX_ECMP_MODE(unit)                      &&
   1016             !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
   1017             alloc_sz += sizeof(uint16) *
   1018                 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   1019         }
   1020 #endif
   1021 
   1022 #ifdef BCM_TRIUMPH3_SUPPORT
   1023         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   1024             int ecmp_dlb_alloc_sz = 0;
   1025 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   1026             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   1027                 BCM_IF_ERROR_RETURN
   1028                 (bcm_th2_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz));
   1029             } else
   1030 #endif /* BCM_TOMAHAWK2_SUPPORT */
   1031             {
   1032                 BCM_IF_ERROR_RETURN
   1033                 (bcm_tr3_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz));
   1034             }
   1035             alloc_sz += ecmp_dlb_alloc_sz;
   1036         }
   1037 #endif /* BCM_TRIUMPH3_SUPPORT */
   1038 
   1039 #ifdef BCM_TRIUMPH2_SUPPORT
   1040         if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
   1041                 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   1042             int wb_alloc_sz;
   1043 
   1044             BCM_IF_ERROR_RETURN
   1045                 (bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get(unit,
   1046                                                                      &wb_alloc_sz));
   1047             alloc_sz += wb_alloc_sz;
   1048         }
   1049 #endif /* BCM_TRIUMPH2_SUPPORT */
   1050     }
   1051     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_6) {
   1052 #ifdef BCM_TRIDENT2_SUPPORT 
   1053         if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
   1054             int wb_alloc_sz;
   1055             BCM_IF_ERROR_RETURN
   1056                 (_bcm_td2_l3_ip4_options_profile_scache_len_get(unit, &wb_alloc_sz));
   1057                 alloc_sz += wb_alloc_sz;
   1058         }
   1059 #endif /* BCM_TRIUMPH_SUPPORT */
   1060     }
   1061 
   1062 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\
   1063     defined(BCM_HURRICANE3_SUPPORT)
   1064     if (soc_feature(unit, soc_feature_l3_ingress_interface)){
   1065         alloc_sz +=
   1066             SHR_BITALLOCSIZE(soc_mem_index_count(unit, L3_IIFm));
   1067     }
   1068 #endif /* defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||
   1069         * defined(BCM_HURRICANE3_SUPPORT)
   1070         */
   1071     /* to save max ecmp paths info */
   1072     alloc_sz += sizeof(int);
   1073 
   1074     /* each bit save per L3_ECMP_GROUP entry valid/invalid */
   1075     if (soc_feature(unit, soc_feature_l3)) {
   1076         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   1077     }
   1078  
   1079 #ifdef BCM_TOMAHAWK_SUPPORT   
   1080     /* Determine Hierarchical ECMP Level flags */
   1081     if (soc_feature(unit, soc_feature_l3) &&
   1082         soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   1083         /* ECMP Level 1 flags */
   1084         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
   1085         /* ECMP Level 2 flags */
   1086         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
   1087     }
   1088 #endif /* BCM_TOMAHAWK_SUPPORT */
   1089 
   1090 #ifdef BCM_TRIDENT2_SUPPORT   
   1091     /* ECMP group resorting flag */
   1092     if (soc_feature(unit, soc_feature_l3)) {
   1093         alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   1094     }
   1095 #endif
   1096 #ifdef BCM_TRIUMPH3_SUPPORT
   1097     if (soc_feature(unit, soc_feature_l2gre)) {
   1098         alloc_sz += soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   1099         l3_flags_alloced = 1;
   1100     }
   1101 #endif /* BCM_TRIUMPH3_SUPPORT */
   1102 #ifdef BCM_TRIDENT_SUPPORT
   1103     if (soc_feature(unit, soc_feature_trill)) {
   1104         if (!l3_flags_alloced) {
   1105             alloc_sz += soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   1106             l3_flags_alloced = 1;
   1107         }
   1108     }
   1109 #endif /* BCM_TRIDENT_SUPPORT */   
   1110 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   1111     if (soc_feature(unit, soc_feature_vxlan) ||
   1112         soc_feature(unit, soc_feature_vxlan_lite)) {
   1113         if (!l3_flags_alloced) {
   1114             alloc_sz += soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   1115             l3_flags_alloced = 1;
   1116         }
   1117     }
   1118 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   1119 #ifdef BCM_TOMAHAWK_SUPPORT 
   1120     if (soc_feature(unit, soc_feature_l3) &&
   1121         soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   1122         /* Save RH max paths */
   1123         alloc_sz += sizeof(int);
   1124         /* ECMP max paths info per RH group */
   1125         alloc_sz += sizeof(uint16) *
   1126                     BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   1127         /* save interface count for each ecmp group */
   1128         alloc_sz += (RH_ECMP_MEMBER_TBL_MAX(unit) *
   1129                        (sizeof(int16) + sizeof(bcm_if_t)));
   1130     }
   1131     if (SOC_IS_TOMAHAWKX(unit)) {
   1132         int th_wb_l3_extended_size = 0;
   1133         /* Get the required scache size */
   1134         bcm_th_l3_extended_required_scache_size_get(unit, &th_wb_l3_extended_size);
   1135         alloc_sz += th_wb_l3_extended_size;
   1136     }
   1137 #endif /* BCM_TOMAHAWK_SUPPORT */
   1138 
   1139     /* memory needed for multi level prot s/w state */
   1140     if (soc_feature(unit, soc_feature_l3) &&
   1141         (soc_feature(unit, soc_feature_hierarchical_protection))) {
   1142 
   1143         alloc_sz += (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
   1144     }
   1145 
   1146 #ifdef BCM_TRIDENT_SUPPORT
   1147     if (soc_feature(unit, soc_feature_nh_for_ifp_actions)) {
   1148         if (!l3_flags_alloced) {
   1149             alloc_sz += soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   1150         }
   1151     }
   1152 #endif /* BCM_TRIDENT_SUPPORT */
   1153 #if defined(BCM_RIOT_SUPPORT)
   1154     if (soc_feature(unit, soc_feature_riot)) {
   1155         int td2p_wb_l3_extended_size = 0;
   1156         bcm_td2p_l3_extended_required_scache_size_get(unit, &td2p_wb_l3_extended_size);
   1157         alloc_sz += td2p_wb_l3_extended_size;
   1158     }
   1159 #endif /* BCM_RIOT_SUPPORT */
   1160 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   1161     if (soc_feature(unit, soc_feature_dgm)) {
   1162         alloc_sz += sizeof(uint16) *
   1163                     BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   1164     }
   1165 #endif /* BCM_TOMAHAWK2_SUPPORT */
   1166     if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_15) {
   1167         /* Maximum VRF IDs on the device */
   1168         alloc_sz += sizeof(uint16);
   1169     }
   1170  
   1171     if (!(BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL)) &&
   1172          (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_16)) {
   1173         /* arl interface bitamp */
   1174         alloc_sz += SHR_BITALLOCSIZE(soc_mem_index_count(unit,  EGR_L3_INTFm));
   1175     }
   1176 
   1177 
   1178     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L3, 0);
   1179 
   1180     /* This function is only used for Cold Boot */
   1181     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE,
   1182                                  alloc_sz, &l3_scache_ptr, 
   1183                                  BCM_WB_DEFAULT_VERSION, NULL);
   1184 
   1185     if (BCM_E_NOT_FOUND == rv) {
   1186         /* Proceed with Level 1 Warm Boot */
   1187         rv = BCM_E_NONE;
   1188     }
   1189 
   1190     return rv;
   1191 }
   1192 #endif /* BCM_WARM_BOOT_SUPPORT */
   1193 #endif /* defined(BCM_XGS3_SWITCH_SUPPORT) */
   1194 
   1195 /*
   1196  * Function:
   1197  *      bcm_l3_init
   1198  * Purpose:
   1199  *      Initialize the L3 table, default IP table and the L3 interface table.
   1200  * Parameters:
   1201  *      unit - SOC device unit number
   1202  * Returns:
   1203  *      BCM_E_NONE              Success
   1204  *      BCM_E_UNIT              Illegal unit number
   1205  *      BCM_E_MEMORY            Cannot allocate memory
   1206  *      BCM_E_INTERNAL          Chip access failure
   1207  * Notes:
   1208  *      This function has to be called before any other L3 functions.
   1209  */
   1210 
   1211 int
   1212 bcm_esw_l3_init(int unit)
   1213 {
   1214     _bcm_l3_bookkeeping_t *l3;
   1215 
   1216     if (!soc_feature(unit, soc_feature_l3)) {
   1217         if (!soc_feature(unit, soc_feature_miml_no_l3)) {
   1218             return BCM_E_UNAVAIL;
   1219         }
   1220     }
   1221 
   1222     if (!soc_property_get(unit, spn_L3_ENABLE, 1)) {
   1223         l3_internal_initialized = 0;
   1224         return BCM_E_DISABLED;
   1225     }
   1226 
   1227 
   1228     if (!l3_internal_initialized) {
   1229         sal_memset(_bcm_l3_bk_info, 0,
   1230                    BCM_MAX_NUM_UNITS * sizeof(_bcm_l3_bookkeeping_t));
   1231         l3_internal_initialized = 1;
   1232     }
   1233 
   1234     l3 = &_bcm_l3_bk_info[unit];
   1235     l3->flags = 0;
   1236 
   1237     if (soc_property_get(unit, spn_L3_DISABLE_ADD_TO_ARL, 0)) {
   1238         BCM_L3_BK_FLAG_SET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL);
   1239     }
   1240 
   1241 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1242     if (soc_feature(unit, soc_feature_riot) ||
   1243         soc_feature(unit, soc_feature_multi_level_ecmp)) {
   1244         l3->l3_ecmp_levels = 
   1245             soc_property_get(unit, spn_L3_ECMP_LEVELS, 1);
   1246     }
   1247     else {
   1248         l3->l3_ecmp_levels = 1;
   1249     }
   1250 
   1251     l3->l3_ecmp_rh_overlay_entries =
   1252         soc_property_get(unit, spn_RIOT_OVERLAY_ECMP_RESILIENT_HASH_SIZE, 0);
   1253 
   1254 #ifdef BCM_TRIDENT3_SUPPORT
   1255     if ((l3->l3_ecmp_levels > 1) && (l3->l3_ecmp_rh_overlay_entries == 0) && (SOC_IS_TRIDENT3X(unit))) {
   1256         l3->l3_ecmp_rh_overlay_entries =
   1257             soc_mem_view_index_count(unit, RH_ECMP_FLOWSETm) / 2;
   1258     }
   1259 
   1260     if (soc_feature(unit, soc_feature_td3_style_riot)) {
   1261         l3->l3_ecmp_group_first_lkup_mem_size =
   1262             soc_property_get(unit, spn_L3_ECMP_GROUP_FIRST_LKUP_MEM_SIZE, 0);
   1263         l3->l3_ecmp_member_first_lkup_mem_size =
   1264             soc_property_get(unit, spn_L3_ECMP_MEMBER_FIRST_LKUP_MEM_SIZE, 0);
   1265     }
   1266 #endif
   1267 #endif
   1268 
   1269 #ifdef BCM_RIOT_SUPPORT
   1270     if (soc_property_get(unit, spn_RIOT_ENABLE, 0) &&
   1271         (soc_feature(unit, soc_feature_riot))) {
   1272 
   1273         LOG_INFO(BSL_LS_BCM_L3, (BSL_META_U(unit,
   1274             "Routing into and out of Tunnels is Enabled.\n")));
   1275         l3->riot_enable = TRUE;
   1276         /* Hierarchical ECMP support required to support RIOT in TD3 
   1277            l3_ecmp_levels configuration should handle this */
   1278     }
   1279 
   1280     l3->l3_intf_overlay_entries =
   1281         soc_property_get(unit, spn_RIOT_OVERLAY_L3_INTF_MEM_SIZE, 0);
   1282     l3->l3_nh_overlay_entries =
   1283         soc_property_get(unit, spn_RIOT_OVERLAY_L3_EGRESS_MEM_SIZE, 0);
   1284 
   1285     /* "alloc mode" is 0 by default for backward compatible */
   1286     l3->l3_intf_overlay_alloc_mode =
   1287         soc_property_get(unit, spn_RIOT_OVERLAY_L3_INTF_MEM_ALLOC_MODE, 0);
   1288     l3->l3_nh_overlay_alloc_mode =
   1289         soc_property_get(unit, spn_RIOT_OVERLAY_L3_EGRESS_MEM_ALLOC_MODE, 0);
   1290 
   1291 #endif
   1292 
   1293     if (soc_property_get(unit, spn_EMBEDDED_NH_VP_SUPPORT, 0)) {
   1294 #ifdef BCM_TOMAHAWK_SUPPORT
   1295         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   1296             BCM_L3_BK_FLAG_SET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE);
   1297         }
   1298 #endif /* BCM_TOMAHAWK_SUPPORT */
   1299     }
   1300 
   1301     l3->l3_nh_reserve_for_ecmp = soc_property_get(
   1302         unit, spn_RESERVE_NH_FOR_ECMP, 0);
   1303 
   1304 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   1305     if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) {
   1306         int tbl_size;
   1307         soc_esw_ecmp_init_info_t init_info;
   1308         soc_esw_ecmp_init_info_t_init(&init_info);
   1309 
   1310         tbl_size = soc_mem_index_count(unit, L3_ECMPm);
   1311 
   1312         init_info.num_banks = BCMI_L3_ECMP_MAX_BANKS(unit);
   1313         init_info.bank_size = BCMI_L3_ECMP_PER_BANK(unit);
   1314         init_info.num_levels = l3->l3_ecmp_levels;
   1315         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   1316             /* HECMP enabled. Table needs to be split into lkup1 & lkup2. */
   1317             init_info.lkup1_size = l3->l3_ecmp_member_first_lkup_mem_size;
   1318             if (init_info.lkup1_size == 0) {
   1319                 /* HX5: If LKUP1 size is not specified, expectation is to
   1320                  * devide the table into two equal partitions.
   1321                  *
   1322                  * Since one bank needs to be reserved for protected accesses
   1323                  * to the table, we will end up reserving 2 banks here.
   1324                  */
   1325                  tbl_size /= 2;
   1326                  init_info.lkup1_size = (tbl_size / 2);
   1327             } else {
   1328                 /* One bank reserved. */
   1329                 tbl_size -= init_info.bank_size;
   1330             }
   1331             init_info.lkup2_size = (tbl_size - init_info.lkup1_size);
   1332             if (init_info.lkup2_size <= 0) {
   1333                 LOG_ERROR(
   1334                     BSL_LS_BCM_L3,
   1335                     (BSL_META_U(unit, "The config property "
   1336                                 "l3_ecmp_member_first_lkup_mem_size cannot be "
   1337                                 "greater than 2048 for this device.\n")));
   1338                 return BCM_E_CONFIG;
   1339             }
   1340         }
   1341         init_info.ecmp_if_offset = BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   1342 #ifdef BCM_WARM_BOOT_SUPPORT
   1343         SOC_SCACHE_HANDLE_SET(init_info.scache_handle, unit,
   1344                               BCM_MODULE_L3, BCM_WB_PART_SOC_ECMP_STATE);
   1345 #endif /* BCM_WARM_BOOT_SUPPORT */
   1346 
   1347         SOC_IF_ERROR_RETURN(soc_esw_ecmp_protected_init(unit, &init_info));
   1348     }
   1349 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   1350 
   1351 #ifdef BCM_TRIDENT3_SUPPORT
   1352     if (soc_feature(unit, soc_feature_cancun)) {
   1353         /* These two features are supported on TD3 from 6.0.0 and above */
   1354         uint32 cancun_ver;
   1355         SOC_IF_ERROR_RETURN(soc_cancun_version_get(unit, &cancun_ver));
   1356 
   1357         if (SOC_IS_TRIDENT3(unit) && (cancun_ver >= SOC_CANCUN_VERSION_DEF_6_0_0)) {
   1358             SOC_FEATURE_SET(unit, soc_feature_large_scale_nat);
   1359             SOC_FEATURE_SET(unit, soc_feature_vfi_switched_l2_change_fields);
   1360         }
   1361     }
   1362 #endif /* BCM_TRIDENT3_SUPPORT */
   1363 
   1364 #ifdef BCM_WARM_BOOT_SUPPORT
   1365     if (SOC_WARM_BOOT(unit)) {
   1366         return (_bcm_l3_reinit(unit));
   1367     }
   1368 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   1369     else {
   1370         BCM_IF_ERROR_RETURN(_bcm_esw_l3_warm_boot_alloc(unit));
   1371     }
   1372 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1373 #endif /* BCM_WARM_BOOT_SUPPORT */
   1374 
   1375 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
   1376     if (soc_feature(unit, soc_feature_urpf) &&
   1377         SOC_REG_FIELD_VALID(unit, L3_DEFIP_RPF_CONTROLr, DEFIP_RPF_ENABLEf)) {
   1378         BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit,
   1379             L3_DEFIP_RPF_CONTROLr, REG_PORT_ANY, DEFIP_RPF_ENABLEf, 0x0));
   1380     }
   1381 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
   1382 
   1383     BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_tables_init(unit));
   1384 
   1385     if (!BCM_XGS3_L3_NH_CNT(unit)) {
   1386         BCM_XGS3_L3_NH_CNT(unit) = 1;
   1387     }
   1388 
   1389     l3->l3_initialized = 1;
   1390 
   1391     if (soc_property_get(unit, spn_L3_INTF_VLAN_SPLIT_EGRESS, 0)) {
   1392         BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_L3_INTF_VLAN_SPLIT_EGRESS;
   1393     } else {
   1394         BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_L3_INTF_VLAN_SPLIT_EGRESS;
   1395     }
   1396 
   1397    return BCM_E_NONE;
   1398 }
   1399 
   1400 /*
   1401  * Function:
   1402  *     _bcm_esw_l3_intf_create
   1403  * Purpose:
   1404  *     Create an L3 interface
   1405  * Parameters:
   1406  *     unit  - StrataXGS unit number
   1407  *     intf  - interface info: l3a_mac_addr - MAC address;
   1408  *             l3a_vid - VLAN ID;
   1409  *             flag BCM_L3_ADD_TO_ARL: add mac address to arl table
   1410  *                                     with static bit and L3 bit set.
   1411  *             flag BCM_L3_WITH_ID: use specified interface ID l3a_intf.
   1412  *             flag BCM_L3_REPLACE: overwrite if interface already exists.
   1413  * Returns:
   1414  *      BCM_E_XXX
   1415  * Notes:
   1416  *      The VLAN table should be set up properly before this call.
   1417  *      The L3 interface ID is automatically assigned unless a specific
   1418  *      ID is requested with the BCM_L3_WITH_ID flag.
   1419  */
   1420 
   1421 int
   1422 _bcm_esw_l3_intf_create(int unit, bcm_l3_intf_t *intf)
   1423 {
   1424     _bcm_l3_intf_cfg_t l3i;
   1425     bcm_l3_intf_t find_if;
   1426     int rv;
   1427 #ifdef BCM_RIOT_SUPPORT
   1428     int32 l3IntfMapMode = 0;
   1429     int32 l3IngressMode = 0;
   1430 #endif
   1431 
   1432     /* Input parameters check. */
   1433     if (NULL == intf) {
   1434         return (BCM_E_PARAM);
   1435     }
   1436 
   1437     if (((intf->l3a_vrf > SOC_VRF_MAX(unit)) ||
   1438         (intf->l3a_vrf < BCM_L3_VRF_DEFAULT))
   1439         && !soc_feature(unit, soc_feature_fp_based_routing)) {
   1440 
   1441         if ((!soc_mem_field_valid(unit, L3_IIFm, VRF_VALIDf)) ||
   1442             ((soc_mem_field_valid(unit, L3_IIFm, VRF_VALIDf) &&
   1443             (intf->l3a_vrf != BCM_L3_VRF_INVALID)))) {
   1444              return (BCM_E_PARAM);
   1445         }
   1446     }
   1447 
   1448     if (BCM_MAC_IS_ZERO(intf->l3a_mac_addr)) {
   1449         return (BCM_E_PARAM);
   1450     }
   1451 
   1452 #ifdef BCM_RIOT_SUPPORT
   1453     /*
   1454      * If user sends vpn in place of vlan
   1455      * then RIOT must be enabled
   1456      */
   1457     if (_BCM_VPN_VFI_IS_SET((intf->l3a_vid))) {
   1458         if (!(BCMI_RIOT_IS_ENABLED(unit))) {
   1459             return BCM_E_UNAVAIL;
   1460         }
   1461     }
   1462     /*
   1463      * SDK will not allow creating RIOT flow without
   1464      * l3 ingress mode and l3 interface map mode set.
   1465      * It has been discussed with API team.
   1466      */
   1467     if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf->l3a_vid)) {
   1468         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   1469             BCM_IF_ERROR_RETURN(
   1470                 bcm_xgs3_l3_ingress_intf_map_get(unit, &l3IntfMapMode));
   1471             if (!l3IntfMapMode) {
   1472                 LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
   1473                 "Enable bcmSwitchL3IngressInterfaceMapSet for overlay intf\n")));
   1474 
   1475                 return BCM_E_PARAM;
   1476             }
   1477             BCM_IF_ERROR_RETURN(
   1478                 bcm_xgs3_l3_ingress_mode_get(unit, &l3IngressMode));
   1479             if (!l3IngressMode) {
   1480                 LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
   1481                 "Enable bcmSwitchLl3IngressMode to create overlay intf\n")));
   1482 
   1483                 return BCM_E_PARAM;
   1484             }
   1485         } else {
   1486             LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
   1487             "Enable soc_feature_l3_ingress_interface for overlay intf\n")));
   1488             return BCM_E_PARAM;
   1489         }
   1490     }
   1491 #endif
   1492 
   1493     /*  L3 interfaces can also accept VFI as part of vid.
   1494         These interfaces are used in overlay domain 
   1495      */
   1496     if ((!BCM_VLAN_VALID(intf->l3a_vid)) 
   1497 #ifdef BCM_RIOT_SUPPORT
   1498         && (BCMI_RIOT_VPN_VFI_IS_NOT_SET(unit, intf->l3a_vid))
   1499 #endif
   1500     ) {
   1501         return (BCM_E_PARAM);
   1502     }
   1503     if (!BCM_TTL_VALID(intf->l3a_ttl)) {
   1504         return (BCM_E_PARAM);
   1505     }
   1506 
   1507     if (intf->l3a_group) {
   1508         return (BCM_E_PARAM);
   1509     }
   1510 
   1511     if ((intf->l3a_group > SOC_INTF_CLASS_MAX(unit)) ||
   1512         (intf->l3a_group < 0)) {
   1513         return (BCM_E_PARAM);
   1514     }
   1515 
   1516     if ((0 == SOC_IS_TRX(unit)) && (intf->l3a_inner_vlan)) {
   1517         return (BCM_E_PARAM);
   1518     }
   1519 
   1520     sal_memset(&l3i, 0, sizeof(_bcm_l3_intf_cfg_t));
   1521     sal_memcpy(l3i.l3i_mac_addr, intf->l3a_mac_addr, sizeof(bcm_mac_t));
   1522     l3i.l3i_vid = intf->l3a_vid;
   1523     l3i.l3i_inner_vlan = intf->l3a_inner_vlan;
   1524     l3i.l3i_flags = intf->l3a_flags;
   1525 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   1526     l3i.l3i_vrf = intf->l3a_vrf;
   1527     l3i.l3i_group = intf->l3a_group;
   1528     l3i.l3i_ttl = intf->l3a_ttl;
   1529     l3i.l3i_mtu = intf->l3a_mtu;
   1530     l3i.l3i_tunnel_idx = intf->l3a_tunnel_idx;
   1531     sal_memcpy(&l3i.vlan_qos, &intf->vlan_qos, sizeof(bcm_l3_intf_qos_t));
   1532     sal_memcpy(&l3i.inner_vlan_qos, &intf->inner_vlan_qos, sizeof(bcm_l3_intf_qos_t));
   1533     sal_memcpy(&l3i.dscp_qos, &intf->dscp_qos, sizeof(bcm_l3_intf_qos_t));
   1534 #if defined(BCM_TRIUMPH3_SUPPORT)
   1535     if ((intf->l3a_intf_class > SOC_INTF_CLASS_MAX(unit)) ||
   1536         (intf->l3a_intf_class < 0)) {
   1537         return (BCM_E_PARAM);
   1538     }
   1539     l3i.l3i_class = intf->l3a_intf_class;
   1540 #endif /* BCM_TRIUMPH3_SUPPORT */
   1541 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1542 
   1543 #ifdef BCM_TRIDENT2_SUPPORT
   1544     l3i.l3i_ip4_options_profile_id = intf->l3a_ip4_options_profile_id;
   1545     l3i.l3i_nat_realm_id = intf->l3a_nat_realm_id;
   1546     l3i.l3i_intf_flags = intf->l3a_intf_flags;
   1547 #endif /* BCM_TRIDENT2_SUPPORT */
   1548 #ifdef BCM_RIOT_SUPPORT
   1549     l3i.l3i_source_vp = intf->l3a_source_vp;
   1550 #endif /* BCM_RIOT_SUPPORT */
   1551 #ifdef BCM_TRIDENT3_SUPPORT
   1552     if (soc_feature(unit, soc_feature_flex_flow)) {
   1553         l3i.flow_handle = intf->flow_handle;
   1554         l3i.flow_option_handle = intf->flow_option_handle;
   1555         l3i.num_of_fields = intf->num_of_fields;
   1556         sal_memcpy(l3i.logical_fields, intf->logical_fields,
   1557                    intf->num_of_fields*sizeof(bcm_flow_logical_field_t));
   1558     }
   1559 #endif /* BCM_TRIDENT3_SUPPORT */
   1560 
   1561     /* L3 interface ID given */
   1562     if (intf->l3a_flags & BCM_L3_WITH_ID) {
   1563         /* Initilize interface lookup key. */
   1564         bcm_l3_intf_t_init(&find_if);
   1565 
   1566         /* Set interface index. */
   1567         find_if.l3a_intf_id = intf->l3a_intf_id;
   1568 
   1569         /* Read interface info by index. */
   1570         rv = bcm_esw_l3_intf_get(unit, &find_if);
   1571 
   1572         if (rv == BCM_E_NONE) {
   1573             /* BCM_L3_REPLACE flag must be set for interface update. */
   1574             if (!(intf->l3a_flags & BCM_L3_REPLACE)) {
   1575                return BCM_E_EXISTS;
   1576             }
   1577 
   1578             /* Remove old interface layer 2 address if required. */
   1579             if (BCM_L3_INTF_ARL_GET(unit, intf->l3a_intf_id)) {
   1580                 BCM_IF_ERROR_RETURN 
   1581                     (bcm_esw_l2_addr_delete(unit, find_if.l3a_mac_addr,
   1582                                          find_if.l3a_vid));
   1583                 BCM_L3_INTF_ARL_CLR(unit, find_if.l3a_intf_id);
   1584             }
   1585         } else if (rv != BCM_E_NOT_FOUND) { /* Other error */
   1586             return rv;
   1587         }
   1588         /* Set interface index. */
   1589         l3i.l3i_index = intf->l3a_intf_id;
   1590         rv = mbcm_driver[unit]->mbcm_l3_intf_id_create(unit, &l3i);
   1591     } else {
   1592         rv = mbcm_driver[unit]->mbcm_l3_intf_create(unit, &l3i);
   1593     }
   1594 
   1595     if (rv < 0) {
   1596         return (rv);
   1597     }
   1598 
   1599     if (!(intf->l3a_flags & BCM_L3_WITH_ID)) {
   1600         intf->l3a_intf_id = l3i.l3i_index;
   1601     }
   1602 
   1603     return BCM_E_NONE;
   1604 }
   1605 
   1606 /*
   1607  * Function:
   1608  *     bcm_esw_l3_intf_create
   1609  * Purpose:
   1610  *     Create an L3 interface
   1611  * Parameters:
   1612  *     unit  - StrataXGS unit number
   1613  *     intf  - interface info: l3a_mac_addr - MAC address;
   1614  *             l3a_vid - VLAN ID;
   1615  *             flag BCM_L3_ADD_TO_ARL: add mac address to arl table
   1616  *                                     with static bit and L3 bit set.
   1617  *             flag BCM_L3_WITH_ID: use specified interface ID l3a_intf.
   1618  *             flag BCM_L3_REPLACE: overwrite if interface already exists.
   1619  * Returns:
   1620  *      BCM_E_XXX
   1621  * Notes:
   1622  *      The VLAN table should be set up properly before this call.
   1623  *      The L3 interface ID is automatically assigned unless a specific
   1624  *      ID is requested with the BCM_L3_WITH_ID flag.
   1625  */
   1626 int
   1627 bcm_esw_l3_intf_create(int unit, bcm_l3_intf_t *intf)
   1628 {
   1629     int rv;
   1630 
   1631     L3_INIT(unit);
   1632     L3_LOCK(unit);
   1633 
   1634     rv = _bcm_esw_l3_intf_create(unit, intf);
   1635 
   1636     L3_UNLOCK(unit);
   1637     return (rv);
   1638 }
   1639 
   1640 /*
   1641  * Function:
   1642  *     bcm_esw_l3_intf_delete
   1643  * Purpose:
   1644  *     Delete L3 interface based on L3 interface ID
   1645  * Parameters:
   1646  *     unit  - StrataXGS unit number
   1647  *     intf  - interface structure with L3 interface ID as input
   1648  * Returns:
   1649  *     BCM_E_XXX
   1650  */
   1651 int
   1652 bcm_esw_l3_intf_delete(int unit, bcm_l3_intf_t *intf)
   1653 {
   1654     _bcm_l3_intf_cfg_t l3i;
   1655     int rv;
   1656 
   1657     L3_INIT(unit);
   1658 
   1659     if (NULL == intf) {
   1660         return (BCM_E_PARAM);
   1661     } 
   1662 
   1663     sal_memset(&l3i, 0, sizeof(_bcm_l3_intf_cfg_t));
   1664     l3i.l3i_index = intf->l3a_intf_id;
   1665     l3i.l3i_flags = intf->l3a_flags;
   1666 
   1667     L3_LOCK(unit);
   1668     rv = mbcm_driver[unit]->mbcm_l3_intf_delete(unit, &l3i);
   1669     L3_UNLOCK(unit);
   1670     return (rv);
   1671 }
   1672 
   1673 /*
   1674  * Function:
   1675  *     bcm_esw_l3_intf_find
   1676  * Purpose:
   1677  *     Find the L3 intf number based on (MAC, VLAN)
   1678  * Parameters:
   1679  *     unit  - StrataXGS unit number
   1680  *     intf  - (IN) interface (MAC, VLAN), (OUT)intf number
   1681  * Returns:
   1682  *     BCM_E_XXX
   1683  */
   1684 int
   1685 bcm_esw_l3_intf_find(int unit, bcm_l3_intf_t *intf)
   1686 {
   1687     _bcm_l3_intf_cfg_t l3i;
   1688     int rv;
   1689 
   1690     L3_INIT(unit);
   1691 
   1692     if (NULL == intf) {
   1693         return (BCM_E_PARAM);
   1694     } 
   1695 
   1696     if ((BCM_MAC_IS_MCAST(intf->l3a_mac_addr)) || 
   1697         (BCM_MAC_IS_ZERO(intf->l3a_mac_addr))) {
   1698         return (BCM_E_PARAM);
   1699     }
   1700 
   1701     if ((!BCM_VLAN_VALID(intf->l3a_vid))
   1702 #ifdef BCM_RIOT_SUPPORT
   1703         && (BCMI_RIOT_VPN_VFI_IS_NOT_SET(unit, intf->l3a_vid))
   1704 #endif
   1705     ) { 
   1706         return (BCM_E_PARAM);
   1707     }
   1708 
   1709     sal_memset(&l3i, 0, sizeof(_bcm_l3_intf_cfg_t));
   1710     sal_memcpy(l3i.l3i_mac_addr, intf->l3a_mac_addr, sizeof(bcm_mac_t));
   1711     l3i.l3i_vid = intf->l3a_vid;
   1712 
   1713     L3_LOCK(unit);
   1714 
   1715     rv = mbcm_driver[unit]->mbcm_l3_intf_lookup(unit, &l3i);
   1716 
   1717     L3_UNLOCK(unit);
   1718 
   1719     intf->l3a_intf_id = l3i.l3i_index;
   1720 
   1721     return rv;
   1722 }
   1723 
   1724 /*
   1725  * Function:
   1726  *     bcm_esw_l3_intf_get
   1727  * Purpose:
   1728  *     Given the L3 interface number, return the MAC and VLAN
   1729  * Parameters:
   1730  *     unit  - StrataXGS unit number
   1731  *     intf  - (IN) L3 interface; (OUT)VLAN ID, 802.3 MAC for this L3 intf
   1732  * Returns:
   1733  *     BCM_E_XXX
   1734  */
   1735 int
   1736 bcm_esw_l3_intf_get(int unit, bcm_l3_intf_t *intf)
   1737 {
   1738     _bcm_l3_intf_cfg_t l3i;
   1739     int rv;
   1740 
   1741     L3_INIT(unit);
   1742 
   1743     if (NULL == intf) {
   1744         return (BCM_E_PARAM);
   1745     } 
   1746 
   1747     sal_memset(&l3i, 0, sizeof(_bcm_l3_intf_cfg_t));
   1748     l3i.l3i_index = intf->l3a_intf_id;
   1749 
   1750     L3_LOCK(unit);
   1751 
   1752     rv = mbcm_driver[unit]->mbcm_l3_intf_get(unit, &l3i);
   1753 
   1754     L3_UNLOCK(unit);
   1755     if (rv < 0) {
   1756         return (rv);
   1757     }
   1758 
   1759     sal_memcpy(intf->l3a_mac_addr, l3i.l3i_mac_addr, sizeof(bcm_mac_t));
   1760     intf->l3a_vid = l3i.l3i_vid;
   1761     intf->l3a_inner_vlan = l3i.l3i_inner_vlan;
   1762     intf->l3a_tunnel_idx = l3i.l3i_tunnel_idx;
   1763     intf->l3a_flags = l3i.l3i_flags;
   1764     intf->l3a_vrf = l3i.l3i_vrf;
   1765     intf->l3a_ttl = l3i.l3i_ttl;
   1766     intf->l3a_mtu = l3i.l3i_mtu;
   1767     intf->l3a_group = l3i.l3i_group;
   1768     sal_memcpy(&intf->vlan_qos, &l3i.vlan_qos, sizeof(bcm_l3_intf_qos_t));
   1769     sal_memcpy(&intf->inner_vlan_qos, &l3i.inner_vlan_qos, sizeof(bcm_l3_intf_qos_t));
   1770     sal_memcpy(&intf->dscp_qos, &l3i.dscp_qos, sizeof(bcm_l3_intf_qos_t));
   1771 #ifdef BCM_TRIUMPH3_SUPPORT
   1772     intf->l3a_intf_class =  l3i.l3i_class;
   1773 #endif /* BCM_TRIUMPH3_SUPPORT */
   1774 #ifdef BCM_TRIDENT2_SUPPORT
   1775     intf->l3a_ip4_options_profile_id = l3i.l3i_ip4_options_profile_id;
   1776     intf->l3a_nat_realm_id = l3i.l3i_nat_realm_id;
   1777     intf->l3a_intf_flags = l3i.l3i_intf_flags;
   1778 #endif /* BCM_TRIDENT2_SUPPORT */
   1779 #ifdef BCM_RIOT_SUPPORT
   1780     intf->l3a_source_vp = l3i.l3i_source_vp;
   1781 #endif
   1782 #ifdef BCM_TRIDENT3_SUPPORT
   1783     if (soc_feature(unit, soc_feature_flex_flow)) {
   1784         intf->flow_handle = l3i.flow_handle;
   1785         intf->flow_option_handle = l3i.flow_option_handle;
   1786         intf->num_of_fields = l3i.num_of_fields;
   1787         sal_memcpy(intf->logical_fields, l3i.logical_fields,
   1788                    l3i.num_of_fields*sizeof(bcm_flow_logical_field_t));
   1789     }
   1790 #endif
   1791 
   1792     return BCM_E_NONE;
   1793 }
   1794 
   1795 /*
   1796  * Function:
   1797  *     bcm_esw_l3_intf_find_vlan
   1798  * Purpose:
   1799  *     Find the L3 interface by VLAN
   1800  * Parameters:
   1801  *     unit - StrataXGS unit number
   1802  *     intf  - (IN) VID, (OUT)L3 intf info
   1803  * Returns:
   1804  *     BCM_E_XXX
   1805  */
   1806 int
   1807 bcm_esw_l3_intf_find_vlan(int unit, bcm_l3_intf_t *intf)
   1808 {
   1809     int rv;
   1810     _bcm_l3_intf_cfg_t l3i;
   1811 
   1812     L3_INIT(unit);
   1813 
   1814     if (NULL == intf) {
   1815         return (BCM_E_PARAM);
   1816     } 
   1817 
   1818     if (!BCM_VLAN_VALID(intf->l3a_vid)
   1819 #ifdef BCM_RIOT_SUPPORT
   1820         && !BCMI_RIOT_VPN_VFI_IS_SET(unit, intf->l3a_vid)
   1821 #endif
   1822     ) {
   1823         return (BCM_E_PARAM);
   1824     }
   1825 
   1826     sal_memset(&l3i, 0, sizeof(_bcm_l3_intf_cfg_t));
   1827     l3i.l3i_vid = intf->l3a_vid;
   1828 
   1829     L3_LOCK(unit);
   1830     rv = mbcm_driver[unit]->mbcm_l3_intf_get_by_vid(unit, &l3i);
   1831 
   1832     L3_UNLOCK(unit);
   1833     if (rv < 0) {
   1834         return (rv);
   1835     }
   1836 
   1837     intf->l3a_intf_id = l3i.l3i_index;
   1838     sal_memcpy(intf->l3a_mac_addr, l3i.l3i_mac_addr, sizeof(bcm_mac_t));
   1839     intf->l3a_tunnel_idx = l3i.l3i_tunnel_idx;
   1840     intf->l3a_flags = l3i.l3i_flags;
   1841     intf->l3a_vrf = l3i.l3i_vrf;
   1842     intf->l3a_ttl = l3i.l3i_ttl;
   1843     intf->l3a_mtu = l3i.l3i_mtu;
   1844     intf->l3a_group = l3i.l3i_group;
   1845 #ifdef BCM_TRIDENT2_SUPPORT
   1846     intf->l3a_intf_flags = l3i.l3i_intf_flags;
   1847 #endif /* BCM_TRIDENT2_SUPPORT */
   1848 
   1849     return (BCM_E_NONE);
   1850 }
   1851 
   1852 /*
   1853  * Function:
   1854  *      bcm_esw_l3_intf_delete_all
   1855  * Purpose:
   1856  *      Delete all L3 interfaces
   1857  * Parameters:
   1858  *      unit - SOC device unit number
   1859  * Returns:
   1860  *      BCM_E_XXXX
   1861  */
   1862 int
   1863 bcm_esw_l3_intf_delete_all(int unit)
   1864 {
   1865     int rv;
   1866     L3_INIT(unit);
   1867     L3_LOCK(unit);
   1868 
   1869     rv = mbcm_driver[unit]->mbcm_l3_intf_delete_all(unit);
   1870 
   1871     L3_UNLOCK(unit);
   1872 
   1873     return (rv);
   1874 }
   1875 
   1876 /*
   1877  * Function:
   1878  *      bcm_esw_l3_host_find
   1879  * Purpose:
   1880  *      Find an entry from the L3 host table given IP address.
   1881  * Parameters:
   1882  *      unit - SOC device unit number
   1883  *      info - (Out) Pointer to memory for bcm_l3_host_t.
   1884  * Returns:
   1885  *      BCM_E_XXX
   1886  * Notes:
   1887  *      1) The hit returned may be either L3SH or L3DH or Both
   1888  *      2) Flag set to BCM_L3_IP6 for IPv6, default is IPv4
   1889  */
   1890 
   1891 int
   1892 bcm_esw_l3_host_find(int unit, bcm_l3_host_t *info)
   1893 {
   1894     _bcm_l3_cfg_t l3cfg;
   1895     int           rt;
   1896 
   1897     L3_INIT(unit);
   1898 
   1899     if (NULL == info) {
   1900         return (BCM_E_PARAM);
   1901     }
   1902 
   1903     /* Vrf is in device supported range check. */
   1904     if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 
   1905         (info->l3a_vrf < BCM_L3_VRF_DEFAULT)) {
   1906         return (BCM_E_PARAM);
   1907     }
   1908   
   1909     /*  Check that device supports ipv6. */
   1910     if (BCM_L3_NO_IP6_SUPPORT(unit, info->l3a_flags)) {
   1911         return (BCM_E_UNAVAIL);
   1912     }
   1913 
   1914     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1915     l3cfg.l3c_flags = info->l3a_flags;
   1916     l3cfg.l3c_vrf = info->l3a_vrf;
   1917 #ifdef BCM_TRIDENT3_SUPPORT
   1918     if (soc_feature(unit, soc_feature_flex_flow)) {
   1919         l3cfg.l3c_flow_handle = info->flow_handle;
   1920         l3cfg.l3c_flow_option_handle = info->flow_option_handle;
   1921         l3cfg.l3c_num_of_fields = info->num_of_fields;
   1922         sal_memcpy(l3cfg.l3c_logical_fields, info->logical_fields,
   1923                    info->num_of_fields*sizeof(bcm_flow_logical_field_t));
   1924     }
   1925 #endif /* BCM_TRIDENT3_SUPPORT */
   1926 
   1927     L3_LOCK(unit);
   1928     if (info->l3a_flags & BCM_L3_IP6) {
   1929         sal_memcpy(l3cfg.l3c_ip6, info->l3a_ip6_addr, BCM_IP6_ADDRLEN);
   1930         rt = mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg);
   1931     } else {
   1932         l3cfg.l3c_ip_addr = info->l3a_ip_addr;
   1933         rt = mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg);
   1934     }
   1935     L3_UNLOCK(unit);
   1936 
   1937     if (rt < 0) {
   1938         return (rt);
   1939     }
   1940 
   1941     info->l3a_flags = l3cfg.l3c_flags;
   1942     info->l3a_flags2 = l3cfg.l3c_flags2;
   1943     if (l3cfg.l3c_flags & BCM_L3_IPMC) {
   1944         info->l3a_ipmc_ptr = l3cfg.l3c_ipmc_ptr;
   1945         info->l3a_ipmc_ptr_l2 = l3cfg.l3c_ipmc_ptr_l2;
   1946     }
   1947     sal_memcpy(info->l3a_nexthop_mac, l3cfg.l3c_mac_addr, sizeof(bcm_mac_t));
   1948     info->l3a_intf = l3cfg.l3c_intf;
   1949     info->l3a_port_tgid = l3cfg.l3c_port_tgid;
   1950     info->l3a_modid = l3cfg.l3c_modid;
   1951 
   1952     /* For devices that support the overlaid_address_range, if the RPE
   1953        field is '0', the 4 bits of PRI are the upper 4 bits
   1954        (of total 10 bits) of the classId, the lower 6 come from classId
   1955        as usual, for rest of the cases, the classID and PRI are copied
   1956        over directly.
   1957     */
   1958     if (soc_feature(unit, soc_feature_overlaid_address_class) && 
   1959                !BCM_L3_RPE_SET(l3cfg.l3c_flags)) {
   1960         info->l3a_lookup_class = ((l3cfg.l3c_prio & 0xF) << 6);
   1961         info->l3a_lookup_class |= (l3cfg.l3c_lookup_class & 0x3F);
   1962     } else {
   1963         info->l3a_lookup_class = l3cfg.l3c_lookup_class;
   1964         info->l3a_pri = l3cfg.l3c_prio;
   1965     }
   1966 
   1967 #ifdef BCM_TRIUMPH2_SUPPORT
   1968     if (soc_feature(unit, soc_feature_wlan) && 
   1969         BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, l3cfg.l3c_intf)) {
   1970         /* Get DVP using the egress object ID and construct a gport */
   1971         egr_l3_next_hop_entry_t next_hop;
   1972         _bcm_gport_dest_t dest;
   1973         int nh_idx = l3cfg.l3c_intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   1974         BCM_IF_ERROR_RETURN
   1975             (READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, nh_idx, &next_hop));
   1976         dest.wlan_id = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &next_hop, DVPf);
   1977         dest.gport_type = _SHR_GPORT_TYPE_WLAN_PORT;
   1978         BCM_IF_ERROR_RETURN(
   1979             _bcm_esw_gport_construct(unit, &dest, &(info->l3a_port_tgid)));
   1980     } else
   1981 #endif
   1982 #ifdef BCM_TOMAHAWK_SUPPORT
   1983     if (soc_feature(unit, soc_feature_virtual_port_routing) &&
   1984         BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   1985         if (BCM_GPORT_IS_NIV_PORT(info->l3a_port_tgid) ||
   1986             BCM_GPORT_IS_EXTENDER_PORT(info->l3a_port_tgid)) {
   1987             /* For NIV and PE, info->l3a_port_tgid already represents a gport
   1988                       * Hence simply return from this routine.
   1989                       */
   1990             return BCM_E_NONE;
   1991         } else {
   1992             BCM_IF_ERROR_RETURN
   1993                 (_bcm_esw_l3_gport_construct(unit, info->l3a_port_tgid, 
   1994                                              info->l3a_modid, info->l3a_port_tgid, 
   1995                                              info->l3a_flags, 
   1996                                              &(info->l3a_port_tgid)));
   1997         }
   1998     } else
   1999 #endif /* BCM_TOMAHAWK_SUPPORT */
   2000     {
   2001         BCM_IF_ERROR_RETURN
   2002             (_bcm_esw_l3_gport_construct(unit, info->l3a_port_tgid, 
   2003                                          info->l3a_modid, info->l3a_port_tgid, 
   2004                                          info->l3a_flags, 
   2005                                          &(info->l3a_port_tgid)));
   2006     }
   2007     return BCM_E_NONE;
   2008 }
   2009 
   2010 /*
   2011  * Function:
   2012  *      bcm_esw_l3_host_add
   2013  * Purpose:
   2014  *      Add an entry to the L3 table.
   2015  * Parameters:
   2016  *      unit - SOC unit number
   2017  *      info - Pointer to bcm_l3_host_t containing fields related to IP table.
   2018  * Returns:
   2019  *      BCM_E_XXX
   2020  * Notes:
   2021  *  1. Flag set to BCM_L3_IP6 for IPv6, default is IPv4
   2022  *
   2023  *  2. If BCM_L3_REPLACE flag is set, replace exisiting L3 entry
   2024  *     with new information, otherwise, add only if key does not
   2025  *     exist.
   2026  *     On XGS, the DEFIP table points to the L3 entry, so this
   2027  *     function will affect both L3 switching entry and routes.
   2028  *     The affected route is one whose next hop IP address
   2029  *     is the key (2nd parameter of this function).
   2030  */
   2031 
   2032 int
   2033 bcm_esw_l3_host_add(int unit, bcm_l3_host_t *info)
   2034 {
   2035     int rv;
   2036     _bcm_l3_cfg_t l3cfg;
   2037     bcm_l3_host_t info_orig, info_local;
   2038     bcm_l3_route_t  info_route;
   2039 
   2040     L3_INIT(unit);
   2041 
   2042     if (NULL == info) {
   2043         return (BCM_E_PARAM);
   2044     }
   2045 
   2046     /* Copy provided structure to local so it can be modified. */
   2047     sal_memcpy(&info_local, info, sizeof(bcm_l3_host_t));
   2048 
   2049     /* Vrf is in device supported range check. */
   2050     if ((info_local.l3a_vrf > SOC_VRF_MAX(unit)) || 
   2051         (info_local.l3a_vrf < BCM_L3_VRF_DEFAULT)) {
   2052         return (BCM_E_PARAM);
   2053     }
   2054   
   2055     /*  Check that device supports ipv6. */
   2056     if (BCM_L3_NO_IP6_SUPPORT(unit, info_local.l3a_flags)) {
   2057         return (BCM_E_UNAVAIL);
   2058     }
   2059 
   2060     if (info_local.l3a_intf < 0) {
   2061         return (BCM_E_PARAM);
   2062     }
   2063 
   2064     /* FP lookup class range check. */
   2065     /* These are the 3 classID validity checks:
   2066      
   2067        1. If the device is a TR3, the 10 bit classID is natively supported.
   2068           and hence we check against the same.
   2069      
   2070        2. For devices that support the overlaid_address_range, if the RPE
   2071           field is '0', the 4 bits of PRI are the upper 4 bits
   2072           (of total 10 bits) of the classId, the lower 6 come from classId
   2073           as usual, we hence need to check the value range accordingly. 
   2074      
   2075        3. For rest of the cases classID is restricted to 6 bits and we
   2076           need to check accordingly.
   2077     */
   2078 
   2079     if (soc_feature(unit, soc_feature_extended_address_class)) {
   2080         if ((info_local.l3a_lookup_class > SOC_EXT_ADDR_CLASS_MAX(unit)) ||
   2081             (info_local.l3a_lookup_class < 0)) {
   2082                     return (BCM_E_PARAM);
   2083         }
   2084     } else if (soc_feature(unit, soc_feature_overlaid_address_class) && 
   2085                !BCM_L3_RPE_SET(info_local.l3a_flags)) {
   2086                    if ((info_local.l3a_lookup_class > 
   2087                         SOC_OVERLAID_ADDR_CLASS_MAX(unit)) ||
   2088                       (info_local.l3a_lookup_class < 0)) {
   2089                         return (BCM_E_PARAM);
   2090             }
   2091     } else if ((info_local.l3a_lookup_class > SOC_ADDR_CLASS_MAX(unit)) || 
   2092                (info_local.l3a_lookup_class < 0)) {
   2093                         return (BCM_E_PARAM);
   2094     }
   2095 
   2096     /* 
   2097      * When RPE is not set and soc_feature_overlaid_address_class is
   2098      * not enabled, priority values range from 0-7.
   2099      * When RPE is set, priority values range from 0-15.
   2100      * When RPE is not set but soc_feature_overlaid_address_class
   2101      * is enabled, priority value ranges from 0-15.
   2102      */
   2103     if(!BCM_L3_RPE_SET(info_local.l3a_flags) &&
   2104        !soc_feature(unit, soc_feature_overlaid_address_class)) {
   2105        if (!BCM_PRIORITY_VALID(info_local.l3a_pri)) {
   2106            return (BCM_E_PARAM);
   2107        }
   2108     } else {
   2109        if (!BCM_RPE_PRIORITY_VALID(info_local.l3a_pri)) {
   2110            return (BCM_E_PARAM);
   2111        }
   2112     }
   2113     if (BCM_GPORT_IS_SET(info_local.l3a_port_tgid)) {
   2114         bcm_trunk_t trunk_id;
   2115         int vp_routing = FALSE;
   2116         
   2117         if (BCM_GPORT_IS_NIV_PORT(info_local.l3a_port_tgid) ||
   2118             BCM_GPORT_IS_EXTENDER_PORT(info_local.l3a_port_tgid)) {
   2119             if (soc_feature(unit, soc_feature_virtual_port_routing) &&
   2120                 BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   2121                 vp_routing = TRUE;
   2122             } else {
   2123                 /* host add only accepts niv/port extender gport when config
   2124                  * property EMBEDDED_NH_VP_SUPPORT is enabled for the device.
   2125                  */
   2126                 return BCM_E_PARAM;
   2127             }
   2128         }
   2129 
   2130         if (vp_routing) {
   2131         /* l3a_port_tgid can contain either port or trunk */
   2132             rv = _bcm_esw_gport_resolve(unit, info_local.l3a_port_tgid, 
   2133                                         &(info_local.l3a_modid), 
   2134                                         &(info_local.l3a_port_tgid), 
   2135                                         &trunk_id, 
   2136                                         &(info_local.encap_id));  
   2137             if (-1 != trunk_id) {
   2138                 info_local.l3a_flags |= BCM_L3_TGID;
   2139                 info_local.l3a_port_tgid = trunk_id;
   2140             }
   2141         } else {
   2142         BCM_IF_ERROR_RETURN(
   2143             _bcm_esw_l3_gport_resolve(unit, info_local.l3a_port_tgid, 
   2144                                       &(info_local.l3a_port_tgid),
   2145                                       &(info_local.l3a_modid), 
   2146                                       &(info_local.l3a_port_tgid), 
   2147                                       &(info_local.l3a_flags)));
   2148         }
   2149     } else if (!(info_local.l3a_flags & BCM_L3_TGID)) {
   2150         PORT_DUALMODID_VALID(unit, info_local.l3a_port_tgid);
   2151     }
   2152     /* Check if host entry already exists. */
   2153     L3_LOCK(unit);
   2154     info_orig = info_local;
   2155     rv = bcm_esw_l3_host_find(unit, &info_orig);
   2156     if ((BCM_SUCCESS(rv)) && (0 == (info_local.l3a_flags & BCM_L3_REPLACE))) {
   2157         /* If so BCM_L3_REPLACE flag must be set.  */
   2158         L3_UNLOCK(unit);
   2159         return (BCM_E_EXISTS);
   2160     } else if ((BCM_FAILURE(rv)) && (BCM_E_NOT_FOUND != rv)) {
   2161         L3_UNLOCK(unit);
   2162         return (rv);
   2163     }
   2164 
   2165     /* Initialize mbcm structure. */
   2166     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2167     sal_memcpy(l3cfg.l3c_mac_addr, info_local.l3a_nexthop_mac, sizeof(bcm_mac_t));
   2168     l3cfg.l3c_intf = info_local.l3a_intf;
   2169     l3cfg.l3c_modid = info_local.l3a_modid;
   2170     l3cfg.l3c_port_tgid = info_local.l3a_port_tgid;
   2171     l3cfg.l3c_flags = info_local.l3a_flags;
   2172     l3cfg.l3c_flags2 = info_local.l3a_flags2;
   2173     l3cfg.l3c_vrf = info_local.l3a_vrf;
   2174     l3cfg.l3c_encap_id = info_local.encap_id;
   2175     if (info_local.l3a_flags & BCM_L3_IPMC) {
   2176         l3cfg.l3c_ipmc_ptr = _BCM_MULTICAST_ID_GET(info_local.l3a_ipmc_ptr);
   2177         l3cfg.l3c_ipmc_ptr_l2 = _BCM_MULTICAST_ID_GET(info_local.l3a_ipmc_ptr_l2);
   2178     }
   2179 
   2180 #ifdef BCM_TRIDENT3_SUPPORT
   2181     if (soc_feature(unit, soc_feature_flex_flow)) {
   2182         l3cfg.l3c_flow_handle = info_local.flow_handle;
   2183         l3cfg.l3c_flow_option_handle = info_local.flow_option_handle;
   2184         l3cfg.l3c_num_of_fields = info_local.num_of_fields;
   2185         sal_memcpy(l3cfg.l3c_logical_fields, info_local.logical_fields,
   2186                    info_local.num_of_fields*sizeof(bcm_flow_logical_field_t));
   2187     }
   2188 #endif /* BCM_TRIDENT3_SUPPORT */
   2189 
   2190     /* If the chip uses the 'soc_feature_overlaid_address_class' feature and
   2191        if the RPE is '0' the upper 4 bits of the classId need to be copied
   2192        from the PRI field, the lower bits get copied to the classId field as, 
   2193        for all other cases, the classID and PRI are assigned directly */
   2194     if (soc_feature(unit, soc_feature_overlaid_address_class) && 
   2195         (!BCM_L3_RPE_SET(info_local.l3a_flags))) {
   2196             l3cfg.l3c_prio = ((info_local.l3a_lookup_class & 0x3C0) >> 6);
   2197             l3cfg.l3c_lookup_class = (info_local.l3a_lookup_class & 0x3F);
   2198     } else {
   2199         l3cfg.l3c_prio = info_local.l3a_pri;
   2200         l3cfg.l3c_lookup_class = info_local.l3a_lookup_class;
   2201     }
   2202 
   2203     if (info_local.l3a_flags & BCM_L3_IP6) {
   2204         sal_memcpy(l3cfg.l3c_ip6, info_local.l3a_ip6_addr, BCM_IP6_ADDRLEN);
   2205         /* Add host entry - no prior entry found */
   2206         if (BCM_FAILURE(rv)) {
   2207             rv = mbcm_driver[unit]->mbcm_l3_ip6_add(unit, &l3cfg);
   2208         } else {
   2209             /* Remove Route entry and add to Host table */
   2210             if ((info_orig.l3a_flags & BCM_L3_HOST_AS_ROUTE) &&
   2211                 !(info_local.l3a_flags2 & BCM_L3_FLAGS2_ROUTE_NO_MOVE) &&
   2212                 !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
   2213 
   2214                /* Entry exists within ROUTE table */
   2215                l3cfg.l3c_flags &=  ~BCM_L3_HOST_AS_ROUTE;
   2216 
   2217                /* Add entry to HOST Table */
   2218                rv = mbcm_driver[unit]->mbcm_l3_ip6_add(unit, &l3cfg);
   2219 
   2220                if (BCM_SUCCESS(rv)) {
   2221 
   2222                   /* Init ROUTE entry */
   2223                   sal_memset(&info_route, 0, sizeof(bcm_l3_route_t));
   2224                   sal_memcpy(info_route.l3a_nexthop_mac, l3cfg.l3c_mac_addr, sizeof(bcm_mac_t));
   2225                   info_route.l3a_vrf = l3cfg.l3c_vrf;
   2226                   info_route.l3a_flags = BCM_L3_IP6;
   2227                   sal_memcpy(info_route.l3a_ip6_net, l3cfg.l3c_ip6,
   2228                                             sizeof(bcm_ip6_t));
   2229                   bcm_ip6_mask_create(info_route.l3a_ip6_mask, 128);
   2230                   info_route.l3a_intf = l3cfg.l3c_intf;
   2231                   info_route.l3a_modid = l3cfg.l3c_modid;
   2232                   info_route.l3a_port_tgid = l3cfg.l3c_port_tgid;
   2233                   info_route.l3a_pri = l3cfg.l3c_prio;
   2234                   info_route.l3a_lookup_class = l3cfg.l3c_lookup_class;
   2235 
   2236                   /* Delete ROUTE entry */
   2237                   rv = bcm_esw_l3_route_delete(unit, &info_route);
   2238                   if (BCM_SUCCESS(rv)) {
   2239                      /* Special return value - as entry existed within ROUTE table */
   2240 #if defined(BCM_FIREBOLT_SUPPORT)
   2241                      (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv);
   2242 #endif /* BCM_FIREBOLT_SUPPORT  */
   2243                   }
   2244                } else {
   2245                   /* Update ROUTE entry */
   2246                   l3cfg.l3c_flags |=  BCM_L3_HOST_AS_ROUTE;
   2247                   rv = mbcm_driver[unit]->mbcm_l3_ip6_replace(unit, &l3cfg);
   2248                }
   2249             } else {
   2250                 /* Replace prior entry found */
   2251                 if ((info_orig.l3a_flags & BCM_L3_HOST_AS_ROUTE) &&
   2252                     !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
   2253                     l3cfg.l3c_flags |=  BCM_L3_HOST_AS_ROUTE;
   2254                 }
   2255                 rv = mbcm_driver[unit]->mbcm_l3_ip6_replace(unit, &l3cfg);
   2256             }
   2257         }
   2258     } else {
   2259         l3cfg.l3c_ip_addr = info_local.l3a_ip_addr;
   2260         /* Add host entry - no prior entry found */
   2261         if (BCM_FAILURE(rv)) {
   2262             rv = mbcm_driver[unit]->mbcm_l3_ip4_add(unit, &l3cfg);
   2263         } else {
   2264             /* Remove Route entry and add to Host table */
   2265             if ((info_orig.l3a_flags & BCM_L3_HOST_AS_ROUTE) &&
   2266                 !(info_local.l3a_flags2 & BCM_L3_FLAGS2_ROUTE_NO_MOVE) &&
   2267                 !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
   2268                /* Entry exists within ROUTE table */
   2269                l3cfg.l3c_flags &=  ~BCM_L3_HOST_AS_ROUTE;
   2270 
   2271                /* Add entry to HOST Table */
   2272                rv = mbcm_driver[unit]->mbcm_l3_ip4_add(unit, &l3cfg);
   2273 
   2274                if (BCM_SUCCESS(rv)) {
   2275 
   2276                   /* Init ROUTE entry */
   2277                   sal_memset(&info_route, 0, sizeof(bcm_l3_route_t));
   2278                   sal_memcpy(info_route.l3a_nexthop_mac, l3cfg.l3c_mac_addr, sizeof(bcm_mac_t));
   2279                   info_route.l3a_vrf = l3cfg.l3c_vrf;
   2280                   info_route.l3a_subnet = l3cfg.l3c_ip_addr;
   2281                   info_route.l3a_ip_mask = bcm_ip_mask_create(32);
   2282                   info_route.l3a_intf = l3cfg.l3c_intf;
   2283                   info_route.l3a_modid = l3cfg.l3c_modid;
   2284                   info_route.l3a_port_tgid = l3cfg.l3c_port_tgid;
   2285                   info_route.l3a_pri = l3cfg.l3c_prio;
   2286                   info_route.l3a_lookup_class = l3cfg.l3c_lookup_class;
   2287 
   2288                   /* Delete ROUTE entry */
   2289                   rv = bcm_esw_l3_route_delete(unit, &info_route);
   2290                   if (BCM_SUCCESS(rv)) {
   2291                      /* Special return value - as entry existed within ROUTE table */
   2292 #if defined(BCM_FIREBOLT_SUPPORT)
   2293                      (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv);
   2294 #endif /* BCM_FIREBOLT_SUPPORT  */
   2295                   }
   2296                } else {
   2297                   /* Update ROUTE entry */
   2298                   l3cfg.l3c_flags |=  BCM_L3_HOST_AS_ROUTE;
   2299                   rv = mbcm_driver[unit]->mbcm_l3_ip4_replace(unit, &l3cfg);
   2300                }
   2301             } else {
   2302                 /* Replace prior entry found */
   2303                 if ((info_orig.l3a_flags & BCM_L3_HOST_AS_ROUTE) &&
   2304                     !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
   2305                     l3cfg.l3c_flags |=  BCM_L3_HOST_AS_ROUTE;
   2306                 }
   2307                 rv = mbcm_driver[unit]->mbcm_l3_ip4_replace(unit, &l3cfg);
   2308             }
   2309         }
   2310     }
   2311     L3_UNLOCK(unit);
   2312     return (rv);
   2313 }
   2314 
   2315 /*
   2316  * Function:
   2317  *      bcm_esw_l3_host_delete
   2318  * Purpose:
   2319  *      Delete an entry from the L3 table.
   2320  * Parameters:
   2321  *      unit - SOC device unit number
   2322  *      ip_addr - Pointer to host structure containing
   2323  *                destination IP address.
   2324  * Returns:
   2325  *      BCM_E_NONE              Success
   2326  *      BCM_E_UNIT              Illegal unit number
   2327  *      BCM_E_INTERNAL          Chip access failure
   2328  *      BCM_E_INIT              Unit Not initialized yet
   2329  *      BCM_E_NOT_FOUND      Cannot find a match
   2330  * Notes:
   2331  *     Flag set to BCM_L3_IP6 for IPv6, default is IPv4
   2332  */
   2333 
   2334 int
   2335 bcm_esw_l3_host_delete(int unit, bcm_l3_host_t *ip_addr)
   2336 {
   2337     _bcm_l3_cfg_t l3cfg;
   2338     bcm_l3_host_t info;
   2339     int rt;
   2340 
   2341     L3_INIT(unit);
   2342 
   2343     if (NULL == ip_addr) {
   2344         return (BCM_E_PARAM);
   2345     }
   2346 
   2347     /* Vrf is in device supported range check. */
   2348     if ((ip_addr->l3a_vrf > SOC_VRF_MAX(unit)) || 
   2349         (ip_addr->l3a_vrf < BCM_L3_VRF_DEFAULT)) {
   2350         return (BCM_E_PARAM);
   2351     }
   2352   
   2353     /*  Check that device supports ipv6. */
   2354     if (BCM_L3_NO_IP6_SUPPORT(unit, ip_addr->l3a_flags)) {
   2355         return (BCM_E_UNAVAIL);
   2356     }
   2357 
   2358     bcm_l3_host_t_init(&info);
   2359     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2360     info.l3a_vrf = ip_addr->l3a_vrf;
   2361 
   2362 #ifdef BCM_TRIDENT3_SUPPORT
   2363     if (soc_feature(unit, soc_feature_flex_flow)) {
   2364         info.flow_handle = ip_addr->flow_handle;
   2365         info.flow_option_handle = ip_addr->flow_option_handle;
   2366         info.num_of_fields = ip_addr->num_of_fields;
   2367         sal_memcpy(info.logical_fields, ip_addr->logical_fields,
   2368                    ip_addr->num_of_fields*sizeof(bcm_flow_logical_field_t));
   2369 
   2370         l3cfg.l3c_flow_handle = ip_addr->flow_handle;
   2371         l3cfg.l3c_flow_option_handle = ip_addr->flow_option_handle;
   2372         l3cfg.l3c_num_of_fields = ip_addr->num_of_fields;
   2373         sal_memcpy(l3cfg.l3c_logical_fields, ip_addr->logical_fields,
   2374                    ip_addr->num_of_fields*sizeof(bcm_flow_logical_field_t));
   2375     }
   2376 #endif /* BCM_TRIDENT3_SUPPORT */
   2377 
   2378     L3_LOCK(unit);
   2379     if (ip_addr->l3a_flags & BCM_L3_IP6) {
   2380         info.l3a_flags   = BCM_L3_IP6;
   2381         sal_memcpy(info.l3a_ip6_addr, ip_addr->l3a_ip6_addr, BCM_IP6_ADDRLEN);
   2382         rt = bcm_esw_l3_host_find(unit, &info);
   2383         if (rt != BCM_E_NONE) {
   2384             L3_UNLOCK(unit);
   2385             return rt;
   2386         }
   2387 
   2388         sal_memcpy(l3cfg.l3c_ip6,
   2389                    ip_addr->l3a_ip6_addr, BCM_IP6_ADDRLEN);
   2390         l3cfg.l3c_flags = info.l3a_flags;
   2391         l3cfg.l3c_flags2 = info.l3a_flags2;
   2392         l3cfg.l3c_vrf = ip_addr->l3a_vrf;
   2393         rt = mbcm_driver[unit]->mbcm_l3_ip6_delete(unit, &l3cfg);
   2394     } else {
   2395         info.l3a_ip_addr = ip_addr->l3a_ip_addr;
   2396         rt = bcm_esw_l3_host_find(unit, &info);
   2397         if (rt != BCM_E_NONE) {
   2398             L3_UNLOCK(unit);
   2399             return rt;
   2400         }
   2401 
   2402         l3cfg.l3c_ip_addr = ip_addr->l3a_ip_addr;
   2403         l3cfg.l3c_flags = info.l3a_flags;  /* BCM_L3_L2TOCPU might be set */
   2404         l3cfg.l3c_flags2 = info.l3a_flags2;        
   2405         l3cfg.l3c_vrf = ip_addr->l3a_vrf;
   2406         rt = mbcm_driver[unit]->mbcm_l3_ip4_delete(unit, &l3cfg);
   2407     }
   2408     L3_UNLOCK(unit);
   2409     return rt;
   2410 }
   2411 
   2412 /*
   2413  * Function:
   2414  *      bcm_esw_l3_host_delete_by_network
   2415  * Purpose:
   2416  *      Delete all L3 entries that match the IP address mask
   2417  * Parameters:
   2418  *      unit    - SOC device unit number
   2419  *      net_addr - Pointer to route structure containing the network
   2420  *                address to be matched against
   2421  * Returns:
   2422  *      BCM_E_NONE              Success
   2423  *      BCM_E_UNIT              Illegal unit number
   2424  *      BCM_E_INTERNAL          Chip access failure
   2425  *      BCM_E_INIT              Unit Not initialized yet
   2426  * Notes:
   2427  *     Flag set to BCM_L3_IP6 for IPv6, default is IPv4
   2428  */
   2429 
   2430 int
   2431 bcm_esw_l3_host_delete_by_network(int unit, bcm_l3_route_t *net_addr)
   2432 {
   2433     _bcm_l3_cfg_t l3cfg;
   2434     int rv;
   2435 
   2436     L3_INIT(unit);
   2437 
   2438     if (NULL == net_addr) {
   2439         return (BCM_E_PARAM);
   2440     }
   2441 
   2442     /* Vrf is in device supported range check. */
   2443     if ((net_addr->l3a_vrf > SOC_VRF_MAX(unit)) || 
   2444         (net_addr->l3a_vrf < BCM_L3_VRF_DEFAULT)) {
   2445         return (BCM_E_PARAM);
   2446     }
   2447 
   2448     /*  Check that device supports ipv6. */
   2449     if (BCM_L3_NO_IP6_SUPPORT(unit, net_addr->l3a_flags)) {
   2450         return (BCM_E_UNAVAIL);
   2451     }
   2452 
   2453     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2454     l3cfg.l3c_vrf        = net_addr->l3a_vrf;
   2455 
   2456     L3_LOCK(unit);
   2457     if (net_addr->l3a_flags & BCM_L3_IP6) {
   2458         sal_memcpy(l3cfg.l3c_ip6,
   2459                    net_addr->l3a_ip6_net, BCM_IP6_ADDRLEN);
   2460         sal_memcpy(l3cfg.l3c_ip6_mask,
   2461                    net_addr->l3a_ip6_mask, BCM_IP6_ADDRLEN);
   2462         l3cfg.l3c_flags = BCM_L3_IP6;
   2463         rv = mbcm_driver[unit]->mbcm_l3_ip6_delete_prefix(unit, &l3cfg);
   2464     } else { 
   2465         l3cfg.l3c_ip_addr    = net_addr->l3a_subnet;
   2466         l3cfg.l3c_ip_mask    = net_addr->l3a_ip_mask;
   2467         rv = mbcm_driver[unit]->mbcm_l3_ip4_delete_prefix(unit, &l3cfg);
   2468     } 
   2469     L3_UNLOCK(unit);
   2470     return (rv);
   2471 }
   2472 
   2473 /*
   2474  * Function:
   2475  *      bcm_esw_l3_host_delete_by_interface
   2476  * Purpose:
   2477  *      Delete all L3 entries that match the L3 interface
   2478  * Parameters:
   2479  *      unit - SOC device unit number
   2480  *      info - The host structure containing the to be matched interface ID
   2481  *             (IN)l3a_intf_id member
   2482  * Returns:
   2483  *      BCM_E_NONE              Success
   2484  *      BCM_E_UNIT              Illegal unit number
   2485  *      BCM_E_INIT              Unit Not initialized yet
   2486  * Notes:
   2487  *   - Flag set to BCM_L3_NEGATE to delete all host entries
   2488  *     that do NOT match the L3 interface.
   2489  */
   2490 int
   2491 bcm_esw_l3_host_delete_by_interface(int unit, bcm_l3_host_t *info)
   2492 {
   2493     int rv;
   2494     _bcm_l3_cfg_t l3cfg;
   2495     int negate;
   2496 
   2497     L3_INIT(unit);
   2498 
   2499     if (NULL == info) {
   2500         return (BCM_E_PARAM);
   2501     }
   2502 
   2503     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2504 
   2505     l3cfg.l3c_intf = info->l3a_intf;
   2506     negate = info->l3a_flags & BCM_L3_NEGATE ? 1 : 0;
   2507 
   2508     L3_LOCK(unit);
   2509 
   2510     rv = mbcm_driver[unit]->mbcm_l3_delete_intf(unit, &l3cfg, negate);
   2511 
   2512     L3_UNLOCK(unit);
   2513     return (rv);
   2514 }
   2515 
   2516 /*
   2517  * Function:
   2518  *      bcm_esw_l3_host_delete_all
   2519  * Purpose:
   2520  *      Delete all entries from the L3 table.
   2521  * Parameters:
   2522  *      unit - SOC device unit number
   2523  *      info - Pointer to host structure containing the flag
   2524  *             indicating IPv4 or IPv6
   2525  * Returns:
   2526  *      BCM_E_NONE              Success
   2527  *      BCM_E_UNIT              Illegal unit number
   2528  *      BCM_E_INTERNAL          Chip access failure
   2529  *      BCM_E_INIT              Unit Not initialized yet
   2530  */
   2531 int
   2532 bcm_esw_l3_host_delete_all(int unit, bcm_l3_host_t *info)
   2533 {
   2534     int rv;
   2535     L3_INIT(unit);
   2536 
   2537     L3_LOCK(unit);
   2538 
   2539     rv = mbcm_driver[unit]->mbcm_l3_delete_all(unit);
   2540 
   2541     L3_UNLOCK(unit);
   2542     return (rv);
   2543 }
   2544 
   2545 /*
   2546  * Function:
   2547  *      bcm_esw_l3_host_conflict_get
   2548  * Purpose:
   2549  *      Given a IP address, return conflicts in the L3 table.
   2550  * Parameters:
   2551  *      unit     - SOC unit number.
   2552  *      ipkey    - IP address to test conflict condition
   2553  *      cf_array - (OUT) arrary of conflicting addresses(at most 8)
   2554  *      cf_max   - max number of conflicts wanted
   2555  *      cf_count    - (OUT) actual # of conflicting addresses
   2556  * Returns:
   2557  *      BCM_E_XXX
   2558  */
   2559 int
   2560 bcm_esw_l3_host_conflict_get(int unit, bcm_l3_key_t *ipkey, bcm_l3_key_t *cf_array,
   2561                     int cf_max, int *cf_count)
   2562 {
   2563     int rv;
   2564     L3_INIT(unit);
   2565 
   2566     if (NULL == ipkey) {
   2567         return (BCM_E_PARAM);
   2568     } 
   2569 
   2570     /* Vrf is in device supported range check. */
   2571     if ((ipkey->l3k_vrf > SOC_VRF_MAX(unit)) || 
   2572         (ipkey->l3k_vrf < BCM_L3_VRF_DEFAULT)) {
   2573         return (BCM_E_PARAM);
   2574     }
   2575 
   2576     /*  Check that device supports ipv6. */
   2577     if (BCM_L3_NO_IP6_SUPPORT(unit, ipkey->l3k_flags)) {
   2578         return (BCM_E_UNAVAIL);
   2579     }
   2580 
   2581     L3_LOCK(unit);
   2582 
   2583     rv = mbcm_driver[unit]->mbcm_l3_conflict_get(unit, ipkey, cf_array, 
   2584                                                  cf_max, cf_count);
   2585     L3_UNLOCK(unit);
   2586     return (rv);
   2587 }
   2588 
   2589 /*
   2590  * Function:
   2591  *      bcm_esw_l3_host_age
   2592  * Purpose:
   2593  *      Age out the L3 entry by clearing the HIT bit when appropriate,
   2594  *      the L3 host entry itself is removed if HIT bit is not set.
   2595  * Parameters:
   2596  *      unit - SOC device unit number
   2597  *      flags - The criteria used to age out L3 table.
   2598  *      age_cb - Call back routine.
   2599  *      user_data  - (IN) User provided cookie for callback.
   2600  * Returns:
   2601  *      BCM_E_UNIT              Illegal unit number
   2602  *      BCM_E_INIT              Unit Not initialized yet
   2603  */
   2604 
   2605 int
   2606 bcm_esw_l3_host_age(int unit, uint32 flags, bcm_l3_host_traverse_cb age_cb, 
   2607                     void *user_data)
   2608 {
   2609     int rv;
   2610     L3_INIT(unit);
   2611 
   2612     /*  Check that device supports ipv6. */
   2613     if (BCM_L3_NO_IP6_SUPPORT(unit, flags)) {
   2614         return (BCM_E_UNAVAIL);
   2615     }
   2616 
   2617     L3_LOCK(unit);
   2618 
   2619     rv = mbcm_driver[unit]->mbcm_l3_age(unit, flags, age_cb, user_data);
   2620 
   2621     L3_UNLOCK(unit);
   2622     return (rv);
   2623 }
   2624 
   2625 /*
   2626  * Function:
   2627  *      bcm_esw_l3_host_traverse
   2628  * Purpose:
   2629  *      Go through all valid L3 entries, and call the callback function
   2630  *      at each entry
   2631  * Parameters:
   2632  *      unit - SOC device unit number
   2633  *      flags - BCM_L3_IP6
   2634  *      start - Callback called after this many L3 entries
   2635  *      end   - Callback called before this many L3 entries
   2636  *      cb    - User supplied callback function
   2637  *      user_data - User supplied cookie used in parameter in callback function
   2638  * Returns:
   2639  *      BCM_E_UNIT              Illegal unit number
   2640  *      BCM_E_INIT              Unit Not initialized yet
   2641  */
   2642 
   2643 int
   2644 bcm_esw_l3_host_traverse(int unit, uint32 flags,
   2645                          uint32 start, uint32 end,
   2646                          bcm_l3_host_traverse_cb cb, void *user_data)
   2647 {
   2648     int rv;
   2649 
   2650     L3_INIT(unit);
   2651 
   2652     if (NULL == cb) {
   2653         return (BCM_E_PARAM);
   2654     }
   2655 
   2656     /*  Check that device supports ipv6. */
   2657     if (BCM_L3_NO_IP6_SUPPORT(unit, flags)) {
   2658         return (BCM_E_UNAVAIL);
   2659     }
   2660 
   2661     L3_LOCK(unit);
   2662 
   2663     if (flags & BCM_L3_IP6) {
   2664         rv = mbcm_driver[unit]->mbcm_l3_ip6_traverse(unit, flags,
   2665                                 start, end, cb, user_data);
   2666     } else {
   2667         rv = mbcm_driver[unit]->mbcm_l3_ip4_traverse(unit, flags,
   2668                                 start, end, cb, user_data);
   2669     }
   2670 
   2671     L3_UNLOCK(unit);
   2672     return (rv);
   2673 }
   2674 
   2675 /*
   2676  * Function:
   2677  *      bcm_esw_l3_host_invalidate_entry
   2678  * Purpose:
   2679  *      Given a IP address, invalidate the L3 entry without
   2680  *      clearing the entry information, so that the entry can be
   2681  *      turned back to valid without resetting all the information.
   2682  * Parameters:
   2683  *      unit     - SOC unit number.
   2684  *      ipaddr   - IP address to test conflict condition
   2685  * Returns:
   2686  *      BCM_E_XXX
   2687  */
   2688 int
   2689 bcm_esw_l3_host_invalidate_entry(int unit, bcm_ip_t ipaddr)
   2690 {
   2691 #ifdef BCM_XGS12_SWITCH_SUPPORT
   2692     int rv;
   2693 #endif  /* BCM_XGS_SWITCH_SUPPORT */
   2694     L3_INIT(unit);
   2695 
   2696 #ifdef BCM_XGS12_SWITCH_SUPPORT
   2697     if (SOC_IS_XGS12_SWITCH(unit)) {
   2698         L3_LOCK(unit);
   2699         rv = bcm_xgs_l3_invalidate_entry(unit, ipaddr);
   2700         L3_UNLOCK(unit);
   2701         return (rv);
   2702     }
   2703 #endif  /* BCM_XGS_SWITCH_SUPPORT */
   2704 
   2705     return BCM_E_UNAVAIL;
   2706 }
   2707 
   2708 /*
   2709  * Function:
   2710  *      bcm_esw_l3_host_validate_entry
   2711  * Purpose:
   2712  *      Given a IP address, validate the L3 entry without
   2713  *      resetting the entry information.
   2714  * Parameters:
   2715  *      unit     - SOC unit number.
   2716  *      ipaddr   - IP address to test conflict condition
   2717  * Returns:
   2718  *      BCM_E_XXX
   2719  */
   2720 int
   2721 bcm_esw_l3_host_validate_entry(int unit, bcm_ip_t ipaddr)
   2722 {
   2723 #ifdef BCM_XGS12_SWITCH_SUPPORT
   2724     int rv;
   2725 #endif  /* BCM_XGS_SWITCH_SUPPORT */
   2726     L3_INIT(unit);
   2727 
   2728 #ifdef BCM_XGS12_SWITCH_SUPPORT
   2729     if (SOC_IS_XGS12_SWITCH(unit)) {
   2730         L3_LOCK(unit);
   2731         rv = bcm_xgs_l3_validate_entry(unit, ipaddr);
   2732         L3_UNLOCK(unit);
   2733         return (rv);
   2734     }
   2735 #endif  /* BCM_XGS_SWITCH_SUPPORT */
   2736 
   2737     return BCM_E_UNAVAIL;
   2738 }
   2739 
   2740 /*
   2741  * Function:
   2742  *      bcm_esw_l3_route_add
   2743  * Purpose:
   2744  *      Add an IP route to the DEFIP table.
   2745  * Parameters:
   2746  *      unit - SOC device unit number
   2747  *      info - Pointer to bcm_l3_route_t containing all valid fields.
   2748  * Returns:
   2749  *      BCM_E_XXX
   2750  * Note:
   2751  *  1. In addition to the route info (i.e. the network number,
   2752  *     nexthop MAC addr, L3 intf, port, modid, or trunk ID),
   2753  *     on XGS chips, one must specify the nexthop IP addr.
   2754  *     This is used as key to find entry in the L3 table.
   2755  *
   2756  *  2. XGS ECMP route must have BCM_L3_MULTIPATH flag set.
   2757  *     ECMP is supported on all XGS devices.
   2758  *
   2759  *  3. BCM_L3_DEFIP_LOCAL flag is used, then packets that matches
   2760  *     LPM table will be sent to CPU unchanged (XGS only).
   2761  *     BCM_L3_DEFIP_LOCAL flag is used for last hop direct-connected
   2762  *     subnet (e.g where workstations are attached to router).
   2763  *     BCM_L3_DEFIP_LOCAL and BCM_L3_MULTIPATH can not be both set.
   2764  *     When BCM_L3_DEFIP_LOCAL flag is used, nexthop IP addr
   2765  *     is not needed.
   2766  */
   2767 
   2768 int
   2769 bcm_esw_l3_route_add(int unit, bcm_l3_route_t *info)
   2770 {
   2771     int max_prefix_length;
   2772     _bcm_defip_cfg_t defip;
   2773     uint8 ip6_zero[BCM_IP6_ADDRLEN] = {0};
   2774     int rv;
   2775     bcm_l3_route_t  info_local;
   2776     bcm_module_t    source_modid = 0;
   2777     bcm_port_t      source_port_tgid = 0;
   2778     uint32 source_trunk_flag = 0;
   2779 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   2780     int l3iif_max;
   2781 #endif
   2782 
   2783     L3_INIT(unit);
   2784 
   2785     if (NULL == info) {
   2786         return (BCM_E_PARAM);
   2787     }
   2788 
   2789     /* Copy provided structure to local so it can be modified. */
   2790     sal_memcpy(&info_local, info, sizeof(bcm_l3_route_t));
   2791 
   2792     if ((info_local.l3a_vrf > SOC_VRF_MAX(unit)) || 
   2793         (info_local.l3a_vrf < BCM_L3_VRF_GLOBAL)) {
   2794         return (BCM_E_PARAM);
   2795     }
   2796 
   2797     /*  Check that device supports ipv6. */
   2798     if (BCM_L3_NO_IP6_SUPPORT(unit, info_local.l3a_flags)) {
   2799         return (BCM_E_UNAVAIL);
   2800     }
   2801 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   2802     if (soc_feature(unit, soc_feature_ipmc_defip)) { 
   2803 
   2804         if ((info_local.l3a_flags & BCM_L3_IPMC) &&
   2805             !(_BCM_MULTICAST_IS_L3(info_local.l3a_mc_group)) &&
   2806             !(_BCM_MULTICAST_IS_VXLAN(info_local.l3a_mc_group))) {
   2807             return BCM_E_PARAM;
   2808         }
   2809         /* Expected L3IIF and RP ID cannot go together */
   2810         if((info_local.l3a_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) &&
   2811             (info_local.l3a_rp != BCM_IPMC_RP_ID_INVALID)) {
   2812             return (BCM_E_PARAM);
   2813         }
   2814         /* Resolve is not applicable */
   2815         if(info_local.l3a_ipmc_flags & BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE) {
   2816             return (BCM_E_PARAM);
   2817         }
   2818         l3iif_max = _BCM_DEFIP_IPMC_EXPECTED_L3IIF_MAX;
   2819         if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve) &&
   2820             SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, EXPECTED_L3_IIF0f)) {
   2821             l3iif_max =
   2822                 (1 << soc_mem_field_length(unit, L3_DEFIPm, EXPECTED_L3_IIF0f)) - 1;
   2823         }
   2824         /*
   2825          * 1) Expected L3IIF cannot be more than _BCM_DEFIP_IPMC_EXPECTED_L3IIF_MAX
   2826          * 2) MULTIPATH and MULTICAST cannot be true together
   2827          */
   2828         if((info_local.l3a_expected_intf > l3iif_max) ||
   2829            ((info_local.l3a_flags & BCM_L3_MULTIPATH) &&
   2830             (info_local.l3a_flags & BCM_L3_IPMC))) {
   2831             return (BCM_E_PARAM);
   2832         }
   2833     }
   2834 #endif
   2835     
   2836     if (soc_feature(unit, soc_feature_extended_address_class)) {
   2837         if ((info_local.l3a_lookup_class > SOC_EXT_ADDR_CLASS_MAX(unit)) ||
   2838             (info_local.l3a_lookup_class < 0)) {
   2839                     return (BCM_E_PARAM);
   2840         }
   2841     } else if (soc_feature(unit, soc_feature_overlaid_address_class) && 
   2842                !BCM_L3_RPE_SET(info_local.l3a_flags)) {
   2843                    if ((info_local.l3a_lookup_class > 
   2844                         SOC_OVERLAID_ADDR_CLASS_MAX(unit)) ||
   2845                       (info_local.l3a_lookup_class < 0)) {
   2846                         return (BCM_E_PARAM);
   2847             }
   2848     } else if ((info_local.l3a_lookup_class > SOC_ADDR_CLASS_MAX(unit)) || 
   2849         (info_local.l3a_lookup_class < 0)) {
   2850         return (BCM_E_PARAM);
   2851     }
   2852 
   2853     /* 
   2854      * When RPE is not set and soc_feature_overlaid_address_class is
   2855      * not enabled, priority values range from 0-7.
   2856      * When RPE is set, priority values range from 0-15.
   2857      * When RPE is not set but soc_feature_overlaid_address_class
   2858      * is enabled, priority value ranges from 0-15.
   2859      */
   2860     if(!BCM_L3_RPE_SET(info_local.l3a_flags) &&
   2861        !soc_feature(unit, soc_feature_overlaid_address_class)) {
   2862        if (!BCM_PRIORITY_VALID(info_local.l3a_pri)) {
   2863            return (BCM_E_PARAM);
   2864        }
   2865     } else {
   2866        if (!BCM_RPE_PRIORITY_VALID(info_local.l3a_pri)) {
   2867            return (BCM_E_PARAM);
   2868        }
   2869     }
   2870 
   2871     if (BCM_GPORT_IS_SET(info_local.l3a_port_tgid)) {
   2872 
   2873         /* l3a_port_tgid can contain either port or trunk */
   2874         BCM_IF_ERROR_RETURN(
   2875             _bcm_esw_l3_gport_resolve(unit, info_local.l3a_port_tgid, 
   2876                                       &(info_local.l3a_port_tgid),
   2877                                       &(info_local.l3a_modid), 
   2878                                       &(info_local.l3a_port_tgid), 
   2879                                       &(info_local.l3a_flags)));
   2880     } else {
   2881         PORT_DUALMODID_VALID(unit, info_local.l3a_port_tgid);
   2882     }
   2883 
   2884     if (soc_feature(unit, soc_feature_ipmc_defip) &&
   2885             (info_local.l3a_flags & BCM_L3_IPMC) &&
   2886             !(info_local.l3a_ipmc_flags & BCM_IPMC_SOURCE_PORT_NOCHECK)) {
   2887         if (BCM_GPORT_IS_SET(info_local.l3a_expected_src_gport)) {
   2888 
   2889             /* l3a_port_tgid can contain either port or trunk */
   2890             BCM_IF_ERROR_RETURN(
   2891                     _bcm_esw_l3_gport_resolve(unit,
   2892                         info_local.l3a_expected_src_gport,
   2893                         &source_port_tgid,
   2894                         &source_modid, 
   2895                         &source_port_tgid,
   2896                         &source_trunk_flag));
   2897         } else {
   2898             PORT_DUALMODID_VALID(unit, info_local.l3a_expected_src_gport);
   2899         }
   2900     }
   2901 
   2902     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   2903 
   2904     sal_memcpy(defip.defip_mac_addr, info_local.l3a_nexthop_mac,
   2905                sizeof(bcm_mac_t));
   2906     defip.defip_intf       = info_local.l3a_intf;
   2907     defip.defip_modid      = info_local.l3a_modid;
   2908     defip.defip_port_tgid  = info_local.l3a_port_tgid;
   2909     defip.defip_vid        = info_local.l3a_vid;
   2910     defip.defip_flags      = info_local.l3a_flags;
   2911     defip.defip_flags2     = info_local.l3a_flags2;
   2912     defip.defip_ipmc_flags = info_local.l3a_ipmc_flags;
   2913     defip.defip_vrf        = info_local.l3a_vrf;
   2914     defip.defip_tunnel_option = (info_local.l3a_tunnel_option & 0xffff);
   2915     defip.defip_mpls_label = info_local.l3a_mpls_label;
   2916     defip.defip_expected_intf = info_local.l3a_expected_intf;
   2917     defip.defip_l3a_rp     = info_local.l3a_rp;
   2918     defip.defip_mc_group   = info_local.l3a_mc_group;
   2919     if (soc_feature(unit, soc_feature_ipmc_defip) &&
   2920             (defip.defip_flags & BCM_L3_IPMC)) {
   2921         defip.defip_source_modid = source_modid;
   2922         defip.defip_source_port_tgid = source_port_tgid;
   2923         defip.defip_source_ts = (source_trunk_flag & BCM_L3_TGID) ? 1 : 0;
   2924         if(_BCM_MULTICAST_IS_L3(defip.defip_mc_group) ||
   2925            _BCM_MULTICAST_IS_VXLAN(defip.defip_mc_group)) {
   2926             defip.defip_mc_group = _BCM_MULTICAST_ID_GET(defip.defip_mc_group);
   2927         } else {
   2928             return BCM_E_PARAM;
   2929         }
   2930     }
   2931     if (soc_feature(unit, soc_feature_overlaid_address_class) && 
   2932         (!BCM_L3_RPE_SET(info_local.l3a_flags))) {
   2933         defip.defip_prio = ((info_local.l3a_lookup_class & 0x3C0) >> 6);
   2934         defip.defip_lookup_class = (info_local.l3a_lookup_class & 0x3F);
   2935     } else {
   2936         defip.defip_prio = info_local.l3a_pri;
   2937         defip.defip_lookup_class = info_local.l3a_lookup_class;
   2938     }
   2939 
   2940 #ifdef BCM_TRIDENT3_SUPPORT
   2941     if (soc_feature(unit, soc_feature_flex_flow)) {
   2942         defip.defip_flow_handle = info_local.flow_handle;
   2943         defip.defip_flow_option_handle = info_local.flow_option_handle;
   2944         defip.defip_num_of_fields = info_local.num_of_fields;
   2945         sal_memcpy(defip.defip_logical_fields, info_local.logical_fields,
   2946                    info_local.num_of_fields*sizeof(bcm_flow_logical_field_t));
   2947     }
   2948 #endif /* BCM_TRIDENT3_SUPPORT */
   2949     L3_LOCK(unit);
   2950     if (info_local.l3a_flags & BCM_L3_IP6) {
   2951         max_prefix_length = 
   2952             soc_feature(unit, soc_feature_lpm_prefix_length_max_128) ? 128 : 64;
   2953         if (bcm_ip6_mask_length(info_local.l3a_ip6_mask) == 0 &&
   2954             sal_memcmp(info_local.l3a_ip6_net, ip6_zero, BCM_IP6_ADDRLEN) != 0) {
   2955             L3_UNLOCK(unit);
   2956             return (BCM_E_PARAM);
   2957         }
   2958         sal_memcpy(defip.defip_ip6_addr, info_local.l3a_ip6_net, BCM_IP6_ADDRLEN);
   2959         defip.defip_sub_len = bcm_ip6_mask_length(info_local.l3a_ip6_mask);
   2960         if (defip.defip_sub_len > max_prefix_length) {
   2961             L3_UNLOCK(unit);
   2962             return (BCM_E_PARAM);
   2963         } 
   2964         rv = mbcm_driver[unit]->mbcm_ip6_defip_add(unit, &defip);
   2965     } else {
   2966         if (info_local.l3a_ip_mask == 0 && info_local.l3a_subnet != 0) {
   2967             L3_UNLOCK(unit);
   2968             return (BCM_E_PARAM);
   2969         }
   2970         defip.defip_ip_addr    = info_local.l3a_subnet & info_local.l3a_ip_mask;
   2971         defip.defip_sub_len    = bcm_ip_mask_length(info_local.l3a_ip_mask);
   2972         defip.defip_nexthop_ip = info_local.l3a_nexthop_ip;
   2973         rv = mbcm_driver[unit]->mbcm_ip4_defip_add(unit, &defip);
   2974     }
   2975     L3_UNLOCK(unit);
   2976 
   2977     return (rv);
   2978 }
   2979 
   2980 /*
   2981  * Function:
   2982  *      bcm_esw_l3_route_delete
   2983  * Purpose:
   2984  *      Delete an entry from the Default IP Router table.
   2985  * Parameters:
   2986  *      unit - SOC device unit number
   2987  *      info - Pointer to bcm_l3_route_t structure with valid IP subnet & mask.
   2988  * Returns:
   2989  *      BCM_E_XXX.
   2990  * Note:
   2991  *  1. For non-ECMP routes, it suffices to specify the network number
   2992  *     in order to delete the route, since there is only one path.
   2993  *
   2994  *  2. For ECMP routes, in addition to specifying the network number,
   2995  *     one must specify which ECMP path is to be deleted.
   2996  *     This is done by specifying the following parameters:
   2997  *     nexthop MAC addr, L3 intf, port, modid, next hop IP addr.
   2998  *
   2999  *     This is how these parameters are used to identify the ECMP path:
   3000  *        next hop IP addr | nexthop MAC addr |
   3001  *        (L3 intf, port, modid)
   3002  *     Unspecified nexthop IP or MAC addr must be set to 0.
   3003  *
   3004  *     XGS ECMP route must have BCM_L3_MULTIPATH flag set.
   3005  *     ECMP is supported on all XGS devices.
   3006  */
   3007 
   3008 int
   3009 bcm_esw_l3_route_delete(int unit, bcm_l3_route_t *info)
   3010 {
   3011     int max_prefix_length;
   3012     _bcm_defip_cfg_t defip;
   3013     int rv;
   3014     bcm_l3_route_t info_local;
   3015 
   3016     L3_INIT(unit);
   3017 
   3018     if (NULL == info) {
   3019         return (BCM_E_PARAM);
   3020     }
   3021 
   3022     /* Copy provided structure to local so it can be modified. */
   3023     sal_memcpy(&info_local, info, sizeof(bcm_l3_route_t));
   3024 
   3025     if ((info_local.l3a_vrf > SOC_VRF_MAX(unit)) || 
   3026         (info_local.l3a_vrf < BCM_L3_VRF_GLOBAL)) {
   3027         return (BCM_E_PARAM);
   3028     }
   3029 
   3030     /*  Check that device supports ipv6. */
   3031     if (BCM_L3_NO_IP6_SUPPORT(unit, info_local.l3a_flags)) {
   3032         return (BCM_E_UNAVAIL);
   3033     }
   3034 
   3035     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   3036 
   3037     defip.defip_vid        = info_local.l3a_vid;
   3038     defip.defip_flags      = info_local.l3a_flags;
   3039     defip.defip_vrf        = info_local.l3a_vrf;
   3040 
   3041     if (info_local.l3a_flags & BCM_L3_MULTIPATH) {
   3042          if (BCM_GPORT_IS_SET(info_local.l3a_port_tgid)) {
   3043               /* l3a_port_tgid can contain either port or trunk */
   3044               BCM_IF_ERROR_RETURN(
   3045                    _bcm_esw_l3_gport_resolve(unit, info_local.l3a_port_tgid, 
   3046                                   &(info_local.l3a_port_tgid),
   3047                                   &(info_local.l3a_modid), 
   3048                                   &(info_local.l3a_port_tgid), 
   3049                                   &(info_local.l3a_flags)));
   3050          } 
   3051 
   3052         sal_memcpy(defip.defip_mac_addr, info_local.l3a_nexthop_mac,
   3053                    sizeof(bcm_mac_t));
   3054         defip.defip_intf      = info_local.l3a_intf;
   3055         defip.defip_port_tgid = info_local.l3a_port_tgid;
   3056         defip.defip_modid     = info_local.l3a_modid;
   3057         defip.defip_flags      = info_local.l3a_flags;
   3058     }
   3059 #ifdef BCM_TRIDENT3_SUPPORT
   3060     if (soc_feature(unit, soc_feature_flex_flow)) {
   3061         defip.defip_flow_handle = info_local.flow_handle;
   3062         defip.defip_flow_option_handle = info_local.flow_option_handle;
   3063         defip.defip_num_of_fields = info_local.num_of_fields;
   3064         sal_memcpy(defip.defip_logical_fields, info_local.logical_fields,
   3065                    info_local.num_of_fields*sizeof(bcm_flow_logical_field_t));
   3066     }
   3067 #endif /* BCM_TRIDENT3_SUPPORT */
   3068 
   3069     L3_LOCK(unit);
   3070     if (info_local.l3a_flags & BCM_L3_IP6) {
   3071         max_prefix_length = 
   3072             soc_feature(unit, soc_feature_lpm_prefix_length_max_128) ? 128 : 64;
   3073         sal_memcpy(defip.defip_ip6_addr, info_local.l3a_ip6_net, BCM_IP6_ADDRLEN);
   3074         defip.defip_sub_len    = bcm_ip6_mask_length(info_local.l3a_ip6_mask);
   3075         if (defip.defip_sub_len > max_prefix_length) {
   3076             L3_UNLOCK(unit);
   3077             return (BCM_E_PARAM);
   3078         } 
   3079         rv = mbcm_driver[unit]->mbcm_ip6_defip_delete(unit, &defip);
   3080     } else {
   3081         defip.defip_ip_addr    = info_local.l3a_subnet & info_local.l3a_ip_mask;
   3082         defip.defip_sub_len    = bcm_ip_mask_length(info_local.l3a_ip_mask);
   3083         defip.defip_nexthop_ip = info_local.l3a_nexthop_ip;
   3084 
   3085         rv = mbcm_driver[unit]->mbcm_ip4_defip_delete(unit, &defip);
   3086     }
   3087 
   3088     L3_UNLOCK(unit);
   3089     return (rv);
   3090 }
   3091 
   3092 /*
   3093  * Function:
   3094  *      bcm_esw_l3_route_get
   3095  * Purpose:
   3096  *      Get an entry from the DEF IP table.
   3097  * Parameters:
   3098  *      unit - SOC device unit number
   3099  *      info - (OUT)Pointer to bcm_l3_route_t for return information.
   3100  * Returns:
   3101  *      BCM_E_XXX
   3102  * Notes:
   3103  *    - Application has to pass IP address, IP mask for the network
   3104  *    - If the route is local, then the BCM_L3_DEFIP_LOCAL flag is
   3105  *      set, and next hop MAC, port/tgid, interface, MODID fields
   3106  *      are all cleared.
   3107  */
   3108 
   3109 int
   3110 bcm_esw_l3_route_get(int unit, bcm_l3_route_t *info)
   3111 {
   3112     int max_prefix_length;
   3113     _bcm_defip_cfg_t defip;
   3114     int rv;
   3115 #if defined(BCM_TRX_SUPPORT)
   3116     uint32 ipmc_id;
   3117 #endif
   3118 
   3119     L3_INIT(unit);
   3120 
   3121     if (NULL == info) {
   3122         return BCM_E_PARAM;
   3123     }
   3124 
   3125     if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 
   3126         (info->l3a_vrf < BCM_L3_VRF_GLOBAL)) {
   3127         return (BCM_E_PARAM);
   3128     }
   3129 
   3130     /*  Check that device supports ipv6. */
   3131     if (BCM_L3_NO_IP6_SUPPORT(unit, info->l3a_flags)) {
   3132         return (BCM_E_UNAVAIL);
   3133     }
   3134 
   3135     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   3136     defip.defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   3137     defip.defip_flags = info->l3a_flags;
   3138     defip.defip_vrf     = info->l3a_vrf;
   3139 
   3140 #ifdef BCM_TRIDENT3_SUPPORT
   3141     if (soc_feature(unit, soc_feature_flex_flow)) {
   3142         defip.defip_flow_handle = info->flow_handle;
   3143         defip.defip_flow_option_handle = info->flow_option_handle;
   3144         defip.defip_num_of_fields = info->num_of_fields;
   3145         sal_memcpy(defip.defip_logical_fields, info->logical_fields,
   3146                    info->num_of_fields*sizeof(bcm_flow_logical_field_t));
   3147     }
   3148 #endif /* BCM_TRIDENT3_SUPPORT */
   3149 
   3150     L3_LOCK(unit);
   3151     if (info->l3a_flags & BCM_L3_IP6) {
   3152         max_prefix_length = 
   3153             soc_feature(unit, soc_feature_lpm_prefix_length_max_128) ? 128 : 64;
   3154         sal_memcpy(defip.defip_ip6_addr, info->l3a_ip6_net, BCM_IP6_ADDRLEN);
   3155         defip.defip_sub_len    = bcm_ip6_mask_length(info->l3a_ip6_mask);
   3156         if (defip.defip_sub_len > max_prefix_length) {
   3157             L3_UNLOCK(unit);
   3158             return (BCM_E_PARAM);
   3159         } 
   3160         rv = mbcm_driver[unit]->mbcm_ip6_defip_cfg_get(unit, &defip);
   3161     } else {
   3162         defip.defip_ip_addr = info->l3a_subnet & info->l3a_ip_mask;
   3163         defip.defip_sub_len = bcm_ip_mask_length(info->l3a_ip_mask);
   3164         rv = mbcm_driver[unit]->mbcm_ip4_defip_cfg_get(unit, &defip);
   3165     }
   3166 
   3167     L3_UNLOCK(unit);
   3168     if (rv < 0) {
   3169         return rv;
   3170     }
   3171 
   3172     sal_memcpy(info->l3a_nexthop_mac, defip.defip_mac_addr,
   3173                sizeof(bcm_mac_t));
   3174     info->l3a_nexthop_ip = defip.defip_nexthop_ip;
   3175     info->l3a_intf = defip.defip_intf;
   3176     info->l3a_port_tgid = defip.defip_port_tgid;
   3177     info->l3a_modid = defip.defip_modid;
   3178     info->l3a_lookup_class = defip.defip_lookup_class;
   3179     info->l3a_flags = defip.defip_flags;
   3180     info->l3a_flags2 = defip.defip_flags2;
   3181     info->l3a_mpls_label = defip.defip_mpls_label;
   3182     info->l3a_tunnel_option = defip.defip_tunnel_option;
   3183     info->l3a_expected_intf = defip.defip_expected_intf;
   3184     info->l3a_rp = defip.defip_l3a_rp;
   3185     info->l3a_mc_group = defip.defip_mc_group;
   3186     info->l3a_ipmc_flags = defip.defip_ipmc_flags;
   3187     if (defip.defip_flags & BCM_L3_IPMC ) {
   3188 #if defined(BCM_TRX_SUPPORT)
   3189         if (SOC_IS_TRX(unit)) {
   3190             ipmc_id = info->l3a_mc_group;
   3191             rv = _bcm_tr_multicast_ipmc_group_type_get(
   3192                     unit, ipmc_id, &(info->l3a_mc_group));
   3193             if (BCM_FAILURE(rv)) {
   3194                 /* default to _BCM_MULTICAST_TYPE_L3 */
   3195                 _BCM_MULTICAST_GROUP_SET(info->l3a_mc_group,
   3196                                          _BCM_MULTICAST_TYPE_L3, ipmc_id);
   3197             }
   3198         } else
   3199 #endif
   3200         {
   3201             _BCM_MULTICAST_GROUP_SET(info->l3a_mc_group,
   3202                                      _BCM_MULTICAST_TYPE_L3, info->l3a_mc_group);
   3203         }
   3204     }
   3205 
   3206     /* For devices that support the overlaid_address_range, if the RPE
   3207        field is '0', the 4 bits of PRI are the upper 4 bits
   3208        (of total 10 bits) of the classId, the lower 6 come from classId
   3209        as usual, for rest of the cases, the classID and PRI are copied
   3210        over directly.
   3211     */
   3212     if (soc_feature(unit, soc_feature_overlaid_address_class) && 
   3213                     !BCM_L3_RPE_SET(defip.defip_flags)) {
   3214         info->l3a_lookup_class = ((defip.defip_prio & 0xF) << 6);
   3215         info->l3a_lookup_class |= (defip.defip_lookup_class & 0x3F);
   3216     } else {
   3217         info->l3a_pri = defip.defip_prio;
   3218     }
   3219 
   3220 #ifdef BCM_TRIDENT3_SUPPORT
   3221     if (soc_feature(unit, soc_feature_flex_flow)) {
   3222         sal_memcpy(info->logical_fields,
   3223                    defip.defip_logical_fields,
   3224                    defip.defip_num_of_fields * sizeof(bcm_flow_logical_field_t));
   3225     }
   3226 #endif /* BCM_TRIDENT3_SUPPORT */
   3227 
   3228     BCM_IF_ERROR_RETURN(
   3229         _bcm_esw_l3_gport_construct(unit, info->l3a_port_tgid, info->l3a_modid, 
   3230                                     info->l3a_port_tgid, info->l3a_flags, 
   3231                                     &(info->l3a_port_tgid)));
   3232 
   3233     if (!(info->l3a_ipmc_flags & BCM_IPMC_SOURCE_PORT_NOCHECK)) {
   3234         BCM_IF_ERROR_RETURN(
   3235                 _bcm_esw_l3_gport_construct(unit, defip.defip_source_port_tgid,
   3236                     defip.defip_source_modid,
   3237                     defip.defip_source_port_tgid,
   3238                     defip.defip_source_ts ? BCM_L3_TGID : 0,
   3239                     &(info->l3a_expected_src_gport)));
   3240     }
   3241     return BCM_E_NONE;
   3242 }
   3243 
   3244 /*
   3245  * Function:
   3246  *      bcm_l3_route_find
   3247  * Purpose:
   3248  *      Get a Longest Prefix Matched entry from the DEF IP table for 
   3249  *      a host address.
   3250  * Parameters:
   3251  *      unit  - SOC device unit number
   3252  *      dest  - (IN) Given host address.
   3253  *      route - (OUT)Pointer to bcm_l3_route_t for return information.
   3254  * Returns:
   3255  *      BCM_E_XXX
   3256  * Notes:
   3257  *    - Application has to pass IP address and flag for IP version. 
   3258  */
   3259 int
   3260 bcm_esw_l3_route_find(int unit, bcm_l3_host_t *host, bcm_l3_route_t *route)
   3261 {
   3262     int max_prefix_length;
   3263     _bcm_defip_cfg_t defip;
   3264     int rv;
   3265 
   3266     L3_INIT(unit);
   3267 
   3268     if (NULL == host || NULL == route) {
   3269         return BCM_E_PARAM;
   3270     }
   3271 
   3272     if ((host->l3a_vrf > SOC_VRF_MAX(unit)) || 
   3273         (host->l3a_vrf < BCM_L3_VRF_GLOBAL)) {
   3274         return (BCM_E_PARAM);
   3275     }
   3276 
   3277     /*  Check that device supports ipv6. */
   3278     if (BCM_L3_NO_IP6_SUPPORT(unit, host->l3a_flags)) {
   3279         return (BCM_E_UNAVAIL);
   3280     }
   3281 
   3282     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   3283     defip.defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   3284     defip.defip_flags = host->l3a_flags;
   3285     defip.defip_vrf   = host->l3a_vrf;
   3286 
   3287     L3_LOCK(unit);
   3288     if (host->l3a_flags & BCM_L3_IP6) {
   3289         max_prefix_length = 128;
   3290         sal_memcpy(defip.defip_ip6_addr, host->l3a_ip6_addr, BCM_IP6_ADDRLEN);
   3291         defip.defip_sub_len = max_prefix_length;
   3292         rv = bcm_xgs3_defip_find(unit, &defip);
   3293     } else {
   3294         defip.defip_ip_addr = host->l3a_ip_addr;
   3295         defip.defip_sub_len = 32;
   3296         rv = bcm_xgs3_defip_find(unit, &defip);
   3297     }
   3298 
   3299     L3_UNLOCK(unit);
   3300     if (rv < 0) {
   3301         return rv;
   3302     }
   3303 
   3304     sal_memcpy(route->l3a_nexthop_mac, defip.defip_mac_addr,
   3305                sizeof(bcm_mac_t));
   3306     route->l3a_nexthop_ip = defip.defip_nexthop_ip;
   3307     route->l3a_intf = defip.defip_intf;
   3308     route->l3a_port_tgid = defip.defip_port_tgid;
   3309     route->l3a_modid = defip.defip_modid;
   3310     route->l3a_flags = defip.defip_flags;
   3311     route->l3a_flags2 = defip.defip_flags2;
   3312     route->l3a_mpls_label = defip.defip_mpls_label;
   3313     route->l3a_tunnel_option = (uint32)defip.defip_index;
   3314     route->l3a_vrf = defip.defip_vrf;
   3315     route->l3a_expected_intf = defip.defip_expected_intf;
   3316     route->l3a_rp = defip.defip_l3a_rp;
   3317     route->l3a_mc_group = defip.defip_mc_group;
   3318     route->l3a_ipmc_flags = defip.defip_ipmc_flags;
   3319     if (defip.defip_flags & BCM_L3_IPMC ) {
   3320         _BCM_MULTICAST_GROUP_SET(route->l3a_mc_group, _BCM_MULTICAST_TYPE_L3,
   3321                                  route->l3a_mc_group);
   3322     }
   3323 
   3324     if (soc_feature(unit, soc_feature_overlaid_address_class) && 
   3325                !BCM_L3_RPE_SET(defip.defip_flags)) {
   3326         route->l3a_lookup_class = ((defip.defip_prio & 0xF) << 6);
   3327         route->l3a_lookup_class |= (defip.defip_lookup_class & 0x3F);
   3328     } else {
   3329         route->l3a_lookup_class = defip.defip_lookup_class;
   3330     }
   3331     if (defip.defip_flags & BCM_L3_IP6) {
   3332         sal_memcpy(route->l3a_ip6_net, defip.defip_ip6_addr, BCM_IP6_ADDRLEN);
   3333         bcm_ip6_mask_create(route->l3a_ip6_mask, defip.defip_sub_len);
   3334     } else {
   3335         route->l3a_subnet = defip.defip_ip_addr;
   3336         route->l3a_ip_mask = bcm_ip_mask_create(defip.defip_sub_len);
   3337     }
   3338 
   3339     BCM_IF_ERROR_RETURN(
   3340         _bcm_esw_l3_gport_construct(unit, route->l3a_port_tgid, route->l3a_modid, 
   3341                                     route->l3a_port_tgid, route->l3a_flags, 
   3342                                     &(route->l3a_port_tgid)));
   3343 
   3344     if (!(route->l3a_ipmc_flags & BCM_IPMC_SOURCE_PORT_NOCHECK)) {
   3345         BCM_IF_ERROR_RETURN(
   3346                 _bcm_esw_l3_gport_construct(unit, defip.defip_source_port_tgid,
   3347                     defip.defip_source_modid,
   3348                     defip.defip_source_port_tgid,
   3349                     defip.defip_source_ts ? BCM_L3_TGID : 0,
   3350                     &(route->l3a_expected_src_gport)));
   3351     }
   3352 
   3353     return BCM_E_NONE;
   3354 }
   3355 
   3356 /*
   3357  * Function:
   3358  *      bcm_l3_subnet_route_find
   3359  * Purpose:
   3360  *      Get a Longest Prefix Matched entry from the DEF IP table for a subnet.
   3361  * Parameters:
   3362  *      unit  - SOC device unit number
   3363  *      input - (IN) Given subnet.
   3364  *      route - (OUT)Pointer to bcm_l3_route_t for return information.
   3365  * Returns:
   3366  *      BCM_E_XXX
   3367  * Notes:
   3368  *    - Application has to pass IP address, IP mask for the network, and 
   3369  *    - flag for IP version.
   3370  */
   3371 int
   3372 bcm_esw_l3_subnet_route_find(int unit, bcm_l3_route_t *input, 
   3373                              bcm_l3_route_t *route)
   3374 {
   3375     int max_prefix_length;
   3376     _bcm_defip_cfg_t defip;
   3377     int rv;
   3378 
   3379     L3_INIT(unit);
   3380 
   3381     if (NULL == input || NULL == route) {
   3382         return BCM_E_PARAM;
   3383     }
   3384 
   3385     if ((input->l3a_vrf > SOC_VRF_MAX(unit)) || 
   3386         (input->l3a_vrf < BCM_L3_VRF_GLOBAL)) {
   3387         return (BCM_E_PARAM);
   3388     }
   3389 
   3390     /*  Check that device supports ipv6. */
   3391     if (BCM_L3_NO_IP6_SUPPORT(unit, input->l3a_flags)) {
   3392         return (BCM_E_UNAVAIL);
   3393     }
   3394 
   3395     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   3396     defip.defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   3397     defip.defip_flags = input->l3a_flags;
   3398     defip.defip_vrf   = input->l3a_vrf;
   3399 
   3400     L3_LOCK(unit);
   3401     if (input->l3a_flags & BCM_L3_IP6) {
   3402         bcm_ip6_t mask;
   3403         max_prefix_length = 128;
   3404         sal_memcpy(defip.defip_ip6_addr, input->l3a_ip6_net, BCM_IP6_ADDRLEN);
   3405         sal_memcpy(mask, input->l3a_ip6_mask, BCM_IP6_ADDRLEN);
   3406         defip.defip_sub_len = bcm_ip6_mask_length(mask);
   3407         if (defip.defip_sub_len > max_prefix_length) {
   3408             L3_UNLOCK(unit);
   3409             return (BCM_E_PARAM);
   3410         } 
   3411         rv = bcm_xgs3_defip_find(unit, &defip);
   3412     } else {
   3413         defip.defip_ip_addr = input->l3a_subnet & input->l3a_ip_mask;
   3414         defip.defip_sub_len = bcm_ip_mask_length(input->l3a_ip_mask);
   3415         rv = bcm_xgs3_defip_find(unit, &defip);
   3416     }
   3417 
   3418     L3_UNLOCK(unit);
   3419     if (rv < 0) {
   3420         return rv;
   3421     }
   3422 
   3423     sal_memcpy(route->l3a_nexthop_mac, defip.defip_mac_addr,
   3424                sizeof(bcm_mac_t));
   3425     route->l3a_nexthop_ip = defip.defip_nexthop_ip;
   3426     route->l3a_intf = defip.defip_intf;
   3427     route->l3a_port_tgid = defip.defip_port_tgid;
   3428     route->l3a_modid = defip.defip_modid;
   3429     route->l3a_lookup_class = defip.defip_lookup_class;
   3430     route->l3a_flags = defip.defip_flags;
   3431     route->l3a_flags2 = defip.defip_flags2;
   3432     route->l3a_mpls_label = defip.defip_mpls_label;
   3433     route->l3a_tunnel_option = (uint32)defip.defip_index;
   3434     route->l3a_vrf = defip.defip_vrf;
   3435     route->l3a_expected_intf = defip.defip_expected_intf;
   3436     route->l3a_rp = defip.defip_l3a_rp;
   3437     route->l3a_mc_group = defip.defip_mc_group;
   3438     route->l3a_ipmc_flags = defip.defip_ipmc_flags;
   3439     if (defip.defip_flags & BCM_L3_IPMC ) {
   3440         _BCM_MULTICAST_GROUP_SET(route->l3a_mc_group, _BCM_MULTICAST_TYPE_L3,
   3441                                  route->l3a_mc_group);
   3442     }
   3443     if (defip.defip_flags & BCM_L3_IP6) {
   3444         sal_memcpy(route->l3a_ip6_net, defip.defip_ip6_addr, BCM_IP6_ADDRLEN);
   3445         bcm_ip6_mask_create(route->l3a_ip6_mask, defip.defip_sub_len);
   3446     } else {
   3447         route->l3a_subnet = defip.defip_ip_addr;
   3448         route->l3a_ip_mask = bcm_ip_mask_create(defip.defip_sub_len);
   3449     }
   3450 
   3451     BCM_IF_ERROR_RETURN(
   3452         _bcm_esw_l3_gport_construct(unit, route->l3a_port_tgid, route->l3a_modid, 
   3453                                     route->l3a_port_tgid, route->l3a_flags, 
   3454                                     &(route->l3a_port_tgid)));
   3455     return BCM_E_NONE;
   3456 }
   3457 
   3458 /*
   3459  * Function:
   3460  *      bcm_esw_l3_route_multipath_get
   3461  * Purpose:
   3462  *      Get all paths for a route, useful for ECMP route,
   3463  *      For non-ECMP route, there is only one path returned.
   3464  * Parameters:
   3465  *      unit       - (IN) SOC device unit number
   3466  *      the_route  - (IN) route's net/mask
   3467  *      path_array - (OUT) Array of all ECMP paths
   3468  *      path_count - (OUT) Actual number of ECMP paths
   3469  * Returns:
   3470  *      BCM_E_XXX
   3471  */
   3472 
   3473 int
   3474 bcm_esw_l3_route_multipath_get(int unit, bcm_l3_route_t *the_route,
   3475        bcm_l3_route_t *path_array, int max_path, int *path_count)
   3476 {
   3477     int max_prefix_length;
   3478     _bcm_defip_cfg_t defip;
   3479     int rv;
   3480 
   3481     L3_INIT(unit);
   3482 
   3483     if ((NULL == the_route) || (max_path < 1)) {
   3484         return BCM_E_PARAM;
   3485     }
   3486 
   3487     if ((the_route->l3a_vrf > SOC_VRF_MAX(unit)) || 
   3488         (the_route->l3a_vrf < BCM_L3_VRF_GLOBAL)) {
   3489         return (BCM_E_PARAM);
   3490     }
   3491 
   3492     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   3493     defip.defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   3494     defip.defip_flags = the_route->l3a_flags;
   3495     defip.defip_vrf = the_route->l3a_vrf;
   3496 
   3497     L3_LOCK(unit);
   3498     if (the_route->l3a_flags & BCM_L3_IP6) {
   3499         max_prefix_length = 
   3500             soc_feature(unit, soc_feature_lpm_prefix_length_max_128) ? 128 : 64;
   3501         sal_memcpy(defip.defip_ip6_addr, the_route->l3a_ip6_net, BCM_IP6_ADDRLEN);
   3502         defip.defip_sub_len    = bcm_ip6_mask_length(the_route->l3a_ip6_mask);
   3503         if (defip.defip_sub_len > max_prefix_length) {
   3504             L3_UNLOCK(unit);
   3505             return (BCM_E_PARAM);
   3506         } 
   3507         rv = mbcm_driver[unit]->mbcm_ip6_defip_ecmp_get_all(unit, &defip,
   3508                                  path_array, max_path, path_count);
   3509     } else {
   3510         defip.defip_ip_addr = the_route->l3a_subnet & the_route->l3a_ip_mask;
   3511         defip.defip_sub_len = bcm_ip_mask_length(the_route->l3a_ip_mask);
   3512         rv = mbcm_driver[unit]->mbcm_ip4_defip_ecmp_get_all(unit, &defip,
   3513                                  path_array, max_path, path_count);
   3514     }
   3515     L3_UNLOCK(unit);
   3516     return (rv);
   3517 }
   3518 
   3519 /*
   3520  * Function:
   3521  *      bcm_esw_l3_route_delete_by_interface
   3522  * Purpose:
   3523  *      Delete all entries from the DEF IP table which have
   3524  *      L3 interface number intf.
   3525  * Parameters:
   3526  *      unit - SOC device unit number
   3527  *      intf - The L3 interface number
   3528  * Returns:
   3529  *      BCM_E_NONE              Success
   3530  *      BCM_E_UNIT              Illegal unit number
   3531  *      BCM_E_INIT              Unit Not initialized yet
   3532  * Notes:
   3533  *   - Flag set to BCM_L3_IP6 for IPv6, default is IPv4
   3534  *   - Flag set to BCM_L3_NEGATE to delete all host entries
   3535  *     that do NOT match the L3 interface.
   3536  */
   3537 
   3538 int
   3539 bcm_esw_l3_route_delete_by_interface(int unit, bcm_l3_route_t *info)
   3540 {
   3541     int rv;
   3542     _bcm_defip_cfg_t defip;
   3543 
   3544     L3_INIT(unit);
   3545 
   3546     if (NULL == info) {
   3547         return (BCM_E_PARAM);
   3548     }
   3549 
   3550     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   3551     defip.defip_intf = info->l3a_intf;
   3552     defip.defip_flags = info->l3a_flags;
   3553 
   3554     L3_LOCK(unit);
   3555 
   3556     if (info->l3a_flags & BCM_L3_NEGATE) {
   3557         rv = mbcm_driver[unit]->mbcm_defip_delete_intf(unit, &defip, 1);
   3558     } else {
   3559         rv = mbcm_driver[unit]->mbcm_defip_delete_intf(unit, &defip, 0);
   3560     }
   3561 
   3562     L3_UNLOCK(unit);
   3563 
   3564     return (rv);
   3565 }
   3566 
   3567 /*
   3568  * Function:
   3569  *      bcm_esw_l3_route_delete_all
   3570  * Purpose:
   3571  *      Remove all defip entries for a specified unit.
   3572  * Parameters:
   3573  *      unit - StrataSwitch Unit #.
   3574  * Returns:
   3575  *      BCM_E_NONE - delete successful.
   3576  *      BCM_E_XXX - delete failed.
   3577  */
   3578 
   3579 int
   3580 bcm_esw_l3_route_delete_all(int unit, bcm_l3_route_t *info)
   3581 {
   3582     int rv;
   3583     L3_INIT(unit);
   3584 
   3585     L3_LOCK(unit);
   3586 
   3587     rv = mbcm_driver[unit]->mbcm_defip_delete_all(unit);
   3588 
   3589     L3_UNLOCK(unit);
   3590 
   3591     return (rv);
   3592 }
   3593 
   3594 /*
   3595  * Function:
   3596  *      bcm_esw_l3_route_traverse
   3597  * Purpose:
   3598  *      Find entries from the DEF IP table.
   3599  * Parameters:
   3600  *      unit - SOC device unit number
   3601  *      flags - BCM_L3_IP6
   3602  *      start - Starting point of interest.
   3603  *      end - Ending point of interest.
   3604  *      trav_fn - User callback function, called once per defip entry.
   3605  *      user_data - User supplied cookie used in parameter in callback function
   3606  * Returns:
   3607  *      BCM_E_XXX
   3608  * Notes:
   3609  *      The hit returned may be either L3SH or L3DH or Both
   3610  */
   3611 int
   3612 bcm_esw_l3_route_traverse(int unit, uint32 flags,
   3613                           uint32 start, uint32 end,
   3614                           bcm_l3_route_traverse_cb trav_fn, void *user_data)
   3615 {
   3616     int rv;
   3617 
   3618     L3_INIT(unit);
   3619     L3_LOCK(unit);
   3620 
   3621     /*  Check that device supports ipv6. */
   3622     if (BCM_L3_NO_IP6_SUPPORT(unit, flags)) {
   3623         L3_UNLOCK(unit);
   3624         return (BCM_E_UNAVAIL);
   3625     }
   3626 
   3627     if (flags & BCM_L3_IP6) {
   3628         rv = mbcm_driver[unit]->mbcm_ip6_defip_traverse(unit,
   3629                                 start, end, trav_fn, user_data);
   3630     } else {
   3631         rv = mbcm_driver[unit]->mbcm_ip4_defip_traverse(unit,
   3632                                 start, end, trav_fn, user_data);
   3633     }
   3634 
   3635     L3_UNLOCK(unit);
   3636     return (rv);
   3637 }
   3638 
   3639 /* to be deprecated */
   3640 int
   3641 bcm_esw_l3_defip_traverse(int unit, bcm_l3_route_traverse_cb trav_fn,
   3642                       uint32 start, uint32 end)
   3643 {
   3644     int rv;
   3645     L3_INIT(unit);
   3646 
   3647     if (start > end) {
   3648         return (BCM_E_PARAM);
   3649     }
   3650 
   3651     L3_LOCK(unit);
   3652 
   3653     rv  = mbcm_driver[unit]->mbcm_ip4_defip_traverse(unit,
   3654                                      start, end, trav_fn, NULL);
   3655     L3_UNLOCK(unit);
   3656     return (rv);
   3657 }
   3658 
   3659 /*
   3660  * Function:
   3661  *      bcm_esw_l3_route_age
   3662  * Purpose:
   3663  *      Age on DEFIP routing table, clear HIT bit of entry if set
   3664  * Parameters:
   3665  *      unit       - (IN) BCM device unit number.
   3666  *      age_out    - (IN) Call back routine.
   3667  *      user_data  - (IN) User provided cookie for callback.
   3668  * Returns:
   3669  *      BCM_E_XXX
   3670  */
   3671 int
   3672 bcm_esw_l3_route_age(int unit, uint32 flags, bcm_l3_route_traverse_cb age_out,
   3673                      void *user_data)
   3674 {
   3675     int rv;
   3676     L3_INIT(unit);
   3677 
   3678     L3_LOCK(unit);
   3679 
   3680     rv = mbcm_driver[unit]->mbcm_defip_age(unit, age_out, user_data);
   3681 
   3682     L3_UNLOCK(unit);
   3683     return (rv);
   3684 }
   3685 
   3686 /*
   3687  * Function:
   3688  *    bcm_esw_l3_route_max_ecmp_set
   3689  * Purpose:
   3690  *    Set the maximum ECMP paths allowed for a route
   3691  *    for chips that supports ECMP
   3692  * Parameters:
   3693  *    unit - SOC device unit number
   3694  *    max  - MAX number of paths for ECMP (number must be power of 2)
   3695  * Returns:
   3696  *      BCM_E_XXX
   3697  * Note:
   3698  *    There is a hardware limit on the number of ECMP paths,
   3699  *    for bcm_ip_mask_length it is 32, BCM5665/50/73/74 is 8.
   3700  *    The above parameter must be within the hardware limit.
   3701  *    This function can be called before ECMP routes are added,
   3702  *    normally at the beginning.  Once ECMP routes exist, cannot be reset.
   3703  */
   3704 int
   3705 bcm_esw_l3_route_max_ecmp_set(int unit, int max)
   3706 {
   3707     int rv = BCM_E_UNAVAIL;
   3708     L3_INIT(unit);
   3709     L3_LOCK(unit);
   3710 
   3711 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   3712     if (SOC_IS_XGS3_SWITCH(unit)) {
   3713         rv = bcm_xgs3_max_ecmp_set(unit, max);
   3714     }
   3715 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   3716 
   3717     L3_UNLOCK(unit);
   3718     return (rv);
   3719 }
   3720 
   3721 /*
   3722  * Function:
   3723  *    bcm_esw_l3_route_max_ecmp_get
   3724  * Purpose:
   3725  *    Get the maximum ECMP paths allowed for a route
   3726  *    for chips that supports ECMP
   3727  * Parameters:
   3728  *    unit - SOC device unit number
   3729  *    max  - (OUT)MAX number of paths for ECMP (number must be power of 2)
   3730  * Returns:
   3731  *      BCM_E_XXX
   3732  */
   3733 int
   3734 bcm_esw_l3_route_max_ecmp_get(int unit, int *max)
   3735 {
   3736     int rv = BCM_E_UNAVAIL;
   3737     L3_INIT(unit);
   3738 
   3739     if (NULL == max) {
   3740         return (BCM_E_PARAM);
   3741     }
   3742 
   3743     *max = 0;
   3744 
   3745     L3_LOCK(unit);
   3746 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   3747     if (SOC_IS_XGS3_SWITCH(unit)) {
   3748         rv = bcm_xgs3_max_ecmp_get(unit, max);
   3749     }
   3750 #endif   /* BCM_XGS3_SWITCH_SUPPORT */
   3751     L3_UNLOCK(unit);
   3752     return (rv);
   3753 }
   3754 
   3755 /*
   3756  * Function:
   3757  *      bcm_l3_cleanup
   3758  * Purpose:
   3759  *      Detach L3 function for a unit, clean up all tables and data structures
   3760  * Parameters:
   3761  *      unit - StrataSwitch Unit #.
   3762  * Returns:
   3763  *      BCM_E_NONE - detach successful.
   3764  *      BCM_E_XXX - detach failed.
   3765  */
   3766 
   3767 int
   3768 bcm_esw_l3_cleanup(int unit)
   3769 {
   3770     int rv = BCM_E_NONE;
   3771 
   3772     if ((0 == l3_internal_initialized) || 
   3773         (0 == _bcm_l3_bk_info[unit].l3_initialized)) {
   3774         if (NULL != mbcm_driver[unit]) {
   3775             rv = mbcm_driver[unit]->mbcm_l3_tables_cleanup(unit);
   3776         }
   3777         return rv;
   3778     }
   3779 
   3780     L3_LOCK(unit);
   3781 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   3782     if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) {
   3783         rv = soc_esw_ecmp_protected_detach(unit);
   3784         if (BCM_FAILURE(rv)) {
   3785             L3_UNLOCK(unit);
   3786             return (rv);
   3787         }
   3788     }
   3789 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   3790 
   3791     rv = bcm_esw_ipmc_detach(unit);
   3792     if (BCM_FAILURE(rv)) {
   3793         L3_UNLOCK(unit);
   3794         return (rv);
   3795     }
   3796     
   3797     /*no subport feature in Hurricane*/
   3798     if(!(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit) ||
   3799         SOC_IS_GREYHOUND2(unit))) {
   3800         rv = bcm_esw_subport_cleanup(unit);
   3801         if (BCM_FAILURE(rv)) {
   3802             L3_UNLOCK(unit);
   3803             return (rv);
   3804         }
   3805     }/*SOC_IS_HURRICANE*/
   3806 
   3807     rv = bcm_esw_mpls_cleanup(unit);
   3808     if (BCM_FAILURE(rv)) {
   3809         L3_UNLOCK(unit);
   3810         return (rv);
   3811     }
   3812 
   3813     if(!(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit) ||
   3814         SOC_IS_GREYHOUND2(unit))) {
   3815         rv = bcm_esw_wlan_detach(unit);
   3816         if (BCM_FAILURE(rv)) {
   3817             L3_UNLOCK(unit);
   3818             return (rv);
   3819         }
   3820     }/*SOC_IS_HURRICANE*/
   3821 
   3822     if(!(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit) ||
   3823         SOC_IS_GREYHOUND2(unit))) {
   3824         rv = bcm_esw_mim_detach(unit);
   3825         if (BCM_FAILURE(rv)) {
   3826             L3_UNLOCK(unit);
   3827             return (rv);
   3828         }
   3829     }
   3830 
   3831     if (0 == SOC_HW_ACCESS_DISABLE(unit)) {
   3832         rv = bcm_esw_l3_route_delete_all(unit, NULL);
   3833         if (BCM_FAILURE(rv)) {
   3834             L3_UNLOCK(unit);
   3835             return (rv);
   3836         }
   3837         rv = bcm_esw_l3_host_delete_all(unit, NULL);
   3838         if (BCM_FAILURE(rv)) {
   3839             L3_UNLOCK(unit);
   3840             return (rv);
   3841         }
   3842         rv = bcm_esw_l3_intf_delete_all(unit);
   3843         if (BCM_FAILURE(rv)) {
   3844             L3_UNLOCK(unit);
   3845             return (rv);
   3846         }
   3847     }
   3848 
   3849     rv = mbcm_driver[unit]->mbcm_l3_tables_cleanup(unit);
   3850     _bcm_l3_bk_info[unit].l3_initialized = 0;
   3851 
   3852     /* Clear the state which is needed in L3 subsystem */
   3853     bcmi_esw_l3_dependent_cleanup(unit);
   3854 
   3855     L3_UNLOCK(unit);
   3856 
   3857     return(rv);
   3858 }
   3859 
   3860 /*
   3861  * Function:
   3862  *      bcm_esw_l3_enable_set
   3863  * Purpose:
   3864  *      Enable/disable L3 function for a unit without clearing any L3 tables
   3865  * Parameters:
   3866  *      unit - StrataSwitch Unit #.
   3867  *      enable - 1 for enable, 0 for disable
   3868  * Returns:
   3869  *      BCM_E_XXX
   3870  */
   3871 
   3872 int
   3873 bcm_esw_l3_enable_set(int unit, int enable)
   3874 {
   3875     L3_INIT(unit);
   3876     L3_LOCK(unit);
   3877 
   3878     mbcm_driver[unit]->mbcm_l3_enable(unit, enable);
   3879 
   3880     L3_UNLOCK(unit);
   3881 
   3882     return (BCM_E_NONE);
   3883 }
   3884 
   3885 /*
   3886  * Function:
   3887  *      bcm_esw_l3_info
   3888  * Purpose:
   3889  *      Get the status of hardware.
   3890  * Parameters:
   3891  *      unit - SOC device unit number
   3892  *      l3_info - (OUT) Available hardware's L3 information.
   3893  * Returns:
   3894  *      BCM_E_XXX.
   3895  */
   3896 
   3897 int
   3898 bcm_esw_l3_info(int unit, bcm_l3_info_t *l3info)
   3899 {
   3900     int rv;
   3901     L3_INIT(unit);
   3902 
   3903     if (l3info == NULL) {
   3904         return (BCM_E_PARAM);
   3905     }
   3906     L3_LOCK(unit);
   3907 
   3908     rv = mbcm_driver[unit]->mbcm_l3_info_get(unit, l3info);
   3909 
   3910     L3_UNLOCK(unit);
   3911     return (rv);
   3912 }
   3913 
   3914 /*
   3915  * Function:
   3916  *      bcm_esw_l3_ingress_create
   3917  * Purpose:
   3918  *      Create an Ingress Interface object.
   3919  * Parameters:
   3920  *      unit    - (IN)  bcm device.
   3921  *      flags   - (IN)  BCM_L3_INGRESS_REPLACE: replace existing.
   3922  *                          BCM_L3_INGRESS_WITH_ID: intf argument is given.
   3923  *                          BCM_L3_INGRESS_GLOBAL_ROUTE : 
   3924  *                          BCM_L3_INGRESS_DSCP_TRUST : 
   3925  *      ing_intf     - (IN) Ingress Interface information.
   3926  *      intf_id    - (OUT) L3 Ingress interface id pointing to Ingress object.
   3927  *                      This is an IN argument if either BCM_L3_INGRESS_REPLACE
   3928  *                      or BCM_L3_INGRESS_WITH_ID are given in flags.
   3929  * Returns:
   3930  *      BCM_E_XXX
   3931 */
   3932 
   3933 int 
   3934 bcm_esw_l3_ingress_create(int unit, bcm_l3_ingress_t *ing_intf, bcm_if_t *intf_id)
   3935 {
   3936     int rv = BCM_E_UNAVAIL;
   3937 #if defined (BCM_TRIUMPH_SUPPORT)
   3938     if (soc_feature(unit,soc_feature_l3_ingress_interface)) {
   3939          L3_LOCK(unit);
   3940          rv =  bcm_xgs3_l3_ingress_create(unit, ing_intf, intf_id);
   3941          L3_UNLOCK(unit);
   3942     }
   3943 #endif
   3944     return rv;
   3945 }
   3946 
   3947 /*
   3948  * Function:
   3949  *      bcm_esw_l3_ingress_destroy
   3950  * Purpose:
   3951  *      Destroy an Ingress Interface object.
   3952  * Parameters:
   3953  *      unit    - (IN) bcm device.
   3954  *      intf_id    - (IN) L3 Ingress interface id pointing to Ingress object.
   3955  * Returns:
   3956  *      BCM_E_XXX
   3957  */
   3958 
   3959 int 
   3960 bcm_esw_l3_ingress_destroy(int unit, bcm_if_t intf_id)
   3961 {
   3962     int rv = BCM_E_UNAVAIL;
   3963 #if defined (BCM_TRIUMPH_SUPPORT)
   3964     if (soc_feature(unit,soc_feature_l3_ingress_interface)) {
   3965          L3_LOCK(unit);
   3966          rv =  bcm_xgs3_l3_ingress_destroy(unit, intf_id);
   3967          L3_UNLOCK(unit);
   3968 }
   3969 #endif
   3970     return rv;
   3971 }
   3972 
   3973 /*
   3974  * Function:
   3975  *      bcm_esw_l3_ingress_find
   3976  * Purpose:
   3977  *      Find an Ingress Interface object.     
   3978  * Parameters:
   3979  *      unit       - (IN) bcm device.
   3980  *      ing_intf        - (IN) Ingress Interface information.
   3981  *      intf_id       - (OUT) L3 Ingress interface id pointing to Ingress object.
   3982  * Returns:
   3983  *      BCM_E_XXX
   3984  */
   3985 
   3986 int 
   3987 bcm_esw_l3_ingress_find(int unit, bcm_l3_ingress_t *ing_intf, bcm_if_t *intf_id)
   3988 {
   3989     int rv = BCM_E_UNAVAIL;
   3990 #if defined (BCM_TRIUMPH_SUPPORT)
   3991     if (soc_feature(unit,soc_feature_l3_ingress_interface)) {
   3992          L3_LOCK(unit);
   3993          rv =  bcm_xgs3_l3_ingress_find(unit, ing_intf, intf_id);
   3994          L3_UNLOCK(unit);
   3995     }
   3996 #endif
   3997     return rv;
   3998 }
   3999 
   4000 /*
   4001  * Function:
   4002  *      bcm_esw_l3_ingress_get
   4003  * Purpose:
   4004  *      Get an Ingress Interface object.
   4005  * Parameters:
   4006  *      unit    - (IN) bcm device.
   4007  *      intf_id    - (IN) L3 Ingress interface id pointing to Ingress object.
   4008  *      ing_intf  - (OUT) Ingress Interface information.
   4009  * Returns:
   4010  *      BCM_E_XXX
   4011  */
   4012 
   4013 int 
   4014 bcm_esw_l3_ingress_get(int unit, bcm_if_t intf_id, bcm_l3_ingress_t *ing_intf)
   4015 {
   4016     int rv = BCM_E_UNAVAIL;
   4017 #if defined (BCM_TRIUMPH_SUPPORT)
   4018     if (soc_feature(unit,soc_feature_l3_ingress_interface)) {
   4019          L3_LOCK(unit);
   4020          rv =  bcm_xgs3_l3_ingress_get(unit, intf_id, ing_intf);
   4021          L3_UNLOCK(unit);
   4022 }
   4023 #endif
   4024     return rv;
   4025 }
   4026 
   4027 /*
   4028  * Function:
   4029  *      bcm_esw_l3_ingress_traverse
   4030  * Purpose:
   4031  *      Goes through ijgress interface objects table and runs the user callback
   4032  *      function at each valid ingress objects entry passing back the
   4033  *      information for that object.
   4034  * Parameters:
   4035  *      unit       - (IN) bcm device.
   4036  *      trav_fn    - (IN) Callback function. 
   4037  *      user_data  - (IN) User data to be passed to callback function.
   4038  * Returns:
   4039  *      BCM_E_XXX
   4040  */
   4041 int 
   4042 bcm_esw_l3_ingress_traverse(int unit, 
   4043                            bcm_l3_ingress_traverse_cb trav_fn, void *user_data)
   4044 {
   4045     int rv = BCM_E_UNAVAIL;
   4046 #if defined (BCM_TRIUMPH_SUPPORT)
   4047     if (soc_feature(unit,soc_feature_l3_ingress_interface)) {
   4048          L3_LOCK(unit);
   4049          rv =  bcm_xgs3_l3_ingress_traverse(unit, trav_fn, user_data);
   4050          L3_UNLOCK(unit);
   4051 }
   4052 #endif
   4053     return rv;
   4054 }
   4055 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4056 /*
   4057  * Function:
   4058  *      _bcm_esw_l3_egress_stat_get_table_info
   4059  * Description:
   4060  *      Provides relevant flex table information(table-name,index with
   4061  *      direction)  for given egress interface.
   4062  *
   4063  * Parameters:
   4064  *      unit             - (IN) unit number
   4065  *      intf_id          - (IN) Interface id of a egress L3 object.
   4066  *      num_of_tables    - (OUT) Number of flex counter tables
   4067  *      table_info       - (OUT) Flex counter tables information
   4068  *
   4069  * Return Value:
   4070  *      BCM_E_XXX
   4071  * Notes:
   4072  */
   4073 static 
   4074 bcm_error_t _bcm_esw_l3_egress_stat_get_table_info(
   4075            int                        unit,
   4076            bcm_if_t                   intf_id,
   4077            uint32                     *num_of_tables,
   4078            bcm_stat_flex_table_info_t *table_info)
   4079 {
   4080     bcm_l3_egress_t egr_intf={0};
   4081     int index=0;
   4082 
   4083     (*num_of_tables) = 0;
   4084     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4085         return BCM_E_UNAVAIL;
   4086     }
   4087     BCM_IF_ERROR_RETURN(bcm_esw_l3_egress_get(unit, intf_id, &egr_intf));
   4088 #ifdef BCM_TRIUMPH2_SUPPORT
   4089     if (soc_feature(unit, soc_feature_wlan) && egr_intf.encap_id > 0) {
   4090         index = intf_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) ;
   4091     } else
   4092 #endif
   4093     {
   4094         if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_id)) {
   4095             index = intf_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   4096         } else {
   4097             index = intf_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
   4098         }
   4099     }
   4100     table_info[*num_of_tables].table=EGR_L3_NEXT_HOPm;
   4101     table_info[*num_of_tables].index=index;
   4102     table_info[*num_of_tables].direction=bcmStatFlexDirectionEgress;
   4103     (*num_of_tables)++;
   4104     return BCM_E_NONE;
   4105 }
   4106 /*
   4107  * Function:
   4108  *      _bcm_esw_l3_ingress_stat_get_table_info
   4109  * Description:
   4110  *      Provides relevant flex table information(table-name,index with
   4111  *      direction)  for given ingress interface.
   4112  *
   4113  * Parameters:
   4114  *      unit             - (IN) unit number
   4115  *      intf_id          - (IN) Interface id of a ingress L3 object.
   4116  *      num_of_tables    - (OUT) Number of flex counter tables
   4117  *      table_info       - (OUT) Flex counter tables information
   4118  *
   4119  * Return Value:
   4120  *      BCM_E_XXX
   4121  * Notes:
   4122  */
   4123 static 
   4124 bcm_error_t _bcm_esw_l3_ingress_stat_get_table_info(
   4125             int                        unit,
   4126             bcm_if_t                   intf_id,
   4127             uint32                     *num_of_tables,
   4128             bcm_stat_flex_table_info_t *table_info)
   4129 {
   4130     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4131         return BCM_E_UNAVAIL;
   4132     }
   4133 
   4134     /* Input parameters check. */
   4135     if ( (intf_id < 0) ||  (intf_id >= BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) {
   4136        return (BCM_E_PARAM);
   4137     }
   4138 
   4139     if (!SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_id)) {
   4140         return (BCM_E_NOT_FOUND);
   4141     }
   4142 
   4143     table_info[*num_of_tables].table=L3_IIFm;
   4144     table_info[*num_of_tables].index=intf_id;
   4145     table_info[*num_of_tables].direction=bcmStatFlexDirectionIngress;
   4146     (*num_of_tables)++;
   4147     return BCM_E_NONE;
   4148 }
   4149 #endif
   4150 
   4151 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   4152 STATIC _bcm_flex_stat_t
   4153 _bcm_esw_l3_stat_to_flex_stat(bcm_l3_stat_t stat)
   4154 {
   4155     _bcm_flex_stat_t flex_stat;
   4156 
   4157     switch (stat) {
   4158     case bcmL3StatInPackets:
   4159         flex_stat = _bcmFlexStatIngressPackets;
   4160         break;
   4161     case bcmL3StatInBytes:
   4162         flex_stat = _bcmFlexStatIngressBytes;
   4163         break;
   4164     case bcmL3StatOutPackets:
   4165         flex_stat = _bcmFlexStatEgressPackets;
   4166         break;
   4167     case bcmL3StatOutBytes:
   4168         flex_stat = _bcmFlexStatEgressBytes;
   4169         break;
   4170     default:
   4171         flex_stat = _bcmFlexStatNum;
   4172     }
   4173 
   4174     return flex_stat;
   4175 }
   4176 #endif
   4177 
   4178 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4179 /*
   4180  * Function:
   4181  *      _bcm_esw_l3_egress_stat_attach
   4182  * Description:
   4183  *      Attach counters entries to the given L3 Egress interface
   4184  *
   4185  * Parameters:
   4186  *      unit             - (IN) unit number
   4187  *      intf_id          - (IN) Interface id of a egress L3 object.
   4188  *      stat_counter_id  - (IN) Stat Counter ID.
   4189  *
   4190  * Return Value:
   4191  *      BCM_E_XXX
   4192  * Notes:
   4193  */
   4194 STATIC bcm_error_t _bcm_esw_l3_egress_stat_attach(
   4195             int      unit, 
   4196             bcm_if_t intf_id, 
   4197             uint32   stat_counter_id)
   4198 {
   4199     soc_mem_t                  table=0;
   4200     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   4201     uint32                     pool_number=0;
   4202     uint32                     base_index=0;
   4203     bcm_stat_flex_mode_t       offset_mode=0;
   4204     bcm_stat_object_t          object=bcmStatObjectIngPort;
   4205     bcm_stat_group_mode_t      group_mode= bcmStatGroupModeSingle;
   4206     uint32                     count=0;
   4207     uint32                     actual_num_tables=0;
   4208     uint32                     num_of_tables=0;
   4209     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4210 
   4211     _bcm_esw_stat_get_counter_id_info(
   4212                   unit,
   4213                   stat_counter_id,
   4214                   &group_mode,&object,&offset_mode,&pool_number,&base_index);
   4215     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction));
   4216     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode));
   4217     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   4218                         unit,object,1,&actual_num_tables,&table,&direction));
   4219 
   4220     BCM_IF_ERROR_RETURN(_bcm_esw_l3_egress_stat_get_table_info(
   4221                         unit, intf_id,&num_of_tables,&table_info[0]));
   4222     for (count=0; count < num_of_tables ; count++) {
   4223          if ((table_info[count].direction == direction) &&
   4224              (table_info[count].table == table) ) {
   4225               if (direction == bcmStatFlexDirectionIngress) {
   4226                   return _bcm_esw_stat_flex_attach_ingress_table_counters(
   4227                          unit,
   4228                          table_info[count].table,
   4229                          table_info[count].index,
   4230                          offset_mode,
   4231                          base_index,
   4232                          pool_number);
   4233               } else {
   4234                   return _bcm_esw_stat_flex_attach_egress_table_counters(
   4235                          unit,
   4236                          table_info[count].table,
   4237                          table_info[count].index,
   4238                          0,
   4239                          offset_mode,
   4240                          base_index,
   4241                          pool_number);
   4242               } 
   4243          }
   4244     }
   4245     return BCM_E_NOT_FOUND;
   4246 }
   4247 #endif
   4248 
   4249 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   4250 STATIC int
   4251 _bcm_esw_l3_egr_flex_stat_hw_index_set(int unit, _bcm_flex_stat_handle_t fsh,
   4252                                      int fs_idx, void *cookie) 
   4253 {
   4254     bcm_if_t  intf_id;
   4255     int index;
   4256     egr_l3_next_hop_entry_t egr_nh;
   4257     int rv;
   4258     uint32 handle = _BCM_FLEX_STAT_HANDLE_WORD_GET(fsh, 0);   
   4259     bcm_l3_egress_t egr_intf={0};
   4260     int entry_type;
   4261     soc_mem_info_t *memp;
   4262     soc_field_t ctr_field;
   4263     soc_field_t use_ctr_field;
   4264 
   4265     intf_id = (bcm_if_t)handle;
   4266     rv = BCM_E_NONE;
   4267 
   4268     BCM_IF_ERROR_RETURN(bcm_esw_l3_egress_get(unit, intf_id, &egr_intf));
   4269 
   4270     if (soc_feature(unit, soc_feature_wlan) && egr_intf.encap_id > 0) {
   4271         index = intf_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   4272     } else {
   4273         index = intf_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
   4274     }
   4275 
   4276     rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,index,&egr_nh);
   4277 
   4278     if (BCM_SUCCESS(rv)) {
   4279         entry_type = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   4280                            ENTRY_TYPEf);
   4281         memp = &SOC_MEM_INFO(unit, EGR_L3_NEXT_HOPm);
   4282         if (memp->views != NULL) {
   4283             if (sal_strcmp(memp->views[entry_type],"L3") == 0) {
   4284                 ctr_field = L3__VINTF_CTR_IDXf;
   4285                 use_ctr_field = L3__USE_VINTF_CTR_IDXf; 
   4286             } else if (sal_strcmp(memp->views[entry_type],"PROXY") == 0) {
   4287                 ctr_field = PROXY__VINTF_CTR_IDXf;
   4288                 use_ctr_field = PROXY__USE_VINTF_CTR_IDXf; 
   4289             } else if (sal_strcmp(memp->views[entry_type],"MPLS") == 0) {
   4290                 ctr_field = MPLS__VINTF_CTR_IDXf;
   4291                 use_ctr_field = MPLS__USE_VINTF_CTR_IDXf; 
   4292             } else if (sal_strcmp(memp->views[entry_type],"SD_TAG") == 0) {
   4293                 ctr_field = SD_TAG__VINTF_CTR_IDXf;
   4294                 use_ctr_field = SD_TAG__USE_VINTF_CTR_IDXf; 
   4295             } else if (sal_strcmp(memp->views[entry_type],"MIM") == 0) {
   4296                 ctr_field = MIM__VINTF_CTR_IDXf;
   4297                 use_ctr_field = MIM__USE_VINTF_CTR_IDXf; 
   4298             } else {
   4299                 return BCM_E_UNAVAIL;
   4300             }
   4301         } else {
   4302             ctr_field = L3__VINTF_CTR_IDXf;
   4303             use_ctr_field = L3__USE_VINTF_CTR_IDXf; 
   4304         }
   4305 
   4306         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, use_ctr_field)) {
   4307             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   4308                             use_ctr_field, fs_idx > 0 ? 1 : 0);
   4309         }
   4310         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, ctr_field)) {
   4311             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   4312                             ctr_field, fs_idx);
   4313         }
   4314         rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ALL, index,
   4315                                    &egr_nh);
   4316     }
   4317     return rv;
   4318 }
   4319 
   4320 STATIC int
   4321 _bcm_esw_l3_ingr_flex_stat_hw_index_set(int unit, _bcm_flex_stat_handle_t fsh,
   4322                                      int fs_idx, void *cookie)
   4323 {
   4324     int index;
   4325     int rv;
   4326     uint32 handle = _BCM_FLEX_STAT_HANDLE_WORD_GET(fsh, 0);
   4327     iif_entry_t       l3iif_entry;
   4328 
   4329     index = (int)handle;  /* interface_id */
   4330     rv = BCM_E_NONE;
   4331 
   4332     rv = soc_mem_read(unit, L3_IIFm, MEM_BLOCK_ANY,index,&l3iif_entry);
   4333 
   4334     if (BCM_SUCCESS(rv)) {
   4335         if (soc_mem_field_valid(unit, L3_IIFm,
   4336                                     USE_VINTF_CTR_IDXf)) {
   4337             soc_mem_field32_set(unit, L3_IIFm, &l3iif_entry,
   4338                             USE_VINTF_CTR_IDXf,
   4339                             fs_idx > 0 ? 1 : 0);
   4340         }
   4341         soc_mem_field32_set(unit, L3_IIFm, &l3iif_entry,
   4342                             VINTF_CTR_IDXf, fs_idx);
   4343         rv = soc_mem_write(unit, L3_IIFm, MEM_BLOCK_ALL, index,
   4344                                    &l3iif_entry);
   4345     }
   4346     return rv;
   4347 }
   4348 
   4349 #endif
   4350 
   4351 /*
   4352  * Function:
   4353  *      bcm_esw_l3_egress_stat_attach
   4354  * Description:
   4355  *      Attach counters entries to the given L3 Egress interface
   4356  *
   4357  * Parameters:
   4358  *      unit             - (IN) unit number
   4359  *      intf_id          - (IN) Interface id of a egress L3 object.
   4360  *      stat_counter_id  - (IN) Stat Counter ID.
   4361  *
   4362  * Return Value:
   4363  *      BCM_E_XXX
   4364  * Notes:
   4365  */
   4366 int bcm_esw_l3_egress_stat_attach(
   4367             int      unit,
   4368             bcm_if_t intf_id,
   4369             uint32   stat_counter_id)
   4370 {
   4371 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4372     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4373         return _bcm_esw_l3_egress_stat_attach(unit,intf_id,stat_counter_id);
   4374     } else
   4375 #endif
   4376 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   4377     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   4378         _bcm_flex_stat_type_t fs_type;
   4379         uint32 fs_inx;
   4380         uint32 flag;
   4381         int rv;
   4382 
   4383         fs_type = _BCM_FLEX_STAT_TYPE(stat_counter_id);
   4384         fs_inx  = _BCM_FLEX_STAT_COUNT_INX(stat_counter_id);
   4385 
   4386         if (!((fs_type == _bcmFlexStatTypeEgressGport) && fs_inx)) {
   4387             return BCM_E_PARAM;
   4388         }
   4389 
   4390         flag = _BCM_FLEX_STAT_HW_EGRESS;
   4391 
   4392         rv = _bcm_esw_flex_stat_enable_set(unit, fs_type,
   4393                              _bcm_esw_l3_egr_flex_stat_hw_index_set,
   4394                                       INT_TO_PTR(flag),
   4395                                       intf_id, TRUE,fs_inx);
   4396         return rv;
   4397     } else
   4398 #endif
   4399     {
   4400         return BCM_E_UNAVAIL;
   4401     }
   4402 }
   4403 
   4404 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4405 /*
   4406  * Function:
   4407  *      _bcm_esw_l3_egress_stat_detach
   4408  * Description:
   4409  *      Detach  counters entries to the given L3 Egress interface. 
   4410  *
   4411  * Parameters:
   4412  *      unit             - (IN) unit number
   4413  *      intf_id          - (IN) Interface id of a egress L3 object.
   4414  *      stat_counter_id  - (IN) Stat Counter ID.
   4415  *
   4416  * Return Value:
   4417  *      BCM_E_XXX
   4418  * Notes:
   4419  */
   4420 STATIC
   4421 bcm_error_t _bcm_esw_l3_egress_stat_detach(
   4422             int      unit, 
   4423             bcm_if_t intf_id)
   4424 {
   4425     uint32                     count=0;
   4426     uint32                     num_of_tables=0;
   4427     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4428     bcm_error_t                rv = BCM_E_NONE;
   4429     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NOT_FOUND};
   4430     uint32                     flag[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {0};
   4431 
   4432     BCM_IF_ERROR_RETURN(_bcm_esw_l3_egress_stat_get_table_info(
   4433                    unit, intf_id,&num_of_tables,&table_info[0]));
   4434 
   4435     for (count=0; count < num_of_tables ; count++) {
   4436          if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   4437              if (0 == flag[bcmStatFlexDirectionIngress]) {
   4438                  err_code[bcmStatFlexDirectionIngress] = BCM_E_NONE;
   4439                  flag[bcmStatFlexDirectionIngress] = 1;
   4440              }
   4441              rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   4442                         unit, table_info[count].table,table_info[count].index);
   4443             if (BCM_E_NONE != rv && 
   4444                 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   4445                 err_code[bcmStatFlexDirectionIngress] = rv;
   4446             }
   4447          } else {
   4448              if (0 == flag[bcmStatFlexDirectionEgress]) {
   4449                  err_code[bcmStatFlexDirectionEgress] = BCM_E_NONE;
   4450                  flag[bcmStatFlexDirectionEgress] = 1;
   4451              }
   4452              rv = _bcm_esw_stat_flex_detach_egress_table_counters(
   4453                         unit, 0, table_info[count].table,
   4454                         table_info[count].index);
   4455              if (BCM_E_NONE != rv &&
   4456                 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   4457                 err_code[bcmStatFlexDirectionEgress] = rv;
   4458              }
   4459          }
   4460     }
   4461 
   4462     BCM_STAT_FLEX_DETACH_RETURN(err_code)
   4463 }
   4464 #endif
   4465 
   4466 /*
   4467  * Function:
   4468  *      bcm_esw_l3_egress_stat_detach
   4469  * Description:
   4470  *      Detach  counters entries to the given L3 Egress interface.
   4471  *
   4472  * Parameters:
   4473  *      unit             - (IN) unit number
   4474  *      intf_id          - (IN) Interface id of a egress L3 object.
   4475  *      stat_counter_id  - (IN) Stat Counter ID.
   4476  *
   4477  * Return Value:
   4478  *      BCM_E_XXX
   4479  * Notes:
   4480  */
   4481 int bcm_esw_l3_egress_stat_detach(
   4482             int      unit,
   4483             bcm_if_t intf_id)
   4484 {
   4485 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4486     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4487         return _bcm_esw_l3_egress_stat_detach(unit,intf_id);
   4488     } else
   4489 #endif
   4490 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   4491     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   4492         uint32 flag;
   4493         int rv;
   4494 
   4495         flag = _BCM_FLEX_STAT_HW_EGRESS;
   4496 
   4497         rv = _bcm_esw_flex_stat_enable_set(unit, _bcmFlexStatTypeEgressGport,
   4498                              _bcm_esw_l3_egr_flex_stat_hw_index_set,
   4499                                       INT_TO_PTR(flag),
   4500                                       intf_id, FALSE,1);
   4501         return rv;
   4502     } else
   4503 #endif
   4504     {
   4505         return BCM_E_UNAVAIL;
   4506     }
   4507 }
   4508 
   4509 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4510 /*
   4511  * Function:
   4512  *      _bcm_esw_l3_egress_stat_counter_get
   4513  * Description:
   4514  *      Get the specified counter statistic for a L3 egress interface 
   4515  *      if sync_mode is set, sync the sw accumulated count
   4516  *      with hw count value first, else return sw count.  
   4517  *
   4518  * Parameters:
   4519  *      unit             - (IN) unit number
   4520  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   4521  *      intf_id          - (IN) Interface id of a egress L3 object.
   4522  *      stat             - (IN) Type of the counter to retrieve
   4523  *                              I.e. ingress/egress byte/packet)
   4524  *      num_entries      - (IN) Number of counter Entries
   4525  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   4526  *      counter_values   - (OUT) Pointer to counter values
   4527  *
   4528  * Return Value:
   4529  *      BCM_E_XXX
   4530  * Notes:
   4531  */
   4532 STATIC
   4533 bcm_error_t _bcm_esw_l3_egress_stat_counter_get(int              unit, 
   4534                                                 int              sync_mode, 
   4535                                                 bcm_if_t         intf_id, 
   4536                                                 bcm_l3_stat_t    stat, 
   4537                                                 uint32           num_entries, 
   4538                                                 uint32           *counter_indexes, 
   4539                                                 bcm_stat_value_t *counter_values)
   4540 {
   4541     uint32                     table_count=0;
   4542     uint32                     index_count=0;
   4543     uint32                     num_of_tables=0;
   4544     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   4545     uint32                     byte_flag=0;
   4546     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4547 
   4548     if ((stat == bcmL3StatOutPackets) ||
   4549         (stat == bcmL3StatOutBytes)) {
   4550          direction = bcmStatFlexDirectionEgress;
   4551     } else {
   4552          /* direction = bcmStatFlexDirectionIngress; */
   4553          return BCM_E_PARAM;
   4554     }
   4555     if (stat == bcmL3StatOutPackets) {
   4556         byte_flag=0;
   4557     } else {
   4558         byte_flag=1;
   4559     }
   4560     
   4561     BCM_IF_ERROR_RETURN(_bcm_esw_l3_egress_stat_get_table_info(
   4562                         unit, intf_id,&num_of_tables,&table_info[0]));
   4563 
   4564     for (table_count=0; table_count < num_of_tables ; table_count++) {
   4565          if (table_info[table_count].direction == direction) {
   4566              for (index_count=0; index_count < num_entries ; index_count++) {
   4567                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   4568                                       unit, sync_mode,
   4569                                       table_info[table_count].index,
   4570                                       table_info[table_count].table,
   4571                                       0, byte_flag,
   4572                                       counter_indexes[index_count],
   4573                                       &counter_values[index_count]));
   4574              }
   4575          }
   4576     }
   4577     return BCM_E_NONE;
   4578 }
   4579 #endif
   4580 
   4581 /*
   4582  * Function:
   4583  *      _bcm_esw_l3_egress_counter_get
   4584  * Description:
   4585  *      Get the specified counter statistic for a L3 egress interface
   4586  *      if sync_mode is set, sync the sw accumulated count
   4587  *      with hw count value first, else return sw count.  
   4588  *
   4589  * Parameters:
   4590  *      unit             - (IN) unit number
   4591  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   4592  *      intf_id          - (IN) Interface id of a egress L3 object.
   4593  *      stat             - (IN) Type of the counter to retrieve
   4594  *                              I.e. ingress/egress byte/packet)
   4595  *      num_entries      - (IN) Number of counter Entries
   4596  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   4597  *      counter_values   - (OUT) Pointer to counter values
   4598  *
   4599  * Return Value:
   4600  *      BCM_E_XXX
   4601  * Notes:
   4602  */
   4603 int _bcm_esw_l3_egress_counter_get(int              unit,
   4604                                    int              sync_mode,
   4605                                    bcm_if_t         intf_id,
   4606                                    bcm_l3_stat_t    stat,
   4607                                    uint32           num_entries,
   4608                                    uint32           *counter_indexes,
   4609                                    bcm_stat_value_t *counter_values)
   4610 {
   4611 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4612     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4613         return _bcm_esw_l3_egress_stat_counter_get(unit, sync_mode, 
   4614                                                    intf_id, 
   4615                                                    stat, num_entries, 
   4616                                                    counter_indexes,
   4617                                                    counter_values);
   4618     } else
   4619 #endif
   4620 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   4621     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   4622         uint64 val;
   4623         int rv = BCM_E_NONE;
   4624 
   4625         if (!(stat == bcmL3StatOutPackets ||
   4626               stat == bcmL3StatOutBytes)) {
   4627             return BCM_E_PARAM;
   4628         }   
   4629         rv =  _bcm_esw_flex_stat_get(unit,
   4630                                      sync_mode,
   4631                                      _bcmFlexStatTypeEgressGport,
   4632                                      intf_id,
   4633                                      _bcm_esw_l3_stat_to_flex_stat(stat), 
   4634                                      &val);
   4635 
   4636         if (stat == bcmL3StatOutPackets) {
   4637             counter_values->packets = COMPILER_64_LO(val);
   4638         } else {
   4639             COMPILER_64_SET(counter_values->bytes,
   4640                       COMPILER_64_HI(val),
   4641                       COMPILER_64_LO(val));
   4642         }
   4643         return rv;
   4644 
   4645     } else
   4646 #endif
   4647     {
   4648         return BCM_E_UNAVAIL;
   4649     }
   4650 }
   4651 
   4652 /*
   4653  * Function:
   4654  *      bcm_esw_l3_egress_stat_counter_get
   4655  * Description:
   4656  *      Get the specified counter statistic for a L3 egress interface
   4657  *
   4658  * Parameters:
   4659  *      unit             - (IN) unit number
   4660  *      intf_id          - (IN) Interface id of a egress L3 object.
   4661  *      stat             - (IN) Type of the counter to retrieve
   4662  *                              I.e. ingress/egress byte/packet)
   4663  *      num_entries      - (IN) Number of counter Entries
   4664  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   4665  *      counter_values   - (OUT) Pointer to counter values
   4666  *
   4667  * Return Value:
   4668  *      BCM_E_XXX
   4669  * Notes:
   4670  */
   4671 int bcm_esw_l3_egress_stat_counter_get(
   4672             int              unit,
   4673             bcm_if_t         intf_id,
   4674             bcm_l3_stat_t    stat,
   4675             uint32           num_entries,
   4676             uint32           *counter_indexes,
   4677             bcm_stat_value_t *counter_values)
   4678 {
   4679     return _bcm_esw_l3_egress_counter_get(unit, 0, intf_id, stat,
   4680                                         num_entries, 
   4681                                         counter_indexes,
   4682                                         counter_values);   
   4683 }
   4684 
   4685 /*
   4686  * Function:
   4687  *      bcm_esw_l3_egress_stat_counter_sync_get
   4688  * Description:
   4689  *      retrieve set of counter statistics for a L3 egress interface
   4690  *      sw accumulated counters synced with hw count.
   4691  *
   4692  * Parameters:
   4693  *      unit             - (IN) unit number
   4694  *      intf_id          - (IN) Interface id of a egress L3 object.
   4695  *      stat             - (IN) Type of the counter to retrieve
   4696  *                              I.e. ingress/egress byte/packet)
   4697  *      num_entries      - (IN) Number of counter Entries
   4698  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   4699  *      counter_values   - (OUT) Pointer to counter values
   4700  *
   4701  * Return Value:
   4702  *      BCM_E_XXX
   4703  * Notes:
   4704  */
   4705 int bcm_esw_l3_egress_stat_counter_sync_get(int              unit,
   4706                                             bcm_if_t         intf_id,
   4707                                             bcm_l3_stat_t    stat,
   4708                                             uint32           num_entries,
   4709                                             uint32           *counter_indexes,
   4710                                             bcm_stat_value_t *counter_values)
   4711 {
   4712     return _bcm_esw_l3_egress_counter_get(unit, 1, intf_id, stat,
   4713                                           num_entries, counter_indexes,
   4714                                           counter_values);   
   4715 }
   4716 
   4717 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4718 /*
   4719  * Function:
   4720  *      _bcm_esw_l3_egress_stat_counter_set
   4721  * Description:
   4722  *      Set the specified counter statistic for a L3 egress interface 
   4723  *
   4724  * Parameters:
   4725  *      unit             - (IN) unit number
   4726  *      intf_id          - (IN) Interface id of a egress L3 object.
   4727  *      stat             - (IN) Type of the counter to retrieve
   4728  *                              I.e. ingress/egress byte/packet)
   4729  *      num_entries      - (IN) Number of counter Entries
   4730  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   4731  *      counter_values   - (IN) Pointer to counter values
   4732  *
   4733  * Return Value:
   4734  *      BCM_E_XXX
   4735  * Notes:
   4736  */
   4737 STATIC
   4738 bcm_error_t _bcm_esw_l3_egress_stat_counter_set(
   4739             int              unit, 
   4740             bcm_if_t         intf_id, 
   4741             bcm_l3_stat_t    stat, 
   4742             uint32           num_entries, 
   4743             uint32           *counter_indexes, 
   4744             bcm_stat_value_t *counter_values)
   4745 {
   4746     uint32                     table_count=0;
   4747     uint32                     index_count=0;
   4748     uint32                     num_of_tables=0;
   4749     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   4750     uint32                     byte_flag=0;
   4751     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4752 
   4753     if ((stat == bcmL3StatOutPackets) ||
   4754         (stat == bcmL3StatOutBytes)) {
   4755          direction = bcmStatFlexDirectionEgress;
   4756     } else {
   4757          /* direction = bcmStatFlexDirectionIngress; */
   4758          return BCM_E_PARAM;
   4759     }
   4760     if (stat == bcmL3StatOutPackets) {
   4761         byte_flag=0;
   4762     } else {
   4763         byte_flag=1;
   4764     }
   4765 
   4766     BCM_IF_ERROR_RETURN(_bcm_esw_l3_egress_stat_get_table_info(
   4767                         unit, intf_id,&num_of_tables,&table_info[0]));
   4768 
   4769     for (table_count=0; table_count < num_of_tables ; table_count++) {
   4770          if (table_info[table_count].direction == direction) {
   4771              for (index_count=0; index_count < num_entries ; index_count++) {
   4772                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   4773                                       unit,
   4774                                       table_info[table_count].index,
   4775                                       table_info[table_count].table,
   4776                                       0, byte_flag,
   4777                                       counter_indexes[index_count],
   4778                                       &counter_values[index_count]));
   4779             }
   4780          }
   4781     }
   4782     return BCM_E_NONE;
   4783 }
   4784 #endif
   4785 
   4786 /*
   4787  * Function:
   4788  *      bcm_esw_l3_egress_stat_counter_set
   4789  * Description:
   4790  *      Set the specified counter statistic for a L3 egress interface
   4791  *
   4792  * Parameters:
   4793  *      unit             - (IN) unit number
   4794  *      intf_id          - (IN) Interface id of a egress L3 object.
   4795  *      stat             - (IN) Type of the counter to retrieve
   4796  *                              I.e. ingress/egress byte/packet)
   4797  *      num_entries      - (IN) Number of counter Entries
   4798  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   4799  *      counter_values   - (IN) Pointer to counter values
   4800  *
   4801  * Return Value:
   4802  *      BCM_E_XXX
   4803  * Notes:
   4804  */
   4805 int bcm_esw_l3_egress_stat_counter_set(
   4806             int              unit,
   4807             bcm_if_t         intf_id,
   4808             bcm_l3_stat_t    stat,
   4809             uint32           num_entries,
   4810             uint32           *counter_indexes,
   4811             bcm_stat_value_t *counter_values)
   4812 {
   4813 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4814     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4815         return _bcm_esw_l3_egress_stat_counter_set(unit,intf_id,stat,
   4816                       num_entries,counter_indexes,counter_values);
   4817     } else
   4818 #endif
   4819 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   4820     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   4821         uint64 val;
   4822         int rv = BCM_E_NONE;
   4823 
   4824         if (!(stat == bcmL3StatOutPackets ||
   4825               stat == bcmL3StatOutBytes)) {
   4826             return BCM_E_PARAM;
   4827         }
   4828 
   4829         if (stat == bcmL3StatOutPackets) {
   4830             COMPILER_64_SET(val,0,counter_values->packets);
   4831         } else {
   4832             COMPILER_64_SET(val,
   4833                       COMPILER_64_HI(counter_values->bytes),
   4834                       COMPILER_64_LO(counter_values->bytes));
   4835         }
   4836         rv =  _bcm_esw_flex_stat_set(unit,
   4837                 _bcmFlexStatTypeEgressGport,
   4838                 intf_id,
   4839                 _bcm_esw_l3_stat_to_flex_stat(stat), val);
   4840 
   4841        return rv;
   4842 
   4843     } else
   4844 #endif
   4845     {
   4846         return BCM_E_UNAVAIL;
   4847     }
   4848 }
   4849 
   4850 /*
   4851  * Function:
   4852  *      bcm_esw_l3_egress_stat_id_get
   4853  * Description:
   4854  *      Get stat counter id associated with given egress interface id
   4855  *
   4856  * Parameters:
   4857  *      unit             - (IN) unit number
   4858  *      intf_id          - (IN) Interface id of a egress L3 object.
   4859  *      stat             - (IN) Type of the counter to retrieve
   4860  *                              I.e. ingress/egress byte/packet)
   4861  *      Stat_counter_id  - (OUT) Stat Counter ID
   4862  *
   4863  * Return Value:
   4864  *      BCM_E_XXX
   4865  * Notes:
   4866  */
   4867 int bcm_esw_l3_egress_stat_id_get(
   4868             int             unit,
   4869             bcm_if_t        intf_id, 
   4870             bcm_l3_stat_t   stat, 
   4871             uint32          *stat_counter_id)
   4872 {
   4873 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4874     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   4875     uint32                     num_of_tables=0;
   4876     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4877     uint32                     index=0;
   4878     uint32                     num_stat_counter_ids=0;
   4879 
   4880     if ((stat == bcmL3StatInPackets) ||
   4881         (stat == bcmL3StatInBytes)) {
   4882          direction = bcmStatFlexDirectionIngress;
   4883     } else {
   4884          direction = bcmStatFlexDirectionEgress;
   4885     }
   4886     BCM_IF_ERROR_RETURN(_bcm_esw_l3_egress_stat_get_table_info(
   4887                         unit,intf_id,&num_of_tables,&table_info[0]));
   4888     for (index=0; index < num_of_tables ; index++) {
   4889          if (table_info[index].direction == direction)
   4890              return _bcm_esw_stat_flex_get_counter_id(
   4891                                   unit, 1, &table_info[index],
   4892                                   &num_stat_counter_ids,stat_counter_id);
   4893     }
   4894     return BCM_E_NOT_FOUND;
   4895 #else
   4896     return BCM_E_UNAVAIL;
   4897 #endif
   4898 }
   4899 
   4900 
   4901 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4902 /*
   4903  * Function:
   4904  *      _bcm_esw_l3_ingress_stat_attach
   4905  * Description:
   4906  *      Attach counters entries to the given L3 Ingress interface
   4907  *
   4908  * Parameters:
   4909  *      unit             - (IN) unit number
   4910  *      intf_id          - (IN) Interface id of a Ingress L3 object.
   4911  *      stat_counter_id  - (IN) Stat Counter ID.
   4912  *
   4913  * Return Value:
   4914  *      BCM_E_XXX
   4915  * Notes:
   4916  */
   4917 STATIC
   4918 bcm_error_t _bcm_esw_l3_ingress_stat_attach(
   4919             int      unit, 
   4920             bcm_if_t intf_id, 
   4921             uint32   stat_counter_id)
   4922 {
   4923     soc_mem_t                  table=0;
   4924     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   4925     uint32                     pool_number=0;
   4926     uint32                     base_index=0;
   4927     bcm_stat_flex_mode_t       offset_mode=0;
   4928     bcm_stat_object_t          object=bcmStatObjectIngPort;
   4929     bcm_stat_group_mode_t      group_mode= bcmStatGroupModeSingle;
   4930     uint32                     count=0;
   4931     uint32                     actual_num_tables=0;
   4932     uint32                     num_of_tables=0;
   4933     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4934 
   4935     _bcm_esw_stat_get_counter_id_info(
   4936                   unit, stat_counter_id,
   4937                   &group_mode,&object,&offset_mode,&pool_number,&base_index);
   4938     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction));
   4939     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode));
   4940     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   4941                         unit,object,1,&actual_num_tables,&table,&direction));
   4942 
   4943     BCM_IF_ERROR_RETURN(_bcm_esw_l3_ingress_stat_get_table_info(
   4944                         unit, intf_id,&num_of_tables,&table_info[0]));
   4945     for (count=0; count < num_of_tables ; count++) {
   4946          if ((table_info[count].direction == direction) &&
   4947              (table_info[count].table == table) ) {
   4948               if (direction == bcmStatFlexDirectionIngress) {
   4949                   return _bcm_esw_stat_flex_attach_ingress_table_counters(
   4950                          unit,
   4951                          table_info[count].table,
   4952                          table_info[count].index,
   4953                          offset_mode,
   4954                          base_index,
   4955                          pool_number);
   4956               } else {
   4957                   return _bcm_esw_stat_flex_attach_egress_table_counters(
   4958                          unit,
   4959                          table_info[count].table,
   4960                          table_info[count].index,
   4961                          0,
   4962                          offset_mode,
   4963                          base_index,
   4964                          pool_number);
   4965               } 
   4966          }
   4967     }
   4968     return BCM_E_NOT_FOUND;
   4969 }
   4970 #endif
   4971 
   4972 /*
   4973  * Function:
   4974  *      bcm_esw_l3_ingress_stat_attach
   4975  * Description:
   4976  *      Attach counters entries to the given L3 Ingress interface
   4977  *
   4978  * Parameters:
   4979  *      unit             - (IN) unit number
   4980  *      intf_id          - (IN) Interface id of a Ingress L3 object.
   4981  *      stat_counter_id  - (IN) Stat Counter ID.  *
   4982  * Return Value:
   4983  *      BCM_E_XXX
   4984  * Notes:
   4985  */
   4986 int bcm_esw_l3_ingress_stat_attach(
   4987             int      unit,
   4988             bcm_if_t intf_id,
   4989             uint32   stat_counter_id)
   4990 {
   4991 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   4992     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4993         return _bcm_esw_l3_ingress_stat_attach(unit,intf_id,stat_counter_id);
   4994     } else
   4995 #endif
   4996 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   4997     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   4998         _bcm_flex_stat_type_t fs_type;
   4999         uint32 fs_inx;
   5000         uint32 flag;
   5001         int rv;
   5002 
   5003         /* Input parameters check. */
   5004         if ( (intf_id < 0) ||  (intf_id >= BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) {
   5005            return (BCM_E_PARAM);
   5006         }
   5007 
   5008         if (!SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_id)) {
   5009             return (BCM_E_NOT_FOUND);
   5010         }
   5011 
   5012         fs_type = _BCM_FLEX_STAT_TYPE(stat_counter_id);
   5013         fs_inx  = _BCM_FLEX_STAT_COUNT_INX(stat_counter_id);
   5014 
   5015         if (!((fs_type == _bcmFlexStatTypeGport) && fs_inx)) {
   5016             return BCM_E_PARAM;
   5017         }
   5018 
   5019         flag = _BCM_FLEX_STAT_HW_INGRESS;
   5020 
   5021         rv = _bcm_esw_flex_stat_enable_set(unit, fs_type,
   5022                              _bcm_esw_l3_ingr_flex_stat_hw_index_set,
   5023                                       INT_TO_PTR(flag),
   5024                                       intf_id, TRUE,fs_inx);
   5025         return rv;
   5026     } else
   5027 #endif
   5028     {
   5029         return BCM_E_UNAVAIL;
   5030     }
   5031 
   5032 }
   5033 
   5034 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   5035 /*
   5036  * Function:
   5037  *      _bcm_esw_l3_ingress_stat_detach
   5038  * Description:
   5039  *      Detach  counters entries to the given L3 Ingress interface. 
   5040  *
   5041  * Parameters:
   5042  *      unit             - (IN) unit number
   5043  *      intf_id          - (IN) Interface id of a egress L3 object.
   5044  *      stat_counter_id  - (IN) Stat Counter ID.
   5045  *
   5046  * Return Value:
   5047  *      BCM_E_XXX
   5048  * Notes:
   5049  */
   5050 STATIC
   5051 bcm_error_t _bcm_esw_l3_ingress_stat_detach(
   5052             int      unit, 
   5053             bcm_if_t intf_id)
   5054 {
   5055     uint32                     count=0;
   5056     uint32                     num_of_tables=0;
   5057     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   5058     bcm_error_t                rv = BCM_E_NONE;
   5059     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE};
   5060 
   5061     BCM_IF_ERROR_RETURN(_bcm_esw_l3_ingress_stat_get_table_info(
   5062                         unit, intf_id,&num_of_tables,&table_info[0]));
   5063 
   5064     for (count=0; count < num_of_tables ; count++) {
   5065         if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   5066             rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   5067                         unit, table_info[count].table, table_info[count].index);
   5068             if (BCM_E_NONE != rv &&
   5069                 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   5070                 err_code[bcmStatFlexDirectionIngress] = rv;
   5071             }
   5072         } else {
   5073             rv = _bcm_esw_stat_flex_detach_egress_table_counters(
   5074                         unit, 0, table_info[count].table,
   5075                         table_info[count].index);
   5076             if (BCM_E_NONE != rv &&
   5077                 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   5078                 err_code[bcmStatFlexDirectionEgress] = rv;
   5079             }
   5080         }
   5081     }
   5082 
   5083     BCM_STAT_FLEX_DETACH_RETURN(err_code)
   5084 }
   5085 #endif
   5086 
   5087 /*
   5088  * Function:
   5089  *      bcm_esw_l3_ingress_stat_detach
   5090  * Description:
   5091  *      Detach  counters entries to the given L3 Ingress interface.
   5092  *
   5093  * Parameters:
   5094  *      unit             - (IN) unit number
   5095  *      intf_id          - (IN) Interface id of a egress L3 object.
   5096  *      stat_counter_id  - (IN) Stat Counter ID.
   5097  *
   5098  * Return Value:
   5099  *      BCM_E_XXX
   5100  * Notes:
   5101  */
   5102 
   5103 int bcm_esw_l3_ingress_stat_detach(
   5104             int      unit,
   5105             bcm_if_t intf_id)
   5106 {
   5107 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   5108     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   5109         return _bcm_esw_l3_ingress_stat_detach(unit,intf_id);
   5110     } else
   5111 #endif
   5112 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   5113     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   5114         uint32 flag;
   5115         int rv;
   5116 
   5117         flag = _BCM_FLEX_STAT_HW_INGRESS;
   5118 
   5119         rv = _bcm_esw_flex_stat_enable_set(unit, _bcmFlexStatTypeGport,
   5120                              _bcm_esw_l3_ingr_flex_stat_hw_index_set,
   5121                                       INT_TO_PTR(flag),
   5122                                       intf_id, FALSE,1);
   5123         return rv;
   5124     } else
   5125 #endif
   5126     {
   5127         return BCM_E_UNAVAIL;
   5128     }
   5129 }
   5130 
   5131 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   5132 /*
   5133  * Function:
   5134  *      _bcm_esw_l3_ingress_stat_counter_get
   5135  * Description:
   5136  *      Get the specified counter statistic for a L3 ingress interface 
   5137  *      if sync_mode is set, sync the sw accumulated count
   5138  *      with hw count value first, else return sw count.  
   5139  *
   5140  * Parameters:
   5141  *      unit             - (IN) unit number
   5142  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   5143  *      intf_id          - (IN) Interface id of a ingress L3 object.
   5144  *      stat             - (IN) Type of the counter to retrieve
   5145  *                              I.e. ingress/egress byte/packet)
   5146  *      num_entries      - (IN) Number of counter Entries
   5147  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5148  *      counter_values   - (OUT) Pointer to counter values
   5149  *
   5150  * Return Value:
   5151  *      BCM_E_XXX
   5152  * Notes:
   5153  */
   5154 STATIC
   5155 bcm_error_t _bcm_esw_l3_ingress_stat_counter_get(
   5156             int              unit, 
   5157             int              sync_mode,
   5158             bcm_if_t         intf_id, 
   5159             bcm_l3_stat_t    stat, 
   5160             uint32           num_entries, 
   5161             uint32           *counter_indexes, 
   5162             bcm_stat_value_t *counter_values)
   5163 {
   5164     uint32                     table_count=0;
   5165     uint32                     index_count=0;
   5166     uint32                     num_of_tables=0;
   5167     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   5168     uint32                     byte_flag=0;
   5169     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   5170 
   5171     if ((stat == bcmL3StatInPackets) ||
   5172         (stat == bcmL3StatInBytes)) {
   5173          direction = bcmStatFlexDirectionIngress;
   5174     } else {
   5175          /* direction = bcmStatFlexDirectionEgress; */
   5176          return BCM_E_PARAM;
   5177     }
   5178     if (stat == bcmL3StatInPackets) {
   5179         byte_flag=0;
   5180     } else {
   5181         byte_flag=1;
   5182     }
   5183     
   5184     BCM_IF_ERROR_RETURN(_bcm_esw_l3_ingress_stat_get_table_info(
   5185                         unit, intf_id,&num_of_tables,&table_info[0]));
   5186 
   5187     for (table_count=0; table_count < num_of_tables ; table_count++) {
   5188         if (table_info[table_count].direction == direction) {
   5189             for (index_count=0; index_count < num_entries ; index_count++) {
   5190                  BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   5191                                      unit, sync_mode,
   5192                                      table_info[table_count].index,
   5193                                      table_info[table_count].table,
   5194                                      0, byte_flag,
   5195                                      counter_indexes[index_count],
   5196                                      &counter_values[index_count]));
   5197             }
   5198          }
   5199     }
   5200     return BCM_E_NONE;
   5201 }
   5202 #endif
   5203 
   5204 /*
   5205  * Function:
   5206  *      _bcm_esw_l3_ingress_flex_stat_counter_get
   5207  * Description:
   5208  *      Get the specified counter statistic for a L3 ingress interface
   5209  *      if sync_mode is set, sync the sw accumulated count
   5210  *      with hw count value first, else return sw count.  
   5211  *
   5212  * Parameters:
   5213  *      unit             - (IN) unit number
   5214  *      sync_mode        - (IN) hwcount is to be synced to sw count
   5215  *      intf_id          - (IN) Interface id of a ingress L3 object.
   5216  *      stat             - (IN) Type of the counter to retrieve
   5217  *                              I.e. ingress/egress byte/packet)
   5218  *      num_entries      - (IN) Number of counter Entries
   5219  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5220  *      counter_values   - (OUT) Pointer to counter values
   5221  *
   5222  * Return Value:
   5223  *      BCM_E_XXX
   5224  * Notes:
   5225  */
   5226 int _bcm_esw_l3_ingress_flex_stat_counter_get(
   5227             int              unit,
   5228             int              sync_mode,
   5229             bcm_if_t         intf_id,
   5230             bcm_l3_stat_t    stat,
   5231             uint32           num_entries,
   5232             uint32           *counter_indexes,
   5233             bcm_stat_value_t *counter_values)
   5234 {
   5235 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   5236     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   5237         return _bcm_esw_l3_ingress_stat_counter_get(unit, sync_mode, 
   5238                                                     intf_id, stat,
   5239                                                     num_entries, 
   5240                                                     counter_indexes, 
   5241                                                     counter_values);
   5242     } else
   5243 #endif
   5244 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   5245     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   5246         uint64 val;
   5247         int rv = BCM_E_NONE;
   5248 
   5249         if (!(stat == bcmL3StatInPackets ||
   5250               stat == bcmL3StatInBytes)) {
   5251             return BCM_E_PARAM;
   5252         }
   5253         rv =  _bcm_esw_flex_stat_get(unit, sync_mode,
   5254                                      _bcmFlexStatTypeGport,
   5255                                      intf_id,
   5256                                      _bcm_esw_l3_stat_to_flex_stat(stat),
   5257                                      &val);
   5258 
   5259         if (stat == bcmL3StatInPackets) {
   5260             counter_values->packets = COMPILER_64_LO(val);
   5261         } else {
   5262             COMPILER_64_SET(counter_values->bytes,
   5263                       COMPILER_64_HI(val),
   5264                       COMPILER_64_LO(val));
   5265         }
   5266         return rv;
   5267 
   5268     } else
   5269 #endif
   5270     {
   5271         return BCM_E_UNAVAIL;
   5272     }
   5273 }
   5274 
   5275 
   5276 /*
   5277  * Function:
   5278  *      bcm_esw_l3_ingress_stat_counter_get
   5279  * Description:
   5280  *      Get the specified counter statistic for a L3 ingress interface
   5281  *
   5282  * Parameters:
   5283  *      unit             - (IN) unit number
   5284  *      intf_id          - (IN) Interface id of a ingress L3 object.
   5285  *      stat             - (IN) Type of the counter to retrieve
   5286  *                              I.e. ingress/egress byte/packet)
   5287  *      num_entries      - (IN) Number of counter Entries
   5288  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5289  *      counter_values   - (OUT) Pointer to counter values
   5290  *
   5291  * Return Value:
   5292  *      BCM_E_XXX
   5293  * Notes:
   5294  */
   5295 int bcm_esw_l3_ingress_stat_counter_get(
   5296              int              unit,
   5297              bcm_if_t         intf_id,
   5298              bcm_l3_stat_t    stat,
   5299              uint32           num_entries,
   5300              uint32           *counter_indexes,
   5301              bcm_stat_value_t *counter_values)
   5302 {
   5303     int rv = BCM_E_UNAVAIL;
   5304 
   5305     rv = _bcm_esw_l3_ingress_flex_stat_counter_get(unit, 0, intf_id, stat,
   5306                                                    num_entries,
   5307                                                    counter_indexes, 
   5308                                                    counter_values);
   5309 
   5310     return rv;
   5311 }
   5312 
   5313 
   5314 
   5315 /*
   5316  * Function:
   5317  *      bcm_esw_l3_ingress_stat_counter_sync_get
   5318  * Description:
   5319  *      Get the specified counter statisitic for a L3 ingress interface
   5320  *      sw accumulated counters synced with hw count.
   5321  *
   5322  * Parameters:
   5323  *      unit             - (IN) unit number
   5324  *      intf_id          - (IN) Interface id of a ingress L3 object.
   5325  *      stat             - (IN) Type of the counter to retrieve
   5326  *                              I.e. ingress/egress byte/packet)
   5327  *      num_entries      - (IN) Number of counter Entries
   5328  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5329  *      counter_values   - (OUT) Pointer to counter values
   5330  *
   5331  * Return Value:
   5332  *      BCM_E_XXX
   5333  * Notes:
   5334  */
   5335 int bcm_esw_l3_ingress_stat_counter_sync_get(
   5336              int              unit,
   5337              bcm_if_t         intf_id,
   5338              bcm_l3_stat_t    stat,
   5339              uint32           num_entries,
   5340              uint32           *counter_indexes,
   5341              bcm_stat_value_t *counter_values)
   5342 {
   5343     int rv = BCM_E_UNAVAIL;
   5344 
   5345     rv = _bcm_esw_l3_ingress_flex_stat_counter_get(unit, 1, intf_id, stat,
   5346                                                    num_entries,
   5347                                                    counter_indexes, 
   5348                                                    counter_values);
   5349 
   5350     return rv;
   5351 }
   5352 
   5353 
   5354 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   5355 /*
   5356  * Function:
   5357  *      _bcm_esw_l3_ingress_stat_counter_set
   5358  * Description:
   5359  *      Set the specified counter statistic for a L3 ingress interface 
   5360  *
   5361  * Parameters:
   5362  *      unit             - (IN) unit number
   5363  *      intf_id          - (IN) Interface id of a egress L3 object.
   5364  *      stat             - (IN) Type of the counter to retrieve
   5365  *                              I.e. ingress/egress byte/packet)
   5366  *      num_entries      - (IN) Number of counter Entries
   5367  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5368  *      counter_values   - (IN) Pointer to counter values
   5369  *
   5370  * Return Value:
   5371  *      BCM_E_XXX
   5372  * Notes:
   5373  */
   5374 
   5375 STATIC
   5376 bcm_error_t _bcm_esw_l3_ingress_stat_counter_set(
   5377             int              unit, 
   5378             bcm_if_t         intf_id, 
   5379             bcm_l3_stat_t    stat, 
   5380             uint32           num_entries, 
   5381             uint32           *counter_indexes, 
   5382             bcm_stat_value_t *counter_values)
   5383 {
   5384     uint32                     table_count=0;
   5385     uint32                     index_count=0;
   5386     uint32                     num_of_tables=0;
   5387     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   5388     uint32                     byte_flag=0;
   5389     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   5390 
   5391     if ((stat == bcmL3StatInPackets) ||
   5392         (stat == bcmL3StatInBytes)) {
   5393          direction = bcmStatFlexDirectionIngress;
   5394     } else {
   5395          /* direction = bcmStatFlexDirectionEgress; */
   5396          return BCM_E_PARAM;
   5397     }
   5398     if (stat == bcmL3StatInPackets) {
   5399         byte_flag=0;
   5400     } else {
   5401         byte_flag=1;
   5402     }
   5403 
   5404     BCM_IF_ERROR_RETURN(_bcm_esw_l3_ingress_stat_get_table_info(
   5405                         unit, intf_id,&num_of_tables,&table_info[0]));
   5406 
   5407     for (table_count=0; table_count < num_of_tables ; table_count++) {
   5408          if (table_info[table_count].direction == direction) {
   5409              for (index_count=0; index_count < num_entries ; index_count++) {
   5410                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   5411                                       unit,
   5412                                       table_info[table_count].index,
   5413                                       table_info[table_count].table,
   5414                                       0, byte_flag,
   5415                                       counter_indexes[index_count],
   5416                                       &counter_values[index_count]));
   5417              }
   5418          }
   5419     }
   5420     return BCM_E_NONE;
   5421 }
   5422 #endif
   5423 
   5424 #ifdef BCM_KATANA_SUPPORT
   5425 /*
   5426  * Function:
   5427  *      _bcm_kt_extended_queue_config
   5428  * Description:
   5429  *      Set the cosq id and the profile index for subscriber port in 
   5430  *      ING_L3_NEXT_HOP/ING_QUEUE_MAP
   5431  * Parameters:
   5432  *      unit             - (IN) unit number
   5433  *      options          - (IN) options to create the API(REPLACE/WITH_ID..etc..).
   5434  *      flags            - (IN) Flag to indicate EH_TAG_TYPE 
   5435  *      queue_id         - (IN) CosQ id derived from gport 
   5436  *      profile_index    - (IN) value ING_QUEUE_OFFSET_MAPPING_TABLE profile 
   5437  *      intf             - (IN) L3 interface id pointing to Egress object.
   5438  *
   5439  * Return Value:
   5440  *      BCM_E_XXX
   5441  * Notes:
   5442  */
   5443 
   5444 int _bcm_kt_extended_queue_config(int unit, uint32 options, uint32 flags,
   5445                       int queue_id, int profile_index, bcm_if_t *intf) 
   5446 { 
   5447     int idx = 0;
   5448     ing_queue_map_entry_t ing_queue_entry;
   5449     ing_l3_next_hop_entry_t in_entry;
   5450     int old_queue_id = 0;
   5451     int eh_tag_type = 1;   /*EH_QUEUE_TAG contains actual COSQ value */
   5452     int mem = ING_L3_NEXT_HOPm;
   5453     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, *intf)) {
   5454         idx = *intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
   5455     } else {
   5456         idx = *intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5457     }
   5458     sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh));
   5459     /* Read ingress next hop entry. */
   5460     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &in_entry));
   5461     if (flags & BCM_L3_QUEUE_MAP) {
   5462         /*  ING_QUEUE_MAP needs to be configured */          
   5463         sal_memset(&ing_queue_entry, 0, sizeof(ing_queue_map_entry_t));
   5464         soc_mem_field32_set(unit, ING_QUEUE_MAPm, 
   5465                     &ing_queue_entry, QUEUE_SET_BASEf, queue_id);
   5466         soc_mem_field32_set(unit, ING_QUEUE_MAPm, &ing_queue_entry, 
   5467                              QUEUE_OFFSET_PROFILE_INDEXf, profile_index);
   5468         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, ING_QUEUE_MAPm, 
   5469                                             queue_id, &ing_queue_entry));
   5470         eh_tag_type = 2; /* Get BASE QUEUE from ING_QUEUE_MAP */
   5471     }
   5472     if (options & BCM_L3_REPLACE) {
   5473         if (SOC_MEM_FIELD_VALID(unit, mem, EH_QUEUE_TAGf)) {
   5474             old_queue_id = soc_mem_field32_get(unit, mem, &in_entry,
   5475                                              EH_QUEUE_TAGf);
   5476             if ((old_queue_id > 0) && (old_queue_id != queue_id)) {
   5477                 /*  ING_QUEUE_MAP needs to be reset for old entry */
   5478                 sal_memset(&ing_queue_entry, 0, sizeof(ing_queue_map_entry_t));
   5479                 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, ING_QUEUE_MAPm,
   5480                                           old_queue_id, &ing_queue_entry));
   5481             }
   5482         }
   5483         if (queue_id == 0) {
   5484             eh_tag_type = 0;  /* No HQOS */
   5485         }
   5486     }
   5487     if (SOC_MEM_FIELD_VALID(unit, mem, EH_TAG_TYPEf)) {
   5488         soc_mem_field32_set(unit, mem, &in_entry, EH_TAG_TYPEf,
   5489                             eh_tag_type & 0x3);
   5490     }
   5491     if (SOC_MEM_FIELD_VALID(unit, mem, EH_QUEUE_TAGf)) {
   5492          soc_mem_field32_set(unit, mem, &in_entry, EH_QUEUE_TAGf, queue_id);
   5493     }
   5494     /* Write ingress next hop entry. */
   5495     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, mem, idx, &in_entry));
   5496     return BCM_E_NONE;
   5497 }
   5498 /*
   5499  * Function:
   5500  *     _bcm_kt_extended_queue_qos_profile_get
   5501  * Description:
   5502  *      Get qos profile index for subscriber port.
   5503  * Parameters:
   5504  *      unit             - (IN) unit number
   5505  *      intf             - (IN) L3 interface id pointing to Egress object.
   5506  *      profile_index    - (OUT) QoS profile index for a given subscriber port.
   5507  * Return Value:
   5508  *      BCM_E_XXX
   5509  * Notes:
   5510  */
   5511 
   5512 int _bcm_kt_extended_queue_qos_profile_get(int unit,
   5513                                            bcm_if_t intf,
   5514                                            int *profile_index)
   5515 {
   5516     int idx = 0, pid = -1, queue_id = 0;
   5517     ing_queue_map_entry_t ing_queue_entry;
   5518     ing_l3_next_hop_entry_t in_entry;
   5519     int eh_tag_type = 0;
   5520     int mem = ING_L3_NEXT_HOPm;
   5521     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   5522         idx = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
   5523     } else {
   5524         idx = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5525     }
   5526     sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh));
   5527     /* Read ingress next hop entry. */
   5528     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &in_entry));
   5529     if (SOC_MEM_FIELD_VALID(unit, mem, EH_TAG_TYPEf)) {
   5530         eh_tag_type = soc_mem_field32_get(unit, mem, &in_entry, EH_TAG_TYPEf);
   5531     }
   5532     if ((eh_tag_type == 2) && SOC_MEM_FIELD_VALID(unit, mem, EH_QUEUE_TAGf)) {
   5533         queue_id = soc_mem_field32_get(unit, mem, &in_entry, EH_QUEUE_TAGf);
   5534     }
   5535 
   5536     if (queue_id) {
   5537         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, ING_QUEUE_MAPm,
   5538                                               queue_id, &ing_queue_entry));
   5539         pid = soc_mem_field32_get(unit, ING_QUEUE_MAPm, &ing_queue_entry,
   5540                                   QUEUE_OFFSET_PROFILE_INDEXf);
   5541     }
   5542     *profile_index = pid;
   5543     return BCM_E_NONE;
   5544 }
   5545 #endif /* BCM_KATANA_SUPPORT */
   5546 
   5547 /*
   5548  * Function:
   5549  *      bcm_esw_l3_ingress_stat_counter_set
   5550  * Description:
   5551  *      Set the specified counter statistic for a L3 ingress interface
   5552  *
   5553  * Parameters:
   5554  *      unit             - (IN) unit number
   5555  *      intf_id          - (IN) Interface id of a egress L3 object.
   5556  *      stat             - (IN) Type of the counter to retrieve
   5557  *                              I.e. ingress/egress byte/packet)
   5558  *      num_entries      - (IN) Number of counter Entries
   5559  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5560  *      counter_values   - (IN) Pointer to counter values
   5561  *
   5562  * Return Value:
   5563  *      BCM_E_XXX
   5564  * Notes:
   5565  */
   5566 
   5567 int bcm_esw_l3_ingress_stat_counter_set(
   5568             int              unit,
   5569             bcm_if_t         intf_id,
   5570             bcm_l3_stat_t    stat,
   5571             uint32           num_entries,
   5572             uint32           *counter_indexes,
   5573             bcm_stat_value_t *counter_values)
   5574 {
   5575 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   5576     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   5577         return _bcm_esw_l3_ingress_stat_counter_set(unit,intf_id,stat,
   5578                       num_entries,counter_indexes,counter_values);
   5579     } else
   5580 #endif
   5581 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   5582     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   5583         uint64 val;
   5584         int rv = BCM_E_NONE;
   5585 
   5586         if (!(stat == bcmL3StatInPackets ||
   5587               stat == bcmL3StatInBytes)) {
   5588             return BCM_E_PARAM;
   5589         }
   5590 
   5591         if (stat == bcmL3StatInPackets) {
   5592             COMPILER_64_SET(val,0,counter_values->packets);
   5593         } else {
   5594             COMPILER_64_SET(val,
   5595                       COMPILER_64_HI(counter_values->bytes),
   5596                       COMPILER_64_LO(counter_values->bytes));
   5597         }
   5598         rv =  _bcm_esw_flex_stat_set(unit,
   5599                 _bcmFlexStatTypeGport,
   5600                 intf_id,
   5601                 _bcm_esw_l3_stat_to_flex_stat(stat), val);
   5602        return rv;
   5603     } else
   5604 #endif
   5605     {
   5606         return BCM_E_UNAVAIL;
   5607     }
   5608 }
   5609 
   5610 /*
   5611  * Function:
   5612  *      bcm_esw_l3_egress_stat_id_get
   5613  * Description:
   5614  *      Get stat counter id associated with given ingress interface id
   5615  *
   5616  * Parameters:
   5617  *      unit             - (IN) unit number
   5618  *      intf_id          - (IN) Interface id of a ingress L3 object.
   5619  *      stat             - (IN) Type of the counter to retrieve
   5620  *                              I.e. ingress/egress byte/packet)
   5621  *      Stat_counter_id  - (OUT) Stat Counter ID
   5622  *
   5623  * Return Value:
   5624  *      BCM_E_XXX
   5625  * Notes:
   5626  */
   5627 int bcm_esw_l3_ingress_stat_id_get(
   5628             int             unit,
   5629             bcm_if_t        intf_id,
   5630             bcm_l3_stat_t stat, 
   5631             uint32          *stat_counter_id)
   5632 {
   5633 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   5634     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   5635     uint32                     num_of_tables=0;
   5636     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   5637     uint32                     index=0;
   5638     uint32                     num_stat_counter_ids=0;
   5639 
   5640     if ((stat == bcmL3StatInPackets) ||
   5641         (stat == bcmL3StatInBytes)) {
   5642          direction = bcmStatFlexDirectionIngress;
   5643     } else {
   5644          direction = bcmStatFlexDirectionEgress;
   5645     }
   5646     BCM_IF_ERROR_RETURN(_bcm_esw_l3_ingress_stat_get_table_info(
   5647                         unit,intf_id,&num_of_tables,&table_info[0]));
   5648     for (index=0; index < num_of_tables ; index++) {
   5649          if (table_info[index].direction == direction)
   5650              return _bcm_esw_stat_flex_get_counter_id(
   5651                                   unit, 1, &table_info[index],
   5652                                   &num_stat_counter_ids,stat_counter_id);
   5653     }
   5654     return BCM_E_NOT_FOUND;
   5655 #else
   5656     return BCM_E_UNAVAIL;
   5657 #endif
   5658 }
   5659 
   5660 
   5661 
   5662 
   5663 /*
   5664  * Function:
   5665  *      bcm_esw_l3_egress_create
   5666  * Purpose:
   5667  *      Create an Egress forwarding object.
   5668  * Parameters:
   5669  *      unit    - (IN)  bcm device.
   5670  *      flags   - (IN)  BCM_L3_REPLACE: replace existing.
   5671  *                      BCM_L3_WITH_ID: intf argument is given.
   5672  *      egr     - (IN) Egress forwarding destination.
   5673  *      intf    - (OUT) L3 interface id pointing to Egress object.
   5674  *                      This is an IN argument if either BCM_L3_REPLACE
   5675  *                      or BCM_L3_WITH_ID are given in flags.
   5676  * Returns:
   5677  *      BCM_E_XXX
   5678  */
   5679 int 
   5680 bcm_esw_l3_egress_create(int unit, uint32 flags, bcm_l3_egress_t *egr, 
   5681                          bcm_if_t *intf)
   5682 {
   5683     int rv = BCM_E_UNAVAIL;
   5684 #ifdef BCM_KATANA_SUPPORT
   5685     int extended_queue_id = 0;
   5686 #endif
   5687 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   5688     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   5689         bcm_l3_egress_t egr_local;
   5690         int vp_routing = FALSE;
   5691 
   5692         /* Input parameters check. */
   5693         if ((NULL == egr) || (NULL == intf)) {
   5694             return (BCM_E_PARAM);
   5695         }
   5696 
   5697         /* Copy provided structure to local so it can be modified. */
   5698         sal_memcpy(&egr_local, egr, sizeof(bcm_l3_egress_t));
   5699 
   5700         if (egr_local.vlan >= BCM_VLAN_INVALID) {
   5701             return (BCM_E_PARAM);
   5702         }
   5703 
   5704         /* The MEPID field is of 13 bits. So max value is
   5705          * 8191.
   5706          */
   5707         if (egr_local.oam_global_context_id >= 8192) {
   5708             return (BCM_E_PARAM);
   5709         }
   5710 
   5711 #ifdef BCM_KATANA_SUPPORT        
   5712         if ((BCM_GPORT_IS_UCAST_QUEUE_GROUP(egr_local.port)) ||
   5713             (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(egr_local.port)) ||
   5714             (BCM_GPORT_IS_MCAST_SUBSCRIBER_QUEUE_GROUP(egr_local.port))) {
   5715             if ((((egr_local.qos_map_id >> _BCM_QOS_MAP_SHIFT) !=
   5716                        _BCM_QOS_MAP_TYPE_ING_QUEUE_OFFSET_MAP_TABLE)) ||
   5717                  ((egr_local.qos_map_id & _BCM_QOS_MAP_TYPE_MASK) > 
   5718                                      _BCM_QOS_MAP_ING_QUEUE_OFFSET_MAX)) {
   5719                 return (BCM_E_PARAM);
   5720             }
   5721         }
   5722 #endif
   5723         if (BCM_GPORT_IS_BLACK_HOLE(egr_local.port)) {
   5724              return BCM_E_PARAM;
   5725         } else if (BCM_GPORT_IS_SET(egr_local.port)) {
   5726             if (BCM_GPORT_IS_NIV_PORT(egr_local.port) ||
   5727                 BCM_GPORT_IS_EXTENDER_PORT(egr_local.port) ||
   5728                 BCM_GPORT_IS_VLAN_PORT(egr_local.port) ||
   5729                 (!soc_feature(unit, soc_feature_riot) &&
   5730                     BCM_GPORT_IS_MPLS_PORT(egr_local.port))
   5731                 ) {
   5732 #ifdef BCM_TRIDENT2_SUPPORT
   5733                 if (soc_feature(unit, soc_feature_virtual_port_routing)) {
   5734                     vp_routing = TRUE;
   5735                 } else
   5736 #endif /* BCM_TRIDENT2_SUPPORT */
   5737                 {
   5738                     return BCM_E_UNAVAIL;
   5739                 }
   5740             }
   5741             if (BCM_GPORT_IS_WLAN_PORT(egr_local.port) || (vp_routing)) {
   5742                 /* Resolve the gport and store the VP in egr->encap_id */
   5743                 BCM_IF_ERROR_RETURN(
   5744                    _bcm_esw_gport_resolve(unit, egr_local.port, 
   5745                                             &(egr_local.module), 
   5746                                             &(egr_local.port), 
   5747                                             &(egr_local.trunk), 
   5748                                             &(egr_local.encap_id)));  
   5749                 if (-1 != egr_local.trunk) {
   5750                     egr_local.flags |= BCM_L3_TGID;
   5751                 }
   5752             } else {
   5753                 /* vxlan port is used to associate with underlay NH */
   5754                 if (!(egr_local.flags2 & BCM_L3_FLAGS2_UNDERLAY)) {
   5755                     BCM_IF_ERROR_RETURN(
   5756                         _bcm_esw_l3_gport_resolve(unit, egr_local.port, 
   5757                                                    &(egr_local.port), 
   5758                                                    &(egr_local.module), 
   5759                                                    &(egr_local.trunk), 
   5760                                                    &(egr_local.flags)));
   5761                 }
   5762 
   5763             }
   5764         } else {
   5765             PORT_DUALMODID_VALID(unit, egr_local.port);
   5766         }
   5767 		
   5768         if((egr_local.flags & BCM_L3_IPMC) && 
   5769             !BCM_MAC_IS_ZERO(egr_local.mac_addr)) {
   5770             if (!soc_feature(unit, soc_feature_ipmc_use_configured_dest_mac)) {
   5771                 return BCM_E_CONFIG;
   5772             }
   5773         }
   5774 		
   5775         L3_LOCK(unit);
   5776         if (soc_feature(unit, soc_feature_mpls)) {
   5777 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
   5778             rv = bcm_tr_mpls_lock(unit);
   5779             if ((rv != BCM_E_INIT) && BCM_FAILURE(rv)) {
   5780                 L3_UNLOCK(unit);
   5781                 return rv;
   5782             }
   5783 #endif /* BCM_TRIUMPH_SUPPORT &&  BCM_MPLS_SUPPORT */
   5784         }
   5785 #ifdef BCM_KATANA_SUPPORT
   5786         if (soc_feature(unit, soc_feature_extended_queueing)) {
   5787             if ((BCM_GPORT_IS_UCAST_QUEUE_GROUP(egr->port)) ||
   5788                 (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(egr->port)) ||
   5789                 (BCM_GPORT_IS_MCAST_SUBSCRIBER_QUEUE_GROUP(egr->port))) {
   5790                 extended_queue_id = egr_local.trunk;
   5791                 egr_local.trunk = 0;
   5792             }
   5793         }
   5794 #endif
   5795         rv = bcm_xgs3_l3_egress_create(unit, flags, &egr_local, intf);
   5796         if (soc_feature(unit, soc_feature_mpls)) {
   5797 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
   5798             bcm_tr_mpls_unlock(unit);
   5799 #endif /* BCM_TRIUMPH_SUPPORT &&  BCM_MPLS_SUPPORT */
   5800         }
   5801 #ifdef BCM_KATANA_SUPPORT
   5802         if (BCM_SUCCESS(rv)) {
   5803             if (soc_feature(unit, soc_feature_extended_queueing)) {
   5804                 if ((BCM_GPORT_IS_UCAST_QUEUE_GROUP(egr->port)) ||
   5805                     (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(egr->port)) ||
   5806                     (BCM_GPORT_IS_MCAST_SUBSCRIBER_QUEUE_GROUP(egr->port))) {
   5807                     rv = _bcm_kt_extended_queue_config(unit, flags, egr_local.flags,
   5808                                                        extended_queue_id, 
   5809                           (egr_local.qos_map_id & _BCM_QOS_MAP_TYPE_MASK), intf); 
   5810                 } else {
   5811                     /* Reset extended queue configuration, if any */
   5812                     if (flags & BCM_L3_REPLACE) {
   5813                         rv = _bcm_kt_extended_queue_config(unit, flags, egr_local.flags,
   5814                                                            0, 0, intf);
   5815                     }
   5816                 }
   5817             }
   5818         }
   5819 #endif
   5820         L3_UNLOCK(unit);
   5821     }
   5822 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   5823     return (rv);
   5824 }
   5825 
   5826 /*
   5827  * Function:
   5828  *      bcm_esw_l3_egress_destroy
   5829  * Purpose:
   5830  *      Destroy an Egress forwarding object.
   5831  * Parameters:
   5832  *      unit    - (IN) bcm device.
   5833  *      intf    - (IN) L3 interface id pointing to Egress object.
   5834  * Returns:
   5835  *      BCM_E_XXX
   5836  */
   5837 int 
   5838 bcm_esw_l3_egress_destroy(int unit, bcm_if_t intf)
   5839 {
   5840     int rv = BCM_E_UNAVAIL;
   5841 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   5842     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   5843         L3_LOCK(unit);
   5844         if (soc_feature(unit, soc_feature_mpls)) {
   5845 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
   5846            rv =  bcm_tr_mpls_lock(unit);
   5847             if ((rv != BCM_E_INIT) && BCM_FAILURE(rv)) {
   5848                L3_UNLOCK(unit);
   5849                return rv;
   5850            }
   5851 #endif /* BCM_TRIUMPH_SUPPORT &&  BCM_MPLS_SUPPORT */
   5852         }
   5853          rv = bcm_xgs3_l3_egress_destroy(unit, intf);
   5854          if (soc_feature(unit, soc_feature_mpls)) {
   5855 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
   5856              bcm_tr_mpls_unlock(unit);
   5857 #endif /* BCM_TRIUMPH_SUPPORT &&  BCM_MPLS_SUPPORT */
   5858          }
   5859         L3_UNLOCK(unit);
   5860     }
   5861 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   5862     return rv;
   5863 }
   5864 
   5865 /*
   5866  * Function:
   5867  *      bcm_esw_l3_egress_get
   5868  * Purpose:
   5869  *      Get an Egress forwarding object.
   5870  * Parameters:
   5871  *      unit    - (IN) bcm device.
   5872  *      intf    - (IN) L3 interface id pointing to Egress object.
   5873  *      egr     - (OUT) Egress forwarding destination.
   5874  * Returns:
   5875  *      BCM_E_XXX
   5876  */
   5877 int 
   5878 bcm_esw_l3_egress_get (int unit, bcm_if_t intf, bcm_l3_egress_t *egr) 
   5879 {
   5880     int rv = BCM_E_UNAVAIL;
   5881 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   5882 
   5883     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   5884         L3_LOCK(unit);
   5885         rv = bcm_xgs3_l3_egress_get (unit, intf, egr);
   5886         L3_UNLOCK(unit);
   5887         if (BCM_FAILURE(rv)) {
   5888             return rv;
   5889         }
   5890 
   5891 #ifdef BCM_TRX_SUPPORT
   5892         if (egr->encap_id > 0 && egr->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
   5893             /* encap_id contains a virtual port value */
   5894             int vp;
   5895             vp = egr->encap_id;
   5896             if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   5897                 BCM_GPORT_NIV_PORT_ID_SET(egr->port, vp);
   5898             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
   5899                 BCM_GPORT_EXTENDER_PORT_ID_SET(egr->port, vp);
   5900             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   5901                 BCM_GPORT_VLAN_PORT_ID_SET(egr->port, vp);
   5902             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   5903                 BCM_GPORT_WLAN_PORT_ID_SET(egr->port, vp);
   5904             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)){
   5905                 BCM_GPORT_MPLS_PORT_ID_SET(egr->port, vp);
   5906             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) {
   5907                 BCM_GPORT_VXLAN_PORT_ID_SET(egr->encap_id, vp);
   5908                 if (egr->flags2 & BCM_L3_FLAGS2_UNDERLAY) {
   5909                     egr->port = egr->encap_id;
   5910                 }
   5911             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) {
   5912                 BCM_GPORT_FLOW_PORT_ID_SET(egr->encap_id, vp);
   5913             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)) {
   5914                 BCM_GPORT_L2GRE_PORT_ID_SET(egr->encap_id, vp);
   5915             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeTrill)) {
   5916                 BCM_GPORT_TRILL_PORT_ID_SET(egr->encap_id, vp);
   5917             } else {
   5918                 return BCM_E_INTERNAL;
   5919             }
   5920             if (egr->encap_id == vp) {
   5921                 egr->module = 0;
   5922                 egr->trunk = 0;
   5923                 egr->flags &= ~BCM_L3_TGID;
   5924                 egr->encap_id = 0;
   5925             }
   5926         } else if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, egr->encap_id)) {
   5927             /* encap_id contains a L2 egress object ID */
   5928             egr->port = 0;
   5929             egr->module = 0;
   5930             egr->trunk = 0;
   5931             egr->flags &= ~BCM_L3_TGID;
   5932         } else
   5933 #endif /* BCM_TRX_SUPPORT */
   5934 #ifdef BCM_RIOT_SUPPORT
   5935         if ((BCMI_RIOT_IS_ENABLED(unit)) &&
   5936             _bcm_vp_is_vfi_type(unit, egr->port) ) {
   5937             /* we should not do anything here. return the virtual port.*/
   5938             return BCM_E_NONE;
   5939             
   5940         } else 
   5941 #endif
   5942         {
   5943             rv = _bcm_esw_l3_gport_construct(unit, egr->port, egr->module, 
   5944                     egr->trunk, egr->flags, &(egr->port));
   5945             if ((intf - BCM_XGS3_EGRESS_IDX_MIN(unit)) == BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit)) {
   5946                  egr->port = BCM_GPORT_BLACK_HOLE;
   5947             }
   5948         }
   5949     }
   5950 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   5951     return rv;
   5952 }
   5953 
   5954 /*
   5955  * Function:
   5956  *      bcm_esw_l3_egress_find
   5957  * Purpose:
   5958  *      Find an egress forwarding object.     
   5959  * Parameters:
   5960  *      unit       - (IN) bcm device.
   5961  *      egr        - (IN) Egress object properties to match.  
   5962  *      intf       - (OUT) L3 interface id pointing to egress object
   5963  *                         if found. 
   5964  * Returns:
   5965  *      BCM_E_XXX
   5966  */
   5967 int 
   5968 bcm_esw_l3_egress_find(int unit, bcm_l3_egress_t *egr, 
   5969                                  bcm_if_t *intf)
   5970 {
   5971     int rv = BCM_E_UNAVAIL;
   5972 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   5973     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   5974         bcm_l3_egress_t egr_local;
   5975         int vp_routing = FALSE;
   5976 
   5977         /* Input parameters check. */
   5978         if ((NULL == egr) || (NULL == intf)) {
   5979             return (BCM_E_PARAM);
   5980         }
   5981 
   5982         /* Copy provided structure to local so it can be modified. */
   5983         sal_memcpy(&egr_local, egr, sizeof(bcm_l3_egress_t));
   5984 
   5985         if (BCM_GPORT_IS_SET(egr_local.port)) {
   5986 #ifdef BCM_TRIDENT2_SUPPORT
   5987             if (soc_feature(unit, soc_feature_virtual_port_routing) &&
   5988                 (BCM_GPORT_IS_NIV_PORT(egr_local.port) ||
   5989                  BCM_GPORT_IS_EXTENDER_PORT(egr_local.port) ||
   5990                  BCM_GPORT_IS_VLAN_PORT(egr_local.port)
   5991 #ifndef BCM_RIOT_SUPPORT
   5992                  ||(!soc_feature(unit, soc_feature_riot) &&
   5993                     BCM_GPORT_IS_MPLS_PORT(egr_local.port))
   5994 #endif
   5995                  )) {
   5996                 vp_routing = TRUE;
   5997             }
   5998 #endif 
   5999             if (BCM_GPORT_IS_WLAN_PORT(egr_local.port) || (vp_routing)) {
   6000                 /* Resolve the WLAN gport and store the VP in egr->encap_id */
   6001                 rv = _bcm_esw_gport_resolve(unit, egr_local.port, 
   6002                                             &(egr_local.module), 
   6003                                             &(egr_local.port), 
   6004                                             &(egr_local.trunk), 
   6005                                             &(egr_local.encap_id));  
   6006                 if (-1 != egr_local.trunk) {
   6007                     egr_local.flags |= BCM_L3_TGID;
   6008                 }
   6009             } else {
   6010                 rv = _bcm_esw_l3_gport_resolve(unit, egr_local.port, 
   6011                                                &(egr_local.port), 
   6012                                                &(egr_local.module), 
   6013                                                &(egr_local.trunk), 
   6014                                                &(egr_local.flags));
   6015             }
   6016             BCM_IF_ERROR_RETURN(rv); 
   6017         } else {
   6018             PORT_DUALMODID_VALID(unit, egr_local.port);
   6019         }
   6020         L3_LOCK(unit);
   6021         rv = bcm_xgs3_l3_egress_find(unit, &egr_local, intf);
   6022         L3_UNLOCK(unit);
   6023     }
   6024 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6025     return (rv);
   6026 }
   6027 
   6028 /*
   6029  * Function:
   6030  *      bcm_esw_l3_egress_traverse
   6031  * Purpose:
   6032  *      Goes through egress objects table and runs the user callback
   6033  *      function at each valid egress objects entry passing back the
   6034  *      information for that object.
   6035  * Parameters:
   6036  *      unit       - (IN) bcm device.
   6037  *      trav_fn    - (IN) Callback function. 
   6038  *      user_data  - (IN) User data to be passed to callback function.
   6039  * Returns:
   6040  *      BCM_E_XXX
   6041  */
   6042 int 
   6043 bcm_esw_l3_egress_traverse(int unit, 
   6044                            bcm_l3_egress_traverse_cb trav_fn, void *user_data)
   6045 {
   6046     int rv = BCM_E_UNAVAIL;
   6047 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6048     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6049         L3_LOCK(unit);
   6050         rv = bcm_xgs3_l3_egress_traverse(unit, trav_fn, user_data);
   6051         L3_UNLOCK(unit);
   6052     }
   6053 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6054     return rv;
   6055 }
   6056 
   6057 /*
   6058  * Function:
   6059  *      bcm_esw_l3_egress_multipath_max_create 
   6060  * Purpose:
   6061  *      Create an Egress Multipath forwarding object with specified path-width
   6062  * Parameters:
   6063  *      unit       - (IN) bcm device.
   6064  *      flags      - (IN) BCM_L3_REPLACE: replace existing.
   6065  *                        BCM_L3_WITH_ID: intf argument is given.
   6066  *      max_paths - (IN) configurable path-width
   6067  *      intf_count - (IN) Number of elements in intf_array.
   6068  *      intf_array - (IN) Array of Egress forwarding objects.
   6069  *      mpintf     - (OUT) L3 interface id pointing to Egress multipath object.
   6070  *                         This is an IN argument if either BCM_L3_REPLACE
   6071  *                          or BCM_L3_WITH_ID are given in flags.
   6072  * Returns:
   6073  *      BCM_E_XXX
   6074  */
   6075 int
   6076 bcm_esw_l3_egress_multipath_max_create(int unit, uint32 flags, int max_paths,
   6077                                    int intf_count, bcm_if_t *intf_array, bcm_if_t *mpintf)
   6078 {
   6079     int rv = BCM_E_UNAVAIL;
   6080 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6081     if (SOC_IS_TRX(unit) && soc_feature(unit, soc_feature_l3)) {
   6082          L3_LOCK(unit);
   6083          rv = bcm_xgs3_l3_egress_multipath_max_create(unit, flags, 0, max_paths, intf_count,
   6084                                                       intf_array, mpintf, intf_count, NULL);
   6085          L3_UNLOCK(unit);
   6086     }
   6087 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6088     return rv;
   6089 }
   6090 
   6091 /*
   6092  * Function:
   6093  *      bcm_esw_l3_egress_multipath_create 
   6094  * Purpose:
   6095  *      Create an Egress Multipath forwarding object.
   6096  * Parameters:
   6097  *      unit       - (IN) bcm device.
   6098  *      flags      - (IN) BCM_L3_REPLACE: replace existing.
   6099  *                        BCM_L3_WITH_ID: intf argument is given.
   6100  *      intf_count - (IN) Number of elements in intf_array.
   6101  *      intf_array - (IN) Array of Egress forwarding objects.
   6102  *      mpintf     - (OUT) L3 interface id pointing to Egress multipath object.
   6103  *                         This is an IN argument if either BCM_L3_REPLACE
   6104  *                          or BCM_L3_WITH_ID are given in flags.
   6105  * Returns:
   6106  *      BCM_E_XXX
   6107  */
   6108 int 
   6109 bcm_esw_l3_egress_multipath_create(int unit, uint32 flags, int intf_count,
   6110                                    bcm_if_t *intf_array, bcm_if_t *mpintf)
   6111 {
   6112     int rv = BCM_E_UNAVAIL;
   6113 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6114     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6115         L3_LOCK(unit);
   6116         rv = bcm_xgs3_l3_egress_multipath_create(unit, flags, 0, intf_count,
   6117                                                  intf_array, mpintf, intf_count,
   6118                                                  NULL);
   6119         L3_UNLOCK(unit);
   6120     }
   6121 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6122     return rv;
   6123 }
   6124 
   6125 /*
   6126  * Function:
   6127  *      bcm_esw_l3_egress_multipath_destroy
   6128  * Purpose:
   6129  *      Destroy an Egress Multipath forwarding object.
   6130  * Parameters:
   6131  *      unit    - (IN) bcm device.
   6132  *      mpintf  - (IN) L3 interface id pointing to Egress multipath object.
   6133  * Returns:
   6134  *      BCM_E_XXX
   6135  */
   6136 int 
   6137 bcm_esw_l3_egress_multipath_destroy(int unit, bcm_if_t mpintf) 
   6138 {
   6139     int rv = BCM_E_UNAVAIL;
   6140 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6141     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6142         L3_LOCK(unit);
   6143 
   6144         rv = bcm_xgs3_l3_egress_multipath_destroy(unit, mpintf);
   6145 
   6146         L3_UNLOCK(unit);
   6147     }
   6148 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6149     return rv;
   6150 }
   6151 
   6152 /*
   6153  * Function:
   6154  *      bcm_esw_l3_egress_multipath_get
   6155  * Purpose:
   6156  *      Get an Egress Multipath forwarding object.
   6157  * Parameters:
   6158  *      unit       - (IN) bcm device.
   6159  *      mpintf     - (IN) L3 interface id pointing to Egress multipath object.
   6160  *      intf_size  - (IN) Size of allocated entries in intf_array.
   6161  *      intf_array - (OUT) Array of Egress forwarding objects.
   6162  *      intf_count - (OUT) Number of entries of intf_count actually filled in.
   6163  *                      This will be a value less than or equal to the value.
   6164  *                      passed in as intf_size unless intf_size is 0.  If
   6165  *                      intf_size is 0 then intf_array is ignored and
   6166  *                      intf_count is filled in with the number of entries
   6167  *                      that would have been filled into intf_array if
   6168  *                      intf_size was arbitrarily large.
   6169  * Returns:
   6170  *      BCM_E_XXX
   6171  */
   6172 int 
   6173 bcm_esw_l3_egress_multipath_get(int unit, bcm_if_t mpintf, int intf_size,
   6174                                 bcm_if_t *intf_array, int *intf_count)
   6175 {
   6176     int rv = BCM_E_UNAVAIL;
   6177 
   6178 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6179     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6180 
   6181         L3_LOCK(unit);
   6182 
   6183 #ifdef BCM_TOMAHAWK_SUPPORT
   6184         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) {
   6185             L3_UNLOCK(unit);
   6186             return (BCM_E_PARAM);
   6187         } else if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   6188                    bcm_opt_ecmp_group_is_rh(unit, mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit))) {
   6189             rv = bcm_opt_ecmp_rh_multipath_get(unit, mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit),
   6190                                               intf_size,
   6191                                               intf_array,
   6192                                               intf_count,
   6193                                               NULL);
   6194         } else
   6195 #endif
   6196         {
   6197             rv = bcm_xgs3_l3_egress_multipath_get(unit, mpintf, intf_size,
   6198                                                   intf_array, intf_count);
   6199         }
   6200 
   6201         L3_UNLOCK(unit);
   6202 
   6203     }
   6204 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6205     return rv;
   6206 }
   6207 
   6208 /*
   6209  * Function:
   6210  *      bcm_esw_l3_egress_multipath_add
   6211  * Purpose:
   6212  *      Add an Egress forwarding object to an Egress Multipath 
   6213  *      forwarding object.
   6214  * Parameters:
   6215  *      unit    - (IN) bcm device.
   6216  *      mpintf  - (IN) L3 interface id pointing to Egress multipath object.
   6217  *      intf    - (IN) L3 interface id pointing to Egress forwarding object.
   6218  * Returns:
   6219  *      BCM_E_XXX
   6220  */
   6221 int 
   6222 bcm_esw_l3_egress_multipath_add(int unit, bcm_if_t mpintf, bcm_if_t intf)
   6223 {
   6224     int rv = BCM_E_UNAVAIL;
   6225 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6226     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6227         L3_LOCK(unit);
   6228         rv = bcm_xgs3_l3_egress_multipath_add(unit, mpintf, intf);
   6229         L3_UNLOCK(unit);
   6230     }
   6231 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6232     return (rv);
   6233 }
   6234 
   6235 /*
   6236  * Function:
   6237  *      bcm_esw_l3_egress_multipath_delete
   6238  * Purpose:
   6239  *      Delete an Egress forwarding object to an Egress Multipath 
   6240  *      forwarding object.
   6241  * Parameters:
   6242  *      unit    - (IN) bcm device.
   6243  *      mpintf  - (IN) L3 interface id pointing to Egress multipath object
   6244  *      intf    - (IN) L3 interface id pointing to Egress forwarding object
   6245  * Returns:
   6246  *      BCM_E_XXX
   6247  */
   6248 int 
   6249 bcm_esw_l3_egress_multipath_delete(int unit, bcm_if_t mpintf, bcm_if_t intf)
   6250 {
   6251     int rv = BCM_E_UNAVAIL;
   6252 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6253     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6254         L3_LOCK(unit);
   6255         rv = bcm_xgs3_l3_egress_multipath_delete(unit, mpintf, intf);
   6256         L3_UNLOCK(unit);
   6257     }
   6258 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6259     return rv;
   6260 }
   6261 
   6262 /*
   6263  * Function:
   6264  *      bcm_esw_l3_egress_multipath_find
   6265  * Purpose:
   6266  *      Find an egress multipath forwarding object.     
   6267  * Parameters:
   6268  *      unit       - (IN) bcm device.
   6269  *      intf_count - (IN) Number of elements in intf_array. 
   6270  *      intf_array - (IN) Array of egress forwarding objects.  
   6271  *      intf       - (OUT) L3 interface id pointing to egress multipath object
   6272  *                         if found. 
   6273  * Returns:
   6274  *      BCM_E_XXX
   6275  */
   6276 int 
   6277 bcm_esw_l3_egress_multipath_find(int unit, int intf_count, bcm_if_t
   6278                                  *intf_array, bcm_if_t *mpintf)
   6279 {
   6280     int rv = BCM_E_UNAVAIL;
   6281 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6282     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6283         L3_LOCK(unit);
   6284         rv = bcm_xgs3_l3_egress_multipath_find(unit, intf_count,
   6285                                                 intf_array, mpintf);
   6286         L3_UNLOCK(unit);
   6287     }
   6288 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6289     return rv;
   6290 }
   6291 
   6292 /*
   6293  * Function:
   6294  *      bcm_esw_l3_egress_multipath_traverse
   6295  * Purpose:
   6296  *      Goes through multipath egress objects table and runs the user callback
   6297  *      function at each multipath egress objects entry passing back the
   6298  *      information for that multipath object.
   6299  * Parameters:
   6300  *      unit       - (IN) bcm device.
   6301  *      trav_fn    - (IN) Callback function. 
   6302  *      user_data  - (IN) User data to be passed to callback function.
   6303  * Returns:
   6304  *      BCM_E_XXX
   6305  */
   6306 int 
   6307 bcm_esw_l3_egress_multipath_traverse(int unit, 
   6308                           bcm_l3_egress_multipath_traverse_cb trav_fn,
   6309                           void *user_data)
   6310 {
   6311     int rv = BCM_E_UNAVAIL;
   6312 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6313     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6314         L3_LOCK(unit);
   6315         rv = bcm_xgs3_l3_egress_multipath_traverse(unit, trav_fn, user_data);
   6316         L3_UNLOCK(unit);
   6317     }
   6318 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6319     return rv;
   6320 }
   6321 
   6322 /*
   6323  * Function:
   6324  *      _bcm_esw_l3_egress_ecmp_get
   6325  * Purpose:
   6326  *      Get an Egress ECMP forwarding object with members from the ECMP table
   6327  * Parameters:
   6328  *      unit    - (IN) bcm device.
   6329  *      ecmp    - (INOUT) ECMP group info.
   6330  *      intf_size  - (IN) Size of allocated entries in intf_array.
   6331  *      intf_array - (OUT) Array of Egress forwarding objects.
   6332  *      intf_count - (OUT) Number of entries of intf_count actually filled in.
   6333  *                      This will be a value less than or equal to the value.
   6334  *                      passed in as intf_size unless intf_size is 0.  If
   6335  *                      intf_size is 0 then intf_array is ignored and
   6336  *                      intf_count is filled in with the number of entries
   6337  *                      that would have been filled into intf_array if
   6338  *                      intf_size was arbitrarily large.
   6339  * Returns:
   6340  *      BCM_E_XXX
   6341  */
   6342 int 
   6343 _bcm_esw_l3_egress_ecmp_get(int unit, bcm_l3_egress_ecmp_t *ecmp, int intf_size,
   6344                             bcm_if_t *intf_array, int *intf_count, int rh_retrieve)
   6345 {
   6346     int rv = BCM_E_UNAVAIL;
   6347     int  grp_idx = 0;
   6348 #ifdef BCM_TOMAHAWK_SUPPORT
   6349     int lb_mode = 0;
   6350 #endif
   6351 
   6352     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6353         L3_LOCK(unit);
   6354         rv = bcm_xgs3_l3_egress_multipath_get(unit, ecmp->ecmp_intf, intf_size,
   6355                                                 intf_array, intf_count);
   6356         if (BCM_FAILURE(rv)) {
   6357             L3_UNLOCK(unit);
   6358             return rv;
   6359         }
   6360 
   6361         ecmp->flags = 0;
   6362         rv = bcm_xgs3_l3_egress_ecmp_max_paths_get(unit, ecmp->ecmp_intf,
   6363                 &ecmp->max_paths, NULL);
   6364         if (BCM_FAILURE(rv)) {
   6365             L3_UNLOCK(unit);
   6366             return rv;
   6367         }
   6368 
   6369         /* Get ecmp group index. */
   6370         grp_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 
   6371         if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, grp_idx,
   6372                            BCM_L3_ECMP_PATH_NO_SORTING)) {
   6373             ecmp->ecmp_group_flags = BCM_L3_ECMP_PATH_NO_SORTING; 
   6374         } else {    
   6375             ecmp->ecmp_group_flags = 0;
   6376         }
   6377         ecmp->dynamic_mode = 0;
   6378         ecmp->dynamic_size = 0;
   6379         ecmp->dynamic_age = 0;
   6380         ecmp->dynamic_load_exponent = 0;
   6381         ecmp->dynamic_expected_load_exponent = 0;
   6382         ecmp->dgm.threshold = 0;
   6383         ecmp->dgm.cost = 0;
   6384         ecmp->dgm.bias = 0;
   6385 
   6386 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   6387         /* 
   6388          * we can look into the ecmp_grp index to know if this 
   6389          * is overlay entry or underlay entry.
   6390          */
   6391         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   6392 
   6393             if (grp_idx < BCMI_L3_ECMP_OVERLAY_ENTRIES(unit)) {
   6394 
   6395                ecmp->ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
   6396             }
   6397         }
   6398 #endif
   6399 
   6400 #ifdef BCM_TRIUMPH3_SUPPORT
   6401         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   6402 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   6403             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   6404                 rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, ecmp);
   6405             } else
   6406 #endif /* BCM_TOMAHAWK2_SUPPORT  || BCM_TRIDENT3_SUPPORT*/
   6407             {
   6408                 rv = bcm_tr3_l3_egress_ecmp_dlb_get(unit, ecmp);
   6409             }
   6410             if (BCM_FAILURE(rv)) {
   6411                 L3_UNLOCK(unit);
   6412                 return rv;
   6413             }
   6414         }
   6415 #endif /* BCM_TRIUMPH3_SUPPORT */
   6416 
   6417 #ifdef BCM_TRIDENT2_SUPPORT
   6418         if (soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   6419 
   6420 #ifdef BCM_TRIDENT3_SUPPORT
   6421             int ecmp_group;
   6422             ecmp_count_entry_t ecmp_count_entry;
   6423             if (SOC_IS_TRIDENT3X(unit)) {
   6424                if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   6425                    ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   6426 
   6427                    BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
   6428                                ecmp_group, &ecmp_count_entry));
   6429                    lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit,
   6430                                       &ecmp_count_entry, LB_MODEf);
   6431                }
   6432             }
   6433 #endif
   6434             if ((!(SOC_IS_TRIDENT3X(unit)))
   6435 #ifdef BCM_TRIDENT3_SUPPORT
   6436                 || ((SOC_IS_TRIDENT3X(unit)) && (lb_mode == BCM_ECMP_LB_MODE_ENHANCED_HASH)
   6437                                            && (ecmp->dynamic_mode == 0))
   6438                 /* ecmp->dynamic_mode == 0 to make sure this is not DLB.
   6439                    For DLB, the previous call would have filled this up */
   6440                 /* In TD3 ENHANCED_HASHING Is 4*/
   6441 #endif
   6442 #ifdef BCM_TOMAHAWK_SUPPORT
   6443                   || (lb_mode == BCM_TH_L3_ECMP_LB_MODE_RH)
   6444 #endif
   6445                ) {
   6446                 rv = bcm_td2_l3_egress_ecmp_rh_get(unit, ecmp);
   6447             }
   6448 
   6449             if (BCM_FAILURE(rv)) {
   6450                 L3_UNLOCK(unit);
   6451                 return rv;
   6452             }
   6453         }
   6454 #endif /* BCM_TRIUMPH3_SUPPORT */
   6455 
   6456 #ifdef BCM_TOMAHAWK_SUPPORT
   6457         if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   6458             /* Set ECMP Level flags */
   6459             if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
   6460                       (ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
   6461                        BCM_L3_ECMP_OVERLAY)) {
   6462                 ecmp->ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
   6463             }
   6464             if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
   6465                       (ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
   6466                        BCM_L3_ECMP_UNDERLAY)) {
   6467                 ecmp->ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY;
   6468             }
   6469         }
   6470 
   6471         if (
   6472 #ifdef BCM_TRIDENT3_SUPPORT
   6473               ((SOC_IS_TRIDENT3X(unit)) && (lb_mode != BCM_ECMP_LB_MODE_ENHANCED_HASH)) ||
   6474 #endif
   6475                     soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   6476             rv = bcm_opt_l3_egress_ecmp_lb_get(unit, ecmp);
   6477             if (BCM_FAILURE(rv)) {
   6478                 L3_UNLOCK(unit);
   6479                 return rv;
   6480             }
   6481         }
   6482 
   6483         /*
   6484          * On Tomahawk, member table contains the RH set
   6485          * which is returned above.
   6486          * Member array is in the info structure. Hence, need to look
   6487          * into rh info to retrieve member array if it is a RH group
   6488          */
   6489         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   6490             rh_retrieve) {
   6491             if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
   6492                 rv = bcm_opt_ecmp_rh_multipath_get(unit,
   6493                            (ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
   6494                            intf_size, intf_array, intf_count, &ecmp->max_paths);
   6495             }
   6496         }
   6497 #endif /* BCM_TOMAHAWK_SUPPORT */
   6498 
   6499 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6500        if (ecmp->ecmp_group_flags & BCM_L3_ECMP_WEIGHTED) {
   6501             /* Weighted groups are never sorted */
   6502             ecmp->ecmp_group_flags &= ~BCM_L3_ECMP_PATH_NO_SORTING;
   6503        }
   6504 #endif
   6505 
   6506         L3_UNLOCK(unit);
   6507     }
   6508 
   6509     return rv;
   6510 }
   6511 
   6512 /*
   6513  * Function:
   6514  *      _bcm_esw_l3_ecmp_create 
   6515  * Purpose:
   6516  *      Create or modify an Egress ECMP forwarding object.
   6517  * Parameters:
   6518  *      unit       - (IN) bcm device.
   6519  *      ecmp       - (INOUT) ECMP group info.
   6520  *      intf_count - (IN) Number of elements in intf_array.
   6521  *      intf_array - (IN) Array of Egress forwarding objects.
   6522  *      op         - (IN) Member operation: SET, ADD, DELETE, or REPLACE.
   6523  *      count      - (IN) Number of elements in intf.
   6524  *      intf       - (IN) Egress forwarding objects to add, delete, or replace.
   6525  *      primary_count - (IN) Primary count for DGM, if not DGM set intf_count.
   6526  *      ecmp_member_bitmap   - (IN) ECMP DLB members.
   6527  * Returns:
   6528  *      BCM_E_XXX
   6529  */
   6530 int 
   6531 _bcm_esw_l3_ecmp_create(int unit, bcm_l3_egress_ecmp_t *ecmp,
   6532         int intf_count, bcm_if_t *intf_array, int op,
   6533         int count, bcm_if_t *intf, int primary_count,
   6534         SHR_BITDCL *dlb_member_bitmap)
   6535 {
   6536     int rv = BCM_E_UNAVAIL;
   6537 
   6538 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6539 
   6540     int rv2 = BCM_E_NONE;
   6541     uint32 ecmp_group_flags = 0;
   6542     int tmp_max_paths, tmp_intf_count;
   6543     bcm_if_t *tmp_intf_array;
   6544 #ifdef BCM_TOMAHAWK_SUPPORT
   6545     bcm_if_t  *new_intf_array = NULL;
   6546     int cnt;
   6547     int alloc_size;
   6548     int pow = 0;
   6549     int grp_idx;
   6550 #endif /* BCM_TOMAHAWK_SUPPORT */
   6551 #if defined(BCM_TRIDENT3_SUPPORT)
   6552     int rh_status;
   6553 #endif
   6554 
   6555 
   6556     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   6557         ecmp_group_flags = ecmp->ecmp_group_flags;
   6558 
   6559 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6560          if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
   6561                                       ecmp_mode_hierarchical) &&
   6562              (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
   6563              !(ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) &&
   6564              !(ecmp->ecmp_group_flags & BCM_L3_ECMP_UNDERLAY)) {
   6565                if (ecmp->flags & BCM_L3_REPLACE) {
   6566                    if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
   6567                                             ecmp->ecmp_intf)) {
   6568                        ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
   6569                    } else {
   6570                        ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY;
   6571                    }
   6572                } else if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
   6573                         (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp->dynamic_mode))) {
   6574                        ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY;
   6575                } else {
   6576                    return BCM_E_PARAM;
   6577                }
   6578             }
   6579 #endif
   6580         if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_NORMAL ||
   6581             ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED ||
   6582             ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL) {
   6583             if (!soc_feature(unit, soc_feature_ecmp_dlb)) {
   6584                return BCM_E_UNAVAIL;
   6585             }
   6586 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined (BCM_TRIDENT3_SUPPORT) \
   6587                                    || defined(BCM_TOMAHAWK3_SUPPORT)
   6588             /* A DLB group can only be programmed at ECMP Level 2 */
   6589             if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
   6590                 ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) {
   6591                return BCM_E_PARAM;
   6592             }
   6593             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   6594                 ecmp_group_flags |= BCM_L3_ECMP_DLB_OPT;
   6595                 /* Do not sort for DLB resiliency since member offset can't be changed  */
   6596                 ecmp_group_flags |= BCM_L3_ECMP_PATH_NO_SORTING;
   6597             }
   6598 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   6599         } else if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
   6600             if (!(soc_feature(unit, soc_feature_ecmp_resilient_hash) ||
   6601                   soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized))) {
   6602                return BCM_E_UNAVAIL;
   6603             }
   6604             if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   6605                 /* Do not sort if load balancing mode is RH on Tomahawk. */
   6606                 ecmp_group_flags |= BCM_L3_ECMP_PATH_NO_SORTING;
   6607                 ecmp_group_flags |= BCM_L3_ECMP_RH_OPT;
   6608             }
   6609         } else if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_ROUND_ROBIN)  {
   6610             if (!soc_feature(unit, soc_feature_ecmp_round_robin)) {
   6611                return BCM_E_UNAVAIL;
   6612             }
   6613         } else if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RANDOM)  {
   6614             if (!soc_feature(unit, soc_feature_ecmp_random)) {
   6615                return BCM_E_UNAVAIL;
   6616             }
   6617 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   6618         } else if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   6619             if (!soc_feature(unit, soc_feature_dgm)) {
   6620                return BCM_E_UNAVAIL;
   6621             }
   6622             ecmp_group_flags |= BCM_L3_ECMP_DGM_OPT;
   6623             /* Do not sort for DGM resiliency since member offset can't be changed  */
   6624             ecmp_group_flags |= BCM_L3_ECMP_PATH_NO_SORTING;
   6625 #endif /* BCM_TOMAHAWK2_SUPPORT */
   6626         } else if (ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DISABLED) {
   6627             return BCM_E_PARAM;
   6628         }
   6629 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   6630         if (soc_feature(unit, soc_feature_riot) ||
   6631             soc_feature(unit, soc_feature_multi_level_ecmp)) {
   6632             if (!BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) &&
   6633                 ((ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY))) {
   6634                  return (BCM_E_UNAVAIL);
   6635             }
   6636         } else
   6637 #endif
   6638         {
   6639             if ((ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) ||
   6640                 (ecmp->ecmp_group_flags & BCM_L3_ECMP_UNDERLAY)) {
   6641                 if (!(soc_feature(unit, soc_feature_hierarchical_ecmp))) {
   6642                     return (BCM_E_UNAVAIL);
   6643                 }
   6644             }
   6645         }
   6646 
   6647         if ((ecmp->max_paths > 0) && (intf_count > ecmp->max_paths)) {
   6648             return BCM_E_RESOURCE;
   6649         }
   6650 
   6651         if ((intf_count > BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) &&
   6652             !(ecmp_group_flags & BCM_L3_ECMP_RH_OPT)) {
   6653             return BCM_E_RESOURCE;
   6654         }
   6655 
   6656 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   6657         if (soc_feature(unit, soc_feature_dgm)) {
   6658             if (primary_count > BCM_XGS3_L3_ECMP_MAX_PATHS(unit) && 
   6659                 (ecmp_group_flags & BCM_L3_ECMP_DGM_OPT)) {
   6660                 return BCM_E_RESOURCE;
   6661             }
   6662         }
   6663 #endif /* BCM_TOMAHAWK2_SUPPORT */
   6664 
   6665         if (soc_feature(unit, soc_feature_ecmp_resilient_hash) &&
   6666             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) {
   6667             if (intf_count > ecmp->dynamic_size) {
   6668                 return BCM_E_PARAM;
   6669             }
   6670         }
   6671 
   6672 
   6673         if ((ecmp->max_paths > BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) &&
   6674             !(ecmp_group_flags & BCM_L3_ECMP_RH_OPT)) {
   6675             return (BCM_E_PARAM);
   6676         }
   6677 
   6678         L3_LOCK(unit);
   6679 
   6680 #ifdef BCM_TOMAHAWK_SUPPORT
   6681         if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   6682             if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode != 
   6683                                         ecmp_mode_hierarchical) &&
   6684                 ((ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) ||
   6685                  (ecmp->ecmp_group_flags & BCM_L3_ECMP_UNDERLAY))) {
   6686                  L3_UNLOCK(unit);
   6687                  return (BCM_E_UNAVAIL);
   6688             }
   6689             /* Only one ECMP Level can be specified for a group */
   6690             if ((ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) &&
   6691                 (ecmp->ecmp_group_flags & BCM_L3_ECMP_UNDERLAY)) {
   6692                 L3_UNLOCK(unit);
   6693                 return (BCM_E_PARAM);
   6694             }
   6695             /* An RH group can only be programmed at ECMP Level 1 */
   6696             if (!(soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
   6697                 (ecmp->ecmp_group_flags & BCM_L3_ECMP_UNDERLAY) &&
   6698                 (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) {
   6699                 L3_UNLOCK(unit);
   6700                 return (BCM_E_PARAM);
   6701             }
   6702         }
   6703 
   6704 #ifdef BCM_TOMAHAWK3_SUPPORT
   6705         if ((soc_feature(unit, soc_feature_l3_ecmp_weighted)) &&
   6706             (ecmp_group_flags & BCM_L3_ECMP_WEIGHTED)) {
   6707             if ((intf_count != ecmp->max_paths) ||
   6708                 (ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DISABLED)) {
   6709                 return BCM_E_PARAM;
   6710             }
   6711         }
   6712 
   6713         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   6714             (soc_feature(unit, soc_feature_ecmp_rh_1k_unique_members)) &&
   6715             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) {
   6716             if (intf_count > 1024) {
   6717                 return BCM_E_CONFIG;
   6718             }
   6719         }
   6720 
   6721 #endif
   6722 
   6723         /* Here the RH set constructed should be written in the member table */
   6724         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   6725             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) {
   6726 
   6727             if (ecmp->max_paths > BCM_XGS3_L3_ECMP_RH_MAX_PATHS(unit)) {
   6728                 L3_UNLOCK(unit);
   6729                 return BCM_E_PARAM;
   6730             }
   6731             /* Check if RH size is a power of 2 */
   6732             if (op == BCM_L3_ECMP_MEMBER_OP_SET) {
   6733                 pow = (ecmp->dynamic_size &&
   6734                        !(ecmp->dynamic_size & (ecmp->dynamic_size - 1)));
   6735                 if (!pow) {
   6736                     L3_UNLOCK(unit);
   6737                     return BCM_E_PARAM;
   6738                 }
   6739                 if (intf_count > ecmp->dynamic_size) {
   6740                     L3_UNLOCK(unit);
   6741                     return BCM_E_PARAM;
   6742                 }
   6743                 if (ecmp->dynamic_size < RH_OPT_MIN_PATHS(unit) ||
   6744                     ecmp->dynamic_size > RH_OPT_MAX_PATHS(unit)) {
   6745                     L3_UNLOCK(unit);
   6746                     return BCM_E_PARAM;
   6747                 }
   6748             }
   6749             /* Allocate new intf array which will be the RH set */
   6750             alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   6751             new_intf_array = sal_alloc(alloc_size, "RH intf array");
   6752             if (NULL == new_intf_array) {
   6753                 L3_UNLOCK(unit);
   6754                 return(BCM_E_MEMORY);
   6755             }
   6756             sal_memset(new_intf_array, 0, sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit)); 
   6757             /* Get existing RH entry set if the group is already exists */
   6758             if (op != BCM_L3_ECMP_MEMBER_OP_SET) {
   6759                 bcm_l3_egress_ecmp_t ecmp_copy;
   6760                 sal_memcpy(&ecmp_copy, ecmp, sizeof(ecmp_copy));
   6761                 rv = _bcm_esw_l3_egress_ecmp_get(unit, &ecmp_copy, BCM_XGS3_L3_ECMP_MAX(unit),
   6762                                             new_intf_array, &cnt, FALSE);
   6763                 if (BCM_FAILURE(rv)) {
   6764                     sal_free(new_intf_array);
   6765                     L3_UNLOCK(unit);
   6766                     return rv;
   6767                 }
   6768             }
   6769 
   6770             /* Create/modify the RH entry set */
   6771             rv = bcm_opt_l3_egress_ecmp_rh_create(unit, ecmp, intf_count,
   6772                           intf_array, op, count, intf, new_intf_array);
   6773             if (BCM_FAILURE(rv)) {
   6774                 sal_free(new_intf_array);
   6775                 L3_UNLOCK(unit);
   6776                 return rv;
   6777             }
   6778         }
   6779 #endif /* BCM_TOMAHAWK_SUPPORT */
   6780 
   6781 #ifdef BCM_TOMAHAWK3_SUPPORT
   6782         if ((soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) &&
   6783             (ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) &&
   6784             (ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DISABLED) &&
   6785             (ecmp->flags & BCM_L3_REPLACE) && (ecmp->ecmp_intf >= BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)) &&
   6786             (bcm_opt_ecmp_group_is_rh(unit, ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) {
   6787             bcm_opt_l3_egress_ecmp_rh_destroy(unit, ecmp->ecmp_intf);
   6788         } else if ((soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp))
   6789              && (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized))
   6790              && (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DISABLED) &&
   6791             (ecmp->flags & BCM_L3_REPLACE) &&
   6792             (!(ecmp->ecmp_group_flags & BCM_L3_ECMP_RH_OPT)) &&
   6793             (bcm_opt_ecmp_group_is_rh(unit,
   6794             ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) {
   6795 
   6796             /* Restore intf count and intf array */
   6797             if (ecmp->max_paths == 0) {
   6798                 tmp_max_paths = BCM_XGS3_L3_ECMP_RH_MAX_PATHS(unit);
   6799             } else {
   6800                 tmp_max_paths = ecmp->max_paths;
   6801             }
   6802 
   6803             rv = bcm_opt_ecmp_rh_set_intf_arr(unit, intf_count, intf_array,
   6804                                              ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit),
   6805                                              ecmp->dynamic_size, tmp_max_paths);
   6806 
   6807             if (BCM_FAILURE(rv)) {
   6808                 sal_free(new_intf_array);
   6809                 L3_UNLOCK(unit);
   6810                 return rv;
   6811             }
   6812 
   6813         }
   6814 #endif
   6815 
   6816         tmp_max_paths = ecmp->max_paths;
   6817         tmp_intf_count = intf_count;
   6818         tmp_intf_array = intf_array;
   6819 #ifdef BCM_TOMAHAWK_SUPPORT
   6820         /* Save the members of the original intf_array */
   6821         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   6822             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) {
   6823             tmp_max_paths = ecmp->dynamic_size;
   6824             tmp_intf_count = intf_count ? ecmp->dynamic_size : 0;
   6825             primary_count = tmp_intf_count;
   6826             tmp_intf_array = new_intf_array;
   6827         }
   6828 #endif /* BCM_TOMAHAWK_SUPPORT */
   6829         if (tmp_max_paths > 0) {
   6830             rv = bcm_xgs3_l3_egress_multipath_max_create(unit, ecmp->flags, 
   6831                                                          ecmp_group_flags,
   6832                                                          tmp_max_paths,
   6833                                                          tmp_intf_count,
   6834                                                          tmp_intf_array,
   6835                                                          &ecmp->ecmp_intf,
   6836                                                          primary_count,
   6837                                                          dlb_member_bitmap);
   6838         } else {
   6839             rv = bcm_xgs3_l3_egress_multipath_create(unit, ecmp->flags, 
   6840                                                      ecmp_group_flags,
   6841                                                      intf_count,
   6842                                                      intf_array,
   6843                                                      &ecmp->ecmp_intf,
   6844                                                      primary_count,
   6845                                                      dlb_member_bitmap);
   6846         }
   6847 
   6848 #ifdef BCM_TOMAHAWK_SUPPORT
   6849         if (new_intf_array) {
   6850             sal_free(new_intf_array);
   6851             new_intf_array = NULL;
   6852         }
   6853 #endif
   6854         if (BCM_FAILURE(rv)) {
   6855             L3_UNLOCK(unit);
   6856             return rv;
   6857         }
   6858 
   6859 #ifdef BCM_TOMAHAWK_SUPPORT
   6860         grp_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   6861         /* Save the members of the original intf_array */
   6862         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   6863             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) {
   6864             BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, grp_idx,
   6865                                                BCM_L3_ECMP_PATH_NO_SORTING);
   6866 
   6867             /* Restore intf count and intf array */
   6868             if (ecmp->max_paths == 0) {
   6869                 tmp_max_paths = BCM_XGS3_L3_ECMP_RH_MAX_PATHS(unit);
   6870             } else {
   6871                 tmp_max_paths = ecmp->max_paths;
   6872             }
   6873 
   6874             rv = bcm_opt_ecmp_rh_set_intf_arr(unit, intf_count, intf_array,
   6875                                              grp_idx, ecmp->dynamic_size, tmp_max_paths);
   6876             rv = bcm_opt_ecmp_lb_mode_set(unit, grp_idx,
   6877                                          BCM_TH_L3_ECMP_LB_MODE_RH);
   6878         } else if (soc_feature(unit, soc_feature_ecmp_random) &&
   6879             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RANDOM)) {
   6880             rv = bcm_opt_ecmp_lb_mode_set(unit, grp_idx,
   6881                                          BCM_TH_L3_ECMP_LB_MODE_RANDOM);
   6882         } else if (soc_feature(unit, soc_feature_ecmp_round_robin) &&
   6883             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_ROUND_ROBIN)) {
   6884             rv = bcm_opt_ecmp_lb_mode_set(unit, grp_idx,
   6885                                          BCM_TH_L3_ECMP_LB_MODE_RR);
   6886         } else {
   6887             if ((SOC_IS_TRIDENT3X(unit)  && (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DISABLED))
   6888                       || (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized))) {
   6889                 if (!(ecmp_group_flags & BCM_L3_ECMP_WEIGHTED)) {
   6890                 rv = bcm_opt_ecmp_lb_mode_set(unit, grp_idx,
   6891                                              BCM_L3_ECMP_DYNAMIC_MODE_DISABLED);
   6892             }
   6893        }
   6894 
   6895        }
   6896 #endif /* BCM_TOMAHAWK_SUPPORT */
   6897 
   6898 #ifdef BCM_TRIUMPH3_SUPPORT
   6899         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   6900 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   6901             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   6902 #ifdef BCM_TRIDENT3_SUPPORT
   6903                 if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp->dynamic_mode) && SOC_IS_TRIDENT3X(unit)) {
   6904                     BCM_IF_ERROR_RETURN(bcmi_ecmp_rh_status_get(unit, &rh_status));
   6905                     if (rh_status) {
   6906                         /* ECMP DLB and resilient hashing cannot be enabled
   6907                          * at the same time.
   6908                          */
   6909                         return BCM_E_PARAM;
   6910                     }
   6911                 }
   6912 #endif
   6913                 rv = bcm_th2_l3_egress_ecmp_dlb_create(unit, ecmp, intf_count,
   6914                                                        intf_array, primary_count,
   6915                                                        dlb_member_bitmap);
   6916             } else
   6917 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   6918             {
   6919                 rv = bcm_tr3_l3_egress_ecmp_dlb_create(unit, ecmp, intf_count,
   6920                                                        intf_array);
   6921             }
   6922         } 
   6923 #endif /* BCM_TRIUMPH3_SUPPORT */
   6924 
   6925 #ifdef BCM_TRIDENT3_SUPPORT
   6926         rh_status = TRUE; /*Default for non-TD3 */
   6927         if (SOC_IS_TRIDENT3X(unit)) {
   6928             BCM_IF_ERROR_RETURN(bcmi_ecmp_rh_status_get(unit, &rh_status));
   6929         }
   6930 #endif
   6931 #ifdef BCM_TRIDENT2_SUPPORT
   6932         if (
   6933 #ifdef BCM_TRIDENT3_SUPPORT
   6934            ((rh_status && (ecmp->flags & BCM_L3_REPLACE)) ||
   6935            (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) &&
   6936 #endif
   6937             soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   6938 #ifdef BCM_TRIDENT3_SUPPORT
   6939             if (SOC_IS_TRIDENT3X(unit)) {
   6940                 int dlb_status;
   6941                 BCM_IF_ERROR_RETURN(bcmi_ecmp_dlb_status_get(unit, &dlb_status));
   6942                 if (dlb_status) {
   6943                     /* ECMP DLB and resilient hashing cannot be enabled
   6944                      * at the same time.
   6945                      */
   6946                     return BCM_E_PARAM;
   6947                }
   6948             }
   6949 #endif
   6950             rv = bcm_td2_l3_egress_ecmp_rh_create(unit, ecmp, intf_count,
   6951                               intf_array, op, count, intf);
   6952         } 
   6953 #endif /* BCM_TRIUMPH3_SUPPORT */
   6954 
   6955         /*
   6956          * One of above two hashing features should be active at a time.
   6957          *
   6958          * Free/Destroy the software state created for ecmp object if
   6959          * there is error in feature specific multipath state creation.
   6960          * Return the main error coming from feature specific
   6961          * routines. Error coming from multipath destroy is very rare
   6962          * as the object that was just created is being destroyed.
   6963          * But even if there is some error, display a message.
   6964          */
   6965         if (BCM_FAILURE(rv)
   6966 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   6967             && !(soc_feature(unit, soc_feature_ecmp_dlb) &&
   6968             soc_feature(unit, soc_feature_ecmp_dlb_optimized) &&
   6969             BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp->dynamic_mode) &&
   6970             (ecmp->flags & BCM_L3_REPLACE))
   6971             /* When replace fails, the original ECMP group should not be deleted.*/
   6972 #endif
   6973            ) {
   6974             rv2 = bcm_xgs3_l3_egress_multipath_destroy(unit, ecmp->ecmp_intf);
   6975         }
   6976 
   6977         if (BCM_FAILURE(rv2)) {
   6978             LOG_ERROR(BSL_LS_BCM_COMMON,
   6979                       (BSL_META_U(unit,
   6980                                   "multipath destroy failed : %d \n"), rv2));
   6981         }
   6982         L3_UNLOCK(unit);
   6983     }
   6984 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   6985 
   6986     return rv;
   6987 }
   6988 
   6989 /*
   6990  * Function:
   6991  *      bcm_esw_l3_ecmp_create
   6992  * Purpose:
   6993  *      Create or modify an Egress ECMP forwarding object.
   6994  * Parameters:
   6995  *      unit              - (IN) bcm device.
   6996  *      options           - (IN) BCM_L3_ECMP_O_xxx flags
   6997  *      ecmp_info         - (INOUT) ECMP group info.
   6998  *      ecmp_member_count - (IN) Number of elements in
   6999  *                               ecmp_member_array.
   7000  *      ecmp_member_array - (IN) Member array of Egress 
   7001  *                               forwarding objects.
   7002  * Returns:
   7003  *      BCM_E_XXX
   7004  */
   7005 int
   7006 bcm_esw_l3_ecmp_create(
   7007     int unit, 
   7008     uint32 options, 
   7009     bcm_l3_egress_ecmp_t *ecmp_info, 
   7010     int ecmp_member_count, 
   7011     bcm_l3_ecmp_member_t *ecmp_member_array)
   7012 {
   7013     int rv, rv2;
   7014     int i, alloc_size, intf_count, old_intf_count;
   7015     bcm_if_t *intf_array = NULL;
   7016     bcm_if_t *old_intf_array = NULL;
   7017 
   7018     if (ecmp_info == NULL || ecmp_member_array == NULL) {
   7019         return (BCM_E_PARAM);
   7020     }
   7021 
   7022     ecmp_info->flags &= ~(BCM_L3_WITH_ID | BCM_L3_REPLACE);
   7023 
   7024     if (options & BCM_L3_ECMP_O_CREATE_WITH_ID) {
   7025         ecmp_info->flags |= BCM_L3_WITH_ID;
   7026     }
   7027     if (options & BCM_L3_ECMP_O_REPLACE) {
   7028         ecmp_info->flags |= BCM_L3_REPLACE;
   7029     }
   7030 
   7031     L3_LOCK(unit);
   7032 
   7033     intf_count = ecmp_member_count;
   7034     if (intf_count > BCM_XGS3_L3_ECMP_MAX(unit)) {
   7035         rv = BCM_E_RESOURCE;
   7036         goto clean_up;
   7037     }
   7038 
   7039     /* Convert the ecmp_member_array to intf_array */
   7040     alloc_size = BCM_XGS3_L3_ECMP_MAX(unit) * sizeof(bcm_if_t);
   7041     intf_array = sal_alloc(alloc_size, "L3 ECMP intf_array");
   7042     if (intf_array == NULL) {
   7043         rv = BCM_E_MEMORY;
   7044         goto clean_up;
   7045     }
   7046 
   7047     sal_memset(intf_array, 0, alloc_size);
   7048 
   7049     /* Configure the intf_array to HW */
   7050     if ((soc_feature(unit, soc_feature_ecmp_resilient_hash) ||
   7051          soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) &&
   7052         (ecmp_info->flags & BCM_L3_ECMP_RH_REPLACE)) {
   7053 
   7054         for (i = 0; i < intf_count; i++) {
   7055             intf_array[i] = ecmp_member_array[i].egress_if;
   7056         }
   7057 
   7058         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) {
   7059             rv = BCM_E_PARAM;
   7060             goto clean_up;
   7061         }
   7062 
   7063         for (i = 0; i < intf_count; i++) {
   7064             if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) {
   7065                 rv = BCM_E_PARAM;
   7066                 goto clean_up;
   7067             }
   7068         }
   7069 
   7070         /* Allocate interface array */
   7071         alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   7072         old_intf_array = sal_alloc(alloc_size, "old intf array");
   7073         if (NULL == old_intf_array) {
   7074             rv = BCM_E_MEMORY;
   7075             goto clean_up;
   7076         }
   7077         sal_memset(old_intf_array, 0, alloc_size);
   7078 
   7079 
   7080         /* Get ECMP group's existing interface array */
   7081         rv = bcm_esw_l3_egress_multipath_get(unit, ecmp_info->ecmp_intf,
   7082                                              BCM_XGS3_L3_ECMP_MAX(unit),
   7083                                              old_intf_array,
   7084                                              &old_intf_count);
   7085         if (BCM_FAILURE(rv)) {
   7086             goto clean_up;
   7087         }
   7088 
   7089         /* Check if there is room in ECMP group */
   7090         if ((old_intf_count == ecmp_info->max_paths) &&
   7091             (intf_count > old_intf_count)) {
   7092             rv = BCM_E_FULL;
   7093             goto clean_up;
   7094         }
   7095 
   7096 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7097         if (ecmp_info->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
   7098             if (intf_count > ecmp_info->dynamic_size) {
   7099                 rv = BCM_E_RESOURCE;
   7100                 goto clean_up;
   7101             }
   7102         } else
   7103 #endif
   7104         {
   7105             if (intf_count > ecmp_info->max_paths) {
   7106                 rv = BCM_E_RESOURCE;
   7107                 goto clean_up;
   7108             }
   7109         }
   7110 
   7111         /* Update ECMP group */
   7112         ecmp_info->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   7113 
   7114         rv = _bcm_esw_l3_ecmp_create(unit, ecmp_info, intf_count, intf_array,
   7115                  BCM_L3_ECMP_MEMBER_OP_REPLACE, old_intf_count, old_intf_array,
   7116                  intf_count, NULL);
   7117     } else {
   7118 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   7119         if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp_info->dynamic_mode)) {
   7120             rv = bcm_th2_l3_ecmp_dlb_dgm_member_create(unit, ecmp_info,
   7121                                                        ecmp_member_array,
   7122                                                        ecmp_member_count);
   7123             /* No DLB ECMP failover */
   7124             goto clean_up;
   7125         } else
   7126 #endif /* BCM_TOMAHAWK2_SUPPORT  ||  BCM_TRIDENT3_SUPPORT  */
   7127         {
   7128             for (i = 0; i < intf_count; i++) {
   7129                 intf_array[i] = ecmp_member_array[i].egress_if;
   7130             }
   7131             rv = _bcm_esw_l3_ecmp_create(unit, ecmp_info, intf_count,
   7132                                          intf_array, BCM_L3_ECMP_MEMBER_OP_SET,
   7133                                          0, NULL, intf_count, NULL);
   7134         }
   7135     }
   7136 
   7137     if (BCM_FAILURE(rv)) {
   7138         goto clean_up;
   7139     }
   7140 
   7141     /* Configure the member's attributions */
   7142     rv = _bcm_xgs3_l3_ecmp_member_set(unit, ecmp_info,
   7143                                       intf_count, ecmp_member_array);
   7144     if (BCM_FAILURE(rv)) {
   7145         if (!(ecmp_info->flags & BCM_L3_REPLACE)) {
   7146             rv2 = bcm_xgs3_l3_egress_multipath_destroy(unit, ecmp_info->ecmp_intf);
   7147             if (BCM_FAILURE(rv2)) {
   7148                 LOG_ERROR(BSL_LS_BCM_COMMON,
   7149                           (BSL_META_U(unit,
   7150                                       "multipath destroy failed : %d \n"), rv2));
   7151             }
   7152         }
   7153         goto clean_up;
   7154     }
   7155 
   7156 clean_up:
   7157     if (intf_array) {
   7158         sal_free(intf_array);
   7159         intf_array = NULL;
   7160     }
   7161     if (old_intf_array) {
   7162         sal_free(old_intf_array);
   7163         old_intf_array = NULL;
   7164     }
   7165     L3_UNLOCK(unit);
   7166     
   7167     return rv;
   7168 }
   7169 
   7170 /*
   7171  * Function:
   7172  *      bcm_esw_l3_ecmp_destroy
   7173  * Purpose:
   7174  *      Destroy an Egress ECMP forwarding object.
   7175  * Parameters:
   7176  *      unit          - (IN) bcm device.
   7177  *      ecmp_group_id - (IN) L3 interface ID pointing to Egress
   7178  *                           ECMP forwarding object
   7179  * Returns:
   7180  *      BCM_E_XXX
   7181  */
   7182 int
   7183 bcm_esw_l3_ecmp_destroy(
   7184     int unit, 
   7185     bcm_if_t ecmp_group_id)
   7186 {
   7187     int rv = BCM_E_UNAVAIL;
   7188 
   7189 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   7190     if (SOC_IS_XGS3_SWITCH(unit) &&
   7191         soc_feature(unit, soc_feature_l3)) {
   7192         L3_LOCK(unit);
   7193         rv = bcm_xgs3_l3_ecmp_destroy(unit, ecmp_group_id);
   7194         L3_UNLOCK(unit);
   7195     }
   7196 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   7197 
   7198     return rv;
   7199 }
   7200 
   7201 /*
   7202  * Function:
   7203  *      bcm_esw_l3_ecmp_get
   7204  * Purpose:
   7205  *      Get an Egress ECMP forwarding object.
   7206  * Parameters:
   7207  *      unit              - (IN) bcm device.
   7208  *      ecmp_info         - (INOUT) ECMP group info.
   7209  *      ecmp_member_size  - (IN) Size of allocated entries in 
   7210  *                               ecmp_member_array.
   7211  *      ecmp_member_array - (OUT) Member array of Egress forwarding objects.
   7212  *      ecmp_member_count - (OUT) Number of members of ecmp_member_count actually 
   7213  *                                filled in. This will be a value less than or 
   7214  *                                equal to the value passed in as ecmp_member_size  
   7215  *                                unless ecmp_member_size is 0. If ecmp_member_size  
   7216  *                                is 0, then ecmp_member_array is ignored and 
   7217  *                                ecmp_member_count is filled in with the number of 
   7218  *                                members that would have been filled into 
   7219  *                                ecmp_member_array if ecmp_member_size was 
   7220  *                                arbitrarily large.
   7221  * Returns:
   7222  *      BCM_E_XXX
   7223  */
   7224 int
   7225 bcm_esw_l3_ecmp_get(
   7226     int unit, 
   7227     bcm_l3_egress_ecmp_t *ecmp_info, 
   7228     int ecmp_member_size, 
   7229     bcm_l3_ecmp_member_t *ecmp_member_array, 
   7230     int *ecmp_member_count)
   7231 {
   7232     int rv = BCM_E_UNAVAIL;
   7233 
   7234 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   7235     if (SOC_IS_XGS3_SWITCH(unit) && 
   7236         soc_feature(unit, soc_feature_l3)) {
   7237         L3_LOCK(unit);
   7238 
   7239         /* Get the ECMP group's information */
   7240         rv = _bcm_xgs3_l3_ecmp_info_get(unit, ecmp_info);
   7241         if (BCM_FAILURE(rv)) {
   7242             L3_UNLOCK(unit);
   7243             return rv;
   7244         }
   7245 
   7246 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   7247         if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp_info->dynamic_mode)) {
   7248             rv = bcm_th2_l3_ecmp_dlb_dgm_member_get(
   7249                      unit, ecmp_info, ecmp_member_size,
   7250                      ecmp_member_array, ecmp_member_count);
   7251         } else
   7252 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT  */
   7253         {
   7254             /* Get the ECMP member's information */
   7255             rv = _bcm_xgs3_l3_ecmp_member_get(
   7256                      unit, ecmp_info, ecmp_member_size,
   7257                      ecmp_member_array, ecmp_member_count);
   7258         }
   7259         L3_UNLOCK(unit);
   7260     }
   7261 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   7262 
   7263     return rv;
   7264 }
   7265 
   7266 /*
   7267  * Function:
   7268  *      bcm_esw_l3_ecmp_member_add
   7269  * Purpose:
   7270  *      Add a member to an Egress ECMP forwarding object.
   7271  * Parameters:
   7272  *      unit          - (IN) bcm device.
   7273  *      ecmp_group_id - (IN) L3 interface ID pointing to Egress
   7274  *                           ECMP forwarding object
   7275  *      ecmp_member   - (IN) Pointer to Egress forwarding
   7276  *                           object member structure.
   7277  * Returns:
   7278  *      BCM_E_XXX
   7279  */
   7280 int
   7281 bcm_esw_l3_ecmp_member_add(
   7282     int unit, 
   7283     bcm_if_t ecmp_group_id, 
   7284     bcm_l3_ecmp_member_t *ecmp_member)
   7285 {
   7286     int rv = BCM_E_UNAVAIL;
   7287 
   7288 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   7289     if (SOC_IS_XGS3_SWITCH(unit) &&
   7290         soc_feature(unit, soc_feature_l3)) {
   7291         int i, alloc_size;
   7292         bcm_if_t *intf_array = NULL;
   7293         bcm_l3_egress_ecmp_t ecmp_info;
   7294         int ecmp_member_count;
   7295         bcm_l3_ecmp_member_t *ecmp_member_array = NULL;
   7296         int primary_count;
   7297 
   7298         /* Input check */
   7299         if (ecmp_member == NULL) {
   7300             return BCM_E_PARAM;
   7301         }
   7302         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_group_id)) {
   7303             return BCM_E_PARAM;
   7304         }
   7305         if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)) {
   7306 #ifdef BCM_RIOT_SUPPORT
   7307             if ((BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) &&
   7308                 (BCMI_RIOT_IS_ENABLED(unit))) {
   7309 
   7310                 if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit,
   7311                     ecmp_member->egress_if)) {
   7312 
   7313                     return (BCM_E_PARAM);
   7314                 }
   7315             } else
   7316 #endif
   7317             {
   7318                 return (BCM_E_PARAM);
   7319             }
   7320         }
   7321 
   7322         /* Allocate interface array */
   7323         alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   7324         intf_array = sal_alloc(alloc_size, "intf array");
   7325         if (NULL == intf_array) {
   7326             return BCM_E_MEMORY;
   7327         }
   7328         sal_memset(intf_array, 0, alloc_size);
   7329 
   7330         alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   7331         ecmp_member_array = sal_alloc(alloc_size, "ecmp member array");
   7332         if (NULL == ecmp_member_array) {
   7333             sal_free(intf_array);
   7334             return BCM_E_MEMORY;
   7335         }
   7336         sal_memset(ecmp_member_array, 0, alloc_size);
   7337 
   7338         L3_LOCK(unit);
   7339 
   7340         ecmp_info.ecmp_intf = ecmp_group_id;
   7341         rv = bcm_xgs3_l3_ecmp_get(unit, &ecmp_info, BCM_XGS3_L3_ECMP_MAX(unit),
   7342                                   ecmp_member_array, &ecmp_member_count);
   7343         if (BCM_FAILURE(rv)) {
   7344             goto clean_up;
   7345         }
   7346 
   7347 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   7348         if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp_info.dynamic_mode)) {
   7349             rv = bcm_th2_l3_ecmp_dlb_dgm_member_add(
   7350                      unit, &ecmp_info, ecmp_member,
   7351                      ecmp_member_array, &ecmp_member_count);
   7352         } else
   7353 #endif /* BCM_TOMAHAWK2_SUPPORT  ||  BCM_TRIDENT3_SUPPORT */
   7354         {
   7355             /* Check if there is room in ECMP group */
   7356             if (ecmp_member_count == ecmp_info.max_paths) {
   7357                 rv = BCM_E_FULL;
   7358                 goto clean_up;
   7359             }
   7360 
   7361 
   7362             sal_memcpy(&ecmp_member_array[ecmp_member_count], ecmp_member,
   7363                        sizeof(ecmp_member_array[ecmp_member_count]));
   7364             primary_count = ecmp_member_count + 1;
   7365 
   7366             for (i = 0; i <= ecmp_member_count; i++) {
   7367                 intf_array[i] = ecmp_member_array[i].egress_if;
   7368             }
   7369 
   7370             /* Update ECMP group */
   7371             ecmp_info.flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   7372 
   7373             rv = _bcm_esw_l3_ecmp_create(
   7374                      unit, &ecmp_info, ecmp_member_count + 1,
   7375                      intf_array, BCM_L3_ECMP_MEMBER_OP_ADD,
   7376                      1, &ecmp_member->egress_if, primary_count, NULL);
   7377             if (BCM_FAILURE(rv)) {
   7378                 goto clean_up;
   7379             }
   7380 
   7381             rv = _bcm_xgs3_l3_ecmp_member_set(unit, &ecmp_info,
   7382                                               ecmp_member_count + 1, ecmp_member_array);
   7383             if (BCM_FAILURE(rv)) {
   7384                 goto clean_up;
   7385             }
   7386         }
   7387 
   7388 clean_up:
   7389         if (intf_array) {
   7390             sal_free(intf_array);
   7391             intf_array = NULL;
   7392         }
   7393         if (ecmp_member_array) {
   7394             sal_free(ecmp_member_array);
   7395             ecmp_member_array = NULL;
   7396         }
   7397 
   7398         L3_UNLOCK(unit);
   7399     }
   7400 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   7401 
   7402     return rv;
   7403 }
   7404 
   7405 /*
   7406  * Function:
   7407  *      bcm_esw_l3_ecmp_member_delete
   7408  * Purpose:
   7409  *      Delete a member from an Egress ECMP forwarding object.
   7410  * Parameters:
   7411  *      unit          - (IN) bcm device.
   7412  *      ecmp_group_id - (IN) L3 interface ID pointing to Egress
   7413  *                           ECMP forwarding object.
   7414  *      ecmp_member   - (IN) L3 interface id pointing to Egress 
   7415  *                           forwarding object
   7416  * Returns:
   7417  *      BCM_E_XXX
   7418  */
   7419 
   7420 int
   7421 bcm_esw_l3_ecmp_member_delete(
   7422     int unit, 
   7423     bcm_if_t ecmp_group_id, 
   7424     bcm_l3_ecmp_member_t *ecmp_member)
   7425 {
   7426     int rv = BCM_E_UNAVAIL;
   7427 
   7428 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   7429     if (SOC_IS_XGS3_SWITCH(unit) &&
   7430         soc_feature(unit, soc_feature_l3)) {
   7431         int alloc_size;
   7432         bcm_if_t *intf_array = NULL;
   7433         int i, j;
   7434         bcm_l3_egress_ecmp_t ecmp_info;
   7435         int ecmp_member_count;
   7436         bcm_l3_ecmp_member_t *ecmp_member_array = NULL;
   7437         int primary_count;
   7438 
   7439         /* Input check */
   7440         if (ecmp_member == NULL) {
   7441             return BCM_E_PARAM;
   7442         }
   7443         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_group_id)) {
   7444             return (BCM_E_PARAM);
   7445         }
   7446         if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)) {
   7447 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7448             if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
   7449                 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
   7450                                                     ecmp_mode_hierarchical)) {
   7451                 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)) {
   7452                     return (BCM_E_PARAM);
   7453                 }
   7454             } else
   7455 #endif
   7456 #ifdef BCM_RIOT_SUPPORT
   7457             if ((BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) &&
   7458                 (BCMI_RIOT_IS_ENABLED(unit))) {
   7459 
   7460                 if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit,
   7461                     ecmp_member->egress_if)) {
   7462 
   7463                     return (BCM_E_PARAM);
   7464                 }
   7465             } else
   7466 #endif
   7467             {
   7468                 return (BCM_E_PARAM);
   7469             }
   7470         }
   7471 
   7472         /* Allocate interface array */
   7473         alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   7474         intf_array = sal_alloc(alloc_size, "intf array");
   7475         if (NULL == intf_array) {
   7476             return BCM_E_MEMORY;
   7477         }
   7478         sal_memset(intf_array, 0, alloc_size);
   7479 
   7480         alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   7481         ecmp_member_array = sal_alloc(alloc_size, "ecmp member array");
   7482         if (NULL == ecmp_member_array) {
   7483             sal_free(intf_array);
   7484             return BCM_E_MEMORY;
   7485         }
   7486         sal_memset(ecmp_member_array, 0, alloc_size);
   7487 
   7488         L3_LOCK(unit);
   7489 
   7490         /* Get ECMP group's existing member array */
   7491         ecmp_info.ecmp_intf = ecmp_group_id;
   7492         rv = bcm_xgs3_l3_ecmp_get(unit, &ecmp_info, BCM_XGS3_L3_ECMP_MAX(unit),
   7493                                   ecmp_member_array, &ecmp_member_count);
   7494         if (BCM_FAILURE(rv)) {
   7495             goto clean_up;
   7496         }
   7497 
   7498 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   7499         if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp_info.dynamic_mode)) {
   7500 
   7501             rv  = bcm_th2_l3_ecmp_dlb_dgm_member_delete(
   7502                       unit, &ecmp_info, ecmp_member,
   7503                       ecmp_member_array, &ecmp_member_count);
   7504         } else
   7505 #endif /* BCM_TOMAHAWK2_SUPPORT  ||  BCM_TRIDENT3_SUPPORT */
   7506         {
   7507             for (i = 0; i < ecmp_member_count; i++) {
   7508                 intf_array[i] = ecmp_member_array[i].egress_if;
   7509             }
   7510 
   7511             /* Search for given intf */
   7512             for (i = 0; i < ecmp_member_count; i++) {
   7513                 if (intf_array[i] == ecmp_member->egress_if) {
   7514                     break;
   7515                 }
   7516             }
   7517             if (i == ecmp_member_count) {
   7518                 /* Not found */
   7519                 rv = BCM_E_NOT_FOUND;
   7520                 goto clean_up;
   7521             }
   7522 
   7523             primary_count = ecmp_member_count - 1;
   7524 
   7525             /* Shift remaining elements of intf_array */
   7526             for (j = i; j < ecmp_member_count - 1; j++) {
   7527                 intf_array[j] = intf_array[j + 1];
   7528                 sal_memcpy(&ecmp_member_array[j], &ecmp_member_array[j + 1],
   7529                            sizeof(ecmp_member_array[j]));
   7530             }
   7531 
   7532             /* Update ECMP group */
   7533             ecmp_info.flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   7534             rv = _bcm_esw_l3_ecmp_create(unit, &ecmp_info, ecmp_member_count - 1,
   7535                                          intf_array, BCM_L3_ECMP_MEMBER_OP_DELETE,
   7536                                          1, &ecmp_member->egress_if,
   7537                                          primary_count, NULL);
   7538             if (BCM_FAILURE(rv)) {
   7539                 goto clean_up;
   7540             }
   7541 
   7542             rv = _bcm_xgs3_l3_ecmp_member_set(unit, &ecmp_info,
   7543                                               ecmp_member_count - 1, ecmp_member_array);
   7544             if (BCM_FAILURE(rv)) {
   7545                 goto clean_up;
   7546             }
   7547         }
   7548 
   7549 clean_up:
   7550         if (intf_array) {
   7551             sal_free(intf_array);
   7552             intf_array = NULL;
   7553         }
   7554         if (ecmp_member_array) {
   7555             sal_free(ecmp_member_array);
   7556             ecmp_member_array = NULL;
   7557         }
   7558 
   7559         L3_UNLOCK(unit);
   7560     }
   7561 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   7562 
   7563     return rv;
   7564 }
   7565 
   7566 /*
   7567  * Function:
   7568  *      bcm_esw_l3_ecmp_member_delete_all
   7569  * Purpose:
   7570  *      Delete all members from an Egress ECMP forwarding object.
   7571  * Parameters:
   7572  *      unit          - (IN) bcm device.
   7573  *      ecmp_group_id - (IN) L3 interface ID pointing to Egress
   7574  *                           ECMP forwarding object.
   7575  * Returns:
   7576  *      BCM_E_XXX
   7577  */
   7578 
   7579 int
   7580 bcm_esw_l3_ecmp_member_delete_all(
   7581     int unit, 
   7582     bcm_if_t ecmp_group_id)
   7583 {
   7584     int rv = BCM_E_UNAVAIL;
   7585 
   7586 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   7587     if (SOC_IS_XGS3_SWITCH(unit) && 
   7588         soc_feature(unit, soc_feature_l3)) {
   7589         int i, alloc_size;
   7590         bcm_l3_egress_ecmp_t ecmp_info;
   7591         int ecmp_member_count;
   7592         bcm_l3_ecmp_member_t *ecmp_member_array = NULL;
   7593 
   7594         L3_LOCK(unit);
   7595 
   7596         bcm_l3_egress_ecmp_t_init(&ecmp_info);
   7597 
   7598         ecmp_info.ecmp_intf = ecmp_group_id;
   7599 
   7600         rv = bcm_esw_l3_ecmp_get(unit, &ecmp_info, 0, 
   7601                                  NULL, &ecmp_member_count);
   7602         if (BCM_FAILURE(rv)) {
   7603             goto clean_up;
   7604         }
   7605         if (ecmp_member_count > 0) {
   7606             alloc_size = ecmp_member_count * sizeof(bcm_l3_ecmp_member_t);
   7607             ecmp_member_array = sal_alloc(alloc_size, "ecmp_member_array");
   7608             if (ecmp_member_array == NULL) {
   7609                 rv = BCM_E_MEMORY;
   7610                 goto clean_up;
   7611             }
   7612             sal_memset(ecmp_member_array, 0, alloc_size);
   7613 
   7614             rv = bcm_esw_l3_ecmp_get(unit, &ecmp_info, ecmp_member_count, 
   7615                                      ecmp_member_array, &ecmp_member_count);
   7616             if (BCM_FAILURE(rv)) {
   7617                 goto clean_up;
   7618             }
   7619 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7620             /* Update ECMP group */
   7621          if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
   7622              (ecmp_mode_hierarchical ==
   7623               BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode) &&
   7624               ((BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2) >
   7625                (ecmp_group_id - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) {
   7626             ecmp_info.flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   7627             rv = _bcm_esw_l3_ecmp_create(unit, &ecmp_info, 0,
   7628                                          NULL, BCM_L3_ECMP_MEMBER_OP_REPLACE,
   7629                                          0, NULL,
   7630                                          0, NULL);
   7631             if (BCM_FAILURE(rv)) {
   7632                 goto clean_up;
   7633             }
   7634 
   7635             rv = _bcm_xgs3_l3_ecmp_member_set(unit, &ecmp_info,
   7636                                               ecmp_member_count - 1, ecmp_member_array);
   7637             if (BCM_FAILURE(rv)) {
   7638                 goto clean_up;
   7639             }
   7640          } else
   7641 #endif
   7642          {
   7643 
   7644             for (i = 0; i < ecmp_member_count; i++) {
   7645                 rv = bcm_esw_l3_ecmp_member_delete(unit, ecmp_info.ecmp_intf,
   7646                                                    &ecmp_member_array[i]);
   7647                 if (BCM_FAILURE(rv)) {
   7648                     goto clean_up;
   7649                 }
   7650             }
   7651         }
   7652         }
   7653 clean_up:
   7654         if (ecmp_member_array) {
   7655             sal_free(ecmp_member_array);
   7656             ecmp_member_array = NULL;
   7657         }
   7658 
   7659         L3_UNLOCK(unit);
   7660     }
   7661 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   7662 
   7663     return rv;
   7664 }
   7665 
   7666 /*
   7667  * Function:
   7668  *      bcm_esw_l3_ecmp_find
   7669  * Purpose:
   7670  *      Find an Egress ECMP forwarding object.     
   7671  * Parameters:
   7672  *      unit              - (IN) bcm device.
   7673  *      ecmp_member_count - (IN) Number of elements in ecmp_member_array. 
   7674  *      ecmp_member_array - (IN) Member array of Egress forwarding objects.  
   7675  *      ecmp_info         - (OUT) ECMP group info.
   7676  * Returns:
   7677  *      BCM_E_XXX
   7678  */
   7679 
   7680 int
   7681 bcm_esw_l3_ecmp_find(
   7682     int unit, 
   7683     int ecmp_member_count, 
   7684     bcm_l3_ecmp_member_t *ecmp_member_array, 
   7685     bcm_l3_egress_ecmp_t *ecmp_info)
   7686 {
   7687     int rv = BCM_E_UNAVAIL;
   7688 
   7689 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   7690     if (SOC_IS_XGS3_SWITCH(unit) && 
   7691         soc_feature(unit, soc_feature_l3)) {
   7692         L3_LOCK(unit);
   7693         rv = bcm_xgs3_l3_ecmp_find(unit, ecmp_member_count, ecmp_member_array,
   7694                                    ecmp_info);
   7695         L3_UNLOCK(unit);
   7696     }
   7697 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   7698 
   7699     return rv;
   7700 }
   7701 
   7702 /*
   7703  * Function:
   7704  *      bcm_esw_l3_ecmp_traverse
   7705  * Purpose:
   7706  *      Goes through Egress ECMP forwarding objects table and runs the 
   7707  *      user callback function at each Egress ECMP forwarding objects 
   7708  *      entry passing back the information for that ECMP object.
   7709  * Parameters:
   7710  *      unit       - (IN) bcm device.
   7711  *      trav_fn    - (IN) Callback function. 
   7712  *      user_data  - (IN) User data to be passed to callback function.
   7713  * Returns:
   7714  *      BCM_E_XXX
   7715  */
   7716 
   7717 int
   7718 bcm_esw_l3_ecmp_traverse(
   7719     int unit, 
   7720     bcm_l3_ecmp_traverse_cb trav_fn, 
   7721     void *user_data)
   7722 {
   7723     int rv = BCM_E_UNAVAIL;
   7724 
   7725 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   7726     if (SOC_IS_XGS3_SWITCH(unit) && 
   7727         soc_feature(unit, soc_feature_l3)) {
   7728         L3_LOCK(unit);
   7729         rv = bcm_xgs3_l3_ecmp_traverse(unit, trav_fn, user_data);
   7730         L3_UNLOCK(unit);
   7731     }
   7732 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   7733 
   7734     return rv;
   7735 }
   7736 
   7737 #ifdef BCM_TOMAHAWK_SUPPORT
   7738 
   7739 STATIC int
   7740 _bcm_th_l3_ecmp_agm_update(int unit,
   7741                            bcm_if_t l3_ecmp_id, bcm_switch_agm_type_t agm_type,
   7742                            int agm_pool_id, int agm_index)
   7743 {
   7744     int rv, ecmp_index;
   7745     uint32 mpath_flag;
   7746     int ecmp_group_id;
   7747     ecmp_count_entry_t ecmpc_entry;
   7748     soc_mem_t mem = L3_ECMP_COUNTm;
   7749 
   7750     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit) == 0) {
   7751         return BCM_E_UNAVAIL;
   7752     }
   7753 
   7754     /* Check l3_ecmp_id */
   7755     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3_ecmp_id)) {
   7756         return BCM_E_PARAM;
   7757     }
   7758 
   7759     rv = bcm_xgs3_get_nh_from_egress_object(unit, l3_ecmp_id, &mpath_flag,
   7760                                             0, &ecmp_group_id);
   7761     if (BCM_FAILURE(rv)) {
   7762         return BCM_E_PARAM;
   7763     }
   7764     if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
   7765         ecmp_index = ecmp_group_id * BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
   7766     } else {
   7767         ecmp_index = ecmp_group_id;
   7768     }
   7769 
   7770 #ifdef BCM_TOMAHAWK3_SUPPORT
   7771     /* Check if the given ecmp itf is hierarchial */
   7772     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
   7773         (ecmp_mode_hierarchical ==
   7774          BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode) &&
   7775         ((BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2) >
   7776          (l3_ecmp_id - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) {
   7777 
   7778         /* Check that AGMTYPE is overlay if the ecmp intf is hierarchial */
   7779         if (bcmSwitchAgmTypeL3EcmpOverlay != agm_type) {
   7780             return (BCM_E_PARAM);
   7781         }
   7782 
   7783         /* Choose the correct memory based on the AGM type */
   7784         if (soc_mem_is_valid(unit, ECMP_GROUP_HIERARCHICALm)) {
   7785             mem = ECMP_GROUP_HIERARCHICALm;
   7786         }
   7787     }
   7788 #endif
   7789 
   7790     /* l3_ecmp group entry */
   7791     SOC_IF_ERROR_RETURN
   7792         (soc_mem_read(unit, mem, MEM_BLOCK_ANY, ecmp_index, &ecmpc_entry));
   7793     soc_mem_field32_set(
   7794         unit, mem, &ecmpc_entry, AGM_MONITOR_POOL_IDf, agm_pool_id);
   7795     soc_mem_field32_set(unit, mem, &ecmpc_entry, AGM_MONITOR_IDf, agm_index);
   7796 
   7797 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
   7798     if (soc_feature(unit, soc_feature_dgm) &&
   7799         soc_feature(unit, soc_feature_agm_support_for_dgm)) {
   7800         int count;
   7801         bcm_l3_egress_ecmp_t ecmp_info;
   7802         bcm_l3_egress_ecmp_t_init(&ecmp_info);
   7803         ecmp_info.ecmp_intf = ecmp_group_id + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   7804         rv = bcm_xgs3_l3_ecmp_get(unit, &ecmp_info, 0, NULL, &count);
   7805 
   7806         if (SOC_SUCCESS(rv) &&
   7807             ecmp_info.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   7808             if (0 == agm_index) { /* detach */
   7809                 count -= BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[ecmp_index];
   7810             }
   7811             soc_mem_field32_set(unit, mem, &ecmpc_entry, COUNTf, count - 1);
   7812         }
   7813     }
   7814 #endif
   7815     SOC_IF_ERROR_RETURN
   7816         (soc_mem_write(unit, mem, MEM_BLOCK_ANY, ecmp_index, &ecmpc_entry));
   7817 
   7818     return rv;
   7819 }
   7820 
   7821 /*
   7822  * Function:
   7823  *      bcm_th_l3_ecmp_agm_attach
   7824  * Purpose:
   7825  *      Attach already created monitor entry to a l3 ecmp group
   7826  *      Internally, Map the monitor_entry_id to an aggregation
   7827  *      group (l3 ecmp group).
   7828  */
   7829 int
   7830 bcm_th_l3_ecmp_agm_attach(int unit, bcm_if_t l3_ecmp_id,
   7831                           bcm_switch_agm_id_t agm_id)
   7832 {
   7833     int rv = BCM_E_NONE;
   7834     agm_monitor_t agm_mnt;
   7835     bcm_switch_agm_id_t agm_id_old;
   7836     int agm_pool_id;
   7837     uint32 agm_index;
   7838     int mbm_cnt = 0, mbm_max;
   7839     bcm_if_t *mbm_arr;
   7840 
   7841     /* Validate parameters */
   7842     if (!SOC_UNIT_VALID(unit)) {
   7843         return BCM_E_UNIT;
   7844     }
   7845     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3_ecmp_id)) {
   7846         return BCM_E_PARAM;
   7847     }
   7848 
   7849     BCM_IF_ERROR_RETURN(bcm_th_switch_agm_info(unit, agm_id, &agm_mnt));
   7850     if ((agm_mnt.attr.agm_type != bcmSwitchAgmTypeL3Ecmp) &&
   7851         (agm_mnt.attr.agm_type != bcmSwitchAgmTypeL3EcmpOverlay)) {
   7852         return BCM_E_PARAM;
   7853     }
   7854 
   7855     if (agm_mnt.group_id == (int)l3_ecmp_id) {
   7856         return BCM_E_EXISTS;
   7857     }
   7858 
   7859     mbm_max = agm_mnt.attr.num_members;
   7860     mbm_arr = sal_alloc(mbm_max * sizeof(*mbm_arr), "mbm_arr");
   7861     if (mbm_arr == NULL) {
   7862         return BCM_E_MEMORY;
   7863     }
   7864 
   7865     rv = bcm_esw_l3_egress_multipath_get(unit, l3_ecmp_id, mbm_max,
   7866                                          mbm_arr, &mbm_cnt);
   7867     sal_free(mbm_arr);
   7868     if (BCM_FAILURE(rv)) {
   7869         return rv;
   7870     }
   7871     if (mbm_cnt != agm_mnt.attr.num_members) {
   7872         LOG_VERBOSE(BSL_LS_BCM_L3, (BSL_META_U(unit,
   7873                     "AGM %d member cnt %d doesn't match ECMP %d member cnt %d\n"), 
   7874                     agm_id, agm_mnt.attr.num_members, l3_ecmp_id, mbm_cnt));
   7875         return BCM_E_PARAM;
   7876     }
   7877 
   7878 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7879     if (SOC_IS_TOMAHAWK3(unit)) {
   7880         BCM_IF_ERROR_RETURN(
   7881             bcm_th3_switch_agm_l3_ecmp_stat_destroy(unit, agm_id));
   7882         BCM_IF_ERROR_RETURN(
   7883             bcm_th3_switch_agm_l3_ecmp_stat_create(unit, agm_id, l3_ecmp_id));
   7884     }
   7885 #endif /* BCM_TOMAHAWK3_SUPPORT */
   7886 
   7887     agm_pool_id = agm_mnt.agm_pool_id;
   7888     agm_index   = agm_mnt.attr.agm_id;
   7889 
   7890     rv = _bcm_th_l3_ecmp_agm_update(unit, l3_ecmp_id,
   7891             agm_mnt.attr.agm_type, agm_pool_id, agm_index);
   7892     if (BCM_FAILURE(rv)) {
   7893 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7894         if (SOC_IS_TOMAHAWK3(unit)) {
   7895             bcm_th3_switch_agm_l3_ecmp_stat_destroy(unit, agm_id);
   7896         }
   7897 #endif /* BCM_TOMAHAWK3_SUPPORT */
   7898         return rv;
   7899     }
   7900 
   7901     /* in case of changing AGM, detach the old AGM first */
   7902     if (BCM_SUCCESS(bcm_th_switch_agm_id_get_by_group(unit, l3_ecmp_id, 
   7903                     &agm_id_old))) {
   7904         BCM_IF_ERROR_RETURN(bcm_th_switch_agm_fwd_grp_update(unit, agm_id_old, 
   7905                     _AGM_GROUP_ID_INVALID));
   7906     }
   7907 
   7908     BCM_IF_ERROR_RETURN(bcm_th_switch_agm_fwd_grp_update(unit, agm_id,
   7909                                                          l3_ecmp_id));
   7910     return rv;
   7911 }
   7912 
   7913 /*
   7914  * Function:
   7915  *      bcm_th_l3_ecmp_agm_detach
   7916  * Purpose:
   7917  *      Detach a monitor entry from a l3 ecmp group
   7918  *      Internally, un-map the monitor_entry_id from an aggregation
   7919  *      group (l3 ecmp group).
   7920  */
   7921 int
   7922 bcm_th_l3_ecmp_agm_detach(int unit, bcm_if_t l3_ecmp_id,
   7923                           bcm_switch_agm_id_t agm_id)
   7924 {
   7925     int rv = BCM_E_NONE;
   7926     agm_monitor_t agm_mnt;
   7927 
   7928     /* Validate parameters */
   7929     if (!SOC_UNIT_VALID(unit)) {
   7930         return BCM_E_UNIT;
   7931     }
   7932     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3_ecmp_id)) {
   7933         return BCM_E_PARAM;
   7934     }
   7935 
   7936     BCM_IF_ERROR_RETURN(bcm_th_switch_agm_info(unit, agm_id, &agm_mnt));
   7937     if ((agm_mnt.attr.agm_type != bcmSwitchAgmTypeL3Ecmp) &&
   7938         (agm_mnt.attr.agm_type != bcmSwitchAgmTypeL3EcmpOverlay)) {
   7939         return BCM_E_PARAM;
   7940     }
   7941 
   7942     if (agm_mnt.group_id != (int)l3_ecmp_id) {
   7943         return BCM_E_NOT_FOUND;
   7944     }
   7945 
   7946     BCM_IF_ERROR_RETURN(_bcm_th_l3_ecmp_agm_update(unit, l3_ecmp_id,
   7947                                                   agm_mnt.attr.agm_type, 0, 0));
   7948     BCM_IF_ERROR_RETURN(bcm_th_switch_agm_fwd_grp_update(unit, agm_id, -1));
   7949 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7950     if (SOC_IS_TOMAHAWK3(unit)) {
   7951         BCM_IF_ERROR_RETURN(bcm_th3_switch_agm_l3_ecmp_stat_destroy(unit, agm_id));
   7952     }
   7953 #endif /* BCM_TOMAHAWK3_SUPPORT */
   7954 
   7955     return rv;
   7956 }
   7957 
   7958 /*
   7959  * Function:
   7960  *      bcm_th_l3_ecmp_agm_attach_get
   7961  * Purpose:
   7962  *      Retrieve a monitor id attached to a l3 ecmp group.
   7963  */
   7964 int
   7965 bcm_th_l3_ecmp_agm_attach_get(int unit, bcm_if_t l3_ecmp_id,
   7966                               bcm_switch_agm_id_t *agm_id)
   7967 {
   7968     /* Validate parameters */
   7969     if (!SOC_UNIT_VALID(unit)) {
   7970         return BCM_E_UNIT;
   7971     }
   7972     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3_ecmp_id)) {
   7973         return BCM_E_PARAM;
   7974     }
   7975 
   7976     return bcm_th_switch_agm_id_get_by_group(unit, l3_ecmp_id, agm_id);
   7977 }
   7978 
   7979 #endif /* BCM_TOMAHAWK_SUPPORT */
   7980 
   7981 /*
   7982  * Function:
   7983  *      bcm_esw_l3_ecmp_agm_attach
   7984  * Purpose:
   7985  *      Attach already created monitor entry to a l3 ecmp group
   7986  *      Internally, Map the monitor_entry_id to an aggregation
   7987  *      group (l3 ecmp group).
   7988  * Parameters:
   7989  *      unit       - (IN) bcm device.
   7990  *      l3_ecmp_id - (IN) ecmp group id.
   7991  *      agm_id     - (IN) id of aggregation group monitoring entry created
   7992  *                        via the bcm_switch_agm_create api.
   7993  * Returns:
   7994  *      BCM_E_NONE: if the attachment is succeed
   7995  *      BCM_E_PARAM: if the monitor_id is not valid or the monitor
   7996  *                   entry is not created. If the ecmp id is not valid
   7997  *      BCM_E_FULL: if a monitor entry is already attached to
   7998  *      BCM_E_PARAM: if number of l3 ecmp member is different from the
   7999  *                   number on the monitor entry
   8000  */
   8001 int
   8002 bcm_esw_l3_ecmp_agm_attach(int unit, bcm_if_t l3_ecmp_id,
   8003                            bcm_switch_agm_id_t agm_id)
   8004 {
   8005     int rv = BCM_E_UNAVAIL;
   8006 #if defined(BCM_TOMAHAWK_SUPPORT)
   8007     if (soc_feature(unit, soc_feature_agm) &&
   8008         soc_feature(unit, soc_feature_l3)) {
   8009         L3_LOCK(unit);
   8010         rv = bcm_th_l3_ecmp_agm_attach(unit, l3_ecmp_id, agm_id);
   8011         L3_UNLOCK(unit);
   8012     }
   8013 #endif /* BCM_TOMAHAWK_SUPPORT */
   8014     return rv;
   8015 }
   8016 
   8017 /*
   8018  * Function:
   8019  *      bcm_esw_l3_ecmp_agm_detach
   8020  * Purpose:
   8021  *      Detach a monitor entry from a l3 ecmp group
   8022  *      Internally, un-map the monitor_entry_id from an aggregation
   8023  *      group (l3 ecmp group).
   8024  * Parameters:
   8025  *      unit       - (IN) bcm device.
   8026  *      l3_ecmp_id - (IN) ecmp group id.
   8027  *      agm_id     - (IN) id of aggregation group monitoring entry created
   8028  *                        via the bcm_switch_agm_create api.
   8029  * Returns:
   8030  *      BCM_E_NONE: if the enable or disable is succeed
   8031  *      BCM_E_PARAM: If the ecmp id is not valid
   8032  *      BCM_E_NOT_FOUND: if no monitor entry is attached to the
   8033  *                       aggregation group.
   8034  */
   8035 int
   8036 bcm_esw_l3_ecmp_agm_detach(int unit, bcm_if_t l3_ecmp_id,
   8037                            bcm_switch_agm_id_t agm_id)
   8038 {
   8039     int rv = BCM_E_UNAVAIL;
   8040 #if defined(BCM_TOMAHAWK_SUPPORT)
   8041     if (soc_feature(unit, soc_feature_agm) &&
   8042         soc_feature(unit, soc_feature_l3)) {
   8043         L3_LOCK(unit);
   8044         rv = bcm_th_l3_ecmp_agm_detach(unit, l3_ecmp_id, agm_id);
   8045         L3_UNLOCK(unit);
   8046     }
   8047 #endif /* BCM_TOMAHAWK_SUPPORT */
   8048     return rv;
   8049 }
   8050 
   8051 /*
   8052  * Function:
   8053  *      bcm_esw_l3_ecmp_agm_attach_get
   8054  * Purpose:
   8055  *      Retrieve a monitor id attached to a l3 ecmp group.
   8056  * Parameters:
   8057  *      unit       - (IN) bcm device.
   8058  *      l3_ecmp_id - (IN) ecmp group id.
   8059  *      agm_id     - (IN/OUT) aggregation group monitoring entry.
   8060  * Returns:
   8061  *      BCM_E_NONE: if monitor entry id found
   8062  *      BCM_E_NOT_FOUND: if no monitor entry is attached to the
   8063  *                       aggregation group.
   8064  */
   8065 int
   8066 bcm_esw_l3_ecmp_agm_attach_get(int unit, bcm_if_t l3_ecmp_id,
   8067                                bcm_switch_agm_id_t *agm_id)
   8068 {
   8069     int rv = BCM_E_UNAVAIL;
   8070 #if defined(BCM_TOMAHAWK_SUPPORT)
   8071     if (soc_feature(unit, soc_feature_agm) &&
   8072         soc_feature(unit, soc_feature_l3)) {
   8073         L3_LOCK(unit);
   8074         rv = bcm_th_l3_ecmp_agm_attach_get(unit, l3_ecmp_id, agm_id);
   8075         L3_UNLOCK(unit);
   8076     }
   8077 #endif /* BCM_TOMAHAWK_SUPPORT */
   8078     return rv;
   8079 }
   8080 
   8081 /*
   8082  * Function:
   8083  *      bcm_esw_l3_egress_ecmp_create 
   8084  * Purpose:
   8085  *      Create or modify an Egress ECMP forwarding object.
   8086  * Parameters:
   8087  *      unit       - (IN) bcm device.
   8088  *      ecmp       - (INOUT) ECMP group info.
   8089  *      intf_count - (IN) Number of elements in intf_array.
   8090  *      intf_array - (IN) Array of Egress forwarding objects.
   8091  * Returns:
   8092  *      BCM_E_XXX
   8093  */
   8094 int 
   8095 bcm_esw_l3_egress_ecmp_create(int unit, bcm_l3_egress_ecmp_t *ecmp,
   8096         int intf_count, bcm_if_t *intf_array)
   8097 {
   8098     int rv;
   8099 
   8100     if (ecmp == NULL) {
   8101         return (BCM_E_PARAM);
   8102     }
   8103     if ((soc_feature(unit, soc_feature_ecmp_resilient_hash) ||
   8104          soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) &&
   8105         (ecmp->flags & BCM_L3_ECMP_RH_REPLACE)) {
   8106         int alloc_size, old_intf_count;
   8107         bcm_if_t *old_intf_array = NULL;
   8108         int i;
   8109 
   8110         /* Input check */
   8111         if (intf_count > 0 && intf_array == NULL) {
   8112             return (BCM_E_PARAM);
   8113         }
   8114 
   8115         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   8116             return (BCM_E_PARAM);
   8117         }
   8118 
   8119         for (i = 0; i < intf_count; i++) {
   8120             if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) {
   8121 #if defined(BCM_TOMAHAWK3_SUPPORT)
   8122                 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) {
   8123                     if (!(BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[i]))
   8124                         || !(BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
   8125                                       ecmp_mode_hierarchical)) {
   8126                 return (BCM_E_PARAM);
   8127             }
   8128                 } else
   8129 #endif
   8130                 {
   8131                     return (BCM_E_PARAM);
   8132                 }
   8133             }
   8134         }
   8135 
   8136         /* Allocate interface array */
   8137         alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   8138         old_intf_array = sal_alloc(alloc_size, "old intf array");
   8139         if (NULL == old_intf_array) {
   8140             return BCM_E_MEMORY;
   8141         }
   8142         sal_memset(old_intf_array, 0, alloc_size);
   8143 
   8144         L3_LOCK(unit);
   8145 
   8146         /* Get ECMP group's existing interface array */
   8147         rv = _bcm_esw_l3_egress_ecmp_get(unit, ecmp, BCM_XGS3_L3_ECMP_MAX(unit),
   8148                 old_intf_array, &old_intf_count, TRUE);
   8149         if (BCM_FAILURE(rv)) {
   8150             sal_free(old_intf_array);
   8151             L3_UNLOCK(unit);
   8152             return rv;
   8153         }
   8154 
   8155         /* Check if there is room in ECMP group */
   8156         if ((old_intf_count == ecmp->max_paths) &&
   8157             (intf_count > old_intf_count)) {
   8158             sal_free(old_intf_array);
   8159             L3_UNLOCK(unit);
   8160             return BCM_E_FULL;
   8161         }
   8162 
   8163         if (intf_count > ecmp->max_paths) {
   8164             sal_free(old_intf_array);
   8165             L3_UNLOCK(unit);
   8166             return BCM_E_RESOURCE;
   8167         }
   8168 
   8169         /* Update ECMP group */
   8170         ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   8171         rv = _bcm_esw_l3_ecmp_create(unit, ecmp, intf_count, intf_array,
   8172                 BCM_L3_ECMP_MEMBER_OP_REPLACE, old_intf_count, old_intf_array,
   8173                 intf_count, NULL);
   8174         sal_free(old_intf_array);
   8175         L3_UNLOCK(unit);
   8176     } else {
   8177 
   8178 
   8179 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8180         if (BCM_TH2_ECMP_IS_DLB(unit, ecmp->dynamic_mode)) {
   8181             L3_LOCK(unit);
   8182             rv = bcm_th2_l3_ecmp_dlb_member_create(unit, ecmp,
   8183                                                    intf_array, intf_count);
   8184             L3_UNLOCK(unit);
   8185         } else
   8186 #endif /* BCM_TOMAHAWK2_SUPPORT  ||  BCM_TRIDENT3_SUPPORT */
   8187         {
   8188             rv = _bcm_esw_l3_ecmp_create(unit, ecmp, intf_count,
   8189                                          intf_array, BCM_L3_ECMP_MEMBER_OP_SET,
   8190                                          0, NULL, intf_count, NULL);
   8191         }
   8192     }
   8193 
   8194     return rv;
   8195 }
   8196 
   8197 /*
   8198  * Function:
   8199  *      bcm_esw_l3_egress_ecmp_destroy
   8200  * Purpose:
   8201  *      Destroy an Egress ECMP forwarding object.
   8202  * Parameters:
   8203  *      unit    - (IN) bcm device.
   8204  *      ecmp    - (IN) ECMP group info.
   8205  * Returns:
   8206  *      BCM_E_XXX
   8207  */
   8208 int 
   8209 bcm_esw_l3_egress_ecmp_destroy(int unit, bcm_l3_egress_ecmp_t *ecmp) 
   8210 {
   8211     int rv = BCM_E_UNAVAIL;
   8212 
   8213 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   8214     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   8215         L3_LOCK(unit);
   8216         rv = bcm_xgs3_l3_egress_multipath_destroy(unit, ecmp->ecmp_intf);
   8217 
   8218 #ifdef BCM_TRIUMPH3_SUPPORT
   8219         if (BCM_SUCCESS(rv)) {
   8220             if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   8221 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8222                 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   8223                     rv = bcm_th2_l3_egress_ecmp_dlb_destroy(unit, ecmp->ecmp_intf);
   8224                 } else
   8225 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   8226                 {
   8227                     rv = bcm_tr3_l3_egress_ecmp_dlb_destroy(unit, ecmp->ecmp_intf);
   8228                 }
   8229             }
   8230         }
   8231 #endif /* BCM_TRIUMPH3_SUPPORT */
   8232 
   8233 #ifdef BCM_TRIDENT2_SUPPORT
   8234         if (BCM_SUCCESS(rv)) {
   8235             if (soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   8236 #ifdef BCM_TRIDENT3_SUPPORT
   8237                 int lb_mode = 0;
   8238                 int ecmp_group;
   8239                 ecmp_count_entry_t ecmp_count_entry;
   8240 
   8241                 if (SOC_IS_TRIDENT3X(unit)) {
   8242                    if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   8243                        ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   8244 
   8245                        BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
   8246                                    ecmp_group, &ecmp_count_entry));
   8247                        lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit,
   8248                                           &ecmp_count_entry, LB_MODEf);
   8249                    }
   8250                 }
   8251 #endif
   8252                 if ( (!(SOC_IS_TRIDENT3X(unit))) 
   8253 #ifdef BCM_TRIDENT3_SUPPORT
   8254                       || (lb_mode == BCM_ECMP_LB_MODE_ENHANCED_HASH)
   8255 #endif
   8256                    ) {
   8257                     rv = bcm_td2_l3_egress_ecmp_rh_destroy(unit, ecmp->ecmp_intf);
   8258                 }
   8259             }
   8260         }
   8261 #endif /* BCM_TRIDENT2_SUPPORT */
   8262 
   8263 #ifdef BCM_TOMAHAWK_SUPPORT
   8264         if (BCM_SUCCESS(rv) &&
   8265             soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   8266             rv = bcm_opt_l3_egress_ecmp_rh_destroy(unit, ecmp->ecmp_intf);
   8267         }
   8268         if (BCM_SUCCESS(rv) &&
   8269             (SOC_IS_TRIDENT3X(unit) || soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized))) {
   8270             rv = bcm_opt_ecmp_lb_mode_reset(unit, ecmp->ecmp_intf);
   8271         }
   8272         if (BCM_SUCCESS(rv) && soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   8273             BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit),
   8274                                                BCM_L3_ECMP_UNDERLAY);
   8275             BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit),
   8276                                                BCM_L3_ECMP_OVERLAY);
   8277         }
   8278 #endif /* BCM_TOMAHAWK_SUPPORT */
   8279 
   8280         L3_UNLOCK(unit);
   8281 
   8282     }
   8283 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   8284 
   8285     return rv;
   8286 }
   8287 
   8288 /*
   8289  * Function:
   8290  *      bcm_esw_l3_egress_ecmp_get
   8291  * Purpose:
   8292  *      Get an Egress ECMP forwarding object.
   8293  * Parameters:
   8294  *      unit    - (IN) bcm device.
   8295  *      ecmp    - (INOUT) ECMP group info.
   8296  *      intf_size  - (IN) Size of allocated entries in intf_array.
   8297  *      intf_array - (OUT) Array of Egress forwarding objects.
   8298  *      intf_count - (OUT) Number of entries of intf_count actually filled in.
   8299  *                      This will be a value less than or equal to the value.
   8300  *                      passed in as intf_size unless intf_size is 0.  If
   8301  *                      intf_size is 0 then intf_array is ignored and
   8302  *                      intf_count is filled in with the number of entries
   8303  *                      that would have been filled into intf_array if
   8304  *                      intf_size was arbitrarily large.
   8305  * Returns:
   8306  *      BCM_E_XXX
   8307  */
   8308 int 
   8309 bcm_esw_l3_egress_ecmp_get(int unit, bcm_l3_egress_ecmp_t *ecmp, int intf_size,
   8310                                 bcm_if_t *intf_array, int *intf_count)
   8311 {
   8312     int rv = BCM_E_UNAVAIL;
   8313 
   8314 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   8315 
   8316     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   8317 
   8318 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8319         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)){
   8320             SHR_BITDCL *group_bitmap_ptr = NULL;
   8321             int         ecmp_group_idx   = 0;
   8322 
   8323             if ((NULL == ecmp) ||
   8324                 !BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   8325                 return (BCM_E_PARAM);
   8326             }
   8327 
   8328             ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   8329 
   8330             group_bitmap_ptr =
   8331                 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   8332 
   8333             L3_LOCK(unit);
   8334             if (!SHR_BITNULL_RANGE(group_bitmap_ptr, 0,
   8335                                    BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit))) {
   8336                 rv = bcm_th2_l3_ecmp_dlb_member_get(unit, ecmp, intf_size,
   8337                                                     intf_array, intf_count);
   8338             } else {
   8339                 rv = _bcm_esw_l3_egress_ecmp_get(unit, ecmp, intf_size,
   8340                                                  intf_array, intf_count, TRUE);
   8341             }
   8342             L3_UNLOCK(unit);
   8343         } else
   8344 #endif /* BCM_TOMAHAWK2_SUPPORT  || BCM_TRIDENT3_SUPPORT*/
   8345         {
   8346             rv = _bcm_esw_l3_egress_ecmp_get(unit, ecmp, intf_size,
   8347                                              intf_array, intf_count, TRUE);
   8348         }
   8349     }
   8350 
   8351 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   8352 
   8353     return rv;
   8354 }
   8355 
   8356 /*
   8357  * Function:
   8358  *      bcm_esw_l3_egress_ecmp_add
   8359  * Purpose:
   8360  *      Add an Egress forwarding object to an Egress ECMP 
   8361  *      forwarding object.
   8362  * Parameters:
   8363  *      unit    - (IN) bcm device.
   8364  *      ecmp    - (IN) ECMP group info.
   8365  *      intf    - (IN) L3 interface id pointing to Egress forwarding object.
   8366  * Returns:
   8367  *      BCM_E_XXX
   8368  */
   8369 int 
   8370 bcm_esw_l3_egress_ecmp_add(int unit, bcm_l3_egress_ecmp_t *ecmp, bcm_if_t intf)
   8371 {
   8372     int rv = BCM_E_UNAVAIL;
   8373 
   8374 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   8375     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   8376         int alloc_size;
   8377         bcm_if_t *intf_array;
   8378         int intf_count;
   8379 
   8380         /* Input check */
   8381         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   8382             return (BCM_E_PARAM);
   8383         }
   8384 
   8385         if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   8386 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   8387             if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   8388 
   8389 #if defined(BCM_RIOT_SUPPORT)
   8390                 if (BCMI_RIOT_IS_ENABLED(unit)) {
   8391                     if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   8392                         if (!soc_feature(unit, soc_feature_multi_level_ecmp)) {
   8393                             return (BCM_E_PARAM);
   8394                         }
   8395                         else if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
   8396                             return (BCM_E_PARAM);
   8397                         }
   8398                     }
   8399                 } else
   8400 #endif
   8401                 {
   8402                     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
   8403                         return (BCM_E_PARAM);
   8404                     }
   8405                 }
   8406             } else
   8407 #endif
   8408             if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   8409                 if (!soc_feature(unit,soc_feature_virtual_port_routing)) {
   8410                     return (BCM_E_PARAM);
   8411                 }
   8412             } else {
   8413                 if (!soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   8414                     return (BCM_E_PARAM);
   8415                 } else {
   8416                     /* In Hierarchical/Multi-level ecmp mode, member can 
   8417                      * be another ECMP group
   8418                      */
   8419                     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
   8420                         return (BCM_E_PARAM);
   8421                     }
   8422                 }
   8423             }
   8424         }
   8425 
   8426         /* Allocate interface array */
   8427         alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   8428         intf_array = sal_alloc(alloc_size, "intf array");
   8429         if (NULL == intf_array) {
   8430             return BCM_E_MEMORY;
   8431         }
   8432         sal_memset(intf_array, 0, alloc_size);
   8433 
   8434         L3_LOCK(unit);
   8435         /* Get ECMP group's existing interface array */
   8436         rv = _bcm_esw_l3_egress_ecmp_get(unit, ecmp, BCM_XGS3_L3_ECMP_MAX(unit),
   8437                 intf_array, &intf_count, TRUE);
   8438         if (BCM_FAILURE(rv)) {
   8439             sal_free(intf_array);
   8440             L3_UNLOCK(unit);
   8441             return rv;
   8442         }
   8443 
   8444         /* Check if there is room in ECMP group */
   8445 #ifdef BCM_TOMAHAWK_SUPPORT
   8446         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   8447             (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT)) {
   8448             if (intf_count == BCM_XGS3_L3_ECMP_RH_MAX_PATHS(unit)) {
   8449                 sal_free(intf_array);
   8450                 L3_UNLOCK(unit);
   8451                 return BCM_E_RESOURCE;
   8452             }
   8453         }
   8454 #ifdef BCM_TOMAHAWK_SUPPORT
   8455         else if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
   8456                  (ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) &&
   8457                  (intf_count > 1)) {
   8458                 sal_free(intf_array);
   8459                 L3_UNLOCK(unit);
   8460                 return BCM_E_PARAM;
   8461         }
   8462 #endif
   8463 #endif
   8464 
   8465 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8466         if (BCM_TH2_ECMP_IS_DLB(unit, ecmp->dynamic_mode)) {
   8467             rv = bcm_th2_l3_ecmp_dlb_member_add(unit, ecmp, intf,
   8468                                                 intf_array, &intf_count);
   8469         } else
   8470 #endif /* BCM_TOMAHAWK2_SUPPORT  ||  BCM_TRIDENT3_SUPPORT */
   8471         {
   8472             /* Check if there is room in ECMP group */
   8473             if (intf_count == ecmp->max_paths) {
   8474                 sal_free(intf_array);
   8475                 L3_UNLOCK(unit);
   8476                 return BCM_E_FULL;
   8477             }
   8478             intf_array[intf_count] = intf;
   8479 
   8480             /* Update ECMP group */
   8481             ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   8482             rv = _bcm_esw_l3_ecmp_create(unit, ecmp, intf_count + 1,
   8483                     intf_array, BCM_L3_ECMP_MEMBER_OP_ADD, 1, &intf,
   8484                     intf_count + 1, NULL);
   8485         }
   8486         sal_free(intf_array);
   8487 
   8488         L3_UNLOCK(unit);
   8489     }
   8490 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   8491 
   8492     return rv;
   8493 }
   8494 
   8495 /*
   8496  * Function:
   8497  *      bcm_esw_l3_egress_ecmp_delete
   8498  * Purpose:
   8499  *      Delete an Egress forwarding object to an Egress ECMP
   8500  *      forwarding object.
   8501  * Parameters:
   8502  *      unit    - (IN) bcm device.
   8503  *      ecmp    - (IN) ECMP group info.
   8504  *      intf    - (IN) L3 interface id pointing to Egress forwarding object
   8505  * Returns:
   8506  *      BCM_E_XXX
   8507  */
   8508 int 
   8509 bcm_esw_l3_egress_ecmp_delete(int unit, bcm_l3_egress_ecmp_t *ecmp,
   8510         bcm_if_t intf)
   8511 {
   8512     int rv = BCM_E_UNAVAIL;
   8513 
   8514 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   8515     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   8516         int alloc_size;
   8517         bcm_if_t *intf_array;
   8518         int intf_count;
   8519         int i, j;
   8520 
   8521         /* Input check */
   8522         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   8523             return (BCM_E_PARAM);
   8524         }
   8525         if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   8526 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   8527             if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   8528 
   8529 #if defined(BCM_RIOT_SUPPORT)
   8530                 if (BCMI_RIOT_IS_ENABLED(unit)) {
   8531                     if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   8532                         if (!soc_feature(unit, soc_feature_multi_level_ecmp)) {
   8533                             return (BCM_E_PARAM);
   8534                         }
   8535                         else if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
   8536                             return (BCM_E_PARAM);
   8537                         }
   8538                     }
   8539                 } else
   8540 #endif
   8541                 {
   8542                     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
   8543                         return (BCM_E_PARAM);
   8544                     }
   8545                 }
   8546             } else
   8547 #endif
   8548             if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   8549                 if (!soc_feature(unit,soc_feature_virtual_port_routing)) {
   8550                     return (BCM_E_PARAM);
   8551                 }
   8552             } else {
   8553                 if (!soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   8554                     return (BCM_E_PARAM);
   8555                 } else {
   8556                     /* In Hierarchical/Multi-level ecmp mode, member can
   8557                      * be another ECMP group
   8558                      */
   8559                     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
   8560                         return (BCM_E_PARAM);
   8561                     }
   8562                 }
   8563             }
   8564         }
   8565 
   8566         /* Allocate interface array */
   8567         alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   8568         intf_array = sal_alloc(alloc_size, "intf array");
   8569         if (NULL == intf_array) {
   8570             return BCM_E_MEMORY;
   8571         }
   8572         sal_memset(intf_array, 0, alloc_size);
   8573         L3_LOCK(unit);
   8574 
   8575         /* Get ECMP group's existing interface array */
   8576         rv = _bcm_esw_l3_egress_ecmp_get(unit, ecmp, BCM_XGS3_L3_ECMP_MAX(unit),
   8577                                         intf_array, &intf_count, TRUE);
   8578         if (BCM_FAILURE(rv)) {
   8579             sal_free(intf_array);
   8580             L3_UNLOCK(unit);
   8581             return rv;
   8582 
   8583         }
   8584 
   8585 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8586         if (BCM_TH2_ECMP_IS_DLB(unit, ecmp->dynamic_mode)) {
   8587             rv = bcm_th2_l3_ecmp_dlb_member_delete(unit, ecmp, intf,
   8588                                                    intf_array, &intf_count);
   8589         } else
   8590 #endif /* BCM_TOMAHAWK2_SUPPORT  ||  BCM_TRIDENT3_SUPPORT */
   8591         {
   8592             /* Search for given intf */
   8593             for (i = 0; i < intf_count; i++) {
   8594                 if (intf_array[i] == intf) {
   8595                     break;
   8596                 }
   8597             }
   8598             if (i == intf_count) {
   8599                 /* Not found */
   8600                 sal_free(intf_array);
   8601                 L3_UNLOCK(unit);
   8602                 return BCM_E_NOT_FOUND;
   8603             }
   8604 
   8605             /* Shift remaining elements of intf_array */
   8606             for (j = i; j < intf_count - 1; j++) {
   8607                 intf_array[j] = intf_array[j+1];
   8608             }
   8609 
   8610             /* Update ECMP group */
   8611             ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   8612             rv = _bcm_esw_l3_ecmp_create(unit, ecmp, intf_count - 1,
   8613                     intf_array, BCM_L3_ECMP_MEMBER_OP_DELETE, 1, &intf,
   8614                     intf_count - 1, NULL);
   8615 
   8616 
   8617         }
   8618 
   8619         sal_free(intf_array);
   8620 
   8621         L3_UNLOCK(unit);
   8622     }
   8623 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   8624 
   8625     return rv;
   8626 }
   8627 
   8628 /*
   8629  * Function:
   8630  *      bcm_esw_l3_egress_ecmp_find
   8631  * Purpose:
   8632  *      Find an egress ECMP forwarding object.     
   8633  * Parameters:
   8634  *      unit       - (IN) bcm device.
   8635  *      intf_count - (IN) Number of elements in intf_array. 
   8636  *      intf_array - (IN) Array of egress forwarding objects.  
   8637  *      ecmp       - (OUT) ECMP group info.
   8638  * Returns:
   8639  *      BCM_E_XXX
   8640  */
   8641 int 
   8642 bcm_esw_l3_egress_ecmp_find(int unit, int intf_count,
   8643         bcm_if_t *intf_array, bcm_l3_egress_ecmp_t *ecmp)
   8644 {
   8645     int rv = BCM_E_UNAVAIL;
   8646 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   8647     int grp_idx = 0;
   8648 #endif
   8649 
   8650 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   8651     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   8652 
   8653         L3_LOCK(unit);
   8654 
   8655         rv = bcm_xgs3_l3_egress_multipath_find(unit, intf_count,
   8656                                                 intf_array, &ecmp->ecmp_intf);
   8657 
   8658         if (BCM_FAILURE(rv)) {
   8659             L3_UNLOCK(unit);
   8660             return rv;
   8661         }
   8662 
   8663         ecmp->flags = 0;
   8664         rv = bcm_xgs3_l3_egress_ecmp_max_paths_get(unit, ecmp->ecmp_intf,
   8665                                                    &ecmp->max_paths, NULL);
   8666         if (BCM_FAILURE(rv)) {
   8667             L3_UNLOCK(unit);
   8668             return rv;
   8669         }
   8670 
   8671         ecmp->ecmp_group_flags = 0;
   8672         ecmp->dynamic_mode = 0;
   8673         ecmp->dynamic_size = 0;
   8674         ecmp->dynamic_age = 0;
   8675         ecmp->dynamic_load_exponent = 0;
   8676         ecmp->dynamic_expected_load_exponent = 0;
   8677         ecmp->dgm.threshold = 0;
   8678         ecmp->dgm.cost = 0;
   8679         ecmp->dgm.bias = 0;
   8680 
   8681 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   8682         /* Get ecmp group index. */
   8683         grp_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   8684 
   8685         /* 
   8686          * we can look into the ecmp_grp index to know if this 
   8687          * is overlay entry or underlay entry.
   8688          */
   8689         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   8690 
   8691             if (grp_idx < BCMI_L3_ECMP_OVERLAY_ENTRIES(unit)) {
   8692 
   8693                 ecmp->ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
   8694             }
   8695         }
   8696 #endif
   8697 
   8698 #ifdef BCM_TRIUMPH3_SUPPORT
   8699         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   8700 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8701             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   8702                 rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, ecmp);
   8703             } else
   8704 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   8705             {
   8706                 rv = bcm_tr3_l3_egress_ecmp_dlb_get(unit, ecmp);
   8707             }
   8708             if (BCM_FAILURE(rv)) {
   8709                 L3_UNLOCK(unit);
   8710                 return rv;
   8711             }
   8712         }
   8713 #endif /* BCM_TRIUMPH3_SUPPORT */
   8714 
   8715 #ifdef BCM_TRIDENT2_SUPPORT
   8716         if (soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   8717             rv = bcm_td2_l3_egress_ecmp_rh_get(unit, ecmp);
   8718             if (BCM_FAILURE(rv)) {
   8719                 L3_UNLOCK(unit);
   8720                 return rv;
   8721             }
   8722         }
   8723 #endif /* BCM_TRIUMPH3_SUPPORT */
   8724 
   8725 #ifdef BCM_TOMAHAWK_SUPPORT
   8726         /* Get ECMP Level flags */
   8727         if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   8728             if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
   8729                       (ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
   8730                        BCM_L3_ECMP_OVERLAY)) {
   8731                 ecmp->ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
   8732             }
   8733             if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
   8734                       (ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
   8735                        BCM_L3_ECMP_UNDERLAY)) {
   8736                 ecmp->ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY;
   8737             }
   8738         }
   8739 
   8740         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   8741             rv = bcm_opt_l3_egress_ecmp_lb_get(unit, ecmp);
   8742             if (BCM_FAILURE(rv)) {
   8743                 L3_UNLOCK(unit);
   8744                 return rv;
   8745             }
   8746         }
   8747 #endif /* BCM_TOMAHAWK_SUPPORT */
   8748 
   8749         L3_UNLOCK(unit);
   8750     }
   8751 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   8752 
   8753     return rv;
   8754 }
   8755 
   8756 /*
   8757  * Function:
   8758  *      bcm_esw_l3_egress_ecmp_traverse
   8759  * Purpose:
   8760  *      Goes through ECMP egress objects table and runs the user callback
   8761  *      function at each ECMP egress objects entry passing back the
   8762  *      information for that ECMP object.
   8763  * Parameters:
   8764  *      unit       - (IN) bcm device.
   8765  *      trav_fn    - (IN) Callback function. 
   8766  *      user_data  - (IN) User data to be passed to callback function.
   8767  * Returns:
   8768  *      BCM_E_XXX
   8769  */
   8770 int 
   8771 bcm_esw_l3_egress_ecmp_traverse(int unit, 
   8772                           bcm_l3_egress_ecmp_traverse_cb trav_fn,
   8773                           void *user_data)
   8774 {
   8775     int rv = BCM_E_UNAVAIL;
   8776 
   8777 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   8778     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
   8779         L3_LOCK(unit);
   8780         rv = bcm_xgs3_l3_egress_ecmp_traverse(unit, trav_fn, user_data);
   8781         L3_UNLOCK(unit);
   8782     }
   8783 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   8784 
   8785     return rv;
   8786 }
   8787 
   8788 /*
   8789  * Function:
   8790  *      bcm_esw_l3_egress_ecmp_member_status_set
   8791  * Purpose:
   8792  *      Set ECMP dynamic load balancing member status.
   8793  * Parameters:
   8794  *      unit - (IN) Unit number.
   8795  *      intf - (IN) L3 Interface ID pointing to an Egress forwarding object.
   8796  *      status - (IN) ECMP member status.
   8797  * Returns:
   8798  *      BCM_E_XXX
   8799  */
   8800 int 
   8801 bcm_esw_l3_egress_ecmp_member_status_set(
   8802     int unit, 
   8803     bcm_if_t intf,
   8804     int status)
   8805 {
   8806     int rv = BCM_E_UNAVAIL;
   8807 
   8808 #ifdef BCM_TRIUMPH3_SUPPORT
   8809     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   8810         L3_LOCK(unit);
   8811 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8812         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   8813             rv = bcm_th2_l3_egress_ecmp_member_status_set(unit, intf, status);
   8814         } else
   8815 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   8816         {
   8817             rv = bcm_tr3_l3_egress_ecmp_member_status_set(unit, intf, status);
   8818         }
   8819         L3_UNLOCK(unit);
   8820     }
   8821 #endif /* BCM_TRIUMPH3_SUPPORT */
   8822 
   8823     return rv;
   8824 }
   8825 
   8826 /*
   8827  * Function:
   8828  *      bcm_esw_l3_egress_ecmp_member_status_get
   8829  * Purpose:
   8830  *      Get ECMP member status.
   8831  * Parameters:
   8832  *      unit - (IN) Unit number.
   8833  *      intf - (IN) L3 Interface ID pointing to an Egress forwarding object.
   8834  *      status - (OUT) ECMP member status.
   8835  * Returns:
   8836  *      BCM_E_XXX
   8837  */
   8838 int 
   8839 bcm_esw_l3_egress_ecmp_member_status_get(
   8840     int unit, 
   8841     bcm_if_t intf,
   8842     int *status)
   8843 {
   8844     int rv = BCM_E_UNAVAIL;
   8845 
   8846 #ifdef BCM_TRIUMPH3_SUPPORT
   8847     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   8848         L3_LOCK(unit);
   8849 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8850         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   8851             rv = bcm_th2_l3_egress_ecmp_member_status_get(unit, intf, status);
   8852         } else
   8853 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   8854         {
   8855             rv = bcm_tr3_l3_egress_ecmp_member_status_get(unit, intf, status);
   8856         }
   8857         L3_UNLOCK(unit);
   8858     }
   8859 #endif /* BCM_TRIUMPH3_SUPPORT */
   8860 
   8861     return rv;
   8862 }
   8863 
   8864 /*
   8865  * Function:
   8866  *      bcm_esw_l3_egress_ecmp_ethertype_set
   8867  * Purpose:
   8868  *      Set the Ethertypes that are eligible or ineligible for
   8869  *      ECMP dynamic load balancing or resilient hashing.
   8870  * Parameters:
   8871  *      unit - (IN) Unit number.
   8872  *      flags - (IN) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
   8873  *      ethertype_count - (IN) Number of elements in ethertype_array.
   8874  *      ethertype_array - (IN) Array of Ethertypes.
   8875  * Returns:
   8876  *      BCM_E_XXX
   8877  */
   8878 int 
   8879 bcm_esw_l3_egress_ecmp_ethertype_set(
   8880     int unit, 
   8881     uint32 flags, 
   8882     int ethertype_count, 
   8883     int *ethertype_array)
   8884 {
   8885     int rv;
   8886     int i;
   8887 
   8888     if ((ethertype_count > 0) && (NULL == ethertype_array)) {
   8889         return BCM_E_PARAM;
   8890     }
   8891     for (i = 0; i < ethertype_count; i++) {
   8892         if (ethertype_array[i] < 0 || ethertype_array[i] > 0xffff) {
   8893             return BCM_E_PARAM;
   8894         }
   8895     }
   8896 
   8897     L3_LOCK(unit);
   8898 
   8899     rv = BCM_E_UNAVAIL;
   8900 
   8901     if (flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_RESILIENT) {
   8902 #ifdef BCM_TRIDENT2_SUPPORT
   8903         if (soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   8904             rv = bcm_td2_l3_egress_ecmp_rh_ethertype_set(unit, flags,
   8905                     ethertype_count, ethertype_array);
   8906             if (BCM_FAILURE(rv)) {
   8907                 L3_UNLOCK(unit);
   8908                 return rv;
   8909             }
   8910         }
   8911 #endif /* BCM_TRIDENT2_SUPPORT */
   8912     } else {
   8913 #ifdef BCM_TRIUMPH3_SUPPORT
   8914         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   8915 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8916             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   8917                 rv = bcm_th2_l3_egress_ecmp_dlb_ethertype_set(unit, flags,
   8918                         ethertype_count, ethertype_array);
   8919             } else
   8920 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT */
   8921             {
   8922                 rv = bcm_tr3_l3_egress_ecmp_dlb_ethertype_set(unit, flags,
   8923                         ethertype_count, ethertype_array);
   8924             }
   8925             if (BCM_FAILURE(rv)) {
   8926                 L3_UNLOCK(unit);
   8927                 return rv;
   8928             }
   8929         }
   8930 #endif /* BCM_TRIUMPH3_SUPPORT */
   8931     }
   8932 
   8933     L3_UNLOCK(unit);
   8934 
   8935     return rv;
   8936 }
   8937 
   8938 /*
   8939  * Function:
   8940  *      bcm_esw_l3_egress_ecmp_ethertype_get
   8941  * Purpose:
   8942  *      Get the Ethertypes that are eligible or ineligible for
   8943  *      ECMP dynamic load balancing.
   8944  * Parameters:
   8945  *      unit - (IN) Unit number.
   8946  *      flags - (INOUT) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
   8947  *      ethertype_max - (IN) Number of elements in ethertype_array.
   8948  *      ethertype_array - (OUT) Array of Ethertypes.
   8949  *      ethertype_count - (OUT) Number of elements returned in ethertype_array.
   8950  * Returns:
   8951  *      BCM_E_XXX
   8952  */
   8953 int 
   8954 bcm_esw_l3_egress_ecmp_ethertype_get(
   8955     int unit, 
   8956     uint32 *flags, 
   8957     int ethertype_max, 
   8958     int *ethertype_array, 
   8959     int *ethertype_count)
   8960 {
   8961     int rv;
   8962 
   8963     L3_LOCK(unit);
   8964 
   8965     rv = BCM_E_UNAVAIL;
   8966 
   8967     if (*flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_RESILIENT) {
   8968 #ifdef BCM_TRIDENT2_SUPPORT
   8969         if (soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   8970             rv = bcm_td2_l3_egress_ecmp_rh_ethertype_get(unit, flags,
   8971                     ethertype_max, ethertype_array, ethertype_count);
   8972             if (BCM_FAILURE(rv)) {
   8973                 L3_UNLOCK(unit);
   8974                 return rv;
   8975             }
   8976         }
   8977 #endif /* BCM_TRIDENT2_SUPPORT */
   8978     } else {
   8979 #ifdef BCM_TRIUMPH3_SUPPORT
   8980         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   8981 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   8982             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   8983                 rv = bcm_th2_l3_egress_ecmp_dlb_ethertype_get(unit, flags,
   8984                         ethertype_max, ethertype_array, ethertype_count);
   8985             } else
   8986 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   8987             {
   8988                 rv = bcm_tr3_l3_egress_ecmp_dlb_ethertype_get(unit, flags,
   8989                         ethertype_max, ethertype_array, ethertype_count);
   8990             }
   8991             if (BCM_FAILURE(rv)) {
   8992                 L3_UNLOCK(unit);
   8993                 return rv;
   8994             }
   8995         }
   8996 #endif /* BCM_TRIUMPH3_SUPPORT */
   8997     }
   8998 
   8999     L3_UNLOCK(unit);
   9000     return rv;
   9001 }
   9002 
   9003 /*
   9004  * Function:
   9005  *      bcm_esw_l3_ip6_prefix_map_get
   9006  * Purpose:
   9007  *      Get a list of IPv6 96 bit prefixes which are mapped to ipv4 lookup
   9008  *      space.
   9009  * Parameters:
   9010  *      unit       - (IN) bcm device.
   9011  *      map_size   - (IN) Size of allocated entries in ip6_array.
   9012  *      ip6_array  - (OUT) Array of mapped prefixes.
   9013  *      ip6_count  - (OUT) Number of entries of ip6_array actually filled in.
   9014  *                      This will be a value less than or equal to the value.
   9015  *                      passed in as map_size unless map_size is 0.  If
   9016  *                      map_size is 0 then ip6_array is ignored and
   9017  *                      ip6_count is filled in with the number of entries
   9018  *                      that would have been filled into ip6_array if
   9019  *                      map_size was arbitrarily large.
   9020  * Returns:
   9021  *      BCM_E_XXX
   9022  */
   9023 int
   9024 bcm_esw_l3_ip6_prefix_map_get(int unit, int map_size, 
   9025                               bcm_ip6_t *ip6_array, int *ip6_count)
   9026 {
   9027     int rv = BCM_E_UNAVAIL;
   9028 
   9029     /*  Check that device supports ipv6. */
   9030     if (BCM_L3_NO_IP6_SUPPORT(unit, BCM_L3_IP6)) {
   9031         return (BCM_E_UNAVAIL);
   9032     }
   9033 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   9034     L3_LOCK(unit);
   9035     rv = bcm_xgs3_l3_ip6_prefix_map_get(unit, map_size, 
   9036                                           ip6_array, ip6_count);
   9037     L3_UNLOCK(unit);
   9038 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   9039     return rv;
   9040 }
   9041 /*
   9042  * Function:
   9043  *      bcm_esw_l3_ip6_prefix_map_add
   9044  * Purpose:
   9045  *      Create an IPv6 prefix map into IPv4 entry. In case Ipv6 traffic
   9046  *      destination or source IP address matches upper 96 bits of
   9047  *      translation entry. traffic will be routed/switched  based on
   9048  *      lower 32 bits of destination/source IP address treated as IPv4 address.
   9049  * Parameters:
   9050  *      unit     - (IN)  bcm device.
   9051  *      ip6_addr - (IN)  New IPv6 translation address.
   9052  * Returns:
   9053  *      BCM_E_XXX
   9054  */
   9055 int
   9056 bcm_esw_l3_ip6_prefix_map_add(int unit, bcm_ip6_t ip6_addr) 
   9057 {
   9058     int rv = BCM_E_UNAVAIL;
   9059 
   9060     /*  Check that device supports ipv6. */
   9061     if (BCM_L3_NO_IP6_SUPPORT(unit, BCM_L3_IP6)) {
   9062         return (BCM_E_UNAVAIL);
   9063     }
   9064 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   9065     L3_LOCK(unit);
   9066     rv = bcm_xgs3_l3_ip6_prefix_map_add(unit, ip6_addr);
   9067     L3_UNLOCK(unit);
   9068 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   9069     return (rv);
   9070 }
   9071 
   9072 /*
   9073  * Function:
   9074  *      bcm_esw_l3_ip6_prefix_map_delete
   9075  * Purpose:
   9076  *      Destroy an IPv6 prefix map entry.
   9077  * Parameters:
   9078  *      unit     - (IN)  bcm device.
   9079  *      ip6_addr - (IN)  IPv6 translation address.
   9080  * Returns:
   9081  *      BCM_E_XXX
   9082  */
   9083 int
   9084 bcm_esw_l3_ip6_prefix_map_delete(int unit, bcm_ip6_t ip6_addr)
   9085 {
   9086     int rv = BCM_E_UNAVAIL;
   9087 
   9088     /*  Check that device supports ipv6. */
   9089     if (BCM_L3_NO_IP6_SUPPORT(unit, BCM_L3_IP6)) {
   9090         return (BCM_E_UNAVAIL);
   9091     }
   9092 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   9093     L3_LOCK(unit);
   9094     rv = bcm_xgs3_l3_ip6_prefix_map_delete(unit, ip6_addr);
   9095     L3_UNLOCK(unit);
   9096 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   9097     return (rv);
   9098 }
   9099 
   9100 /*
   9101  * Function:
   9102  *      bcm_esw_l3_ip6_prefix_map_delete_all
   9103  * Purpose:
   9104  *      Flush all IPv6 prefix maps.
   9105  * Parameters:
   9106  *      unit     - (IN)  bcm device.
   9107  * Returns:
   9108  *      BCM_E_XXX
   9109  */
   9110 int
   9111 bcm_esw_l3_ip6_prefix_map_delete_all(int unit)
   9112 {
   9113     int rv = BCM_E_UNAVAIL;
   9114 
   9115     /*  Check that device supports ipv6. */
   9116     if (BCM_L3_NO_IP6_SUPPORT(unit, BCM_L3_IP6)) {
   9117         return (BCM_E_UNAVAIL);
   9118     }
   9119 
   9120 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   9121     L3_LOCK(unit);
   9122     rv = bcm_xgs3_l3_ip6_prefix_map_delete_all(unit);
   9123     L3_UNLOCK(unit);
   9124 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   9125     return (rv);
   9126 }
   9127 
   9128 /*
   9129  * Function:
   9130  *      bcm_esw_l3_vrrp_add
   9131  * Purpose:
   9132  *      Add VRID for the given VSI. Adding a VRID using this API means
   9133  *      the physical node has become the master for the virtual router
   9134  * Parameters:
   9135  *      unit - (IN) Unit number.
   9136  *      vlan - (IN) VLAN/VSI
   9137  *      vrid - (IN) VRID - Virtual router ID to be added
   9138  * Returns:
   9139  *      BCM_E_xxx
   9140  * Notes:
   9141  */
   9142 int 
   9143 bcm_esw_l3_vrrp_add(int unit, bcm_vlan_t vlan, uint32 vrid)
   9144 {
   9145     bcm_l2_addr_t l2addr;            /* Layer 2 address for interface. */
   9146     int rv;                          /* Operation return status.       */
   9147     bcm_mac_t mac = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00};/* Mac address.*/
   9148 
   9149     if (!BCM_VLAN_VALID(vlan)) {
   9150         return (BCM_E_PARAM);
   9151     }
   9152 
   9153     if (vrid > 0xff) {
   9154         return (BCM_E_PARAM);
   9155     }
   9156     mac[5] = vrid;
   9157 
   9158     /* Set l2 address info. */
   9159     bcm_l2_addr_t_init(&l2addr, mac, vlan);
   9160 
   9161 #if defined(BCM_MIRAGE_SUPPORT)
   9162     if (soc_feature(unit, soc_feature_fp_routing_mirage)) {
   9163         /* Set l2 entry flags. */
   9164         l2addr.flags = BCM_L2_STATIC | BCM_L2_REPLACE_DYNAMIC;
   9165 
   9166         /* Set l2 entry port to CPU port. */
   9167         l2addr.port = BCM_MIRAGE_L3_PORT;
   9168     } else 
   9169 #endif /* BCM_MIRAGE_SUPPORT */
   9170     {
   9171         /* Set l2 entry flags. */
   9172         l2addr.flags = BCM_L2_L3LOOKUP | BCM_L2_STATIC | BCM_L2_REPLACE_DYNAMIC;
   9173 
   9174         /* Set l2 entry port to CPU port. */
   9175         l2addr.port = CMIC_PORT(unit); 
   9176     }
   9177 
   9178     /* Set l2 entry module id to local module. */
   9179     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &l2addr.modid));
   9180 
   9181     /* Overwrite existing entry if any. */
   9182     bcm_esw_l2_addr_delete(unit, mac, vlan);
   9183 
   9184     /* Add entry to l2 table. */
   9185     rv = bcm_esw_l2_addr_add(unit, &l2addr);
   9186 
   9187     return rv;
   9188 }
   9189 
   9190 /*
   9191  * Function:
   9192  *      bcm_esw_l3_vrrp_delete
   9193  * Purpose:
   9194  *      Delete VRID for a particulat VLAN/VSI
   9195  * Parameters:
   9196  *      unit - (IN) Unit number.
   9197  *      vlan - (IN) VLAN/VSI
   9198  *      vrid - (IN) VRID - Virtual router ID to be deleted
   9199  * Returns:
   9200  *      BCM_E_xxx
   9201  * Notes:
   9202  */
   9203 int 
   9204 bcm_esw_l3_vrrp_delete(int unit, bcm_vlan_t vlan, uint32 vrid)
   9205 {
   9206     bcm_l2_addr_t l2addr;            /* Layer 2 address for interface. */
   9207     int rv;                          /* Operation return status.       */
   9208     bcm_mac_t mac = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00};/* Mac address.*/
   9209 
   9210     if (!BCM_VLAN_VALID(vlan)) {
   9211         return (BCM_E_PARAM);
   9212     }
   9213 
   9214     if (vrid > 0xff) {
   9215         return (BCM_E_PARAM);
   9216     }
   9217     mac[5] = vrid;
   9218 
   9219     /* Set l2 address info. */
   9220     bcm_l2_addr_t_init(&l2addr, mac, vlan);
   9221 
   9222     /* Overwrite existing entry if any. */
   9223     rv = bcm_esw_l2_addr_delete(unit, mac, vlan);
   9224     return rv;
   9225 }
   9226 
   9227 /*
   9228  * Function:
   9229  *      bcm_esw_l3_vrrp_delete_all
   9230  * Purpose:
   9231  *      Delete all the VRIDs for a particular VLAN/VSI
   9232  * Parameters:
   9233  *      unit - (IN) Unit number.
   9234  *      vlan - (IN) VLAN/VSI
   9235  * Returns:
   9236  *      BCM_E_xxx
   9237  * Notes:
   9238  */
   9239 int 
   9240 bcm_esw_l3_vrrp_delete_all(int unit, bcm_vlan_t vlan)
   9241 {
   9242     int idx;     /* vr id iteration index.   */ 
   9243     int rv;      /* Operation return status. */
   9244 
   9245     if (!BCM_VLAN_VALID(vlan)) {
   9246         return (BCM_E_PARAM);
   9247     }
   9248 
   9249     for (idx = 0; idx < 0x100; idx++) {
   9250         rv = bcm_esw_l3_vrrp_delete(unit, vlan, idx);
   9251         if (BCM_FAILURE(rv) && (BCM_E_NOT_FOUND != rv)) {
   9252             return (rv);
   9253         }
   9254     }
   9255     return (BCM_E_NONE);
   9256 }
   9257 
   9258 
   9259 /*
   9260  * Function:
   9261  *      bcm_esw_l3_vrrp_get
   9262  * Purpose:
   9263  *      Get all the VRIDs for which the physical node is master for
   9264  *      the virtual routers on the given VLAN/VSI
   9265  * Parameters:
   9266  *      unit - (IN) Unit number.
   9267  *      vlan - (IN) VLAN/VSI
   9268  *      alloc_size - (IN) Size of vrid_array
   9269  *      vrid_array - (OUT) Pointer to the array to which the VRIDs will be copied
   9270  *      count - (OUT) Number of VRIDs copied
   9271  * Returns:
   9272  *      BCM_E_xxx
   9273  * Notes:
   9274  */
   9275 int 
   9276 bcm_esw_l3_vrrp_get(int unit, bcm_vlan_t vlan, int alloc_size, 
   9277                     int *vrid_array, int *count)
   9278 {
   9279     bcm_l2_addr_t l2addr;             /* Layer 2 address for interface. */
   9280     int idx;                          /* vr id iteration index.         */ 
   9281     int tmp_cnt;                      /* Valie entry count.             */ 
   9282     int rv;                           /* Operation return status.       */
   9283     bcm_mac_t mac = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00};/* Mac address.*/
   9284 
   9285     if (!BCM_VLAN_VALID(vlan)) {
   9286         return (BCM_E_PARAM);
   9287     }
   9288 
   9289     if (NULL == count) {
   9290         return (BCM_E_PARAM);
   9291     }
   9292 
   9293     tmp_cnt = 0;
   9294     for (idx = 0; idx < 0x100; idx++) {
   9295         if ( alloc_size > tmp_cnt) {
   9296             mac[5] = idx;
   9297 
   9298             /* Set l2 address info. */
   9299             bcm_l2_addr_t_init(&l2addr, mac, vlan);
   9300 
   9301             /* Overwrite existing entry if any. */
   9302             rv = bcm_esw_l2_addr_get(unit, mac, vlan, &l2addr);
   9303             if (BCM_SUCCESS(rv)) {
   9304                 if (NULL != vrid_array) {
   9305                     vrid_array[tmp_cnt] = idx;  
   9306                 }
   9307                 tmp_cnt++;
   9308             }
   9309         }
   9310     }
   9311     *count = tmp_cnt;
   9312     return (BCM_E_NONE);
   9313 }
   9314 
   9315 
   9316 #if defined(BCM_TRIUMPH2_SUPPORT)
   9317 #define BCM_VRF_STAT_VALID(unit, vrf) \
   9318     if (!soc_feature(unit, soc_feature_gport_service_counters)) { \
   9319         return BCM_E_UNAVAIL; \
   9320     } else if (((vrf) > SOC_VRF_MAX(unit)) || \
   9321                ((vrf) < BCM_L3_VRF_DEFAULT)) { return (BCM_E_PARAM); }
   9322 
   9323 STATIC int
   9324 _bcm_vrf_flex_stat_hw_index_set(int unit, _bcm_flex_stat_handle_t fsh,
   9325                                 int fs_idx, void *cookie)
   9326 {
   9327     uint32 handle = _BCM_FLEX_STAT_HANDLE_WORD_GET(fsh, 0);
   9328     COMPILER_REFERENCE(cookie);
   9329     if (SOC_MEM_FIELD_VALID(unit, VRFm, USE_SERVICE_CTR_IDXf)) {
   9330         BCM_IF_ERROR_RETURN(
   9331             soc_mem_field32_modify(unit, VRFm, handle,
   9332                                   USE_SERVICE_CTR_IDXf, (fs_idx!=0) ? 1:0));
   9333     }
   9334     return soc_mem_field32_modify(unit, VRFm, handle,
   9335                                   SERVICE_CTR_IDXf, fs_idx);
   9336 }
   9337 
   9338 STATIC _bcm_flex_stat_t
   9339 _bcm_esw_l3_vrf_stat_to_flex_stat(bcm_l3_vrf_stat_t stat)
   9340 {
   9341     _bcm_flex_stat_t flex_stat;
   9342 
   9343     switch (stat) {
   9344     case bcmL3VrfStatIngressPackets:
   9345         flex_stat = _bcmFlexStatIngressPackets;
   9346         break;
   9347     case bcmL3VrfStatIngressBytes:
   9348         flex_stat = _bcmFlexStatIngressBytes;
   9349         break;
   9350     default:
   9351         flex_stat = _bcmFlexStatNum;
   9352     }
   9353 
   9354     return flex_stat;
   9355 }
   9356 
   9357 /* Requires "idx" variable */
   9358 #define BCM_VRF_STAT_ARRAY_VALID(unit, nstat, value_arr) \
   9359     for (idx = 0; idx < nstat; idx++) { \
   9360         if (NULL == value_arr + idx) { \
   9361             return (BCM_E_PARAM); \
   9362         } \
   9363     }
   9364 
   9365 STATIC int
   9366 _bcm_l3_vrf_stat_array_convert(int unit, int nstat,
   9367                                bcm_l3_vrf_stat_t *stat_arr, 
   9368                                _bcm_flex_stat_t *fs_arr)
   9369 {
   9370     int idx;
   9371 
   9372     if ((nstat <= 0) || (nstat > _bcmFlexStatEgressPackets)) {
   9373         /* VRF only has ingress support, so the number of ingress types
   9374          * is the first egress type. */
   9375         return BCM_E_PARAM;
   9376     }
   9377 
   9378     if (NULL == stat_arr) {
   9379         return (BCM_E_PARAM);
   9380     }
   9381 
   9382     for (idx = 0; idx < nstat; idx++) {
   9383         fs_arr[idx] = _bcm_esw_l3_vrf_stat_to_flex_stat(stat_arr[idx]);
   9384     }
   9385     return BCM_E_NONE;
   9386 }
   9387 #endif /* BCM_TRIUMPH2_SUPPORT */
   9388 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9389 /*
   9390  * Function:
   9391  *      _bcm_esw_l3_vrf_stat_get_table_info
   9392  * Description:
   9393  *      Provides relevant flex table information(table-name,index with
   9394  *      direction)  for given VRF(Virtual Router Interface) id.
   9395  *
   9396  * Parameters:
   9397  *      unit             - (IN) unit number
   9398  *      vrf              - (IN) VRF(Virtual Router Interface) id
   9399  *      num_of_tables    - (OUT) Number of flex counter tables
   9400  *      table_info       - (OUT) Flex counter tables information
   9401  *
   9402  * Return Value:
   9403  *      BCM_E_XXX
   9404  * Notes:
   9405  */
   9406 static 
   9407 bcm_error_t _bcm_esw_l3_vrf_stat_get_table_info(
   9408             int                        unit,
   9409             bcm_vrf_t                  vrf,
   9410             uint32                     *num_of_tables,
   9411             bcm_stat_flex_table_info_t *table_info)
   9412 {
   9413     (*num_of_tables)=0;
   9414 
   9415     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
   9416         return BCM_E_UNAVAIL;
   9417     }
   9418 
   9419 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   9420     if (soc_feature(unit, soc_feature_l3_256_defip_table) || 
   9421         soc_feature(unit, soc_feature_no_vrf_stats)) {
   9422         return BCM_E_UNAVAIL; /* VRF stats not valid for Ranger & Ranger + */
   9423     }
   9424 #endif /* BCM_TRIUMPH3_SUPPORT || BCM_GREYHOUND2_SUPPORT*/
   9425 
   9426 #if defined(BCM_TRIUMPH2_SUPPORT)
   9427     L3_INIT(unit);
   9428     if ((vrf > SOC_VRF_MAX(unit)) || (vrf < BCM_L3_VRF_DEFAULT)) {
   9429          return (BCM_E_PARAM);
   9430     }
   9431 #if defined (BCM_TRIDENT3_SUPPORT)
   9432     if (SOC_IS_TRIDENT3X(unit)){
   9433         table_info[*num_of_tables].table = VRF_ATTRS_2m;
   9434     } else
   9435 #endif
   9436     {
   9437         table_info[*num_of_tables].table=VRFm;
   9438     }
   9439     table_info[*num_of_tables].index=vrf;
   9440     table_info[*num_of_tables].direction=bcmStatFlexDirectionIngress;
   9441     (*num_of_tables)++;
   9442     return BCM_E_NONE;
   9443 #else
   9444     return BCM_E_UNAVAIL;
   9445 #endif /* BCM_TRIUMPH2_SUPPORT */
   9446 }
   9447 #endif
   9448 
   9449 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9450 /*
   9451  * Function:
   9452  *      _bcm_esw_l3_vrf_stat_attach
   9453  * Description:
   9454  *      Attach counters entries to the given  VRF 
   9455  *
   9456  * Parameters:
   9457  *      unit             - (IN) unit number
   9458  *      vrf              - (IN) Virtual router instance
   9459  *      stat_counter_id  - (IN) Stat Counter ID.
   9460  *
   9461  * Return Value:
   9462  *      BCM_E_XXX
   9463  * Notes:
   9464  */
   9465 
   9466 STATIC bcm_error_t _bcm_esw_l3_vrf_stat_attach(
   9467             int       unit, 
   9468             bcm_vrf_t vrf, 
   9469             uint32    stat_counter_id)
   9470 {
   9471     soc_mem_t                  table=0;
   9472     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   9473     uint32                     pool_number=0;
   9474     uint32                     base_index=0;
   9475     bcm_stat_flex_mode_t       offset_mode=0;
   9476     bcm_stat_object_t          object=bcmStatObjectIngPort;
   9477     bcm_stat_group_mode_t      group_mode= bcmStatGroupModeSingle;
   9478     uint32                     count=0;
   9479     uint32                     actual_num_tables=0;
   9480     uint32                     num_of_tables=0;
   9481     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9482 
   9483     _bcm_esw_stat_get_counter_id_info(
   9484                   unit, stat_counter_id,
   9485                   &group_mode,&object,&offset_mode,&pool_number,&base_index);
   9486     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction));
   9487     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode));
   9488     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   9489                         unit,object,1,&actual_num_tables,&table,&direction));
   9490 
   9491     BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_get_table_info(
   9492                         unit, vrf,&num_of_tables,&table_info[0]));
   9493     for (count=0; count < num_of_tables ; count++) {
   9494          if ((table_info[count].direction == direction) &&
   9495              (table_info[count].table == table) ) {
   9496               if (direction == bcmStatFlexDirectionIngress) {
   9497                   return _bcm_esw_stat_flex_attach_ingress_table_counters(
   9498                          unit,
   9499                          table_info[count].table,
   9500                          table_info[count].index,
   9501                          offset_mode,
   9502                          base_index,
   9503                          pool_number);
   9504               } else {
   9505                   return _bcm_esw_stat_flex_attach_egress_table_counters(
   9506                          unit,
   9507                          table_info[count].table,
   9508                          table_info[count].index,
   9509                          0,
   9510                          offset_mode,
   9511                          base_index,
   9512                          pool_number);
   9513               } 
   9514          }
   9515     }
   9516     return BCM_E_NOT_FOUND;
   9517 }
   9518 #endif
   9519 
   9520 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   9521 /*
   9522  * Function:
   9523  *      _tr2_l3_vrf_stat_attach
   9524  * Description:
   9525  *      Attach counters entries to the given VRF for TR2/Trident device
   9526  *
   9527  * Parameters:
   9528  *      unit             - (IN) unit number
   9529  *      vrf              - (IN) Virtual router instance
   9530  *      stat_counter_id  - (IN) Stat Counter ID.
   9531  *
   9532  * Return Value:
   9533  *      BCM_E_XXX
   9534  * Notes:
   9535  */
   9536 
   9537 STATIC bcm_error_t _tr2_l3_vrf_stat_attach(
   9538             int       unit,
   9539             bcm_vrf_t vrf,
   9540             uint32    stat_counter_id,
   9541             int enable)
   9542 {
   9543 
   9544     _bcm_flex_stat_type_t fs_type;
   9545     uint32 fs_inx;
   9546     int rv;
   9547 
   9548     fs_type = _BCM_FLEX_STAT_TYPE(stat_counter_id);
   9549     fs_inx  = _BCM_FLEX_STAT_COUNT_INX(stat_counter_id);
   9550 
   9551     if (!((fs_type == _bcmFlexStatTypeVrf) && fs_inx)) {
   9552         return BCM_E_PARAM;
   9553     }
   9554     BCM_VRF_STAT_VALID(unit, vrf);
   9555 
   9556     L3_LOCK(unit);
   9557     rv = _bcm_esw_flex_stat_enable_set(unit, fs_type,
   9558                          _bcm_vrf_flex_stat_hw_index_set,
   9559                                   INT_TO_PTR(_BCM_FLEX_STAT_HW_INGRESS),
   9560                                   vrf, enable,fs_inx);
   9561     L3_UNLOCK(unit);
   9562     return rv;
   9563 }
   9564 #endif
   9565 
   9566 /*
   9567  * Function:
   9568  *      bcm_esw_l3_vrf_stat_attach
   9569  * Description:
   9570  *      Attach counters entries to the given  VRF
   9571  *
   9572  * Parameters:
   9573  *      unit             - (IN) unit number
   9574  *      vrf              - (IN) Virtual router instance
   9575  *      stat_counter_id  - (IN) Stat Counter ID.
   9576  *
   9577  * Return Value:
   9578  *      BCM_E_XXX
   9579  * Notes:
   9580  */
   9581 
   9582 int bcm_esw_l3_vrf_stat_attach(
   9583             int       unit,
   9584             bcm_vrf_t vrf,
   9585             uint32    stat_counter_id)
   9586 {
   9587 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9588     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   9589         return _bcm_esw_l3_vrf_stat_attach(unit,vrf,stat_counter_id);
   9590     } else
   9591 #endif
   9592 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   9593     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   9594         return _tr2_l3_vrf_stat_attach(unit,vrf,stat_counter_id,TRUE);
   9595     } else
   9596 #endif
   9597     {
   9598         return BCM_E_UNAVAIL;
   9599     }
   9600 }
   9601 
   9602 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9603 /*
   9604  * Function:
   9605  *      _bcm_esw_l3_vrf_stat_detach
   9606  * Description:
   9607  *      Detach   counters entries to the given VRF
   9608  *
   9609  * Parameters:
   9610  *      unit             - (IN) unit number
   9611  *      vrf              - (IN) Virtual router instance
   9612  *      stat_counter_id  - (IN) Stat Counter ID.
   9613  *
   9614  * Return Value:
   9615  *      BCM_E_XXX
   9616  * Notes:
   9617  */
   9618 STATIC bcm_error_t _bcm_esw_l3_vrf_stat_detach(
   9619             int       unit, 
   9620             bcm_vrf_t vrf)
   9621 {
   9622     uint32                     count=0;
   9623     uint32                     num_of_tables=0;
   9624     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9625     bcm_error_t                rv = BCM_E_NONE;
   9626     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE};
   9627 
   9628     BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_get_table_info(
   9629                         unit, vrf,&num_of_tables,&table_info[0]));
   9630 
   9631     for (count=0; count < num_of_tables ; count++) {
   9632          if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   9633              rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   9634                         unit, table_info[count].table, table_info[count].index);
   9635              if (BCM_E_NONE != rv &&
   9636                 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   9637                 err_code[bcmStatFlexDirectionIngress] = rv;
   9638              }
   9639          } else {
   9640              rv = _bcm_esw_stat_flex_detach_egress_table_counters(
   9641                         unit, 0, table_info[count].table,
   9642                         table_info[count].index);
   9643              if (BCM_E_NONE != rv && 
   9644                 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   9645                 err_code[bcmStatFlexDirectionEgress] = rv;
   9646              }
   9647          }
   9648     }
   9649 
   9650     BCM_STAT_FLEX_DETACH_RETURN(err_code)
   9651 }
   9652 #endif
   9653 
   9654 /*
   9655  * Function:
   9656  *      bcm_esw_l3_vrf_stat_detach
   9657  * Description:
   9658  *      Detach   counters entries to the given VRF
   9659  *
   9660  * Parameters:
   9661  *      unit             - (IN) unit number
   9662  *      vrf              - (IN) Virtual router instance
   9663  *      stat_counter_id  - (IN) Stat Counter ID.
   9664  *
   9665  * Return Value:
   9666  *      BCM_E_XXX
   9667  * Notes:
   9668  */
   9669 int bcm_esw_l3_vrf_stat_detach(
   9670             int       unit,
   9671             bcm_vrf_t vrf)
   9672 {
   9673 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9674     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   9675         return _bcm_esw_l3_vrf_stat_detach(unit,vrf);
   9676     } else
   9677 #endif
   9678 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   9679     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   9680         return _tr2_l3_vrf_stat_attach(unit,vrf,
   9681                    _BCM_FLEX_STAT_COUNT_ID(_bcmFlexStatTypeVrf,1),
   9682                    FALSE);
   9683     } else
   9684 #endif
   9685     {
   9686         return BCM_E_UNAVAIL;
   9687     }
   9688 }
   9689 
   9690 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9691 /*
   9692  * Function:
   9693  *      _bcm_esw_l3_vrf_stat_counter_get
   9694  * Description:
   9695  * Get L3 VRF counter value for specified VRF statistic type 
   9696  * if sync_mode is set, sync the sw accumulated count
   9697  * with hw count value first, else return sw count.  
   9698  *
   9699  * Parameters:
   9700  *      unit             - (IN) unit number
   9701  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   9702  *      vrf              - (IN) Virtual router instance
   9703  *      stat             - (IN) Type of the counter to retrieve
   9704  *                              I.e. ingress/egress byte/packet)
   9705  *      num_entries      - (IN) Number of counter Entries
   9706  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9707  *      counter_values   - (OUT) Pointer to counter values
   9708  *
   9709  * Return Value:
   9710  *      BCM_E_XXX
   9711  * Notes:
   9712  */
   9713 STATIC bcm_error_t _bcm_esw_l3_vrf_stat_counter_get(
   9714             int               unit, 
   9715             int               sync_mode,
   9716             bcm_vrf_t         vrf, 
   9717             bcm_l3_vrf_stat_t stat, 
   9718             uint32            num_entries, 
   9719             uint32            *counter_indexes, 
   9720             bcm_stat_value_t  *counter_values)
   9721 {
   9722     uint32                     table_count=0;
   9723     uint32                     index_count=0;
   9724     uint32                     num_of_tables=0;
   9725     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   9726     uint32                     byte_flag=0;
   9727     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9728 
   9729     if ((stat == bcmL3VrfStatIngressPackets) ||
   9730         (stat == bcmL3VrfStatIngressBytes)) {
   9731          direction = bcmStatFlexDirectionIngress;
   9732     } else {
   9733          /* direction = bcmStatFlexDirectionEgress; */
   9734          return BCM_E_PARAM;
   9735     }
   9736 
   9737     if ((num_entries > 0) &&
   9738         ((NULL == counter_indexes) || (NULL == counter_values))) {
   9739         return BCM_E_PARAM;
   9740     }
   9741 
   9742     if (stat == bcmL3VrfStatIngressPackets) {
   9743         byte_flag=0;
   9744     } else {
   9745         byte_flag=1;
   9746     }
   9747     
   9748     BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_get_table_info(
   9749                         unit, vrf,&num_of_tables,&table_info[0]));
   9750 
   9751     for (table_count=0; table_count < num_of_tables ; table_count++) {
   9752          if (table_info[table_count].direction == direction) {
   9753              for (index_count=0; index_count < num_entries ; index_count++) {
   9754                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   9755                                       unit, sync_mode,
   9756                                       table_info[table_count].index,
   9757                                       table_info[table_count].table,
   9758                                       0, byte_flag,
   9759                                       counter_indexes[index_count],
   9760                                       &counter_values[index_count]));
   9761              }
   9762          }
   9763     }
   9764     return BCM_E_NONE;
   9765 }
   9766 
   9767 
   9768 #endif 
   9769 /*
   9770  * Function:
   9771  *      _bcm_esw_l3_vrf_flex_stat_counter_get
   9772  * Description:
   9773  * Get L3 VRF counter value for specified VRF statistic type
   9774  *if sync_mode is set, sync the sw accumulated count
   9775  *with hw count value first, else return sw count. 
   9776  *
   9777  * Parameters:
   9778  *      unit             - (IN) unit number
   9779  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   9780  *      vrf              - (IN) Virtual router instance
   9781  *      stat             - (IN) Type of the counter to retrieve
   9782  *                              I.e. ingress/egress byte/packet)
   9783  *      num_entries      - (IN) Number of counter Entries
   9784  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9785  *      counter_values   - (OUT) Pointer to counter values
   9786  *
   9787  * Return Value:
   9788  *      BCM_E_XXX
   9789  * Notes:
   9790  */
   9791 int _bcm_esw_l3_vrf_flex_stat_counter_get(
   9792             int               unit,
   9793             int               sync_mode,
   9794             bcm_vrf_t         vrf,
   9795             bcm_l3_vrf_stat_t stat,
   9796             uint32            num_entries,
   9797             uint32            *counter_indexes,
   9798             bcm_stat_value_t  *counter_values)
   9799 {
   9800 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9801     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   9802         return _bcm_esw_l3_vrf_stat_counter_get(unit, sync_mode, vrf, stat,
   9803                       num_entries, counter_indexes, counter_values);
   9804     } else
   9805 #endif
   9806 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
   9807     if (soc_feature(unit,soc_feature_gport_service_counters)) {
   9808         uint64 val;
   9809         int rv = BCM_E_NONE;
   9810  
   9811         if (NULL == counter_values) {
   9812             return BCM_E_PARAM;
   9813         }
   9814 
   9815         rv = _bcm_esw_l3_vrf_stat_get(unit, sync_mode, vrf, stat, &val);
   9816 
   9817         if (stat == bcmL3VrfStatIngressPackets) {
   9818             counter_values->packets = COMPILER_64_LO(val);
   9819         } else {
   9820             COMPILER_64_SET(counter_values->bytes,
   9821                       COMPILER_64_HI(val),
   9822                       COMPILER_64_LO(val));
   9823         }
   9824         return rv;
   9825 
   9826     } else
   9827 #endif
   9828     {
   9829         return BCM_E_UNAVAIL;
   9830     }
   9831 }
   9832 
   9833 
   9834 
   9835 /*
   9836  * Function:
   9837  *      bcm_esw_l3_vrf_stat_counter_get
   9838  * Description:
   9839  * Get L3 VRF counter value for specified VRF statistic type
   9840  *
   9841  * Parameters:
   9842  *      unit             - (IN) unit number
   9843  *      vrf              - (IN) Virtual router instance
   9844  *      stat             - (IN) Type of the counter to retrieve
   9845  *                              I.e. ingress/egress byte/packet)
   9846  *      num_entries      - (IN) Number of counter Entries
   9847  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9848  *      counter_values   - (OUT) Pointer to counter values
   9849  *
   9850  * Return Value:
   9851  *      BCM_E_XXX
   9852  * Notes:
   9853  */
   9854 int bcm_esw_l3_vrf_stat_counter_get(
   9855             int               unit,
   9856             bcm_vrf_t         vrf,
   9857             bcm_l3_vrf_stat_t stat,
   9858             uint32            num_entries,
   9859             uint32            *counter_indexes,
   9860             bcm_stat_value_t  *counter_values)
   9861 {
   9862     int rv = BCM_E_UNAVAIL;
   9863 
   9864     rv = _bcm_esw_l3_vrf_flex_stat_counter_get(unit, 0, vrf, stat, num_entries,
   9865                                          counter_indexes, counter_values);
   9866     return rv;
   9867 }    
   9868 
   9869 
   9870 /*
   9871  * Function:
   9872  *      bcm_esw_l3_vrf_stat_counter_sync_get
   9873  * Description:
   9874  * Get L3 VRF counter value for specified VRF statistic type
   9875  * sw accumulated counters synced with hw count.
   9876  * Parameters:
   9877  *      unit             - (IN) unit number
   9878  *      vrf              - (IN) Virtual router instance
   9879  *      stat             - (IN) Type of the counter to retrieve
   9880  *                              I.e. ingress/egress byte/packet)
   9881  *      num_entries      - (IN) Number of counter Entries
   9882  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9883  *      counter_values   - (OUT) Pointer to counter values
   9884  *
   9885  * Return Value:
   9886  *      BCM_E_XXX
   9887  * Notes:
   9888  */
   9889 int bcm_esw_l3_vrf_stat_counter_sync_get(
   9890             int               unit,
   9891             bcm_vrf_t         vrf,
   9892             bcm_l3_vrf_stat_t stat,
   9893             uint32            num_entries,
   9894             uint32            *counter_indexes,
   9895             bcm_stat_value_t  *counter_values)
   9896 {
   9897     int rv = BCM_E_UNAVAIL;
   9898 
   9899     rv = _bcm_esw_l3_vrf_flex_stat_counter_get(unit, 1, vrf, stat, num_entries,
   9900                                          counter_indexes, counter_values);
   9901     return rv;
   9902 }
   9903 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   9904 /*
   9905  * Function:
   9906  *      _bcm_esw_l3_vrf_stat_counter_set
   9907  * Description:
   9908  *      Set L3 VRF counter value for specified VRF statistic type 
   9909  *
   9910  * Parameters:
   9911  *      unit             - (IN) unit number
   9912  *      vrf              - (IN) Virtual router instance
   9913  *      stat             - (IN) Type of the counter to retrieve
   9914  *                              I.e. ingress/egress byte/packet)
   9915  *      num_entries      - (IN) Number of counter Entries
   9916  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9917  *      counter_values   - (OUT) Pointer to counter values
   9918  *
   9919  * Return Value:
   9920  *      BCM_E_XXX
   9921  * Notes:
   9922  */
   9923 STATIC bcm_error_t _bcm_esw_l3_vrf_stat_counter_set(
   9924             int               unit, 
   9925             bcm_vrf_t         vrf, 
   9926             bcm_l3_vrf_stat_t stat, 
   9927             uint32            num_entries, 
   9928             uint32            *counter_indexes, 
   9929             bcm_stat_value_t  *counter_values)
   9930 {
   9931     uint32                     table_count=0;
   9932     uint32                     index_count=0;
   9933     uint32                     num_of_tables=0;
   9934     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   9935     uint32                     byte_flag=0;
   9936     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9937 
   9938     if ((stat == bcmL3VrfStatIngressPackets) ||
   9939         (stat == bcmL3VrfStatIngressBytes)) {
   9940          direction = bcmStatFlexDirectionIngress;
   9941     } else {
   9942          /* direction = bcmStatFlexDirectionEgress; */
   9943          return BCM_E_PARAM;
   9944     }
   9945 
   9946     if ((num_entries > 0) &&
   9947         ((NULL == counter_indexes) || (NULL == counter_values))) {
   9948         return BCM_E_PARAM;
   9949     }
   9950 
   9951     if (stat == bcmL3VrfStatIngressPackets) {
   9952         byte_flag=0;
   9953     } else {
   9954         byte_flag=1;
   9955     }
   9956     
   9957     BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_get_table_info(
   9958                         unit, vrf,&num_of_tables,&table_info[0]));
   9959 
   9960     for (table_count=0; table_count < num_of_tables ; table_count++) {
   9961          if (table_info[table_count].direction == direction) {
   9962              for (index_count=0; index_count < num_entries ; index_count++) {
   9963                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   9964                                       unit,
   9965                                       table_info[table_count].index,
   9966                                       table_info[table_count].table,
   9967                                       0, byte_flag,
   9968                                       counter_indexes[index_count],
   9969                                       &counter_values[index_count]));
   9970              }
   9971          }
   9972     }
   9973     return BCM_E_NONE;
   9974 }
   9975 #endif
   9976 
   9977 /*
   9978  * Function:
   9979  *      bcm_esw_l3_vrf_stat_counter_set
   9980  * Description:
   9981  *      Set L3 VRF counter value for specified VRF statistic type
   9982  *
   9983  * Parameters:
   9984  *      unit             - (IN) unit number
   9985  *      vrf              - (IN) Virtual router instance
   9986  *      stat             - (IN) Type of the counter to retrieve
   9987  *                              I.e. ingress/egress byte/packet)
   9988  *      num_entries      - (IN) Number of counter Entries
   9989  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9990  *      counter_values   - (OUT) Pointer to counter values
   9991  *
   9992  * Return Value:
   9993  *      BCM_E_XXX
   9994  * Notes:
   9995  */
   9996 int bcm_esw_l3_vrf_stat_counter_set(
   9997             int               unit,
   9998             bcm_vrf_t         vrf,
   9999             bcm_l3_vrf_stat_t stat,
  10000             uint32            num_entries,
  10001             uint32            *counter_indexes,
  10002             bcm_stat_value_t  *counter_values)
  10003 {
  10004 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10005     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10006         return _bcm_esw_l3_vrf_stat_counter_set(unit,vrf,stat,
  10007                       num_entries,counter_indexes,counter_values);
  10008     } else
  10009 #endif
  10010 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
  10011     if (soc_feature(unit,soc_feature_gport_service_counters)) {
  10012         uint64 val;
  10013         int rv = BCM_E_NONE;
  10014 
  10015         if (NULL == counter_values) {
  10016             return BCM_E_PARAM;
  10017         }
  10018 
  10019         if (stat == bcmL3VrfStatIngressPackets) {
  10020             COMPILER_64_SET(val,0,counter_values->packets);
  10021         } else {
  10022             COMPILER_64_SET(val,
  10023                       COMPILER_64_HI(counter_values->bytes),
  10024                       COMPILER_64_LO(counter_values->bytes));
  10025         }
  10026         rv = bcm_esw_l3_vrf_stat_set(unit,vrf,stat,val);
  10027 
  10028         return rv;
  10029 
  10030     } else
  10031 #endif
  10032     {
  10033         return BCM_E_UNAVAIL;
  10034     }
  10035 
  10036 }
  10037 
  10038 /*
  10039  * Function:
  10040  *      bcm_esw_l3_vrf_stat_id_get
  10041  * Description:
  10042  *      Get stat counter id associated with given VRF
  10043  *
  10044  * Parameters:
  10045  *      unit             - (IN) unit number
  10046  *      vrf              - (IN) Virtual router instance
  10047  *      stat             - (IN) Type of the counter to retrieve
  10048  *                              I.e. ingress/egress byte/packet)
  10049  *      Stat_counter_id  - (OUT) Stat Counter ID
  10050  *
  10051  * Return Value:
  10052  *      BCM_E_XXX
  10053  * Notes:
  10054  */
  10055 int bcm_esw_l3_vrf_stat_id_get(
  10056             int             unit,
  10057             bcm_vrf_t       vrf, 
  10058             bcm_l3_vrf_stat_t stat, 
  10059             uint32          *stat_counter_id)
  10060 {
  10061 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10062     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
  10063     uint32                     num_of_tables=0;
  10064     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
  10065     uint32                     index=0;
  10066     uint32                     num_stat_counter_ids=0;
  10067 
  10068     if ((stat == bcmL3VrfStatIngressPackets) ||
  10069         (stat == bcmL3VrfStatIngressBytes)) {
  10070          direction = bcmStatFlexDirectionIngress;
  10071     } else {
  10072          direction = bcmStatFlexDirectionEgress;
  10073     }
  10074     BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_get_table_info(
  10075                         unit,vrf,&num_of_tables,&table_info[0]));
  10076     for (index=0; index < num_of_tables ; index++) {
  10077          if (table_info[index].direction == direction)
  10078              return _bcm_esw_stat_flex_get_counter_id(
  10079                                   unit, 1, &table_info[index],
  10080                                   &num_stat_counter_ids,stat_counter_id);
  10081     }
  10082     return BCM_E_NOT_FOUND;
  10083 #else
  10084     return BCM_E_UNAVAIL;
  10085 #endif
  10086 }
  10087 
  10088 
  10089 
  10090 
  10091 
  10092 /*
  10093  * Function:
  10094  *      bcm_esw_l3_vrf_stat_enable_set
  10095  * Purpose:
  10096  *      Enable/disable packet and byte counters for the selected VRF.
  10097  * Parameters:
  10098  *      unit - (IN) Unit number.
  10099  *      vrf - (IN) Virtual router instance.
  10100  *      enable - (IN) Non-zero to enable counter collection, zero to disable.
  10101  * Returns:
  10102  *      BCM_E_XXX
  10103  * Notes:
  10104  */
  10105 int 
  10106 bcm_esw_l3_vrf_stat_enable_set(int unit, bcm_vrf_t vrf, int enable)
  10107 {
  10108 #if defined(BCM_TRIUMPH2_SUPPORT)
  10109     int                        rv = BCM_E_UNAVAIL;
  10110 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10111     uint32                     num_of_tables=0;
  10112     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
  10113     bcm_stat_object_t          object=bcmStatObjectIngPort;
  10114     uint32                     num_entries=0;
  10115     uint32                     num_stat_counter_ids=0;
  10116     uint32                     stat_counter_id[
  10117                                      BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]={0};
  10118 #endif /* BCM_KATANA_SUPPORT */
  10119     L3_INIT(unit);
  10120    if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10121     BCM_VRF_STAT_VALID(unit, vrf);
  10122 
  10123     L3_LOCK(unit);
  10124     rv = _bcm_esw_flex_stat_enable_set(unit, _bcmFlexStatTypeVrf,
  10125                                        _bcm_vrf_flex_stat_hw_index_set,
  10126                                        NULL, vrf, enable,0);
  10127     L3_UNLOCK(unit);
  10128     return rv;
  10129    } 
  10130 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10131     if (enable) { 
  10132         BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_get_table_info(
  10133                             unit,vrf,&num_of_tables,&table_info[0]));
  10134         if (num_of_tables != 1) {
  10135                 return BCM_E_INTERNAL;
  10136         }
  10137         if (table_info[0].direction != bcmStatFlexDirectionIngress) {
  10138             return BCM_E_INTERNAL;
  10139         }
  10140         BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_ingress_object(
  10141                             unit,table_info[0].table,
  10142                             table_info[0].index,NULL,&object)); 
  10143         BCM_IF_ERROR_RETURN(bcm_esw_stat_group_create(
  10144                             unit,object,bcmStatGroupModeSingle,
  10145                             &stat_counter_id[table_info[0].direction],
  10146                             &num_entries));
  10147         BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_attach(
  10148                             unit,vrf,stat_counter_id[table_info[0].direction])); 
  10149     } else {
  10150         BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_get_table_info(
  10151                             unit,vrf,&num_of_tables,&table_info[0]));
  10152         BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_counter_id(
  10153                             unit, num_of_tables,&table_info[0],
  10154                             &num_stat_counter_ids,&stat_counter_id[0])); 
  10155         if (num_stat_counter_ids != 1) {
  10156             return BCM_E_INTERNAL;
  10157         }
  10158         BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_detach(unit,vrf));
  10159         BCM_IF_ERROR_RETURN(bcm_esw_stat_group_destroy(
  10160                             unit,
  10161                             stat_counter_id[bcmStatFlexDirectionIngress]));
  10162     }
  10163     return BCM_E_NONE;
  10164 #else
  10165     return BCM_E_UNAVAIL;
  10166 #endif /* BCM_KATANA_SUPPORT */
  10167 #else
  10168     return BCM_E_UNAVAIL;
  10169 #endif /* BCM_TRIUMPH2_SUPPORT */
  10170 }
  10171 
  10172 /*
  10173  * Function:
  10174  *      _bcm_esw_l3_vrf_stat_get
  10175  * Purpose:
  10176  *      Get 64-bit counter value for specified VRF statistic type.
  10177  *      if sync_mode is set, sync the sw accumulated count
  10178  *      with hw count value first, else return sw count.
  10179  * Parameters:
  10180  *      unit      - (IN) Unit number.
  10181  *      sync_mode - (IN) hwcount is to be synced to sw count 
  10182  *      vrf       - (IN) Virtual router instance.
  10183  *      stat      - (IN) Type of the counter to retrieve.
  10184  *      val       - (OUT) Pointer to a counter value.
  10185  * Returns:
  10186  *      BCM_E_XXX
  10187  * Notes:
  10188  */
  10189 int 
  10190 _bcm_esw_l3_vrf_stat_get(int unit, int sync_mode,
  10191                          bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, uint64 *val)
  10192 {
  10193 #if defined(BCM_TRIUMPH2_SUPPORT)
  10194     int              rv=BCM_E_UNAVAIL;
  10195 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10196     uint32           counter_indexes=0;
  10197     bcm_stat_value_t counter_values={0};
  10198 #endif
  10199     L3_INIT(unit);
  10200    if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10201     BCM_VRF_STAT_VALID(unit, vrf);
  10202     L3_LOCK(unit);
  10203 
  10204     rv = _bcm_esw_flex_stat_get(unit, sync_mode, _bcmFlexStatTypeVrf, vrf,
  10205                            _bcm_esw_l3_vrf_stat_to_flex_stat(stat), val);
  10206     L3_UNLOCK(unit);
  10207     return rv;
  10208    } 
  10209 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10210     BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_counter_get(unit, sync_mode, vrf,
  10211                                                          stat, 1, 
  10212                                                          &counter_indexes, 
  10213                                                          &counter_values));
  10214     if (stat == bcmL3VrfStatIngressPackets) {
  10215         COMPILER_64_SET(*val,
  10216                         COMPILER_64_HI(counter_values.packets64),
  10217                         COMPILER_64_LO(counter_values.packets64));
  10218     } else {
  10219         COMPILER_64_SET(*val,
  10220                         COMPILER_64_HI(counter_values.bytes),
  10221                         COMPILER_64_LO(counter_values.bytes));
  10222     }
  10223     return BCM_E_NONE;
  10224 #else
  10225     return BCM_E_UNAVAIL;
  10226 #endif
  10227 #else
  10228     return BCM_E_UNAVAIL;
  10229 #endif /* BCM_TRIUMPH2_SUPPORT */
  10230 }
  10231 
  10232 
  10233 /*
  10234  * Function:
  10235  *      bcm_esw_l3_vrf_stat_get
  10236  * Purpose:
  10237  *      Get 64-bit counter value for specified VRF statistic type.
  10238  * Parameters:
  10239  *      unit - (IN) Unit number.
  10240  *      vrf - (IN) Virtual router instance.
  10241  *      stat - (IN) Type of the counter to retrieve.
  10242  *      val - (OUT) Pointer to a counter value.
  10243  * Returns:
  10244  *      BCM_E_XXX
  10245  * Notes:
  10246  */
  10247 int 
  10248 bcm_esw_l3_vrf_stat_get(int unit, bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, 
  10249                         uint64 *val)
  10250 {
  10251     int rv = BCM_E_UNAVAIL;
  10252 
  10253     rv = _bcm_esw_l3_vrf_stat_get(unit, 0, vrf, stat, val);
  10254 
  10255     return rv;
  10256 }
  10257 
  10258 
  10259 /*
  10260  * Function:
  10261  *      bcm_esw_l3_vrf_stat_sync_get
  10262  * Purpose:
  10263  *       Get 64-bit counter value for specified VRF statistic type.
  10264  *       sw accumulated counters synced with hw count.
  10265  * Parameters:
  10266  *      unit - (IN) Unit number.
  10267  *      vrf - (IN) Virtual router instance.
  10268  *      stat - (IN) Type of the counter to retrieve.
  10269  *      val - (OUT) Pointer to a counter value.
  10270  * Returns:
  10271  *      BCM_E_XXX
  10272  * Notes:
  10273  */
  10274 int 
  10275 bcm_esw_l3_vrf_stat_sync_get(int unit, bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, 
  10276                         uint64 *val)
  10277 {
  10278     int rv = BCM_E_UNAVAIL;
  10279 
  10280     rv = _bcm_esw_l3_vrf_stat_get(unit, 1, vrf, stat, val);
  10281 
  10282     return rv;
  10283 } 
  10284 
  10285 
  10286 
  10287 /*
  10288  * Function:
  10289  *      _bcm_esw_l3_vrf_stat_get32
  10290  * Purpose:
  10291  *      Get lower 32-bit counter value for specified VRF statistic
  10292  *      type.
  10293  *      if sync_mode is set, sync the sw accumulated count
  10294  *      with hw count value first, else return sw count.
  10295  * Parameters:
  10296  *      unit        - (IN) Unit number.
  10297  *      sync_mode   - (IN) hwcount is to be synced to sw count 
  10298  *      vrf         - (IN) Virtual router instance.
  10299  *      stat        - (IN) Type of the counter to retrieve.
  10300  *      val         - (OUT) Pointer to a counter value.
  10301  * Returns:
  10302  *      BCM_E_XXX
  10303  * Notes:
  10304  */
  10305 int 
  10306 _bcm_esw_l3_vrf_stat_get32(int unit, int sync_mode, bcm_vrf_t vrf, 
  10307                           bcm_l3_vrf_stat_t stat, uint32 *val)
  10308 {
  10309 #if defined(BCM_TRIUMPH2_SUPPORT)
  10310     int rv = BCM_E_UNAVAIL;
  10311 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10312     uint32           counter_indexes=0;
  10313     bcm_stat_value_t counter_values={0};
  10314 #endif
  10315    if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10316     L3_INIT(unit);
  10317     BCM_VRF_STAT_VALID(unit, vrf);
  10318     L3_LOCK(unit);
  10319 
  10320     rv = _bcm_esw_flex_stat_get32(unit, sync_mode, _bcmFlexStatTypeVrf, vrf,
  10321                           _bcm_esw_l3_vrf_stat_to_flex_stat(stat), val);
  10322     L3_UNLOCK(unit);
  10323     return rv;
  10324    }
  10325 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10326     BCM_IF_ERROR_RETURN(_bcm_esw_l3_vrf_stat_counter_get(unit, sync_mode, vrf,
  10327                                                          stat, 1, 
  10328                                                          &counter_indexes, 
  10329                                                          &counter_values));
  10330     if (stat == bcmL3VrfStatIngressPackets) {
  10331         *val = counter_values.packets;
  10332     } else {
  10333         /* Ignoring Hi bytes value */
  10334         *val = COMPILER_64_LO(counter_values.bytes);
  10335     }
  10336     return BCM_E_NONE;
  10337 #else
  10338     return BCM_E_UNAVAIL;
  10339 #endif
  10340 #else
  10341     return BCM_E_UNAVAIL;
  10342 #endif /* BCM_TRIUMPH2_SUPPORT */
  10343 }
  10344 
  10345 /*
  10346  * Function:
  10347  *      bcm_esw_l3_vrf_stat_get32
  10348  * Purpose:
  10349  *      Get lower 32-bit counter value for specified VRF statistic
  10350  *      type.
  10351  * Parameters:
  10352  *      unit - (IN) Unit number.
  10353  *      sync_mode        - (IN) hwcount is to be synced to sw count 
  10354  *      vrf - (IN) Virtual router instance.
  10355  *      stat - (IN) Type of the counter to retrieve.
  10356  *      val - (OUT) Pointer to a counter value.
  10357  * Returns:
  10358  *      BCM_E_XXX
  10359  * Notes:
  10360  */
  10361 int 
  10362 bcm_esw_l3_vrf_stat_get32(int unit,bcm_vrf_t vrf, 
  10363                           bcm_l3_vrf_stat_t stat, uint32 *val)
  10364 {
  10365     int rv = BCM_E_UNAVAIL;
  10366 
  10367     rv = _bcm_esw_l3_vrf_stat_get32(unit, 0, vrf, stat, val);
  10368 
  10369     return rv;
  10370 }
  10371 
  10372 
  10373 /*
  10374  * Function:
  10375  *      bcm_esw_l3_vrf_stat_sync_get32
  10376  * Purpose:
  10377  *      Get lower 32-bit counter value for specified VRF statistic
  10378  *      type.
  10379  *      sw accumulated counters synced with hw count.
  10380  * Parameters:
  10381  *      unit - (IN) Unit number.
  10382  *      vrf - (IN) Virtual router instance.
  10383  *      stat - (IN) Type of the counter to retrieve.
  10384  *      val - (OUT) Pointer to a counter value.
  10385  * Returns:
  10386  *      BCM_E_XXX
  10387  * Notes:
  10388  */
  10389 int 
  10390 bcm_esw_l3_vrf_stat_sync_get32(int unit,bcm_vrf_t vrf, 
  10391                           bcm_l3_vrf_stat_t stat, uint32 *val)
  10392 {
  10393     int rv = BCM_E_UNAVAIL;
  10394 
  10395     rv = _bcm_esw_l3_vrf_stat_get32(unit, 1, vrf, stat, val);
  10396 
  10397     return rv;
  10398 }
  10399 
  10400 /*
  10401  * Function:
  10402  *      bcm_esw_l3_vrf_stat_set
  10403  * Purpose:
  10404  *      Set 64-bit counter value for specified VRF statistic type.
  10405  * Parameters:
  10406  *      unit - (IN) Unit number.
  10407  *      vrf - (IN) Virtual router instance.
  10408  *      stat - (IN) Type of the counter to retrieve.
  10409  *      val - (IN) New counter value.
  10410  * Returns:
  10411  *      BCM_E_XXX
  10412  * Notes:
  10413  */
  10414 int 
  10415 bcm_esw_l3_vrf_stat_set(int unit, bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, 
  10416                         uint64 val)
  10417 {
  10418 #if defined(BCM_TRIUMPH2_SUPPORT)
  10419     int rv = BCM_E_UNAVAIL;
  10420 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10421     uint32           counter_indexes=0;
  10422     bcm_stat_value_t counter_values={0};
  10423 #endif
  10424     L3_INIT(unit);
  10425    if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10426     BCM_VRF_STAT_VALID(unit, vrf);
  10427     L3_LOCK(unit);
  10428 
  10429     rv = _bcm_esw_flex_stat_set(unit, _bcmFlexStatTypeVrf, vrf,
  10430                            _bcm_esw_l3_vrf_stat_to_flex_stat(stat), val);
  10431     L3_UNLOCK(unit);
  10432     return rv;
  10433    } 
  10434 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10435     if (stat == bcmL3VrfStatIngressPackets) {
  10436         counter_values.packets = COMPILER_64_LO(val);
  10437     } else {
  10438         COMPILER_64_SET(counter_values.bytes,
  10439                         COMPILER_64_HI(val),
  10440                         COMPILER_64_LO(val));
  10441     }
  10442     BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_counter_set(
  10443                         unit,vrf,stat,1, &counter_indexes, &counter_values));
  10444     return BCM_E_NONE;
  10445 #else
  10446     return BCM_E_UNAVAIL;
  10447 #endif
  10448 #else
  10449     return BCM_E_UNAVAIL;
  10450 #endif /* BCM_TRIUMPH2_SUPPORT */
  10451 }
  10452 
  10453 /*
  10454  * Function:
  10455  *      bcm_esw_l3_vrf_stat_set32
  10456  * Purpose:
  10457  *      Set lower 32-bit counter value for specified VRF statistic
  10458  *      type.
  10459  * Parameters:
  10460  *      unit - (IN) Unit number.
  10461  *      vrf - (IN) Virtual router instance.
  10462  *      stat - (IN) Type of the counter to retrieve.
  10463  *      val - (IN) New counter value.
  10464  * Returns:
  10465  *      BCM_E_XXX
  10466  * Notes:
  10467  */
  10468 int 
  10469 bcm_esw_l3_vrf_stat_set32(int unit, bcm_vrf_t vrf, 
  10470                           bcm_l3_vrf_stat_t stat, uint32 val)
  10471 {
  10472 #if defined(BCM_TRIUMPH2_SUPPORT)
  10473     int rv = BCM_E_UNAVAIL;
  10474 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10475     uint32           counter_indexes=0;
  10476     bcm_stat_value_t counter_values={0};
  10477 #endif
  10478     L3_INIT(unit);
  10479    if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10480     BCM_VRF_STAT_VALID(unit, vrf);
  10481     L3_LOCK(unit);
  10482 
  10483     rv = _bcm_esw_flex_stat_set32(unit, _bcmFlexStatTypeVrf, vrf,
  10484                             _bcm_esw_l3_vrf_stat_to_flex_stat(stat), val);
  10485     L3_UNLOCK(unit);
  10486     return rv;
  10487    } 
  10488 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10489     if (stat == bcmL3VrfStatIngressPackets) {
  10490         counter_values.packets = val;
  10491     } else {
  10492         /* Ignoring high value */
  10493         COMPILER_64_SET(counter_values.bytes,0,val);
  10494     }
  10495     BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_counter_set(
  10496                         unit,vrf, stat, 1, &counter_indexes, &counter_values));
  10497     return BCM_E_NONE;
  10498 #else
  10499     return BCM_E_UNAVAIL;
  10500 #endif
  10501 #else
  10502     return BCM_E_UNAVAIL;
  10503 #endif /* BCM_TRIUMPH2_SUPPORT */
  10504 }
  10505 
  10506 /*
  10507  * Function:
  10508  *      bcm_esw_l3_vrf_stat_multi_get
  10509  * Purpose:
  10510  *      Get 64-bit counter value for multiple VRF statistic types.
  10511  * Parameters:
  10512  *      unit - (IN) Unit number.
  10513  *      vrf - (IN) Virtual router instance.
  10514  *      nstat - (IN) Number of elements in stat array
  10515  *      stat_arr - (IN) Collected statistics descriptors array
  10516  *      value_arr - (OUT) Collected counters values
  10517  * Returns:
  10518  *      BCM_E_XXX
  10519  * Notes:
  10520  */
  10521 int 
  10522 bcm_esw_l3_vrf_stat_multi_get(int unit, bcm_vrf_t vrf, int nstat, 
  10523                               bcm_l3_vrf_stat_t *stat_arr,
  10524                               uint64 *value_arr)
  10525 {
  10526 #if defined(BCM_TRIUMPH2_SUPPORT)
  10527     int rv = BCM_E_UNAVAIL;
  10528     _bcm_flex_stat_t fs_arr[_bcmFlexStatNum]; /* Normalize stats */
  10529     int                 idx;       /* Statistics iteration index. */
  10530 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10531     uint32           counter_indexes=0;
  10532     bcm_stat_value_t counter_values={0};
  10533 #endif
  10534 
  10535     L3_INIT(unit);
  10536 
  10537   if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10538     BCM_VRF_STAT_VALID(unit, vrf);
  10539     BCM_IF_ERROR_RETURN
  10540         (_bcm_l3_vrf_stat_array_convert(unit, nstat, stat_arr, fs_arr));
  10541     BCM_VRF_STAT_ARRAY_VALID(unit, nstat, value_arr);
  10542     L3_LOCK(unit);
  10543 
  10544     rv = _bcm_esw_flex_stat_multi_get(unit, _bcmFlexStatTypeVrf, vrf,
  10545                                       nstat, fs_arr, value_arr);
  10546     L3_UNLOCK(unit);
  10547     return rv; 
  10548   } 
  10549 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10550     if ( (NULL == stat_arr) || (NULL == value_arr) ) {
  10551         return BCM_E_PARAM;
  10552     }
  10553     for (idx=0;idx < nstat ; idx ++) {
  10554          BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_counter_get( 
  10555                              unit, vrf, stat_arr[idx], 
  10556                              1, &counter_indexes, &counter_values));
  10557          if (stat_arr[idx] == bcmL3VrfStatIngressPackets) {
  10558              COMPILER_64_SET(value_arr[idx],
  10559                              COMPILER_64_HI(counter_values.packets64),
  10560                              COMPILER_64_LO(counter_values.packets64));
  10561          } else {
  10562              COMPILER_64_SET(value_arr[idx],
  10563                              COMPILER_64_HI(counter_values.bytes),
  10564                              COMPILER_64_LO(counter_values.bytes));
  10565          }
  10566     }
  10567     return  BCM_E_NONE;
  10568 #else
  10569     return BCM_E_UNAVAIL;
  10570 #endif
  10571 #else
  10572     return BCM_E_UNAVAIL;
  10573 #endif /* BCM_TRIUMPH2_SUPPORT */
  10574 }
  10575 
  10576 /*
  10577  * Function:
  10578  *      bcm_esw_l3_vrf_stat_multi_get32
  10579  * Purpose:
  10580  *      Get lower 32-bit counter value for multiple VRF statistic
  10581  *      types.
  10582  * Parameters:
  10583  *      unit - (IN) Unit number.
  10584  *      vrf - (IN) Virtual router instance.
  10585  *      nstat - (IN) Number of elements in stat array
  10586  *      stat_arr - (IN) Collected statistics descriptors array
  10587  *      value_arr - (OUT) Collected counters values
  10588  * Returns:
  10589  *      BCM_E_XXX
  10590  * Notes:
  10591  */
  10592 int 
  10593 bcm_esw_l3_vrf_stat_multi_get32(int unit, bcm_vrf_t vrf, int nstat, 
  10594                                 bcm_l3_vrf_stat_t *stat_arr,
  10595                                 uint32 *value_arr)
  10596 {
  10597 #if defined(BCM_TRIUMPH2_SUPPORT)
  10598     int rv = BCM_E_UNAVAIL;
  10599     _bcm_flex_stat_t fs_arr[_bcmFlexStatNum]; /* Normalize stats */
  10600     int                 idx;       /* Statistics iteration index. */
  10601 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10602     uint32           counter_indexes=0;
  10603     bcm_stat_value_t counter_values={0};
  10604 #endif
  10605 
  10606     L3_INIT(unit);
  10607   if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10608     BCM_VRF_STAT_VALID(unit, vrf);
  10609     BCM_IF_ERROR_RETURN
  10610         (_bcm_l3_vrf_stat_array_convert(unit, nstat, stat_arr, fs_arr));
  10611     BCM_VRF_STAT_ARRAY_VALID(unit, nstat, value_arr);
  10612     L3_LOCK(unit);
  10613 
  10614     rv = _bcm_esw_flex_stat_multi_get32(unit, _bcmFlexStatTypeVrf, vrf,
  10615                                         nstat, fs_arr, value_arr);
  10616     L3_UNLOCK(unit);
  10617     return rv;
  10618   } 
  10619 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10620     if ( (NULL == stat_arr) || (NULL == value_arr) ) {
  10621         return BCM_E_PARAM;
  10622     }
  10623     for (idx=0;idx < nstat ; idx ++) {
  10624          BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_counter_get(
  10625                              unit, vrf, stat_arr[idx], 
  10626                              1, &counter_indexes, &counter_values));
  10627          if (stat_arr[idx] == bcmL3VrfStatIngressPackets) {
  10628              value_arr[idx] = counter_values.packets;
  10629          } else {
  10630              value_arr[idx] = COMPILER_64_LO(counter_values.bytes);
  10631          }
  10632     }
  10633     return BCM_E_NONE;
  10634 #else
  10635     return BCM_E_UNAVAIL;
  10636 #endif
  10637 #else
  10638     return BCM_E_UNAVAIL;
  10639 #endif /* BCM_TRIUMPH2_SUPPORT */
  10640 }
  10641 
  10642 /*
  10643  * Function:
  10644  *      bcm_esw_l3_vrf_stat_multi_set
  10645  * Purpose:
  10646  *      Set 64-bit counter value for multiple VRF statistic types.
  10647  * Parameters:
  10648  *      unit - (IN) Unit number.
  10649  *      vrf - (IN) Virtual router instance.
  10650  *      nstat - (IN) Number of elements in stat array
  10651  *      stat_arr - (IN) New statistics descriptors array
  10652  *      value_arr - (IN) New counters values
  10653  * Returns:
  10654  *      BCM_E_XXX
  10655  * Notes:
  10656  */
  10657 int 
  10658 bcm_esw_l3_vrf_stat_multi_set(int unit, bcm_vrf_t vrf, int nstat, 
  10659                               bcm_l3_vrf_stat_t *stat_arr, 
  10660                               uint64 *value_arr)
  10661 {
  10662 #if defined(BCM_TRIUMPH2_SUPPORT)
  10663     int rv = BCM_E_UNAVAIL;
  10664     _bcm_flex_stat_t fs_arr[_bcmFlexStatNum]; /* Normalize stats */
  10665     int                 idx;       /* Statistics iteration index. */
  10666 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10667     uint32           counter_indexes=0;
  10668     bcm_stat_value_t counter_values={0};
  10669 #endif
  10670 
  10671     L3_INIT(unit);
  10672   if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10673     BCM_VRF_STAT_VALID(unit, vrf);
  10674     BCM_IF_ERROR_RETURN
  10675         (_bcm_l3_vrf_stat_array_convert(unit, nstat, stat_arr, fs_arr));
  10676     BCM_VRF_STAT_ARRAY_VALID(unit, nstat, value_arr);
  10677     L3_LOCK(unit);
  10678 
  10679     rv = _bcm_esw_flex_stat_multi_set(unit, _bcmFlexStatTypeVrf, vrf,
  10680                                       nstat, fs_arr, value_arr);
  10681     L3_UNLOCK(unit);
  10682     return rv;
  10683   } 
  10684 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10685     if ( (NULL == stat_arr) || (NULL == value_arr) ) {
  10686         return BCM_E_PARAM;
  10687     }
  10688     for (idx=0;idx < nstat ; idx ++) {
  10689          if (stat_arr[idx] == bcmL3VrfStatIngressPackets) {
  10690              counter_values.packets = COMPILER_64_LO(value_arr[idx]);
  10691          } else {
  10692              COMPILER_64_SET(counter_values.bytes,
  10693                              COMPILER_64_HI(value_arr[idx]),
  10694                              COMPILER_64_LO(value_arr[idx]));
  10695          }
  10696          BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_counter_set( 
  10697                              unit, vrf, stat_arr[idx], 1, 
  10698                              &counter_indexes, &counter_values));
  10699     }
  10700     return BCM_E_NONE;
  10701 #else
  10702     return BCM_E_UNAVAIL;
  10703 #endif
  10704 #else
  10705     return BCM_E_UNAVAIL;
  10706 #endif /* BCM_TRIUMPH2_SUPPORT */
  10707 }
  10708 
  10709 /*
  10710  * Function:
  10711  *      bcm_esw_l3_vrf_stat_multi_set32
  10712  * Purpose:
  10713  *      Set lower 32-bit counter value for multiple VRF statistic
  10714  *      types.
  10715  * Parameters:
  10716  *      unit - (IN) Unit number.
  10717  *      vrf - (IN) Virtual router instance.
  10718  *      nstat - (IN) Number of elements in stat array
  10719  *      stat_arr - (IN) New statistics descriptors array
  10720  *      value_arr - (IN) New counters values
  10721  * Returns:
  10722  *      BCM_E_XXX
  10723  * Notes:
  10724  */
  10725 int 
  10726 bcm_esw_l3_vrf_stat_multi_set32(int unit, bcm_vrf_t vrf, int nstat,
  10727                                 bcm_l3_vrf_stat_t *stat_arr, 
  10728                                 uint32 *value_arr)
  10729 {
  10730 #if defined(BCM_TRIUMPH2_SUPPORT)
  10731     int rv = BCM_E_UNAVAIL;
  10732     _bcm_flex_stat_t fs_arr[_bcmFlexStatNum]; /* Normalize stats */
  10733     int                 idx;       /* Statistics iteration index. */
  10734 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10735     uint32           counter_indexes=0;
  10736     bcm_stat_value_t counter_values={0};
  10737 #endif
  10738 
  10739     L3_INIT(unit);
  10740  if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
  10741     BCM_VRF_STAT_VALID(unit, vrf);
  10742     BCM_IF_ERROR_RETURN
  10743         (_bcm_l3_vrf_stat_array_convert(unit, nstat, stat_arr, fs_arr));
  10744     BCM_VRF_STAT_ARRAY_VALID(unit, nstat, value_arr);
  10745     L3_LOCK(unit);
  10746 
  10747     rv = _bcm_esw_flex_stat_multi_set32(unit, _bcmFlexStatTypeVrf, vrf,
  10748                                         nstat, fs_arr, value_arr);
  10749     L3_UNLOCK(unit);
  10750     return rv;
  10751   } 
  10752 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10753     if ( (NULL == stat_arr) || (NULL == value_arr) ) {
  10754         return BCM_E_PARAM;
  10755     }
  10756     for (idx=0;idx < nstat ; idx ++) {
  10757          if (stat_arr[idx] == bcmL3VrfStatIngressPackets) {
  10758              counter_values.packets = value_arr[idx];
  10759          } else {
  10760              COMPILER_64_SET(counter_values.bytes,0,value_arr[idx]);
  10761          }
  10762          BCM_IF_ERROR_RETURN(bcm_esw_l3_vrf_stat_counter_set(
  10763                              unit, vrf, stat_arr[idx], 1, 
  10764                              &counter_indexes, &counter_values));
  10765     }
  10766     return BCM_E_NONE;
  10767 #else
  10768     return BCM_E_UNAVAIL;
  10769 #endif
  10770 #else
  10771     return BCM_E_UNAVAIL;
  10772 #endif /* BCM_TRIUMPH2_SUPPORT */
  10773 }
  10774 
  10775 /*
  10776  * Function:
  10777  *     bcm_esw_l3_vrf_route_data_mode_get
  10778  * Purpose:
  10779  *     This function returns the current ALPM route associated data mode
  10780  *     in the VRF and IP type, including the default mode by configuration
  10781  *     if no vrf specific setting available.
  10782  * Parameters:
  10783  *     unit  - (IN) BCM device number
  10784  *     vrf   - (IN) Virtual router instance.
  10785  *     flgas - (IN) IP type flag (BCM_L3_IP6)
  10786  *     mode  - (OUT) Current ALPM data mode.
  10787  * Returns:
  10788  *     BCM_E_XXX:
  10789  *      - BCM_E_NONE:    on success
  10790  *      - BCM_E_PARAM:   if NULL or invalid parameters are passed
  10791  *      - BCM_E_UNAVAIL: if this feature is not supported (eg. ALPM disabled).
  10792  * Notes:
  10793  *     Currently this feature is only supported in TOMAHAWK3 ALPM2.
  10794  */
  10795 int
  10796 bcm_esw_l3_vrf_route_data_mode_get(int unit, bcm_vrf_t vrf, uint32 flags,
  10797                                    bcm_l3_vrf_route_data_mode_t *mode)
  10798 {
  10799 #ifdef ALPM_ENABLE
  10800 #ifdef BCM_TOMAHAWK3_SUPPORT
  10801     int rv;
  10802 
  10803     /* Currently this API is supported on Tomahawk3 only */
  10804     if (!SOC_IS_TOMAHAWK3(unit)) {
  10805         return BCM_E_UNAVAIL;
  10806     }
  10807 
  10808     if (mode == NULL) {
  10809         return BCM_E_PARAM;
  10810     }
  10811 
  10812     if ((vrf > SOC_VRF_MAX(unit)) ||
  10813         (vrf < BCM_L3_VRF_GLOBAL)) {
  10814         return (BCM_E_PARAM);
  10815     }
  10816 
  10817     rv = bcm_esw_alpm_vrf_data_mode_get(unit, vrf, flags, mode);
  10818 
  10819     return rv;
  10820 
  10821 #else /* BCM_TOMAHAWK3_SUPPORT */
  10822     return BCM_E_UNAVAIL;
  10823 #endif
  10824 #else /* ALPM_ENABLE */
  10825     return BCM_E_UNAVAIL;
  10826 #endif
  10827 }
  10828 
  10829 /*
  10830  * Function:
  10831  *     bcm_esw_l3_vrf_route_data_mode_set
  10832  * Purpose:
  10833  *     This function sets ALPM route associated data mode in the VRF
  10834  *     and IP type.
  10835  * Parameters:
  10836  *     unit  - (IN) BCM device number
  10837  *     vrf   - (IN) Virtual router instance.
  10838  *     flgas - (IN) IP type flag (BCM_L3_IP6)
  10839  *     mode  - (IN) ALPM data mode to set.
  10840  * Returns:
  10841  *     BCM_E_XXX:
  10842  *      - BCM_E_NONE:    on success
  10843  *      - BCM_E_PARAM:   if invalid parameters are passed
  10844  *      - BCM_E_UNAVAIL: if this feature is not supported (eg. ALPM disabled).
  10845  *      - BCM_E_FAIL:    if change of ALPM data mode is not allowed
  10846  *                       in the VRF and IP type.
  10847  * Notes:
  10848  *     Currently this feature is only supported in TOMAHAWK3 ALPM2.
  10849  *
  10850  *     Initial Implementation: user can call this API if want to change the
  10851  *     default mode in this VRF and IP type (IPv4 or IPv6), before add the
  10852  *     first ALPM route in the VRF and IP type. Mode change is not allowed
  10853  *     once ALPM VRF initialized (ALPM route added in the VRF and IP type).
  10854  *
  10855  *     Future Enhancement (TBD): user can call this API anytime and SDK will
  10856  *     change the assoc data mode for all ALPM routes in the VRF and IP type.
  10857  */
  10858 int
  10859 bcm_esw_l3_vrf_route_data_mode_set(int unit, bcm_vrf_t vrf, uint32 flags,
  10860                                    bcm_l3_vrf_route_data_mode_t mode)
  10861 {
  10862 #ifdef ALPM_ENABLE
  10863 #ifdef BCM_TOMAHAWK3_SUPPORT
  10864     int rv;
  10865 
  10866     /* Currently this API is supported on Tomahawk3 only */
  10867     if (!SOC_IS_TOMAHAWK3(unit)) {
  10868         return BCM_E_UNAVAIL;
  10869     }
  10870 
  10871     if ((vrf > SOC_VRF_MAX(unit)) ||
  10872         (vrf < BCM_L3_VRF_GLOBAL)) {
  10873         return (BCM_E_PARAM);
  10874     }
  10875 
  10876     rv = bcm_esw_alpm_vrf_data_mode_set(unit, vrf, flags, mode);
  10877 
  10878     return rv;
  10879 
  10880 #else /* BCM_TOMAHAWK3_SUPPORT */
  10881     return BCM_E_UNAVAIL;
  10882 #endif
  10883 #else /* ALPM_ENABLE */
  10884     return BCM_E_UNAVAIL;
  10885 #endif
  10886 }
  10887 
  10888 /*
  10889  * Function:
  10890  *      bcm_esw_l3_source_bind_enable_set
  10891  * Purpose:
  10892  *      Enable or disable l3 source binding checks on an ingress port.
  10893  * Parameters:
  10894  *      unit - (IN) Unit number.
  10895  *      port - (IN) Packet ingress port.
  10896  *      enable - (IN) Non-zero to enable l3 source binding checks,
  10897  *               zero to disable.
  10898  * Returns:
  10899  *      BCM_E_XXX
  10900  * Notes:
  10901  */
  10902 int 
  10903 bcm_esw_l3_source_bind_enable_set(int unit, bcm_port_t port, int enable)
  10904 {
  10905 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  10906     int key_type_value;
  10907     int key_type;
  10908     _bcm_port_config_t key_config, port_config;
  10909 
  10910     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  10911         return BCM_E_UNAVAIL;
  10912     }
  10913 
  10914     if (enable) {
  10915         BCM_IF_ERROR_RETURN
  10916             (_bcm_esw_port_config_get(unit, port,
  10917                                 _bcmPortVTKeyTypeSecond, &key_type_value));
  10918         BCM_IF_ERROR_RETURN
  10919             (_bcm_esw_pt_vtkey_type_get(unit,key_type_value,&key_type));
  10920 
  10921         if (key_type == VLXLT_HASH_KEY_TYPE_OVID) {
  10922             /* Overwrite OVID if it's in second slot */
  10923             key_config = _bcmPortVTKeyTypeSecond;
  10924             port_config = _bcmPortVTKeyPortSecond;
  10925         } else { /* Otherwise just use first slot */
  10926             key_config = _bcmPortVTKeyTypeFirst;
  10927             port_config = _bcmPortVTKeyPortFirst;
  10928         }
  10929 
  10930         BCM_IF_ERROR_RETURN
  10931             (_bcm_esw_pt_vtkey_type_value_get(unit,
  10932                      VLXLT_HASH_KEY_TYPE_HPAE,&key_type_value));
  10933         BCM_IF_ERROR_RETURN
  10934             (_bcm_esw_port_config_set(unit, port, key_config,
  10935                                       key_type_value));
  10936         BCM_IF_ERROR_RETURN
  10937             (_bcm_esw_pt_vtkey_type_value_get(unit,
  10938                      VLXLT_HASH_KEY_TYPE_OTAG,&key_type_value));
  10939         BCM_IF_ERROR_RETURN
  10940             (_bcm_esw_port_config_set(unit, port, port_config,
  10941                                       key_type_value));
  10942     } else {
  10943         BCM_IF_ERROR_RETURN
  10944             (_bcm_esw_port_config_get(unit, port,
  10945                                _bcmPortVTKeyTypeSecond, &key_type_value));
  10946         BCM_IF_ERROR_RETURN
  10947             (_bcm_esw_pt_vtkey_type_get(unit,key_type_value,&key_type));
  10948         if (key_type == VLXLT_HASH_KEY_TYPE_HPAE) {
  10949             key_config = _bcmPortVTKeyTypeSecond;
  10950             port_config = _bcmPortVTKeyPortSecond;
  10951         } else {
  10952             BCM_IF_ERROR_RETURN
  10953                 (_bcm_esw_port_config_get(unit, port,
  10954                                           _bcmPortVTKeyTypeFirst,
  10955                                           &key_type_value));
  10956             BCM_IF_ERROR_RETURN
  10957                 (_bcm_esw_pt_vtkey_type_get(unit,
  10958                                  key_type_value,&key_type));
  10959             if (key_type == VLXLT_HASH_KEY_TYPE_HPAE) {
  10960                 key_config = _bcmPortVTKeyTypeFirst;
  10961                 port_config = _bcmPortVTKeyPortFirst;
  10962             } else {
  10963                 /* Already not enabled */
  10964                 return BCM_E_NONE;
  10965             }
  10966         }
  10967         /* Return to OVID usage */
  10968         BCM_IF_ERROR_RETURN
  10969             (_bcm_esw_pt_vtkey_type_value_get(unit,
  10970                      VLXLT_HASH_KEY_TYPE_OVID,&key_type_value));
  10971         BCM_IF_ERROR_RETURN
  10972             (_bcm_esw_port_config_set(unit, port, key_config,
  10973                                       key_type_value));
  10974         BCM_IF_ERROR_RETURN
  10975             (_bcm_esw_pt_vtkey_type_value_get(unit,
  10976                      VLXLT_HASH_KEY_TYPE_OTAG,&key_type_value));
  10977         BCM_IF_ERROR_RETURN
  10978             (_bcm_esw_port_config_set(unit, port, port_config,
  10979                                       key_type_value));
  10980     }
  10981     return BCM_E_NONE; 
  10982 #else
  10983     return BCM_E_UNAVAIL; 
  10984 #endif
  10985 }
  10986 
  10987 /*
  10988  * Function:
  10989  *      bcm_eswl3_source_bind_enable_get
  10990  * Purpose:
  10991  *      Retrieve whether l3 source binding checks are performed on an
  10992  *      ingress port.
  10993  * Parameters:
  10994  *      unit - (IN) Unit number.
  10995  *      port - (IN) Packet ingress port.
  10996  *      enable - (OUT) Non-zero if l3 source binding checks are enabled,
  10997  *               zero if disabled.
  10998  * Returns:
  10999  *      BCM_E_XXX
  11000  * Notes:
  11001  */
  11002 int 
  11003 bcm_esw_l3_source_bind_enable_get(int unit, bcm_port_t port, int *enable)
  11004 {
  11005 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  11006     int key_type;
  11007     int key_type_value;
  11008     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11009         return BCM_E_UNAVAIL;
  11010     }
  11011 
  11012     BCM_IF_ERROR_RETURN
  11013         (_bcm_esw_port_config_get(unit, port,
  11014                                   _bcmPortVTKeyTypeSecond, &key_type_value));
  11015     BCM_IF_ERROR_RETURN
  11016         (_bcm_esw_pt_vtkey_type_get(unit,key_type_value,&key_type));
  11017 
  11018     if (key_type == VLXLT_HASH_KEY_TYPE_HPAE) {
  11019         *enable = TRUE;
  11020     } else {
  11021         BCM_IF_ERROR_RETURN
  11022             (_bcm_esw_port_config_get(unit, port,
  11023                                 _bcmPortVTKeyTypeFirst, &key_type_value));
  11024         BCM_IF_ERROR_RETURN
  11025             (_bcm_esw_pt_vtkey_type_get(unit,key_type_value,&key_type));
  11026         if (key_type == VLXLT_HASH_KEY_TYPE_HPAE) {
  11027             *enable = TRUE;
  11028         } else {
  11029             *enable = FALSE;
  11030         }
  11031     }
  11032 
  11033     return BCM_E_NONE; 
  11034 #else
  11035     return BCM_E_UNAVAIL; 
  11036 #endif
  11037 }
  11038  
  11039 #if defined(BCM_TRIUMPH3_SUPPORT)
  11040 STATIC int 
  11041 _tr3_l3_source_bind_add(int unit, bcm_l3_source_bind_t *info)
  11042 {
  11043     int             tmp_id, rv, idx = 0;
  11044     bcm_module_t    modid_out;
  11045     bcm_port_t      port_out;
  11046     bcm_trunk_t     trunk_out;
  11047     vlan_xlate_extd_entry_t vxent, res_vxent;
  11048 
  11049     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11050         return BCM_E_UNAVAIL;
  11051     }
  11052 
  11053     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11054         /* Not supported yet */
  11055         return BCM_E_UNAVAIL;
  11056     }
  11057 
  11058     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11059         /* Not supported */
  11060         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11061              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  11062              bcm_errmsg(BCM_E_PARAM)));
  11063         return BCM_E_PARAM;
  11064     }
  11065 
  11066     sal_memset(&vxent, 0, sizeof(vlan_xlate_extd_entry_t));
  11067     sal_memset(&res_vxent, 0, sizeof(vlan_xlate_extd_entry_t));
  11068 
  11069     /* MAC_IP_BIND lookup key type */
  11070     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, VALID_0f, 1);
  11071     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, VALID_1f, 1);
  11072     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, KEY_TYPE_0f,
  11073                               TR3_VLXLT_HASH_KEY_TYPE_HPAE);
  11074     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, KEY_TYPE_1f,
  11075                               TR3_VLXLT_HASH_KEY_TYPE_HPAE);
  11076     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent,
  11077                               MAC_IP_BIND__SIPf, info->ip);
  11078 
  11079     rv = soc_mem_search(unit, VLAN_XLATE_EXTDm, MEM_BLOCK_ALL, &idx, 
  11080                         &vxent, &res_vxent, 0);
  11081 
  11082     if (BCM_SUCCESS(rv)) {
  11083         if (soc_VLAN_XLATE_EXTDm_field32_get(unit, &res_vxent, VALID_0f)) {
  11084             /* Valid entry found */
  11085             if ((info->flags & BCM_L3_SOURCE_BIND_REPLACE) == 0) {
  11086                 /* Entry exists! */
  11087                 return BCM_E_EXISTS;
  11088             }
  11089         }
  11090     } else if (rv != SOC_E_NOT_FOUND) {
  11091         return rv;
  11092     }
  11093 
  11094     if (info->port == BCM_GPORT_INVALID) {
  11095         /* wild card */
  11096         soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent,
  11097                                   MAC_IP_BIND__MODULE_IDf, 0x7f);
  11098         soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent,
  11099                                   MAC_IP_BIND__Tf, 1);
  11100         soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent,
  11101                                   MAC_IP_BIND__PORT_NUMf, 0x3f);
  11102     } else if (BCM_GPORT_IS_SET(info->port)) {
  11103         BCM_IF_ERROR_RETURN
  11104             (_bcm_esw_gport_resolve(unit, info->port, &modid_out,
  11105                                     &port_out, &trunk_out, &tmp_id));
  11106         if (-1 != tmp_id) {
  11107             return BCM_E_PARAM;
  11108         }
  11109         if (BCM_TRUNK_INVALID != trunk_out) {
  11110             soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent,
  11111                                       MAC_IP_BIND__Tf, 1);
  11112             soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, 
  11113                     MAC_IP_BIND__MODULE_IDf, (trunk_out >> 6) & 0x1);
  11114             soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, 
  11115                     MAC_IP_BIND__PORT_NUMf, trunk_out & 0x3f);
  11116         } else {
  11117             soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, 
  11118                      MAC_IP_BIND__MODULE_IDf, modid_out);
  11119             soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, 
  11120                      MAC_IP_BIND__PORT_NUMf, port_out);
  11121         }
  11122     } else {
  11123         return BCM_E_PORT;
  11124     }
  11125 
  11126     soc_VLAN_XLATE_EXTDm_mac_addr_set(unit, &vxent,
  11127                                MAC_IP_BIND__MAC_ADDRf, info->mac);
  11128 
  11129     if (soc_feature(unit, soc_feature_ipfix_rate) && info->rate_id != 0) {
  11130         soc_VLAN_XLATE_EXTDm_field32_set
  11131             (unit, &vxent, MAC_IP_BIND__IPFIX_FLOW_METER_IDf, info->rate_id);
  11132     }
  11133 
  11134     rv = soc_mem_insert(unit, VLAN_XLATE_EXTDm, MEM_BLOCK_ALL, &vxent);
  11135 
  11136     if ((rv == SOC_E_EXISTS) &&
  11137         (info->flags & BCM_L3_SOURCE_BIND_REPLACE)) {
  11138         rv = BCM_E_NONE;
  11139     }
  11140 
  11141     return rv;
  11142 }
  11143 #endif /* BCM_TRIUMPH3_SUPPORT */
  11144 
  11145 #if defined(BCM_TRIDENT3_SUPPORT)
  11146 STATIC int 
  11147 _td3_l3_source_bind_add(int unit, bcm_l3_source_bind_t *info)
  11148 {
  11149     int             tmp_id, rv, idx = 0;
  11150     bcm_module_t    modid_out;
  11151     bcm_port_t      port_out;
  11152     bcm_trunk_t     trunk_out;
  11153     vlan_xlate_1_double_entry_t vxent, res_vxent;
  11154 
  11155     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11156         return BCM_E_UNAVAIL;
  11157     }
  11158 
  11159     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11160         /* Not supported yet */
  11161         return BCM_E_UNAVAIL;
  11162     }
  11163 
  11164     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11165         /* Not supported */
  11166         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11167              "failed with error : %s \n"),
  11168              bcm_errmsg(BCM_E_PARAM)));
  11169         return BCM_E_PARAM;
  11170     }
  11171 
  11172     sal_memset(&vxent, 0, sizeof(vlan_xlate_1_double_entry_t));
  11173     sal_memset(&res_vxent, 0, sizeof(vlan_xlate_1_double_entry_t));
  11174 
  11175     /* MAC_IP_BIND lookup key type */
  11176     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, BASE_VALID_0f, 3);
  11177     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, BASE_VALID_1f, 7);
  11178     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, DATA_TYPEf,
  11179                               7);
  11180     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, KEY_TYPEf, 7);
  11181     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent,
  11182                               MAC_IP_BIND__SIPf, info->ip);
  11183 
  11184     rv = soc_mem_search(unit, VLAN_XLATE_1_DOUBLEm, MEM_BLOCK_ALL, &idx, 
  11185                         &vxent, &res_vxent, 0);
  11186 
  11187     if (BCM_SUCCESS(rv)) {
  11188         if (soc_VLAN_XLATE_1_DOUBLEm_field32_get(unit, &res_vxent, BASE_VALID_0f)) {
  11189             /* Valid entry found */
  11190             if ((info->flags & BCM_L3_SOURCE_BIND_REPLACE) == 0) {
  11191                 /* Entry exists! */
  11192                 return BCM_E_EXISTS;
  11193             }
  11194         }
  11195     } else if (rv != SOC_E_NOT_FOUND) {
  11196         return rv;
  11197     }
  11198 
  11199     if (info->port == BCM_GPORT_INVALID) {
  11200         /* wild card */
  11201         soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent,
  11202                                   MAC_IP_BIND__SRC_MODIDf, 0x7f);
  11203         soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent,
  11204                                   MAC_IP_BIND__SRC_Tf, 1);
  11205         soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent,
  11206                                   MAC_IP_BIND__SRC_PORTf, 0x3f);
  11207     } else if (BCM_GPORT_IS_SET(info->port)) {
  11208         BCM_IF_ERROR_RETURN
  11209             (_bcm_esw_gport_resolve(unit, info->port, &modid_out,
  11210                                     &port_out, &trunk_out, &tmp_id));
  11211         if (-1 != tmp_id) {
  11212             return BCM_E_PARAM;
  11213         }
  11214         if (BCM_TRUNK_INVALID != trunk_out) {
  11215             soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent,
  11216                                       MAC_IP_BIND__SRC_Tf, 1);
  11217             soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, 
  11218                     MAC_IP_BIND__SRC_MODIDf, (trunk_out >> 6) & 0x1);
  11219             soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, 
  11220                     MAC_IP_BIND__SRC_PORTf, trunk_out & 0x3f);
  11221         } else {
  11222             soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, 
  11223                      MAC_IP_BIND__SRC_MODIDf, modid_out);
  11224             soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, 
  11225                      MAC_IP_BIND__SRC_PORTf, port_out);
  11226         }
  11227     } else {
  11228         return BCM_E_PORT;
  11229     }
  11230 
  11231     soc_VLAN_XLATE_1_DOUBLEm_mac_addr_set(unit, &vxent,
  11232                                MAC_IP_BIND__HPAE_MAC_ADDRf, info->mac);
  11233 
  11234     rv = soc_mem_insert(unit, VLAN_XLATE_1_DOUBLEm, MEM_BLOCK_ALL, &vxent);
  11235 
  11236     if ((rv == SOC_E_EXISTS) &&
  11237         (info->flags & BCM_L3_SOURCE_BIND_REPLACE)) {
  11238         rv = BCM_E_NONE;
  11239     }
  11240 
  11241     return rv;
  11242 }
  11243 STATIC int
  11244 _td3_l3_source_bind_delete(int unit, bcm_l3_source_bind_t *info)
  11245 {
  11246     vlan_xlate_1_double_entry_t vxent;
  11247     int rv;
  11248 
  11249     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11250         return BCM_E_UNAVAIL;
  11251     }
  11252 
  11253     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11254         /* Not supported yet */
  11255         return BCM_E_UNAVAIL;
  11256     }
  11257 
  11258     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11259         /* Not supported */
  11260         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11261              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  11262              bcm_errmsg(BCM_E_PARAM)));
  11263         return BCM_E_PARAM;
  11264     }
  11265 
  11266     sal_memset(&vxent, 0, sizeof(vxent));
  11267 
  11268     /* MAC_IP_BIND key type */
  11269     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, BASE_VALID_0f, 3);
  11270     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, BASE_VALID_1f, 7);
  11271     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, DATA_TYPEf,
  11272                               7);
  11273     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, KEY_TYPEf, 7);
  11274     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent,
  11275                               MAC_IP_BIND__SIPf, info->ip);
  11276 
  11277     rv = soc_mem_delete(unit, VLAN_XLATE_1_DOUBLEm, MEM_BLOCK_ALL, &vxent);
  11278 
  11279     return rv;
  11280 }
  11281 
  11282 STATIC int
  11283 _td3_l3_source_bind_delete_all(int unit)
  11284 {
  11285     vlan_xlate_1_double_entry_t *vxent, *vxentp;
  11286     int idx, imin, imax, nent, vmbytes, rv;
  11287 
  11288     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11289         return BCM_E_UNAVAIL;
  11290     }
  11291 
  11292     imin = soc_mem_index_min(unit, VLAN_XLATE_1_DOUBLEm);
  11293     imax = soc_mem_index_max(unit, VLAN_XLATE_1_DOUBLEm);
  11294     nent = soc_mem_index_count(unit, VLAN_XLATE_1_DOUBLEm);
  11295     vmbytes = soc_mem_entry_words(unit, VLAN_XLATE_1_DOUBLEm);
  11296     vmbytes = WORDS2BYTES(vmbytes);
  11297     vxent = soc_cm_salloc(unit, nent * sizeof(*vxent), "vlan_xlate_1_double");
  11298 
  11299     if (vxent == NULL) {
  11300         return BCM_E_MEMORY;
  11301     }
  11302 
  11303     soc_mem_lock(unit, VLAN_XLATE_1_DOUBLEm);
  11304     rv = soc_mem_read_range(unit, VLAN_XLATE_1_DOUBLEm, MEM_BLOCK_ANY,
  11305                             imin, imax, vxent);
  11306     if (BCM_FAILURE(rv)) {
  11307         soc_mem_unlock(unit, VLAN_XLATE_1_DOUBLEm);
  11308         soc_cm_sfree(unit, vxent);
  11309         return rv;
  11310     }
  11311 
  11312     for(idx = 0; idx < nent; idx++) {
  11313         vxentp = soc_mem_table_idx_to_pointer(unit, VLAN_XLATE_1_DOUBLEm,
  11314                         vlan_xlate_1_double_entry_t *, vxent, idx);
  11315 
  11316         if ((0 == soc_VLAN_XLATE_1_DOUBLEm_field32_get(unit, vxentp,
  11317             BASE_VALID_0f)) || (TD3_VLXLT_HASH_KEY_TYPE_HPAE !=
  11318             soc_VLAN_XLATE_1_DOUBLEm_field32_get(unit, vxentp, KEY_TYPEf))) {
  11319             continue;
  11320         }
  11321 
  11322         rv = soc_mem_delete(unit, VLAN_XLATE_1_DOUBLEm, MEM_BLOCK_ALL, vxentp);
  11323         if (BCM_FAILURE(rv)) {
  11324             soc_mem_unlock(unit, VLAN_XLATE_1_DOUBLEm);
  11325             soc_cm_sfree(unit, vxent);
  11326             return rv;
  11327         }
  11328     }
  11329 
  11330     soc_mem_unlock(unit, VLAN_XLATE_1_DOUBLEm);
  11331     soc_cm_sfree(unit, vxent);
  11332     return rv;
  11333 }
  11334 #endif /* BCM_TRIDENT3_SUPPORT */
  11335 
  11336 #if defined(BCM_TRIUMPH2_SUPPORT)
  11337 STATIC int 
  11338 _tr2_l3_source_bind_add(int unit, bcm_l3_source_bind_t *info)
  11339 {
  11340     int             tmp_id, rv, idx = 0;
  11341     bcm_module_t    modid_out;
  11342     bcm_port_t      port_out;
  11343     bcm_trunk_t     trunk_out;
  11344     vlan_mac_entry_t vment, res_vment;
  11345 
  11346     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11347         return BCM_E_UNAVAIL;
  11348     }
  11349 
  11350     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11351         /* Not supported yet */
  11352         return BCM_E_UNAVAIL;
  11353     }
  11354 
  11355     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11356         /* Not supported */
  11357         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11358              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  11359              bcm_errmsg(BCM_E_PARAM)));
  11360         return BCM_E_PARAM;
  11361     }
  11362 
  11363     sal_memset(&vment, 0, sizeof(vlan_mac_entry_t));
  11364     sal_memset(&res_vment, 0, sizeof(vlan_mac_entry_t));
  11365 
  11366     /* MAC_IP_BIND lookup key type */
  11367     soc_VLAN_MACm_field32_set(unit, &vment, VALIDf, 1);
  11368     soc_VLAN_MACm_field32_set(unit, &vment, KEY_TYPEf,
  11369                               TR_VLXLT_HASH_KEY_TYPE_HPAE);
  11370     soc_VLAN_MACm_field32_set(unit, &vment,
  11371                               MAC_IP_BIND__SIPf, info->ip);
  11372 
  11373     rv = soc_mem_search(unit, VLAN_MACm, MEM_BLOCK_ALL, &idx, 
  11374                         &vment, &res_vment, 0);
  11375 
  11376     if (BCM_SUCCESS(rv)) {
  11377         if (soc_VLAN_MACm_field32_get(unit, &res_vment, VALIDf)) {
  11378             /* Valid entry found */
  11379             if ((info->flags & BCM_L3_SOURCE_BIND_REPLACE) == 0) {
  11380                 /* Entry exists! */
  11381                 return BCM_E_EXISTS;
  11382             }
  11383         }
  11384     } else if (rv != SOC_E_NOT_FOUND) {
  11385         return rv;
  11386     }
  11387 
  11388     if (info->port == BCM_GPORT_INVALID) {
  11389         /* wild card */
  11390         soc_VLAN_MACm_field32_set(unit, &vment,
  11391                                   MAC_IP_BIND__SRC_MODIDf, 0x7f);
  11392         soc_VLAN_MACm_field32_set(unit, &vment,
  11393                                   MAC_IP_BIND__SRC_Tf, 1);
  11394         soc_VLAN_MACm_field32_set(unit, &vment,
  11395                                   MAC_IP_BIND__SRC_PORTf, 0x3f);
  11396     } else if (BCM_GPORT_IS_SET(info->port)) {
  11397         BCM_IF_ERROR_RETURN
  11398             (_bcm_esw_gport_resolve(unit, info->port, &modid_out,
  11399                                     &port_out, &trunk_out, &tmp_id));
  11400         if (-1 != tmp_id) {
  11401             return BCM_E_PARAM;
  11402         }
  11403         if (BCM_TRUNK_INVALID != trunk_out) {
  11404             soc_VLAN_MACm_field32_set(unit, &vment,
  11405                                       MAC_IP_BIND__SRC_Tf, 1);
  11406             soc_VLAN_MACm_field32_set(unit, &vment, MAC_IP_BIND__SRC_MODIDf,
  11407                                       (trunk_out >> 6) & 0x1);
  11408             soc_VLAN_MACm_field32_set(unit, &vment, MAC_IP_BIND__SRC_PORTf,
  11409                                       trunk_out & 0x3f);
  11410         } else {
  11411             soc_VLAN_MACm_field32_set(unit, &vment, MAC_IP_BIND__SRC_MODIDf,
  11412                                       modid_out);
  11413             soc_VLAN_MACm_field32_set(unit, &vment, MAC_IP_BIND__SRC_PORTf,
  11414                                       port_out);
  11415         }
  11416     } else {
  11417         return BCM_E_PORT;
  11418     }
  11419 
  11420     soc_VLAN_MACm_mac_addr_set(unit, &vment,
  11421                                MAC_IP_BIND__HPAE_MAC_ADDRf, info->mac);
  11422 
  11423     if (soc_feature(unit, soc_feature_ipfix_rate) && info->rate_id != 0) {
  11424         soc_VLAN_MACm_field32_set
  11425             (unit, &vment, MAC_IP_BIND__IPFIX_FLOW_METER_IDf, info->rate_id);
  11426     }
  11427 
  11428     rv = soc_mem_insert(unit, VLAN_MACm, MEM_BLOCK_ALL, &vment);
  11429 
  11430     if ((rv == SOC_E_EXISTS) &&
  11431         (info->flags & BCM_L3_SOURCE_BIND_REPLACE)) {
  11432         rv = BCM_E_NONE;
  11433     }
  11434 
  11435     return rv;
  11436 }
  11437 #endif /* BCM_TRIUMPH2_SUPPORT */
  11438 
  11439 /*
  11440  * Function:
  11441  *      bcm_esw_l3_source_bind_add
  11442  * Purpose:
  11443  *      Add or replace an L3 source binding.
  11444  * Parameters:
  11445  *      unit - (IN) Unit number.
  11446  *      info - (IN) L3 source binding information
  11447  * Returns:
  11448  *      BCM_E_XXX
  11449  * Notes:
  11450  */
  11451 int
  11452 bcm_esw_l3_source_bind_add(int unit, bcm_l3_source_bind_t *info)
  11453 {
  11454 #if defined(BCM_TRIUMPH3_SUPPORT)
  11455     if (SOC_IS_TRIUMPH3(unit)) {
  11456         BCM_IF_ERROR_RETURN
  11457             (_tr3_l3_source_bind_add(unit,info));
  11458         return BCM_E_NONE;
  11459     } 
  11460 #endif
  11461 #if defined(BCM_TRIDENT3_SUPPORT)
  11462     if ((SOC_IS_TRIDENT3X(unit))) {
  11463         BCM_IF_ERROR_RETURN
  11464             (_td3_l3_source_bind_add(unit,info));
  11465         return BCM_E_NONE;
  11466     } 
  11467 #endif
  11468 #if defined(BCM_TRIUMPH2_SUPPORT)
  11469     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_HURRICANE2(unit)) {
  11470         BCM_IF_ERROR_RETURN
  11471             (_tr2_l3_source_bind_add(unit,info));
  11472         return BCM_E_NONE;
  11473     } 
  11474 #endif
  11475     return BCM_E_UNAVAIL; 
  11476 }
  11477 
  11478 #if defined(BCM_TRIUMPH3_SUPPORT)
  11479 STATIC int
  11480 _tr3_l3_source_bind_delete(int unit, bcm_l3_source_bind_t *info)
  11481 {
  11482     vlan_xlate_extd_entry_t vxent;
  11483     int rv;
  11484 
  11485     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11486         return BCM_E_UNAVAIL;
  11487     }
  11488 
  11489     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11490         /* Not supported yet */
  11491         return BCM_E_UNAVAIL;
  11492     }
  11493 
  11494     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11495         /* Not supported */
  11496         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11497              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  11498              bcm_errmsg(BCM_E_PARAM)));
  11499         return BCM_E_PARAM;
  11500     }
  11501 
  11502     sal_memset(&vxent, 0, sizeof(vxent));
  11503 
  11504     /* MAC_IP_BIND key type */
  11505     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, VALID_0f, 1);
  11506     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, VALID_1f, 1);
  11507     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, KEY_TYPE_0f,
  11508                               TR3_VLXLT_HASH_KEY_TYPE_HPAE);
  11509     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, KEY_TYPE_1f,
  11510                               TR3_VLXLT_HASH_KEY_TYPE_HPAE);
  11511     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent,
  11512                               MAC_IP_BIND__SIPf, info->ip);
  11513 
  11514     rv = soc_mem_delete(unit, VLAN_XLATE_EXTDm, MEM_BLOCK_ALL, &vxent);
  11515 
  11516     return rv;
  11517 }
  11518 #endif /* BCM_TRIUMPH3_SUPPORT */
  11519 
  11520 #if defined(BCM_TRIUMPH2_SUPPORT)
  11521 STATIC int 
  11522 _tr2_l3_source_bind_delete(int unit, bcm_l3_source_bind_t *info)
  11523 {
  11524     vlan_mac_entry_t vment;
  11525     int rv; 
  11526 
  11527     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11528         return BCM_E_UNAVAIL;
  11529     }
  11530 
  11531     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11532         /* Not supported yet */
  11533         return BCM_E_UNAVAIL;
  11534     }
  11535 
  11536     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11537         /* Not supported */
  11538         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11539              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  11540              bcm_errmsg(BCM_E_PARAM)));
  11541         return BCM_E_PARAM;
  11542     }
  11543 
  11544     sal_memset(&vment, 0, sizeof(vment));
  11545 
  11546     /* MAC_IP_BIND key type */
  11547     soc_VLAN_MACm_field32_set(unit, &vment, VALIDf, 1);
  11548     soc_VLAN_MACm_field32_set(unit, &vment, KEY_TYPEf,
  11549                               TR_VLXLT_HASH_KEY_TYPE_HPAE);
  11550     soc_VLAN_MACm_field32_set(unit, &vment,
  11551                               MAC_IP_BIND__SIPf, info->ip);
  11552 
  11553     rv = soc_mem_delete(unit, VLAN_MACm, MEM_BLOCK_ALL, &vment);
  11554 
  11555     return rv;
  11556 }
  11557 #endif /* BCM_TRIUMPH2_SUPPORT */
  11558 
  11559 /*
  11560  * Function:
  11561  *      bcm_esw_l3_source_bind_delete
  11562  * Purpose:
  11563  *      Remove an existing L3 source binding.
  11564  * Parameters:
  11565  *      unit - (IN) Unit number.
  11566  *      info - (IN) L3 source binding information
  11567  * Returns:
  11568  *      BCM_E_XXX
  11569  * Notes:
  11570  */
  11571 int
  11572 bcm_esw_l3_source_bind_delete(int unit, bcm_l3_source_bind_t *info)
  11573 {
  11574 #if defined(BCM_TRIDENT3_SUPPORT)
  11575     if (SOC_IS_TRIDENT3X(unit)) {
  11576         BCM_IF_ERROR_RETURN
  11577             (_td3_l3_source_bind_delete(unit,info));
  11578         return BCM_E_NONE;
  11579     }
  11580 #endif
  11581 #if defined(BCM_TRIUMPH3_SUPPORT)
  11582     if (SOC_IS_TRIUMPH3(unit)) {
  11583         BCM_IF_ERROR_RETURN
  11584             (_tr3_l3_source_bind_delete(unit,info));
  11585         return BCM_E_NONE;
  11586     }
  11587 #endif
  11588 #if defined(BCM_TRIUMPH2_SUPPORT)
  11589     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_HURRICANE2(unit)) {
  11590         BCM_IF_ERROR_RETURN
  11591             (_tr2_l3_source_bind_delete(unit,info));
  11592         return BCM_E_NONE;
  11593     }
  11594 #endif
  11595     return BCM_E_UNAVAIL;
  11596 
  11597 }
  11598 
  11599 #if defined(BCM_TRIUMPH3_SUPPORT)
  11600 STATIC int 
  11601 _tr3_l3_source_bind_delete_all(int unit)
  11602 {
  11603     int idx, imin, imax, nent, vmbytes, rv;
  11604     vlan_xlate_extd_entry_t * vxtab, *vxtabp;
  11605     
  11606     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11607         return BCM_E_UNAVAIL;
  11608     }
  11609 
  11610     imin = soc_mem_index_min(unit, VLAN_XLATE_EXTDm);
  11611     imax = soc_mem_index_max(unit, VLAN_XLATE_EXTDm);
  11612     nent = soc_mem_index_count(unit, VLAN_XLATE_EXTDm);
  11613     vmbytes = soc_mem_entry_words(unit, VLAN_XLATE_EXTDm);
  11614     vmbytes = WORDS2BYTES(vmbytes);
  11615     vxtab = soc_cm_salloc(unit, nent * sizeof(*vxtab), "vlan_xlate_extd");
  11616 
  11617     if (vxtab == NULL) {
  11618         return BCM_E_MEMORY;
  11619     }
  11620     
  11621     soc_mem_lock(unit, VLAN_XLATE_EXTDm);
  11622     rv = soc_mem_read_range(unit, VLAN_XLATE_EXTDm, MEM_BLOCK_ANY,
  11623                             imin, imax, vxtab);
  11624     if (BCM_FAILURE(rv)) {
  11625         soc_mem_unlock(unit, VLAN_XLATE_EXTDm);
  11626         soc_cm_sfree(unit, vxtab);
  11627         return rv; 
  11628     }
  11629     
  11630     for(idx = 0; idx < nent; idx++) {
  11631         vxtabp = soc_mem_table_idx_to_pointer(unit, VLAN_XLATE_EXTDm,
  11632                                               vlan_xlate_extd_entry_t *, 
  11633                                               vxtab, idx);
  11634 
  11635         if ((0 == soc_VLAN_XLATE_EXTDm_field32_get(unit, vxtabp, VALID_0f)) ||
  11636             (TR3_VLXLT_HASH_KEY_TYPE_HPAE !=
  11637              soc_VLAN_XLATE_EXTDm_field32_get(unit, vxtabp, KEY_TYPE_0f))) {
  11638             continue;
  11639         }
  11640 
  11641         rv = soc_mem_delete(unit, VLAN_XLATE_EXTDm, MEM_BLOCK_ALL, vxtabp);
  11642         if (BCM_FAILURE(rv)) {
  11643             soc_mem_unlock(unit, VLAN_XLATE_EXTDm);
  11644             soc_cm_sfree(unit, vxtab);
  11645             return rv; 
  11646         }
  11647     }
  11648     
  11649     soc_mem_unlock(unit, VLAN_XLATE_EXTDm);
  11650     soc_cm_sfree(unit, vxtab);
  11651     return rv;
  11652 }
  11653 #endif /* BCM_TRIUMPH3_SUPPORT */
  11654 
  11655 #if defined(BCM_TRIUMPH2_SUPPORT)
  11656 STATIC int 
  11657 _tr2_l3_source_bind_delete_all(int unit)
  11658 {
  11659     int idx, imin, imax, nent, vmbytes, rv;
  11660     vlan_mac_entry_t * vmtab, *vmtabp;
  11661     
  11662     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11663         return BCM_E_UNAVAIL;
  11664     }
  11665 
  11666     imin = soc_mem_index_min(unit, VLAN_MACm);
  11667     imax = soc_mem_index_max(unit, VLAN_MACm);
  11668     nent = soc_mem_index_count(unit, VLAN_MACm);
  11669     vmbytes = soc_mem_entry_words(unit, VLAN_MACm);
  11670     vmbytes = WORDS2BYTES(vmbytes);
  11671     vmtab = soc_cm_salloc(unit, nent * sizeof(*vmtab), "vlan_mac");
  11672 
  11673     if (vmtab == NULL) {
  11674         return BCM_E_MEMORY;
  11675     }
  11676     
  11677     soc_mem_lock(unit, VLAN_MACm);
  11678     rv = soc_mem_read_range(unit, VLAN_MACm, MEM_BLOCK_ANY,
  11679                             imin, imax, vmtab);
  11680     if (BCM_FAILURE(rv)) {
  11681         soc_mem_unlock(unit, VLAN_MACm);
  11682         soc_cm_sfree(unit, vmtab);
  11683         return rv; 
  11684     }
  11685     
  11686     for(idx = 0; idx < nent; idx++) {
  11687         vmtabp = soc_mem_table_idx_to_pointer(unit, VLAN_MACm,
  11688                                               vlan_mac_entry_t *, 
  11689                                               vmtab, idx);
  11690 
  11691         if ((0 == soc_VLAN_MACm_field32_get(unit, vmtabp, VALIDf)) ||
  11692             (TR_VLXLT_HASH_KEY_TYPE_HPAE !=
  11693              soc_VLAN_MACm_field32_get(unit, vmtabp, KEY_TYPEf))) {
  11694             continue;
  11695         }
  11696 
  11697         rv = soc_mem_delete(unit, VLAN_MACm, MEM_BLOCK_ALL, vmtabp);
  11698         if (BCM_FAILURE(rv)) {
  11699             soc_mem_unlock(unit, VLAN_MACm);
  11700             soc_cm_sfree(unit, vmtab);
  11701             return rv; 
  11702         }
  11703     }
  11704     
  11705     soc_mem_unlock(unit, VLAN_MACm);
  11706     soc_cm_sfree(unit, vmtab);
  11707     return rv;
  11708 }
  11709 #endif /* BCM_TRIUMPH2_SUPPORT */
  11710 
  11711 /*
  11712  * Function:
  11713  *      bcm_esw_l3_source_bind_delete_all
  11714  * Purpose:
  11715  *      Remove all existing L3 source bindings.
  11716  * Parameters:
  11717  *      unit - (IN) Unit number.
  11718  * Returns:
  11719  *      BCM_E_XXX
  11720  * Notes:
  11721  */
  11722 int
  11723 bcm_esw_l3_source_bind_delete_all(int unit)
  11724 {
  11725 #if defined(BCM_TRIUMPH3_SUPPORT)
  11726     if (SOC_IS_TRIUMPH3(unit)) {
  11727         BCM_IF_ERROR_RETURN
  11728             (_tr3_l3_source_bind_delete_all(unit));
  11729         return BCM_E_NONE;
  11730     }
  11731 #endif
  11732 #if defined(BCM_TRIUMPH2_SUPPORT)
  11733     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_HURRICANE2(unit)) {
  11734         BCM_IF_ERROR_RETURN
  11735             (_tr2_l3_source_bind_delete_all(unit));
  11736         return BCM_E_NONE;
  11737     }
  11738 #endif
  11739 #if defined(BCM_TRIDENT3_SUPPORT)
  11740     if (SOC_IS_TRIDENT3X(unit)) {
  11741         BCM_IF_ERROR_RETURN
  11742             (_td3_l3_source_bind_delete_all(unit));
  11743             return BCM_E_NONE;
  11744     }
  11745 #endif
  11746     return BCM_E_UNAVAIL;
  11747 }
  11748 
  11749 #if defined(BCM_TRIDENT3_SUPPORT)
  11750 STATIC int
  11751 _td3_l3_source_bind_hw_entry_to_sw_info(int unit,
  11752                                         vlan_xlate_1_double_entry_t *vxent,
  11753                                         bcm_l3_source_bind_t *info)
  11754 {
  11755     int             t_bit;
  11756     bcm_module_t    modid;
  11757     bcm_port_t      port;
  11758 
  11759     bcm_l3_source_bind_t_init(info);
  11760     info->ip = soc_VLAN_XLATE_1_DOUBLEm_field32_get(unit, vxent,
  11761                       MAC_IP_BIND__SIPf);
  11762     soc_VLAN_XLATE_1_DOUBLEm_mac_addr_get(unit, &vxent,
  11763                                MAC_IP_BIND__HPAE_MAC_ADDRf, info->mac);
  11764 
  11765     /* Port analysis */
  11766 
  11767     port = soc_VLAN_XLATE_1_DOUBLEm_field32_get(unit, &vxent,
  11768                                   MAC_IP_BIND__SRC_PORTf);
  11769     modid = soc_VLAN_XLATE_1_DOUBLEm_field32_get(unit, &vxent,
  11770                                   MAC_IP_BIND__SRC_MODIDf);
  11771     t_bit = soc_VLAN_XLATE_1_DOUBLEm_field32_get(unit, &vxent,
  11772                                   MAC_IP_BIND__SRC_Tf);
  11773     if (t_bit == 1) {
  11774         if ((modid == 0x7f) && (port == 0x3f)) {
  11775             info->port = BCM_GPORT_TYPE_BLACK_HOLE; /* Wild card */
  11776         } else {
  11777             BCM_IF_ERROR_RETURN
  11778                 (_bcm_esw_l3_gport_construct(unit, 0, 0,
  11779                                    (port & 0x3f) | ((modid & 0x1) << 6),
  11780                                              BCM_L3_TGID, &(info->port)));
  11781         }
  11782     } else {
  11783         BCM_IF_ERROR_RETURN
  11784             (_bcm_esw_l3_gport_construct(unit, port, modid,
  11785                                          0, 0, &(info->port)));
  11786     }
  11787 
  11788     return BCM_E_NONE;
  11789 }
  11790 #endif /* BCM_TRIDENT3_SUPPORT */
  11791 
  11792 #if defined(BCM_TRIUMPH3_SUPPORT)
  11793 STATIC int
  11794 _tr3_l3_source_bind_hw_entry_to_sw_info(int unit,
  11795                                         vlan_xlate_extd_entry_t *vxent,
  11796                                         bcm_l3_source_bind_t *info)
  11797 {
  11798     int             t_bit;
  11799     bcm_module_t    modid;
  11800     bcm_port_t      port;
  11801 
  11802     bcm_l3_source_bind_t_init(info);
  11803     info->ip = soc_VLAN_XLATE_EXTDm_field32_get(unit, vxent, 
  11804                       MAC_IP_BIND__SIPf);
  11805     if (soc_feature(unit, soc_feature_ipfix_rate)) {
  11806         info->rate_id = soc_VLAN_XLATE_EXTDm_field32_get
  11807             (unit, vxent, MAC_IP_BIND__IPFIX_FLOW_METER_IDf);
  11808     }
  11809     soc_VLAN_XLATE_EXTDm_mac_addr_get(unit, vxent,
  11810                                MAC_IP_BIND__MAC_ADDRf, info->mac);
  11811 
  11812     /* Port analysis */
  11813 
  11814     port = soc_VLAN_XLATE_EXTDm_field32_get(unit, vxent,
  11815                                            MAC_IP_BIND__PORT_NUMf);
  11816     modid = soc_VLAN_XLATE_EXTDm_field32_get(unit, vxent,
  11817                                       MAC_IP_BIND__MODULE_IDf);
  11818     t_bit = soc_VLAN_XLATE_EXTDm_field32_get(unit, vxent,
  11819                                     MAC_IP_BIND__Tf);
  11820 
  11821     if (t_bit == 1) {
  11822         if ((modid == 0x7f) && (port == 0x3f)) {
  11823             info->port = BCM_GPORT_TYPE_BLACK_HOLE; /* Wild card */
  11824         } else {
  11825             BCM_IF_ERROR_RETURN
  11826                 (_bcm_esw_l3_gport_construct(unit, 0, 0,
  11827                                    (port & 0x3f) | ((modid & 0x1) << 6),
  11828                                              BCM_L3_TGID, &(info->port)));
  11829         }
  11830     } else {
  11831         BCM_IF_ERROR_RETURN
  11832             (_bcm_esw_l3_gport_construct(unit, port, modid,
  11833                                          0, 0, &(info->port)));
  11834     }
  11835 
  11836     return BCM_E_NONE;
  11837 }
  11838 #endif /* BCM_TRIUMPH3_SUPPORT */
  11839 
  11840 #if defined(BCM_TRIUMPH2_SUPPORT)
  11841 STATIC int
  11842 _tr2_l3_source_bind_hw_entry_to_sw_info(int unit,
  11843                                             vlan_mac_entry_t *vment,
  11844                                             bcm_l3_source_bind_t *info)
  11845 {
  11846     int             t_bit;
  11847     bcm_module_t    modid;
  11848     bcm_port_t      port;
  11849 
  11850     bcm_l3_source_bind_t_init(info);
  11851     info->ip = soc_VLAN_MACm_field32_get(unit, vment, MAC_IP_BIND__SIPf);
  11852     if (soc_feature(unit, soc_feature_ipfix_rate)) {
  11853         info->rate_id = soc_VLAN_MACm_field32_get
  11854             (unit, vment, MAC_IP_BIND__IPFIX_FLOW_METER_IDf);
  11855     }
  11856     soc_VLAN_MACm_mac_addr_get(unit, vment,
  11857                                MAC_IP_BIND__HPAE_MAC_ADDRf, info->mac);
  11858 
  11859     /* Port analysis */
  11860 
  11861     port = soc_VLAN_MACm_field32_get(unit, vment,
  11862                                            MAC_IP_BIND__SRC_PORTf);
  11863     modid = soc_VLAN_MACm_field32_get(unit, vment,
  11864                                       MAC_IP_BIND__SRC_MODIDf);
  11865     t_bit = soc_VLAN_MACm_field32_get(unit, vment,
  11866                                     MAC_IP_BIND__SRC_Tf);
  11867 
  11868     if (t_bit == 1) {
  11869         if ((modid == 0x7f) && (port == 0x3f)) {
  11870             info->port = BCM_GPORT_TYPE_BLACK_HOLE; /* Wild card */
  11871         } else {
  11872             BCM_IF_ERROR_RETURN
  11873                 (_bcm_esw_l3_gport_construct(unit, 0, 0,
  11874                                    (port & 0x3f) | ((modid & 0x1) << 6),
  11875                                              BCM_L3_TGID, &(info->port)));
  11876         }
  11877     } else {
  11878         BCM_IF_ERROR_RETURN
  11879             (_bcm_esw_l3_gport_construct(unit, port, modid,
  11880                                          0, 0, &(info->port)));
  11881 #if defined(BCM_HURRICANE2_SUPPORT)
  11882         if (SOC_IS_HURRICANE2(unit)) {
  11883             BCM_GPORT_MODPORT_SET(info->port, modid, port);
  11884         }
  11885 #endif /* BCM_HURRICANE2_SUPPORT */
  11886     }
  11887 
  11888     return BCM_E_NONE;
  11889 }
  11890 #endif /* BCM_TRIUMPH2_SUPPORT */
  11891 
  11892 #if defined(BCM_TRIUMPH3_SUPPORT)
  11893 STATIC int
  11894 _tr3_l3_source_bind_get(int unit, bcm_l3_source_bind_t *info)
  11895 {
  11896     int             rv, idx = 0;
  11897     vlan_xlate_extd_entry_t vxent, res_vxent;
  11898 
  11899     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11900         return BCM_E_UNAVAIL;
  11901     }
  11902 
  11903     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11904         /* Not supported yet */
  11905         return BCM_E_UNAVAIL;
  11906     }
  11907 
  11908     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11909         /* Not supported */
  11910         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11911              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  11912              bcm_errmsg(BCM_E_PARAM)));
  11913         return BCM_E_PARAM;
  11914     }
  11915 
  11916     sal_memset(&vxent, 0, sizeof(vlan_xlate_extd_entry_t));
  11917     sal_memset(&res_vxent, 0, sizeof(vlan_xlate_extd_entry_t));
  11918 
  11919     /* MAC_IP_BIND lookup key type */
  11920     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, VALID_0f, 1);
  11921     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, VALID_1f, 1);
  11922     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, KEY_TYPE_0f,
  11923                               TR3_VLXLT_HASH_KEY_TYPE_HPAE);
  11924     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent, KEY_TYPE_1f,
  11925                               TR3_VLXLT_HASH_KEY_TYPE_HPAE);
  11926     soc_VLAN_XLATE_EXTDm_field32_set(unit, &vxent,
  11927                               MAC_IP_BIND__SIPf, info->ip);
  11928 
  11929     soc_mem_lock(unit, VLAN_XLATE_EXTDm);
  11930     rv = soc_mem_search(unit, VLAN_XLATE_EXTDm, MEM_BLOCK_ALL, &idx,
  11931                         &vxent, &res_vxent, 0);
  11932     soc_mem_unlock(unit, VLAN_XLATE_EXTDm);
  11933     BCM_IF_ERROR_RETURN(rv);
  11934 
  11935     return _tr3_l3_source_bind_hw_entry_to_sw_info(unit, &res_vxent,
  11936                                                        info);
  11937 }
  11938 #endif /* BCM_TRIUMPH3_SUPPORT */
  11939 
  11940 #if defined(BCM_TRIUMPH2_SUPPORT)
  11941 STATIC int 
  11942 _tr2_l3_source_bind_get(int unit, bcm_l3_source_bind_t *info)
  11943 {
  11944     int             rv, idx = 0;
  11945     vlan_mac_entry_t vment, res_vment;
  11946 
  11947     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11948         return BCM_E_UNAVAIL;
  11949     }
  11950 
  11951     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11952         /* Not supported yet */
  11953         return BCM_E_UNAVAIL;
  11954     }
  11955 
  11956     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  11957         /* Not supported */
  11958         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  11959              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  11960              bcm_errmsg(BCM_E_PARAM)));
  11961         return BCM_E_PARAM;
  11962     }
  11963 
  11964     sal_memset(&vment, 0, sizeof(vlan_mac_entry_t));
  11965     sal_memset(&res_vment, 0, sizeof(vlan_mac_entry_t));
  11966 
  11967     /* MAC_IP_BIND lookup key type */
  11968     soc_VLAN_MACm_field32_set(unit, &vment, VALIDf, 1);
  11969     soc_VLAN_MACm_field32_set(unit, &vment, KEY_TYPEf,
  11970                               TR_VLXLT_HASH_KEY_TYPE_HPAE);
  11971     soc_VLAN_MACm_field32_set(unit, &vment,
  11972                               MAC_IP_BIND__SIPf, info->ip);
  11973 
  11974     soc_mem_lock(unit, VLAN_MACm);
  11975     rv = soc_mem_search(unit, VLAN_MACm, MEM_BLOCK_ALL, &idx, 
  11976                         &vment, &res_vment, 0);
  11977     soc_mem_unlock(unit, VLAN_MACm);
  11978     BCM_IF_ERROR_RETURN(rv);
  11979 
  11980     return _tr2_l3_source_bind_hw_entry_to_sw_info(unit, &res_vment,
  11981                                                        info);
  11982 }
  11983 #endif /* BCM_TRIUMPH2_SUPPORT */
  11984 
  11985 #if defined(BCM_TRIDENT3_SUPPORT)
  11986 STATIC int
  11987 _td3_l3_source_bind_get(int unit, bcm_l3_source_bind_t *info)
  11988 {
  11989     int             rv, idx = 0;
  11990     vlan_xlate_1_double_entry_t vxent, res_vxent;
  11991 
  11992     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  11993         return BCM_E_UNAVAIL;
  11994     }
  11995 
  11996     if (info->flags & BCM_L3_SOURCE_BIND_IP6) {
  11997         /* Not supported yet */
  11998         return BCM_E_UNAVAIL;
  11999     }
  12000 
  12001     if (info->flags & BCM_L3_SOURCE_BIND_USE_MASK) {
  12002         /* Not supported */
  12003         LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
  12004              "%s: failed with error : %s \n"), FUNCTION_NAME(),
  12005              bcm_errmsg(BCM_E_PARAM)));
  12006         return BCM_E_PARAM;
  12007     }
  12008 
  12009     sal_memset(&vxent, 0, sizeof(vlan_xlate_1_double_entry_t));
  12010     sal_memset(&res_vxent, 0, sizeof(vlan_xlate_1_double_entry_t));
  12011 
  12012     /* MAC_IP_BIND lookup key type */
  12013     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, BASE_VALID_0f, 3);
  12014     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, BASE_VALID_1f, 7);
  12015     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, DATA_TYPEf,
  12016                               7);
  12017     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent, KEY_TYPEf, 7);
  12018     soc_VLAN_XLATE_1_DOUBLEm_field32_set(unit, &vxent,
  12019                               MAC_IP_BIND__SIPf, info->ip);
  12020 
  12021     rv = soc_mem_search(unit, VLAN_XLATE_1_DOUBLEm, MEM_BLOCK_ALL, &idx,
  12022                         &vxent, &res_vxent, 0);
  12023     BCM_IF_ERROR_RETURN(rv);
  12024 
  12025     return _td3_l3_source_bind_hw_entry_to_sw_info(unit, &res_vxent,
  12026                                                        info);
  12027 }
  12028 #endif /* BCM_TRIDENT3_SUPPORT */
  12029 
  12030 /*
  12031  * Function:
  12032  *      bcm_esw_l3_source_bind_get
  12033  * Purpose:
  12034  *      Retrieve the details of an existing L3 source binding.
  12035  * Parameters:
  12036  *      unit - (IN) Unit number.
  12037  *      info - (IN/OUT) L3 source binding information
  12038  * Returns:
  12039  *      BCM_E_XXX
  12040  * Notes:
  12041  */
  12042 int
  12043 bcm_esw_l3_source_bind_get(int unit, bcm_l3_source_bind_t *info)
  12044 {
  12045 #if defined(BCM_TRIUMPH3_SUPPORT)
  12046     if (SOC_IS_TRIUMPH3(unit)) {
  12047         BCM_IF_ERROR_RETURN
  12048             (_tr3_l3_source_bind_get(unit,info));
  12049         return BCM_E_NONE;
  12050     }
  12051 #endif
  12052 #if defined(BCM_TRIUMPH2_SUPPORT)
  12053     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_HURRICANE2(unit)) {
  12054         BCM_IF_ERROR_RETURN
  12055             (_tr2_l3_source_bind_get(unit,info));
  12056         return BCM_E_NONE;
  12057     }
  12058 #endif
  12059 #if defined(BCM_TRIDENT3_SUPPORT)
  12060     if ((SOC_IS_TRIDENT3X(unit))) {
  12061         BCM_IF_ERROR_RETURN
  12062             (_td3_l3_source_bind_get(unit,info));
  12063         return BCM_E_NONE;
  12064     }
  12065 #endif
  12066 
  12067     return BCM_E_UNAVAIL;
  12068 }
  12069 
  12070 #if defined(BCM_TRIUMPH3_SUPPORT)
  12071 STATIC int 
  12072 _tr3_l3_source_bind_traverse(int unit, bcm_l3_source_bind_traverse_cb cb, 
  12073                                 void *user_data)
  12074 {
  12075     int idx, imin, imax, nent, vmbytes, rv;
  12076     vlan_xlate_extd_entry_t * vxtab, *vxtabp;
  12077     bcm_l3_source_bind_t info;
  12078 
  12079     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  12080         return BCM_E_UNAVAIL;
  12081     }
  12082 
  12083     /* Input parameters check. */
  12084     if (NULL == cb) {
  12085         return (BCM_E_PARAM);
  12086     }
  12087 
  12088     imin = soc_mem_index_min(unit, VLAN_XLATE_EXTDm);
  12089     imax = soc_mem_index_max(unit, VLAN_XLATE_EXTDm);
  12090     nent = soc_mem_index_count(unit, VLAN_XLATE_EXTDm);
  12091     vmbytes = soc_mem_entry_words(unit, VLAN_XLATE_EXTDm);
  12092     vmbytes = WORDS2BYTES(vmbytes);
  12093     vxtab = soc_cm_salloc(unit, nent * sizeof(*vxtab), "vlan_xlate_extd");
  12094 
  12095     if (vxtab == NULL) {
  12096         return BCM_E_MEMORY;
  12097     }
  12098     
  12099     soc_mem_lock(unit, VLAN_XLATE_EXTDm);
  12100     rv = soc_mem_read_range(unit, VLAN_XLATE_EXTDm, MEM_BLOCK_ANY,
  12101                             imin, imax, vxtab);
  12102     if (BCM_FAILURE(rv)) {
  12103         soc_mem_unlock(unit, VLAN_XLATE_EXTDm);
  12104         soc_cm_sfree(unit, vxtab);
  12105         return rv; 
  12106     }
  12107     
  12108     for(idx = 0; idx < nent; idx++) {
  12109         vxtabp = soc_mem_table_idx_to_pointer(unit, VLAN_XLATE_EXTDm,
  12110                                               vlan_xlate_extd_entry_t *, 
  12111                                               vxtab, idx);
  12112 
  12113         if ((0 == soc_VLAN_XLATE_EXTDm_field32_get(unit, vxtabp, VALID_0f)) ||
  12114             (TR3_VLXLT_HASH_KEY_TYPE_HPAE !=
  12115              soc_VLAN_XLATE_EXTDm_field32_get(unit, vxtabp, KEY_TYPE_0f))) {
  12116             continue;
  12117         }
  12118 
  12119         rv = _tr3_l3_source_bind_hw_entry_to_sw_info(unit, vxtabp,
  12120                                                          &info);
  12121 
  12122         if (BCM_SUCCESS(rv)) {
  12123             /* Call traverse callback with the data. */
  12124             rv = cb(unit, &info, user_data);
  12125         }
  12126 
  12127         if (BCM_FAILURE(rv)) {
  12128             soc_mem_unlock(unit, VLAN_XLATE_EXTDm);
  12129             soc_cm_sfree(unit, vxtab);
  12130             return rv; 
  12131         }
  12132     }
  12133     
  12134     soc_mem_unlock(unit, VLAN_XLATE_EXTDm);
  12135     soc_cm_sfree(unit, vxtab);
  12136     return rv;
  12137 }
  12138 #endif /* BCM_TRIUMPH3_SUPPORT */
  12139 
  12140 #if defined(BCM_TRIUMPH2_SUPPORT)
  12141 STATIC int 
  12142 _tr2_l3_source_bind_traverse(int unit, bcm_l3_source_bind_traverse_cb cb, 
  12143                                 void *user_data)
  12144 {
  12145     int idx, imin, imax, nent, vmbytes, rv;
  12146     vlan_mac_entry_t * vmtab, *vmtabp;
  12147     bcm_l3_source_bind_t info;
  12148 
  12149     if (!soc_feature(unit, soc_feature_ip_source_bind)) {
  12150         return BCM_E_UNAVAIL;
  12151     }
  12152 
  12153     /* Input parameters check. */
  12154     if (NULL == cb) {
  12155         return (BCM_E_PARAM);
  12156     }
  12157 
  12158     imin = soc_mem_index_min(unit, VLAN_MACm);
  12159     imax = soc_mem_index_max(unit, VLAN_MACm);
  12160     nent = soc_mem_index_count(unit, VLAN_MACm);
  12161     vmbytes = soc_mem_entry_words(unit, VLAN_MACm);
  12162     vmbytes = WORDS2BYTES(vmbytes);
  12163     vmtab = soc_cm_salloc(unit, nent * sizeof(*vmtab), "vlan_mac");
  12164 
  12165     if (vmtab == NULL) {
  12166         return BCM_E_MEMORY;
  12167     }
  12168     
  12169     soc_mem_lock(unit, VLAN_MACm);
  12170     rv = soc_mem_read_range(unit, VLAN_MACm, MEM_BLOCK_ANY,
  12171                             imin, imax, vmtab);
  12172     if (BCM_FAILURE(rv)) {
  12173         soc_mem_unlock(unit, VLAN_MACm);
  12174         soc_cm_sfree(unit, vmtab);
  12175         return rv; 
  12176     }
  12177     
  12178     for(idx = 0; idx < nent; idx++) {
  12179         vmtabp = soc_mem_table_idx_to_pointer(unit, VLAN_MACm,
  12180                                               vlan_mac_entry_t *, 
  12181                                               vmtab, idx);
  12182 
  12183         if ((0 == soc_VLAN_MACm_field32_get(unit, vmtabp, VALIDf)) ||
  12184             (TR_VLXLT_HASH_KEY_TYPE_HPAE !=
  12185              soc_VLAN_MACm_field32_get(unit, vmtabp, KEY_TYPEf))) {
  12186             continue;
  12187         }
  12188 
  12189         rv = _tr2_l3_source_bind_hw_entry_to_sw_info(unit, vmtabp,
  12190                                                          &info);
  12191 
  12192         if (BCM_SUCCESS(rv)) {
  12193             /* Call traverse callback with the data. */
  12194             rv = cb(unit, &info, user_data);
  12195         }
  12196 
  12197         if (BCM_FAILURE(rv)) {
  12198             soc_mem_unlock(unit, VLAN_MACm);
  12199             soc_cm_sfree(unit, vmtab);
  12200             return rv; 
  12201         }
  12202     }
  12203     
  12204     soc_mem_unlock(unit, VLAN_MACm);
  12205     soc_cm_sfree(unit, vmtab);
  12206     return rv;
  12207 }
  12208 #endif /* BCM_TRIUMPH2_SUPPORT */
  12209 
  12210 /*
  12211  * Function:
  12212  *      bcm_esw_l3_source_bind_traverse
  12213  * Purpose:
  12214  *      Traverse through the L3 source bindings and run callback at
  12215  *      each defined binding.
  12216  * Parameters:
  12217  *      unit - (IN) Unit number.
  12218  *      cb - (IN) Call back routine.
  12219  *      user_data - (IN) User provided cookie for callback.
  12220  * Returns:
  12221  *      BCM_E_XXX
  12222  * Notes:
  12223  */
  12224 int
  12225 bcm_esw_l3_source_bind_traverse(int unit, bcm_l3_source_bind_traverse_cb cb,
  12226                                 void *user_data)
  12227 {
  12228 #if defined(BCM_TRIUMPH3_SUPPORT)
  12229     if (SOC_IS_TRIUMPH3(unit)) {
  12230         BCM_IF_ERROR_RETURN
  12231             (_tr3_l3_source_bind_traverse(unit,cb,user_data));
  12232         return BCM_E_NONE;
  12233     }
  12234 #endif
  12235 #if defined(BCM_TRIUMPH2_SUPPORT)
  12236     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_HURRICANE2(unit)) {
  12237         BCM_IF_ERROR_RETURN
  12238             (_tr2_l3_source_bind_traverse(unit,cb,user_data));
  12239         return BCM_E_NONE;
  12240     }
  12241 #endif
  12242     return BCM_E_UNAVAIL;
  12243 }
  12244 
  12245 #ifdef BCM_WARM_BOOT_SUPPORT
  12246 int
  12247 _bcm_l3_cleanup(int unit)
  12248 {
  12249 
  12250     return(mbcm_driver[unit]->mbcm_l3_tables_cleanup(unit));
  12251 }
  12252 #endif /* BCM_WARM_BOOT_SUPPORT */
  12253 
  12254 /*
  12255  * Function:
  12256  *      bcm_esw_l3_host_stat_attach
  12257  * Description:
  12258  *      Attach counters entries to the given L3 host entry
  12259  *
  12260  * Parameters:
  12261  *      unit             - (IN) unit number
  12262  *      info             - (IN) L3 host description  
  12263  *      stat_counter_id  - (IN) Stat Counter ID.
  12264  *
  12265  * Return Value:
  12266  *      BCM_E_XXX
  12267  */
  12268 int bcm_esw_l3_host_stat_attach(
  12269             int unit,
  12270             bcm_l3_host_t *info,
  12271             uint32 stat_counter_id)
  12272 {
  12273 #if defined(BCM_TRIDENT2_SUPPORT)
  12274     if (SOC_IS_TD2_TT2(unit)) {
  12275         return _bcm_td2_l3_host_stat_attach(unit, info, stat_counter_id);
  12276     } else
  12277 #endif
  12278 #if defined(BCM_TRIUMPH3_SUPPORT)
  12279     if (SOC_IS_TRIUMPH3(unit)) {
  12280         return _bcm_tr3_l3_host_stat_attach(unit, info, stat_counter_id);
  12281     } else
  12282 #endif
  12283     {
  12284         return BCM_E_UNAVAIL;
  12285     }
  12286 }
  12287 
  12288 /*
  12289  * Function:
  12290  *      bcm_esw_l3_host_stat_detach
  12291  * Description:
  12292  *      Detach counters entries to the given L3 host entry
  12293  *
  12294  * Parameters:
  12295  *      unit             - (IN) unit number
  12296  *      info         - (IN) L3 host description
  12297  *
  12298  * Return Value:
  12299  *      BCM_E_XXX
  12300  * Notes:
  12301  */
  12302 int bcm_esw_l3_host_stat_detach(
  12303             int unit,
  12304             bcm_l3_host_t *info)
  12305 {
  12306 #if defined(BCM_TRIDENT2_SUPPORT)
  12307     if (SOC_IS_TD2_TT2(unit)) {    
  12308         return _bcm_td2_l3_host_stat_detach(unit, info);
  12309     } else
  12310 #endif
  12311 #if defined(BCM_TRIUMPH3_SUPPORT)
  12312     if (SOC_IS_TRIUMPH3(unit)) {
  12313         return _bcm_tr3_l3_host_stat_detach(unit, info);
  12314     } else
  12315 #endif
  12316     {
  12317         return BCM_E_UNAVAIL;
  12318     }
  12319 }
  12320 
  12321 /*
  12322  * Function:
  12323  *      _bcm_esw_l3_host_stat_counter_get
  12324  * Description:
  12325  *      Get counter statistic values for specific L3 host entry
  12326  *      if sync_mode is set, sync the sw accumulated count
  12327  *      with hw count value first, else return sw count.  
  12328  * Parameters:
  12329  *      unit             - (IN) unit number
  12330  *      sync_mode        - (IN) hwcount is to be synced to sw count
  12331  *      info             - (IN) L3 host description
  12332  *      stat             - (IN) Type of the counter to retrieve
  12333  *                              I.e. ingress/egress byte/packet)
  12334  *      num_entries      - (IN) Number of counter Entries
  12335  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12336  *      counter_values   - (OUT) Pointer to counter values
  12337  *
  12338  * Return Value:
  12339  *      BCM_E_XXX
  12340  * Notes:
  12341  */
  12342 int _bcm_esw_l3_host_stat_counter_get(
  12343             int unit,
  12344             int sync_mode,
  12345             bcm_l3_host_t *info,
  12346             bcm_l3_stat_t stat,
  12347             uint32 num_entries,
  12348             uint32 *counter_indexes,
  12349             bcm_stat_value_t *counter_values)
  12350 {
  12351 
  12352 #if defined(BCM_TRIDENT2_SUPPORT)
  12353     if (SOC_IS_TD2_TT2(unit)) { 
  12354         return _bcm_td2_l3_host_stat_counter_get(unit, sync_mode, info, 
  12355                     stat, num_entries, counter_indexes, counter_values);
  12356     } else
  12357 #endif
  12358 #if defined(BCM_TRIUMPH3_SUPPORT)
  12359     if (SOC_IS_TRIUMPH3(unit)) {
  12360         return _bcm_tr3_l3_host_stat_counter_get(unit, sync_mode, info, 
  12361                     stat, num_entries, counter_indexes, counter_values);
  12362     } else
  12363 #endif
  12364     {
  12365         return BCM_E_UNAVAIL;
  12366     }
  12367 }
  12368 
  12369 
  12370 /*
  12371  * Function:
  12372  *      bcm_esw_l3_host_stat_counter_get
  12373  * Description:
  12374  *      Get counter statistic values for specific L3 host entry
  12375  *      
  12376  * Parameters:
  12377  *      unit             - (IN) unit number
  12378  *      info             - (IN) L3 host description
  12379  *      stat             - (IN) Type of the counter to retrieve
  12380  *                              I.e. ingress/egress byte/packet)
  12381  *      num_entries      - (IN) Number of counter Entries
  12382  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12383  *      counter_values   - (OUT) Pointer to counter values
  12384  *
  12385  * Return Value:
  12386  *      BCM_E_XXX
  12387  * Notes:
  12388  */
  12389 int bcm_esw_l3_host_stat_counter_get(
  12390             int unit,
  12391             bcm_l3_host_t *info,
  12392             bcm_l3_stat_t stat,
  12393             uint32 num_entries,
  12394             uint32 *counter_indexes,
  12395             bcm_stat_value_t *counter_values)
  12396 {
  12397      int rv = BCM_E_UNAVAIL;
  12398 
  12399      rv = _bcm_esw_l3_host_stat_counter_get(unit, 0, info, stat, 
  12400                                             num_entries, counter_indexes, 
  12401                                             counter_values);
  12402 
  12403      return rv;
  12404 }
  12405 
  12406 
  12407 /*
  12408  * Function:
  12409  *      bcm_esw_l3_host_stat_counter_sync_get
  12410  * Description:
  12411  *      Get counter statistic values for specific L3 host entry
  12412  *      sw accumulated counters synced with hw count.
  12413  * Parameters:
  12414  *      unit             - (IN) unit number
  12415  *      info             - (IN) L3 host description
  12416  *      stat             - (IN) Type of the counter to retrieve
  12417  *                              I.e. ingress/egress byte/packet)
  12418  *      num_entries      - (IN) Number of counter Entries
  12419  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12420  *      counter_values   - (OUT) Pointer to counter values
  12421  *
  12422  * Return Value:
  12423  *      BCM_E_XXX
  12424  * Notes:
  12425  */
  12426 int bcm_esw_l3_host_stat_counter_sync_get(
  12427             int unit,
  12428             bcm_l3_host_t *info,
  12429             bcm_l3_stat_t stat,
  12430             uint32 num_entries,
  12431             uint32 *counter_indexes,
  12432             bcm_stat_value_t *counter_values)
  12433 {
  12434      int rv = BCM_E_UNAVAIL;
  12435 
  12436      rv = _bcm_esw_l3_host_stat_counter_get(unit, 1, info, stat, 
  12437                                             num_entries, counter_indexes, 
  12438                                             counter_values);
  12439 
  12440      return rv;
  12441 }     
  12442 
  12443 /*
  12444  * Function:
  12445  *      bcm_esw_l3_host_stat_counter_set
  12446  * Description:
  12447  *      Set counter statistic values for specific L3 host entry
  12448  *
  12449  * Parameters:
  12450  *      unit             - (IN) unit number
  12451  *      info             - (IN) L3 host description
  12452  *      stat             - (IN) Type of the counter to retrieve
  12453  *                              I.e. ingress/egress byte/packet)
  12454  *      num_entries      - (IN) Number of counter Entries
  12455  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12456  *      counter_values   - (IN) Pointer to counter values
  12457  *
  12458  * Return Value:
  12459  *      BCM_E_XXX
  12460  * Notes:
  12461  */
  12462 int bcm_esw_l3_host_stat_counter_set(
  12463             int unit,
  12464             bcm_l3_host_t *info,
  12465             bcm_l3_stat_t stat,
  12466             uint32 num_entries,
  12467             uint32 *counter_indexes,
  12468             bcm_stat_value_t *counter_values)
  12469 {
  12470 #if defined(BCM_TRIDENT2_SUPPORT)
  12471     if (SOC_IS_TD2_TT2(unit)) {
  12472         return _bcm_td2_l3_host_stat_counter_set(unit, info, stat,
  12473                     num_entries, counter_indexes, counter_values);
  12474     } else
  12475 #endif
  12476 #if defined(BCM_TRIUMPH3_SUPPORT)
  12477     if (SOC_IS_TRIUMPH3(unit)) {
  12478         return _bcm_tr3_l3_host_stat_counter_set(unit, info, stat,
  12479                     num_entries, counter_indexes, counter_values);
  12480     } else
  12481 #endif
  12482     {
  12483         return BCM_E_UNAVAIL;
  12484     }
  12485 }
  12486 
  12487 /*
  12488  * Function:
  12489  *      bcm_esw_l3_host_stat_id_get
  12490  * Description:
  12491  *      Get stat counter id associated with given L3 host entry
  12492  *
  12493  * Parameters:
  12494  *      unit             - (IN) unit number
  12495  *      info             - (IN) L3 host description
  12496  *      stat             - (IN) Type of the counter to retrieve
  12497  *                              I.e. ingress/egress byte/packet)
  12498  *      Stat_counter_id  - (OUT) Stat Counter ID
  12499  * Return Value:
  12500  *      BCM_E_XXX
  12501  * Notes:
  12502  */
  12503 int bcm_esw_l3_host_stat_id_get(
  12504             int unit,
  12505             bcm_l3_host_t *info,
  12506             bcm_l3_stat_t stat,
  12507             uint32 *stat_counter_id)
  12508 {
  12509 #if defined(BCM_TRIDENT2_SUPPORT)
  12510     if (SOC_IS_TD2_TT2(unit)) { 
  12511         return _bcm_td2_l3_host_stat_id_get(unit, info, stat, stat_counter_id);
  12512     } else
  12513 #endif
  12514 #if defined(BCM_TRIUMPH3_SUPPORT)
  12515     if (SOC_IS_TRIUMPH3(unit)) {
  12516         return _bcm_tr3_l3_host_stat_id_get(unit, info, stat, stat_counter_id);
  12517     } else
  12518 #endif
  12519     {
  12520         return BCM_E_UNAVAIL;
  12521     }
  12522 }
  12523 
  12524 /*
  12525  * Function:
  12526  *      bcm_esw_l3_route_stat_attach
  12527  * Description:
  12528  *      Attach counters entries to the given  l3 route defip index . Allocate
  12529  *      flex counter and assign counter index and offset for the index pointed
  12530  *      by l3 defip index
  12531  *
  12532  * Parameters:
  12533  *      unit             - (IN) unit number
  12534  *      info             - (IN) L3 Route Info
  12535  *      stat_counter_id  - (IN) Stat Counter ID.
  12536  *
  12537  * Return Value:
  12538  *      BCM_E_XXX
  12539  * Notes:
  12540  */
  12541     
  12542 int  bcm_esw_l3_route_stat_attach (
  12543                             int                 unit,
  12544                             bcm_l3_route_t      *info,
  12545                             uint32              stat_counter_id)
  12546 {
  12547 int     rv = BCM_E_UNAVAIL;
  12548 
  12549 #if defined(BCM_TRIDENT2_SUPPORT)
  12550     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12551         L3_LOCK(unit);
  12552         rv = _bcm_td2_l3_route_stat_attach (
  12553                     unit, info, stat_counter_id);
  12554 
  12555         L3_UNLOCK(unit);
  12556     } 
  12557 #endif
  12558     return rv;
  12559 }
  12560 
  12561 
  12562 /*
  12563  * Function:
  12564  *      bcm_esw_l3_route_stat_detach
  12565  * Description:
  12566  *      Detach counter entries to the given  l3 route index. 
  12567  *
  12568  * Parameters:
  12569  *      unit             - (IN) unit number
  12570  *      info             - (IN) L3 Route Info
  12571  *
  12572  * Return Value:
  12573  *      BCM_E_XXX
  12574  * Notes:
  12575  */
  12576 int  bcm_esw_l3_route_stat_detach (
  12577                             int                 unit,
  12578                             bcm_l3_route_t      *info)
  12579 {
  12580 int     rv = BCM_E_UNAVAIL;
  12581 
  12582 #if defined(BCM_TRIDENT2_SUPPORT)
  12583     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12584         L3_LOCK(unit);
  12585         rv = _bcm_td2_l3_route_stat_detach (unit, info);
  12586         L3_UNLOCK(unit);
  12587     } 
  12588 #endif
  12589     return rv;
  12590 }
  12591 
  12592 /*
  12593  * Function:
  12594  *      _bcm_esw_l3_route_stat_counter_get
  12595  *
  12596  * Description:
  12597  *  Get l3 route counter value for specified l3 route index
  12598  *  if sync_mode is set, sync the sw accumulated count
  12599  *  with hw count value first, else return sw count.
  12600  *
  12601  * Parameters:
  12602  *      unit             - (IN) unit number
  12603  *      sync_mode        - (IN) hwcount is to be synced to sw count
  12604  *      info             - (IN)  L3 Route Info
  12605  *      stat             - (IN) l3 route counter stat types
  12606  *      num_entries      - (IN) Number of counter Entries
  12607  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12608  *      counter_values   - (OUT) Pointer to counter values
  12609  *
  12610  * Return Value:
  12611  *      BCM_E_XXX
  12612  * Notes:
  12613  */
  12614 int  _bcm_esw_l3_route_stat_counter_get(
  12615                             int                 unit, 
  12616                             int                 sync_mode,
  12617                             bcm_l3_route_t      *info,
  12618                             bcm_l3_route_stat_t stat, 
  12619                             uint32              num_entries, 
  12620                             uint32              *counter_indexes, 
  12621                             bcm_stat_value_t    *counter_values)
  12622 {
  12623 int     rv = BCM_E_UNAVAIL;
  12624 
  12625 #if defined(BCM_TRIDENT2_SUPPORT)
  12626     
  12627     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12628         L3_LOCK(unit);
  12629         rv = _bcm_td2_l3_route_stat_counter_get (
  12630                     unit, sync_mode, info, stat, num_entries, 
  12631                     counter_indexes, counter_values);
  12632         L3_UNLOCK(unit);
  12633     } 
  12634 #endif
  12635     return rv;
  12636 }
  12637 
  12638 
  12639 /*
  12640  * Function:
  12641  *      bcm_esw_l3_route_stat_counter_get
  12642  *
  12643  * Description:
  12644  *  Get l3 route counter value for specified l3 route index
  12645  *
  12646  * Parameters:
  12647  *      unit             - (IN) unit number
  12648  *      info			 - (IN)  L3 Route Info
  12649  *      stat             - (IN) l3 route counter stat types
  12650  *      num_entries      - (IN) Number of counter Entries
  12651  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12652  *      counter_values   - (OUT) Pointer to counter values
  12653  *
  12654  * Return Value:
  12655  *      BCM_E_XXX
  12656  * Notes:
  12657  */
  12658 int  bcm_esw_l3_route_stat_counter_get(
  12659                             int                 unit, 
  12660                             bcm_l3_route_t	    *info,
  12661                             bcm_l3_route_stat_t stat, 
  12662                             uint32              num_entries, 
  12663                             uint32              *counter_indexes, 
  12664                             bcm_stat_value_t    *counter_values)
  12665 {
  12666     int rv = BCM_E_UNAVAIL;
  12667 
  12668     rv = _bcm_esw_l3_route_stat_counter_get(unit, 0, info, stat,
  12669                                             num_entries, counter_indexes, 
  12670                                             counter_values);
  12671     return rv;                                            
  12672 }
  12673 
  12674 
  12675 
  12676 /*
  12677  * Function:
  12678  *      bcm_esw_l3_route_stat_counter_sync_get
  12679  *
  12680  * Description:
  12681  *  Get l3 route counter value for specified l3 route index
  12682  *  sw accumulated counters synced with hw count.
  12683  * Parameters:
  12684  *      unit             - (IN) unit number
  12685  *      info			 - (IN)  L3 Route Info
  12686  *      stat             - (IN) l3 route counter stat types
  12687  *      num_entries      - (IN) Number of counter Entries
  12688  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12689  *      counter_values   - (OUT) Pointer to counter values
  12690  *
  12691  * Return Value:
  12692  *      BCM_E_XXX
  12693  * Notes:
  12694  */
  12695 int  bcm_esw_l3_route_stat_counter_sync_get(
  12696                             int                 unit, 
  12697                             bcm_l3_route_t	    *info,
  12698                             bcm_l3_route_stat_t stat, 
  12699                             uint32              num_entries, 
  12700                             uint32              *counter_indexes, 
  12701                             bcm_stat_value_t    *counter_values)
  12702 {
  12703     int rv = BCM_E_UNAVAIL;
  12704 
  12705     rv = _bcm_esw_l3_route_stat_counter_get(unit, 1, info, stat,
  12706                                             num_entries, counter_indexes, 
  12707                                             counter_values);
  12708     return rv;                                     
  12709 }    
  12710 /*
  12711  * Function:
  12712  *      bcm_esw_l3_route_stat_counter_set
  12713  *
  12714  * Description:
  12715  *  Set l3 route counter value for specified l3 route index
  12716  *
  12717  * Parameters:
  12718  *      unit             - (IN) unit number
  12719  *      info             - (IN) L3 Route Info
  12720  *      stat             - (IN) l3 route counter stat types
  12721  *      num_entries      - (IN) Number of counter Entries
  12722  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12723  *      counter_values   - (OUT) Pointer to counter values
  12724  *
  12725  * Return Value:
  12726  *      BCM_E_XXX
  12727  * Notes:
  12728  */
  12729 int  bcm_esw_l3_route_stat_counter_set(
  12730                             int                 unit, 
  12731                             bcm_l3_route_t      *info,
  12732                             bcm_l3_route_stat_t stat, 
  12733                             uint32              num_entries, 
  12734                             uint32              *counter_indexes, 
  12735                             bcm_stat_value_t    *counter_values)
  12736 {
  12737     int rv = BCM_E_UNAVAIL;
  12738 
  12739     if (counter_indexes == NULL || counter_values == NULL) {
  12740         return BCM_E_PARAM;
  12741     }
  12742 
  12743 #if defined(BCM_TRIDENT2_SUPPORT)
  12744     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12745         L3_LOCK(unit);
  12746         rv = _bcm_td2_l3_route_stat_counter_set (
  12747                     unit, info, stat, num_entries, 
  12748                     counter_indexes, counter_values);
  12749         L3_UNLOCK(unit);
  12750     } 
  12751 #endif
  12752     return rv;
  12753 }
  12754 
  12755 /*
  12756  * Function:
  12757  *      bcm_esw_l3_route_stat_multi_get
  12758  *
  12759  * Description:
  12760  *  Get Multiple l3 route counter value for specified l3 route index for multiple stat
  12761  *  types
  12762  *
  12763  * Parameters:
  12764  *      unit             - (IN) unit number
  12765  *      info             - (IN) L3 Route Info
  12766  *      nstat            - (IN) Number of elements in stat array
  12767  *      stat_arr         - (IN) Collected statistics descriptors array
  12768  *      value_arr        - (OUT) Collected counters values
  12769  *
  12770  * Return Value:
  12771  *      BCM_E_XXX
  12772  * Notes:
  12773  */
  12774 
  12775     
  12776 int  bcm_esw_l3_route_stat_multi_get(
  12777                             int                 unit, 
  12778                             bcm_l3_route_t      *info,
  12779                             int                 nstat, 
  12780                             bcm_l3_route_stat_t *stat_arr,
  12781                             uint64              *value_arr)
  12782 {
  12783 int     rv = BCM_E_UNAVAIL;
  12784 
  12785 #if defined(BCM_TRIDENT2_SUPPORT)
  12786     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12787         L3_LOCK(unit);
  12788         rv = _bcm_td2_l3_route_stat_multi_get (
  12789                     unit, info, nstat, stat_arr, value_arr);
  12790         L3_UNLOCK(unit);
  12791     } 
  12792 #endif
  12793     return rv;
  12794 }
  12795 
  12796 /*
  12797  * Function:
  12798  *      bcm_esw_l3_route_stat_multi_get32
  12799  *
  12800  * Description:
  12801  *  Get 32bit l3 route counter value for specified l3 route index for multiple stat
  12802  *  types
  12803  *
  12804  * Parameters:
  12805  *      unit             - (IN) unit number
  12806  *      info             - (IN) L3 Route Info
  12807  *      nstat            - (IN) Number of elements in stat array
  12808  *      stat_arr         - (IN) Collected statistics descriptors array
  12809  *      value_arr        - (OUT) Collected counters values
  12810  *
  12811  * Return Value:
  12812  *      BCM_E_XXX
  12813  * Notes:
  12814  */
  12815 int  bcm_esw_l3_route_stat_multi_get32(
  12816                             int                 unit, 
  12817                             bcm_l3_route_t      *info,
  12818                             int                 nstat, 
  12819                             bcm_l3_route_stat_t *stat_arr,
  12820                             uint32              *value_arr)
  12821 {
  12822 int     rv = BCM_E_UNAVAIL;
  12823 
  12824 #if defined(BCM_TRIDENT2_SUPPORT)
  12825     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12826         L3_LOCK(unit);
  12827        rv = _bcm_td2_l3_route_stat_multi_get32 (
  12828                     unit, info, nstat, stat_arr, value_arr);
  12829         L3_UNLOCK(unit);
  12830     } 
  12831 #endif
  12832     return rv;
  12833 }
  12834 
  12835 /*
  12836  * Function:
  12837  *     bcm_esw_l3_route_stat_multi_set
  12838  *
  12839  * Description:
  12840  *  Set l3 route counter value for specified l3 route index for multiple stat
  12841  *  types
  12842  *
  12843  * Parameters:
  12844  *      unit             - (IN) unit number
  12845  *      info             - (IN) L3 Route Info
  12846  *      stat             - (IN) l3 route counter stat types
  12847  *      num_entries      - (IN) Number of counter Entries
  12848  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12849  *      counter_values   - (OUT) Pointer to counter values
  12850  *
  12851  * Return Value:
  12852  *      BCM_E_XXX
  12853  * Notes:
  12854  */
  12855 int  bcm_esw_l3_route_stat_multi_set(
  12856                             int                 unit, 
  12857                             bcm_l3_route_t      *info,
  12858                             int                 nstat, 
  12859                             bcm_l3_route_stat_t *stat_arr,
  12860                             uint64              *value_arr)
  12861 {
  12862 int     rv = BCM_E_UNAVAIL;
  12863 
  12864 #if defined(BCM_TRIDENT2_SUPPORT)
  12865     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12866         L3_LOCK(unit);
  12867         rv = _bcm_td2_l3_route_stat_multi_set (
  12868                     unit, info, nstat, stat_arr, value_arr);
  12869         L3_UNLOCK(unit);
  12870     } 
  12871 #endif
  12872     return rv;
  12873 
  12874 }
  12875 
  12876 /*
  12877  * Function:
  12878  *      bcm_esw_l3_route_stat_multi_set32
  12879  *
  12880  * Description:
  12881  *  Set 32bit l3 route counter value for specified l3 route index for multiple stat
  12882  *  types
  12883  *
  12884  * Parameters:
  12885  *      unit             - (IN) unit number
  12886  *      info             - (IN) L3 Route Info
  12887  *      stat             - (IN) l3 route counter stat types
  12888  *      num_entries      - (IN) Number of counter Entries
  12889  *      counter_indexes  - (IN) Pointer to Counter indexes entries
  12890  *      counter_values   - (OUT) Pointer to counter values
  12891  *
  12892  * Return Value:
  12893  *      BCM_E_XXX
  12894  * Notes:
  12895  */
  12896 
  12897 int  bcm_esw_l3_route_stat_multi_set32(
  12898                             int                 unit, 
  12899                             bcm_l3_route_t      *info,
  12900                             int                 nstat, 
  12901                             bcm_l3_route_stat_t *stat_arr,
  12902                             uint32              *value_arr)
  12903 {
  12904 int     rv = BCM_E_UNAVAIL;
  12905 
  12906 #if defined(BCM_TRIDENT2_SUPPORT)
  12907     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12908         L3_LOCK(unit);
  12909         rv = _bcm_td2_l3_route_stat_multi_set32 (
  12910                     unit, info, nstat, stat_arr, value_arr);
  12911         L3_UNLOCK(unit);
  12912     } 
  12913 #endif
  12914     return rv;
  12915 }
  12916 
  12917 /*
  12918  * Function: 
  12919  *      bcm_esw_l3_route_stat_id_get
  12920  *
  12921  * Description: 
  12922  *      Get Stat Counter if associated with given l3 route index
  12923  *
  12924  * Parameters: 
  12925  *      unit             - (IN) bcm device
  12926  *      info             - (IN) L3 Route Info
  12927  *      stat             - (IN) l3 route counter stat types
  12928  *      stat_counter_id  - (IN) Stat Counter ID.
  12929  *
  12930  * Returns:
  12931  *      BCM_E_NONE - Success
  12932  *      BCM_E_XXX
  12933  * Notes:
  12934  */
  12935 
  12936 int  bcm_esw_l3_route_stat_id_get(
  12937                             int                 unit,
  12938                             bcm_l3_route_t      *info,
  12939                             bcm_l3_route_stat_t stat, 
  12940                             uint32              *stat_counter_id) 
  12941 {
  12942 int     rv = BCM_E_UNAVAIL;
  12943 
  12944 #if defined(BCM_TRIDENT2_SUPPORT)
  12945     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  12946         rv = _bcm_td2_l3_route_stat_id_get (
  12947                     unit, info, stat, stat_counter_id);
  12948     } 
  12949 #endif
  12950     return rv;
  12951 }
  12952 
  12953 /*
  12954  * Function:
  12955  *      bcm_esw_l3_route_stat_enable_set
  12956  * Purpose:
  12957  *      Enable/disable packet and byte counters for the selected route
  12958  * Parameters:
  12959  *      unit - (IN) Unit number.
  12960  *      info - (IN) Route info
  12961  *      enable - (IN) Non-zero to enable counter collection, zero to disable.
  12962  * Returns:
  12963  *      BCM_E_XXX
  12964  * Notes:
  12965  */
  12966 int 
  12967 bcm_esw_l3_route_stat_enable_set(int unit, bcm_l3_route_t *info, int enable)
  12968 {
  12969     int     rv = BCM_E_UNAVAIL;
  12970 
  12971     /* Old Flex API interfaces are not supported for L3 Route */
  12972     
  12973     return rv;
  12974 }
  12975 
  12976 /*
  12977  * Function:
  12978  *      bcm_esw_l3_route_stat_get
  12979  * Purpose:
  12980  *      Get 64-bit counter value for specified L3 Route Types.
  12981  * Parameters:
  12982  *      unit - (IN) Unit number.
  12983  *      info - (IN) Route info
  12984  *      stat - (IN) Type of the counter to retrieve.
  12985  *      val - (OUT) Pointer to a counter value.
  12986  * Returns:
  12987  *      BCM_E_XXX
  12988  * Notes:
  12989  */
  12990 int 
  12991 bcm_esw_l3_route_stat_get(int unit, bcm_l3_route_t *info, bcm_l3_stat_t stat,
  12992                         uint64 *val)
  12993 {
  12994     int     rv = BCM_E_UNAVAIL;
  12995 
  12996     /* Old Flex API interfaces are not supported for L3 route */
  12997     
  12998     return rv;
  12999 }
  13000 
  13001 /*
  13002  * Function:
  13003  *      bcm_esw_l3_route_stat_get32
  13004  * Purpose:
  13005  *      Get 32-bit counter value for specified L3 Route Types.
  13006  * Parameters:
  13007  *      unit - (IN) Unit number.
  13008  *      info - (IN) Route info
  13009  *      stat - (IN) Type of the counter to retrieve.
  13010  *      val - (OUT) Pointer to a counter value.
  13011  * Returns:
  13012  *      BCM_E_XXX
  13013  * Notes:
  13014  */
  13015 int 
  13016 bcm_esw_l3_route_stat_get32(int unit, bcm_l3_route_t *info, bcm_l3_stat_t stat,
  13017                         uint32 *val)
  13018 {
  13019     int     rv = BCM_E_UNAVAIL;
  13020 
  13021     /* Old Flex API interfaces are not supported for L3 route */
  13022     
  13023     return rv;
  13024 }
  13025 
  13026 /*
  13027  * Function:
  13028  *      bcm_esw_l3_route_stat_set
  13029  * Purpose:
  13030  *      Get 64-bit counter value for specified L3 Route Types.
  13031  * Parameters:
  13032  *      unit - (IN) Unit number.
  13033  *      info - (IN) Route info
  13034  *      stat - (IN) Type of the counter to retrieve.
  13035  *      val - (OUT) Pointer to a counter value.
  13036  * Returns:
  13037  *      BCM_E_XXX
  13038  * Notes:
  13039  */
  13040 int 
  13041 bcm_esw_l3_route_stat_set(int unit, bcm_l3_route_t *info, bcm_l3_stat_t stat,
  13042                         uint64 val)
  13043 {
  13044     int     rv = BCM_E_UNAVAIL;
  13045 
  13046     /* Old Flex API interfaces are not supported for L3 route */
  13047     
  13048     return rv;
  13049 }
  13050 
  13051 /*
  13052  * Function:
  13053  *      bcm_esw_l3_route_stat_set32
  13054  * Purpose:
  13055  *      Get 32-bit counter value for specified L3 Route Types.
  13056  * Parameters:
  13057  *      unit - (IN) Unit number.
  13058  *      info - (IN) Route info
  13059  *      stat - (IN) Type of the counter to retrieve.
  13060  *      val - (OUT) Pointer to a counter value.
  13061  * Returns:
  13062  *      BCM_E_XXX
  13063  * Notes:
  13064  */
  13065 int 
  13066 bcm_esw_l3_route_stat_set32(int unit, bcm_l3_route_t *info, bcm_l3_stat_t stat,
  13067                         uint32 val)
  13068 {
  13069     int     rv = BCM_E_UNAVAIL;
  13070 
  13071     /* Old Flex API interfaces are not supported for L3 route */
  13072     
  13073     return rv;
  13074 }
  13075 
  13076 
  13077 /*
  13078  * Function:
  13079  *      bcm_esw_l3_ip4_options_profile_create
  13080  * Purpose:
  13081  *      Create an IP option handling profile.
  13082  * Parameters:
  13083  *      unit    - (IN)  bcm device.
  13084  *      flags   - (IN)  BCM_L3_WITH_ID: ip4_options_profile_id argument given.
  13085  *      default_action - (IN) Default action for options in the profile
  13086  *      ip4_options_profile_id - (OUT) L3 IP options profile ID
  13087  *                      This is an IN argument if BCM_L3_WITH_ID is given in 
  13088  *                      flag.
  13089  * Returns:
  13090  *      BCM_E_XXX
  13091  */
  13092 int 
  13093 bcm_esw_l3_ip4_options_profile_create(int unit, uint32 flags, 
  13094                          bcm_l3_ip4_options_action_t default_action, 
  13095                          int *ip4_options_profile_id)
  13096 {
  13097     int rv = BCM_E_UNAVAIL;
  13098     if (ip4_options_profile_id == NULL) {
  13099         return BCM_E_PARAM;
  13100     }
  13101 #ifdef BCM_TRIDENT2_SUPPORT
  13102     if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
  13103         rv = _bcm_td2_l3_ip4_options_profile_create(unit, flags, 
  13104                          default_action, ip4_options_profile_id);
  13105     }
  13106 #endif /* BCM_TRIDENT2_SUPPORT */
  13107     return (rv);
  13108 }
  13109 
  13110 /*
  13111  * Function:
  13112  *      bcm_esw_l3_ip4_options_profile_destroy
  13113  * Purpose:
  13114  *      Delete a IP option handling profile.
  13115  * Parameters:
  13116  *      unit    - (IN)  bcm device.
  13117  *      ip4_options_profile_id - (IN) L3 IP options profile ID
  13118  * Returns:
  13119  *      BCM_E_XXX
  13120  */
  13121 int 
  13122 bcm_esw_l3_ip4_options_profile_destroy(int unit, int ip4_options_profile_id)
  13123 {
  13124     int rv = BCM_E_UNAVAIL;
  13125 #ifdef BCM_TRIDENT2_SUPPORT
  13126     if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
  13127         rv = _bcm_td2_l3_ip4_options_profile_destroy(unit, ip4_options_profile_id);
  13128     }
  13129 #endif /* BCM_TRIDENT2_SUPPORT */
  13130     return (rv);
  13131 }
  13132 
  13133 
  13134 /*
  13135  * Function:
  13136  *      bcm_esw_l3_ip4_options_action_set
  13137  * Purpose:
  13138  *      Update action for given IP action and Profile ID 
  13139  * Parameters:
  13140  *      unit                   - (IN)  bcm device.
  13141  *      ip4_options_profile_id - (IN)  IP options profile ID
  13142  *      ip4_option             - (IN)  New Action for IP Options
  13143  * Returns:
  13144  *      BCM_E_XXX
  13145  */
  13146 int 
  13147 bcm_esw_l3_ip4_options_action_set(int unit,
  13148                          int ip4_options_profile_id, 
  13149                          int ip4_option, 
  13150                          bcm_l3_ip4_options_action_t action)
  13151 {
  13152     int rv = BCM_E_UNAVAIL;
  13153 #ifdef BCM_TRIDENT2_SUPPORT
  13154     if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
  13155         rv = _bcm_td2_l3_ip4_options_profile_action_set(unit, ip4_options_profile_id,
  13156                          ip4_option, action);
  13157     }
  13158 #endif /* BCM_TRIDENT2_SUPPORT */
  13159     return (rv);
  13160 }
  13161 
  13162 /*
  13163  * Function:
  13164  *      bcm_esw_l3_ip4_options_action_get
  13165  * Purpose:
  13166  *      Retrive action for given IP action and Profile ID 
  13167  * Parameters:
  13168  *      unit                   - (IN)  bcm device.
  13169  *      ip4_options_profile_id - (IN)  IP options profile ID
  13170  *      ip4_option             - (OUT) Action for IP Options
  13171  * Returns:
  13172  *      BCM_E_XXX
  13173  */
  13174 int 
  13175 bcm_esw_l3_ip4_options_action_get(int unit,
  13176                          int ip4_options_profile_id, 
  13177                          int ip4_option, 
  13178                          bcm_l3_ip4_options_action_t *action)
  13179 {
  13180     int rv = BCM_E_UNAVAIL;
  13181     if (action == NULL) {
  13182         return BCM_E_PARAM;
  13183     }
  13184 #ifdef BCM_TRIDENT2_SUPPORT
  13185     if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
  13186         rv = _bcm_td2_l3_ip4_options_profile_action_get(unit, ip4_options_profile_id, 
  13187                          ip4_option, action);
  13188     }
  13189 #endif /* BCM_TRIDENT2_SUPPORT */
  13190     return (rv);
  13191 }
  13192 
  13193 /*
  13194  * Function:
  13195  *      _bcm_esw_l3_egress_reference_get
  13196  * Purpose:
  13197  *      Get the reference count of the following object
  13198  *      
  13199  *      Egress object       ECMP = 0
  13200  *      Multipath object    ECMP = 1
  13201  *
  13202  * Parameters:
  13203  *      unit       - (IN) bcm device.
  13204  *      mpintf     - (IN) L3 interface id pointing to Egress nh/multipath object
  13205  *      ecmp       - (IN) Flag to indicate the object is multicast or not
  13206  *      ref_count  - (OUT) The number of references to the L3 Table
  13207  * Returns:
  13208  *      BCM_E_XXX
  13209  */
  13210 int
  13211 _bcm_esw_l3_egress_reference_get(int unit, bcm_if_t mpintf, int ecmp,
  13212                                  uint32 * ref_count)
  13213 {
  13214 #if defined(BCM_XGS3_SWITCH_SUPPORT)
  13215     int offset = 0;
  13216     uint32 object_id;
  13217 
  13218     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
  13219         L3_LOCK(unit);
  13220 
  13221         if (ecmp != 0) {
  13222             /* Multipath object */
  13223             offset = BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  13224         } else {
  13225             /* None-Multipaht object */
  13226             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, mpintf)) {
  13227                 /* Egress object */
  13228                 offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  13229             } else if ( BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, mpintf)) {
  13230                 /* DVP Egress object */
  13231                 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  13232             }
  13233         }
  13234 
  13235         object_id = mpintf - offset;
  13236 
  13237         _bcm_xgs3_nh_ref_cnt_get(unit, object_id, ecmp, ref_count);
  13238 
  13239         L3_UNLOCK(unit);
  13240     }
  13241 #endif /* BCM_XGS3_SWITCH_SUPPORT */
  13242     return (BCM_E_NONE);
  13243 }
  13244 
  13245 /*
  13246  * Function:
  13247  *      _bcm_esw_l3_egress_ref_dlb_update
  13248  * Purpose:
  13249  *      Update the reference count based on DLB
  13250  *
  13251  * Parameters:
  13252  *      unit       - (IN) bcm device.
  13253  *      index       - (IN) egress object index
  13254  *      ref_count  - (OUT) pointer of the number of references to the L3 Table
  13255  * Returns:
  13256  *      BCM_E_XXX
  13257  */
  13258 int
  13259 _bcm_esw_l3_egress_ref_dlb_update(int unit, int index,uint32 * ref_count)
  13260 {
  13261     int rv = BCM_E_NONE;
  13262 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined (BCM_TRIDENT3_SUPPORT)
  13263     int i, j;
  13264     bcm_l3_egress_ecmp_t tmp_ecmp;
  13265     SHR_BITDCL *group_bitmap_ptr = NULL;
  13266     int dlb_intf_count = 0;
  13267     bcm_if_t *dlb_intf_array = NULL;
  13268     int group_enable;
  13269     ecmp_dlb_control_entry_t *ecmp_group_entry;
  13270     int offset = 0;
  13271     int index_min, index_max, buf_size;
  13272     uint8 *ecmp_dlb_buf = NULL;
  13273     soc_mem_t mem = ECMP_DLB_CONTROLm;
  13274 
  13275     if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  13276         int dlb_start = 0, dlb_end = 0;
  13277         dlb_intf_array = sal_alloc(sizeof(bcm_if_t) *
  13278                                    BCM_XGS3_L3_ECMP_MAX(unit),
  13279                                    "ecmp intf array");
  13280         if (NULL == dlb_intf_array) {
  13281             return BCM_E_MEMORY;
  13282         }
  13283 #if defined(BCM_TOMAHAWK3_SUPPORT)
  13284         if (soc_feature(unit, soc_feature_th3_style_dlb)) {
  13285             dlb_start = BCM_TH3_L3_ECMP_DLB_START(unit);
  13286             dlb_end = BCM_TH3_L3_ECMP_DLB_END(unit) + 1;
  13287         } else
  13288 #endif
  13289         {
  13290             index_min = soc_mem_index_min(unit, mem);
  13291             index_max = soc_mem_index_max(unit, mem);
  13292             dlb_end = soc_mem_index_count(unit, ECMP_DLB_CONTROLm);
  13293             buf_size = SOC_MEM_TABLE_BYTES(unit, mem);
  13294             ecmp_dlb_buf = soc_cm_salloc(unit, buf_size, "ECMP_DLB_CONTROL buffer for group");
  13295             if (NULL == ecmp_dlb_buf) {
  13296                 rv = BCM_E_MEMORY;
  13297                 goto cleanup;
  13298             }
  13299             rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, index_min, index_max, ecmp_dlb_buf);
  13300             if (SOC_FAILURE(rv)) {
  13301                 goto cleanup;
  13302             }
  13303         }
  13304 #if defined(BCM_TOMAHAWK3_SUPPORT)
  13305         if (soc_feature(unit, soc_feature_th3_style_dlb)) {
  13306             offset = (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) ? 1 : 2;
  13307         } else
  13308 #endif
  13309         {
  13310             offset = 1;
  13311         }
  13312         for (i = dlb_start; i < dlb_end; i += offset) {
  13313 #if defined(BCM_TOMAHAWK3_SUPPORT)
  13314             if (soc_feature(unit, soc_feature_th3_style_dlb)) {
  13315                 uint64 dlb_en_bitmap;
  13316                 uint32 dlb_id, len;
  13317                 dlb_id = i - BCM_TH3_L3_ECMP_DLB_START(unit);
  13318                 len = soc_reg_field_length(unit,
  13319                                            DLB_ID_0_TO_63_ENABLEr, BITMAPf);
  13320                 if (len == 0) {
  13321                     rv = BCM_E_INTERNAL;
  13322                     goto cleanup;
  13323                 }
  13324                 if (dlb_id < len) {
  13325                     SOC_IF_ERROR_RETURN
  13326                         (READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap));
  13327                     group_enable = ((COMPILER_64_BITTEST(dlb_en_bitmap,
  13328                                                          dlb_id)));
  13329                 } else {
  13330                     SOC_IF_ERROR_RETURN
  13331                         (READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap));
  13332                     group_enable = ((COMPILER_64_BITTEST(dlb_en_bitmap,
  13333                                                          dlb_id - len)));
  13334                 }
  13335             } else
  13336 #endif
  13337             {
  13338                 ecmp_group_entry = (ecmp_dlb_control_entry_t *)
  13339                                soc_mem_table_idx_to_pointer
  13340                                   (unit, mem, void *, ecmp_dlb_buf, i);
  13341                 group_enable = soc_ECMP_DLB_CONTROLm_field32_get(unit,
  13342                                                              ecmp_group_entry,
  13343                                                              GROUP_ENABLEf);
  13344             }
  13345             if (0 == group_enable) {
  13346                 /* DLB not enabled */
  13347                 continue;
  13348             }
  13349 
  13350             bcm_l3_egress_ecmp_t_init(&tmp_ecmp);
  13351             tmp_ecmp.ecmp_intf = i + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  13352             rv = _bcm_esw_l3_egress_ecmp_get(unit, &tmp_ecmp,
  13353                                              BCM_XGS3_L3_ECMP_MAX(unit),
  13354                                              dlb_intf_array, &dlb_intf_count,
  13355                                              TRUE);
  13356             if (BCM_FAILURE(rv)) {
  13357                 rv = BCM_E_INTERNAL;
  13358                 goto cleanup;
  13359             }
  13360             group_bitmap_ptr =
  13361                 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, i);
  13362             for (j = 0; j < dlb_intf_count; j++) {
  13363                 if (!SHR_BITGET(group_bitmap_ptr, j) &&
  13364                     (index == dlb_intf_array[j])) {
  13365                     ref_count--;
  13366                 }
  13367             }
  13368         }
  13369 cleanup:
  13370         if (ecmp_dlb_buf) {
  13371             soc_cm_sfree(unit, ecmp_dlb_buf);
  13372         }
  13373         sal_free(dlb_intf_array);
  13374     }
  13375 #endif
  13376 
  13377     return rv;
  13378 }
  13379 
  13380 /*
  13381  * Function:
  13382  *      bcmi_esw_l3_egress_ref_count_update
  13383  * Purpose:
  13384  *      Update the reference count of the following object
  13385  *
  13386  *      Egress object       ECMP = 0
  13387  *      Multipath object    ECMP = 1
  13388  *
  13389  * Parameters:
  13390  *      unit       - (IN) bcm device.
  13391  *      intf       - (IN) L3 interface id pointing to Egress nh/multipath object
  13392  *      flags      - (IN) Flag to indicate the object is multicast or not
  13393  *      nh_ecmp_id - (IN) Next Hop ECMP Id
  13394  *      incr       - (IN) Increment/Decrement
  13395  * Returns:
  13396  *      BCM_E_XXX
  13397  */
  13398 int
  13399 bcmi_esw_l3_egress_ref_count_update(int unit,
  13400                                          bcm_if_t intf,
  13401                                          uint32 flags,
  13402                                          int nh_ecmp_id,
  13403                                          int incr) 
  13404 {
  13405     int rv = BCM_E_UNAVAIL;
  13406 
  13407 #if defined(BCM_XGS3_SWITCH_SUPPORT)
  13408     if (SOC_IS_XGS3_SWITCH(unit) && soc_feature(unit, soc_feature_l3)) {
  13409         L3_LOCK(unit);
  13410         rv = bcmi_xgs3_l3_egress_ref_count_update (unit,
  13411                 intf, flags, nh_ecmp_id, incr);
  13412         L3_UNLOCK(unit);
  13413     }
  13414 #endif
  13415     return rv;
  13416 }
  13417 
  13418 /*
  13419  * Function:
  13420  *      bcm_esw_l3_egress_multi_alloc
  13421  * Purpose:
  13422  *      Allocates multiple egress objects.
  13423  *
  13424  * Parameters:
  13425  *      unit                - (IN) bcm device.
  13426  *      egress_multi_info   - (IN) information needed to create multiple
  13427  *                                 egress objects
  13428  *      base_egress_id      - (IN/OUT) base Next Hop Id
  13429  * Returns:
  13430  *      BCM_E_XXX
  13431  */
  13432 int
  13433 bcm_esw_l3_egress_multi_alloc(int unit,
  13434         bcm_l3_egress_multi_info_t egress_multi_info,
  13435         bcm_if_t *base_egress_id)
  13436 {
  13437     int rv = BCM_E_NONE;
  13438 
  13439     if (base_egress_id == NULL) {
  13440         return BCM_E_PARAM;
  13441     }
  13442 
  13443     L3_LOCK(unit);
  13444     rv = bcmi_l3_egress_multi_alloc(unit, egress_multi_info, base_egress_id);
  13445     L3_UNLOCK(unit);
  13446 
  13447     return rv;
  13448 }
  13449 
  13450 /*
  13451  * Function:
  13452  *      bcm_esw_l3_egress_multi_free
  13453  * Purpose:
  13454  *      Frees multiple egress objects.
  13455  *
  13456  * Parameters:
  13457  *      unit                - (IN) bcm device.
  13458  *      base_egress_id      - (IN) base Next Hop Id
  13459  * Returns:
  13460  *      BCM_E_XXX
  13461  */
  13462 int
  13463 bcm_esw_l3_egress_multi_free(int unit, bcm_if_t base_egress_id)
  13464 {
  13465 
  13466     int rv = BCM_E_NONE;
  13467 
  13468     L3_LOCK(unit);
  13469     rv = bcmi_l3_egress_multi_free(unit, base_egress_id);
  13470     L3_UNLOCK(unit);
  13471 
  13472     return rv;
  13473 }
  13474 
  13475 /*
  13476  * Function:
  13477  *      bcm_esw_l3_intf_vpn_set
  13478  * Purpose:
  13479  *      Set the VPN on a given L3 Egress interface.
  13480  *
  13481  * Parameters:
  13482  *      unit         - (IN) Unit number.
  13483  *      l3_intf_id   - (IN) Interface ID of an egress L3 object
  13484  *      bcm_vpn_t    - (IN) VPN_ID that needs to be set on this interface
  13485  *      flags        - (IN) Flags for future use
  13486  * Returns:
  13487  *      BCM_E_XXX
  13488  */
  13489 int
  13490 bcm_esw_l3_intf_vpn_set(int unit,
  13491         bcm_if_t l3_intf_id, uint32 flags,
  13492         bcm_vpn_t vpn)
  13493 {
  13494     int rv = BCM_E_UNAVAIL;
  13495 #ifdef BCM_TRIDENT3_SUPPORT
  13496     if (soc_feature(unit, soc_feature_egr_intf_vlan_vfi_deoverlay)) {
  13497         L3_LOCK(unit);
  13498         rv = bcmi_l3_intf_vpn_set(unit, l3_intf_id, vpn, flags);
  13499         L3_UNLOCK(unit);
  13500     }
  13501 #endif
  13502         return rv;
  13503 }
  13504 
  13505 /*
  13506  * Function:
  13507  *      bcm_esw_l3_intf_vpn_get
  13508  * Purpose:
  13509  *      Get the VPN on a given L3 Egress interface.
  13510  *
  13511  * Parameters:
  13512  *      unit         - (IN) Unit number.
  13513  *      l3_intf_id   - (IN) Interface ID of an egress L3 object
  13514  *      bcm_vpn_t    - (OUT) VPN_ID that was set on this interface
  13515  *      flags        - (OUT) Flags for future use
  13516  * Returns:
  13517  *      BCM_E_XXX
  13518  */
  13519 int
  13520 bcm_esw_l3_intf_vpn_get(int unit,
  13521         bcm_if_t l3_intf_id, uint32 *flags,
  13522         bcm_vpn_t *vpn)
  13523 {
  13524     int rv = BCM_E_UNAVAIL;
  13525 #ifdef BCM_TRIDENT3_SUPPORT
  13526     if (soc_feature(unit, soc_feature_egr_intf_vlan_vfi_deoverlay)) {
  13527         L3_LOCK(unit);
  13528         rv = bcmi_l3_intf_vpn_get(unit, l3_intf_id, vpn, flags);
  13529         L3_UNLOCK(unit);
  13530     }
  13531 #endif
  13532         return rv;
  13533 }
  13534 
  13535 /*
  13536  * Function:
  13537  *    bcmi_esw_l3_dependent_cleanup
  13538  * Purpose:
  13539  *    frees l3 dependednt resources from other modules.
  13540  * Parameters:
  13541  *    unit                 - (IN)bcm device id
  13542  * Returns:
  13543  *    NONE
  13544  */
  13545 void
  13546 bcmi_esw_l3_dependent_cleanup(int unit)
  13547 {
  13548     bcmi_l3_dependent_free_resources(unit);
  13549 }
  13550 
  13551 /*
  13552  * Function:
  13553  *      bcm_esw_l3_ecmp_dlb_mon_config_set
  13554  * Purpose:
  13555  *      This API configures DLB flow monitoring parameters for a DLB id
  13556  *      derived from ECMP group id (the second argument). The monitored packets
  13557  *      can be copied to cpu and/or mirrored (using newly defined PSAMP header
  13558  *      formats). The sample rate is used to program sampling threshold to
  13559  *      determine when a packet should be sampled.
  13560  * Parameters:
  13561  *      unit :        (IN) Device's unit number
  13562  *      ecmp_intf :   (IN) ECMP interface id obtained from bcm_l3_ecmp_create or
  13563  *                         bcm_l3_egress_ecmp_create
  13564  *      dlb_mon_cfg : (IN) DLB flow monitoring configuration
  13565  * Returns:
  13566  *      BCM_E_XXX
  13567  * Notes:
  13568  *    Property spn_DLB_FLOW_MONITOR_EN must be enabled to use this API
  13569  */
  13570 int
  13571 bcm_esw_l3_ecmp_dlb_mon_config_set(int unit,
  13572                                    bcm_if_t ecmp_intf,
  13573                                    bcm_l3_ecmp_dlb_mon_cfg_t *dlb_mon_cfg)
  13574 {
  13575 #ifdef BCM_TOMAHAWK3_SUPPORT
  13576     int rv = BCM_E_UNAVAIL;
  13577 
  13578     /* Currently this API is supported on Tomahawk3 only */
  13579     if (!SOC_IS_TOMAHAWK3(unit)) {
  13580         return BCM_E_UNAVAIL;
  13581     }
  13582 
  13583     rv = bcm_th3_l3_ecmp_dlb_mon_config_set(unit, ecmp_intf, dlb_mon_cfg);
  13584 
  13585     return rv;
  13586 #else /* BCM_TOMAHAWK3_SUPPORT */
  13587     return BCM_E_UNAVAIL;
  13588 #endif
  13589 }
  13590 
  13591 /*
  13592  * Function:
  13593  *    bcm_esw_l3_ecmp_dlb_mon_config_get
  13594  * Purpose:
  13595  *    This API will fetch DLB monitoring parameters from hardware, for a DLB id
  13596  *    derived from ECMP group id (the second argument). If the get API is called
  13597  *    before any configuration, just after init, it will return default hardware
  13598  *    values. In other cases, it will contain the last configured set of values
  13599  *    associated with the DLB id.
  13600  * Parameters:
  13601  *    unit :        (IN) Device's unit number
  13602  *    ecmp_intf :   (IN) ECMP interface id obtained from bcm_l3_ecmp_create or,
  13603  *                       bcm_l3_egress_ecmp_create
  13604  *    dlb_mon_cfg : (OUT) DLB flow monitoring configuration read from h/w for
  13605  *                        specified DLB
  13606  * Returns:
  13607  *    BCM_E_XXX
  13608  * Notes:
  13609  * 1. Property spn_DLB_FLOW_MONITOR_EN must be enabled to use this API
  13610  * 2. Sample rates are calculated only if MONITOR_EN is set for a DLB id.
  13611  *    Otherwise, sample rate of 0 is returned.
  13612  */
  13613 int bcm_esw_l3_ecmp_dlb_mon_config_get(int unit,
  13614                                        bcm_if_t ecmp_intf,
  13615                                        bcm_l3_ecmp_dlb_mon_cfg_t *dlb_mon_cfg)
  13616 {
  13617 #ifdef BCM_TOMAHAWK3_SUPPORT
  13618     int rv = BCM_E_UNAVAIL;
  13619 
  13620     /* Currently this API is supported on Tomahawk3 only */
  13621     if (!SOC_IS_TOMAHAWK3(unit)) {
  13622         return BCM_E_UNAVAIL;
  13623     }
  13624 
  13625     rv = bcm_th3_l3_ecmp_dlb_mon_config_get(unit, ecmp_intf, dlb_mon_cfg);
  13626 
  13627     return rv;
  13628 #else /* BCM_TOMAHAWK3_SUPPORT */
  13629     return BCM_E_UNAVAIL;
  13630 #endif
  13631 }
  13632 
  13633 #endif  /* INCLUDE_L3 */
  13634