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 */