openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

multicast.c (21494B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:    multicast.c
      8  * Purpose: Implements procedures needed by the feature of
      9  *          L3 interface-on-virtual port multicast encapsulation ID.
     10  */
     11 
     12 #include <soc/defs.h>
     13 #include <sal/core/libc.h>
     14 #include <shared/bsl.h>
     15 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
     16 
     17 #include <soc/drv.h>
     18 
     19 #include <bcm/error.h>
     20 #include <bcm/types.h>
     21 
     22 #include <bcm_int/esw/firebolt.h>
     23 #include <bcm_int/esw/trident.h>
     24 #include <bcm_int/esw/trident2.h>
     25 #include <bcm_int/esw/virtual.h>
     26 #include <bcm_int/esw_dispatch.h>
     27 #include <bcm_int/esw/qos.h>
     28 
     29 
     30 typedef struct _td2_l3_vp_encap_id_s {
     31     int vp; /* The virtual port on which the L3 interface resides */
     32     int nh_index; /* The next hop index used by MMU replication */
     33     struct _td2_l3_vp_encap_id_s *next; /* Pointer to next element in
     34                                            linked list */
     35 } _td2_l3_vp_encap_id_t;
     36 
     37 typedef struct _td2_multicast_l3_vp_s {
     38     _td2_l3_vp_encap_id_t **list_array; /* Array of lists of encap IDs,
     39                                           indexed by L3 interface */
     40     int list_array_size; /* Number of lists in list_array */
     41 } _td2_multicast_l3_vp_t;
     42 
     43 STATIC _td2_multicast_l3_vp_t *_td2_multicast_l3_vp_info[BCM_MAX_NUM_UNITS];
     44 
     45 #ifdef BCM_WARM_BOOT_SUPPORT
     46 
     47 /*
     48  * Function:
     49  *      _bcm_td2_multicast_l3_vp_reinit
     50  * Purpose:
     51  *      Recover software state for warm boot.
     52  * Parameters:
     53  *      unit  - (IN) Unit number.
     54  * Returns:
     55  *      BCM_E_XXX
     56  */
     57 STATIC int 
     58 _bcm_td2_multicast_l3_vp_reinit(int unit)
     59 {
     60     int rv = BCM_E_NONE;
     61     int chunk_size, num_chunks;
     62     uint8 *egr_nh_buf = NULL;
     63     int chunk_index;
     64     int entry_index_min, entry_index_max;
     65     int i;
     66     uint32 *egr_nh_entry;
     67     int vp, intf;
     68     _td2_l3_vp_encap_id_t *l3_vp_encap_id;
     69     soc_field_t   entry_type_field;
     70 
     71     chunk_size = 1024;
     72     num_chunks = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm) / chunk_size;
     73     if (soc_mem_index_count(unit, EGR_L3_NEXT_HOPm) % chunk_size) {
     74         num_chunks++;
     75     }
     76 
     77     egr_nh_buf = soc_cm_salloc(unit, sizeof(egr_l3_next_hop_entry_t) *
     78             chunk_size, "EGR_L3_NEXT_HOP entry buffer");
     79     if (NULL == egr_nh_buf) {
     80         rv = BCM_E_MEMORY;
     81         goto cleanup;
     82     }
     83 
     84     for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) {
     85 
     86         /* Get a chunk of entries */
     87         entry_index_min = chunk_index * chunk_size;
     88         entry_index_max = entry_index_min + chunk_size - 1;
     89         if (entry_index_max > soc_mem_index_max(unit, EGR_L3_NEXT_HOPm)) {
     90             entry_index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOPm);
     91         }
     92         rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
     93                 entry_index_min, entry_index_max, egr_nh_buf);
     94         if (SOC_FAILURE(rv)) {
     95             goto cleanup;
     96         }
     97 
     98         /* Read each entry of the chunk */
     99         for (i = 0; i < (entry_index_max - entry_index_min + 1); i++) {
    100             egr_nh_entry = soc_mem_table_idx_to_pointer(unit,
    101                     EGR_L3_NEXT_HOPm, uint32 *, egr_nh_buf, i);
    102             if (SOC_IS_TRIDENT3X(unit)) {
    103                 entry_type_field = DATA_TYPEf;
    104             } else {
    105                 entry_type_field = ENTRY_TYPEf;
    106             }
    107             if (7 != soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
    108                         entry_type_field)) {
    109                 continue;
    110             }
    111 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    112             if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
    113                 if (1 != soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
    114                             L3MC__NEXT_PTR_TYPEf)) {
    115                     continue;
    116                 }
    117             } else
    118 #endif
    119             if (1 != soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
    120                         L3MC__DVP_VALIDf)) {
    121                 continue;
    122             }
    123 
    124             vp = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
    125                     L3MC__DVPf);
    126             if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv) &&
    127                 !_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender) &&
    128                 !_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
    129                 continue;
    130             }
    131             intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
    132                     L3MC__INTF_NUMf);
    133 
    134             /* Add the VP and the next hop index to the L3 interface's
    135              * linked list of encap IDs.
    136              */
    137             l3_vp_encap_id = sal_alloc(sizeof(_td2_l3_vp_encap_id_t),
    138                     "L3 interface-on-virtual port encap ID");
    139             if  (NULL == l3_vp_encap_id) {
    140                 rv = BCM_E_MEMORY;
    141                 goto cleanup;
    142             }
    143             l3_vp_encap_id->vp = vp;
    144             l3_vp_encap_id->nh_index = entry_index_min + i;
    145             l3_vp_encap_id->next = _td2_multicast_l3_vp_info[unit]->list_array[intf];
    146             _td2_multicast_l3_vp_info[unit]->list_array[intf] = l3_vp_encap_id;
    147         }
    148     }
    149 
    150 cleanup:
    151     if (egr_nh_buf) {
    152         soc_cm_sfree(unit, egr_nh_buf);
    153     }
    154 
    155     if (BCM_FAILURE(rv)) {
    156         (void) bcm_td2_multicast_l3_vp_detach(unit);
    157     }
    158 
    159     return rv;
    160 }
    161 
    162 #endif /* BCM_WARM_BOOT_SUPPORT */
    163 
    164 /*
    165  * Function:
    166  *      bcm_td2_multicast_l3_vp_detach
    167  * Purpose:
    168  *      Deallocate data structures for storing L3 interface-on-virtual port
    169  *      multicast encapsulation IDs.
    170  * Parameters:
    171  *      unit - (IN) SOC unit number.
    172  * Returns:
    173  *      BCM_E_xxx
    174  */
    175 int
    176 bcm_td2_multicast_l3_vp_detach(int unit)
    177 {
    178     int i;
    179     _td2_l3_vp_encap_id_t *curr_ptr;
    180     _td2_l3_vp_encap_id_t *next_ptr;
    181 
    182     if (_td2_multicast_l3_vp_info[unit]) {
    183         if (_td2_multicast_l3_vp_info[unit]->list_array) {
    184             for (i = 0; i < _td2_multicast_l3_vp_info[unit]->list_array_size;
    185                     i++) {
    186                 /* Traverse linked list of encap IDs */
    187                 curr_ptr = _td2_multicast_l3_vp_info[unit]->list_array[i];
    188                 while (NULL != curr_ptr) {
    189                     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0,
    190                                 curr_ptr->nh_index));
    191                     next_ptr = curr_ptr->next;
    192                     sal_free(curr_ptr);
    193                     curr_ptr = next_ptr;
    194                 }
    195                 _td2_multicast_l3_vp_info[unit]->list_array[i] = NULL;
    196             }
    197             sal_free(_td2_multicast_l3_vp_info[unit]->list_array);
    198             _td2_multicast_l3_vp_info[unit]->list_array = NULL;
    199         }
    200         sal_free(_td2_multicast_l3_vp_info[unit]);
    201         _td2_multicast_l3_vp_info[unit] = NULL;
    202     }
    203 
    204     return BCM_E_NONE;
    205 }
    206 
    207 /*
    208  * Function:
    209  *      bcm_td2_multicast_l3_vp_init
    210  * Purpose:
    211  *      Initialize the data structures for storing L3 interface-on-virtual port
    212  *      multicast encapsulation IDs.
    213  * Parameters:
    214  *      unit  - (IN) Unit number.
    215  * Returns:
    216  *      BCM_E_XXX
    217  */
    218 int 
    219 bcm_td2_multicast_l3_vp_init(int unit)
    220 {
    221     int list_array_size;
    222 
    223     BCM_IF_ERROR_RETURN(bcm_td2_multicast_l3_vp_detach(unit));
    224 
    225     _td2_multicast_l3_vp_info[unit] = sal_alloc
    226         (sizeof(_td2_multicast_l3_vp_t), "Multicast L3 VP info");
    227     if (NULL == _td2_multicast_l3_vp_info[unit]) {
    228         (void) bcm_td2_multicast_l3_vp_init(unit);
    229         return BCM_E_MEMORY;
    230     }
    231     sal_memset(_td2_multicast_l3_vp_info[unit], 0,
    232             sizeof(_td2_multicast_l3_vp_t));
    233 
    234     list_array_size = soc_mem_index_count(unit, EGR_L3_INTFm);
    235     _td2_multicast_l3_vp_info[unit]->list_array = sal_alloc
    236         (sizeof(_td2_l3_vp_encap_id_t *) * list_array_size,
    237          "Encap ID list array");
    238     if (NULL == _td2_multicast_l3_vp_info[unit]->list_array) {
    239         (void) bcm_td2_multicast_l3_vp_init(unit);
    240         return BCM_E_MEMORY;
    241     }
    242     sal_memset(_td2_multicast_l3_vp_info[unit]->list_array, 0,
    243             sizeof(_td2_l3_vp_encap_id_t *) * list_array_size);
    244     _td2_multicast_l3_vp_info[unit]->list_array_size = list_array_size;
    245 
    246 #ifdef BCM_WARM_BOOT_SUPPORT
    247     if (SOC_WARM_BOOT(unit)) {
    248         BCM_IF_ERROR_RETURN(_bcm_td2_multicast_l3_vp_reinit(unit));
    249     }
    250 #endif /* BCM_WARM_BOOT_SUPPORT */
    251 
    252     return BCM_E_NONE;
    253 }
    254 
    255 /*
    256  * Function:
    257  *      bcm_td2_multicast_l3_vp_encap_get
    258  * Purpose:
    259  *      Get the Encap ID for a L3 interface on a virtual port.
    260  * Parameters:
    261  *      unit  - (IN) Unit number.
    262  *      group - (IN) Multicast group ID.
    263  *      port  - (IN) Virtual port GPORT ID.
    264  *      intf  - (IN) L3 interface ID.
    265  *      encap_id - (OUT) Encap ID.
    266  * Returns:
    267  *      BCM_E_XXX
    268  */
    269 int 
    270 bcm_td2_multicast_l3_vp_encap_get(int unit, bcm_multicast_t group,
    271                                bcm_gport_t port, bcm_if_t intf,
    272                                bcm_if_t *encap_id)
    273 {
    274     int vp;
    275     _td2_l3_vp_encap_id_t *curr_ptr;
    276     _td2_l3_vp_encap_id_t *l3_vp_encap_id;
    277     bcm_l3_egress_t nh_info;
    278     uint32 nh_flags;
    279     int nh_index;
    280     egr_l3_next_hop_entry_t egr_nh;
    281     bcm_niv_port_t niv_port;
    282     bcm_extender_port_t extender_port;
    283     int etag_dot1p_mapping_ptr = 0;
    284     bcm_niv_egress_t niv_egress;
    285     int              rv                   = BCM_E_NONE;
    286     uint16           virtual_interface_id = 0;
    287     uint32           mc_flags             = 0;
    288     int              count;
    289     bcm_extender_egress_t extender_egress;
    290     uint16 extended_port_vid;
    291     uint8 pcp, de;
    292     uint32 pcp_de_select;
    293     int qos_map_id;
    294 
    295     if (NULL == _td2_multicast_l3_vp_info[unit]) {
    296         return BCM_E_INIT;
    297     }
    298 
    299     /* Check virtual port */
    300     if (BCM_GPORT_IS_VLAN_PORT(port)) {
    301         vp = BCM_GPORT_VLAN_PORT_ID_GET(port);
    302         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
    303             return BCM_E_PARAM;
    304         }
    305     } else if (BCM_GPORT_IS_NIV_PORT(port)) {
    306         vp = BCM_GPORT_NIV_PORT_ID_GET(port);
    307         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
    308             return BCM_E_PARAM;
    309         }
    310     } else if (BCM_GPORT_IS_EXTENDER_PORT(port)) {
    311         vp = BCM_GPORT_EXTENDER_PORT_ID_GET(port);
    312         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
    313             return BCM_E_PARAM;
    314         }
    315     } else {
    316         return BCM_E_PARAM;
    317     }
    318 
    319     /* Search the linked list of L3 interface-on-virtual port encap IDs */
    320     curr_ptr = _td2_multicast_l3_vp_info[unit]->list_array[intf];
    321     while (NULL != curr_ptr) {
    322         if (curr_ptr->vp == vp) {
    323             *encap_id = curr_ptr->nh_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
    324             return BCM_E_NONE;
    325         }
    326         curr_ptr = curr_ptr->next;
    327     }
    328 
    329     /* Get a free next hop index */
    330     bcm_l3_egress_t_init(&nh_info);
    331     nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
    332     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index));
    333 
    334     /* Write EGR_L3_NEXT_HOP entry */
    335     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    336 #ifdef BCM_TRIDENT3_SUPPORT
    337     if (SOC_IS_TRIDENT3X(unit)) {
    338         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, DATA_TYPEf, 7);
    339     } else
    340 #endif /* BCM_TRIDENT3_SUPPORT */
    341     {
    342         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, ENTRY_TYPEf, 7);
    343     }
    344     soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__INTF_NUMf, intf);
    345 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    346     if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
    347         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh,
    348                 L3MC__NEXT_PTR_TYPEf, 1);
    349     } else
    350 #endif
    351     {
    352         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__DVP_VALIDf, 1);
    353     }
    354     soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__DVPf, vp);
    355     if (BCM_GPORT_IS_NIV_PORT(port)) {
    356         niv_port.niv_port_id = port;
    357         BCM_IF_ERROR_RETURN(bcm_esw_niv_port_get(unit, &niv_port));
    358         if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) {
    359             bcm_niv_egress_t_init(&niv_egress);
    360             rv = bcm_trident_niv_egress_get(unit, niv_port.niv_port_id,
    361                                             1, &niv_egress, &count);
    362             if(BCM_FAILURE(rv)) {
    363                 return BCM_E_PARAM;
    364             }
    365 
    366             if (niv_egress.flags & BCM_NIV_EGRESS_MULTICAST) {
    367                 return BCM_E_PARAM;
    368             } else {
    369                 virtual_interface_id = niv_egress.virtual_interface_id;
    370                 mc_flags             = 0;
    371             }
    372         } else {
    373             virtual_interface_id = niv_port.virtual_interface_id;
    374             mc_flags             = niv_port.flags & BCM_NIV_PORT_MULTICAST;
    375         }
    376         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__VNTAG_DST_VIFf,
    377                 virtual_interface_id);
    378         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__VNTAG_Pf,
    379                 mc_flags ? 1 : 0);
    380         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__VNTAG_ACTIONSf,
    381                 1);
    382     } else if (BCM_GPORT_IS_EXTENDER_PORT(port)) {
    383         extender_port.extender_port_id = port;
    384         BCM_IF_ERROR_RETURN(bcm_esw_extender_port_get(unit, &extender_port));
    385         if (extender_port.flags & BCM_EXTENDER_PORT_MATCH_NONE) {
    386             bcm_extender_egress_t_init(&extender_egress);
    387             BCM_IF_ERROR_RETURN(bcm_esw_extender_egress_get_all(unit,
    388                         extender_port.extender_port_id, 1, &extender_egress, &count));
    389             if (count == 0) {
    390                 /* No Extender egress object has been added to VP yet. */
    391                 return BCM_E_CONFIG;
    392             }
    393             if (extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) {
    394                 return BCM_E_PARAM;
    395             }
    396             qos_map_id        = extender_egress.qos_map_id;
    397             extended_port_vid = extender_egress.extended_port_vid;
    398             pcp_de_select     = extender_egress.pcp_de_select;
    399             pcp               = extender_egress.pcp;
    400             de                = extender_egress.de;
    401         } else {
    402             qos_map_id        = extender_port.qos_map_id;
    403             extended_port_vid = extender_port.extended_port_vid;
    404             pcp_de_select     = extender_port.pcp_de_select;
    405             pcp               = extender_port.pcp;
    406             de                = extender_port.de;
    407         }
    408 
    409         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__VNTAG_DST_VIFf,
    410                 extended_port_vid);
    411         soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh, L3MC__VNTAG_ACTIONSf,
    412                 2);
    413         if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_DEFAULT) {
    414             soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh,
    415                     L3MC__ETAG_PCP_DE_SOURCEf, 2);
    416             soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh,
    417                     L3MC__ETAG_PCPf, pcp);
    418             soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh,
    419                     L3MC__ETAG_DEf, de);
    420         } else if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_PHB) {
    421             soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh,
    422                     L3MC__ETAG_PCP_DE_SOURCEf, 3);
    423             bcm_td2_qos_egr_etag_id2profile(unit, qos_map_id,
    424                                                     &etag_dot1p_mapping_ptr);
    425             soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh,
    426                     L3MC__ETAG_DOT1P_MAPPING_PTRf, etag_dot1p_mapping_ptr);
    427         } else {
    428             return BCM_E_INTERNAL;
    429         }
    430     }
    431     SOC_IF_ERROR_RETURN
    432         (WRITE_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ALL, nh_index, &egr_nh));
    433 
    434     /* Add the next hop index to the linked list of L3 interface-on-virtual
    435      * port encap IDs.
    436      */
    437     l3_vp_encap_id = sal_alloc(sizeof(_td2_l3_vp_encap_id_t),
    438             "L3 interface-on-virtual port encap ID");
    439     if  (NULL == l3_vp_encap_id) {
    440         (void) bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index);
    441         return BCM_E_MEMORY;
    442     }
    443     l3_vp_encap_id->vp = vp;
    444     l3_vp_encap_id->nh_index = nh_index;
    445     l3_vp_encap_id->next = _td2_multicast_l3_vp_info[unit]->list_array[intf];
    446     _td2_multicast_l3_vp_info[unit]->list_array[intf] = l3_vp_encap_id;
    447 
    448     /* Form encap id */
    449     *encap_id = nh_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
    450 
    451     return BCM_E_NONE;
    452 }
    453 
    454 /*
    455  * Function:
    456  *      bcm_td2_multicast_l3_vp_next_hop_free
    457  * Purpose:
    458  *      Free the next hop indices allocated for a given L3 interface.
    459  * Parameters:
    460  *      unit - (IN) Unit number.
    461  *      intf - (IN) L3 interface.
    462  * Returns:
    463  *      BCM_E_XXX
    464  */
    465 int 
    466 bcm_td2_multicast_l3_vp_next_hop_free(int unit, int intf)
    467 {
    468     _td2_l3_vp_encap_id_t *curr_ptr;
    469     _td2_l3_vp_encap_id_t *next_ptr;
    470     egr_l3_next_hop_entry_t egr_nh;
    471     int intf_num, vp_valid, vp;
    472     soc_field_t entry_type_field;
    473 
    474     if (NULL == _td2_multicast_l3_vp_info[unit]) {
    475         /* Nothing to free */
    476         return BCM_E_NONE;
    477     }
    478 
    479     if (NULL == _td2_multicast_l3_vp_info[unit]->list_array[intf]) {
    480         /* Nothing to free */
    481         return BCM_E_NONE;
    482     }
    483 
    484     /* Traverse the L3 interface's linked list of intf-on-vp encap IDs */
    485     curr_ptr = _td2_multicast_l3_vp_info[unit]->list_array[intf];
    486     while (NULL != curr_ptr) {
    487         /* Ascertaining the egress next hop entry has the right
    488          * entry type, L3 interface, and virtual port values
    489          * before clearing it. This is necessary in the following
    490          * scenario:
    491          * (1) User calls bcm_l3_egress_create to create a multicast L3
    492          *     egress object on a virtual port.
    493          * (2) User does a warm boot. The _bcm_td2_multicast_l3_vp_reinit
    494          *     procedure wil recover the multicast L3 egress object and
    495          *     insert it into the _td2_multicast_l3_vp_info[unit]->
    496          *     list_array[intf] linked list.
    497          * (3) User calls bcm_l3_egress_destroy to destroy the multicast L3
    498          *     egress object.
    499          * (4) The next hop index freed by step (3) is being re-allocated
    500          *     to some other application.
    501          * (5) User calls bcm_l3_intf_delete, which will trigger
    502          *     bcm_td2_multicast_l3_vp_next_hop_free procedure. This procedure
    503          *     will find that the egress next hop entry does not contain
    504          *     the expected data, due to step (4). Hence, bcm_xgs3_nh_del
    505          *     will not be called. Nevertheless, the element will still be
    506          *     removed from the linked list.
    507          */
    508         SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    509                     curr_ptr->nh_index, &egr_nh));
    510         if (SOC_IS_TRIDENT3X(unit)) {
    511             entry_type_field = DATA_TYPEf;
    512         } else {
    513             entry_type_field = ENTRY_TYPEf;
    514         }
    515         if (7 == soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    516                     entry_type_field)) {
    517             intf_num = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    518                     L3MC__INTF_NUMf);
    519 
    520             vp = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    521                     L3MC__DVPf);
    522 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    523             if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
    524                 vp_valid = (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    525                         L3MC__NEXT_PTR_TYPEf) & 0x1);
    526             } else
    527 #endif
    528             {
    529                 vp_valid = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    530                         L3MC__DVP_VALIDf);
    531             }
    532 
    533             if ((intf_num == intf) &&
    534                 vp_valid &&
    535                 (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv) ||
    536                  _bcm_vp_used_get(unit, vp, _bcmVpTypeExtender) || 
    537                  _bcm_vp_used_get(unit, vp, _bcmVpTypeVlan))) {
    538                 BCM_IF_ERROR_RETURN
    539                     (bcm_xgs3_nh_del(unit, 0, curr_ptr->nh_index));
    540             }
    541         }
    542 
    543         /* Remove the element from the linked list */
    544         next_ptr = curr_ptr->next;
    545         sal_free(curr_ptr);
    546         curr_ptr = next_ptr;
    547     }
    548     _td2_multicast_l3_vp_info[unit]->list_array[intf] = NULL;
    549 
    550     return BCM_E_NONE;
    551 }
    552 
    553 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
    554 
    555 /*
    556  * Function:
    557  *     bcm_td2_multicast_l3_vp_sw_dump
    558  * Purpose:
    559  *     Displays information maintained by software.
    560  * Parameters:
    561  *     unit - Device unit number
    562  * Returns:
    563  *     None
    564  */
    565 void
    566 bcm_td2_multicast_l3_vp_sw_dump(int unit)
    567 {
    568     int i, j, num_items_per_line;
    569     _td2_l3_vp_encap_id_t *curr_ptr;
    570 
    571     LOG_CLI((BSL_META_U(unit,
    572                         "L3 Interface-on-Virtual Port Encapsulation ID Information:\n")));
    573 
    574     num_items_per_line = 4;
    575     for (i = 0; i < _td2_multicast_l3_vp_info[unit]->list_array_size; i++) {
    576         if (_td2_multicast_l3_vp_info[unit]->list_array[i] != NULL) {
    577             LOG_CLI((BSL_META_U(unit,
    578                                 "  L3 interface %4d: virtual_port:next_hop_index"), i));
    579             curr_ptr = _td2_multicast_l3_vp_info[unit]->list_array[i];
    580             j = 0;
    581             while (curr_ptr != NULL) {
    582                 if (j % num_items_per_line == 0) {
    583                     LOG_CLI((BSL_META_U(unit,
    584                                         "\n                    ")));
    585                 }
    586                 LOG_CLI((BSL_META_U(unit,
    587                                     " %5d:%-5d"), curr_ptr->vp, curr_ptr->nh_index));
    588                 j++;
    589                 curr_ptr = curr_ptr->next;
    590             }
    591             LOG_CLI((BSL_META_U(unit,
    592                                 "\n")));
    593         }
    594     }
    595     LOG_CLI((BSL_META_U(unit,
    596                         "\n")));
    597 
    598     return;
    599 }
    600 
    601 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
    602 
    603 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */