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


      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 functions
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <soc/defs.h>
     14 #include <sal/core/libc.h>
     15 #if defined(BCM_ENDURO_SUPPORT) && defined(INCLUDE_L3) 
     16 
     17 #include <soc/drv.h>
     18 #include <soc/scache.h>
     19 #include <soc/hash.h>
     20 
     21 #include <bcm/error.h>
     22 
     23 #include <bcm_int/esw_dispatch.h>
     24 #include <bcm_int/api_xlate_port.h>
     25 
     26 #include <bcm_int/common/multicast.h>
     27 #include <bcm_int/esw/multicast.h>
     28 #include <bcm_int/esw/virtual.h>
     29 #include <bcm_int/esw/vlan.h>
     30 #include <bcm_int/esw/firebolt.h>
     31 #include <bcm_int/esw/trx.h>
     32 #include <bcm_int/esw/triumph2.h>
     33 #include <bcm_int/esw/enduro.h>
     34 #include <bcm_int/esw/stack.h>
     35 #include <bcm_int/esw/ipmc.h>
     36 
     37 typedef struct _bcm_enduro_vlan_vp_info_s {
     38     bcm_vlan_port_match_t criteria;
     39     uint32 flags;
     40     bcm_vlan_t match_vlan;
     41     bcm_vlan_t match_inner_vlan;
     42     bcm_vlan_t egress_vlan;
     43     bcm_gport_t port;
     44 } _bcm_enduro_vlan_vp_info_t;
     45 
     46 /*
     47  * Software book keeping for VLAN virtual related information
     48  */
     49 typedef struct _bcm_enduro_vlan_virtual_bookkeeping_s {
     50     int vlan_virtual_initialized; /* Flag to check initialized status */
     51     sal_mutex_t vlan_virtual_mutex; /* VLAN virtual module lock */
     52     _bcm_enduro_vlan_vp_info_t *port_info; /* VP state */
     53 } _bcm_enduro_vlan_virtual_bookkeeping_t;
     54 
     55 STATIC _bcm_enduro_vlan_virtual_bookkeeping_t _bcm_enduro_vlan_virtual_bk_info[BCM_MAX_NUM_UNITS];
     56 
     57 #define VLAN_VIRTUAL_INFO(unit) (&_bcm_enduro_vlan_virtual_bk_info[unit])
     58 
     59 #define VLAN_VIRTUAL_INIT(unit)                                   \
     60     do {                                                          \
     61         if ((unit < 0) || (unit >= BCM_MAX_NUM_UNITS)) {          \
     62             return BCM_E_UNIT;                                    \
     63         }                                                         \
     64         if (!VLAN_VIRTUAL_INFO(unit)->vlan_virtual_initialized) { \
     65             return BCM_E_INIT;                                    \
     66         }                                                         \
     67     } while (0)
     68 
     69 #define VLAN_VIRTUAL_LOCK(unit) \
     70         sal_mutex_take(VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex, sal_mutex_FOREVER);
     71 
     72 #define VLAN_VIRTUAL_UNLOCK(unit) \
     73         sal_mutex_give(VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex);
     74 
     75 #define VLAN_VP_INFO(unit, vp) (&VLAN_VIRTUAL_INFO(unit)->port_info[vp])
     76 
     77 /*
     78  * Function:
     79  *      _bcm_enduro_vlan_vp_port_cnt_update
     80  * Purpose:
     81  *      Update port's VP count.
     82  * Parameters:
     83  *      unit  - (IN) SOC unit number. 
     84  *      gport - (IN) GPORT ID.
     85  *      vp    - (IN) Virtual port number.
     86  *      incr  - (IN) If TRUE, increment VP count, else decrease VP count.
     87  * Returns:
     88  *      BCM_X_XXX
     89  */
     90 STATIC int
     91 _bcm_enduro_vlan_vp_port_cnt_update(int unit, bcm_gport_t gport,
     92         int vp, int incr)
     93 {
     94     int mod_out, port_out, tgid_out, id_out;
     95     int idx;
     96     int mod_local;
     97     _bcm_port_info_t *port_info;
     98     int local_member_count;
     99     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
    100     uint32 port_flags;
    101 
    102     BCM_IF_ERROR_RETURN
    103         (_bcm_esw_gport_resolve(unit, gport, &mod_out, 
    104                                 &port_out, &tgid_out, &id_out));
    105     if (-1 != id_out) {
    106         return BCM_E_PARAM;
    107     }
    108 
    109     /* Update the physical port's SW state. If associated with a trunk,
    110      * update each local physical port's SW state.
    111      */
    112 
    113     if (BCM_TRUNK_INVALID != tgid_out) {
    114 
    115         BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, tgid_out,
    116                     SOC_MAX_NUM_PORTS, local_member_array, &local_member_count));
    117 
    118         for (idx = 0; idx < local_member_count; idx++) {
    119             _bcm_port_info_access(unit, local_member_array[idx], &port_info);
    120             if (incr) {
    121                 port_info->vp_count++;
    122             } else {
    123                 port_info->vp_count--;
    124             }
    125             BCM_IF_ERROR_RETURN(
    126                 bcm_esw_port_vlan_member_get(
    127                     unit, local_member_array[idx], &port_flags));
    128             BCM_IF_ERROR_RETURN(
    129                 bcm_esw_port_vlan_member_set(
    130                     unit, local_member_array[idx], port_flags));
    131         }
    132     } else {
    133         BCM_IF_ERROR_RETURN
    134             (_bcm_esw_modid_is_local(unit, mod_out, &mod_local));
    135         if (mod_local) {
    136             if (soc_feature(unit, soc_feature_sysport_remap)) { 
    137                 BCM_XLATE_SYSPORT_S2P(unit, &port_out); 
    138             }
    139             _bcm_port_info_access(unit, port_out, &port_info);
    140             if (incr) {
    141                 port_info->vp_count++;
    142             } else {
    143                 port_info->vp_count--;
    144             }
    145             BCM_IF_ERROR_RETURN(
    146                 bcm_esw_port_vlan_member_get(
    147                     unit, port_out, &port_flags));
    148             BCM_IF_ERROR_RETURN(
    149                 bcm_esw_port_vlan_member_set(
    150                     unit, port_out, port_flags));
    151         }
    152     }
    153 
    154     return BCM_E_NONE;
    155 }
    156 
    157 /*
    158  * Function:
    159  *      _bcm_enduro_vlan_virtual_free_resources
    160  * Purpose:
    161  *      Free all allocated tables and memory
    162  * Parameters:
    163  *      unit - SOC unit number
    164  * Returns:
    165  *      Nothing
    166  */
    167 STATIC void
    168 _bcm_enduro_vlan_virtual_free_resources(int unit)
    169 {
    170     if (VLAN_VIRTUAL_INFO(unit)->port_info) {
    171         sal_free(VLAN_VIRTUAL_INFO(unit)->port_info);
    172         VLAN_VIRTUAL_INFO(unit)->port_info = NULL;
    173     }
    174     if (VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex) {
    175         sal_mutex_destroy(VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex);
    176         VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex = NULL;
    177     } 
    178 }
    179 
    180 #ifdef BCM_WARM_BOOT_SUPPORT
    181 /*
    182  * Function:
    183  *      bcm_enduro_vlan_virtual_reinit
    184  * Purpose:
    185  *      Warm boot recovery for the VLAN virtual software module
    186  * Parameters:
    187  *      unit - Device Number
    188  * Returns:
    189  *      BCM_E_XXX
    190  */
    191 int 
    192 bcm_enduro_vlan_virtual_reinit(int unit)
    193 {
    194     int rv = BCM_E_NONE;
    195     int stable_size;
    196     uint8 *vlan_xlate_buf = NULL;
    197     vlan_xlate_entry_t *vt_entry;
    198     int i, index_min, index_max;
    199     uint32 key_type, vp, nh_index, trunk_bit;
    200     source_vp_entry_t svp_entry;
    201     ing_dvp_table_entry_t dvp_entry;
    202     ing_l3_next_hop_entry_t ing_nh_entry;
    203     wlan_svp_table_entry_t wlan_svp_entry;
    204     bcm_trunk_t tgid;
    205     bcm_module_t modid, mod_out;
    206     bcm_port_t port_num, port_out;
    207     uint32 profile_idx;
    208     ing_vlan_tag_action_profile_entry_t ing_profile_entry;
    209     _bcm_vp_info_t vp_info;
    210     
    211     _bcm_vp_info_init(&vp_info);
    212     vp_info.vp_type = _bcmVpTypeVlan;
    213 
    214     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
    215 
    216     /* Recover VLAN virtual ports from VLAN_XLATE table */
    217 
    218     vlan_xlate_buf = soc_cm_salloc(unit,
    219             SOC_MEM_TABLE_BYTES(unit, VLAN_XLATEm), "VLAN_XLATE buffer");
    220     if (NULL == vlan_xlate_buf) {
    221         rv = BCM_E_MEMORY;
    222         goto cleanup;
    223     }
    224 
    225     index_min = soc_mem_index_min(unit, VLAN_XLATEm);
    226     index_max = soc_mem_index_max(unit, VLAN_XLATEm);
    227     rv = soc_mem_read_range(unit, VLAN_XLATEm, MEM_BLOCK_ANY,
    228             index_min, index_max, vlan_xlate_buf);
    229     if (SOC_FAILURE(rv)) {
    230         goto cleanup;
    231     }
    232 
    233     for (i = index_min; i <= index_max; i++) {
    234         vt_entry = soc_mem_table_idx_to_pointer
    235             (unit, VLAN_XLATEm, vlan_xlate_entry_t *, 
    236              vlan_xlate_buf, i);
    237 
    238         if (soc_VLAN_XLATEm_field32_get(unit, vt_entry, VALIDf) == 0) {
    239             continue;
    240         }
    241 
    242         key_type = soc_VLAN_XLATEm_field32_get(unit, vt_entry, KEY_TYPEf);
    243         if ((key_type != TR_VLXLT_HASH_KEY_TYPE_OVID) &&
    244                 (key_type != TR_VLXLT_HASH_KEY_TYPE_IVID_OVID) &&
    245                 (key_type != TR_VLXLT_HASH_KEY_TYPE_OTAG)) {
    246             continue;
    247         }
    248 
    249         if (soc_VLAN_XLATEm_field32_get(unit, vt_entry, MPLS_ACTIONf) != 1) {
    250             continue;
    251         }
    252 
    253         vp = soc_VLAN_XLATEm_field32_get(unit, vt_entry, SOURCE_VPf);
    254         if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    255             /* Determine if VP is a VLAN VP by process of elimination.
    256              * Can rule out NIV VP since NIV VPs have different VIF key
    257              * types in VLAN_XLATEm.
    258              */
    259 
    260             rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry);
    261             if (BCM_FAILURE(rv)) {
    262                 goto cleanup;
    263             }
    264             /* Rule out MPLS and MiM VPs, for which ENTRY_TYPE = 1 */
    265             if (soc_SOURCE_VPm_field32_get(unit, &svp_entry, ENTRY_TYPEf) != 3) {
    266                 continue;
    267             }
    268 
    269             rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry);
    270             if (BCM_FAILURE(rv)) {
    271                 goto cleanup;
    272             }
    273 
    274             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp_entry,
    275                     NEXT_HOP_INDEXf);
    276             rv = READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, nh_index,
    277                     &ing_nh_entry);
    278             if (BCM_FAILURE(rv)) {
    279                 goto cleanup;
    280             }
    281             /* Rule out Subport VPs, for which ENTRY_TYPE = 3 */
    282             if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
    283                         ENTRY_TYPEf) != 2) {
    284                 continue;
    285             }
    286 
    287             /* Rule out WLAN vp */
    288             if (SOC_MEM_IS_VALID(unit, WLAN_SVP_TABLEm)) {
    289                 if (vp > soc_mem_index_max(unit, WLAN_SVP_TABLEm)) {
    290                     continue;
    291                 }
    292                 rv = READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp,
    293                     &wlan_svp_entry);
    294                 if (BCM_FAILURE(rv)) {
    295                     goto cleanup;
    296                 }
    297                 if (soc_WLAN_SVP_TABLEm_field32_get(unit, &wlan_svp_entry,
    298                             VALIDf) == 1) { 
    299                     continue;
    300                 }
    301             }
    302 
    303             /* At this point, we are sure VP is a VLAN VP. */
    304 
    305             rv = _bcm_vp_used_set(unit, vp, vp_info);
    306             if (BCM_FAILURE(rv)) {
    307                 goto cleanup;
    308             }
    309         } else {
    310             if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
    311                 /* VP bitmap is recovered by virtual_init */
    312                 continue;
    313             }
    314         }
    315 
    316         /* Recover VLAN_VP_INFO(unit, vp)->criteria, match_vlan, and
    317          * match_inner_vlan.
    318          */
    319         switch (key_type) {
    320             case TR_VLXLT_HASH_KEY_TYPE_OVID:
    321                 VLAN_VP_INFO(unit, vp)->criteria =
    322                     BCM_VLAN_PORT_MATCH_PORT_VLAN;
    323                 VLAN_VP_INFO(unit, vp)->match_vlan = 
    324                     soc_VLAN_XLATEm_field32_get(unit, vt_entry, OVIDf);
    325                 break;
    326             case TR_VLXLT_HASH_KEY_TYPE_IVID_OVID:
    327                 VLAN_VP_INFO(unit, vp)->criteria =
    328                     BCM_VLAN_PORT_MATCH_PORT_VLAN_STACKED;
    329                 VLAN_VP_INFO(unit, vp)->match_vlan = 
    330                     soc_VLAN_XLATEm_field32_get(unit, vt_entry, OVIDf);
    331                 VLAN_VP_INFO(unit, vp)->match_inner_vlan = 
    332                     soc_VLAN_XLATEm_field32_get(unit, vt_entry, IVIDf);
    333                 break;
    334             case TR_VLXLT_HASH_KEY_TYPE_OTAG:
    335                 VLAN_VP_INFO(unit, vp)->criteria =
    336                     BCM_VLAN_PORT_MATCH_PORT_VLAN16;
    337                 VLAN_VP_INFO(unit, vp)->match_vlan = 
    338                     soc_VLAN_XLATEm_field32_get(unit, vt_entry, OTAGf);
    339                 break;
    340             /* coverity[dead_error_begin] */
    341             default:
    342                 continue;
    343         }
    344 
    345         /* Recover VLAN_VP_INFO(unit, vp)->port */
    346         trunk_bit = soc_VLAN_XLATEm_field32_get(unit, vt_entry, Tf);
    347         if (trunk_bit) {
    348             tgid = soc_VLAN_XLATEm_field32_get(unit, vt_entry, TGIDf);
    349             BCM_GPORT_TRUNK_SET(VLAN_VP_INFO(unit, vp)->port, tgid);
    350         } else {
    351             modid = soc_VLAN_XLATEm_field32_get(unit, vt_entry, MODULE_IDf);
    352             port_num = soc_VLAN_XLATEm_field32_get(unit, vt_entry, PORT_NUMf);
    353             rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    354                                     modid, port_num, &mod_out, &port_out);
    355             if (BCM_FAILURE(rv)) {
    356                 goto cleanup;
    357             }
    358             BCM_GPORT_MODPORT_SET(VLAN_VP_INFO(unit, vp)->port,
    359                     mod_out, port_out);
    360         }
    361 
    362         /* Recover VLAN_VP_INFO(unit, vp)->flags */
    363         profile_idx = soc_VLAN_XLATEm_field32_get(unit, vt_entry,
    364                                                   TAG_ACTION_PROFILE_PTRf); 
    365         rv = READ_ING_VLAN_TAG_ACTION_PROFILEm(unit, MEM_BLOCK_ANY,
    366                 profile_idx, &ing_profile_entry);
    367         if (BCM_FAILURE(rv)) {
    368             goto cleanup;
    369         }
    370         if ((soc_ING_VLAN_TAG_ACTION_PROFILEm_field32_get(unit,
    371                     &ing_profile_entry, DT_OTAG_ACTIONf) ==
    372                     bcmVlanActionReplace) &&
    373             (soc_ING_VLAN_TAG_ACTION_PROFILEm_field32_get(unit,
    374                     &ing_profile_entry, DT_ITAG_ACTIONf) ==
    375                     bcmVlanActionNone)) {
    376             VLAN_VP_INFO(unit, vp)->flags |= BCM_VLAN_PORT_INNER_VLAN_PRESERVE;
    377         }
    378         if (VLAN_VP_INFO(unit, vp)->criteria ==
    379                 BCM_VLAN_PORT_MATCH_PORT_VLAN16) {
    380             VLAN_VP_INFO(unit, vp)->flags |= BCM_VLAN_PORT_EGRESS_VLAN16;
    381         }
    382 
    383         if (stable_size == 0) {
    384             /* In the Port module, a port's VP count is not recovered in 
    385              * level 1 Warm Boot.
    386              */
    387             rv = _bcm_enduro_vlan_vp_port_cnt_update(unit,
    388                     VLAN_VP_INFO(unit, vp)->port, vp, TRUE);
    389             if (BCM_FAILURE(rv)) {
    390                 goto cleanup;
    391             }
    392         }
    393     }
    394 
    395 cleanup:
    396     if (vlan_xlate_buf) {
    397         soc_cm_sfree(unit, vlan_xlate_buf);
    398     }
    399 
    400     if (BCM_FAILURE(rv)) {
    401         _bcm_enduro_vlan_virtual_free_resources(unit);
    402     }
    403 
    404     return rv;
    405 }
    406 #endif /* BCM_WARM_BOOT_SUPPORT */
    407 
    408 #ifndef BCM_SW_STATE_DUMP_DISABLE
    409 /*
    410  * Function:
    411  *     _bcm_enduro_vlan_vp_sw_dump
    412  * Purpose:
    413  *     Displays VLAN VP information maintained by software.
    414  * Parameters:
    415  *     unit - Device unit number
    416  * Returns:
    417  *     None
    418  */
    419 void
    420 bcm_enduro_vlan_vp_sw_dump(int unit)
    421 {
    422     int i, num_vp;
    423 
    424     LOG_CLI((BSL_META_U(unit,
    425                         "\nSW Information VLAN VP - Unit %d\n"), unit));
    426 
    427     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    428 
    429     for (i = 0; i < num_vp; i++) {
    430         if (VLAN_VP_INFO(unit, i)->port == 0) {
    431             continue;
    432         }
    433         LOG_CLI((BSL_META_U(unit,
    434                             "\n  VLAN vp = %d\n"), i));
    435         LOG_CLI((BSL_META_U(unit,
    436                             "  Criteria = 0x%x,"), VLAN_VP_INFO(unit, i)->criteria));
    437         switch (VLAN_VP_INFO(unit, i)->criteria) {
    438             case BCM_VLAN_PORT_MATCH_PORT_VLAN:
    439                 LOG_CLI((BSL_META_U(unit,
    440                                     " port plus outer VLAN ID\n")));
    441                 break;
    442             case BCM_VLAN_PORT_MATCH_PORT_VLAN_STACKED:
    443                 LOG_CLI((BSL_META_U(unit,
    444                                     " port plus outer and inner VLAN IDs\n")));
    445                 break;
    446             case BCM_VLAN_PORT_MATCH_PORT_VLAN16:
    447                 LOG_CLI((BSL_META_U(unit,
    448                                     " port plus outer VLAN tag\n")));
    449                 break;
    450             default:
    451                 LOG_CLI((BSL_META_U(unit,
    452                                     " \n")));
    453         }
    454         LOG_CLI((BSL_META_U(unit,
    455                             "  Flags = 0x%x\n"), VLAN_VP_INFO(unit, i)->flags));
    456         LOG_CLI((BSL_META_U(unit,
    457                             "  Match VLAN = 0x%x\n"), VLAN_VP_INFO(unit, i)->match_vlan));
    458         LOG_CLI((BSL_META_U(unit,
    459                             "  Match Inner VLAN = 0x%x\n"),
    460                  VLAN_VP_INFO(unit, i)->match_inner_vlan));
    461         LOG_CLI((BSL_META_U(unit,
    462                             "  Port = 0x%x\n"), VLAN_VP_INFO(unit, i)->port));
    463     }
    464 
    465     return;
    466 }
    467 #endif /* BCM_SW_STATE_DUMP_DISABLE */
    468 
    469 /*
    470  * Function:
    471  *      bcm_enduro_vlan_virtual_init
    472  * Purpose:
    473  *      Initialize the VLAN virtual port module.
    474  * Parameters:
    475  *      unit - SOC unit number.
    476  * Returns:
    477  *      BCM_E_XXX
    478  */
    479 int
    480 bcm_enduro_vlan_virtual_init(int unit)
    481 {
    482     int num_vp;
    483 
    484     if (VLAN_VIRTUAL_INFO(unit)->vlan_virtual_initialized) {
    485         bcm_enduro_vlan_virtual_detach(unit);
    486     }
    487 
    488     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    489     if (NULL == VLAN_VIRTUAL_INFO(unit)->port_info) {
    490         VLAN_VIRTUAL_INFO(unit)->port_info =
    491             sal_alloc(sizeof(_bcm_enduro_vlan_vp_info_t) * num_vp, "vlan_vp_info");
    492         if (NULL == VLAN_VIRTUAL_INFO(unit)->port_info) {
    493             _bcm_enduro_vlan_virtual_free_resources(unit);
    494             return BCM_E_MEMORY;
    495         }
    496     }
    497     sal_memset(VLAN_VIRTUAL_INFO(unit)->port_info, 0,
    498             sizeof(_bcm_enduro_vlan_vp_info_t) * num_vp);
    499 
    500     if (NULL == VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex) {
    501         VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex =
    502             sal_mutex_create("vlan virtual mutex");
    503         if (NULL == VLAN_VIRTUAL_INFO(unit)->vlan_virtual_mutex) {
    504             _bcm_enduro_vlan_virtual_free_resources(unit);
    505             return BCM_E_MEMORY;
    506         }
    507     }
    508 
    509     VLAN_VIRTUAL_INFO(unit)->vlan_virtual_initialized = 1;
    510 
    511     /* Warm boot recovery of VLAN_VP_INFO depends on the completion
    512      * of _bcm_virtual_init, but _bcm_virtual_init is after the 
    513      * VLAN module in the init sequence. Hence, warm boot recovery
    514      * of VLAN_VP_INFO is moved to end of _bcm_virtual_init.
    515      */
    516 
    517     return BCM_E_NONE;
    518 }
    519 
    520 /*
    521  * Function:
    522  *      bcm_enduro_vlan_virtual_detach
    523  * Purpose:
    524  *      Detach the VLAN virtual port module.
    525  * Parameters:
    526  *      unit - SOC unit number.
    527  * Returns:
    528  *      BCM_E_XXX
    529  */
    530 int
    531 bcm_enduro_vlan_virtual_detach(int unit)
    532 {
    533     _bcm_enduro_vlan_virtual_free_resources(unit);
    534 
    535     VLAN_VIRTUAL_INFO(unit)->vlan_virtual_initialized = 0;
    536 
    537     return BCM_E_NONE;
    538 }
    539 
    540 /*
    541  * Function:
    542  *      _bcm_enduro_vlan_vp_nh_info_set
    543  * Purpose:
    544  *      Get a next hop index and configure next hop tables.
    545  * Parameters:
    546  *      unit       - (IN) SOC unit number. 
    547  *      vlan_vp    - (IN) Pointer to VLAN virtual port structure. 
    548  *      vp         - (IN) Virtual port number. 
    549  *      drop       - (IN) Drop indication. 
    550  *      nh_index   - (IN/OUT) Next hop index. 
    551  * Returns:
    552  *      BCM_X_XXX
    553  */
    554 STATIC int
    555 _bcm_enduro_vlan_vp_nh_info_set(int unit, bcm_vlan_port_t *vlan_vp, int vp,
    556         int drop, int *nh_index)
    557 {
    558     int rv;
    559     uint32 nh_flags;
    560     bcm_l3_egress_t nh_info;
    561     egr_l3_next_hop_entry_t egr_nh;
    562     uint8 egr_nh_entry_type;
    563     bcm_module_t mod_out;
    564     bcm_port_t port_out;
    565     bcm_trunk_t trunk_id;
    566     int id;
    567     int ing_nh_port;
    568     int ing_nh_module;
    569     int ing_nh_trunk;
    570     ing_l3_next_hop_entry_t ing_nh;
    571     initial_ing_l3_next_hop_entry_t initial_ing_nh;
    572 
    573     /* Get a next hop index */
    574 
    575     if (vlan_vp->flags & BCM_VLAN_PORT_REPLACE) {
    576         if ((*nh_index > soc_mem_index_max(unit, EGR_L3_NEXT_HOPm)) ||
    577                 (*nh_index < soc_mem_index_min(unit, EGR_L3_NEXT_HOPm)))  {
    578             return BCM_E_PARAM;
    579         }
    580     } else {
    581         /*
    582          * Allocate a next-hop entry. By calling bcm_xgs3_nh_add()
    583          * with _BCM_L3_SHR_WRITE_DISABLE flag, a next-hop index is
    584          * allocated but nothing is written to hardware. The "nh_info"
    585          * in this case is not used, so just set to all zeros.
    586          */
    587         bcm_l3_egress_t_init(&nh_info);
    588 
    589         nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
    590         rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, nh_index);
    591         BCM_IF_ERROR_RETURN(rv);
    592     }
    593 
    594     /* Write EGR_L3_NEXT_HOP entry */
    595 
    596     if (vlan_vp->flags & BCM_VLAN_PORT_REPLACE) {
    597         /* Read the existing egress next_hop entry */
    598         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
    599                 *nh_index, &egr_nh);
    600         BCM_IF_ERROR_RETURN(rv);
    601 
    602         /* Be sure that the existing entry is programmed to SD-tag */
    603         egr_nh_entry_type = 
    604             soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, ENTRY_TYPEf);
    605         if (egr_nh_entry_type != 0x2) { /* != SD-tag */
    606             return BCM_E_PARAM;
    607         }
    608     } else {
    609         egr_nh_entry_type = 0x2; /* SD-tag */
    610     }
    611 
    612     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    613     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
    614             ENTRY_TYPEf, egr_nh_entry_type);
    615     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
    616             SD_TAG__DVPf, vp);
    617     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
    618             SD_TAG__HG_HDR_SELf, 1);
    619     rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    620             MEM_BLOCK_ALL, *nh_index, &egr_nh);
    621     if (rv < 0) {
    622         goto cleanup;
    623     }
    624 
    625     /* Resolve gport */
    626 
    627     rv = _bcm_esw_gport_resolve(unit, vlan_vp->port, &mod_out, 
    628             &port_out, &trunk_id, &id);
    629     if (rv < 0) {
    630         goto cleanup;
    631     }
    632 
    633     ing_nh_port = -1;
    634     ing_nh_module = -1;
    635     ing_nh_trunk = -1;
    636 
    637     if (BCM_GPORT_IS_TRUNK(vlan_vp->port)) {
    638         ing_nh_module = -1;
    639         ing_nh_port = -1;
    640         ing_nh_trunk = trunk_id;
    641     } else {
    642         ing_nh_module = mod_out;
    643         ing_nh_port = port_out;
    644         ing_nh_trunk = -1;
    645     }
    646 
    647     /* Write ING_L3_NEXT_HOP entry */
    648 
    649     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
    650 
    651     if (ing_nh_trunk == -1) {
    652         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    653                 &ing_nh, PORT_NUMf, ing_nh_port);
    654         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    655                 &ing_nh, MODULE_IDf, ing_nh_module);
    656     } else {    
    657         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    658                 &ing_nh, Tf, 1);
    659         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    660                 &ing_nh, TGIDf, ing_nh_trunk);
    661     }
    662 
    663     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, drop);
    664     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    665             &ing_nh, ENTRY_TYPEf, 0x2); /* L2 DVP */
    666     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    667             &ing_nh, MTU_SIZEf, 0x3fff);
    668     rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
    669             MEM_BLOCK_ALL, *nh_index, &ing_nh);
    670     if (rv < 0) {
    671         goto cleanup;
    672     }
    673 
    674     /* Write INITIAL_ING_L3_NEXT_HOP entry */
    675 
    676     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
    677     if (ing_nh_trunk == -1) {
    678         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    679                 &initial_ing_nh, PORT_NUMf, ing_nh_port);
    680         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    681                 &initial_ing_nh, MODULE_IDf, ing_nh_module);
    682     } else {
    683         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    684                 &initial_ing_nh, Tf, 1);
    685         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    686                 &initial_ing_nh, TGIDf, ing_nh_trunk);
    687     }
    688     rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
    689             MEM_BLOCK_ALL, *nh_index, &initial_ing_nh);
    690     if (rv < 0) {
    691         goto cleanup;
    692     }
    693 
    694     return rv;
    695 
    696 cleanup:
    697     if (!(vlan_vp->flags & BCM_VLAN_PORT_REPLACE)) {
    698         (void) bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, *nh_index);
    699     }
    700     return rv;
    701 }
    702 
    703 /*
    704  * Function:
    705  *      _bcm_enduro_vlan_vp_nh_info_delete
    706  * Purpose:
    707  *      Free next hop index and clear next hop tables.
    708  * Parameters:
    709  *      unit     - (IN) SOC unit number. 
    710  *      nh_index - (IN) Next hop index. 
    711  * Returns:
    712  *      BCM_X_XXX
    713  */
    714 STATIC int
    715 _bcm_enduro_vlan_vp_nh_info_delete(int unit, int nh_index)
    716 {
    717     egr_l3_next_hop_entry_t egr_nh;
    718     ing_l3_next_hop_entry_t ing_nh;
    719     initial_ing_l3_next_hop_entry_t initial_ing_nh;
    720 
    721     /* Clear EGR_L3_NEXT_HOP entry */
    722     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    723     BCM_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    724                                    MEM_BLOCK_ALL, nh_index, &egr_nh));
    725 
    726     /* Clear ING_L3_NEXT_HOP entry */
    727     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
    728     BCM_IF_ERROR_RETURN(soc_mem_write (unit, ING_L3_NEXT_HOPm,
    729                                    MEM_BLOCK_ALL, nh_index, &ing_nh));
    730 
    731     /* Clear INITIAL_ING_L3_NEXT_HOP entry */
    732     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
    733     BCM_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
    734                                    MEM_BLOCK_ALL, nh_index, &initial_ing_nh));
    735 
    736     /* Free the next-hop index. */
    737     BCM_IF_ERROR_RETURN
    738         (bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index));
    739 
    740     return BCM_E_NONE;
    741 }
    742 
    743 /*
    744  * Function:
    745  *      _bcm_enduro_vlan_vp_match_add
    746  * Purpose:
    747  *      Add match criteria for VLAN VP.
    748  * Parameters:
    749  *      unit - (IN) SOC unit number. 
    750  *      vlan_vp - (IN) Pointer to VLAN virtual port structure. 
    751  *      vp - (IN) Virtual port number.
    752  * Returns:
    753  *      BCM_X_XXX
    754  */
    755 STATIC int
    756 _bcm_enduro_vlan_vp_match_add(int unit, bcm_vlan_port_t *vlan_vp, int vp)
    757 {
    758     vlan_xlate_entry_t vent, old_vent;
    759     int key_type = 0;
    760     bcm_vlan_action_set_t action;
    761     uint32 profile_idx;
    762     int rv;
    763 
    764     if (vlan_vp->criteria == BCM_VLAN_PORT_MATCH_NONE) {
    765        return BCM_E_NONE;
    766     }
    767 
    768     if (!((vlan_vp->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN) ||
    769           (vlan_vp->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN_STACKED) ||
    770           (vlan_vp->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN16))) {
    771         return BCM_E_PARAM;
    772     }
    773 
    774     if ((vlan_vp->egress_vlan > BCM_VLAN_MAX) ||
    775         (vlan_vp->egress_inner_vlan > BCM_VLAN_MAX)) {
    776         return BCM_E_PARAM;
    777     }
    778 
    779     sal_memset(&vent, 0, sizeof(vlan_xlate_entry_t));
    780 
    781     soc_VLAN_XLATEm_field32_set(unit, &vent, VALIDf, 1);
    782 
    783     if (vlan_vp->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN) {
    784         key_type = bcmVlanTranslateKeyPortOuter;
    785     } else if (vlan_vp->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN_STACKED) {
    786         key_type = bcmVlanTranslateKeyPortDouble;
    787     } else if (vlan_vp->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN16) {
    788         key_type = bcmVlanTranslateKeyPortOuterTag;
    789     }
    790     BCM_IF_ERROR_RETURN
    791         (_bcm_trx_vlan_translate_entry_assemble(unit, &vent,
    792                                                 vlan_vp->port,
    793                                                 key_type,
    794                                                 vlan_vp->match_inner_vlan,
    795                                                 vlan_vp->match_vlan));
    796 
    797     soc_VLAN_XLATEm_field32_set(unit, &vent, MPLS_ACTIONf, 0x1); /* SVP */
    798     soc_VLAN_XLATEm_field32_set(unit, &vent, SOURCE_VPf, vp);
    799     soc_VLAN_XLATEm_field32_set(unit, &vent, NEW_OVIDf,
    800                                 vlan_vp->egress_vlan);
    801     soc_VLAN_XLATEm_field32_set(unit, &vent, NEW_IVIDf,
    802                                 vlan_vp->egress_inner_vlan);
    803 
    804     bcm_vlan_action_set_t_init(&action);
    805 
    806     /* For double tagged packets */
    807     if (vlan_vp->flags & BCM_VLAN_PORT_INNER_VLAN_PRESERVE) {
    808         action.dt_outer = bcmVlanActionReplace;
    809         action.dt_outer_prio = bcmVlanActionReplace;
    810         action.dt_inner = bcmVlanActionNone;
    811         action.dt_inner_prio = bcmVlanActionNone;
    812     } else {
    813         /* Strip inner VLAN */
    814         action.dt_outer = bcmVlanActionReplace;
    815         action.dt_outer_prio = bcmVlanActionReplace;
    816         action.dt_inner = bcmVlanActionDelete;
    817         action.dt_inner_prio = bcmVlanActionDelete;
    818     }
    819 
    820     if (vlan_vp->flags & BCM_VLAN_PORT_INNER_VLAN_ADD) {
    821         action.ot_inner = bcmVlanActionAdd;
    822     } else {
    823         action.ot_inner = bcmVlanActionNone;
    824     }
    825 
    826     action.ot_outer = bcmVlanActionReplace;
    827     action.ot_outer_prio = bcmVlanActionReplace;
    828 
    829     BCM_IF_ERROR_RETURN
    830         (_bcm_trx_vlan_action_profile_entry_add(unit, &action, &profile_idx));
    831 
    832     soc_VLAN_XLATEm_field32_set(unit, &vent, TAG_ACTION_PROFILE_PTRf,
    833                                 profile_idx);
    834 
    835     rv = soc_mem_insert_return_old(unit, VLAN_XLATEm, MEM_BLOCK_ALL,
    836                                    &vent, &old_vent);
    837     if (rv == SOC_E_EXISTS) {
    838         /* Delete the old vlan translate profile entry */
    839         profile_idx = soc_VLAN_XLATEm_field32_get(unit, &old_vent,
    840                                                   TAG_ACTION_PROFILE_PTRf);       
    841         rv = _bcm_trx_vlan_action_profile_entry_delete(unit, profile_idx);
    842     }
    843     return rv;
    844 }
    845 
    846 /*
    847  * Function:
    848  *      _bcm_enduro_vlan_vp_match_delete
    849  * Purpose:
    850  *      Delete match criteria for VLAN VP.
    851  * Parameters:
    852  *      unit - (IN) SOC unit number. 
    853  *      vp - (IN) Virtual port number.
    854  * Returns:
    855  *      BCM_X_XXX
    856  */
    857 STATIC int
    858 _bcm_enduro_vlan_vp_match_delete(int unit, int vp)
    859 {
    860     vlan_xlate_entry_t vent, old_vent;
    861     int key_type = 0;
    862     uint32 profile_idx;
    863     int rv;
    864 
    865     if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_NONE) {
    866         return BCM_E_NONE;
    867     }
    868 
    869     if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN) {
    870         key_type = bcmVlanTranslateKeyPortOuter;
    871     } else if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN_STACKED) {
    872         key_type = bcmVlanTranslateKeyPortDouble;
    873     } else if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN16) {
    874         key_type = bcmVlanTranslateKeyPortOuterTag;
    875     } else {
    876         return BCM_E_INTERNAL;
    877     }
    878 
    879     sal_memset(&vent, 0, sizeof(vlan_xlate_entry_t));
    880     BCM_IF_ERROR_RETURN
    881         (_bcm_trx_vlan_translate_entry_assemble(unit, &vent,
    882                                                 VLAN_VP_INFO(unit, vp)->port,
    883                                                 key_type,
    884                                                 VLAN_VP_INFO(unit, vp)->match_inner_vlan,
    885                                                 VLAN_VP_INFO(unit, vp)->match_vlan));
    886 
    887     rv = soc_mem_delete_return_old(unit, VLAN_XLATEm, MEM_BLOCK_ALL, &vent, &old_vent);
    888     if ((rv == SOC_E_NONE) && soc_VLAN_XLATEm_field32_get(unit, &old_vent, VALIDf)) {
    889         profile_idx = soc_VLAN_XLATEm_field32_get(unit, &old_vent,
    890                                                   TAG_ACTION_PROFILE_PTRf);       
    891         /* Delete the old vlan action profile entry */
    892         rv = _bcm_trx_vlan_action_profile_entry_delete(unit, profile_idx);
    893     }
    894     return rv;
    895 }
    896 
    897 /*
    898  * Function:
    899  *      _bcm_enduro_vlan_vp_match_get
    900  * Purpose:
    901  *      Get match criteria for VLAN VP.
    902  * Parameters:
    903  *      unit - (IN) SOC unit number. 
    904  *      vp - (IN) Virtual port number.
    905  *      vlan_vp - (OUT) Pointer to VLAN virtual port structure. 
    906  * Returns:
    907  *      BCM_X_XXX
    908  */
    909 STATIC int
    910 _bcm_enduro_vlan_vp_match_get(int unit, int vp, bcm_vlan_port_t *vlan_vp)
    911 {
    912     vlan_xlate_entry_t vent, vent_out;
    913     int key_type = 0;
    914     int idx;
    915 
    916     vlan_vp->criteria = VLAN_VP_INFO(unit, vp)->criteria;
    917     vlan_vp->match_vlan = VLAN_VP_INFO(unit, vp)->match_vlan;
    918     vlan_vp->match_inner_vlan = VLAN_VP_INFO(unit, vp)->match_inner_vlan;
    919     vlan_vp->port = VLAN_VP_INFO(unit, vp)->port;
    920 
    921     if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_NONE) {
    922         return BCM_E_NONE;
    923     }
    924 
    925     if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN) {
    926         key_type = bcmVlanTranslateKeyPortOuter;
    927     } else if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN_STACKED) {
    928         key_type = bcmVlanTranslateKeyPortDouble;
    929     } else if (VLAN_VP_INFO(unit, vp)->criteria == BCM_VLAN_PORT_MATCH_PORT_VLAN16) {
    930         key_type = bcmVlanTranslateKeyPortOuterTag;
    931     } else {
    932         return BCM_E_INTERNAL;
    933     }
    934 
    935     sal_memset(&vent, 0, sizeof(vlan_xlate_entry_t));
    936     BCM_IF_ERROR_RETURN
    937         (_bcm_trx_vlan_translate_entry_assemble(unit, &vent,
    938                                                 VLAN_VP_INFO(unit, vp)->port,
    939                                                 key_type,
    940                                                 VLAN_VP_INFO(unit, vp)->match_inner_vlan,
    941                                                 VLAN_VP_INFO(unit, vp)->match_vlan));
    942 
    943     BCM_IF_ERROR_RETURN
    944         (soc_mem_search(unit, VLAN_XLATEm, MEM_BLOCK_ALL,
    945                         &idx, &vent, &vent_out, 0));
    946     vlan_vp->egress_vlan = soc_VLAN_XLATEm_field32_get(unit, &vent_out,
    947                                                        NEW_OVIDf);
    948     vlan_vp->egress_inner_vlan = soc_VLAN_XLATEm_field32_get(unit, &vent_out,
    949                                                        NEW_IVIDf);
    950 
    951     return BCM_E_NONE;
    952 }
    953 
    954 /*
    955  * Function:
    956  *      _bcm_enduro_vlan_vp_create
    957  * Purpose:
    958  *      Create a VLAN virtual port.
    959  * Parameters:
    960  *      unit - (IN) SOC unit number. 
    961  *      vlan_vp - (IN/OUT) Pointer to VLAN virtual port structure. 
    962  * Returns:
    963  *      BCM_X_XXX
    964  */
    965 STATIC int
    966 _bcm_enduro_vlan_vp_create(int unit,
    967                          bcm_vlan_port_t *vlan_vp)
    968 {
    969     int mode;
    970     int vp;
    971     int rv = BCM_E_NONE;
    972     int num_vp;
    973     int nh_index = 0;
    974     ing_dvp_table_entry_t dvp_entry;
    975     source_vp_entry_t svp_entry;
    976     int cml_default_enable=0, cml_default_new=0, cml_default_move=0;
    977     _bcm_vp_info_t vp_info;
    978     
    979     _bcm_vp_info_init(&vp_info);
    980     vp_info.vp_type = _bcmVpTypeVlan;
    981 
    982     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_egress_mode_get(unit, &mode));
    983     if (!mode) {
    984         LOG_INFO(BSL_LS_BCM_L3,
    985                  (BSL_META_U(unit,
    986                              "L3 egress mode must be set first\n")));
    987         return BCM_E_DISABLED;
    988     }
    989 
    990     if (!(vlan_vp->flags & BCM_VLAN_PORT_REPLACE)) { /* Create new VLAN VP */
    991 
    992         if (vlan_vp->flags & BCM_VLAN_PORT_WITH_ID) {
    993             if (!BCM_GPORT_IS_VLAN_PORT(vlan_vp->vlan_port_id)) {
    994                 return BCM_E_PARAM;
    995             }
    996             vp = BCM_GPORT_VLAN_PORT_ID_GET(vlan_vp->vlan_port_id);
    997             if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
    998                 return BCM_E_PARAM;
    999             }
   1000             if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   1001                 return BCM_E_EXISTS;
   1002             } else {
   1003                 rv = _bcm_vp_used_set(unit, vp, vp_info);
   1004                 if (rv < 0) {
   1005                     return rv;
   1006                 }
   1007             }
   1008         } else {
   1009             /* allocate a new VP index */
   1010             num_vp = soc_mem_index_count(unit, SOURCE_VPm);
   1011             rv = _bcm_vp_alloc(unit, 0, (num_vp - 1), 1, SOURCE_VPm,
   1012                     vp_info, &vp);
   1013             if (rv < 0) {
   1014                 return rv;
   1015             }
   1016         }
   1017 
   1018         /* Configure next hop tables */
   1019         rv = _bcm_enduro_vlan_vp_nh_info_set(unit, vlan_vp, vp, 0,
   1020                                               &nh_index);
   1021         if (rv < 0) {
   1022             goto cleanup;
   1023         }
   1024 
   1025         /* Configure DVP table */
   1026         sal_memset(&dvp_entry, 0, sizeof(ing_dvp_table_entry_t));
   1027         soc_ING_DVP_TABLEm_field32_set(unit, &dvp_entry, NEXT_HOP_INDEXf,
   1028                                        nh_index);
   1029         rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp_entry);
   1030         if (rv < 0) {
   1031             goto cleanup;
   1032         }
   1033 
   1034         /* Configure SVP table */
   1035         sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t));
   1036         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 3);
   1037 
   1038         /* Set the CML */
   1039         rv = _bcm_vp_default_cml_mode_get (unit, 
   1040                            &cml_default_enable, &cml_default_new, 
   1041                            &cml_default_move);
   1042          if (rv < 0) {
   1043              goto cleanup;
   1044          }
   1045 
   1046         if (cml_default_enable) {
   1047             /* Set the CML to default values */
   1048             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, cml_default_new);
   1049             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, cml_default_move);
   1050         } else {
   1051             /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */
   1052             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, 0x8);
   1053             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, 0x8);
   1054         }
   1055 
   1056         rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   1057         if (rv < 0) {
   1058             goto cleanup;
   1059         }
   1060 
   1061         /* Configure ingress VLAN translation table */
   1062         rv = _bcm_enduro_vlan_vp_match_add(unit, vlan_vp, vp);
   1063         if (rv < 0) {
   1064             goto cleanup;
   1065         }
   1066 
   1067         /* Increment port's VP count */
   1068         rv = _bcm_enduro_vlan_vp_port_cnt_update(unit, vlan_vp->port, vp, TRUE);
   1069         if (rv < 0) {
   1070             goto cleanup;
   1071         }
   1072 
   1073     } else { /* Replace properties of existing VLAN VP */
   1074 
   1075         if (!(vlan_vp->flags & BCM_VLAN_PORT_WITH_ID)) {
   1076             return BCM_E_PARAM;
   1077         }
   1078         if (!BCM_GPORT_IS_VLAN_PORT(vlan_vp->vlan_port_id)) {
   1079             return BCM_E_PARAM;
   1080         }
   1081         vp = BCM_GPORT_VLAN_PORT_ID_GET(vlan_vp->vlan_port_id);
   1082         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   1083             return BCM_E_PARAM;
   1084         }
   1085 
   1086         /* For existing vlan vp, NH entry already exists */
   1087         BCM_IF_ERROR_RETURN
   1088             (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   1089 
   1090         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp_entry,
   1091                 NEXT_HOP_INDEXf);
   1092 
   1093         /* Update existing next hop entries */
   1094         BCM_IF_ERROR_RETURN
   1095             (_bcm_enduro_vlan_vp_nh_info_set(unit, vlan_vp, vp, 0,
   1096                                               &nh_index));
   1097 
   1098         /* Delete old ingress VLAN translation entry,
   1099          * install new ingress VLAN translation entry
   1100          */
   1101         BCM_IF_ERROR_RETURN
   1102             (_bcm_enduro_vlan_vp_match_delete(unit, vp));
   1103 
   1104         BCM_IF_ERROR_RETURN
   1105             (_bcm_enduro_vlan_vp_match_add(unit, vlan_vp, vp));
   1106 
   1107         /* Decrement old port's VP count, increment new port's VP count */
   1108         BCM_IF_ERROR_RETURN
   1109             (_bcm_enduro_vlan_vp_port_cnt_update(unit,
   1110                 VLAN_VP_INFO(unit, vp)->port, vp, FALSE));
   1111 
   1112         BCM_IF_ERROR_RETURN
   1113             (_bcm_enduro_vlan_vp_port_cnt_update(unit,
   1114                 vlan_vp->port, vp, TRUE));
   1115     }
   1116 
   1117     /* Set VLAN VP software state */
   1118     VLAN_VP_INFO(unit, vp)->criteria = vlan_vp->criteria;
   1119     VLAN_VP_INFO(unit, vp)->flags = vlan_vp->flags;
   1120     VLAN_VP_INFO(unit, vp)->match_vlan = vlan_vp->match_vlan;
   1121     VLAN_VP_INFO(unit, vp)->match_inner_vlan = vlan_vp->match_inner_vlan;
   1122     VLAN_VP_INFO(unit, vp)->egress_vlan = vlan_vp->egress_vlan;
   1123     VLAN_VP_INFO(unit, vp)->port = vlan_vp->port;
   1124 
   1125     BCM_GPORT_VLAN_PORT_ID_SET(vlan_vp->vlan_port_id, vp);
   1126     vlan_vp->encap_id = nh_index;
   1127 
   1128     return rv;
   1129 
   1130 cleanup:
   1131     if (!(vlan_vp->flags & BCM_VLAN_PORT_REPLACE)) {
   1132         (void) _bcm_vp_free(unit, _bcmVpTypeVlan, 1, vp);
   1133         _bcm_enduro_vlan_vp_nh_info_delete(unit, nh_index);
   1134 
   1135         sal_memset(&dvp_entry, 0, sizeof(ing_dvp_table_entry_t));
   1136         (void)WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp_entry);
   1137 
   1138         sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t));
   1139         (void)WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   1140 
   1141         (void) _bcm_enduro_vlan_vp_match_delete(unit, vp);
   1142     }
   1143 
   1144     return rv;
   1145 }
   1146 
   1147 /*
   1148  * Function:
   1149  *      bcm_enduro_vlan_vp_create
   1150  * Purpose:
   1151  *      Create a VLAN virtual port.
   1152  * Parameters:
   1153  *      unit - (IN) SOC unit number. 
   1154  *      vlan_vp - (IN/OUT) Pointer to VLAN virtual port structure. 
   1155  * Returns:
   1156  *      BCM_X_XXX
   1157  */
   1158 int
   1159 bcm_enduro_vlan_vp_create(int unit,
   1160                          bcm_vlan_port_t *vlan_vp)
   1161 {
   1162     int rv;
   1163 
   1164     VLAN_VIRTUAL_INIT(unit);
   1165 
   1166     VLAN_VIRTUAL_LOCK(unit);
   1167 
   1168     rv = _bcm_enduro_vlan_vp_create(unit, vlan_vp);
   1169 
   1170     VLAN_VIRTUAL_UNLOCK(unit);
   1171 
   1172     return rv;
   1173 }
   1174 
   1175 /*
   1176  * Function:
   1177  *      _bcm_enduro_vlan_vp_destroy
   1178  * Purpose:
   1179  *      Destroy a VLAN virtual port.
   1180  * Parameters:
   1181  *      unit - (IN) SOC unit number. 
   1182  *      gport - (IN) VLAN VP GPORT ID.
   1183  * Returns:
   1184  *      BCM_X_XXX
   1185  */
   1186 STATIC int
   1187 _bcm_enduro_vlan_vp_destroy(int unit, bcm_gport_t gport)
   1188 {
   1189     int vp;
   1190     source_vp_entry_t svp_entry;
   1191     int nh_index;
   1192     ing_dvp_table_entry_t dvp_entry;
   1193 
   1194     if (!BCM_GPORT_IS_VLAN_PORT(gport)) {
   1195         return BCM_E_PARAM;
   1196     }
   1197 
   1198     vp = BCM_GPORT_VLAN_PORT_ID_GET(gport);
   1199     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   1200         return BCM_E_NOT_FOUND;
   1201     }
   1202 
   1203     /* Delete ingress VLAN translation entry */
   1204     BCM_IF_ERROR_RETURN
   1205         (_bcm_enduro_vlan_vp_match_delete(unit, vp));
   1206 
   1207     /* Clear SVP entry */
   1208     sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t));
   1209     BCM_IF_ERROR_RETURN
   1210         (WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry));
   1211 
   1212     /* Clear DVP entry */
   1213     BCM_IF_ERROR_RETURN
   1214         (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   1215     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp_entry, NEXT_HOP_INDEXf);
   1216 
   1217     sal_memset(&dvp_entry, 0, sizeof(ing_dvp_table_entry_t));
   1218     BCM_IF_ERROR_RETURN
   1219         (WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp_entry));
   1220 
   1221     /* Clear next hop entries and free next hop index */
   1222     BCM_IF_ERROR_RETURN
   1223         (_bcm_enduro_vlan_vp_nh_info_delete(unit, nh_index));
   1224 
   1225     /* Decrement port's VP count */
   1226     BCM_IF_ERROR_RETURN
   1227         (_bcm_enduro_vlan_vp_port_cnt_update(unit,
   1228                                               VLAN_VP_INFO(unit, vp)->port,
   1229                                               vp, FALSE));
   1230     /* Free VP */
   1231     BCM_IF_ERROR_RETURN
   1232         (_bcm_vp_free(unit, _bcmVpTypeVlan, 1, vp));
   1233 
   1234     /* Clear VLAN VP software state */
   1235     sal_memset(VLAN_VP_INFO(unit, vp), 0, sizeof(_bcm_enduro_vlan_vp_info_t));
   1236 
   1237     return BCM_E_NONE;
   1238 }
   1239 
   1240 /*
   1241  * Function:
   1242  *      bcm_enduro_vlan_vp_destroy
   1243  * Purpose:
   1244  *      Destroy a VLAN virtual port.
   1245  * Parameters:
   1246  *      unit - (IN) SOC unit number. 
   1247  *      gport - (IN) VLAN VP GPORT ID.
   1248  * Returns:
   1249  *      BCM_X_XXX
   1250  */
   1251 int
   1252 bcm_enduro_vlan_vp_destroy(int unit, bcm_gport_t gport)
   1253 {
   1254     int rv;
   1255 
   1256     VLAN_VIRTUAL_INIT(unit);
   1257 
   1258     VLAN_VIRTUAL_LOCK(unit);
   1259 
   1260     rv = _bcm_enduro_vlan_vp_destroy(unit, gport);
   1261 
   1262     VLAN_VIRTUAL_UNLOCK(unit);
   1263 
   1264     return rv;
   1265 }
   1266 
   1267 /*
   1268  * Function:
   1269  *      _bcm_enduro_vlan_vp_find
   1270  * Purpose:
   1271  *      Get VLAN virtual port info.
   1272  * Parameters:
   1273  *      unit - (IN) SOC unit number. 
   1274  *      vlan_vp - (IN/OUT) Pointer to VLAN virtual port structure. 
   1275  * Returns:
   1276  *      BCM_X_XXX
   1277  */
   1278 STATIC int
   1279 _bcm_enduro_vlan_vp_find(int unit, bcm_vlan_port_t *vlan_vp)
   1280 {
   1281     int vp;
   1282     ing_dvp_table_entry_t dvp_entry;
   1283     int nh_index;
   1284 
   1285     if (!BCM_GPORT_IS_VLAN_PORT(vlan_vp->vlan_port_id)) {
   1286         return BCM_E_PARAM;
   1287     }
   1288 
   1289     vp = BCM_GPORT_VLAN_PORT_ID_GET(vlan_vp->vlan_port_id);
   1290     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   1291         return BCM_E_NOT_FOUND;
   1292     }
   1293 
   1294     bcm_vlan_port_t_init(vlan_vp);
   1295 
   1296     BCM_IF_ERROR_RETURN(_bcm_enduro_vlan_vp_match_get(unit, vp, vlan_vp));
   1297 
   1298     vlan_vp->flags = VLAN_VP_INFO(unit, vp)->flags;
   1299 
   1300     BCM_IF_ERROR_RETURN
   1301         (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   1302     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp_entry, NEXT_HOP_INDEXf);
   1303     vlan_vp->encap_id = nh_index;
   1304 
   1305     BCM_GPORT_VLAN_PORT_ID_SET(vlan_vp->vlan_port_id, vp);
   1306 
   1307     return BCM_E_NONE;
   1308 }
   1309 
   1310 /*
   1311  * Function:
   1312  *      bcm_enduro_vlan_vp_find
   1313  * Purpose:
   1314  *      Get VLAN virtual port info.
   1315  * Parameters:
   1316  *      unit - (IN) SOC unit number. 
   1317  *      vlan_vp - (IN/OUT) Pointer to VLAN virtual port structure. 
   1318  * Returns:
   1319  *      BCM_X_XXX
   1320  */
   1321 int
   1322 bcm_enduro_vlan_vp_find(int unit, bcm_vlan_port_t *vlan_vp)
   1323 {
   1324     VLAN_VIRTUAL_INIT(unit);
   1325     return _bcm_enduro_vlan_vp_find(unit, vlan_vp);
   1326 }
   1327 
   1328 /*
   1329  * Function:
   1330  *      _bcm_enduro_vlan_vp_is_local
   1331  * Purpose:
   1332  *      Determine if VLAN VP resides on a local port.
   1333  * Parameters:
   1334  *      unit - (IN) SOC unit number. 
   1335  *      vp   - (IN) Virtual port number.
   1336  *      vp_is_local - (OUT) Indicates if VLAN VP is local.
   1337  * Returns:
   1338  *      BCM_X_XXX
   1339  */
   1340 STATIC int
   1341 _bcm_enduro_vlan_vp_is_local(int unit, int vp, int *vp_is_local)
   1342 {
   1343     bcm_gport_t gport;
   1344     bcm_trunk_t trunk_id;
   1345     int rv = BCM_E_NONE;
   1346     bcm_module_t mod_out;
   1347     bcm_port_t port_out;
   1348     int id;
   1349     int modid_local;
   1350     int local_member_count;
   1351 
   1352     *vp_is_local = 0;
   1353 
   1354     if (vp < 0) {
   1355         return BCM_E_PARAM;
   1356     }
   1357 
   1358     gport = VLAN_VP_INFO(unit, vp)->port;
   1359 
   1360     if (BCM_GPORT_IS_TRUNK(gport)) {
   1361         trunk_id = BCM_GPORT_TRUNK_GET(gport);
   1362         rv = _bcm_trunk_id_validate(unit, trunk_id);
   1363         if (BCM_FAILURE(rv)) {
   1364             return (BCM_E_PORT);
   1365         }
   1366         rv = _bcm_esw_trunk_local_members_get(unit, trunk_id, 0, NULL,
   1367                 &local_member_count);
   1368         if (BCM_FAILURE(rv)) {
   1369             return (BCM_E_PORT);
   1370         }   
   1371 
   1372         if (local_member_count > 0) {
   1373             *vp_is_local = 1;
   1374         }
   1375     } else {
   1376         BCM_IF_ERROR_RETURN
   1377             (_bcm_esw_gport_resolve(unit, gport, &mod_out, &port_out,
   1378                                     &trunk_id, &id)); 
   1379 
   1380         BCM_IF_ERROR_RETURN
   1381             (_bcm_esw_modid_is_local(unit, mod_out, &modid_local));
   1382 
   1383         *vp_is_local = modid_local;
   1384     }
   1385 
   1386     return BCM_E_NONE;
   1387 }
   1388 
   1389 /*
   1390  * Function:
   1391  *      _bcm_enduro_vlan_vp_untagged_add
   1392  * Purpose:
   1393  *      Set VLAN VP tagging/untagging status by adding
   1394  *      a (VLAN VP, VLAN) egress VLAN translation entry.
   1395  * Parameters:
   1396  *      unit - (IN) SOC unit number. 
   1397  *      vlan - (IN) VLAN ID. 
   1398  *      vp   - (IN) Virtual port number.
   1399  *      flags - (IN) Untagging indication.
   1400  * Returns:
   1401  *      BCM_X_XXX
   1402  */
   1403 STATIC int
   1404 _bcm_enduro_vlan_vp_untagged_add(int unit, bcm_vlan_t vlan, int vp,
   1405                                   int flags)
   1406 {
   1407     egr_vlan_xlate_entry_t vent, old_vent;
   1408     bcm_vlan_action_set_t action;
   1409     uint32 profile_idx;
   1410     int rv;
   1411 
   1412     sal_memset(&vent, 0, sizeof(egr_vlan_xlate_entry_t));
   1413 
   1414     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, VALIDf, 1);
   1415 
   1416     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 1);
   1417     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, DVPf, vp);
   1418     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, OVIDf, vlan);
   1419 
   1420     if (VLAN_VP_INFO(unit, vp)->flags & BCM_VLAN_PORT_EGRESS_VLAN16) {
   1421         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, NEW_OTAG_VPTAG_SELf, 1);
   1422         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, NEW_OTAG_VPTAGf,
   1423                                         VLAN_VP_INFO(unit, vp)->match_vlan);
   1424         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, NEW_IVIDf,
   1425                 VLAN_VP_INFO(unit, vp)->egress_vlan & 0xfff);
   1426     } else {
   1427         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, NEW_OTAG_VPTAG_SELf, 0);
   1428         /* egress_vlan in vlan_vp structure is used as switching vlan */
   1429         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, NEW_OVIDf,
   1430                 VLAN_VP_INFO(unit, vp)->match_vlan & 0xfff);
   1431         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, NEW_IVIDf,
   1432                 VLAN_VP_INFO(unit, vp)->egress_vlan & 0xfff);
   1433     }
   1434 
   1435     bcm_vlan_action_set_t_init(&action);
   1436 
   1437     action.dt_outer = bcmVlanActionReplace;
   1438     action.ot_outer = bcmVlanActionReplace;
   1439 
   1440     if (flags & BCM_VLAN_PORT_UNTAGGED) {
   1441         action.dt_inner = bcmVlanActionNone;
   1442         action.ot_inner = bcmVlanActionNone;
   1443     } else {
   1444         action.dt_inner = bcmVlanActionReplace;
   1445         action.ot_inner = bcmVlanActionAdd;
   1446     }
   1447 
   1448     BCM_IF_ERROR_RETURN
   1449         (_bcm_trx_egr_vlan_action_profile_entry_add(unit, &action, &profile_idx));
   1450 
   1451     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, TAG_ACTION_PROFILE_PTRf,
   1452                                 profile_idx);
   1453 
   1454     rv = soc_mem_insert_return_old(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL,
   1455                                    &vent, &old_vent);
   1456     if (rv == SOC_E_EXISTS) {
   1457         /* Delete the old vlan translate profile entry */
   1458         profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &old_vent,
   1459                                                   TAG_ACTION_PROFILE_PTRf);       
   1460         rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, profile_idx);
   1461     }
   1462 
   1463     return rv;
   1464 }
   1465 
   1466 /*
   1467  * Function:
   1468  *      _bcm_enduro_vlan_vp_untagged_delete
   1469  * Purpose:
   1470  *      Delete (VLAN VP, VLAN) egress VLAN translation entry.
   1471  * Parameters:
   1472  *      unit - (IN) SOC unit number. 
   1473  *      vlan - (IN) VLAN ID. 
   1474  *      vp   - (IN) Virtual port number.
   1475  * Returns:
   1476  *      BCM_X_XXX
   1477  */
   1478 STATIC int
   1479 _bcm_enduro_vlan_vp_untagged_delete(int unit, bcm_vlan_t vlan, int vp)
   1480 {
   1481     egr_vlan_xlate_entry_t vent, old_vent;
   1482     uint32 profile_idx;
   1483     int rv;
   1484 
   1485     sal_memset(&vent, 0, sizeof(egr_vlan_xlate_entry_t));
   1486 
   1487     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 1);
   1488     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, DVPf, vp);
   1489     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, OVIDf, vlan);
   1490 
   1491     rv = soc_mem_delete_return_old(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL,
   1492                                    &vent, &old_vent);
   1493     if ((rv == SOC_E_NONE) &&
   1494             soc_EGR_VLAN_XLATEm_field32_get(unit, &old_vent, VALIDf)) {
   1495         /* Delete the old vlan translate profile entry */
   1496         profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &old_vent,
   1497                                                   TAG_ACTION_PROFILE_PTRf);       
   1498         rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, profile_idx);
   1499     }
   1500 
   1501     return rv;
   1502 }
   1503 
   1504 /*
   1505  * Function:
   1506  *      _bcm_enduro_vlan_vp_untagged_delete_all
   1507  * Purpose:
   1508  *      Delete all (VLAN VP, VLAN) egress VLAN translation entries for a
   1509  *      given VLAN.
   1510  * Parameters:
   1511  *      unit - (IN) SOC unit number. 
   1512  *      vlan - (IN) VLAN ID. 
   1513  *      array_size  - (IN) Number of elements in the virtual port array.
   1514  *      gport_array - (IN) Array of VLAN VP GPORT IDs.
   1515  * Returns:
   1516  *      BCM_X_XXX
   1517  */
   1518 STATIC int
   1519 _bcm_enduro_vlan_vp_untagged_delete_all(int unit, bcm_vlan_t vlan,
   1520         int array_size, bcm_gport_t *gport_array)
   1521 {
   1522     int i;
   1523     egr_vlan_xlate_entry_t vent, old_vent;
   1524     int vp;
   1525     uint32 profile_idx;
   1526     int rv = BCM_E_NONE;
   1527 
   1528     for (i = 0; i < array_size; i++) {
   1529 
   1530         sal_memset(&vent, 0, sizeof(egr_vlan_xlate_entry_t));
   1531 
   1532         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 1);
   1533         vp = BCM_GPORT_VLAN_PORT_ID_GET(gport_array[i]);
   1534         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, DVPf, vp);
   1535         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, OVIDf, vlan);
   1536 
   1537         rv = soc_mem_delete_return_old(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL,
   1538                 &vent, &old_vent);
   1539         BCM_IF_ERROR_RETURN(rv);
   1540 
   1541         if (soc_EGR_VLAN_XLATEm_field32_get(unit, &old_vent, VALIDf)) {
   1542             /* Delete the old vlan translate profile entry */
   1543             profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &old_vent,
   1544                     TAG_ACTION_PROFILE_PTRf);       
   1545             rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, profile_idx);
   1546         }
   1547     }
   1548 
   1549     return rv;
   1550 }
   1551 
   1552 /*
   1553  * Function:
   1554  *      _bcm_enduro_vlan_vp_untagged_get
   1555  * Purpose:
   1556  *      Get tagging/untagging status of a VLAN virtual port by
   1557  *      reading the (VLAN VP, VLAN) egress vlan translation entry.
   1558  * Parameters:
   1559  *      unit - (IN) SOC unit number. 
   1560  *      vlan - (IN) VLAN to remove virtual port from.
   1561  *      vp   - (IN) Virtual port number.
   1562  *      flags - (OUT) Untagging status of the VLAN virtual port.
   1563  * Returns:
   1564  *      BCM_E_XXX
   1565  */
   1566 STATIC int
   1567 _bcm_enduro_vlan_vp_untagged_get(int unit, bcm_vlan_t vlan, int vp,
   1568                                  int *flags) 
   1569 {
   1570     egr_vlan_xlate_entry_t vent, res_vent;
   1571     int idx;
   1572     uint32 profile_idx;
   1573     int rv;
   1574     bcm_vlan_action_set_t action;
   1575 
   1576     sal_memset(&vent, 0, sizeof(egr_vlan_xlate_entry_t));
   1577 
   1578     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 1);
   1579     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, DVPf, vp);
   1580     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, OVIDf, vlan);
   1581 
   1582     rv = soc_mem_search(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &idx,
   1583                                    &vent, &res_vent, 0);
   1584     if ((rv == SOC_E_NONE) &&
   1585             soc_EGR_VLAN_XLATEm_field32_get(unit, &res_vent, VALIDf)) {
   1586         profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &res_vent,
   1587                                                   TAG_ACTION_PROFILE_PTRf);       
   1588         _bcm_trx_egr_vlan_action_profile_entry_get(unit, &action, profile_idx);
   1589 
   1590         if (bcmVlanActionNone == action.ot_inner) {
   1591             *flags = BCM_VLAN_PORT_UNTAGGED;
   1592         } else {
   1593             *flags = 0;
   1594         }
   1595     }
   1596 
   1597     return rv;
   1598 }
   1599 
   1600 /*
   1601  * Function:
   1602  *      bcm_enduro_vlan_vp_update_vlan_pbmp
   1603  * Purpose:
   1604  *      Update VLAN table's port bitmap.
   1605  * Parameters:
   1606  *      unit  - (IN) SOC unit number. 
   1607  *      vlan  - (IN) VLAN ID.
   1608  *      pbmp  - (IN) VLAN port bitmap. 
   1609  * Returns:
   1610  *      BCM_E_XXX
   1611  */
   1612 int
   1613 bcm_enduro_vlan_vp_update_vlan_pbmp(int unit, bcm_vlan_t vlan,
   1614         bcm_pbmp_t *pbmp)
   1615 {
   1616     int rv = BCM_E_NONE;
   1617     vlan_tab_entry_t vtab;
   1618     egr_vlan_entry_t egr_vtab;
   1619 
   1620     soc_mem_lock(unit, VLAN_TABm);
   1621     
   1622     rv = soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vlan, &vtab);
   1623     if (rv < 0) {
   1624         soc_mem_unlock(unit, VLAN_TABm);
   1625         return rv;
   1626     }
   1627 
   1628     soc_mem_pbmp_field_set(unit, VLAN_TABm, &vtab, PORT_BITMAPf, pbmp);
   1629     rv = soc_mem_write(unit, VLAN_TABm, MEM_BLOCK_ALL, vlan, &vtab);
   1630     if (rv < 0) {
   1631         soc_mem_unlock(unit, VLAN_TABm);
   1632         return rv;
   1633     }
   1634 
   1635     soc_mem_unlock(unit, VLAN_TABm);
   1636 
   1637     soc_mem_lock(unit, EGR_VLANm);
   1638 
   1639     rv = soc_mem_read(unit, EGR_VLANm, MEM_BLOCK_ANY, vlan, &egr_vtab); 
   1640     if (rv < 0) {
   1641         soc_mem_unlock(unit, EGR_VLANm);
   1642         return rv;
   1643     }
   1644 
   1645     soc_mem_pbmp_field_set(unit, EGR_VLANm, &egr_vtab, PORT_BITMAPf, pbmp);
   1646     rv = soc_mem_write(unit, EGR_VLANm, MEM_BLOCK_ALL, vlan, &egr_vtab);
   1647     if (rv < 0) {
   1648         soc_mem_unlock(unit, EGR_VLANm);
   1649         return rv;
   1650     }
   1651 
   1652     soc_mem_unlock(unit, EGR_VLANm);
   1653 
   1654     return rv;
   1655 }
   1656 
   1657 /*
   1658  * Function:
   1659  *      bcm_enduro_vlan_vp_add
   1660  * Purpose:
   1661  *      Add a VLAN virtual port to the specified vlan.
   1662  * Parameters:
   1663  *      unit  - (IN) SOC unit number. 
   1664  *      vlan  - (IN) VLAN ID to add virtual port to as a member.
   1665  *      gport - (IN) VLAN VP Gport ID
   1666  *      flags - (IN) Indicates if packet should egress out of the given
   1667  *                   VLAN virtual port untagged. 
   1668  * Returns:
   1669  *      BCM_E_XXX
   1670  */
   1671 int
   1672 bcm_enduro_vlan_vp_add(int unit, bcm_vlan_t vlan, bcm_gport_t gport,
   1673                        int flags)
   1674 {
   1675     int rv = BCM_E_NONE;
   1676     int vp;
   1677     int vp_is_local;
   1678     vlan_tab_entry_t vtab;
   1679     bcm_pbmp_t vlan_pbmp, vlan_ubmp, l2_pbmp, l3_pbmp, l2_l3_pbmp;
   1680     int i, mc_idx;
   1681     bcm_vlan_port_t vlan_vp;
   1682     bcm_module_t mod_out;
   1683     bcm_port_t port_out;
   1684     bcm_trunk_t trunk_id;
   1685     int id;
   1686     int mod_local;
   1687     bcm_gport_t local_gport;
   1688     bcm_if_t encap_id;
   1689     bcm_multicast_t group;
   1690     int bc_idx, umc_idx, uuc_idx;
   1691     soc_field_t group_type[3] = {BC_IDXf, UMC_IDXf, UUC_IDXf};
   1692     int bc_do_not_add = 0, umc_do_not_add = 0, uuc_do_not_add = 0;
   1693 
   1694     VLAN_VIRTUAL_INIT(unit);
   1695 
   1696     vp = BCM_GPORT_VLAN_PORT_ID_GET(gport);
   1697     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   1698         return BCM_E_NOT_FOUND;
   1699     }
   1700 
   1701     BCM_IF_ERROR_RETURN
   1702         (_bcm_enduro_vlan_vp_is_local(unit, vp, &vp_is_local));
   1703     if (!vp_is_local) {
   1704         return BCM_E_PORT;
   1705     }
   1706 
   1707     if (flags & ~(BCM_VLAN_PORT_UNTAGGED |
   1708                   BCM_VLAN_GPORT_ADD_UNKNOWN_UCAST_DO_NOT_ADD |
   1709                   BCM_VLAN_GPORT_ADD_UNKNOWN_MCAST_DO_NOT_ADD |
   1710                   BCM_VLAN_GPORT_ADD_BCAST_DO_NOT_ADD)) {
   1711         return BCM_E_PARAM;
   1712     }
   1713 
   1714     sal_memset(&vtab, 0, sizeof(vlan_tab_entry_t));
   1715 
   1716     soc_mem_lock(unit, VLAN_TABm);
   1717 
   1718     rv = soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vlan, &vtab); 
   1719     if (rv < 0) {
   1720         soc_mem_unlock(unit, VLAN_TABm);
   1721         return rv;
   1722     }
   1723 
   1724     if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VALIDf)) {
   1725         soc_mem_unlock(unit, VLAN_TABm);
   1726         return BCM_E_NOT_FOUND;
   1727     }
   1728 
   1729     /* Enable VP switching on the VLAN */
   1730     if (!SHR_BITGET(vlan_info[unit].vp_mode, vlan) && 
   1731         SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
   1732         if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VIRTUAL_PORT_ENf)) {
   1733            soc_mem_field32_set(unit, VLAN_TABm, &vtab, VIRTUAL_PORT_ENf, 1);
   1734            rv = soc_mem_write(unit, VLAN_TABm, MEM_BLOCK_ALL, vlan, &vtab);
   1735            if (rv < 0) {
   1736               soc_mem_unlock(unit, VLAN_TABm);
   1737               return rv;
   1738            }
   1739            soc_mem_unlock(unit, VLAN_TABm);
   1740 
   1741            /* Also need to copy the physical port members to the L2_BITMAP of
   1742             * the IPMC entry for each group once we've gone virtual */
   1743            rv = mbcm_driver[unit]->mbcm_vlan_port_get
   1744                (unit, vlan, &vlan_pbmp, &vlan_ubmp, NULL);
   1745            if (rv < 0) {
   1746                return rv;
   1747            }
   1748 
   1749            /* Deal with each group */
   1750            for (i = 0; i < 3; i++) {
   1751                mc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, group_type[i]);
   1752                rv = _bcm_esw_multicast_ipmc_read(unit, mc_idx, &l2_pbmp, &l3_pbmp);
   1753                if (rv < 0) {
   1754                    return rv;
   1755                }
   1756                rv = _bcm_esw_multicast_ipmc_write(unit, mc_idx, vlan_pbmp,
   1757                    l3_pbmp, TRUE);
   1758                if (rv < 0) {
   1759                    return rv;
   1760                }
   1761            }
   1762         }   
   1763     } else { 
   1764         soc_mem_unlock(unit, VLAN_TABm);
   1765     }
   1766 
   1767     bc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, BC_IDXf);
   1768     umc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UMC_IDXf);
   1769     uuc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UUC_IDXf);
   1770 
   1771     if (flags & BCM_VLAN_GPORT_ADD_BCAST_DO_NOT_ADD) {
   1772         bc_do_not_add = 1;
   1773     } else {
   1774         bc_do_not_add = 0;
   1775     }
   1776     if (flags & BCM_VLAN_GPORT_ADD_UNKNOWN_MCAST_DO_NOT_ADD) {
   1777         umc_do_not_add = 1;
   1778     } else {
   1779         umc_do_not_add = 0;
   1780     }
   1781     if (flags & BCM_VLAN_GPORT_ADD_UNKNOWN_UCAST_DO_NOT_ADD) {
   1782         uuc_do_not_add = 1;
   1783     } else {
   1784         uuc_do_not_add = 0;
   1785     }
   1786 
   1787     if ((bc_idx == umc_idx) && (bc_do_not_add != umc_do_not_add)) {
   1788         return BCM_E_PARAM;
   1789     }
   1790     if ((bc_idx == uuc_idx) && (bc_do_not_add != uuc_do_not_add)) {
   1791         return BCM_E_PARAM;
   1792     }
   1793     if ((umc_idx == uuc_idx) && (umc_do_not_add != uuc_do_not_add)) {
   1794         return BCM_E_PARAM;
   1795     }
   1796     
   1797     /* Get the VP attributes (need physical port) */
   1798     bcm_vlan_port_t_init(&vlan_vp);
   1799     vlan_vp.vlan_port_id = gport;
   1800     rv = _bcm_enduro_vlan_vp_find(unit, &vlan_vp);
   1801     if (rv < 0) {
   1802         return rv;
   1803     }
   1804 
   1805     /* Check if vlan_vp.port is a local port or trunk */
   1806     if (BCM_GPORT_IS_TRUNK(vlan_vp.port)) {
   1807         trunk_id = BCM_GPORT_TRUNK_GET(vlan_vp.port);
   1808         rv = _bcm_trunk_id_validate(unit, trunk_id);
   1809         if (BCM_FAILURE(rv)) {
   1810             return BCM_E_PORT;
   1811         }
   1812         local_gport = vlan_vp.port;
   1813     } else {
   1814         rv = _bcm_esw_gport_resolve(unit, vlan_vp.port, &mod_out, &port_out,
   1815                 &trunk_id, &id); 
   1816         if (BCM_FAILURE(rv)) {
   1817             return (BCM_E_PORT);
   1818         }
   1819         rv = _bcm_esw_modid_is_local(unit, mod_out, &mod_local);
   1820         if (BCM_FAILURE(rv)) {
   1821             return rv;
   1822         }
   1823         if (TRUE != mod_local) {
   1824             /* Only add this to replication set if destination is local */
   1825             return BCM_E_PORT;
   1826         }
   1827         /* Convert system local_port to physical local_port */
   1828         if (soc_feature(unit, soc_feature_sysport_remap)) {
   1829             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   1830         }
   1831         rv = bcm_esw_port_gport_get(unit, port_out, &local_gport);
   1832         if (BCM_FAILURE(rv)) {
   1833             return rv;
   1834         }        
   1835     }
   1836 
   1837     /* Add the VP to the BC group */
   1838     if (!bc_do_not_add) {
   1839         _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, bc_idx);
   1840         rv = bcm_esw_multicast_vlan_encap_get(unit, group, local_gport,
   1841                 gport, &encap_id);
   1842         if (BCM_FAILURE(rv)) {
   1843             return rv;
   1844         }
   1845         rv = bcm_esw_multicast_egress_add(unit, group, local_gport, encap_id); 
   1846         if (rv < 0) {
   1847             return rv;
   1848         } 
   1849 
   1850     }
   1851 
   1852     /* Add the VP to the UMC group, if UMC group is different from BC group */
   1853     if (!umc_do_not_add) {
   1854         if (umc_idx != bc_idx) {
   1855             _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, umc_idx);
   1856             rv = bcm_esw_multicast_vlan_encap_get(unit, group, local_gport,
   1857                     gport, &encap_id);
   1858             if (BCM_FAILURE(rv)) {
   1859                 return rv;
   1860             }
   1861             rv = bcm_esw_multicast_egress_add(unit, group, local_gport, encap_id); 
   1862             if (rv < 0) {
   1863                 return rv;
   1864             }
   1865         }
   1866     }
   1867 
   1868     /* Add the VP to the UUC group, if UUC group is different from BC/UMC group */
   1869     if (!uuc_do_not_add) {
   1870         if ((uuc_idx != bc_idx) && (uuc_idx != umc_idx)) {
   1871             _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, uuc_idx);
   1872             rv = bcm_esw_multicast_vlan_encap_get(unit, group, local_gport,
   1873                     gport, &encap_id);
   1874             if (BCM_FAILURE(rv)) {
   1875                 return rv;
   1876             }
   1877             rv = bcm_esw_multicast_egress_add(unit, group, local_gport, encap_id); 
   1878             if (rv < 0) {
   1879                 return rv;
   1880             }
   1881         }
   1882     }
   1883 
   1884     /* Update the VLAN table's port bitmap to contain the BC/UMC/UUC groups' 
   1885      * L2 and L3 bitmaps, since the VLAN table's port bitmap is used for
   1886      * ingress and egress VLAN membership checks.
   1887      */
   1888 
   1889     BCM_PBMP_CLEAR(l2_l3_pbmp);
   1890     for (i = 0; i < 3; i++) {
   1891         mc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, group_type[i]);
   1892         rv = _bcm_esw_multicast_ipmc_read(unit, mc_idx, &l2_pbmp, &l3_pbmp);
   1893         if (rv < 0) {
   1894             return rv;
   1895         }
   1896         BCM_PBMP_OR(l2_l3_pbmp, l2_pbmp);
   1897         BCM_PBMP_OR(l2_l3_pbmp, l3_pbmp);
   1898     }
   1899 
   1900     rv = bcm_enduro_vlan_vp_update_vlan_pbmp(unit, vlan, &l2_l3_pbmp);
   1901     if (rv < 0) {
   1902         return rv;
   1903     }
   1904 
   1905     VLAN_VIRTUAL_LOCK(unit);
   1906     rv = _bcm_enduro_vlan_vp_untagged_add(unit, vlan, vp, flags);
   1907     VLAN_VIRTUAL_UNLOCK(unit);
   1908 
   1909     return rv;
   1910 }
   1911 
   1912 /*
   1913  * Function:
   1914  *      bcm_enduro_vlan_vp_delete
   1915  * Purpose:
   1916  *      Remove a VLAN virtual port from the specified vlan.
   1917  * Parameters:
   1918  *      unit  - (IN) SOC unit number. 
   1919  *      vlan  - (IN) VLAN to remove virtual port from.
   1920  *      gport - (IN) VLAN VP Gport ID
   1921  * Returns:
   1922  *      BCM_E_XXX
   1923  */
   1924 int
   1925 bcm_enduro_vlan_vp_delete(int unit, bcm_vlan_t vlan, bcm_gport_t gport) 
   1926 {
   1927     int rv = BCM_E_NONE;
   1928     int vp;
   1929     int vp_is_local;
   1930     vlan_tab_entry_t vtab;
   1931     bcm_vlan_port_t vlan_vp;
   1932     bcm_module_t mod_out;
   1933     bcm_port_t port_out;
   1934     bcm_trunk_t trunk_id;
   1935     int id;
   1936     int mod_local;
   1937     bcm_gport_t local_gport;
   1938     int bc_idx, umc_idx, uuc_idx;
   1939     bcm_multicast_t group;
   1940     bcm_if_t encap_id;
   1941     int i, mc_idx;
   1942     soc_field_t group_type[3] = {BC_IDXf, UMC_IDXf, UUC_IDXf};
   1943     bcm_pbmp_t l2_pbmp, l3_pbmp, l2_l3_pbmp;
   1944 
   1945     VLAN_VIRTUAL_INIT(unit);
   1946 
   1947     vp = BCM_GPORT_VLAN_PORT_ID_GET(gport);
   1948     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   1949         return BCM_E_NOT_FOUND;
   1950     }
   1951 
   1952     BCM_IF_ERROR_RETURN
   1953         (_bcm_enduro_vlan_vp_is_local(unit, vp, &vp_is_local));
   1954     if (!vp_is_local) {
   1955         return BCM_E_PORT;
   1956     }
   1957 
   1958     sal_memset(&vtab, 0, sizeof(vlan_tab_entry_t));
   1959 
   1960     rv = soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vlan, &vtab); 
   1961     if (rv < 0) {
   1962         return rv;
   1963     }
   1964 
   1965     if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VALIDf)) {
   1966         return BCM_E_NOT_FOUND;
   1967     }
   1968 
   1969     if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
   1970       if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VIRTUAL_PORT_ENf)) {
   1971          /* VP switching is not enabled on the VLAN */
   1972          return BCM_E_PORT;
   1973       }
   1974     }
   1975 
   1976     /* Get the VP attributes (need physical port) */
   1977     bcm_vlan_port_t_init(&vlan_vp);
   1978     vlan_vp.vlan_port_id = gport;
   1979     rv = _bcm_enduro_vlan_vp_find(unit, &vlan_vp);
   1980     if (rv < 0) {
   1981         return rv;
   1982     }
   1983 
   1984     /* Check if vlan_vp.port is a local port or trunk */
   1985     if (BCM_GPORT_IS_TRUNK(vlan_vp.port)) {
   1986         trunk_id = BCM_GPORT_TRUNK_GET(vlan_vp.port);
   1987         rv = _bcm_trunk_id_validate(unit, trunk_id);
   1988         if (BCM_FAILURE(rv)) {
   1989             return BCM_E_PORT;
   1990         }
   1991         local_gport = vlan_vp.port;
   1992     } else {
   1993         rv = _bcm_esw_gport_resolve(unit, vlan_vp.port, &mod_out, &port_out,
   1994                 &trunk_id, &id); 
   1995         if (BCM_FAILURE(rv)) {
   1996             return (BCM_E_PORT);
   1997         }
   1998         rv = _bcm_esw_modid_is_local(unit, mod_out, &mod_local);
   1999         if (BCM_FAILURE(rv)) {
   2000             return rv;
   2001         }
   2002         if (TRUE != mod_local) {
   2003             /* Only add this to replication set if destination is local */
   2004             return BCM_E_PORT;
   2005         }
   2006         /* Convert system local_port to physical local_port */
   2007         if (soc_feature(unit, soc_feature_sysport_remap)) {
   2008             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   2009         }
   2010         rv = bcm_esw_port_gport_get(unit, port_out, &local_gport);
   2011         if (BCM_FAILURE(rv)) {
   2012             return rv;
   2013         }        
   2014     }
   2015 
   2016     /* Delete the VP from the BC group */
   2017     bc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, BC_IDXf);
   2018     _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, bc_idx);
   2019     rv = bcm_esw_multicast_vlan_encap_get(unit, group, local_gport,
   2020             gport, &encap_id);
   2021     if (BCM_FAILURE(rv)) {
   2022         return rv;
   2023     }
   2024     rv = bcm_esw_multicast_egress_delete(unit, group, local_gport, encap_id); 
   2025     if (rv < 0) {
   2026         return rv;
   2027     }
   2028 
   2029     /* Delete the VP from the UMC group, if UMC group is different
   2030      * from BC group.
   2031      */ 
   2032     umc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UMC_IDXf);
   2033     if (umc_idx != bc_idx) {
   2034         _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, umc_idx);
   2035         rv = bcm_esw_multicast_vlan_encap_get(unit, group, local_gport,
   2036                 gport, &encap_id);
   2037         if (BCM_FAILURE(rv)) {
   2038             return rv;
   2039         }
   2040         rv = bcm_esw_multicast_egress_delete(unit, group, local_gport, encap_id); 
   2041         if (rv < 0) {
   2042             return rv;
   2043         }
   2044     }
   2045 
   2046     /* Delete the VP from the UUC group, if UUC group is different
   2047      * from BC and UMC groups.
   2048      */
   2049     uuc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UUC_IDXf);
   2050     if ((uuc_idx != bc_idx) && (uuc_idx != umc_idx)) {
   2051         _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, uuc_idx);
   2052         rv = bcm_esw_multicast_vlan_encap_get(unit, group, local_gport,
   2053                 gport, &encap_id);
   2054         if (BCM_FAILURE(rv)) {
   2055             return rv;
   2056         }
   2057         rv = bcm_esw_multicast_egress_delete(unit, group, local_gport, encap_id); 
   2058         if (rv < 0) {
   2059             return rv;
   2060         }
   2061     }
   2062 
   2063     /* Update the VLAN table's port bitmap to contain the BC/UMC/UUC groups' 
   2064      * L2 and L3 bitmaps, since the VLAN table's port bitmap is used for
   2065      * ingress and egress VLAN membership checks.
   2066      */
   2067 
   2068     BCM_PBMP_CLEAR(l2_l3_pbmp);
   2069     for (i = 0; i < 3; i++) {
   2070         mc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, group_type[i]);
   2071         rv = _bcm_esw_multicast_ipmc_read(unit, mc_idx, &l2_pbmp, &l3_pbmp);
   2072         if (rv < 0) {
   2073             return rv;
   2074         }
   2075         BCM_PBMP_OR(l2_l3_pbmp, l2_pbmp);
   2076         BCM_PBMP_OR(l2_l3_pbmp, l3_pbmp);
   2077     }
   2078 
   2079     rv = bcm_enduro_vlan_vp_update_vlan_pbmp(unit, vlan, &l2_l3_pbmp);
   2080     if (rv < 0) {
   2081         return rv;
   2082     }
   2083 
   2084     VLAN_VIRTUAL_LOCK(unit);
   2085     rv = _bcm_enduro_vlan_vp_untagged_delete(unit, vlan, vp);
   2086     VLAN_VIRTUAL_UNLOCK(unit);
   2087 
   2088     return rv;
   2089 }
   2090 
   2091 STATIC int
   2092 _bcm_enduro_vlan_mc_group_gport_is_member(int unit, bcm_multicast_t group,
   2093         bcm_gport_t gport, bcm_gport_t vp, int *is_member) 
   2094 {
   2095     int rv = BCM_E_NONE;
   2096     bcm_if_t encap_id;
   2097     int if_max;
   2098     bcm_if_t *if_array;
   2099     int if_count, if_cur;
   2100     int mc_idx;
   2101 
   2102     if (NULL == is_member) {
   2103         return BCM_E_PARAM;
   2104     }
   2105     *is_member = FALSE;
   2106 
   2107     /* Get VP's multicast encap id */
   2108     if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   2109         BCM_IF_ERROR_RETURN(bcm_esw_multicast_vlan_encap_get(unit, group,
   2110                     vp, gport, &encap_id));
   2111     } else {
   2112         return BCM_E_PARAM;
   2113     }
   2114 
   2115     /* Find out if VP is a member of the multicast group */
   2116     if_max = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   2117     if_array = sal_alloc(if_max * sizeof(bcm_if_t),
   2118             "temp repl interface array");
   2119     if (if_array == NULL) {
   2120         return BCM_E_MEMORY;
   2121     }
   2122 
   2123     mc_idx = _BCM_MULTICAST_ID_GET(group);
   2124     {
   2125         rv = bcm_esw_ipmc_egress_intf_get(unit, mc_idx,
   2126                 vp, if_max, if_array, &if_count);
   2127         if (BCM_FAILURE(rv)) {
   2128             sal_free(if_array);
   2129             return rv;
   2130         }
   2131         for (if_cur = 0; if_cur < if_count; if_cur++) {
   2132             if (if_array[if_cur] == encap_id) {
   2133                 *is_member = TRUE;
   2134                 sal_free(if_array);
   2135                 return BCM_E_NONE;
   2136             }
   2137         }
   2138     }
   2139 
   2140     sal_free(if_array);
   2141     return BCM_E_NONE;
   2142 }
   2143 
   2144 
   2145 /*
   2146  * Function:
   2147  *      bcm_enduro_vlan_vp_get
   2148  * Purpose:
   2149  *      Get untagging status of a VLAN virtual port.
   2150  * Parameters:
   2151  *      unit  - (IN) SOC unit number. 
   2152  *      vlan  - (IN) VLAN to remove virtual port from.
   2153  *      gport - (IN) VLAN VP Gport ID
   2154  *      flags - (OUT) Untagging status of the VLAN virtual port.
   2155  * Returns:
   2156  *      BCM_E_XXX
   2157  */
   2158 int
   2159 bcm_enduro_vlan_vp_get(int unit, bcm_vlan_t vlan, bcm_gport_t gport,
   2160         int *flags)
   2161 {
   2162     int rv = BCM_E_NONE;
   2163     int vp;
   2164     bcm_vlan_port_t vlan_vp;
   2165     bcm_gport_t phy_port_trunk = BCM_GPORT_INVALID;
   2166     int vp_is_local;
   2167     vlan_tab_entry_t vtab;
   2168     int bc_idx, umc_idx, uuc_idx;
   2169     bcm_multicast_t group;
   2170     int is_bc_member = FALSE;
   2171     int is_umc_member = FALSE;
   2172     int is_uuc_member = FALSE;
   2173     int untagged_flag = 0;
   2174 
   2175     VLAN_VIRTUAL_INIT(unit);
   2176 
   2177     vp = BCM_GPORT_VLAN_PORT_ID_GET(gport);
   2178     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   2179         return BCM_E_NOT_FOUND;
   2180     }
   2181 
   2182     /* Get the physical port or trunk the VP resides on */
   2183     bcm_vlan_port_t_init(&vlan_vp);
   2184     vlan_vp.vlan_port_id = gport;
   2185     BCM_IF_ERROR_RETURN(bcm_enduro_vlan_vp_find(unit, &vlan_vp));
   2186     phy_port_trunk = vlan_vp.port;
   2187     BCM_IF_ERROR_RETURN
   2188         (_bcm_enduro_vlan_vp_is_local(unit, vp, &vp_is_local));
   2189     if (!vp_is_local) {
   2190         return BCM_E_PORT;
   2191     }
   2192 
   2193     *flags = 0;
   2194     
   2195     sal_memset(&vtab, 0, sizeof(vlan_tab_entry_t));
   2196     SOC_IF_ERROR_RETURN
   2197         (soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vlan, &vtab));
   2198     if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VALIDf)) {
   2199         return BCM_E_NOT_FOUND;
   2200     }
   2201 
   2202     if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
   2203        if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VIRTUAL_PORT_ENf)) {
   2204            /* No virtual port exists for this VLAN */
   2205            return BCM_E_NOT_FOUND;
   2206        } 
   2207     }
   2208     
   2209     if (phy_port_trunk != BCM_GPORT_INVALID) {
   2210     
   2211         bc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, BC_IDXf);
   2212         _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, bc_idx);        
   2213         BCM_IF_ERROR_RETURN(_bcm_enduro_vlan_mc_group_gport_is_member(unit, group,
   2214                     gport, phy_port_trunk, &is_bc_member));
   2215 
   2216         umc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UMC_IDXf);
   2217         if (umc_idx != bc_idx) {
   2218             BCM_IF_ERROR_RETURN(_bcm_tr_multicast_ipmc_group_type_get(unit, umc_idx,
   2219                         &group));
   2220             BCM_IF_ERROR_RETURN(_bcm_enduro_vlan_mc_group_gport_is_member(unit, group,
   2221                         gport, phy_port_trunk, &is_umc_member));
   2222         } else {
   2223             is_umc_member = is_bc_member;
   2224         }
   2225 
   2226         uuc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UUC_IDXf);
   2227         if (uuc_idx != bc_idx && uuc_idx != umc_idx) {
   2228             BCM_IF_ERROR_RETURN(_bcm_tr_multicast_ipmc_group_type_get(unit, uuc_idx,
   2229                         &group));
   2230             BCM_IF_ERROR_RETURN(_bcm_enduro_vlan_mc_group_gport_is_member(unit, group,
   2231                         gport, phy_port_trunk, &is_uuc_member));
   2232         } else if (uuc_idx == bc_idx) {
   2233             is_uuc_member = is_bc_member;
   2234         } else {
   2235             is_uuc_member = is_umc_member;
   2236         }
   2237         
   2238     }
   2239     if (!is_bc_member) {
   2240         *flags |= BCM_VLAN_GPORT_ADD_BCAST_DO_NOT_ADD;
   2241     }
   2242     if (!is_umc_member) {
   2243         *flags |= BCM_VLAN_GPORT_ADD_UNKNOWN_MCAST_DO_NOT_ADD;
   2244     }
   2245     if (!is_uuc_member) {
   2246         *flags |= BCM_VLAN_GPORT_ADD_UNKNOWN_UCAST_DO_NOT_ADD;
   2247     }
   2248     
   2249     rv = _bcm_enduro_vlan_vp_untagged_get(unit, vlan, vp, &untagged_flag);
   2250     
   2251     *flags |= untagged_flag;
   2252     
   2253     return rv;
   2254     
   2255 }
   2256 
   2257 /*
   2258  * Function:
   2259  *      _bcm_enduro_vlan_vp_mc_group_get_all
   2260  * Purpose:
   2261  *      Get all the next hop indices of the given multicast group.
   2262  * Parameters:
   2263  *      unit   - (IN) SOC unit number. 
   2264  *      mc_idx - (IN) Multicast group index.
   2265  *      nh_bitmap - (IN/OUT) Bitmap of next hop indices.
   2266  * Returns:
   2267  *      BCM_E_XXX
   2268  */
   2269 STATIC int
   2270 _bcm_enduro_vlan_vp_mc_group_get_all(int unit, int mc_idx,
   2271         SHR_BITDCL *nh_bitmap)
   2272 {
   2273     bcm_multicast_t mc_group;
   2274     int rv;
   2275     int num_encap_id;
   2276     bcm_if_t *encap_id_array = NULL;
   2277     int i;
   2278     int nh_index;
   2279 
   2280     _BCM_MULTICAST_GROUP_SET(mc_group, _BCM_MULTICAST_TYPE_VLAN, mc_idx);
   2281 
   2282     /* Get the number of encap IDs of the multicast group */
   2283     rv = bcm_esw_multicast_egress_get(unit, mc_group, 0,
   2284                                       NULL, NULL, &num_encap_id);
   2285     if (rv < 0) {
   2286         return rv;
   2287     }
   2288 
   2289     /* Get all the encap IDs of the multicast group */
   2290 
   2291     encap_id_array = sal_alloc(sizeof(bcm_if_t) * num_encap_id,
   2292             "encap_id_array");
   2293     if (NULL == encap_id_array) {
   2294         return BCM_E_MEMORY;
   2295     }
   2296     sal_memset(encap_id_array, 0, sizeof(bcm_if_t) * num_encap_id);
   2297 
   2298     rv = bcm_esw_multicast_egress_get(unit, mc_group, num_encap_id,
   2299                                       NULL, encap_id_array, &num_encap_id);
   2300     if (rv < 0) {
   2301         sal_free(encap_id_array);
   2302         return rv;
   2303     }
   2304 
   2305     /* Convert encap IDs to next hop indices */
   2306 
   2307     for (i = 0; i < num_encap_id; i++) {
   2308         if (BCM_IF_INVALID != (uint32)encap_id_array[i]) {
   2309             nh_index = encap_id_array[i];
   2310             SHR_BITSET(nh_bitmap, nh_index);
   2311         }
   2312     }
   2313 
   2314     sal_free(encap_id_array);
   2315     return rv;
   2316 }
   2317 
   2318 /*
   2319  * Function:
   2320  *      bcm_enduro_vlan_vp_get_all
   2321  * Purpose:
   2322  *      Get virtual ports of the given VLAN.
   2323  * Parameters:
   2324  *      unit      - (IN) SOC unit number. 
   2325  *      vlan      - (IN) VLAN ID.
   2326  *      array_max - (IN) Max number of elements in the array.
   2327  *      gport_array       - (OUT) Array of virtual ports in GPORT format.
   2328  *      flags_array       - (OUT) Array of untagging status.
   2329  *      array_size        - (OUT) Actual number of elements in the array.
   2330  * Returns:
   2331  *      BCM_E_XXX
   2332  * Notes: If array_max == 0 and gport_array == NULL, actual number of
   2333  *        virtual ports in the VLAN will be returned in array_size.
   2334  */
   2335 int
   2336 bcm_enduro_vlan_vp_get_all(int unit, bcm_vlan_t vlan, int array_max,
   2337         bcm_gport_t *gport_array, int *flags_array, int *array_size) 
   2338 {
   2339     vlan_tab_entry_t vtab;
   2340     int        nh_tbl_size;
   2341     SHR_BITDCL *nh_bitmap = NULL;
   2342     int        bc_idx, umc_idx, uuc_idx;
   2343     int        rv;
   2344     int        i;
   2345     egr_l3_next_hop_entry_t egr_nh;
   2346     int        dvp;
   2347 
   2348     if (array_max < 0) {
   2349         return BCM_E_PARAM;
   2350     }
   2351 
   2352     if ((array_max > 0) && (NULL == gport_array)) {
   2353         return BCM_E_PARAM;
   2354     }
   2355 
   2356     if (NULL == array_size) {
   2357         return BCM_E_PARAM;
   2358     }
   2359 
   2360     *array_size = 0;
   2361 
   2362     VLAN_VIRTUAL_INIT(unit);
   2363 
   2364     BCM_IF_ERROR_RETURN
   2365         (soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, (int)vlan, &vtab));
   2366    
   2367     if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
   2368        if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VIRTUAL_PORT_ENf)) {
   2369            /* This vlan has no virtual port members. */
   2370            return BCM_E_NONE;
   2371        } 
   2372     }
   2373 
   2374     nh_tbl_size = soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   2375     nh_bitmap = sal_alloc(SHR_BITALLOCSIZE(nh_tbl_size), "nh_bitmap");
   2376     if (NULL == nh_bitmap) {
   2377         return BCM_E_MEMORY;
   2378     }
   2379     sal_memset(nh_bitmap, 0, SHR_BITALLOCSIZE(nh_tbl_size));
   2380 
   2381     /* Get VPs from BC group */
   2382     bc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, BC_IDXf);
   2383     rv = _bcm_enduro_vlan_vp_mc_group_get_all(unit, bc_idx, nh_bitmap);
   2384     if (rv < 0) {
   2385         goto cleanup;
   2386     }
   2387 
   2388     /* Get VPs from UMC group, if different from BC group */
   2389     umc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UMC_IDXf);
   2390     if (umc_idx != bc_idx) {
   2391         rv = _bcm_enduro_vlan_vp_mc_group_get_all(unit, umc_idx, nh_bitmap);
   2392         if (rv < 0) {
   2393             goto cleanup;
   2394         }
   2395     }
   2396 
   2397     /* Get VPs from UUC group, if different from BC and UMC group */
   2398     uuc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UUC_IDXf);
   2399     if ((uuc_idx != bc_idx) && (uuc_idx != umc_idx)) {
   2400         rv = _bcm_enduro_vlan_vp_mc_group_get_all(unit, uuc_idx, nh_bitmap);
   2401         if (rv < 0) {
   2402             goto cleanup;
   2403         }
   2404     }
   2405 
   2406     /* Convert next hop indices to VLAN VP gports */
   2407     for (i = 0; i < nh_tbl_size; i++) {
   2408         if (SHR_BITGET(nh_bitmap, i)) {
   2409             if (0 == array_max) {
   2410                 (*array_size)++;
   2411             } else {
   2412                 rv = READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, i, &egr_nh); 
   2413                 if (rv < 0) {
   2414                     goto cleanup;
   2415                 }
   2416                 dvp = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, SD_TAG__DVPf);
   2417                 BCM_GPORT_VLAN_PORT_ID_SET(gport_array[*array_size], dvp);
   2418                 if (NULL != flags_array) {
   2419                     rv = _bcm_enduro_vlan_vp_untagged_get(unit, vlan, dvp,
   2420                             &flags_array[*array_size]);
   2421                     if (rv < 0) {
   2422                         goto cleanup;
   2423                     }
   2424                 }
   2425                 (*array_size)++;
   2426                 if (*array_size == array_max) {
   2427                     break;
   2428                 }
   2429             }
   2430         }
   2431     }
   2432 
   2433 cleanup:
   2434     if (NULL != nh_bitmap) {
   2435         sal_free(nh_bitmap);
   2436     }
   2437 
   2438     return rv;
   2439 }
   2440 
   2441 /*
   2442  * Function:
   2443  *      bcm_enduro_vlan_vp_delete_all
   2444  * Purpose:
   2445  *      Remove all VLAN virtual ports from the specified vlan.
   2446  * Parameters:
   2447  *      unit  - (IN) SOC unit number. 
   2448  *      vlan  - (IN) VLAN to remove virtual ports from.
   2449  * Returns:
   2450  *      BCM_E_XXX
   2451  */
   2452 int
   2453 bcm_enduro_vlan_vp_delete_all(int unit, bcm_vlan_t vlan) 
   2454 {
   2455     vlan_tab_entry_t vtab;
   2456     int num_vp;
   2457     bcm_gport_t *gport_array = NULL;
   2458     int rv = BCM_E_NONE;
   2459     int bc_idx, umc_idx, uuc_idx;
   2460     bcm_multicast_t group;
   2461 
   2462     VLAN_VIRTUAL_INIT(unit);
   2463 
   2464     sal_memset(&vtab, 0, sizeof(vlan_tab_entry_t));
   2465 
   2466     BCM_IF_ERROR_RETURN
   2467         (soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vlan, &vtab)); 
   2468 
   2469     if (!soc_mem_field32_get(unit, VLAN_TABm, &vtab, VALIDf)) {
   2470         return BCM_E_NOT_FOUND;
   2471     }
   2472 
   2473     if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
   2474        if (soc_mem_field32_get(unit, VLAN_TABm, &vtab, VIRTUAL_PORT_ENf)) {
   2475 
   2476            /* Get all VPs from the VLAN before deletion */
   2477 
   2478            BCM_IF_ERROR_RETURN
   2479                (bcm_enduro_vlan_vp_get_all(unit, vlan, 0, NULL, NULL, &num_vp));
   2480 
   2481            gport_array = sal_alloc(sizeof(bcm_gport_t) * num_vp,
   2482                   "vlan vp gport array");
   2483            if (NULL == gport_array) {
   2484                return BCM_E_MEMORY;
   2485            }   
   2486            sal_memset(gport_array, 0, sizeof(bcm_gport_t) * num_vp);
   2487 
   2488            rv = bcm_enduro_vlan_vp_get_all(unit, vlan, num_vp,
   2489                    gport_array, NULL, &num_vp);
   2490            if (rv < 0) {
   2491                goto cleanup;
   2492            }   
   2493 
   2494            /* Delete all VPs from the BC group */
   2495 
   2496            bc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, BC_IDXf);
   2497            _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, bc_idx);
   2498            rv = bcm_esw_multicast_egress_delete_all(unit, group); 
   2499            if (rv < 0) {
   2500                goto cleanup;
   2501            }   
   2502            rv = bcm_esw_multicast_destroy(unit, group);
   2503            if (rv < 0) {
   2504                goto cleanup;
   2505            }
   2506 
   2507            /* Delete all VPs from the UMC group, if UMC group is different
   2508             * from BC group.
   2509             */ 
   2510 
   2511            umc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UMC_IDXf);
   2512            if (umc_idx != bc_idx) {
   2513             _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, umc_idx);
   2514             rv = bcm_esw_multicast_egress_delete_all(unit, group); 
   2515             if (rv < 0) {
   2516                 goto cleanup;
   2517             }
   2518             rv = bcm_esw_multicast_destroy(unit, group);
   2519             if (rv < 0) {
   2520                 goto cleanup;
   2521             }
   2522         }
   2523 
   2524         /* Delete all VPs from the UUC group, if UUC group is different
   2525          * from BC and UMC groups.
   2526          */
   2527         uuc_idx = soc_mem_field32_get(unit, VLAN_TABm, &vtab, UUC_IDXf);
   2528         if ((uuc_idx != bc_idx) && (uuc_idx != umc_idx)) {
   2529             _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_VLAN, uuc_idx);
   2530             rv = bcm_esw_multicast_egress_delete_all(unit, group); 
   2531             if (rv < 0) {
   2532                 goto cleanup;
   2533             }
   2534             rv = bcm_esw_multicast_destroy(unit, group);
   2535             if (rv < 0) {
   2536                 goto cleanup;
   2537             }
   2538         }
   2539 
   2540         if (!SHR_BITGET(vlan_info[unit].vp_mode, vlan) &&
   2541             SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VIRTUAL_PORT_ENf)) {
   2542             soc_mem_field32_set(unit, VLAN_TABm, &vtab, VIRTUAL_PORT_ENf, 0);
   2543         }
   2544         soc_mem_field32_set(unit, VLAN_TABm, &vtab, BC_IDXf, 0);
   2545         soc_mem_field32_set(unit, VLAN_TABm, &vtab, UMC_IDXf, 0);
   2546         soc_mem_field32_set(unit, VLAN_TABm, &vtab, UUC_IDXf, 0);
   2547         rv = soc_mem_write(unit, VLAN_TABm, MEM_BLOCK_ALL, (int)vlan, &vtab);
   2548         if (rv < 0) {
   2549             goto cleanup;
   2550         }
   2551 
   2552         /* Delete all DVP tagging/untagging entries */
   2553         VLAN_VIRTUAL_LOCK(unit);
   2554         rv = _bcm_enduro_vlan_vp_untagged_delete_all(unit, vlan,
   2555                 num_vp, gport_array);
   2556         VLAN_VIRTUAL_UNLOCK(unit);
   2557         if (rv < 0) {
   2558             goto cleanup;
   2559         }
   2560       }
   2561     }
   2562 
   2563 cleanup:
   2564     if (NULL != gport_array) {
   2565         sal_free(gport_array);
   2566     }
   2567     return rv;
   2568 }
   2569 
   2570 /*
   2571  * Function:
   2572  *      _bcm_enduro_vlan_port_resolve
   2573  * Purpose:
   2574  *      Get the modid, port, trunk values for a VLAN virtual port
   2575  * Parameters:
   2576  *      unit - (IN) BCM device number
   2577  *      gport - (IN) Global port identifier
   2578  *      modid - (OUT) Module ID
   2579  *      port - (OUT) Port number
   2580  *      trunk_id - (OUT) Trunk ID
   2581  *      id - (OUT) Virtual port ID
   2582  * Returns:
   2583  *      BCM_E_XXX
   2584  */
   2585 int
   2586 _bcm_enduro_vlan_port_resolve(int unit, bcm_gport_t vlan_port_id,
   2587                           bcm_module_t *modid, bcm_port_t *port,
   2588                           bcm_trunk_t *trunk_id, int *id)
   2589 
   2590 {
   2591     int rv = BCM_E_NONE, nh_index, vp;
   2592     ing_l3_next_hop_entry_t ing_nh;
   2593     ing_dvp_table_entry_t dvp;
   2594 
   2595     VLAN_VIRTUAL_INIT(unit);
   2596 
   2597     if (!BCM_GPORT_IS_VLAN_PORT(vlan_port_id)) {
   2598         return (BCM_E_BADID);
   2599     }
   2600 
   2601     vp = BCM_GPORT_VLAN_PORT_ID_GET(vlan_port_id);
   2602     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   2603         return BCM_E_NOT_FOUND;
   2604     }
   2605     BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   2606     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   2607                                               NEXT_HOP_INDEXf);
   2608     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   2609                                       nh_index, &ing_nh));
   2610 
   2611     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x2) {
   2612         /* Entry type is not L2 DVP */
   2613         return BCM_E_NOT_FOUND;
   2614     }
   2615     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   2616         *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   2617     } else {
   2618         /* Only add this to replication set if destination is local */
   2619         *modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   2620         *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   2621     }
   2622     *id = vp;
   2623     return rv;
   2624 }
   2625 
   2626 
   2627 #endif /* BCM_ENDURO_SUPPORT && INCLUDE_L3 */