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

vlan.c (85579B)


      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:    vlan.c
      8  * Purpose: Manages VLAN virtual port creation and deletion.
      9  *          Also manages addition and removal of virtual
     10  *          ports from VLAN. The types of virtual ports that
     11  *          can be added to or remove from VLAN can be VLAN
     12  *          VPs or NIV VPs.
     13  */
     14 
     15 #include <soc/defs.h>
     16 #include <sal/core/libc.h>
     17 #include <shared/bsl.h>
     18 #if defined(BCM_TRIDENT_SUPPORT) && defined(INCLUDE_L3) 
     19 
     20 #include <soc/mem.h>
     21 #include <soc/hash.h>
     22 
     23 #include <bcm/error.h>
     24 
     25 #include <bcm_int/esw_dispatch.h>
     26 #include <bcm_int/api_xlate_port.h>
     27 
     28 #include <bcm_int/common/multicast.h>
     29 #include <bcm_int/esw/multicast.h>
     30 #include <bcm_int/esw/virtual.h>
     31 #include <bcm_int/esw/vlan.h>
     32 #include <bcm_int/esw/firebolt.h>
     33 #include <bcm_int/esw/trx.h>
     34 #include <bcm_int/esw/triumph2.h>
     35 #include <bcm_int/esw/trident.h>
     36 #include <bcm_int/esw/stack.h>
     37 #include <bcm_int/esw/trunk.h>
     38 #include <bcm_int/esw/ipmc.h>
     39 #if defined(BCM_TRIUMPH3_SUPPORT)
     40 #include <bcm_int/esw/triumph3.h>
     41 #endif /* BCM_TRIUMPH3_SUPPORT*/
     42 
     43 /* --------------------------------------------------------
     44  * Software book keeping for virtual port group information
     45  * --------------------------------------------------------
     46  */
     47 
     48 typedef struct _bcm_td_vp_group_s {
     49     int vp_count;            /* Number of VPs that belong to this VP group */
     50     SHR_BITDCL *vp_bitmap;   /* Bitmap of VPs that belong to this VP group */
     51     SHR_BITDCL *vlan_bitmap; /* VLANs this VP group belongs to */
     52 } _bcm_td_vp_group_t;
     53 
     54 typedef struct _bcm_td_vp_group_bk_s {
     55     int vp_group_initialized; /* Flag to check initialized status */
     56     int num_ing_vp_group;     /* Number of ingress VP groups */
     57     _bcm_td_vp_group_t *ing_vp_group_array; /* Ingress VP group array */
     58     int num_eg_vp_group;      /* Number of egress VP groups */
     59     _bcm_td_vp_group_t *eg_vp_group_array; /* Egress VP group array */
     60 } _bcm_td_vp_group_bk_t;
     61 
     62 typedef struct {
     63     int ingress;
     64     int egress;
     65 } _bcm_td_vp_group_unmanaged_t;
     66 
     67 STATIC _bcm_td_vp_group_bk_t _bcm_td_vp_group_bk[BCM_MAX_NUM_UNITS];
     68 
     69 STATIC _bcm_td_vp_group_unmanaged_t 
     70         _bcm_td_vp_group_unmanaged[BCM_MAX_NUM_UNITS];
     71 
     72 #define VP_GROUP_BK(unit) (&_bcm_td_vp_group_bk[unit])
     73 
     74 #define VP_GROUP_INIT(unit)                              \
     75     do {                                                 \
     76         if ((unit < 0) || (unit >= BCM_MAX_NUM_UNITS)) { \
     77             return BCM_E_UNIT;                           \
     78         }                                                \
     79         if (!VP_GROUP_BK(unit)->vp_group_initialized) {  \
     80             return BCM_E_INIT;                           \
     81         }                                                \
     82     } while (0)
     83 
     84 #define ING_VP_GROUP(unit, vp_group) \
     85     (&VP_GROUP_BK(unit)->ing_vp_group_array[vp_group])
     86 
     87 #define EG_VP_GROUP(unit, vp_group) \
     88     (&VP_GROUP_BK(unit)->eg_vp_group_array[vp_group])
     89 
     90 #define TD2_EGR_DVP_ATTRIBUTE_FIELD(_type,_sf) \
     91         (_type) == 1 ? TRILL__##_sf: \
     92         (_type) == 2 ? VXLAN__##_sf: \
     93         (_type) == 3 ? L2GRE__##_sf: \
     94         COMMON__##_sf;
     95 
     96 /*
     97  * Function:
     98  *      _bcm_td_vp_group_free_resources
     99  * Purpose:
    100  *      Free VP group data structures. 
    101  * Parameters:
    102  *      unit - SOC unit number
    103  * Returns:
    104  *      Nothing
    105  */
    106 STATIC void
    107 _bcm_td_vp_group_free_resources(int unit)
    108 {
    109     int num_vp_groups, i;
    110 
    111     if (VP_GROUP_BK(unit)->ing_vp_group_array) {
    112         num_vp_groups = soc_mem_field_length(unit, VLAN_TABLE(unit), VP_GROUP_BITMAPf);
    113         for (i = 0; i < num_vp_groups; i++) {
    114             if (ING_VP_GROUP(unit, i)->vp_bitmap) {
    115                 sal_free(ING_VP_GROUP(unit, i)->vp_bitmap);
    116                 ING_VP_GROUP(unit, i)->vp_bitmap = NULL;
    117             }
    118             if (ING_VP_GROUP(unit, i)->vlan_bitmap) {
    119                 sal_free(ING_VP_GROUP(unit, i)->vlan_bitmap);
    120                 ING_VP_GROUP(unit, i)->vlan_bitmap = NULL;
    121             }
    122         }
    123         sal_free(VP_GROUP_BK(unit)->ing_vp_group_array);
    124         VP_GROUP_BK(unit)->ing_vp_group_array = NULL;
    125     }
    126 
    127     if (VP_GROUP_BK(unit)->eg_vp_group_array) {
    128         num_vp_groups = soc_mem_field_length(unit, EGR_VLANm, VP_GROUP_BITMAPf);
    129         for (i = 0; i < num_vp_groups; i++) {
    130             if (EG_VP_GROUP(unit, i)->vp_bitmap) {
    131                 sal_free(EG_VP_GROUP(unit, i)->vp_bitmap);
    132                 EG_VP_GROUP(unit, i)->vp_bitmap = NULL;
    133             }
    134             if (EG_VP_GROUP(unit, i)->vlan_bitmap) {
    135                 sal_free(EG_VP_GROUP(unit, i)->vlan_bitmap);
    136                 EG_VP_GROUP(unit, i)->vlan_bitmap = NULL;
    137             }
    138         }
    139         sal_free(VP_GROUP_BK(unit)->eg_vp_group_array);
    140         VP_GROUP_BK(unit)->eg_vp_group_array = NULL;
    141     }
    142 
    143     return;
    144 }
    145 
    146 /*
    147  * Function:
    148  *      _td_egr_dvp_attribute_field_name_get
    149  * Purpose:
    150  *      Retrieve the proper field name based the device and vp type.
    151  * Parameters:
    152  *      unit - SOC unit number.
    153  * Returns:
    154  *      BCM_E_XXX
    155  */
    156 int
    157 _td_egr_dvp_attribute_field_name_get(int unit, 
    158                          egr_dvp_attribute_entry_t *dvp_entry, 
    159                          soc_field_t legacy_name,
    160                          soc_field_t *result_name)
    161 {
    162 
    163 #ifdef BCM_TRIDENT2_SUPPORT
    164     if (SOC_IS_TD2_TT2(unit)) {
    165         int vp_type;
    166         soc_field_t vp_type_f = VP_TYPEf;
    167 
    168         if (SOC_MEM_FIELD_VALID(unit, EGR_DVP_ATTRIBUTEm, DATA_TYPEf)) {
    169             vp_type_f = DATA_TYPEf;
    170         }
    171         vp_type = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, dvp_entry, vp_type_f);
    172         switch (legacy_name) {
    173             case EN_EFILTERf:
    174                 *result_name = TD2_EGR_DVP_ATTRIBUTE_FIELD(vp_type, EN_EFILTERf);
    175                 break;
    176             case VLAN_MEMBERSHIP_PROFILEf:
    177                 *result_name = TD2_EGR_DVP_ATTRIBUTE_FIELD(vp_type,
    178                                      VLAN_MEMBERSHIP_PROFILEf);
    179                 break;
    180             default:
    181                 return BCM_E_NOT_FOUND;
    182                 break;
    183         }
    184     } else
    185 #endif
    186     {
    187         *result_name = legacy_name;
    188     }
    189     return BCM_E_NONE;
    190 }
    191 
    192 
    193 #ifdef BCM_WARM_BOOT_SUPPORT
    194 /*
    195  * Function:
    196  *      _bcm_td_vp_group_reinit
    197  * Purpose:
    198  *      Recover the virtual port group data structures.
    199  * Parameters:
    200  *      unit - SOC unit number.
    201  * Returns:
    202  *      BCM_E_XXX
    203  */
    204 STATIC int
    205 _bcm_td_vp_group_reinit(int unit)
    206 {
    207     int rv = BCM_E_NONE;
    208     uint8 *source_vp_buf = NULL;
    209     uint8 *vlan_buf = NULL;
    210     uint8* vlan_2_buf=NULL;
    211     uint8 *egr_dvp_buf = NULL;
    212     uint8 *egr_vlan_buf = NULL;
    213     int index_min, index_max;
    214     int i, k;
    215     source_vp_entry_t *svp_entry;
    216     int vp_group;
    217     vlan_tab_entry_t *vlan_entry;
    218     vlan_2_tab_entry_t *vlan_2_entry;
    219     uint32 fldbuf[2];
    220     egr_dvp_attribute_entry_t *egr_dvp_entry;
    221     egr_vlan_entry_t *egr_vlan_entry;
    222     soc_field_t en_efilter_f;
    223     soc_field_t vm_prof_f;
    224 
    225     if (soc_feature(unit, soc_feature_vp_group_ingress_vlan_membership) &&
    226         (!bcm_td_ing_vp_group_unmanaged_get(unit))) {
    227 
    228         /* Recover ingress VP group's virtual ports from SOURCE_VP table */
    229 
    230         source_vp_buf = soc_cm_salloc(unit,
    231                 SOC_MEM_TABLE_BYTES(unit, SOURCE_VPm), "SOURCE_VP buffer");
    232         if (NULL == source_vp_buf) {
    233             rv = BCM_E_MEMORY;
    234             goto cleanup;
    235         }
    236 
    237         index_min = soc_mem_index_min(unit, SOURCE_VPm);
    238         index_max = soc_mem_index_max(unit, SOURCE_VPm);
    239         rv = soc_mem_read_range(unit, SOURCE_VPm, MEM_BLOCK_ANY,
    240                 index_min, index_max, source_vp_buf);
    241         if (SOC_FAILURE(rv)) {
    242             goto cleanup;
    243         }
    244 
    245         for (i = index_min; i <= index_max; i++) {
    246             svp_entry = soc_mem_table_idx_to_pointer
    247                 (unit, SOURCE_VPm, source_vp_entry_t *, source_vp_buf, i);
    248 
    249             if (soc_SOURCE_VPm_field32_get(unit, svp_entry,
    250                         ENABLE_IFILTERf) == 0) {
    251                 continue;
    252             }
    253 
    254             vp_group = soc_SOURCE_VPm_field32_get(unit, svp_entry,
    255                     VLAN_MEMBERSHIP_PROFILEf);
    256             SHR_BITSET(ING_VP_GROUP(unit, vp_group)->vp_bitmap, i);
    257             ING_VP_GROUP(unit, vp_group)->vp_count++;
    258         }
    259 
    260         soc_cm_sfree(unit, source_vp_buf);
    261         source_vp_buf= NULL;
    262 
    263         /* Recover ingress VP group's vlans from VLAN table */
    264 
    265         vlan_buf = soc_cm_salloc(unit,
    266                 SOC_MEM_TABLE_BYTES(unit, VLAN_TABm), "VLAN_TAB buffer");
    267         if (NULL == vlan_buf) {
    268             rv = BCM_E_MEMORY;
    269             goto cleanup;
    270         }
    271         if (SOC_MEM_IS_VALID(unit,VLAN_2_TABm)) {
    272             vlan_2_buf = soc_cm_salloc(unit,
    273                 SOC_MEM_TABLE_BYTES(unit, VLAN_2_TABm), "VLAN_2_TAB buffer");
    274             if (NULL == vlan_2_buf) {
    275                 rv = BCM_E_MEMORY;
    276                 goto cleanup;
    277             }
    278         }
    279         index_min = soc_mem_index_min(unit, VLAN_TABm);
    280         index_max = soc_mem_index_max(unit, VLAN_TABm);
    281         rv = soc_mem_read_range(unit, VLAN_TABm, MEM_BLOCK_ANY,
    282                 index_min, index_max, vlan_buf);
    283         if (SOC_FAILURE(rv)) {
    284             goto cleanup;
    285         }
    286         if (SOC_MEM_IS_VALID(unit,VLAN_2_TABm)) {
    287             rv = soc_mem_read_range(unit, VLAN_2_TABm, MEM_BLOCK_ANY,
    288                                     index_min, index_max, vlan_2_buf);
    289             if (SOC_FAILURE(rv)) {
    290                 goto cleanup;
    291             }
    292         }
    293         for (i = index_min; i <= index_max; i++) {
    294             vlan_entry = soc_mem_table_idx_to_pointer
    295                 (unit, VLAN_TABm, vlan_tab_entry_t *, vlan_buf, i);
    296 
    297             if (soc_VLAN_TABm_field32_get(unit, vlan_entry, VALIDf) == 0) {
    298                 continue;
    299             }
    300 
    301             if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
    302                if (soc_VLAN_TABm_field32_get(unit, vlan_entry,
    303                            VIRTUAL_PORT_ENf) == 0) {
    304                    continue;
    305                }
    306             }
    307 
    308             if (SOC_MEM_IS_VALID(unit, VLAN_2_TABm)) {
    309                 vlan_2_entry = soc_mem_table_idx_to_pointer
    310                     (unit, VLAN_2_TABm, vlan_2_tab_entry_t *, vlan_2_buf, i);
    311                 soc_VLAN_2_TABm_field_get(unit, vlan_2_entry, VP_GROUP_BITMAPf, fldbuf);
    312             } else {
    313                 soc_VLAN_TABm_field_get(unit, vlan_entry, VP_GROUP_BITMAPf, fldbuf);
    314             }
    315 
    316             for (k = 0; k < VP_GROUP_BK(unit)->num_ing_vp_group; k++) {
    317                 if (fldbuf[k / 32] & (1 << (k % 32))) {
    318                     /* The bit in VP_GROUP_BITMAP that corresponds to
    319                      * VP group k is set.
    320                      */
    321                     SHR_BITSET(ING_VP_GROUP(unit, k)->vlan_bitmap, i);
    322                 }
    323             }
    324         }
    325 
    326         soc_cm_sfree(unit, vlan_buf);
    327         vlan_buf = NULL;
    328         if (SOC_MEM_IS_VALID(unit,VLAN_2_TABm)) {
    329             soc_cm_sfree(unit, vlan_2_buf);
    330             vlan_2_buf = NULL;
    331         }
    332     }
    333 
    334     if (soc_feature(unit, soc_feature_vp_group_egress_vlan_membership) &&
    335         (!bcm_td_egr_vp_group_unmanaged_get(unit))) {
    336 
    337         /* Recover egress VP group's virtual ports from
    338          * EGR_DVP_ATTRIBUTE table
    339          */
    340 
    341         egr_dvp_buf = soc_cm_salloc(unit,
    342                 SOC_MEM_TABLE_BYTES(unit, EGR_DVP_ATTRIBUTEm),
    343                 "EGR_DVP buffer");
    344         if (NULL == egr_dvp_buf) {
    345             rv = BCM_E_MEMORY;
    346             goto cleanup;
    347         }
    348 
    349         index_min = soc_mem_index_min(unit, EGR_DVP_ATTRIBUTEm);
    350         index_max = soc_mem_index_max(unit, EGR_DVP_ATTRIBUTEm);
    351         rv = soc_mem_read_range(unit, EGR_DVP_ATTRIBUTEm, MEM_BLOCK_ANY,
    352                 index_min, index_max, egr_dvp_buf);
    353         if (SOC_FAILURE(rv)) {
    354             goto cleanup;
    355         }
    356 
    357         for (i = index_min; i <= index_max; i++) {
    358             egr_dvp_entry = soc_mem_table_idx_to_pointer
    359                 (unit, EGR_DVP_ATTRIBUTEm, egr_dvp_attribute_entry_t *,
    360                  egr_dvp_buf, i);
    361 
    362             BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
    363                          egr_dvp_entry, EN_EFILTERf, &en_efilter_f));
    364 
    365             if (soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, egr_dvp_entry,
    366                         en_efilter_f) == 0) {
    367                 continue;
    368             }
    369 
    370             BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
    371                          egr_dvp_entry, VLAN_MEMBERSHIP_PROFILEf, 
    372                          &vm_prof_f));
    373 
    374             vp_group = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, egr_dvp_entry,
    375                     vm_prof_f);
    376             SHR_BITSET(EG_VP_GROUP(unit, vp_group)->vp_bitmap, i);
    377             EG_VP_GROUP(unit, vp_group)->vp_count++;
    378         }
    379 
    380         soc_cm_sfree(unit, egr_dvp_buf);
    381         egr_dvp_buf = NULL;
    382 
    383         /* Recover egress VP group's vlans from EGR_VLAN table */
    384 
    385         egr_vlan_buf = soc_cm_salloc(unit,
    386                 SOC_MEM_TABLE_BYTES(unit, EGR_VLANm), "EGR_VLAN buffer");
    387         if (NULL == egr_vlan_buf) {
    388             rv = BCM_E_MEMORY;
    389             goto cleanup;
    390         }
    391 
    392         index_min = soc_mem_index_min(unit, EGR_VLANm);
    393         index_max = soc_mem_index_max(unit, EGR_VLANm);
    394         rv = soc_mem_read_range(unit, EGR_VLANm, MEM_BLOCK_ANY,
    395                 index_min, index_max, egr_vlan_buf);
    396         if (SOC_FAILURE(rv)) {
    397             goto cleanup;
    398         }
    399 
    400         for (i = index_min; i <= index_max; i++) {
    401             egr_vlan_entry = soc_mem_table_idx_to_pointer
    402                 (unit, EGR_VLANm, egr_vlan_entry_t *, egr_vlan_buf, i);
    403 
    404             if (soc_EGR_VLANm_field32_get(unit, egr_vlan_entry, VALIDf) == 0) {
    405                 continue;
    406             }
    407 
    408             soc_EGR_VLANm_field_get(unit, egr_vlan_entry, VP_GROUP_BITMAPf,
    409                     fldbuf);
    410             for (k = 0; k < VP_GROUP_BK(unit)->num_eg_vp_group; k++) {
    411                 if (fldbuf[k / 32] & (1 << (k % 32))) {
    412                     /* The bit in VP_GROUP_BITMAP that corresponds to
    413                      * VP group k is set.
    414                      */
    415                     SHR_BITSET(EG_VP_GROUP(unit, k)->vlan_bitmap, i);
    416                 }
    417             }
    418         }
    419         
    420         soc_cm_sfree(unit, egr_vlan_buf);
    421         egr_vlan_buf = NULL;
    422     }
    423 
    424 cleanup:
    425     if (source_vp_buf) {
    426         soc_cm_sfree(unit, source_vp_buf);
    427     }
    428     if (vlan_buf) {
    429         soc_cm_sfree(unit, vlan_buf);
    430     }
    431     if (vlan_2_buf) {
    432         soc_cm_sfree(unit, vlan_2_buf);
    433     }
    434     if (egr_dvp_buf) {
    435         soc_cm_sfree(unit, egr_dvp_buf);
    436     }
    437     if (egr_vlan_buf) {
    438         soc_cm_sfree(unit, egr_vlan_buf);
    439     }
    440 
    441     return rv;
    442 }
    443 #endif /* BCM_WARM_BOOT_SUPPORT */
    444 
    445 #ifndef BCM_SW_STATE_DUMP_DISABLE
    446 /*
    447  * Function:
    448  *     bcm_td_vp_group_sw_dump
    449  * Purpose:
    450  *     Displays VP group information maintained by software.
    451  * Parameters:
    452  *     unit - Device unit number
    453  * Returns:
    454  *     None
    455  */
    456 void
    457 bcm_td_vp_group_sw_dump(int unit)
    458 {
    459     int i, k;
    460     int vp_bitmap_bit_size;
    461     int num_vlan;
    462 
    463     LOG_CLI((BSL_META_U(unit,
    464                         "\nSW Information Ingress VP Group - Unit %d\n"), unit));
    465     for (i = 0; i < VP_GROUP_BK(unit)->num_ing_vp_group; i++) {
    466         LOG_CLI((BSL_META_U(unit,
    467                             "\n  Ingress VP Group = %d\n"), i));
    468         LOG_CLI((BSL_META_U(unit,
    469                             "    VP Count = %d\n"), ING_VP_GROUP(unit, i)->vp_count));
    470 
    471         LOG_CLI((BSL_META_U(unit,
    472                             "    VP List =")));
    473         vp_bitmap_bit_size = soc_mem_index_count(unit, SOURCE_VPm);
    474         for (k = 0; k < vp_bitmap_bit_size; k++) {
    475             if (SHR_BITGET(ING_VP_GROUP(unit, i)->vp_bitmap, k)) {
    476                 LOG_CLI((BSL_META_U(unit,
    477                                     " %d"), k));
    478             }
    479         }
    480         LOG_CLI((BSL_META_U(unit,
    481                             "\n")));
    482 
    483         LOG_CLI((BSL_META_U(unit,
    484                             "    VLAN List =")));
    485         num_vlan = soc_mem_index_count(unit, VLAN_TABm);
    486         for (k = 0; k < num_vlan; k++) {
    487             if (SHR_BITGET(ING_VP_GROUP(unit, i)->vlan_bitmap, k)) {
    488                 LOG_CLI((BSL_META_U(unit,
    489                                     " %d"), k));
    490             }
    491         }
    492         LOG_CLI((BSL_META_U(unit,
    493                             "\n")));
    494     }
    495 
    496     LOG_CLI((BSL_META_U(unit,
    497                         "\nSW Information Egress VP Group - Unit %d\n"), unit));
    498     for (i = 0; i < VP_GROUP_BK(unit)->num_eg_vp_group; i++) {
    499         LOG_CLI((BSL_META_U(unit,
    500                             "\n  Egress VP Group = %d\n"), i));
    501         LOG_CLI((BSL_META_U(unit,
    502                             "    VP Count = %d\n"), EG_VP_GROUP(unit, i)->vp_count));
    503 
    504         LOG_CLI((BSL_META_U(unit,
    505                             "    VP List =")));
    506         vp_bitmap_bit_size = soc_mem_index_count(unit, EGR_DVP_ATTRIBUTEm);
    507         for (k = 0; k < vp_bitmap_bit_size; k++) {
    508             if (SHR_BITGET(EG_VP_GROUP(unit, i)->vp_bitmap, k)) {
    509                 LOG_CLI((BSL_META_U(unit,
    510                                     " %d"), k));
    511             }
    512         }
    513         LOG_CLI((BSL_META_U(unit,
    514                             "\n")));
    515 
    516         LOG_CLI((BSL_META_U(unit,
    517                             "    VLAN List =")));
    518         num_vlan = soc_mem_index_count(unit, EGR_VLANm);
    519         for (k = 0; k < num_vlan; k++) {
    520             if (SHR_BITGET(EG_VP_GROUP(unit, i)->vlan_bitmap, k)) {
    521                 LOG_CLI((BSL_META_U(unit,
    522                                     " %d"), k));
    523             }
    524         }
    525         LOG_CLI((BSL_META_U(unit,
    526                             "\n")));
    527     }
    528 
    529     return;
    530 }
    531 #endif /* BCM_SW_STATE_DUMP_DISABLE */
    532 
    533 /*
    534  * Function:
    535  *      bcm_td_vp_group_init
    536  * Purpose:
    537  *      Initialize the virtual port group data structures.
    538  * Parameters:
    539  *      unit - SOC unit number.
    540  * Returns:
    541  *      BCM_E_XXX
    542  */
    543 int
    544 bcm_td_vp_group_init(int unit)
    545 {
    546     int num_vp_groups, num_vp, num_vlan, i;
    547     int rv = BCM_E_NONE;
    548 
    549     _bcm_td_vp_group_free_resources(unit);
    550 
    551 #ifdef BCM_WARM_BOOT_SUPPORT
    552     if (SOC_WARM_BOOT(unit)) {
    553     } else
    554 #endif
    555     {
    556         _bcm_td_vp_group_unmanaged[unit].ingress = FALSE;
    557         _bcm_td_vp_group_unmanaged[unit].egress  = FALSE;
    558     }
    559     sal_memset(VP_GROUP_BK(unit), 0, sizeof(_bcm_td_vp_group_bk_t));
    560 
    561     if (SOC_MEM_FIELD_VALID(unit, VLAN_TABLE(unit), VP_GROUP_BITMAPf)) {
    562         num_vp_groups = soc_mem_field_length(unit, VLAN_TABLE(unit), VP_GROUP_BITMAPf);
    563         VP_GROUP_BK(unit)->num_ing_vp_group = num_vp_groups;
    564 
    565         if (NULL == VP_GROUP_BK(unit)->ing_vp_group_array) {
    566             VP_GROUP_BK(unit)->ing_vp_group_array = 
    567                 sal_alloc(sizeof(_bcm_td_vp_group_t) * num_vp_groups,
    568                         "ingress vp group array");
    569             if (NULL == VP_GROUP_BK(unit)->ing_vp_group_array) {
    570                 _bcm_td_vp_group_free_resources(unit);
    571                 return BCM_E_MEMORY;
    572             }
    573         }
    574         sal_memset(VP_GROUP_BK(unit)->ing_vp_group_array, 0,
    575                 sizeof(_bcm_td_vp_group_t) * num_vp_groups);
    576 
    577         for (i = 0; i < num_vp_groups; i++) {
    578             num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    579             if (NULL == ING_VP_GROUP(unit, i)->vp_bitmap) {
    580                 ING_VP_GROUP(unit, i)->vp_bitmap = sal_alloc
    581                     (SHR_BITALLOCSIZE(num_vp), "ingress vp group vp bitmap");
    582                 if (NULL == ING_VP_GROUP(unit, i)->vp_bitmap) {
    583                     _bcm_td_vp_group_free_resources(unit);
    584                     return BCM_E_MEMORY;
    585                 }
    586             }
    587             sal_memset(ING_VP_GROUP(unit, i)->vp_bitmap, 0,
    588                     SHR_BITALLOCSIZE(num_vp));
    589 
    590             num_vlan = soc_mem_index_count(unit, VLAN_TABLE(unit));
    591             if (NULL == ING_VP_GROUP(unit, i)->vlan_bitmap) {
    592                 ING_VP_GROUP(unit, i)->vlan_bitmap = sal_alloc
    593                     (SHR_BITALLOCSIZE(num_vlan), "ingress vp group vlan bitmap");
    594                 if (NULL == ING_VP_GROUP(unit, i)->vlan_bitmap) {
    595                     _bcm_td_vp_group_free_resources(unit);
    596                     return BCM_E_MEMORY;
    597                 }
    598             }
    599             sal_memset(ING_VP_GROUP(unit, i)->vlan_bitmap, 0,
    600                     SHR_BITALLOCSIZE(num_vlan));
    601         }
    602     }
    603 
    604     if (SOC_MEM_FIELD_VALID(unit, EGR_VLANm, VP_GROUP_BITMAPf)) {
    605         num_vp_groups = soc_mem_field_length(unit, EGR_VLANm, VP_GROUP_BITMAPf);
    606         VP_GROUP_BK(unit)->num_eg_vp_group = num_vp_groups;
    607 
    608         if (NULL == VP_GROUP_BK(unit)->eg_vp_group_array) {
    609             VP_GROUP_BK(unit)->eg_vp_group_array = 
    610                 sal_alloc(sizeof(_bcm_td_vp_group_t) * num_vp_groups,
    611                         "egress vp group array");
    612             if (NULL == VP_GROUP_BK(unit)->eg_vp_group_array) {
    613                 _bcm_td_vp_group_free_resources(unit);
    614                 return BCM_E_MEMORY;
    615             }
    616         }
    617         sal_memset(VP_GROUP_BK(unit)->eg_vp_group_array, 0,
    618                 sizeof(_bcm_td_vp_group_t) * num_vp_groups);
    619 
    620         for (i = 0; i < num_vp_groups; i++) {
    621             num_vp = soc_mem_index_count(unit, EGR_DVP_ATTRIBUTEm);
    622             if (NULL == EG_VP_GROUP(unit, i)->vp_bitmap) {
    623                 EG_VP_GROUP(unit, i)->vp_bitmap = sal_alloc
    624                     (SHR_BITALLOCSIZE(num_vp), "egress vp group vp bitmap");
    625                 if (NULL == EG_VP_GROUP(unit, i)->vp_bitmap) {
    626                     _bcm_td_vp_group_free_resources(unit);
    627                     return BCM_E_MEMORY;
    628                 }
    629             }
    630             sal_memset(EG_VP_GROUP(unit, i)->vp_bitmap, 0,
    631                     SHR_BITALLOCSIZE(num_vp));
    632 
    633             num_vlan = soc_mem_index_count(unit, EGR_VLANm);
    634             if (NULL == EG_VP_GROUP(unit, i)->vlan_bitmap) {
    635                 EG_VP_GROUP(unit, i)->vlan_bitmap = sal_alloc
    636                     (SHR_BITALLOCSIZE(num_vlan), "egress vp group vlan bitmap");
    637                 if (NULL == EG_VP_GROUP(unit, i)->vlan_bitmap) {
    638                     _bcm_td_vp_group_free_resources(unit);
    639                     return BCM_E_MEMORY;
    640                 }
    641             }
    642             sal_memset(EG_VP_GROUP(unit, i)->vlan_bitmap, 0,
    643                     SHR_BITALLOCSIZE(num_vlan));
    644         }
    645     }
    646 
    647     VP_GROUP_BK(unit)->vp_group_initialized = 1;
    648 
    649 #ifdef BCM_WARM_BOOT_SUPPORT
    650     if (SOC_WARM_BOOT(unit)) {
    651         rv = _bcm_td_vp_group_reinit(unit);
    652         if (BCM_FAILURE(rv)) {
    653             _bcm_td_vp_group_free_resources(unit);
    654         }
    655     }
    656 #endif /* BCM_WARM_BOOT_SUPPORT */
    657 
    658     return rv;
    659 }
    660 
    661 /*
    662  * Function:
    663  *      bcm_td_vp_group_detach
    664  * Purpose:
    665  *      De-initialize the virtual port group data structures.
    666  * Parameters:
    667  *      unit - SOC unit number.
    668  * Returns:
    669  *      BCM_E_XXX
    670  */
    671 int
    672 bcm_td_vp_group_detach(int unit)
    673 {
    674     _bcm_td_vp_group_free_resources(unit);
    675 
    676     VP_GROUP_BK(unit)->vp_group_initialized = 0;
    677 
    678     return BCM_E_NONE;
    679 }
    680 
    681 /*
    682  * Function:
    683  *      _bcm_td_phy_port_trunk_is_local
    684  * Purpose:
    685  *      Determine if the given physical port or trunk is local.
    686  * Parameters:
    687  *      unit  - (IN) SOC unit number. 
    688  *      gport - (IN) Physical port or trunk GPORT ID.
    689  *      is_local - (OUT) Indicates if gport is local.
    690  * Returns:
    691  *      BCM_X_XXX
    692  */
    693 STATIC int
    694 _bcm_td_phy_port_trunk_is_local(int unit, bcm_gport_t gport, int *is_local)
    695 {
    696     bcm_trunk_t trunk_id;
    697     int rv = BCM_E_NONE;
    698     int local_member_count;
    699     bcm_module_t mod_out;
    700     bcm_port_t port_out;
    701     int id;
    702     int modid_local;
    703 
    704     *is_local = 0;
    705 
    706     if (BCM_GPORT_IS_TRUNK(gport)) {
    707         trunk_id = BCM_GPORT_TRUNK_GET(gport);
    708         rv = _bcm_trunk_id_validate(unit, trunk_id);
    709         if (BCM_FAILURE(rv)) {
    710             return (BCM_E_PORT);
    711         }
    712         rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
    713                 0, NULL, &local_member_count);
    714         if (BCM_FAILURE(rv)) {
    715             return (BCM_E_PORT);
    716         }   
    717         if (local_member_count > 0) {
    718             *is_local = 1;
    719         }
    720     } else {
    721         BCM_IF_ERROR_RETURN
    722             (_bcm_esw_gport_resolve(unit, gport, &mod_out, &port_out,
    723                                     &trunk_id, &id)); 
    724         /* In case of extended queuing on KTX, trunk_id gets updated with
    725          * extended queue value. So set it to invalid value.
    726          */
    727 #ifdef BCM_KATANA_SUPPORT
    728        if (soc_feature(unit, soc_feature_extended_queueing)) {
    729            if ((BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) ||
    730                (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(gport)) ||
    731                (BCM_GPORT_IS_MCAST_SUBSCRIBER_QUEUE_GROUP(gport))) {
    732                 trunk_id = BCM_TRUNK_INVALID;
    733            }
    734        }
    735 #endif
    736         if ((trunk_id != -1) || (id != -1)) {
    737             return BCM_E_PARAM;
    738         }
    739 
    740         BCM_IF_ERROR_RETURN
    741             (_bcm_esw_modid_is_local(unit, mod_out, &modid_local));
    742 
    743         *is_local = modid_local;
    744     }
    745 
    746     return BCM_E_NONE;
    747 }
    748 
    749 
    750 /*
    751  * Function:
    752  *      bcm_td_vlan_vp_group_set
    753  * Purpose:
    754  *      set/clear the specified VP group in the vlan's vp group bitmap.
    755  * Parameters:
    756  *      unit       - (IN) Device Number
    757  *      vlan_mem         - (IN) VLAN_TABm or EGR_VLANm 
    758  *      vlan             - (IN) vlan mem entry index 
    759  *      vp_group         - (IN) the specified VP group 
    760  *      enable           - (IN) TRUE to set, FALSE to clear  
    761  * Returns:
    762  *      BCM_E_XXX
    763  * Notes:
    764  *      If vp_group == -1 and enable == false, clear the vp_group bitmap
    765  */
    766 
    767 int
    768 bcm_td_vlan_vp_group_set(
    769       int unit,           /* unit number */
    770       soc_mem_t vlan_mem, /* either VLAN_TABm or EGR_VLANm */
    771       int vlan,           /* index to the above memory table */
    772       int vp_group,       /* the VP group number */
    773       int enable          /* TRUE to set, FALSE to clear the VP group */
    774 )
    775 {
    776     int field_len;
    777     vlan_tab_entry_t vtab;  /* both egr_vlan and vlan_tab is same size*/
    778     uint32 vp_group_bitmap[2];
    779     int i;
    780     int rv;
    781 
    782     /* safety check */
    783     field_len = soc_mem_field_length(unit,vlan_mem,
    784                VP_GROUP_BITMAPf);
    785     if (vp_group >= 0) {
    786         if (vp_group >= field_len) {
    787             return BCM_E_PARAM;
    788         }
    789     } else if (enable) {
    790         return BCM_E_PARAM;
    791     }
    792 
    793     if (field_len > sizeof(vp_group_bitmap) * 8) {
    794         return BCM_E_INTERNAL;
    795     }
    796 
    797     sal_memset(&vtab, 0, sizeof(vlan_tab_entry_t));
    798 
    799     soc_mem_lock(unit, vlan_mem);
    800 
    801     if ((rv = soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, vlan,
    802                     &vtab)) != BCM_E_NONE) {
    803         soc_mem_unlock(unit, vlan_mem);
    804         return rv;
    805     }
    806 
    807     if (vp_group >= 0) {
    808         soc_mem_field_get(unit, vlan_mem, (uint32 *)&vtab,
    809                         VP_GROUP_BITMAPf, vp_group_bitmap);
    810         if (enable) {
    811             vp_group_bitmap[vp_group/32] |= 1 << (vp_group%32);
    812         } else {
    813             /* clear the vp_group */
    814             vp_group_bitmap[vp_group/32] &= ~(1 << (vp_group%32));
    815         }
    816     } else {
    817         /* clear the VP group bitmap for this vlan */
    818         for (i = 0; i < COUNTOF(vp_group_bitmap); i++) {
    819             vp_group_bitmap[i] = 0;
    820         }
    821     }
    822     soc_mem_field_set(unit, vlan_mem, (uint32 *)&vtab,
    823                         VP_GROUP_BITMAPf, vp_group_bitmap);
    824     if ((rv = soc_mem_write(unit, vlan_mem,
    825                  MEM_BLOCK_ALL, vlan, &vtab)) != BCM_E_NONE) {
    826         soc_mem_unlock(unit, vlan_mem);
    827         return rv;
    828     }
    829     soc_mem_unlock(unit, vlan_mem);
    830     return BCM_E_NONE;
    831 }
    832 
    833 /*
    834  * Function:
    835  *      bcm_td_vlan_vp_group_get
    836  * Purpose:
    837  *      get the flags indicating the given vp group is set for
    838  *      ingress or/and egress.
    839  * Parameters:
    840  *      unit       - (IN) Device Number
    841  *      vlan_mem         - (IN) VLAN_TABm or EGR_VLANm 
    842  *      vlan             - (IN) vlan mem entry index 
    843  *      vp_group         - (IN) the specified VP group 
    844  *      enable           - (OUT) usage flag  
    845  * Returns:
    846  *      BCM_E_XXX
    847  */
    848 
    849 int
    850 bcm_td_vlan_vp_group_get(
    851       int unit,           /* unit number */
    852       soc_mem_t vlan_mem, /* either VLAN_TABm or EGR_VLANm */
    853       int vlan,           /* index to the above memory table */
    854       int vp_group,       /* the VP group number */
    855       int *enable         /* TRUE: the given group is set */
    856 )
    857 {
    858     int field_len;
    859     vlan_tab_entry_t vtab;  /* both egr_vlan and vlan_tab is same size*/
    860     uint32 vp_group_bitmap[2];
    861     int rv;
    862 
    863     /* safety check */
    864     field_len = soc_mem_field_length(unit,vlan_mem,
    865                VP_GROUP_BITMAPf);
    866     if (vp_group >= field_len) {
    867         return BCM_E_PARAM;
    868     }
    869 
    870     if (field_len > sizeof(vp_group_bitmap) * 8) {
    871         return BCM_E_INTERNAL;
    872     }
    873     
    874     *enable = 0;
    875     sal_memset(&vtab, 0, sizeof(vlan_tab_entry_t));
    876 
    877     if ((rv = soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, vlan,
    878                     &vtab)) != BCM_E_NONE) {
    879         return rv;
    880     }
    881 
    882     soc_mem_field_get(unit, vlan_mem, (uint32 *)&vtab,
    883                         VP_GROUP_BITMAPf, vp_group_bitmap);
    884     if (vp_group_bitmap[vp_group/32] & (1 << (vp_group%32))) {
    885         *enable = TRUE;
    886     }
    887         
    888     return BCM_E_NONE;
    889 }
    890 
    891 /*
    892  * Function:
    893  *      _bcm_td_vp_local_ports_get
    894  * Purpose:
    895  *      Get the local ports on which the given VP resides.
    896  * Parameters:
    897  *      unit       - (IN) Device Number
    898  *      vp         - (IN) Virtual port number
    899  *      local_port_max   - (OUT) Size of local_port_array
    900  *      local_port_array - (OUT) Array of local ports
    901  *      local_port_count - (OUT) Number of local ports 
    902  * Returns:
    903  *      BCM_E_XXX
    904  * Notes:
    905  *      If local_port_max = 0 and local_port_array == NULL,
    906  *      the number of local ports will still be returned in
    907  *      local_port_count. 
    908  */
    909 
    910 STATIC int
    911 _bcm_td_vp_local_ports_get(int unit, int vp, int local_port_max,
    912         bcm_port_t *local_port_array, int *local_port_count)
    913 {
    914     ing_dvp_table_entry_t dvp_entry;
    915     ing_l3_next_hop_entry_t ing_nh;
    916     uint32 nh_index;
    917     bcm_trunk_t trunk_id;
    918     bcm_module_t modid;
    919     bcm_port_t port;
    920     int modid_local;
    921 
    922     if (local_port_max < 0) {
    923         return BCM_E_PARAM;
    924     }
    925 
    926     if ((local_port_max == 0) && (NULL != local_port_array)) {
    927         return BCM_E_PARAM;
    928     }
    929 
    930     if ((local_port_max > 0) && (NULL == local_port_array)) {
    931         return BCM_E_PARAM;
    932     }
    933 
    934     if (NULL == local_port_count) {
    935         return BCM_E_PARAM;
    936     }
    937 
    938     *local_port_count = 0;
    939 
    940     BCM_IF_ERROR_RETURN
    941         (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
    942     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp_entry,
    943             NEXT_HOP_INDEXf);
    944     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    945                 nh_index, &ing_nh));
    946 
    947     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
    948         trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
    949 
    950         BCM_IF_ERROR_RETURN
    951             (_bcm_esw_trunk_local_members_get(unit,
    952                                              trunk_id, 
    953                                              local_port_max,
    954                                              local_port_array, 
    955                                              local_port_count));
    956     } else {
    957         modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
    958         port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
    959 
    960         BCM_IF_ERROR_RETURN
    961             (_bcm_esw_modid_is_local(unit, modid, &modid_local));
    962         if (TRUE != modid_local) {
    963             *local_port_count = 0;
    964             return BCM_E_NONE;
    965         }
    966 
    967         *local_port_count = 1;
    968         if (NULL != local_port_array) {
    969             local_port_array[0] = port;
    970         }
    971     }
    972 
    973     return BCM_E_NONE;
    974 }
    975 
    976 /*
    977  * Function:
    978  *      bcm_td_vlan_vp_group_get_all
    979  * Purpose:
    980  *      get the array of gports and flags related to the gport.
    981  * Parameters:
    982  *      unit       - (IN) Device Number
    983  *      vlan       - (IN) vlan mem entry index
    984  *      array_max  - (IN) max size of the array 
    985  *      bcm_gport_t *gport_array  - (IN) gport array
    986  *      flags_array -(IN) flags array related to gports
    987  *      port_cnt   - (IN/OUT) point to the first available array entry
    988  * Returns:
    989  *      BCM_E_XXX
    990  */
    991 
    992 int
    993 bcm_td_vlan_vp_group_get_all(
    994       int unit,           /* unit number */
    995       int vlan,           /* index to the vlan  memory table */
    996       int array_max,      /* max size of the array */
    997       bcm_gport_t *gport_array,    /* gport array */
    998       int *flags_array,            /* flags array related to gports */
    999       int *port_cnt)      /* point to the first available array entry */
   1000 {
   1001     int num_vp_groups;
   1002     int vpg;
   1003     int ing_enable;
   1004     int egr_enable;
   1005     int rv;
   1006 
   1007     num_vp_groups = soc_mem_field_length(unit, VLAN_TABLE(unit),
   1008                                            VP_GROUP_BITMAPf);
   1009 
   1010     for (vpg = 0; vpg < num_vp_groups; vpg++) {
   1011         ing_enable = 0;
   1012         egr_enable = 0;
   1013         if ((*port_cnt == array_max) && (gport_array || flags_array)) {
   1014             break;
   1015         }
   1016         if (flags_array) {
   1017             flags_array[*port_cnt] = 0;
   1018         }
   1019         if (soc_feature(unit,
   1020                   soc_feature_vp_group_ingress_vlan_membership) &&
   1021                   bcm_td_ing_vp_group_unmanaged_get(unit)) {
   1022             rv = bcm_td_vlan_vp_group_get(unit,VLAN_TABLE(unit),vlan,
   1023                              vpg,&ing_enable);
   1024             BCM_IF_ERROR_RETURN(rv);
   1025             if (ing_enable) {
   1026                 if (gport_array) {
   1027                     BCM_GPORT_VP_GROUP_SET(gport_array[*port_cnt],vpg);
   1028                 }
   1029                 if (flags_array) {
   1030                     flags_array[*port_cnt] = BCM_VLAN_PORT_INGRESS_ONLY;
   1031                 }
   1032             }
   1033         }
   1034         if (soc_feature(unit,
   1035                  soc_feature_vp_group_egress_vlan_membership) &&
   1036                  bcm_td_egr_vp_group_unmanaged_get(unit)) {
   1037             rv = bcm_td_vlan_vp_group_get(unit,EGR_VLANm,vlan,
   1038                              vpg,&egr_enable);
   1039             BCM_IF_ERROR_RETURN(rv);
   1040             if (egr_enable) {
   1041                 if (gport_array) {
   1042                     BCM_GPORT_VP_GROUP_SET(gport_array[*port_cnt],vpg);
   1043                 }
   1044                 if (flags_array) {
   1045                     flags_array[*port_cnt] |= BCM_VLAN_PORT_EGRESS_ONLY;
   1046                 }
   1047             }
   1048         }
   1049         if (ing_enable || egr_enable) {
   1050             (*port_cnt)++;
   1051         }
   1052     }
   1053     return BCM_E_NONE;
   1054 }
   1055 
   1056 /*
   1057  * Function:
   1058  *      _bcm_td_vp_vlan_bitmap_get
   1059  * Purpose:
   1060  *      Get a bitmap of all the VLANs the given VP belongs to.
   1061  * Parameters:
   1062  *      unit        - (IN) BCM device number
   1063  *      vp_gport    - (IN) VP gport ID 
   1064  *      vlan_bitmap - (OUT) Bitmap of VLANs
   1065  * Returns:
   1066  *      BCM_E_XXX
   1067  */
   1068 STATIC int
   1069 _bcm_td_vp_vlan_bitmap_get(int unit, bcm_gport_t vp_gport, SHR_BITDCL *vlan_bitmap)
   1070 {
   1071     int rv;
   1072     int vp;
   1073     int mc_type;
   1074     source_vp_entry_t svp_entry;
   1075     int vp_group;
   1076     int num_vlan;
   1077     egr_dvp_attribute_entry_t egr_dvp_entry;
   1078     bcm_port_t local_port;
   1079     int local_port_count;
   1080     uint8 *vlan_tab_buf = NULL;
   1081     int index_min, index_max;
   1082     int if_max, if_count;
   1083     bcm_if_t *if_array = NULL;
   1084     int i, j, k;
   1085     vlan_tab_entry_t *vlan_tab_entry;
   1086     int mc_index_array[3];
   1087     int match_prev_mc_index = FALSE;
   1088     bcm_multicast_t group;
   1089     bcm_gport_t local_gport;
   1090     bcm_if_t encap_id;
   1091     int match = FALSE;
   1092 
   1093     if (BCM_GPORT_IS_VLAN_PORT(vp_gport)) {
   1094         vp = BCM_GPORT_VLAN_PORT_ID_GET(vp_gport);
   1095         mc_type = _BCM_MULTICAST_TYPE_VLAN;
   1096     } else if (BCM_GPORT_IS_NIV_PORT(vp_gport)) {
   1097         vp = BCM_GPORT_NIV_PORT_ID_GET(vp_gport);
   1098         mc_type = _BCM_MULTICAST_TYPE_NIV;
   1099     } else if (BCM_GPORT_IS_EXTENDER_PORT(vp_gport)) {
   1100         vp = BCM_GPORT_EXTENDER_PORT_ID_GET(vp_gport);
   1101         mc_type = _BCM_MULTICAST_TYPE_EXTENDER;
   1102     } else if (BCM_GPORT_IS_TRUNK(vp_gport)) {
   1103         BCM_IF_ERROR_RETURN(                                                    
   1104             _bcm_esw_trunk_tid_to_vp_lag_vp(
   1105                 unit, BCM_GPORT_TRUNK_GET(vp_gport), &vp));
   1106         /* there is no need to set mc_type for vplag */
   1107         mc_type = 0;
   1108     } else {
   1109         return BCM_E_PARAM;
   1110     }
   1111 
   1112     /* Check if VP already belongs to a VP group.
   1113      * If so, just return the VP group's VLAN bitmap.
   1114      */
   1115 
   1116     if (soc_feature(unit, soc_feature_vp_group_ingress_vlan_membership)) {
   1117         SOC_IF_ERROR_RETURN
   1118             (READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   1119         if (soc_SOURCE_VPm_field32_get(
   1120             unit, &svp_entry, ENABLE_IFILTERf) == 1) {
   1121             vp_group = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
   1122                     VLAN_MEMBERSHIP_PROFILEf);
   1123             num_vlan = soc_mem_index_count(unit, VLAN_TABm);
   1124             sal_memcpy(vlan_bitmap, ING_VP_GROUP(unit, vp_group)->vlan_bitmap,
   1125                     SHR_BITALLOCSIZE(num_vlan));
   1126             return BCM_E_NONE;
   1127         }
   1128     }
   1129 
   1130     if (soc_feature(unit, soc_feature_vp_group_egress_vlan_membership)) {
   1131         soc_field_t en_efilter_f;
   1132         soc_field_t vm_prof_f;
   1133 
   1134         SOC_IF_ERROR_RETURN
   1135             (READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &egr_dvp_entry));
   1136 
   1137         BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   1138                      &egr_dvp_entry, EN_EFILTERf, &en_efilter_f));
   1139 
   1140         if (soc_EGR_DVP_ATTRIBUTEm_field32_get(
   1141             unit, &egr_dvp_entry, en_efilter_f) == 1) {
   1142             BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   1143                          &egr_dvp_entry, VLAN_MEMBERSHIP_PROFILEf, &vm_prof_f));
   1144             vp_group = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &egr_dvp_entry,
   1145                     vm_prof_f);
   1146             num_vlan = soc_mem_index_count(unit, EGR_VLANm);
   1147             sal_memcpy(vlan_bitmap, EG_VP_GROUP(unit, vp_group)->vlan_bitmap,
   1148                     SHR_BITALLOCSIZE(num_vlan));
   1149             return BCM_E_NONE;
   1150         }
   1151     }
   1152 
   1153 #if defined(BCM_TRIDENT2_SUPPORT)
   1154     /* need a special process for vp-lag */
   1155     if (BCM_GPORT_IS_TRUNK(vp_gport)) {
   1156         bcm_trunk_member_t *member_array;
   1157         int member_count, member_max;
   1158         bcm_trunk_chip_info_t trunk_chip_info;
   1159         SHR_BITDCL *vlan_bitmap_tmp = NULL;
   1160 
   1161         /* 1 get vp-lag member count max */
   1162         rv = bcm_esw_trunk_chip_info_get(unit, &trunk_chip_info);
   1163         if (BCM_FAILURE(rv)) {
   1164             goto cleanup;
   1165         }
   1166 
   1167         member_max = trunk_chip_info.vp_ports_max;
   1168         /* 2 alloc member array according to the member count */
   1169         member_array = sal_alloc(member_max * sizeof(bcm_trunk_member_t),
   1170                                 "member array");
   1171         if (NULL == member_array) {
   1172             rv = BCM_E_MEMORY;
   1173             goto cleanup;
   1174         }
   1175         /* 3 get member array */
   1176         rv = bcm_esw_trunk_get(unit, BCM_GPORT_TRUNK_GET(vp_gport), NULL, 
   1177                                member_max, member_array, &member_count);
   1178         if (BCM_FAILURE(rv)) {
   1179             sal_free (member_array);
   1180             goto cleanup;
   1181         } 
   1182         /* 4 alloc vlan bitmap tmp */
   1183         num_vlan = soc_mem_index_count(unit, VLAN_TABm);
   1184         vlan_bitmap_tmp = sal_alloc(SHR_BITALLOCSIZE(num_vlan),
   1185                                     "vlan bitmap tmp");
   1186         if (NULL == vlan_bitmap_tmp) {
   1187             sal_free (member_array);
   1188             goto cleanup;
   1189         }       
   1190         /* 5 get each member vlan bitmap, then or them together */
   1191         for (i = 0; i < member_count; i++) {
   1192             sal_memset(vlan_bitmap_tmp, 0, SHR_BITALLOCSIZE(num_vlan));                           
   1193             rv = _bcm_td_vp_vlan_bitmap_get(
   1194                     unit, member_array[i].gport, vlan_bitmap_tmp);
   1195             if (BCM_FAILURE(rv)) {
   1196                 sal_free (vlan_bitmap_tmp);
   1197                 sal_free (member_array);
   1198                 goto cleanup;
   1199             }
   1200 
   1201             SHR_BITOR_RANGE(
   1202                     vlan_bitmap_tmp, vlan_bitmap, 0, num_vlan, vlan_bitmap);
   1203         }
   1204 
   1205         sal_free (vlan_bitmap_tmp);
   1206         sal_free (member_array);  
   1207         return BCM_E_NONE;
   1208     }
   1209 #endif/*BCM_TRIDENT2_SUPPORT*/
   1210     /* VP does not belong to any VP group. Need to derive VLAN bitmap by
   1211      * searching through each VLAN table entry's BC_IDX/UMC_IDX/UUC_IDX
   1212      * multicast groups to see if VP belongs to their VP replication lists.
   1213      */ 
   1214 
   1215     /* Get one local port on which the VP resides.
   1216      * Even if the VP resides on a trunk group, only one trunk
   1217      * member is needed since all members of a trunk group
   1218      * have the same VP replication list.
   1219      */
   1220     BCM_IF_ERROR_RETURN
   1221         (_bcm_td_vp_local_ports_get(unit,
   1222                                     vp, 1, &local_port, &local_port_count));
   1223     if (local_port_count == 0) {
   1224         return BCM_E_PORT; 
   1225     }
   1226 
   1227     vlan_tab_buf = soc_cm_salloc(unit,
   1228             SOC_MEM_TABLE_BYTES(unit, VLAN_TABm), "VLAN_TAB buffer");
   1229     if (NULL == vlan_tab_buf) {
   1230         rv = BCM_E_MEMORY;
   1231         goto cleanup;
   1232     }
   1233 
   1234     index_min = soc_mem_index_min(unit, VLAN_TABm);
   1235     index_max = soc_mem_index_max(unit, VLAN_TABm);
   1236     rv = soc_mem_read_range(unit, VLAN_TABm, MEM_BLOCK_ANY,
   1237             index_min, index_max, vlan_tab_buf);
   1238     if (SOC_FAILURE(rv)) {
   1239         goto cleanup;
   1240     }
   1241 
   1242     if_max = soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   1243     if_array = sal_alloc(sizeof(bcm_if_t) * if_max, "if_array");
   1244     if (NULL == if_array) {
   1245         rv = BCM_E_MEMORY;
   1246         goto cleanup;
   1247     }
   1248     sal_memset(if_array, 0, sizeof(bcm_if_t) * if_max);
   1249 
   1250     SHR_BITCLR_RANGE(vlan_bitmap, 0, soc_mem_index_count(unit, VLAN_TABm));
   1251 
   1252     for (i = index_min; i <= index_max; i++) {
   1253         vlan_tab_entry = soc_mem_table_idx_to_pointer
   1254             (unit, VLAN_TABm, vlan_tab_entry_t *, vlan_tab_buf, i);
   1255 
   1256         if (0 == soc_VLAN_TABm_field32_get(unit, vlan_tab_entry,
   1257                     VALIDf)) {
   1258             continue;
   1259         }
   1260         
   1261         if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
   1262            if (0 == soc_VLAN_TABm_field32_get(unit, vlan_tab_entry,
   1263                        VIRTUAL_PORT_ENf)) {
   1264                continue;
   1265            }
   1266         }
   1267 
   1268         mc_index_array[0] = soc_VLAN_TABm_field32_get(unit, vlan_tab_entry,
   1269                 BC_IDXf);
   1270         mc_index_array[1] = soc_VLAN_TABm_field32_get(unit, vlan_tab_entry,
   1271                 UMC_IDXf);
   1272         mc_index_array[2] = soc_VLAN_TABm_field32_get(unit, vlan_tab_entry,
   1273                 UUC_IDXf);
   1274 
   1275         for (j = 0; j < 3; j++) {
   1276 
   1277             /* Check if the same mc_index was already searched */
   1278             match_prev_mc_index = FALSE;
   1279             for (k = j - 1; k >= 0; k--) {
   1280                 if (mc_index_array[j] == mc_index_array[k]) {
   1281                     match_prev_mc_index = TRUE;
   1282                     break;
   1283                 }
   1284             }
   1285             if (match_prev_mc_index) {
   1286                 /* continue to next mc_index */
   1287                 continue;
   1288             }
   1289 
   1290             /* Get VP replication list for (mc_index, local_port) */
   1291             rv = bcm_esw_ipmc_egress_intf_get(unit, mc_index_array[j],
   1292                     local_port, if_max, if_array, &if_count);
   1293             if (SOC_FAILURE(rv)) {
   1294                 goto cleanup;
   1295             }
   1296 
   1297             /* Get VP's encap_id */
   1298             _BCM_MULTICAST_GROUP_SET(group, mc_type, mc_index_array[j]);
   1299             rv = bcm_esw_port_gport_get(unit, local_port, &local_gport);
   1300             if (SOC_FAILURE(rv)) {
   1301                 goto cleanup;
   1302             }
   1303             if (BCM_GPORT_IS_VLAN_PORT(vp_gport))  {
   1304                 rv = bcm_esw_multicast_vlan_encap_get(unit, group, local_gport, 
   1305                                               vp_gport, &encap_id);
   1306             } else if (BCM_GPORT_IS_NIV_PORT(vp_gport)) {
   1307                 rv = bcm_esw_multicast_niv_encap_get(unit, group, local_gport, 
   1308                                               vp_gport, &encap_id);
   1309             } else if (BCM_GPORT_IS_EXTENDER_PORT(vp_gport)) {
   1310                 rv = bcm_esw_multicast_extender_encap_get(unit, group, local_gport, 
   1311                                               vp_gport, &encap_id);
   1312             } 
   1313 
   1314 
   1315             if (SOC_FAILURE(rv)) {
   1316                 goto cleanup;
   1317             }
   1318 
   1319             /* Search for VP's encap_id in if_array */
   1320             match = FALSE;
   1321             for (k = 0; k < if_count; k++) {
   1322                 if (encap_id == if_array[k]) {
   1323                     match = TRUE;
   1324                     break;
   1325                 }
   1326             }
   1327             if (match) {
   1328                 break;
   1329             }
   1330         }
   1331 
   1332         if (match) {
   1333             /* VP belongs to this VLAN */
   1334             SHR_BITSET(vlan_bitmap, i);
   1335         }
   1336     }
   1337 
   1338 cleanup:
   1339     if (vlan_tab_buf) {
   1340         soc_cm_sfree(unit, vlan_tab_buf);
   1341     }
   1342 
   1343     if (if_array) {
   1344         sal_free(if_array);
   1345     }
   1346 
   1347     return rv;
   1348 }
   1349 
   1350 /*
   1351  * Function:
   1352  *      _bcm_td_ing_vp_group_join
   1353  * Purpose:
   1354  *      Assign VP to an ingress VP group.
   1355  * Parameters:
   1356  *      unit        - (IN) BCM device number
   1357  *      vp          - (IN) VP number
   1358  *      vlan_bitmap - (IN) Bitmap of VLANs the VP belongs to.
   1359  *      vp_group    - (OUT) Assigned VP group.
   1360  * Returns:
   1361  *      BCM_E_XXX
   1362  */
   1363 STATIC int
   1364 _bcm_td_ing_vp_group_join(int unit, int vp,
   1365         SHR_BITDCL *vlan_bitmap, int *vp_group)
   1366 {
   1367     int i;
   1368     int num_vlan, vid;
   1369     vlan_tab_entry_t vlan_entry;
   1370     uint32 fldbuf[2];
   1371 
   1372     num_vlan = soc_mem_index_count(unit, VLAN_TABLE(unit));
   1373 
   1374     /* First, check if VP's vlan_bitmap matches any existing ingress
   1375      * VP group's vlan_bitmap. If so, assign the VP to the VP group
   1376      * with the matching vlan_bitmap.
   1377      */
   1378     for (i = 0; i < VP_GROUP_BK(unit)->num_ing_vp_group; i++) {
   1379         if ((ING_VP_GROUP(unit, i)->vp_count > 0) &&
   1380             SHR_BITEQ_RANGE(vlan_bitmap, ING_VP_GROUP(unit, i)->vlan_bitmap,
   1381                     0, num_vlan)) {
   1382             *vp_group = i;
   1383             SHR_BITSET(ING_VP_GROUP(unit, i)->vp_bitmap, vp);
   1384             ING_VP_GROUP(unit, i)->vp_count++;
   1385             return BCM_E_NONE;
   1386         }
   1387     }
   1388 
   1389     /* VP's vlan_bitmap does not match any existing VP group's
   1390      * vlan_bitmap. Allocate a new ingress VP group for the VP.
   1391      */
   1392     for (i = 0; i < VP_GROUP_BK(unit)->num_ing_vp_group; i++) {
   1393         if (0 == ING_VP_GROUP(unit, i)->vp_count) {
   1394             *vp_group = i;
   1395             SHR_BITSET(ING_VP_GROUP(unit, i)->vp_bitmap, vp);
   1396             ING_VP_GROUP(unit, i)->vp_count++;
   1397             sal_memcpy(ING_VP_GROUP(unit, i)->vlan_bitmap, vlan_bitmap,
   1398                     SHR_BITALLOCSIZE(num_vlan));
   1399 
   1400             /* Update VLAN table's VP_GROUP_BITMAP field */
   1401             for (vid = 0; vid < num_vlan; vid++) {
   1402                 if (SHR_BITGET(ING_VP_GROUP(unit, i)->vlan_bitmap, vid)) {
   1403                     SOC_IF_ERROR_RETURN
   1404                         (soc_mem_read(unit, VLAN_TABLE(unit), MEM_BLOCK_ANY, vid, &vlan_entry));
   1405                     soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32 *)&vlan_entry,
   1406                             VP_GROUP_BITMAPf, fldbuf);
   1407                     fldbuf[i / 32] |= (1 << (i % 32));
   1408                     soc_mem_field_set(unit, VLAN_TABLE(unit), (uint32 *)&vlan_entry,
   1409                             VP_GROUP_BITMAPf, fldbuf);
   1410                     SOC_IF_ERROR_RETURN
   1411                         (soc_mem_write(unit, VLAN_TABLE(unit), MEM_BLOCK_ALL, vid, &vlan_entry));
   1412                 }
   1413             }
   1414 
   1415             return BCM_E_NONE;
   1416         }
   1417     }
   1418 
   1419     /* An empty VP group is not available. */
   1420     return BCM_E_RESOURCE;
   1421 }
   1422 
   1423 /*
   1424  * Function:
   1425  *      _bcm_td_eg_vp_group_join
   1426  * Purpose:
   1427  *      Assign VP to an egress VP group.
   1428  * Parameters:
   1429  *      unit        - (IN) BCM device number
   1430  *      vp          - (IN) VP number
   1431  *      vlan_bitmap - (IN) Bitmap of VLANs the VP belongs to.
   1432  *      vp_group    - (OUT) Assigned VP group.
   1433  * Returns:
   1434  *      BCM_E_XXX
   1435  */
   1436 STATIC int
   1437 _bcm_td_eg_vp_group_join(int unit, int vp,
   1438         SHR_BITDCL *vlan_bitmap, int *vp_group)
   1439 {
   1440     int i;
   1441     int num_vlan, vid;
   1442     egr_vlan_entry_t egr_vlan_entry;
   1443     uint32 fldbuf[2];
   1444 
   1445     num_vlan = soc_mem_index_count(unit, EGR_VLANm);
   1446 
   1447     /* First, check if VP's vlan_bitmap matches any existing egress
   1448      * VP group's vlan_bitmap. If so, assign the VP to the VP group
   1449      * with the matching vlan_bitmap.
   1450      */
   1451     for (i = 0; i < VP_GROUP_BK(unit)->num_eg_vp_group; i++) {
   1452         if ((EG_VP_GROUP(unit, i)->vp_count > 0) &&
   1453             SHR_BITEQ_RANGE(vlan_bitmap, EG_VP_GROUP(unit, i)->vlan_bitmap,
   1454                     0, num_vlan)) {
   1455             *vp_group = i;
   1456             SHR_BITSET(EG_VP_GROUP(unit, i)->vp_bitmap, vp);
   1457             EG_VP_GROUP(unit, i)->vp_count++;
   1458             return BCM_E_NONE;
   1459         }
   1460     }
   1461 
   1462     /* VP's vlan_bitmap does not match any existing VP group's
   1463      * vlan_bitmap. Allocate a new egress VP group for the VP.
   1464      */
   1465     for (i = 0; i < VP_GROUP_BK(unit)->num_eg_vp_group; i++) {
   1466         if (0 == EG_VP_GROUP(unit, i)->vp_count) {
   1467             *vp_group = i;
   1468             SHR_BITSET(EG_VP_GROUP(unit, i)->vp_bitmap, vp);
   1469             EG_VP_GROUP(unit, i)->vp_count++;
   1470             sal_memcpy(EG_VP_GROUP(unit, i)->vlan_bitmap, vlan_bitmap,
   1471                     SHR_BITALLOCSIZE(num_vlan));
   1472 
   1473             /* Update EGR_VLAN table's VP_GROUP_BITMAP field */
   1474             for (vid = 0; vid < num_vlan; vid++) {
   1475                 if (SHR_BITGET(EG_VP_GROUP(unit, i)->vlan_bitmap, vid)) {
   1476                     SOC_IF_ERROR_RETURN
   1477                         (READ_EGR_VLANm(unit, MEM_BLOCK_ANY, vid,
   1478                                         &egr_vlan_entry));
   1479                     soc_EGR_VLANm_field_get(unit, &egr_vlan_entry,
   1480                             VP_GROUP_BITMAPf, fldbuf);
   1481                     fldbuf[i / 32] |= (1 << (i % 32));
   1482                     soc_EGR_VLANm_field_set(unit, &egr_vlan_entry,
   1483                             VP_GROUP_BITMAPf, fldbuf);
   1484                     SOC_IF_ERROR_RETURN
   1485                         (WRITE_EGR_VLANm(unit, MEM_BLOCK_ALL, vid,
   1486                                          &egr_vlan_entry));
   1487                 }
   1488             }
   1489 
   1490             return BCM_E_NONE;
   1491         }
   1492     }
   1493 
   1494     /* An empty VP group is not available. */
   1495     return BCM_E_RESOURCE;
   1496 }
   1497 
   1498 /*
   1499  * Function:
   1500  *      _bcm_td_ing_vp_group_leave
   1501  * Purpose:
   1502  *      Remove VP from an ingress VP group.
   1503  * Parameters:
   1504  *      unit     - (IN) BCM device number
   1505  *      vp       - (IN) VP number
   1506  *      vp_group - (IN) VP group.
   1507  * Returns:
   1508  *      BCM_E_XXX
   1509  */
   1510 STATIC int
   1511 _bcm_td_ing_vp_group_leave(int unit, int vp, int vp_group)
   1512 {
   1513     int num_vlan, vid;
   1514     vlan_tab_entry_t vlan_entry;
   1515     uint32 fldbuf[2];
   1516 
   1517     SHR_BITCLR(ING_VP_GROUP(unit, vp_group)->vp_bitmap, vp);
   1518     ING_VP_GROUP(unit, vp_group)->vp_count--;
   1519 
   1520     if (0 == ING_VP_GROUP(unit, vp_group)->vp_count) {
   1521 
   1522         /* Clear the bit corresponding to the given VP group in
   1523          * VLAN table's VP_GROUP_BITMAP field
   1524          */
   1525         num_vlan = soc_mem_index_count(unit, VLAN_TABLE(unit));
   1526         for (vid = 0; vid < num_vlan; vid++) {
   1527             if (SHR_BITGET(ING_VP_GROUP(unit, vp_group)->vlan_bitmap, vid)) {
   1528                 SOC_IF_ERROR_RETURN
   1529                     (soc_mem_read(unit, VLAN_TABLE(unit), MEM_BLOCK_ANY, vid, &vlan_entry));
   1530                 soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32 *)&vlan_entry,
   1531                         VP_GROUP_BITMAPf, fldbuf);
   1532                 fldbuf[vp_group / 32] &= ~(1 << (vp_group % 32));
   1533                 soc_mem_field_set(unit, VLAN_TABLE(unit), (uint32 *)&vlan_entry,
   1534                         VP_GROUP_BITMAPf, fldbuf);
   1535                 SOC_IF_ERROR_RETURN
   1536                     (soc_mem_write(unit,  VLAN_TABLE(unit), MEM_BLOCK_ALL, vid, &vlan_entry));
   1537             }
   1538         }
   1539 
   1540         SHR_BITCLR_RANGE(ING_VP_GROUP(unit, vp_group)->vlan_bitmap, 0, num_vlan);
   1541     }
   1542 
   1543     return BCM_E_NONE;
   1544 }
   1545 
   1546 /*
   1547  * Function:
   1548  *      _bcm_td_eg_vp_group_leave
   1549  * Purpose:
   1550  *      Remove VP from an egress VP group.
   1551  * Parameters:
   1552  *      unit     - (IN) BCM device number
   1553  *      vp       - (IN) VP number
   1554  *      vp_group - (IN) VP group.
   1555  * Returns:
   1556  *      BCM_E_XXX
   1557  */
   1558 STATIC int
   1559 _bcm_td_eg_vp_group_leave(int unit, int vp, int vp_group)
   1560 {
   1561     int num_vlan, vid;
   1562     egr_vlan_entry_t egr_vlan_entry;
   1563     uint32 fldbuf[2];
   1564 
   1565     SHR_BITCLR(EG_VP_GROUP(unit, vp_group)->vp_bitmap, vp);
   1566     EG_VP_GROUP(unit, vp_group)->vp_count--;
   1567 
   1568     if (0 == EG_VP_GROUP(unit, vp_group)->vp_count) {
   1569 
   1570         /* Clear the bit corresponding to the given VP group in
   1571          * EGR_VLAN table's VP_GROUP_BITMAP field
   1572          */
   1573         num_vlan = soc_mem_index_count(unit, EGR_VLANm);
   1574         for (vid = 0; vid < num_vlan; vid++) {
   1575             if (SHR_BITGET(EG_VP_GROUP(unit, vp_group)->vlan_bitmap, vid)) {
   1576                 SOC_IF_ERROR_RETURN
   1577                     (READ_EGR_VLANm(unit, MEM_BLOCK_ANY, vid, &egr_vlan_entry));
   1578                 soc_EGR_VLANm_field_get(unit, &egr_vlan_entry,
   1579                         VP_GROUP_BITMAPf, fldbuf);
   1580                 fldbuf[vp_group / 32] &= ~(1 << (vp_group % 32));
   1581                 soc_EGR_VLANm_field_set(unit, &egr_vlan_entry,
   1582                         VP_GROUP_BITMAPf, fldbuf);
   1583                 SOC_IF_ERROR_RETURN
   1584                     (WRITE_EGR_VLANm(unit, MEM_BLOCK_ALL, vid, &egr_vlan_entry));
   1585             }
   1586         }
   1587 
   1588         SHR_BITCLR_RANGE(EG_VP_GROUP(unit, vp_group)->vlan_bitmap, 0, num_vlan);
   1589     }
   1590 
   1591     return BCM_E_NONE;
   1592 }
   1593 
   1594 /*
   1595  * Function:
   1596  *      bcm_td_ing_vp_group_move
   1597  * Purpose:
   1598  *      Move VP from one ingress VP group to another due to add/remove VP
   1599  *      to/from VLAN.
   1600  * Parameters:
   1601  *      unit - (IN) BCM device number
   1602  *      vp   - (IN) VP number
   1603  *      vlan - (IN) VLAN to/from which VP is added or removed
   1604  *      add  - (IN) If TRUE, VP is added to VLAN, else removed from VLAN.
   1605  * Returns:
   1606  *      BCM_E_XXX
   1607  */
   1608 int
   1609 bcm_td_ing_vp_group_move(int unit, int vp, bcm_vlan_t vlan, int add)
   1610 {
   1611     int rv = BCM_E_NONE;
   1612     source_vp_entry_t svp_entry;
   1613     int ifilter_en;
   1614     int old_vp_group, new_vp_group;
   1615     int num_vlan;
   1616     SHR_BITDCL *new_vlan_bitmap = NULL;
   1617 
   1618     SOC_IF_ERROR_RETURN
   1619         (READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   1620     ifilter_en = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
   1621             ENABLE_IFILTERf);
   1622     if (1 != ifilter_en) {
   1623         return BCM_E_DISABLED;
   1624     }
   1625 
   1626     old_vp_group = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
   1627             VLAN_MEMBERSHIP_PROFILEf);
   1628 
   1629     /* Derive VP's new VLAN bitmap by adding/removing VLAN
   1630      * to/from VP group's VLAN bitmap
   1631      */
   1632     num_vlan = soc_mem_index_count(unit, VLAN_TABm);
   1633     new_vlan_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vlan),
   1634             "vlan bitmap");
   1635     if (NULL == new_vlan_bitmap) {
   1636         return BCM_E_MEMORY;
   1637     }
   1638     sal_memset(new_vlan_bitmap, 0, SHR_BITALLOCSIZE(num_vlan));
   1639 
   1640     sal_memcpy(new_vlan_bitmap,
   1641             ING_VP_GROUP(unit, old_vp_group)->vlan_bitmap, 
   1642             SHR_BITALLOCSIZE(num_vlan));
   1643     if (add) {
   1644         SHR_BITSET(new_vlan_bitmap, vlan);
   1645     } else {
   1646         SHR_BITCLR(new_vlan_bitmap, vlan);
   1647     }
   1648 
   1649     /* If VP's new VLAN bitmap is not the same as the VP group's
   1650      * VLAN bitmap, move the VP to another VP group
   1651      */
   1652     if (!SHR_BITEQ_RANGE(new_vlan_bitmap,
   1653                 ING_VP_GROUP(unit, old_vp_group)->vlan_bitmap,
   1654                 0, num_vlan)) {
   1655 
   1656         /* Join a new VP group */
   1657         rv = _bcm_td_ing_vp_group_join(unit, vp, new_vlan_bitmap,
   1658                 &new_vp_group);
   1659         if (BCM_FAILURE(rv)) {
   1660             goto cleanup;
   1661         }
   1662 
   1663         /* Update vp group field */
   1664         soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   1665                 VLAN_MEMBERSHIP_PROFILEf, new_vp_group);
   1666         rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   1667         if (BCM_FAILURE(rv)) {
   1668             goto cleanup;
   1669         }
   1670 
   1671         /* Leave the old VP group */
   1672         rv = _bcm_td_ing_vp_group_leave(unit, vp, old_vp_group);
   1673         if (BCM_FAILURE(rv)) {
   1674             goto cleanup;
   1675         }
   1676     }
   1677 
   1678 cleanup:
   1679     if (new_vlan_bitmap) {
   1680         sal_free(new_vlan_bitmap);
   1681     }
   1682 
   1683     return rv;
   1684 }
   1685 
   1686 /*
   1687  * Function:
   1688  *      bcm_td_eg_vp_group_move
   1689  * Purpose:
   1690  *      Move VP from one egress VP group to another due to add/remove VP
   1691  *      to/from VLAN.
   1692  * Parameters:
   1693  *      unit - (IN) BCM device number
   1694  *      vp   - (IN) VP number
   1695  *      vlan - (IN) VLAN to/from which VP is added or removed
   1696  *      add  - (IN) If TRUE, VP is added to VLAN, else removed from VLAN.
   1697  * Returns:
   1698  *      BCM_E_XXX
   1699  */
   1700 int
   1701 bcm_td_eg_vp_group_move(int unit, int vp, bcm_vlan_t vlan, int add)
   1702 {
   1703     int rv = BCM_E_NONE;
   1704     egr_dvp_attribute_entry_t dvp_entry;
   1705     int efilter_en;
   1706     int old_vp_group, new_vp_group;
   1707     int num_vlan;
   1708     SHR_BITDCL *new_vlan_bitmap = NULL;
   1709     soc_field_t en_efilter_f;
   1710     soc_field_t vm_prof_f;
   1711 
   1712     SOC_IF_ERROR_RETURN
   1713         (READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   1714     BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   1715                 &dvp_entry, EN_EFILTERf, &en_efilter_f));
   1716     efilter_en = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &dvp_entry,
   1717             en_efilter_f);
   1718     if (1 != efilter_en) {
   1719         return BCM_E_DISABLED;
   1720     }
   1721 
   1722     BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   1723                 &dvp_entry, VLAN_MEMBERSHIP_PROFILEf, &vm_prof_f));
   1724     old_vp_group = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &dvp_entry,
   1725             vm_prof_f);
   1726 
   1727     /* Derive VP's new VLAN bitmap by adding/removing VLAN
   1728      * to/from VP group's VLAN bitmap
   1729      */
   1730     num_vlan = soc_mem_index_count(unit, EGR_VLANm);
   1731     new_vlan_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vlan),
   1732             "vlan bitmap");
   1733     if (NULL == new_vlan_bitmap) {
   1734         return BCM_E_MEMORY;
   1735     }
   1736     sal_memset(new_vlan_bitmap, 0, SHR_BITALLOCSIZE(num_vlan));
   1737 
   1738     sal_memcpy(new_vlan_bitmap,
   1739             EG_VP_GROUP(unit, old_vp_group)->vlan_bitmap, 
   1740             SHR_BITALLOCSIZE(num_vlan));
   1741     if (add) {
   1742         SHR_BITSET(new_vlan_bitmap, vlan);
   1743     } else {
   1744         SHR_BITCLR(new_vlan_bitmap, vlan);
   1745     }
   1746 
   1747     /* If VP's new VLAN bitmap is not the same as the VP group's
   1748      * VLAN bitmap, move the VP to another VP group
   1749      */
   1750     if (!SHR_BITEQ_RANGE(new_vlan_bitmap,
   1751                 EG_VP_GROUP(unit, old_vp_group)->vlan_bitmap,
   1752                 0, num_vlan)) {
   1753 
   1754         /* Join a new VP group */
   1755         rv = _bcm_td_eg_vp_group_join(unit, vp, new_vlan_bitmap,
   1756                 &new_vp_group);
   1757         if (BCM_FAILURE(rv)) {
   1758             goto cleanup;
   1759         }
   1760 
   1761         /* Update vp group field */
   1762         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   1763                 vm_prof_f, new_vp_group);
   1764         rv = WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL, vp, &dvp_entry);
   1765         if (BCM_FAILURE(rv)) {
   1766             goto cleanup;
   1767         }
   1768 
   1769         /* Leave the old VP group */
   1770         rv = _bcm_td_eg_vp_group_leave(unit, vp, old_vp_group);
   1771         if (BCM_FAILURE(rv)) {
   1772             goto cleanup;
   1773         }
   1774     }
   1775 
   1776 cleanup:
   1777     if (new_vlan_bitmap) {
   1778         sal_free(new_vlan_bitmap);
   1779     }
   1780 
   1781     return rv;
   1782 }
   1783 
   1784 /*
   1785  * Function:
   1786  *      bcm_td_ing_vp_group_vlan_get_all
   1787  * Purpose:
   1788  *      Get all VPs from the VP groups belonging to the given VLAN.
   1789  * Parameters:
   1790  *      unit - (IN) BCM device number
   1791  *      vlan - (IN) VLAN ID 
   1792  *      vp_bitmap - (OUT) Bitmap of VPs.
   1793  * Returns:
   1794  *      BCM_E_XXX
   1795  */
   1796 int
   1797 bcm_td_ing_vp_group_vlan_get_all(int unit, bcm_vlan_t vlan,
   1798         SHR_BITDCL *vp_bitmap)
   1799 {
   1800     vlan_tab_entry_t vlan_entry;
   1801     uint32 fldbuf[2];
   1802     int i;
   1803 
   1804     SOC_IF_ERROR_RETURN
   1805         (soc_mem_read(unit, VLAN_TABLE(unit), MEM_BLOCK_ANY, vlan, &vlan_entry));
   1806     soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32 *)&vlan_entry, VP_GROUP_BITMAPf, fldbuf);
   1807 
   1808     for (i = 0; i < VP_GROUP_BK(unit)->num_ing_vp_group; i++) {
   1809         if (fldbuf[i / 32] & (1 << (i % 32))) {
   1810             /* The bit in VP_GROUP_BITMAP that corresponds to
   1811              * VP group i is set. Get all VPs in VP group i.
   1812              */
   1813             SHR_BITOR_RANGE(vp_bitmap, ING_VP_GROUP(unit, i)->vp_bitmap,
   1814                     0, soc_mem_index_count(unit, SOURCE_VPm), vp_bitmap);
   1815         }
   1816     }
   1817 
   1818     return BCM_E_NONE;
   1819 }
   1820 
   1821 /*
   1822  * Function:
   1823  *      bcm_td_eg_vp_group_vlan_get_all
   1824  * Purpose:
   1825  *      Get all VPs from the VP groups belonging to the given VLAN.
   1826  * Parameters:
   1827  *      unit - (IN) BCM device number
   1828  *      vlan - (IN) VLAN ID 
   1829  *      vp_bitmap - (OUT) Bitmap of VPs.
   1830  * Returns:
   1831  *      BCM_E_XXX
   1832  */
   1833 int
   1834 bcm_td_eg_vp_group_vlan_get_all(int unit, bcm_vlan_t vlan,
   1835         SHR_BITDCL *vp_bitmap)
   1836 {
   1837     egr_vlan_entry_t egr_vlan_entry;
   1838     uint32 fldbuf[2];
   1839     int i;
   1840 
   1841     SOC_IF_ERROR_RETURN
   1842         (READ_EGR_VLANm(unit, MEM_BLOCK_ANY, vlan, &egr_vlan_entry));
   1843     soc_EGR_VLANm_field_get(unit, &egr_vlan_entry, VP_GROUP_BITMAPf, fldbuf);
   1844 
   1845     for (i = 0; i < VP_GROUP_BK(unit)->num_eg_vp_group; i++) {
   1846         if (fldbuf[i / 32] & (1 << (i % 32))) {
   1847             /* The bit in VP_GROUP_BITMAP that corresponds to
   1848              * VP group i is set. Get all VPs in VP group i.
   1849              */
   1850             SHR_BITOR_RANGE(vp_bitmap, EG_VP_GROUP(unit, i)->vp_bitmap,
   1851                     0, soc_mem_index_count(unit, SOURCE_VPm), vp_bitmap);
   1852         }
   1853     }
   1854 
   1855     return BCM_E_NONE;
   1856 }
   1857 
   1858 /*
   1859  * Function:
   1860  *      bcm_td_ing_vp_group_vlan_delete_all
   1861  * Purpose:
   1862  *      Delete all VP groups from the given VLAN.
   1863  * Parameters:
   1864  *      unit - (IN) BCM device number
   1865  *      vlan - (IN) VLAN ID 
   1866  * Returns:
   1867  *      BCM_E_XXX
   1868  */
   1869 int
   1870 bcm_td_ing_vp_group_vlan_delete_all(int unit, bcm_vlan_t vlan)
   1871 {
   1872     vlan_tab_entry_t vlan_entry;
   1873     uint32 fldbuf[2];
   1874     int i, k;
   1875     int vp_bitmap_bit_size;
   1876 
   1877     SOC_IF_ERROR_RETURN
   1878         (soc_mem_read(unit, VLAN_TABLE(unit), MEM_BLOCK_ANY, vlan, &vlan_entry));
   1879     soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32 *)&vlan_entry, VP_GROUP_BITMAPf, fldbuf);
   1880 
   1881     for (i = 0; i < VP_GROUP_BK(unit)->num_ing_vp_group; i++) {
   1882         if (fldbuf[i / 32] & (1 << (i % 32))) {
   1883             /* The bit in VP_GROUP_BITMAP that corresponds to
   1884              * VP group i is set. Then remove all VPs in VP group i
   1885              * from VLAN.
   1886              */
   1887             vp_bitmap_bit_size = soc_mem_index_count(unit, SOURCE_VPm);
   1888             for (k = 0; k < vp_bitmap_bit_size; k++) {
   1889                 if (SHR_BITGET(ING_VP_GROUP(unit, i)->vp_bitmap, k)) {
   1890                     /* VP k belongs to VP group i */
   1891                     BCM_IF_ERROR_RETURN
   1892                         (bcm_td_ing_vp_group_move(unit, k, vlan, FALSE));  
   1893                 }
   1894             }
   1895         }
   1896     }
   1897 
   1898     return BCM_E_NONE;
   1899 }
   1900 
   1901 /*
   1902  * Function:
   1903  *      bcm_td_eg_vp_group_vlan_delete_all
   1904  * Purpose:
   1905  *      Delete all VP groups from the given VLAN.
   1906  * Parameters:
   1907  *      unit - (IN) BCM device number
   1908  *      vlan - (IN) VLAN ID 
   1909  * Returns:
   1910  *      BCM_E_XXX
   1911  */
   1912 int
   1913 bcm_td_eg_vp_group_vlan_delete_all(int unit, bcm_vlan_t vlan)
   1914 {
   1915     egr_vlan_entry_t egr_vlan_entry;
   1916     uint32 fldbuf[2];
   1917     int i, k;
   1918     int vp_bitmap_bit_size;
   1919 
   1920     SOC_IF_ERROR_RETURN
   1921         (READ_EGR_VLANm(unit, MEM_BLOCK_ANY, vlan, &egr_vlan_entry));
   1922     soc_EGR_VLANm_field_get(unit, &egr_vlan_entry, VP_GROUP_BITMAPf, fldbuf);
   1923 
   1924     for (i = 0; i < VP_GROUP_BK(unit)->num_eg_vp_group; i++) {
   1925         if (fldbuf[i / 32] & (1 << (i % 32))) {
   1926             /* The bit in VP_GROUP_BITMAP that corresponds to
   1927              * VP group i is set. Then remove all VPs in VP group i
   1928              * from VLAN.
   1929              */
   1930             vp_bitmap_bit_size = soc_mem_index_count(unit, EGR_DVP_ATTRIBUTEm);
   1931             for (k = 0; k < vp_bitmap_bit_size; k++) {
   1932                 if (SHR_BITGET(EG_VP_GROUP(unit, i)->vp_bitmap, k)) {
   1933                     /* VP k belongs to VP group i */
   1934                     BCM_IF_ERROR_RETURN
   1935                         (bcm_td_eg_vp_group_move(unit, k, vlan, FALSE));  
   1936                 }
   1937             }
   1938         }
   1939     }
   1940 
   1941     return BCM_E_NONE;
   1942 }
   1943 
   1944 /*
   1945  * Function:
   1946  *      bcm_td_vp_vlan_member_set
   1947  * Purpose:
   1948  *      Set virtual port ingress and egress filter modes.
   1949  * Parameters:
   1950  *      unit  - (IN) BCM device number
   1951  *      gport - (IN) VP gport ID 
   1952  *      flags - (IN) Ingress and egress filter modes.
   1953  * Returns:
   1954  *      BCM_E_XXX
   1955  */
   1956 int
   1957 bcm_td_vp_vlan_member_set(int unit, bcm_gport_t gport, uint32 flags)
   1958 {
   1959     int rv = BCM_E_NONE;
   1960     int vp;
   1961     bcm_vlan_port_t vlan_vp;
   1962     bcm_gport_t phy_port_trunk;
   1963     int is_local;
   1964     source_vp_entry_t svp_entry;
   1965     egr_dvp_attribute_entry_t dvp_entry;
   1966     int old_ifilter_en, old_efilter_en;
   1967     int old_vp_group, vp_group;
   1968     int num_vlan;
   1969     SHR_BITDCL *vlan_bitmap = NULL;
   1970     soc_field_t   en_efilter_f;
   1971     soc_field_t   vm_prof_f;
   1972 
   1973     if (flags & BCM_PORT_VLAN_MEMBER_INGRESS) {
   1974         if (!soc_feature(unit, soc_feature_vp_group_ingress_vlan_membership)) {
   1975             return BCM_E_UNAVAIL;
   1976         }
   1977     }
   1978 
   1979     if (flags & BCM_PORT_VLAN_MEMBER_EGRESS) {
   1980         if (!soc_feature(unit, soc_feature_vp_group_egress_vlan_membership)) {
   1981             return BCM_E_UNAVAIL;
   1982         }
   1983     }
   1984 
   1985     if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   1986         vp = BCM_GPORT_VLAN_PORT_ID_GET(gport);
   1987 
   1988         /* Get the physical port or trunk the VP resides on */
   1989         bcm_vlan_port_t_init(&vlan_vp);
   1990         BCM_GPORT_VLAN_PORT_ID_SET(vlan_vp.vlan_port_id, vp);
   1991         BCM_IF_ERROR_RETURN(bcm_tr2_vlan_vp_find(unit, &vlan_vp));
   1992         phy_port_trunk = vlan_vp.port;
   1993 
   1994     } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   1995         bcm_niv_port_t niv_port;
   1996         bcm_niv_egress_t niv_egress;
   1997         int              count;
   1998 
   1999         vp = BCM_GPORT_NIV_PORT_ID_GET(gport);
   2000 
   2001         /* Get the physical port or trunk the VP resides on */
   2002         bcm_niv_port_t_init(&niv_port);
   2003         BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, vp);
   2004         BCM_IF_ERROR_RETURN(bcm_trident_niv_port_get(unit, &niv_port));
   2005         if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) {
   2006             phy_port_trunk = BCM_GPORT_INVALID;
   2007             bcm_niv_egress_t_init(&niv_egress);
   2008             rv = bcm_trident_niv_egress_get(unit, niv_port.niv_port_id,
   2009                                             1, &niv_egress, &count);
   2010             if (BCM_SUCCESS(rv)) {
   2011                 if (!(niv_egress.flags & BCM_NIV_EGRESS_MULTICAST)) {
   2012                     phy_port_trunk = niv_egress.port;
   2013                 } 
   2014             }
   2015         } else {
   2016             phy_port_trunk = niv_port.port;
   2017         }
   2018 #ifdef BCM_TRIUMPH3_SUPPORT
   2019     } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   2020         bcm_extender_port_t extender_port;
   2021         bcm_extender_egress_t extender_egress;
   2022         int count;
   2023         vp = BCM_GPORT_EXTENDER_PORT_ID_GET(gport);
   2024 
   2025         /* Get the physical port or trunk the VP resides on */
   2026         bcm_extender_port_t_init(&extender_port);
   2027         BCM_GPORT_EXTENDER_PORT_ID_SET(extender_port.extender_port_id, vp);
   2028         BCM_IF_ERROR_RETURN(bcm_tr3_extender_port_get(unit, &extender_port));
   2029         if (extender_port.flags & BCM_EXTENDER_PORT_MATCH_NONE) {
   2030             phy_port_trunk = BCM_GPORT_INVALID;
   2031             bcm_extender_egress_t_init(&extender_egress);
   2032             rv = bcm_tr3_extender_egress_get_all(unit,
   2033                         extender_port.extender_port_id, 1, &extender_egress, &count);
   2034             if (count == 0) {
   2035                 /* No Extender egress object has been added to VP yet. */
   2036                 return BCM_E_CONFIG;
   2037             }
   2038             if (BCM_SUCCESS(rv)) {
   2039                 if (!extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) {
   2040                     phy_port_trunk = extender_egress.port;
   2041                 }
   2042             }
   2043         } else {
   2044             phy_port_trunk = extender_port.port;
   2045         }
   2046 #endif /* BCM_TRIUMPH3_SUPPORT */
   2047     } else if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   2048         vp = BCM_GPORT_MPLS_PORT_ID_GET(gport);
   2049         phy_port_trunk = BCM_GPORT_INVALID;
   2050     } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   2051         vp = BCM_GPORT_VXLAN_PORT_ID_GET(gport);
   2052         phy_port_trunk = BCM_GPORT_INVALID;
   2053     } else if (BCM_GPORT_IS_TRUNK(gport)) {
   2054         BCM_IF_ERROR_RETURN(
   2055             _bcm_esw_trunk_tid_to_vp_lag_vp(unit, 
   2056                                             BCM_GPORT_TRUNK_GET(gport), &vp));
   2057         phy_port_trunk = BCM_GPORT_INVALID;
   2058     } else {
   2059         return BCM_E_PARAM;
   2060     }
   2061 
   2062     /* If gport is invalid or cleanning-up the vp membership, 
   2063        ignore is_local check */
   2064     if (phy_port_trunk != BCM_GPORT_INVALID 
   2065         && (flags & (BCM_PORT_VLAN_MEMBER_INGRESS |
   2066                      BCM_PORT_VLAN_MEMBER_EGRESS))) {
   2067         BCM_IF_ERROR_RETURN
   2068             (_bcm_td_phy_port_trunk_is_local(unit, phy_port_trunk, &is_local));
   2069         if (!is_local) {
   2070             /* Ingress and egress filter modes can be set only on local VPs */
   2071             return BCM_E_PORT;
   2072         }
   2073     }
   2074 
   2075     /* Set ingress filter mode */
   2076 
   2077 #ifdef BCM_TRIDENT2_SUPPORT
   2078     if (soc_feature(unit, soc_feature_ing_vp_vlan_membership) &&
   2079        (flags & BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP)) {
   2080         SOC_IF_ERROR_RETURN
   2081             (READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   2082         old_ifilter_en = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
   2083                 ENABLE_IFILTERf);
   2084         if (flags & BCM_PORT_VLAN_MEMBER_INGRESS) { 
   2085             /* td2 hash table */
   2086             if (0 == old_ifilter_en) {
   2087                 /* enable hash table */
   2088                 soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2089                     ENABLE_IFILTERf, 2);
   2090                 SOC_IF_ERROR_RETURN(WRITE_SOURCE_VPm(unit, 
   2091                                 MEM_BLOCK_ALL, vp, &svp_entry));
   2092             }
   2093 
   2094             if (soc_feature(unit, soc_feature_vp_group_ingress_vlan_membership)
   2095                 && (1 == old_ifilter_en)) {
   2096                 /* Update ingress filter enable and vp group fields */
   2097                 old_vp_group = soc_SOURCE_VPm_field32_get(
   2098                     unit, &svp_entry, VLAN_MEMBERSHIP_PROFILEf);
   2099                 soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2100                                            ENABLE_IFILTERf, 2);
   2101                 if (!bcm_td_ing_vp_group_unmanaged_get(unit)) {
   2102                     soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2103                                                VLAN_MEMBERSHIP_PROFILEf, 0);
   2104                 }
   2105                 BCM_IF_ERROR_RETURN(
   2106                     WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry));
   2107                 if (!bcm_td_ing_vp_group_unmanaged_get(unit)) {
   2108                     /* Remove VP from VP group */
   2109                     BCM_IF_ERROR_RETURN(
   2110                         _bcm_td_ing_vp_group_leave(unit, vp, old_vp_group));
   2111                 }    
   2112             }
   2113         } else {
   2114             if (2 == old_ifilter_en) {
   2115                 soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2116                         ENABLE_IFILTERf, 0);
   2117                 BCM_IF_ERROR_RETURN
   2118                     (WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry));
   2119             }
   2120         }
   2121     } else 
   2122 #endif
   2123     if (soc_feature(unit, soc_feature_vp_group_ingress_vlan_membership)) {
   2124 
   2125         SOC_IF_ERROR_RETURN
   2126             (READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   2127         old_ifilter_en = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
   2128                 ENABLE_IFILTERf);
   2129         old_vp_group = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
   2130                 VLAN_MEMBERSHIP_PROFILEf);
   2131 
   2132         if (flags & BCM_PORT_VLAN_MEMBER_INGRESS) {
   2133             if (0 == old_ifilter_en 
   2134 #ifdef BCM_TRIDENT2_SUPPORT
   2135                 || (soc_feature(unit, soc_feature_ing_vp_vlan_membership)
   2136                 && (2 == old_ifilter_en))
   2137 #endif
   2138             ) {
   2139                 /* Enable ingress filtering */
   2140                 if (!bcm_td_ing_vp_group_unmanaged_get(unit)) {
   2141                     /* Get all the VLANs this VP belongs to */
   2142                     num_vlan = soc_mem_index_count(unit, VLAN_TABm);
   2143                     vlan_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vlan),
   2144                             "vlan bitmap");
   2145                     if (NULL == vlan_bitmap) {
   2146                         return BCM_E_MEMORY;
   2147                     }
   2148                     sal_memset(vlan_bitmap, 0, SHR_BITALLOCSIZE(num_vlan));
   2149                     rv = _bcm_td_vp_vlan_bitmap_get(unit, gport, vlan_bitmap);
   2150                     if (BCM_FAILURE(rv)) {
   2151                         goto cleanup;
   2152                     }
   2153     
   2154                     /* Assign VP to an ingress VP group */ 
   2155                     rv = _bcm_td_ing_vp_group_join(unit, vp, vlan_bitmap,
   2156                             &vp_group);
   2157                     if (BCM_FAILURE(rv)) {
   2158                         goto cleanup;
   2159                     }
   2160 
   2161                     soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2162                         VLAN_MEMBERSHIP_PROFILEf, vp_group);
   2163                 }
   2164                 /* Update ingress filter enable and vp group fields */
   2165                 soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2166                         ENABLE_IFILTERf, 1);
   2167                 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   2168                 if (BCM_FAILURE(rv)) {
   2169                     goto cleanup;
   2170                 }
   2171 
   2172                 if (vlan_bitmap) {
   2173                     sal_free(vlan_bitmap);
   2174                     vlan_bitmap = NULL;
   2175                 }
   2176             }
   2177         } else {
   2178             if (1 == old_ifilter_en) {
   2179                 /* Disable ingress filtering */
   2180 
   2181                 /* Update ingress filter enable and vp group fields */
   2182                 soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2183                         ENABLE_IFILTERf, 0);
   2184                 if (!bcm_td_ing_vp_group_unmanaged_get(unit)) {
   2185                     soc_SOURCE_VPm_field32_set(unit, &svp_entry,
   2186                         VLAN_MEMBERSHIP_PROFILEf, 0);
   2187                 }
   2188                 BCM_IF_ERROR_RETURN
   2189                     (WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry));
   2190                 if (!bcm_td_ing_vp_group_unmanaged_get(unit)) {
   2191                     /* Remove VP from VP group */
   2192                     BCM_IF_ERROR_RETURN
   2193                         (_bcm_td_ing_vp_group_leave(unit, vp, old_vp_group));
   2194                 }
   2195             }
   2196         }
   2197     }
   2198 
   2199     SOC_IF_ERROR_RETURN
   2200         (READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   2201     BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   2202                  &dvp_entry, EN_EFILTERf, &en_efilter_f));
   2203     BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   2204                  &dvp_entry, VLAN_MEMBERSHIP_PROFILEf, &vm_prof_f));
   2205 
   2206     /* Set egress filter mode */
   2207 
   2208 #ifdef BCM_TRIDENT2_SUPPORT
   2209     if (soc_feature(unit, soc_feature_egr_vp_vlan_membership) &&
   2210        (flags & BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP)) { 
   2211         old_efilter_en = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, 
   2212                            &dvp_entry, en_efilter_f);
   2213         /* td2 hash table */
   2214         if (flags & BCM_PORT_VLAN_MEMBER_EGRESS) {
   2215             if (0 == old_efilter_en) {
   2216                 /* enable hash table */
   2217                 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2218                         en_efilter_f, 2);
   2219                 BCM_IF_ERROR_RETURN(WRITE_EGR_DVP_ATTRIBUTEm(unit, 
   2220                                   MEM_BLOCK_ALL, vp, &dvp_entry));
   2221             }
   2222 
   2223             if (soc_feature(unit, soc_feature_vp_group_egress_vlan_membership)
   2224                 && (1 == old_efilter_en)) {
   2225                 /* Update egress filter enable and vp group fields */
   2226                 old_vp_group = soc_EGR_DVP_ATTRIBUTEm_field32_get(
   2227                     unit, &dvp_entry, vm_prof_f);
   2228                 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2229                                                    en_efilter_f, 2);
   2230                 if (!bcm_td_egr_vp_group_unmanaged_get(unit)) {
   2231                     soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2232                                                        vm_prof_f, 0);
   2233                 }
   2234                 BCM_IF_ERROR_RETURN(WRITE_EGR_DVP_ATTRIBUTEm(
   2235                     unit, MEM_BLOCK_ALL, vp, &dvp_entry));
   2236                 if (!bcm_td_egr_vp_group_unmanaged_get(unit)) {
   2237                     /* Remove VP from VP group */
   2238                     BCM_IF_ERROR_RETURN(
   2239                         _bcm_td_eg_vp_group_leave(unit, vp, old_vp_group));
   2240                 }
   2241             }
   2242         } else {
   2243            if (2 == old_efilter_en) {
   2244                 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2245                                     en_efilter_f, 0);
   2246                 BCM_IF_ERROR_RETURN(WRITE_EGR_DVP_ATTRIBUTEm(unit, 
   2247                                   MEM_BLOCK_ALL, vp, &dvp_entry));
   2248             }
   2249         }
   2250     } else 
   2251 #endif
   2252     if (soc_feature(unit, soc_feature_vp_group_egress_vlan_membership)) {
   2253         old_efilter_en = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &dvp_entry,
   2254                                  en_efilter_f);
   2255         old_vp_group = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &dvp_entry,
   2256                                      vm_prof_f);
   2257         if (flags & BCM_PORT_VLAN_MEMBER_EGRESS) {
   2258             if (0 == old_efilter_en
   2259 #ifdef BCM_TRIDENT2_SUPPORT
   2260                 || (soc_feature(unit, soc_feature_egr_vp_vlan_membership)
   2261                 && (2 == old_efilter_en))
   2262 #endif
   2263             ) {
   2264                 /* Enable egress filtering */
   2265                 if (!bcm_td_egr_vp_group_unmanaged_get(unit)) {
   2266                     /* Get all the VLANs this VP belongs to */
   2267                     num_vlan = soc_mem_index_count(unit, EGR_VLANm);
   2268                     vlan_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vlan),
   2269                             "vlan bitmap");
   2270                     if (NULL == vlan_bitmap) {
   2271                         return BCM_E_MEMORY;
   2272                     }
   2273                     sal_memset(vlan_bitmap, 0, SHR_BITALLOCSIZE(num_vlan));
   2274                     rv = _bcm_td_vp_vlan_bitmap_get(unit, gport, vlan_bitmap);
   2275                     if (BCM_FAILURE(rv)) {
   2276                         goto cleanup;
   2277                     }
   2278     
   2279                     /* Assign VP to an egress VP group */ 
   2280                     rv = _bcm_td_eg_vp_group_join(unit, vp, vlan_bitmap,
   2281                             &vp_group);
   2282                     if (BCM_FAILURE(rv)) {
   2283                         goto cleanup;
   2284                     }
   2285     
   2286                     soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2287                                                        vm_prof_f, vp_group);
   2288                 }
   2289                 /* Update egress filter enable and vp group fields */
   2290                 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2291                         en_efilter_f, 1);
   2292                 rv = WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL, vp, &dvp_entry);
   2293                 if (BCM_FAILURE(rv)) {
   2294                     goto cleanup;
   2295                 }
   2296 
   2297                 if (vlan_bitmap) {
   2298                     sal_free(vlan_bitmap);
   2299                     vlan_bitmap = NULL;
   2300                 }
   2301             }
   2302         } else {
   2303             if (1 == old_efilter_en) {
   2304                 /* Disable egress filtering */
   2305 
   2306                 /* Update egress filter enable and vp group fields */
   2307                 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2308                         en_efilter_f, 0);
   2309                 if (!bcm_td_egr_vp_group_unmanaged_get(unit)) {
   2310                     soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &dvp_entry,
   2311                         vm_prof_f, 0);
   2312                 }
   2313                 BCM_IF_ERROR_RETURN
   2314                     (WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL, vp, &dvp_entry));
   2315 
   2316                 if (!bcm_td_egr_vp_group_unmanaged_get(unit)) {
   2317                     /* Remove VP from VP group */
   2318                     BCM_IF_ERROR_RETURN
   2319                         (_bcm_td_eg_vp_group_leave(unit, vp, old_vp_group));
   2320                 }
   2321             }
   2322         }
   2323     }
   2324 
   2325 cleanup:
   2326     if (vlan_bitmap) {
   2327         sal_free(vlan_bitmap);
   2328     }
   2329 
   2330     return rv;
   2331 }
   2332 
   2333 /*
   2334  * Function:
   2335  *      bcm_td_vp_vlan_member_get
   2336  * Purpose:
   2337  *      Get virtual port ingress and egress filter modes.
   2338  * Parameters:
   2339  *      unit  - (IN) BCM device number
   2340  *      gport - (IN) VP gport id
   2341  *      flags - (OUT) Ingress and egress filter modes.
   2342  * Returns:
   2343  *      BCM_E_XXX
   2344  */
   2345 int
   2346 bcm_td_vp_vlan_member_get(int unit, bcm_gport_t gport, uint32 *flags)
   2347 {
   2348     int vp;
   2349     source_vp_entry_t svp_entry;
   2350     int ifilter_en;
   2351     egr_dvp_attribute_entry_t dvp_entry;
   2352     int efilter_en;
   2353     soc_field_t en_efilter_f;
   2354 
   2355     if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   2356         vp = BCM_GPORT_VLAN_PORT_ID_GET(gport);
   2357     } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   2358         vp = BCM_GPORT_NIV_PORT_ID_GET(gport);
   2359     } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   2360         vp = BCM_GPORT_EXTENDER_PORT_ID_GET(gport);
   2361     } else if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   2362         vp = BCM_GPORT_MPLS_PORT_ID_GET(gport);
   2363     } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   2364         vp = BCM_GPORT_VXLAN_PORT_ID_GET(gport);
   2365     } else if (BCM_GPORT_IS_TRUNK(gport)) {
   2366         BCM_IF_ERROR_RETURN(
   2367             _bcm_esw_trunk_tid_to_vp_lag_vp(unit, 
   2368                                             BCM_GPORT_TRUNK_GET(gport), &vp));
   2369     } else {
   2370         return BCM_E_PARAM;
   2371     }
   2372 
   2373     *flags = 0;
   2374 
   2375     if (soc_feature(unit, soc_feature_vp_group_ingress_vlan_membership)) {
   2376         SOC_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   2377         ifilter_en = soc_SOURCE_VPm_field32_get(unit, &svp_entry, ENABLE_IFILTERf);
   2378         if (ifilter_en == 1) {
   2379             *flags |= BCM_PORT_VLAN_MEMBER_INGRESS;
   2380         }
   2381     }
   2382 
   2383 #ifdef BCM_TRIDENT2_SUPPORT
   2384     if (soc_feature(unit, soc_feature_ing_vp_vlan_membership)) {
   2385         SOC_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   2386         ifilter_en = soc_SOURCE_VPm_field32_get(unit, &svp_entry, ENABLE_IFILTERf);
   2387         if (ifilter_en == 2) {
   2388             *flags |= BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP |
   2389                       BCM_PORT_VLAN_MEMBER_INGRESS;
   2390         }
   2391     } 
   2392 #endif
   2393 
   2394 
   2395     if (soc_feature(unit, soc_feature_vp_group_egress_vlan_membership)) {
   2396         SOC_IF_ERROR_RETURN
   2397             (READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   2398         BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   2399                  &dvp_entry, EN_EFILTERf, &en_efilter_f));
   2400         efilter_en = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &dvp_entry,
   2401                 en_efilter_f);
   2402         if (efilter_en == 1) {
   2403             *flags |= BCM_PORT_VLAN_MEMBER_EGRESS;
   2404         }
   2405     }
   2406 #ifdef BCM_TRIDENT2_SUPPORT
   2407     if (soc_feature(unit, soc_feature_egr_vp_vlan_membership)) {
   2408         SOC_IF_ERROR_RETURN
   2409             (READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   2410         BCM_IF_ERROR_RETURN(_td_egr_dvp_attribute_field_name_get(unit,
   2411                  &dvp_entry, EN_EFILTERf, &en_efilter_f));
   2412         efilter_en = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &dvp_entry,
   2413                 en_efilter_f);
   2414         if (efilter_en == 2) {
   2415             *flags |= BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP |
   2416                       BCM_PORT_VLAN_MEMBER_EGRESS;
   2417         }
   2418     } 
   2419 #endif
   2420 
   2421     return BCM_E_NONE;
   2422 }
   2423 
   2424 /*
   2425  * Function:
   2426  *      bcm_td_ing_vp_group_unmanaged_get
   2427  * Purpose:
   2428  *      Check if VP group resource is managed by user. If so, user will be
   2429  *      resposible to assign a VP group to a VP and add the VP group to the
   2430  *      vlan's VP group bitmap in order to establish the vlan membership.
   2431  * Parameters:
   2432  *      unit  - (IN) BCM device number
   2433  * Returns:
   2434  *      TRUE/FALSE
   2435  */
   2436 int
   2437 bcm_td_ing_vp_group_unmanaged_get(int unit)
   2438 {
   2439     return _bcm_td_vp_group_unmanaged[unit].ingress;
   2440 }
   2441 
   2442 int
   2443 bcm_td_egr_vp_group_unmanaged_get(int unit)
   2444 {
   2445     return _bcm_td_vp_group_unmanaged[unit].egress;
   2446 }
   2447 
   2448 /*
   2449  * Function:
   2450  *      bcm_td_ing_vp_group_unmanaged_set
   2451  * Purpose:
   2452  *      Set whether the VP group resource is managed by user.
   2453  * Parameters:
   2454  *      unit  - (IN) BCM device number
   2455         unmanaged - (IN) TRUE/FALSE
   2456  * Returns: BCM_E_XXX 
   2457  */
   2458 int
   2459 bcm_td_ing_vp_group_unmanaged_set(int unit, int flag)
   2460 {
   2461     int num_vp_groups;
   2462     int vp_count;
   2463     int i;
   2464 
   2465     /* check if to set the same value */
   2466     if (_bcm_td_vp_group_unmanaged[unit].ingress == flag) {
   2467         return BCM_E_NONE;
   2468     }
   2469 
   2470     /* make sure auto method hasn't kicked in yet */
   2471     if (VP_GROUP_BK(unit)->vp_group_initialized) {
   2472         num_vp_groups = soc_mem_field_length(unit, VLAN_TABLE(unit), VP_GROUP_BITMAPf);
   2473 
   2474         for (vp_count = 0,i = 0; i < VP_GROUP_BK(unit)->num_ing_vp_group; i++) {
   2475             if (0 == ING_VP_GROUP(unit, i)->vp_count) {
   2476                 vp_count++;
   2477             }
   2478         }
   2479 
   2480         if (vp_count != num_vp_groups) {
   2481             LOG_WARN(BSL_LS_BCM_VLAN,
   2482                      (BSL_META_U(unit,
   2483                                  "Unmanaged mode set fails: VP group auto method already started\n")));
   2484             return BCM_E_EXISTS;
   2485         }
   2486     }
   2487     _bcm_td_vp_group_unmanaged[unit].ingress = flag;
   2488     return BCM_E_NONE;
   2489 }
   2490 
   2491 int
   2492 bcm_td_egr_vp_group_unmanaged_set(int unit, int flag)
   2493 {
   2494     int num_vp_groups;
   2495     int vp_count;
   2496     int i;
   2497 
   2498     /* check if to set the same value */
   2499     if (_bcm_td_vp_group_unmanaged[unit].egress == flag) {
   2500         return BCM_E_NONE;
   2501     }
   2502 
   2503     /* make sure auto method hasn't kicked in yet */
   2504     if (VP_GROUP_BK(unit)->vp_group_initialized) {
   2505         num_vp_groups = soc_mem_field_length(unit, EGR_VLANm, VP_GROUP_BITMAPf);
   2506 
   2507         for (vp_count = 0,i = 0; i < VP_GROUP_BK(unit)->num_eg_vp_group; i++) {
   2508             if (0 == EG_VP_GROUP(unit, i)->vp_count) {
   2509                 vp_count++;
   2510             }
   2511         }
   2512 
   2513         if (vp_count != num_vp_groups) {
   2514             LOG_WARN(BSL_LS_BCM_VLAN,
   2515                      (BSL_META_U(unit,
   2516                                  "Unmanaged mode set fails: VP group auto method already started\n")));
   2517 
   2518             return BCM_E_EXISTS;
   2519         }
   2520     }
   2521     _bcm_td_vp_group_unmanaged[unit].egress = flag;
   2522     return BCM_E_NONE;
   2523 }
   2524 
   2525 
   2526 
   2527 #endif /* BCM_TRIDENT_SUPPORT && INCLUDE_L3 */