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

multicast.c (42301B)


      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:    multicast.c
      8  * Purpose: Manages multicast functions
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <sal/core/libc.h>
     13 
     14 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
     15 
     16 #include <soc/drv.h>
     17 #include <soc/scache.h>
     18 #include <soc/util.h>
     19 #include <soc/debug.h>
     20 #include <soc/triumph.h>
     21 
     22 #include <bcm/error.h>
     23 
     24 #include <bcm_int/esw/mbcm.h>
     25 #include <bcm_int/esw/l3.h>
     26 #include <bcm_int/esw/firebolt.h>
     27 #include <bcm_int/esw/triumph.h>
     28 #ifdef BCM_TRIUMPH2_SUPPORT
     29 #include <bcm_int/esw/triumph2.h>
     30 #endif
     31 #include <bcm_int/esw/virtual.h>
     32 #include <bcm_int/esw/xgs3.h>
     33 #include <bcm_int/common/multicast.h>
     34 #include <bcm_int/esw/multicast.h>
     35 #include <bcm_int/esw/trx.h>
     36 #include <bcm_int/esw/ipmc.h>
     37 #include <bcm_int/esw/virtual.h>
     38 #include <bcm_int/esw/switch.h>
     39 #include <bcm_int/esw/stack.h>
     40 #include <bcm_int/api_xlate_port.h>
     41 #include <bcm_int/esw_dispatch.h>
     42 #ifdef BCM_TRIDENT_SUPPORT
     43 #include <bcm_int/esw/trill.h>
     44 #include <bcm_int/esw/trident.h>
     45 #endif /* BCM_TRIDENT_SUPPORT */
     46 #ifdef BCM_TRIDENT2_SUPPORT
     47 #include <bcm_int/esw/trident2.h>
     48 #endif /* BCM_TRIDENT2_SUPPORT */
     49 #include <bcm_int/esw/failover.h>
     50 #include <bcm_int/esw/mpls.h>
     51 
     52 uint8 *_multicast_ipmc_group_types[BCM_MAX_NUM_UNITS];
     53 uint8 *bcmi_multicast_multi_group_count[BCM_MAX_NUM_UNITS];
     54 
     55 /*
     56  * Function:
     57  *      bcmi_multicast_multi_count_set
     58  * Purpose:
     59  *      Record count for Multicast objects at this id.
     60  * Parameters:
     61  *      unit  - (IN)  StrataSwitch unit number.
     62  *      group - (IN)  multicast group number
     63  *      count - (OUT) no of elements
     64  * Returns:
     65  *      BCM_E_XXX
     66  */
     67 int
     68 bcmi_multicast_multi_count_set(int unit, bcm_multicast_t group,
     69                                int count)
     70 {
     71     uint32 ipmc_id = _BCM_MULTICAST_ID_GET(group);
     72 
     73     if (bcmi_multicast_multi_group_count[unit] == NULL) {
     74         return BCM_E_INIT;
     75     }
     76 
     77     bcmi_multicast_multi_group_count[unit][ipmc_id] = count;
     78 
     79     return BCM_E_NONE;
     80 }
     81 
     82 /*
     83  * Function:
     84  *      bcmi_multicast_multi_count_get
     85  * Purpose:
     86  *      Retrieve count for Multicast objects at this id.
     87  * Parameters:
     88  *      unit  - (IN)  StrataSwitch unit number.
     89  *      group - (IN)  multicast group number
     90  *      count - (OUT) no of elements
     91  * Returns:
     92  *      BCM_E_XXX
     93  */
     94 int
     95 bcmi_multicast_multi_count_get(int unit, bcm_multicast_t group,
     96                                           int *count)
     97 {
     98     uint32 ipmc_id = _BCM_MULTICAST_ID_GET(group);
     99 
    100     if (bcmi_multicast_multi_group_count[unit] == NULL) {
    101         return BCM_E_INIT;
    102     }
    103  
    104     *count = bcmi_multicast_multi_group_count[unit][ipmc_id];
    105     return BCM_E_NONE;
    106 }
    107 
    108 
    109 int
    110 _bcm_tr_multicast_ipmc_group_type_set(int unit, bcm_multicast_t group)
    111 {
    112     uint8 group_type = _BCM_MULTICAST_TYPE_GET(group);
    113     uint32 ipmc_id = _BCM_MULTICAST_ID_GET(group);
    114 
    115     /* Don't check if MULTICAST_GROUP_IS_SET because we also want to
    116      * be able to clear a group. */
    117 
    118     if ((_BCM_MULTICAST_TYPE_L2 != group_type)) {
    119         if ((ipmc_id < soc_mem_index_min(unit, L3_IPMCm)) ||
    120             (ipmc_id > soc_mem_index_max(unit, L3_IPMCm))) {
    121             return BCM_E_PARAM;
    122         }
    123 
    124         /* It's an IPMC type group */
    125         _multicast_ipmc_group_types[unit][ipmc_id] = group_type;
    126 
    127 #ifdef BCM_WARM_BOOT_SUPPORT
    128         SOC_CONTROL_LOCK(unit);
    129         SOC_CONTROL(unit)->scache_dirty = 1;
    130         SOC_CONTROL_UNLOCK(unit);
    131 #endif
    132     }
    133 
    134     return BCM_E_NONE;
    135 }
    136 
    137 int
    138 _bcm_tr_multicast_ipmc_group_type_get(int unit, uint32 ipmc_id,
    139                                       bcm_multicast_t *group)
    140 {
    141     if (SOC_IS_XGS3_FABRIC(unit)) {
    142         /* _multicast_ipmc_group_types not initialized for fabric chips. */
    143         *group = 0;
    144         return BCM_E_NOT_FOUND;
    145     }
    146 
    147     if (ipmc_id >= soc_mem_index_count(unit, L3_IPMCm)) {
    148         *group = 0;
    149         return BCM_E_NOT_FOUND;
    150     }
    151 
    152     if ((NULL != _multicast_ipmc_group_types[unit]) && /* Verify init */
    153         (0 != _multicast_ipmc_group_types[unit][ipmc_id])) {
    154         _BCM_MULTICAST_GROUP_SET(*group,
    155                                  _multicast_ipmc_group_types[unit][ipmc_id],
    156                                  ipmc_id);
    157         return BCM_E_NONE;
    158     } else {
    159         *group = 0;
    160         return BCM_E_NOT_FOUND;
    161     }
    162 }
    163 
    164 #ifdef BCM_WARM_BOOT_SUPPORT
    165 
    166 #define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
    167 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1,0)
    168 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_1
    169 
    170 /*
    171  * Function:
    172  *      _bcm_trx_multicast_sync
    173  * Purpose:
    174  *      Record Multicast module persisitent info for Level 2 Warm Boot
    175  * Parameters:
    176  *      unit - StrataSwitch unit number.
    177  * Returns:
    178  *      BCM_E_XXX
    179  */
    180 int
    181 _bcm_trx_multicast_sync(int unit)
    182 {
    183     int ipmc_mem_size, alloc_size=0;
    184     soc_scache_handle_t scache_handle;
    185     uint8               *multicast_scache;
    186 
    187     if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    188         return BCM_E_NONE;
    189     }
    190     ipmc_mem_size = soc_mem_index_count(unit, L3_IPMCm);
    191     alloc_size = ipmc_mem_size * sizeof(uint8);
    192     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
    193         if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_1) {
    194             alloc_size += ipmc_mem_size * sizeof(uint8);
    195         }
    196     }
    197 
    198     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_MULTICAST, 0);
    199     BCM_IF_ERROR_RETURN
    200         (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
    201                                  alloc_size,
    202                                  &multicast_scache, 
    203                                  BCM_WB_DEFAULT_VERSION, NULL));
    204     /* reset alloc size */
    205     alloc_size = ipmc_mem_size * sizeof(uint8);
    206     if (_multicast_ipmc_group_types[unit] != NULL) {
    207         sal_memcpy(multicast_scache, _multicast_ipmc_group_types[unit],
    208                    alloc_size);
    209         multicast_scache += alloc_size;
    210     }
    211     
    212     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
    213         if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_1) {
    214             sal_memcpy(multicast_scache, bcmi_multicast_multi_group_count[unit],
    215                     alloc_size);
    216             multicast_scache += alloc_size;
    217         }
    218     }
    219 
    220     return BCM_E_NONE;
    221 }
    222 
    223 typedef struct _bcm_esw_multicast_cb_info_s {
    224     uint32 flags;
    225     SHR_BITDCL *ipmc_groups_bits;
    226     int stale_scache;
    227 } _bcm_multicast_cb_info_t;
    228 
    229 /*
    230  * Function:
    231  *      _bcm_trx_multicast_reinit_group
    232  * Purpose:
    233  *      Parse multicast group type and reinitialize the internal structure.
    234  * Parameters:
    235  *      unit      - (IN) Device Number
    236  *      group     - (IN) Multicast group ID
    237  *      mc_cb_info - (IN) data structure pointer passed via the traverse
    238  * Returns:
    239  *      BCM_E_XXX
    240  */
    241 STATIC int
    242 _bcm_trx_multicast_reinit_group(int unit, bcm_multicast_t group,
    243                                 _bcm_multicast_cb_info_t *mc_cb_info)
    244 {
    245     int rv, mc_index;
    246     uint32 group_flags;
    247     uint8 group_type;
    248     bcm_multicast_t scache_group;
    249 
    250     mc_index = _BCM_MULTICAST_ID_GET(group);
    251 
    252     if (SHR_BITGET(mc_cb_info->ipmc_groups_bits, mc_index)) {
    253         /* Already did this group index, skip */
    254         return BCM_E_NONE;
    255     }
    256 
    257     group_type = _BCM_MULTICAST_TYPE_GET(group);
    258 
    259     if (_BCM_MULTICAST_TYPE_L2 == group_type) {
    260         /* This shouldn't happen */
    261         return BCM_E_INTERNAL;
    262     }
    263 
    264     rv  = _bcm_tr_multicast_ipmc_group_type_get(unit, mc_index,
    265                                                 &scache_group);
    266 
    267     if (BCM_E_NOT_FOUND == rv) {
    268         /* Normal operation at UNCACHED Warm Boot */
    269     } else if (BCM_FAILURE(rv)) {
    270         return rv;
    271     } else if (scache_group != group) {
    272         if (FALSE == mc_cb_info->stale_scache) {
    273             if (_BCM_MULTICAST_TYPE_L3 != group_type) {
    274                 /* We have Level 2 info which tells us it isn't,
    275                  * L3 type, so go with the saved info. */
    276             } else {
    277                 /* Stale scache for Warm Boot */
    278                 /* We haven't yet complained about the stale scache */
    279                 SOC_IF_ERROR_RETURN
    280                     (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR, 
    281                                         SOC_STABLE_STALE,
    282                                         SOC_STABLE_MULTICAST, 0));
    283                 mc_cb_info->stale_scache = TRUE;
    284             }
    285         } /* Else, record this as L3 type */
    286     } else {
    287         /* Synchronized scache from Warm Boot Level 2.  Nothing to do */
    288         return BCM_E_NONE;
    289     }
    290 
    291     group_flags = _bcm_esw_multicast_group_type_to_flags(group_type);
    292     /* We record the used group ID's to determine
    293      * which ones are pure L3. */
    294     SHR_BITSET(mc_cb_info->ipmc_groups_bits, mc_index);
    295 
    296     if (mc_cb_info->flags & group_flags) {
    297         BCM_IF_ERROR_RETURN
    298             (_bcm_tr_multicast_ipmc_group_type_set(unit, group));
    299     } else {
    300         /* We shouldn't have this type of group for this device! */
    301         return BCM_E_INTERNAL;
    302     }
    303 
    304     return BCM_E_NONE;
    305 }
    306 
    307 /*
    308  * Function:
    309  *      _bcm_trx_multicast_l2_traverse
    310  * Purpose:
    311  *      Callback for L2 traverse to parse multicast groups.
    312  * Parameters:
    313  *      unit      - (IN) Device Number
    314  *      info      - (IN) L2 addr data structure, including multicast group
    315  *      user_data - (IN) data structure pointer passed via the traverse
    316  * Returns:
    317  *      BCM_E_XXX
    318  */
    319 STATIC int
    320 _bcm_trx_multicast_l2_traverse(int unit, bcm_l2_addr_t *info, 
    321                                void *user_data)
    322 {
    323     _bcm_multicast_cb_info_t *mc_cb_info =
    324         (_bcm_multicast_cb_info_t *)user_data;
    325     
    326     if (!_BCM_MULTICAST_IS_SET(info->l2mc_group)) {
    327         /* Not interested */
    328         return BCM_E_NONE;
    329     }
    330 
    331     return _bcm_trx_multicast_reinit_group(unit, info->l2mc_group,
    332                                            mc_cb_info);
    333 }
    334 
    335 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
    336 /*
    337  * Function:
    338  *      _bcm_trx_multicast_vlan_traverse
    339  * Purpose:
    340  *      Iterate over VLANs and check for multicast groups.
    341  * Parameters:
    342  *      unit      - (IN) Device Number
    343  *      mc_cb_info - (IN) data structure pointer passed via the traverse
    344  * Returns:
    345  *      BCM_E_XXX
    346  */
    347 STATIC int
    348 _bcm_trx_multicast_vlan_traverse(int unit,
    349                                   _bcm_multicast_cb_info_t *mc_cb_info)
    350 {
    351     bcm_vlan_t vlan;
    352     int rv;
    353     bcm_vlan_control_vlan_t control;
    354 
    355     for (vlan = BCM_VLAN_MIN; vlan < BCM_VLAN_COUNT; vlan++) {
    356         rv = bcm_esw_vlan_control_vlan_get(unit, vlan, &control);
    357         if (BCM_E_PARAM == rv) {
    358             /* VLAN isn't created, skip onward */
    359             continue;
    360         } else if (BCM_FAILURE(rv)) {
    361             return rv;
    362         } else {
    363             /* Found a VLAN, check it's parameters */
    364             if (_BCM_MULTICAST_IS_SET(control.broadcast_group)) {
    365                 BCM_IF_ERROR_RETURN
    366                     (_bcm_trx_multicast_reinit_group(unit,
    367                               control.broadcast_group, mc_cb_info));
    368             }
    369             if (_BCM_MULTICAST_IS_SET(control.unknown_multicast_group)) {
    370                 BCM_IF_ERROR_RETURN
    371                     (_bcm_trx_multicast_reinit_group(unit,
    372                               control.unknown_multicast_group, mc_cb_info));
    373             }
    374             if (_BCM_MULTICAST_IS_SET(control.unknown_unicast_group)) {
    375                 BCM_IF_ERROR_RETURN
    376                     (_bcm_trx_multicast_reinit_group(unit,
    377                               control.unknown_unicast_group, mc_cb_info));
    378             }
    379         }
    380     }
    381 
    382     return BCM_E_NONE;
    383 }
    384 #endif
    385 
    386 /*
    387  * Function:
    388  *      _bcm_trx_multicast_vfi_traverse
    389  * Purpose:
    390  *      Iterate over VFIs and check for multicast groups.
    391  * Parameters:
    392  *      unit      - (IN) Device Number
    393  *      mc_cb_info - (IN) data structure pointer passed via the traverse
    394  * Returns:
    395  *      BCM_E_XXX
    396  */
    397 STATIC int
    398 _bcm_trx_multicast_vfi_traverse(int unit,
    399                                 _bcm_multicast_cb_info_t *mc_cb_info)
    400 {
    401     int vfi, num_vfi;
    402     int mc_index;
    403     uint32 multicast_type;
    404     bcm_multicast_t group;
    405     int rv = BCM_E_NONE;
    406     char *vfi_tbl_ptr = NULL;      /* Table dma pointer. */
    407     void *vfi_entry_ptr = NULL; /* VFI Profile entry buffer pointer.*/
    408     vfi_entry_t vfi_entry;
    409 
    410     if (!SOC_MEM_IS_VALID(unit,VFIm)) {
    411        /* if (SOC_IS_HURRICANE(unit))  */
    412        return BCM_E_NONE;
    413     }
    414 
    415     num_vfi = soc_mem_index_count(unit, VFIm);
    416     rv = bcm_xgs3_l3_tbl_dma(unit, VFIm,
    417                              sizeof(vfi_entry_t),
    418                              "vfi", &vfi_tbl_ptr, NULL);
    419     if (BCM_FAILURE(rv)) {
    420         vfi_tbl_ptr = NULL;
    421     }
    422     for (vfi = 0; vfi < num_vfi; vfi++) {
    423         if (_bcm_vfi_used_get(unit, vfi, _bcmVfiTypeMpls)) {
    424             multicast_type = _BCM_MULTICAST_TYPE_VPLS;
    425 #ifdef BCM_TRIUMPH2_SUPPORT
    426         } else if (_bcm_vfi_used_get(unit, vfi, _bcmVfiTypeMim)) {
    427             multicast_type = _BCM_MULTICAST_TYPE_MIM;
    428 #endif
    429         } else {
    430             /* Not a VFI we're interested in */
    431             continue;
    432         }
    433         if (vfi_tbl_ptr == NULL) {
    434             vfi_entry_ptr = (vfi_entry_t *)&vfi_entry;
    435             sal_memcpy(vfi_entry_ptr, soc_mem_entry_null(unit, VFIm), 
    436                        soc_mem_entry_words(unit, VFIm) * 4);
    437             BCM_IF_ERROR_RETURN(
    438                 READ_VFIm(unit, MEM_BLOCK_ALL, vfi, vfi_entry_ptr));
    439         } else {
    440             vfi_entry_ptr =
    441                 soc_mem_table_idx_to_pointer(unit, VFIm, uint32 *,
    442                                              vfi_tbl_ptr, vfi);
    443             /* coverity[var_deref_model : FALSE] */
    444         }
    445 #ifdef BCM_TRIUMPH2_SUPPORT
    446         if (soc_feature(unit, soc_feature_mpls_enhanced)) {
    447             mc_index = soc_VFIm_field32_get(unit, vfi_entry_ptr, BC_INDEXf);
    448             _BCM_MULTICAST_GROUP_SET(group, multicast_type, mc_index);
    449             rv = _bcm_trx_multicast_reinit_group(unit, group, mc_cb_info);
    450             if (BCM_FAILURE(rv)) {
    451                 goto cleanup;
    452             }  
    453             mc_index = soc_VFIm_field32_get(unit, vfi_entry_ptr, UUC_INDEXf);
    454             _BCM_MULTICAST_GROUP_SET(group, multicast_type, mc_index);
    455             rv = _bcm_trx_multicast_reinit_group(unit, group, mc_cb_info);
    456             if (BCM_FAILURE(rv)) {
    457                 goto cleanup;
    458             }  
    459             mc_index = soc_VFIm_field32_get(unit, vfi_entry_ptr, UMC_INDEXf);
    460             _BCM_MULTICAST_GROUP_SET(group, multicast_type, mc_index);
    461             rv = _bcm_trx_multicast_reinit_group(unit, group, mc_cb_info);
    462             if (BCM_FAILURE(rv)) {
    463                 goto cleanup;
    464             }              
    465         } else
    466 #endif
    467         {
    468             mc_index = soc_VFIm_field32_get(unit, vfi_entry_ptr, L3MC_INDEXf);
    469             _BCM_MULTICAST_GROUP_SET(group, multicast_type, mc_index);
    470             rv = _bcm_trx_multicast_reinit_group(unit, group, mc_cb_info);
    471             if (BCM_FAILURE(rv)) {
    472                 goto cleanup;
    473             }              
    474         }
    475     }
    476 cleanup:
    477     if (vfi_tbl_ptr) {
    478         soc_cm_sfree(unit, vfi_tbl_ptr);
    479     }
    480     return rv;
    481 }
    482 
    483 /*
    484  * Function:
    485  *      _bcm_trx_multicast_reinit
    486  * Purpose:
    487  *      Recover Multicast module state for Warm Boot
    488  * Parameters:
    489  *      unit - StrataSwitch unit number.
    490  * Returns:
    491  *      BCM_E_XXX
    492  */
    493 STATIC int
    494 _bcm_trx_multicast_reinit(int unit)
    495 {
    496     int mem_size=0, mc_index, is_set, rv = BCM_E_NONE;
    497     int alloc_size = 0;
    498     soc_scache_handle_t scache_handle;
    499     bcm_multicast_t group, scache_group;
    500     SHR_BITDCL *ipmc_groups_bits = NULL;
    501     uint8               *multicast_scache;
    502     _bcm_multicast_cb_info_t mc_cb_info;
    503     int num_ipmc_groups;
    504 
    505     /* L3 IPMC info may use scache info */
    506     mem_size = soc_mem_index_count(unit, L3_IPMCm);
    507 
    508     num_ipmc_groups = mem_size;
    509 #if defined(BCM_TRIUMPH3_SUPPORT) 
    510     if (soc_feature(unit, soc_feature_static_repl_head_alloc)) {
    511         soc_info_t *si;
    512         int member_count;
    513         int port, phy_port, mmu_port;
    514         /* Each replication group is statically allocated a region
    515          * in REPL_HEAD table. The size of the region depends on the
    516          * maximum number of valid ports. Thus, the max number of
    517          * replication groups is limited to number of REPL_HEAD entries
    518          * divided by the max number of valid ports.
    519          */
    520         si = &SOC_INFO(unit);
    521         member_count = 0;
    522         PBMP_ITER(SOC_CONTROL(unit)->repl_eligible_pbmp, port) {
    523             phy_port = si->port_l2p_mapping[port];
    524             mmu_port = si->port_p2m_mapping[phy_port];
    525             if ((mmu_port == 57) || (mmu_port == 59) || (mmu_port == 62)) {
    526                 /* No replication on MMU ports 57, 59, and 62 */
    527                 continue;
    528             }
    529             member_count++;
    530         }
    531         if (member_count > 0) {
    532             num_ipmc_groups = soc_mem_index_count(unit, MMU_REPL_HEAD_TBLm) /
    533                 member_count;
    534             if (num_ipmc_groups > mem_size) {
    535                 num_ipmc_groups = mem_size;
    536             }
    537         }
    538     }
    539 #endif /* BCM_TRIUMPH3_SUPPORT */
    540 
    541     alloc_size = mem_size * sizeof(uint8);
    542 
    543     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
    544         if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_1) {
    545             alloc_size += mem_size * sizeof(uint8);
    546         }
    547     }
    548 
    549     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_MULTICAST, 0);
    550     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
    551                                  alloc_size, &multicast_scache,
    552                                  BCM_WB_DEFAULT_VERSION, NULL);
    553 
    554     if (BCM_E_NOT_FOUND == rv) {
    555         multicast_scache = NULL;
    556     } else if (BCM_FAILURE(rv)) {
    557         return rv;
    558     } else {
    559         alloc_size = mem_size * sizeof(uint8);
    560         sal_memcpy(_multicast_ipmc_group_types[unit], multicast_scache,
    561                    alloc_size);
    562         multicast_scache += alloc_size;
    563         if (soc_feature(unit, soc_feature_hierarchical_protection)) {
    564             if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_1) {
    565                 sal_memcpy(bcmi_multicast_multi_group_count[unit],
    566                         multicast_scache, alloc_size);
    567                 multicast_scache += alloc_size;
    568             }
    569         }
    570         
    571         for (mc_index = 0; mc_index < num_ipmc_groups; mc_index++) {
    572             rv  = _bcm_tr_multicast_ipmc_group_type_get(
    573                       unit, mc_index, &scache_group);
    574             if (BCM_FAILURE(rv)) {
    575                 if (rv == BCM_E_NOT_FOUND) {
    576                     continue;
    577                 }
    578                 bcm_fb_ipmc_repl_detach(unit);
    579                 return rv;
    580             }
    581            
    582             rv = bcm_xgs3_ipmc_id_is_set(unit, mc_index, &is_set);
    583             if (BCM_SUCCESS(rv)) {
    584                  if (_BCM_MULTICAST_IS_L3(scache_group) && (!is_set)) {
    585                     /* This is an L3 group that was created but
    586                      * not installed, so there is no HW sign of it.
    587                      * We need to mark it recovered in the IPMC area.
    588                      */
    589                     rv = bcm_xgs3_ipmc_id_alloc(unit, mc_index);
    590                     if (BCM_FAILURE(rv)) {
    591                         bcm_fb_ipmc_repl_detach(unit);
    592                         return rv;
    593                     }
    594                 }
    595             }
    596         }
    597 
    598         return BCM_E_NONE;
    599     }
    600 
    601     /* Traversing multiple next hop types, set up IPMC repl logging */
    602     alloc_size = SHR_BITALLOCSIZE(mem_size);
    603     ipmc_groups_bits = sal_alloc(alloc_size, "IPMC groups referenced");
    604     if (ipmc_groups_bits == NULL) {
    605         bcm_fb_ipmc_repl_detach(unit);
    606         return BCM_E_MEMORY;
    607     }
    608     sal_memset(ipmc_groups_bits, 0, alloc_size);    
    609 
    610     /* Store info for callback functions */
    611     mc_cb_info.ipmc_groups_bits = ipmc_groups_bits;        
    612     mc_cb_info.stale_scache = FALSE;
    613 
    614     mc_cb_info.flags = BCM_MULTICAST_TYPE_L3;
    615 
    616     if (soc_feature(unit, soc_feature_mpls)) {
    617         mc_cb_info.flags |= BCM_MULTICAST_TYPE_VPLS;
    618     }
    619     if (soc_feature(unit, soc_feature_subport)) {
    620         mc_cb_info.flags |= BCM_MULTICAST_TYPE_SUBPORT;
    621     }
    622     if (soc_feature(unit, soc_feature_mim)) {
    623         mc_cb_info.flags |= BCM_MULTICAST_TYPE_MIM;
    624     }
    625     if (soc_feature(unit, soc_feature_wlan)) {
    626         mc_cb_info.flags |= BCM_MULTICAST_TYPE_WLAN;
    627     }
    628     if (soc_feature(unit, soc_feature_vlan_vp)) {
    629         mc_cb_info.flags |= BCM_MULTICAST_TYPE_VLAN;
    630     }
    631     if (soc_feature(unit, soc_feature_trill)) {
    632         mc_cb_info.flags |= BCM_MULTICAST_TYPE_TRILL;
    633     }
    634     if (soc_feature(unit, soc_feature_niv)) {
    635         mc_cb_info.flags |= BCM_MULTICAST_TYPE_NIV;
    636     }
    637     if (soc_feature(unit, soc_feature_mpls)) {
    638         mc_cb_info.flags |= BCM_MULTICAST_TYPE_EGRESS_OBJECT;
    639     }
    640     if (soc_feature(unit, soc_feature_port_extension)) {
    641         mc_cb_info.flags |= BCM_MULTICAST_TYPE_EXTENDER;
    642     }
    643 
    644     /* Traverse L2 table for multicast groups */
    645     rv = bcm_esw_l2_traverse(unit, &_bcm_trx_multicast_l2_traverse,
    646                              &mc_cb_info);
    647 
    648 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
    649     /* Traverse VLAN MC groups */
    650     if (BCM_SUCCESS(rv) && (soc_feature(unit, soc_feature_wlan) ||
    651                 soc_feature(unit, soc_feature_vlan_vp) ||
    652                 soc_feature(unit, soc_feature_trill) ||
    653                 soc_feature(unit, soc_feature_niv) ||
    654                 soc_feature(unit, soc_feature_port_extension))) {
    655         rv = _bcm_trx_multicast_vlan_traverse(unit, &mc_cb_info);
    656     }
    657 #endif
    658 
    659     /* Traverse VFI groups */
    660     if (BCM_SUCCESS(rv)) {
    661         if (soc_feature(unit, soc_feature_virtual_switching)) {
    662             rv = _bcm_trx_multicast_vfi_traverse(unit, &mc_cb_info);
    663         }
    664     }
    665 
    666     if (BCM_SUCCESS(rv)) {
    667         for (mc_index = 0; mc_index < num_ipmc_groups; mc_index++) {
    668             if (SHR_BITGET(ipmc_groups_bits, mc_index)) {
    669                 /* Already did this group index, skip */
    670                 continue;
    671             }
    672 
    673             rv = bcm_xgs3_ipmc_id_is_set(unit, mc_index, &is_set);
    674             if ((BCM_E_INIT == rv) || (BCM_E_UNAVAIL == rv)) {
    675                 
    676                 rv = BCM_E_NONE;
    677                 break;
    678             } else if (BCM_FAILURE(rv)) {
    679                 break;
    680             } else if (is_set) {
    681                 /* coverity[dead_error_condition] */
    682                 if (NULL != multicast_scache) {
    683                     /* If scache was used, check for staleness */
    684                     rv  = _bcm_tr_multicast_ipmc_group_type_get(unit,
    685                                             mc_index, &scache_group);
    686 
    687                     if (BCM_E_NOT_FOUND == rv) {
    688 #ifdef BCM_KATANA_SUPPORT
    689                         if (SOC_IS_KATANAX(unit) &&
    690                             ((mc_index == 0) || (mc_index == 1))) {
    691                             continue; 
    692                         }
    693 #endif /* BCM_KATANA_SUPPORT */
    694 #ifdef BCM_XGS3_SWITCH_SUPPORT
    695                         if (SOC_IS_XGS3_SWITCH(unit) &&
    696                             !(SOC_IS_KATANAX(unit)) && mc_index == 0) {
    697                             continue;
    698                         }
    699 #endif /* BCM_XGS3_SWITCH_SUPPORT */   
    700 
    701                         /* We expect a group from the HW state, but
    702                          * it isn't in the scache info */
    703                         if (FALSE == mc_cb_info.stale_scache) {
    704                             /* We have yet to complain about stale scache */
    705                             rv = soc_event_generate(unit,
    706                                            BCM_SWITCH_EVENT_STABLE_ERROR, 
    707                                                     SOC_STABLE_STALE,
    708                                                     SOC_STABLE_MULTICAST, 0);
    709                             if (BCM_FAILURE(rv)) {
    710                                 break;
    711                             }
    712                             mc_cb_info.stale_scache = TRUE;
    713                         }
    714                     } else if (BCM_FAILURE(rv)) {
    715                         return rv;
    716                     } /* Keep the cached group info and continue */
    717                 } else {
    718                     /* Best guess is that this is an L3 group */
    719                     _BCM_MULTICAST_GROUP_SET(group, 
    720                                              _BCM_MULTICAST_TYPE_L3,
    721                                              mc_index);
    722                     rv = _bcm_trx_multicast_reinit_group(unit, group,
    723                                                          &mc_cb_info);
    724                     if (BCM_FAILURE(rv)) {
    725                         break;
    726                     }
    727                 }
    728             } else if (NULL != multicast_scache) {
    729                 /* If scache was used, check for staleness */
    730                 rv  = _bcm_tr_multicast_ipmc_group_type_get(unit, mc_index,
    731                                                             &scache_group);
    732 
    733                 if (BCM_E_NOT_FOUND == rv) {
    734                     /* In sync */
    735                     rv = BCM_E_NONE;
    736                 } else if (BCM_FAILURE(rv)) {
    737                     return rv;
    738                 } else if (0 != scache_group) {
    739                     if (!_BCM_MULTICAST_IS_L3(scache_group)) {
    740                         /* We expect a group from the scache info, but
    741                          * it wasn't recovered from HW. */
    742                         if (FALSE == mc_cb_info.stale_scache) {
    743                             /* We have yet to complain about stale scache */
    744                             rv = soc_event_generate(unit,
    745                                            BCM_SWITCH_EVENT_STABLE_ERROR, 
    746                                                     SOC_STABLE_STALE,
    747                                                     SOC_STABLE_MULTICAST, 0);
    748                             if (BCM_FAILURE(rv)) {
    749                                 break;
    750                             }
    751                             mc_cb_info.stale_scache = TRUE;
    752                         }
    753                     } else {
    754                         /* This is an L3 group that was created but
    755                          * not installed, so there is no HW sign of it.
    756                          * We need to mark it recovered in the IPMC area.
    757                          */
    758                         rv = bcm_xgs3_ipmc_id_alloc(unit, mc_index);
    759                         if (BCM_FAILURE(rv)) {
    760                             break;
    761                         }
    762                     }
    763                 }
    764             }
    765         }
    766     }
    767 
    768     sal_free(ipmc_groups_bits);
    769 
    770     return rv;
    771 }
    772 #endif /* BCM_WARM_BOOT_SUPPORT */
    773 
    774 /*
    775  * Function:
    776  *      bcm_trx_multicast_init
    777  * Purpose:
    778  *      Initialize the multicast module.
    779  * Parameters:
    780  *      unit - (IN) Unit number.
    781  * Returns:
    782  *      BCM_E_xxx
    783  * Notes:
    784  */
    785 int 
    786 bcm_trx_multicast_init(int unit)
    787 {
    788     int ipmc_mem_size=0, alloc_size=0;
    789 #ifdef BCM_WARM_BOOT_SUPPORT
    790     int rv = BCM_E_NONE;
    791     soc_scache_handle_t scache_handle;
    792     uint8               *multicast_scache;
    793 #endif /* BCM_WARM_BOOT_SUPPORT */
    794 
    795     ipmc_mem_size = soc_mem_index_count(unit, L3_IPMCm);
    796     alloc_size = ipmc_mem_size * sizeof(uint8);
    797 
    798 #ifdef BCM_WARM_BOOT_SUPPORT
    799     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
    800         if (BCM_WB_DEFAULT_VERSION >= BCM_WB_VERSION_1_1) {
    801             alloc_size += ipmc_mem_size * sizeof(uint8);
    802         }
    803     }
    804 
    805 
    806     if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    807         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_MULTICAST, 0);
    808         rv = _bcm_esw_scache_ptr_get(unit, scache_handle,
    809                                      (0 == SOC_WARM_BOOT(unit)),
    810                                      alloc_size,
    811                                      &multicast_scache, 
    812                                      BCM_WB_DEFAULT_VERSION, NULL);
    813         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
    814             return rv;
    815         }
    816     } /* Else, not enough memory, don't allocate scache */
    817 #endif /* BCM_WARM_BOOT_SUPPORT */
    818 
    819     /* change alloc size for individual memebers in scache */
    820     alloc_size = ipmc_mem_size * sizeof(uint8);
    821 
    822     if (NULL == _multicast_ipmc_group_types[unit]) {
    823         _multicast_ipmc_group_types[unit] =
    824             sal_alloc(alloc_size, "multicast_group_types");
    825         if (NULL == _multicast_ipmc_group_types[unit]) {
    826             return BCM_E_MEMORY;
    827         }
    828     }
    829     sal_memset(_multicast_ipmc_group_types[unit], 0, alloc_size);
    830 
    831     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
    832         if (NULL == bcmi_multicast_multi_group_count[unit]) {
    833             bcmi_multicast_multi_group_count[unit] =
    834                 sal_alloc(alloc_size, "multicast_group_count");
    835             if (NULL == bcmi_multicast_multi_group_count[unit]) {
    836                 return BCM_E_MEMORY;
    837             }
    838         }
    839         sal_memset(bcmi_multicast_multi_group_count[unit], 0, alloc_size);
    840     }
    841 
    842 
    843 #ifdef BCM_TRIDENT2_SUPPORT
    844     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
    845         BCM_IF_ERROR_RETURN(bcm_td2_multicast_l3_vp_init(unit));
    846     }
    847 #endif /* BCM_TRIDENT2_SUPPORT */
    848 
    849 #ifdef BCM_WARM_BOOT_SUPPORT
    850     if (SOC_WARM_BOOT(unit)) {
    851         return (_bcm_trx_multicast_reinit(unit));
    852     }
    853 #endif /* BCM_WARM_BOOT_SUPPORT */
    854 
    855     return BCM_E_NONE;
    856 }
    857 
    858 /*
    859  * Function:
    860  *      bcm_trx_multicast_detach
    861  * Purpose:
    862  *      Shut down (uninitialize) the multicast module.
    863  * Parameters:
    864  *      unit - (IN) Unit number.
    865  * Returns:
    866  *      BCM_E_xxx
    867  * Notes:
    868  */
    869 int 
    870 bcm_trx_multicast_detach(int unit)
    871 {
    872 
    873 #ifdef BCM_WARM_BOOT_SUPPORT
    874     int autosync;
    875     BCM_IF_ERROR_RETURN(
    876         bcm_esw_switch_control_get(unit, bcmSwitchControlAutoSync, &autosync));
    877     if (autosync) {
    878         BCM_IF_ERROR_RETURN(_bcm_trx_multicast_sync(unit));
    879     }
    880 #endif /* BCM_WARM_BOOT_SUPPORT */
    881 #ifdef BCM_TRIDENT2_SUPPORT
    882     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
    883         BCM_IF_ERROR_RETURN(bcm_td2_multicast_l3_vp_detach(unit));
    884     }
    885 #endif /* BCM_TRIDENT2_SUPPORT */
    886     
    887     if (NULL != _multicast_ipmc_group_types[unit]) {
    888         sal_free(_multicast_ipmc_group_types[unit]);
    889         _multicast_ipmc_group_types[unit] = NULL;
    890     }
    891 
    892     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
    893         if (NULL != bcmi_multicast_multi_group_count[unit]) {
    894             sal_free(bcmi_multicast_multi_group_count[unit]);
    895             bcmi_multicast_multi_group_count[unit] = NULL;
    896         }
    897     }
    898 
    899     return BCM_E_NONE;
    900 }
    901 
    902 /*
    903  * Function:
    904  *      bcm_multicast_vpls_encap_get
    905  * Purpose:
    906  *      Get the Encap ID for a MPLS port.
    907  * Parameters:
    908  *      unit         - (IN) Unit number.
    909  *      group        - (IN) Multicast group ID.
    910  *      port         - (IN) Physical port.
    911  *      mpls_port_id - (IN) MPLS port ID.
    912  *      encap_id     - (OUT) Encap ID.
    913  * Returns:
    914  *      BCM_E_XXX
    915  * Notes:
    916  */
    917 int
    918 bcm_tr_multicast_vpls_encap_get(int unit, bcm_multicast_t group,
    919                                 bcm_gport_t port,
    920                                 bcm_gport_t mpls_port_id, bcm_if_t *encap_id)
    921 {
    922 #if defined(BCM_MPLS_SUPPORT) 
    923     uint32 vp;
    924     ing_dvp_table_entry_t dvp;
    925     int vpless_failover_port = FALSE;
    926     int rv = BCM_E_NONE;
    927 
    928     if (!BCM_GPORT_IS_MPLS_PORT(mpls_port_id)) {
    929         return BCM_E_PARAM;
    930     }
    931     if (_BCM_MPLS_GPORT_FAILOVER_VPLESS_GET(mpls_port_id)) {
    932         vpless_failover_port = TRUE;
    933         mpls_port_id = _BCM_MPLS_GPORT_FAILOVER_VPLESS_CLEAR(mpls_port_id);
    934     }
    935 
    936     vp = BCM_GPORT_MPLS_PORT_ID_GET(mpls_port_id); 
    937     if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
    938         return BCM_E_PARAM;
    939     }
    940     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)) {
    941             return BCM_E_PARAM;
    942     }
    943     BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
    944 
    945     /* Next-hop index is used for multicast replication */
    946     *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    947     if (vpless_failover_port == TRUE) {
    948         int failover_nh_index=0;
    949         int failover_id =0;
    950         int failover_mc_group=0;
    951 
    952         rv = _bcm_esw_failover_prot_nhi_get (unit, *encap_id,
    953               &failover_id, &failover_nh_index, &failover_mc_group);
    954         if (BCM_SUCCESS(rv)) {
    955             if (failover_nh_index) {
    956             *encap_id = failover_nh_index;
    957             }
    958             /*For 1+1 protection NHI use failover multicast group index*/
    959             if(failover_mc_group > 0){
    960                 rv = _bcm_tr_mpls_vpless_failover_nh_index_find(unit,vp,
    961                                              *encap_id, &failover_nh_index);
    962                 if (BCM_SUCCESS(rv)) {
    963                     *encap_id = failover_nh_index;
    964                 }
    965             }
    966         } else if (rv == BCM_E_UNAVAIL) {
    967             if (soc_feature(unit, soc_feature_mpls_software_failover)) {
    968                 rv = _bcm_tr_mpls_vpless_failover_nh_index_find(unit,vp,
    969                                *encap_id, &failover_nh_index);
    970                 if (BCM_SUCCESS(rv)) {
    971                     *encap_id = failover_nh_index;
    972                 }
    973             }
    974         }
    975     }
    976     return rv;
    977 #else
    978     return BCM_E_UNAVAIL;
    979 #endif
    980 }
    981 
    982 /*
    983  * Function:
    984  *      bcm_multicast_subport_encap_get
    985  * Purpose:
    986  *      Get the Encap ID for a subport.
    987  * Parameters:
    988  *      unit      - (IN) Unit number.
    989  *      group     - (IN) Multicast group ID.
    990  *      port      - (IN) Physical port.
    991  *      subport   - (IN) Subport ID.
    992  *      encap_id  - (OUT) Encap ID.
    993  * Returns:
    994  *      BCM_E_XXX
    995  * Notes:
    996  */
    997 int
    998 bcm_tr_multicast_subport_encap_get(int unit, bcm_multicast_t group,
    999                                    bcm_gport_t port,
   1000                                    bcm_gport_t subport, bcm_if_t *encap_id)
   1001 {
   1002     int vp, l3_idx,rv;
   1003     ing_dvp_table_entry_t dvp;
   1004     egr_l3_intf_entry_t l3_intf;
   1005 
   1006     if (!BCM_GPORT_IS_SUBPORT_PORT(subport)) {
   1007         return BCM_E_PARAM;
   1008     }
   1009 
   1010     l3_idx = BCM_GPORT_SUBPORT_PORT_GET(subport) & 0xfff;
   1011     if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 
   1012         return (BCM_E_PARAM);
   1013     }
   1014 
   1015     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1016     BCM_IF_ERROR_RETURN(rv);
   1017 
   1018     vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf);
   1019     if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   1020         return BCM_E_PARAM;
   1021     }
   1022     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeSubport)) {
   1023             return BCM_E_PARAM;
   1024     }
   1025     BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   1026 
   1027     /* Next-hop index is used for multicast replication */
   1028     *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1029     if (!SOC_IS_ENDURO(unit)) {
   1030         *encap_id += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   1031     }
   1032     return BCM_E_NONE;
   1033 
   1034 }
   1035 
   1036 
   1037 /*
   1038  * Function:
   1039  *      bcm_trx_multicast_group_traverse
   1040  * Purpose:
   1041  *      Iterate over the defined multicast groups of the type
   1042  *      specified in 'flags'.  If all types are desired, use
   1043  *      MULTICAST_TYPE_MASK.
   1044  * Parameters:
   1045  *      unit - (IN) Unit number.
   1046  *      trav_fn - (IN) Callback function.
   1047  *      flags - (IN) BCM_MULTICAST_*
   1048  *      user_data - (IN) User data to be passed to callback function.
   1049  * Returns:
   1050  *      BCM_E_XXX
   1051  */
   1052 int
   1053 bcm_trx_multicast_group_traverse(int unit,
   1054                                  bcm_multicast_group_traverse_cb_t trav_fn, 
   1055                                  uint32 flags, void *user_data)
   1056 {
   1057     int l2mc_size, l3mc_size, mc_index, is_set, rv = BCM_E_NONE;
   1058     uint32 group_flags, flags_mask;
   1059     bcm_multicast_t group;
   1060 
   1061     flags_mask = BCM_MULTICAST_TYPE_L2 | BCM_MULTICAST_TYPE_L3;
   1062 
   1063     if (soc_feature(unit, soc_feature_mpls)) {
   1064         flags_mask |= BCM_MULTICAST_TYPE_VPLS;
   1065     }
   1066     if (soc_feature(unit, soc_feature_subport)) {
   1067         flags_mask |= BCM_MULTICAST_TYPE_SUBPORT;
   1068     }
   1069     if (soc_feature(unit, soc_feature_mim)) {
   1070         flags_mask |= BCM_MULTICAST_TYPE_MIM;
   1071     }
   1072     if (soc_feature(unit, soc_feature_wlan)) {
   1073         flags_mask |= BCM_MULTICAST_TYPE_WLAN;
   1074     }
   1075     if (soc_feature(unit, soc_feature_vlan_vp)) {
   1076         flags_mask |= BCM_MULTICAST_TYPE_VLAN;
   1077     }
   1078     if (soc_feature(unit, soc_feature_trill)) {
   1079         flags_mask |= BCM_MULTICAST_TYPE_TRILL;
   1080     }
   1081     if (soc_feature(unit, soc_feature_niv)) {
   1082         flags_mask |= BCM_MULTICAST_TYPE_NIV;
   1083     }
   1084     if (soc_feature(unit, soc_feature_mpls)) {
   1085         flags_mask |= BCM_MULTICAST_TYPE_EGRESS_OBJECT;
   1086     }
   1087     if (soc_feature(unit, soc_feature_port_extension)) {
   1088         flags_mask |= BCM_MULTICAST_TYPE_EXTENDER;
   1089     }
   1090     if (soc_feature(unit, soc_feature_vxlan)) {
   1091         flags_mask |= BCM_MULTICAST_TYPE_VXLAN;
   1092     }
   1093     if (soc_feature(unit, soc_feature_l2gre)) {
   1094         flags_mask |= BCM_MULTICAST_TYPE_L2GRE;
   1095     }
   1096 
   1097     if (0 == (flags & flags_mask)) {
   1098         /* No recognized multicast types to traverse */
   1099         return BCM_E_PARAM;
   1100     }
   1101 
   1102     flags &= flags_mask;
   1103 
   1104     /* Replace the L2 MC logic */
   1105     if (flags & BCM_MULTICAST_TYPE_L2) {
   1106         BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_size_get(unit, &l2mc_size));
   1107         group_flags = BCM_MULTICAST_TYPE_L2 | BCM_MULTICAST_WITH_ID;
   1108 
   1109         for (mc_index = 0; mc_index < l2mc_size; mc_index++) {
   1110             rv = _bcm_xgs3_l2mc_index_is_set(unit, mc_index, &is_set);
   1111             if (BCM_FAILURE(rv)) {
   1112                 return rv;
   1113             } else if (is_set) {
   1114                 _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_L2,
   1115                                          mc_index);
   1116                 BCM_IF_ERROR_RETURN
   1117                     ((*trav_fn)(unit, group, group_flags, user_data));
   1118             }
   1119         }
   1120     }
   1121 
   1122     if (flags & ~(BCM_MULTICAST_TYPE_L2)) {
   1123         l3mc_size = soc_mem_index_count(unit, L3_IPMCm);
   1124         for (mc_index = 0; mc_index < l3mc_size; mc_index++) {
   1125             rv = _bcm_tr_multicast_ipmc_group_type_get(unit, mc_index,
   1126                                                        &group);
   1127 
   1128             if (BCM_E_NOT_FOUND == rv) {
   1129                 continue;
   1130             } else if (BCM_FAILURE(rv)) {
   1131                 return rv;
   1132             } else {
   1133                 group_flags =
   1134                     _bcm_esw_multicast_group_type_to_flags(
   1135                          _BCM_MULTICAST_TYPE_GET(group)) |
   1136                     BCM_MULTICAST_WITH_ID;
   1137 
   1138                 if (group_flags & flags) {
   1139                     BCM_IF_ERROR_RETURN
   1140                         ((*trav_fn)(unit, group, group_flags, user_data));
   1141                 }
   1142             }
   1143         }
   1144     }
   1145 
   1146     return BCM_E_NONE;
   1147 }
   1148 
   1149 /*
   1150  * Function:
   1151  *      bcm_trx_multicast_group_get
   1152  * Purpose:
   1153  *      Retrieve the flags for a multicast group, if it exists.
   1154  * Parameters:
   1155  *      unit       - (IN)   Device Number
   1156  *      group      - (IN)  Group ID
   1157  *      flags      - (OUT)   BCM_MULTICAST_*
   1158  * Returns:
   1159  *      BCM_E_XXX
   1160  */
   1161 int
   1162 bcm_trx_multicast_group_get(int unit, bcm_multicast_t group, uint32 *flags)
   1163 {
   1164     int rv = BCM_E_NONE, mc_index, is_set = FALSE;
   1165     bcm_multicast_t get_group;
   1166 
   1167     mc_index = _BCM_MULTICAST_ID_GET(group);
   1168     if (_BCM_MULTICAST_IS_L2(group)) {
   1169         BCM_IF_ERROR_RETURN
   1170             (_bcm_xgs3_l2mc_index_is_set(unit, mc_index, &is_set));
   1171         if (is_set) {
   1172             *flags |= BCM_MULTICAST_TYPE_L2 | BCM_MULTICAST_WITH_ID;
   1173         } else {
   1174             *flags = 0;
   1175             return BCM_E_NOT_FOUND;
   1176         }
   1177     } else {
   1178         if (!_BCM_MULTICAST_IS_L3(group) &&
   1179             !_BCM_MULTICAST_IS_VPLS(group) && 
   1180             !_BCM_MULTICAST_IS_MIM(group) &&
   1181             !_BCM_MULTICAST_IS_SUBPORT(group) &&
   1182             !_BCM_MULTICAST_IS_WLAN(group) &&
   1183             !_BCM_MULTICAST_IS_VLAN(group) &&
   1184             !_BCM_MULTICAST_IS_TRILL(group) &&
   1185             !_BCM_MULTICAST_IS_NIV(group) &&
   1186             !_BCM_MULTICAST_IS_L2GRE(group) &&
   1187             !_BCM_MULTICAST_IS_VXLAN(group) &&
   1188             !_BCM_MULTICAST_IS_FLOW(group) &&
   1189             !_BCM_MULTICAST_IS_EGRESS_OBJECT(group) &&
   1190             !_BCM_MULTICAST_IS_EXTENDER(group)) {
   1191             return BCM_E_PARAM;
   1192         }
   1193 
   1194         if (_BCM_MULTICAST_IS_VPLS(group) &&
   1195             !soc_feature(unit, soc_feature_mpls)) {
   1196             return BCM_E_UNAVAIL;
   1197         }
   1198         if (_BCM_MULTICAST_IS_SUBPORT(group) &&
   1199             !soc_feature(unit, soc_feature_subport)) {
   1200             return BCM_E_UNAVAIL;
   1201         }
   1202         if (_BCM_MULTICAST_IS_MIM(group) &&
   1203             !soc_feature(unit, soc_feature_mim)) {
   1204             return BCM_E_UNAVAIL;
   1205         }
   1206         if (_BCM_MULTICAST_IS_WLAN(group) &&
   1207             !soc_feature(unit, soc_feature_wlan)) {
   1208             return BCM_E_UNAVAIL;
   1209         }
   1210         if (_BCM_MULTICAST_IS_VLAN(group) &&
   1211             !soc_feature(unit, soc_feature_vlan_vp)) {
   1212             return BCM_E_UNAVAIL;
   1213         }
   1214         if (_BCM_MULTICAST_IS_TRILL(group) &&
   1215             !soc_feature(unit, soc_feature_trill)) {
   1216             return BCM_E_UNAVAIL;
   1217         }
   1218         if (_BCM_MULTICAST_IS_NIV(group) &&
   1219             !soc_feature(unit, soc_feature_niv)) {
   1220             return BCM_E_UNAVAIL;
   1221         }
   1222         if (_BCM_MULTICAST_IS_EGRESS_OBJECT(group) &&
   1223             !soc_feature(unit, soc_feature_mpls)) {
   1224             return BCM_E_UNAVAIL;
   1225         }
   1226         if (_BCM_MULTICAST_IS_L2GRE(group) &&
   1227             !soc_feature(unit, soc_feature_l2gre)) {
   1228             return BCM_E_UNAVAIL;
   1229         }
   1230         if (_BCM_MULTICAST_IS_VXLAN(group) &&
   1231             !soc_feature(unit, soc_feature_vxlan)) {
   1232             return BCM_E_UNAVAIL;
   1233         }
   1234         if (_BCM_MULTICAST_IS_FLOW(group) &&
   1235             !soc_feature(unit, soc_feature_flex_flow)) {
   1236             return BCM_E_UNAVAIL;
   1237         }
   1238         if (_BCM_MULTICAST_IS_EXTENDER(group) &&
   1239             !soc_feature(unit, soc_feature_port_extension)) {
   1240             return BCM_E_UNAVAIL;
   1241         }
   1242 
   1243         rv = _bcm_tr_multicast_ipmc_group_type_get(unit, mc_index,
   1244                                                    &get_group);
   1245 
   1246         if (BCM_E_NOT_FOUND == rv) {
   1247             *flags = 0;
   1248         } else if (BCM_FAILURE(rv)) {
   1249             return rv;
   1250         } else if (get_group != group) {
   1251             /* IPMC index is allocated, but not to the same group type */
   1252             *flags = 0;
   1253             return BCM_E_NOT_FOUND;
   1254         } else {
   1255             *flags =
   1256                 _bcm_esw_multicast_group_type_to_flags(
   1257                      _BCM_MULTICAST_TYPE_GET(group)) |
   1258                 BCM_MULTICAST_WITH_ID;
   1259         }
   1260     }
   1261 
   1262     return rv;
   1263 }
   1264 
   1265 #else  /* INCLUDE_L3 && BCM_TRX_SUPPORT */
   1266 int bcm_esw_triumph_multicast_not_empty;
   1267 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */