ipmc.c (70559B)
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: ipmc.c 8 * Purpose: Trident2 PIM-BIDIR implementation. 9 */ 10 11 #include <soc/defs.h> 12 #include <sal/core/libc.h> 13 #include <shared/bsl.h> 14 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3) 15 16 #include <soc/drv.h> 17 #include <soc/profile_mem.h> 18 19 #include <bcm/error.h> 20 #include <bcm/ipmc.h> 21 #include <bcm/l3.h> 22 23 #include <bcm_int/esw/trident2.h> 24 25 typedef struct _bcm_td2_l3_iif_s { 26 bcm_if_t l3_iif; 27 struct _bcm_td2_l3_iif_s *next; 28 } _bcm_td2_l3_iif_t; 29 30 typedef struct _bcm_td2_rp_s { 31 int valid; /* Indicates if this rendezvous point is valid */ 32 int ref_count; /* Number of IPMC entries referring to 33 this rendezvous point */ 34 _bcm_td2_l3_iif_t *l3_iif_list; /* Linked list of active L3 IIFs 35 belonging to this rendezvous point */ 36 } _bcm_td2_rp_t; 37 38 typedef struct _bcm_td2_pim_bidir_s { 39 int num_rp; /* Number of rendezvous points */ 40 _bcm_td2_rp_t *rp_info; /* Rendezvous points info */ 41 soc_profile_mem_t *active_l3_iif_profile; /* Active L3 IIF profile */ 42 SHR_BITDCL *ipmc_tcam_bitmap; /* Bitmap of valid IPMC TCAM entries */ 43 } _bcm_td2_pim_bidir_t; 44 45 STATIC _bcm_td2_pim_bidir_t *_bcm_td2_pim_bidir_info[BCM_MAX_NUM_UNITS]; 46 47 #define IPMC_NUM_RP(unit) \ 48 (_bcm_td2_pim_bidir_info[unit]->num_rp) 49 50 #define IPMC_RP_INFO(unit, rp_id) \ 51 (&_bcm_td2_pim_bidir_info[unit]->rp_info[rp_id]) 52 53 #define IPMC_ACTIVE_L3_IIF_PROFILE(unit) \ 54 (_bcm_td2_pim_bidir_info[unit]->active_l3_iif_profile) 55 56 #define IPMC_TCAM_BITMAP(unit) \ 57 (_bcm_td2_pim_bidir_info[unit]->ipmc_tcam_bitmap) 58 59 #ifdef BCM_WARM_BOOT_SUPPORT 60 STATIC int _bcm_td2_ipmc_pim_bidir_recover(int unit); 61 #endif /* BCM_WARM_BOOT_SUPPORT */ 62 63 /* 64 * Function: 65 * bcm_td2_ipmc_pim_bidir_detach 66 * Purpose: 67 * Free data structures related to PIM-BIDIR. 68 * Parameters: 69 * unit - StrataSwitch unit # 70 * Returns: 71 * BCM_E_xxx 72 */ 73 int 74 bcm_td2_ipmc_pim_bidir_detach(int unit) 75 { 76 int rv = BCM_E_NONE; 77 _bcm_td2_pim_bidir_t *pim_bidir_info = NULL; 78 int i; 79 _bcm_td2_l3_iif_t *current_ptr, *next_ptr; 80 81 if (NULL != _bcm_td2_pim_bidir_info[unit]) { 82 pim_bidir_info = _bcm_td2_pim_bidir_info[unit]; 83 84 /* Free rendezvous point info array */ 85 if (NULL != pim_bidir_info->rp_info) { 86 for (i = 0; i < pim_bidir_info->num_rp; i++) { 87 /* Free linked list of active L3 IIFs */ 88 current_ptr = pim_bidir_info->rp_info[i].l3_iif_list; 89 while (NULL != current_ptr) { 90 next_ptr = current_ptr->next; 91 sal_free(current_ptr); 92 current_ptr = next_ptr; 93 } 94 pim_bidir_info->rp_info[i].l3_iif_list = NULL; 95 } 96 sal_free(pim_bidir_info->rp_info); 97 pim_bidir_info->rp_info = NULL; 98 } 99 100 if (NULL != pim_bidir_info->active_l3_iif_profile) { 101 (void) soc_profile_mem_destroy(unit, 102 pim_bidir_info->active_l3_iif_profile); 103 sal_free(pim_bidir_info->active_l3_iif_profile); 104 pim_bidir_info->active_l3_iif_profile = NULL; 105 } 106 107 if (NULL != pim_bidir_info->ipmc_tcam_bitmap) { 108 sal_free(pim_bidir_info->ipmc_tcam_bitmap); 109 pim_bidir_info->ipmc_tcam_bitmap = NULL; 110 } 111 112 sal_free(_bcm_td2_pim_bidir_info[unit]); 113 _bcm_td2_pim_bidir_info[unit] = NULL; 114 } 115 116 return rv; 117 } 118 119 /* 120 * Function: 121 * bcm_td2_ipmc_pim_bidir_init 122 * Purpose: 123 * Initialize data structures related to PIM-BIDIR. 124 * Parameters: 125 * unit - StrataSwitch unit # 126 * Returns: 127 * BCM_E_xxx 128 */ 129 int 130 bcm_td2_ipmc_pim_bidir_init(int unit) 131 { 132 int rv = BCM_E_NONE; 133 _bcm_td2_pim_bidir_t *pim_bidir_info = NULL; 134 soc_mem_t profile_mem; 135 int entry_words; 136 void *entry_ptr; 137 uint32 profile_index; 138 int ipmc_tcam_bitmap_length; 139 int i; 140 iif_entry_t *l3_iif_entry; 141 uint8 *mbuf; 142 143 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 144 _bcm_td2_pim_bidir_info[unit] = sal_alloc(sizeof(_bcm_td2_pim_bidir_t), 145 "PIM BIDIR info"); 146 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 147 bcm_td2_ipmc_pim_bidir_detach(unit); 148 return BCM_E_MEMORY; 149 } 150 } 151 sal_memset(_bcm_td2_pim_bidir_info[unit], 0, sizeof(_bcm_td2_pim_bidir_t)); 152 pim_bidir_info = _bcm_td2_pim_bidir_info[unit]; 153 154 /* Allocate an array to keep track of rendezvous point info */ 155 pim_bidir_info->num_rp = soc_mem_field_length(unit, 156 ING_ACTIVE_L3_IIF_PROFILEm, RPA_ID_PROFILEf); 157 pim_bidir_info->rp_info = sal_alloc(pim_bidir_info->num_rp * 158 sizeof(_bcm_td2_rp_t), "RP info array"); 159 if (NULL == pim_bidir_info->rp_info) { 160 bcm_td2_ipmc_pim_bidir_detach(unit); 161 return BCM_E_MEMORY; 162 } 163 sal_memset(pim_bidir_info->rp_info, 0, 164 pim_bidir_info->num_rp * sizeof(_bcm_td2_rp_t)); 165 166 /* Allocate active L3 IIF profile */ 167 pim_bidir_info->active_l3_iif_profile = 168 sal_alloc(sizeof(soc_profile_mem_t), "Active L3 IIF Profile"); 169 if (NULL == pim_bidir_info->active_l3_iif_profile) { 170 bcm_td2_ipmc_pim_bidir_detach(unit); 171 return BCM_E_MEMORY; 172 } 173 soc_profile_mem_t_init(pim_bidir_info->active_l3_iif_profile); 174 175 /* Initialize the active L3 IIF profile */ 176 profile_mem = ING_ACTIVE_L3_IIF_PROFILEm; 177 entry_words = sizeof(ing_active_l3_iif_profile_entry_t) / sizeof(uint32); 178 rv = soc_profile_mem_create(unit, &profile_mem, &entry_words, 1, 179 pim_bidir_info->active_l3_iif_profile); 180 if (BCM_FAILURE(rv)) { 181 bcm_td2_ipmc_pim_bidir_detach(unit); 182 return rv; 183 } 184 185 if (!SOC_WARM_BOOT(unit)) { 186 /* Initially, all L3_IIF entries point to an active L3 IIF profile 187 * that contains no valid rendezvous points. 188 */ 189 entry_ptr = soc_mem_entry_null(unit, ING_ACTIVE_L3_IIF_PROFILEm); 190 rv = soc_profile_mem_add(unit, pim_bidir_info->active_l3_iif_profile, 191 &entry_ptr, 1, &profile_index); 192 if (BCM_FAILURE(rv)) { 193 bcm_td2_ipmc_pim_bidir_detach(unit); 194 return rv; 195 } 196 /* If the default HW value is same to profile index, skip it */ 197 if (!(SOC_HW_RESET(unit) && profile_index == 0)) { 198 /* Program the table */ 199 mbuf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, L3_IIFm), 200 "L3_iif"); 201 if (NULL == mbuf) { 202 bcm_td2_ipmc_pim_bidir_detach(unit); 203 return BCM_E_MEMORY; 204 } 205 rv = soc_mem_read_range(unit, L3_IIFm, MEM_BLOCK_ANY, 206 soc_mem_index_min(unit, L3_IIFm), 207 soc_mem_index_max(unit, L3_IIFm), 208 mbuf); 209 if (BCM_FAILURE(rv)) { 210 bcm_td2_ipmc_pim_bidir_detach(unit); 211 soc_cm_sfree(unit, mbuf); 212 return rv; 213 } 214 215 for (i = 0; i < soc_mem_index_count(unit, L3_IIFm); i++) { 216 l3_iif_entry = soc_mem_table_idx_to_pointer(unit, L3_IIFm, 217 iif_entry_t *, mbuf, i); 218 soc_L3_IIFm_field32_set(unit, l3_iif_entry, 219 ACTIVE_L3_IIF_PROFILE_INDEXf, 220 profile_index); 221 } 222 223 rv = soc_mem_write_range(unit, L3_IIFm, MEM_BLOCK_ANY, 224 soc_mem_index_min(unit, L3_IIFm), 225 soc_mem_index_max(unit, L3_IIFm), 226 mbuf); 227 soc_cm_sfree(unit, mbuf); 228 if (BCM_FAILURE(rv)) { 229 bcm_td2_ipmc_pim_bidir_detach(unit); 230 return rv; 231 } 232 } 233 SOC_PROFILE_MEM_REFERENCE(unit, pim_bidir_info->active_l3_iif_profile, 234 profile_index, soc_mem_index_count(unit, L3_IIFm) - 1); 235 236 if (SOC_IS_TRIDENT2PLUS(unit) && 237 soc_feature(unit, soc_feature_alpm) && 238 soc_feature(unit, soc_feature_td2p_a0_sw_war) && 239 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 240 int rpa_id = IPMC_NUM_RP(unit) - 1; 241 /* Reserve RPA 63 for ALPM WAR */ 242 bcm_td2_ipmc_rp_create(unit, BCM_IPMC_RP_WITH_ID, &rpa_id); 243 } 244 } 245 246 /* Allocate a bitmap indicating which IP_MULTICAST_TCAM entry is valid */ 247 ipmc_tcam_bitmap_length = soc_mem_index_count(unit, IP_MULTICAST_TCAMm); 248 pim_bidir_info->ipmc_tcam_bitmap = 249 sal_alloc(SHR_BITALLOCSIZE(ipmc_tcam_bitmap_length), "IPMC TCAM bitmap"); 250 if (NULL == pim_bidir_info->ipmc_tcam_bitmap) { 251 bcm_td2_ipmc_pim_bidir_detach(unit); 252 return BCM_E_MEMORY; 253 } 254 sal_memset(pim_bidir_info->ipmc_tcam_bitmap, 0, 255 SHR_BITALLOCSIZE(ipmc_tcam_bitmap_length)); 256 257 #ifdef BCM_WARM_BOOT_SUPPORT 258 if (SOC_WARM_BOOT(unit)) { 259 rv = _bcm_td2_ipmc_pim_bidir_recover(unit); 260 if (BCM_FAILURE(rv)) { 261 bcm_td2_ipmc_pim_bidir_detach(unit); 262 return rv; 263 } 264 } 265 #endif /* BCM_WARM_BOOT_SUPPORT */ 266 267 return rv; 268 } 269 270 /* 271 * Function: 272 * bcm_td2_ipmc_rp_create 273 * Purpose: 274 * Create a rendezvous point. 275 * Parameters: 276 * unit - StrataSwitch unit # 277 * flags - BCM_IPMC_RP_xxx flags. 278 * rp_id - (IN/OUT) Rendezvous point ID. 279 * Returns: 280 * BCM_E_xxx 281 */ 282 int 283 bcm_td2_ipmc_rp_create( 284 int unit, 285 uint32 flags, 286 int *rp_id) 287 { 288 int rv = BCM_E_NONE; 289 int i; 290 int rp_min = 0; 291 292 #ifdef BCM_TRIDENT3_SUPPORT 293 if (SOC_IS_TRIDENT3X(unit)) { 294 /* RPA_ID 0 is invalid for TD3X devices */ 295 rp_min = 1; 296 } 297 #endif 298 299 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 300 return BCM_E_INIT; 301 } 302 303 if (NULL == rp_id) { 304 return BCM_E_PARAM; 305 } 306 307 if (flags & BCM_IPMC_RP_WITH_ID) { 308 if ((*rp_id < rp_min) || (*rp_id >= IPMC_NUM_RP(unit))) { 309 return BCM_E_PARAM; 310 } 311 if (IPMC_RP_INFO(unit, *rp_id)->valid) { 312 return BCM_E_EXISTS; 313 } 314 IPMC_RP_INFO(unit, *rp_id)->valid = 1; 315 } else { 316 for (i = rp_min; i < IPMC_NUM_RP(unit); i++) { 317 if (!IPMC_RP_INFO(unit, i)->valid) { 318 IPMC_RP_INFO(unit, i)->valid = 1; 319 *rp_id = i; 320 break; 321 } 322 } 323 if (i == IPMC_NUM_RP(unit)) { 324 /* No available rendezvous point ID */ 325 return BCM_E_RESOURCE; 326 } 327 } 328 329 return rv; 330 } 331 332 /* 333 * Function: 334 * bcm_td2_ipmc_rp_destroy 335 * Purpose: 336 * Destroy a rendezvous point. 337 * Parameters: 338 * unit - StrataSwitch unit # 339 * rp_id - Rendezvous point ID. 340 * Returns: 341 * BCM_E_xxx 342 */ 343 int 344 bcm_td2_ipmc_rp_destroy( 345 int unit, 346 int rp_id) 347 { 348 int rv = BCM_E_NONE; 349 350 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 351 return BCM_E_INIT; 352 } 353 354 if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) { 355 return BCM_E_PARAM; 356 } 357 358 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 359 return BCM_E_NOT_FOUND; 360 } 361 362 if (IPMC_RP_INFO(unit, rp_id)->ref_count > 0) { 363 /* RP ID is still being referenced by IPMC entries. */ 364 return BCM_E_BUSY; 365 } 366 367 /* Delete all active L3 interfaces associated with this RP ID */ 368 BCM_IF_ERROR_RETURN(bcm_td2_ipmc_rp_delete_all(unit, rp_id)); 369 370 IPMC_RP_INFO(unit, rp_id)->valid = 0; 371 372 return rv; 373 } 374 375 /* 376 * Function: 377 * _bcm_td2_ipmc_rp_add 378 * Purpose: 379 * Add an active L3 interface to a rendezvous point. 380 * Parameters: 381 * unit - StrataSwitch unit # 382 * rp_id - Rendezvous point ID 383 * intf_id - Active L3 interface ID 384 * Returns: 385 * BCM_E_xxx 386 */ 387 STATIC int 388 _bcm_td2_ipmc_rp_add( 389 int unit, 390 int rp_id, 391 bcm_if_t intf_id) 392 { 393 int rv = BCM_E_NONE; 394 iif_entry_t l3_iif_entry; 395 uint32 profile_index, new_profile_index; 396 ing_active_l3_iif_profile_entry_t profile_entry; 397 int rp_bitmap_length; 398 SHR_BITDCL *rp_bitmap = NULL; 399 void *entry_ptr; 400 401 /* Get L3 IIF's current active L3 interface profile */ 402 SOC_IF_ERROR_RETURN 403 (READ_L3_IIFm(unit, MEM_BLOCK_ANY, intf_id, &l3_iif_entry)); 404 profile_index = soc_L3_IIFm_field32_get(unit, &l3_iif_entry, 405 ACTIVE_L3_IIF_PROFILE_INDEXf); 406 SOC_IF_ERROR_RETURN 407 (READ_ING_ACTIVE_L3_IIF_PROFILEm(unit, MEM_BLOCK_ANY, profile_index, 408 &profile_entry)); 409 410 /* Get a bitmap of the rendezvous points L3 IIF currently belongs to */ 411 rp_bitmap_length = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm, 412 RPA_ID_PROFILEf); 413 rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(rp_bitmap_length), "RP bitmap"); 414 if (NULL == rp_bitmap) { 415 return BCM_E_MEMORY; 416 } 417 soc_ING_ACTIVE_L3_IIF_PROFILEm_field_get(unit, &profile_entry, 418 RPA_ID_PROFILEf, rp_bitmap); 419 420 /* Check if L3 IIF already belongs to the given rendezvous point */ 421 if (SHR_BITGET(rp_bitmap, rp_id)) { 422 sal_free(rp_bitmap); 423 return BCM_E_EXISTS; 424 } 425 426 /* Add L3 IIF to the given rendezvous point */ 427 SHR_BITSET(rp_bitmap, rp_id); 428 429 /* Add a new active L3 interface profile */ 430 soc_ING_ACTIVE_L3_IIF_PROFILEm_field_set(unit, &profile_entry, 431 RPA_ID_PROFILEf, rp_bitmap); 432 entry_ptr = &profile_entry; 433 rv = soc_profile_mem_add(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit), 434 &entry_ptr, 1, &new_profile_index); 435 if (SOC_FAILURE(rv)) { 436 sal_free(rp_bitmap); 437 return rv; 438 } 439 soc_L3_IIFm_field32_set(unit, &l3_iif_entry, ACTIVE_L3_IIF_PROFILE_INDEXf, 440 new_profile_index); 441 rv = WRITE_L3_IIFm(unit, MEM_BLOCK_ALL, intf_id, &l3_iif_entry); 442 if (SOC_FAILURE(rv)) { 443 sal_free(rp_bitmap); 444 return rv; 445 } 446 447 /* Delete the old active L3 interface profile */ 448 rv = soc_profile_mem_delete(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit), 449 profile_index); 450 if (SOC_FAILURE(rv)) { 451 sal_free(rp_bitmap); 452 return rv; 453 } 454 455 sal_free(rp_bitmap); 456 return rv; 457 } 458 459 /* 460 * Function: 461 * _bcm_td2_ipmc_rp_delete 462 * Purpose: 463 * Delete an active L3 interface from a rendezvous point. 464 * Parameters: 465 * unit - StrataSwitch unit # 466 * rp_id - Rendezvous point ID 467 * intf_id - Active L3 interface ID 468 * Returns: 469 * BCM_E_xxx 470 */ 471 STATIC int 472 _bcm_td2_ipmc_rp_delete( 473 int unit, 474 int rp_id, 475 bcm_if_t intf_id) 476 { 477 int rv = BCM_E_NONE; 478 iif_entry_t l3_iif_entry; 479 uint32 profile_index, new_profile_index; 480 ing_active_l3_iif_profile_entry_t profile_entry; 481 int rp_bitmap_length; 482 SHR_BITDCL *rp_bitmap = NULL; 483 void *entry_ptr; 484 485 /* Get L3 IIF's current active L3 interface profile */ 486 SOC_IF_ERROR_RETURN 487 (READ_L3_IIFm(unit, MEM_BLOCK_ANY, intf_id, &l3_iif_entry)); 488 profile_index = soc_L3_IIFm_field32_get(unit, &l3_iif_entry, 489 ACTIVE_L3_IIF_PROFILE_INDEXf); 490 SOC_IF_ERROR_RETURN 491 (READ_ING_ACTIVE_L3_IIF_PROFILEm(unit, MEM_BLOCK_ANY, profile_index, 492 &profile_entry)); 493 494 /* Get a bitmap of the rendezvous points L3 IIF currently belongs to */ 495 rp_bitmap_length = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm, 496 RPA_ID_PROFILEf); 497 rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(rp_bitmap_length), "RP bitmap"); 498 if (NULL == rp_bitmap) { 499 return BCM_E_MEMORY; 500 } 501 soc_ING_ACTIVE_L3_IIF_PROFILEm_field_get(unit, &profile_entry, 502 RPA_ID_PROFILEf, rp_bitmap); 503 504 /* Make sure L3 IIF belongs to the given rendezvous point */ 505 if (!SHR_BITGET(rp_bitmap, rp_id)) { 506 sal_free(rp_bitmap); 507 return BCM_E_NOT_FOUND; 508 } 509 510 /* Delete L3 IIF from the given rendezvous point */ 511 SHR_BITCLR(rp_bitmap, rp_id); 512 513 /* Add a new active L3 interface profile */ 514 soc_ING_ACTIVE_L3_IIF_PROFILEm_field_set(unit, &profile_entry, 515 RPA_ID_PROFILEf, rp_bitmap); 516 entry_ptr = &profile_entry; 517 rv = soc_profile_mem_add(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit), 518 &entry_ptr, 1, &new_profile_index); 519 if (SOC_FAILURE(rv)) { 520 sal_free(rp_bitmap); 521 return rv; 522 } 523 soc_L3_IIFm_field32_set(unit, &l3_iif_entry, ACTIVE_L3_IIF_PROFILE_INDEXf, 524 new_profile_index); 525 rv = WRITE_L3_IIFm(unit, MEM_BLOCK_ALL, intf_id, &l3_iif_entry); 526 if (SOC_FAILURE(rv)) { 527 sal_free(rp_bitmap); 528 return rv; 529 } 530 531 /* Delete the old active L3 interface profile */ 532 rv = soc_profile_mem_delete(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit), 533 profile_index); 534 if (SOC_FAILURE(rv)) { 535 sal_free(rp_bitmap); 536 return rv; 537 } 538 539 sal_free(rp_bitmap); 540 return rv; 541 } 542 543 /* 544 * Function: 545 * bcm_td2_ipmc_rp_set 546 * Purpose: 547 * Set active L3 interfaces for a rendezvous point. 548 * Parameters: 549 * unit - StrataSwitch unit # 550 * rp_id - Rendezvous point ID 551 * intf_count - Number of elements in intf_array 552 * intf_array - Array of active L3 interfaces 553 * Returns: 554 * BCM_E_xxx 555 */ 556 int 557 bcm_td2_ipmc_rp_set( 558 int unit, 559 int rp_id, 560 int intf_count, 561 bcm_if_t *intf_array) 562 { 563 int rv = BCM_E_NONE; 564 SHR_BITDCL *intf_bitmap = NULL; 565 SHR_BITDCL *still_active_bitmap = NULL; 566 int num_l3_iif; 567 int i; 568 _bcm_td2_l3_iif_t *prev_ptr, *current_ptr; 569 570 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 571 return BCM_E_INIT; 572 } 573 574 /* Input check */ 575 if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) { 576 return BCM_E_PARAM; 577 } 578 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 579 return BCM_E_CONFIG; 580 } 581 if (intf_count > 0 && intf_array == NULL) { 582 return BCM_E_PARAM; 583 } 584 585 /* Convert intf_array to a bitmap */ 586 num_l3_iif = soc_mem_index_count(unit, L3_IIFm); 587 intf_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_iif), 588 "L3 interface bitmap"); 589 if (NULL == intf_bitmap) { 590 return BCM_E_MEMORY; 591 } 592 sal_memset(intf_bitmap, 0, SHR_BITALLOCSIZE(num_l3_iif)); 593 for (i = 0; i < intf_count; i++) { 594 if (intf_array[i] < 0 || intf_array[i] >= num_l3_iif) { 595 rv = BCM_E_PARAM; 596 goto cleanup; 597 } 598 SHR_BITSET(intf_bitmap, intf_array[i]); 599 } 600 601 /* Traverse rendezvous point's existing linked list of active L3 IIFs. 602 * Delete the L3 IIFs that are no longer active, i.e. not in intf_array. 603 * Keep track of L3 IIFs that remain active in still_active_bitmap. 604 */ 605 still_active_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_iif), 606 "Still active L3 interface bitmap"); 607 if (NULL == still_active_bitmap) { 608 rv = BCM_E_MEMORY; 609 goto cleanup; 610 } 611 sal_memset(still_active_bitmap, 0, SHR_BITALLOCSIZE(num_l3_iif)); 612 prev_ptr = NULL; 613 current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list; 614 while (NULL != current_ptr) { 615 if (SHR_BITGET(intf_bitmap, current_ptr->l3_iif)) { 616 /* This L3 IIF remains active. */ 617 SHR_BITSET(still_active_bitmap, current_ptr->l3_iif); 618 prev_ptr = current_ptr; 619 current_ptr = current_ptr->next; 620 } else { 621 /* Delete inactive L3 IIF from rendezvous point */ 622 rv = _bcm_td2_ipmc_rp_delete(unit, rp_id, current_ptr->l3_iif); 623 if (BCM_FAILURE(rv)) { 624 goto cleanup; 625 } 626 if (current_ptr == IPMC_RP_INFO(unit, rp_id)->l3_iif_list) { 627 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr->next; 628 sal_free(current_ptr); 629 current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list; 630 } else { 631 prev_ptr->next = current_ptr->next; 632 sal_free(current_ptr); 633 current_ptr = prev_ptr->next; 634 } 635 } 636 } 637 638 /* Traverse intf_array. Add the L3 IIFs that are not already active, 639 * i.e. not in still_active_bitmap. 640 */ 641 for (i = 0; i < intf_count; i++) { 642 if (SHR_BITGET(still_active_bitmap, intf_array[i])) { 643 /* This L3 IIF is already active. */ 644 continue; 645 } 646 rv = _bcm_td2_ipmc_rp_add(unit, rp_id, intf_array[i]); 647 if (BCM_FAILURE(rv)) { 648 goto cleanup; 649 } 650 current_ptr = sal_alloc(sizeof(_bcm_td2_l3_iif_t), "Active L3 IIF"); 651 if (NULL == current_ptr) { 652 rv = BCM_E_MEMORY; 653 goto cleanup; 654 } 655 current_ptr->l3_iif = intf_array[i]; 656 current_ptr->next = IPMC_RP_INFO(unit, rp_id)->l3_iif_list; 657 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr; 658 } 659 660 cleanup: 661 if (NULL != intf_bitmap) { 662 sal_free(intf_bitmap); 663 } 664 if (NULL != still_active_bitmap) { 665 sal_free(still_active_bitmap); 666 } 667 return rv; 668 } 669 670 /* 671 * Function: 672 * bcm_td2_ipmc_rp_get 673 * Purpose: 674 * Get active L3 interfaces for a rendezvous point. 675 * Parameters: 676 * unit - StrataSwitch unit # 677 * rp_id - Rendezvous point ID 678 * intf_max - Number of elements in intf_array 679 * intf_array - (OUT) Array of active L3 interfaces 680 * intf_count - (OUT) Number of elements returned in intf_array 681 * Returns: 682 * BCM_E_xxx 683 */ 684 int 685 bcm_td2_ipmc_rp_get( 686 int unit, 687 int rp_id, 688 int intf_max, 689 bcm_if_t *intf_array, 690 int *intf_count) 691 { 692 int rv = BCM_E_NONE; 693 _bcm_td2_l3_iif_t *current_ptr; 694 695 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 696 return BCM_E_INIT; 697 } 698 699 /* Input check */ 700 if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) { 701 return BCM_E_PARAM; 702 } 703 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 704 return BCM_E_CONFIG; 705 } 706 if ((intf_max > 0 && intf_array == NULL) || 707 (intf_max == 0 && intf_array != NULL)) { 708 return BCM_E_PARAM; 709 } 710 if (NULL == intf_count) { 711 return BCM_E_PARAM; 712 } 713 714 /* Traverse rendezvous point's linked list of active L3 IIFs. */ 715 *intf_count = 0; 716 current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list; 717 while (NULL != current_ptr) { 718 if (NULL != intf_array) { 719 intf_array[*intf_count] = current_ptr->l3_iif; 720 } 721 (*intf_count)++; 722 if (*intf_count == intf_max) { 723 break; 724 } 725 current_ptr = current_ptr->next; 726 } 727 728 return rv; 729 } 730 731 /* 732 * Function: 733 * bcm_td2_ipmc_rp_add 734 * Purpose: 735 * Add an active L3 interface to a rendezvous point. 736 * Parameters: 737 * unit - StrataSwitch unit # 738 * rp_id - Rendezvous point ID 739 * intf_id - L3 interface ID 740 * Returns: 741 * BCM_E_xxx 742 */ 743 int 744 bcm_td2_ipmc_rp_add( 745 int unit, 746 int rp_id, 747 bcm_if_t intf_id) 748 { 749 int rv = BCM_E_NONE; 750 _bcm_td2_l3_iif_t *current_ptr; 751 752 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 753 return BCM_E_INIT; 754 } 755 756 /* Input check */ 757 if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) { 758 return BCM_E_PARAM; 759 } 760 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 761 return BCM_E_CONFIG; 762 } 763 if (intf_id < 0 || intf_id > soc_mem_index_max(unit, L3_IIFm)) { 764 return BCM_E_PARAM; 765 } 766 767 /* Add intf_id to rendezvous point */ 768 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_rp_add(unit, rp_id, intf_id)); 769 770 /* Insert intf_id to head of rendezvous point's linked list of L3 IIFs */ 771 current_ptr = sal_alloc(sizeof(_bcm_td2_l3_iif_t), "Active L3 IIF"); 772 if (NULL == current_ptr) { 773 return BCM_E_MEMORY; 774 } 775 current_ptr->l3_iif = intf_id; 776 current_ptr->next = IPMC_RP_INFO(unit, rp_id)->l3_iif_list; 777 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr; 778 779 return rv; 780 } 781 782 /* 783 * Function: 784 * bcm_td2_ipmc_rp_delete 785 * Purpose: 786 * Delete an active L3 interface from a rendezvous point. 787 * Parameters: 788 * unit - StrataSwitch unit # 789 * rp_id - Rendezvous point ID 790 * intf_id - L3 interface ID 791 * Returns: 792 * BCM_E_xxx 793 */ 794 int 795 bcm_td2_ipmc_rp_delete( 796 int unit, 797 int rp_id, 798 bcm_if_t intf_id) 799 { 800 int rv = BCM_E_NONE; 801 _bcm_td2_l3_iif_t *current_ptr, *prev_ptr; 802 803 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 804 return BCM_E_INIT; 805 } 806 807 /* Input check */ 808 if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) { 809 return BCM_E_PARAM; 810 } 811 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 812 return BCM_E_CONFIG; 813 } 814 if (intf_id < 0 || intf_id > soc_mem_index_max(unit, L3_IIFm)) { 815 return BCM_E_PARAM; 816 } 817 818 /* Traverse rendezvous point's linked list of active L3 IIFs to 819 * find and delete the given intf_id. 820 */ 821 prev_ptr = NULL; 822 current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list; 823 while (NULL != current_ptr) { 824 if (current_ptr->l3_iif == intf_id) { 825 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_rp_delete(unit, rp_id, intf_id)); 826 if (current_ptr == IPMC_RP_INFO(unit, rp_id)->l3_iif_list) { 827 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr->next; 828 } else { 829 /* 830 * In the following line of code, Coverity thinks the 831 * prev_ptr pointer may still be NULL when 832 * dereferenced. This situation will never occur because 833 * if current_ptr is not pointing to the head of the 834 * linked list, prev_ptr would not be NULL. 835 */ 836 /* coverity[var_deref_op : FALSE] */ 837 prev_ptr->next = current_ptr->next; 838 } 839 sal_free(current_ptr); 840 break; 841 } else { 842 prev_ptr = current_ptr; 843 current_ptr = current_ptr->next; 844 } 845 } 846 if (NULL == current_ptr) { 847 return BCM_E_NOT_FOUND; 848 } 849 850 return rv; 851 } 852 853 /* 854 * Function: 855 * bcm_td2_ipmc_rp_delete_all 856 * Purpose: 857 * Delete all active L3 interfaces from a rendezvous point. 858 * Parameters: 859 * unit - StrataSwitch unit # 860 * rp_id - Rendezvous point ID 861 * Returns: 862 * BCM_E_xxx 863 */ 864 int 865 bcm_td2_ipmc_rp_delete_all( 866 int unit, 867 int rp_id) 868 { 869 return bcm_td2_ipmc_rp_set(unit, rp_id, 0, NULL); 870 } 871 872 /* 873 * Function: 874 * bcm_td2_ipmc_rp_ref_count_incr 875 * Purpose: 876 * Increment reference count of rendezvous point. 877 * Parameters: 878 * unit - StrataSwitch unit # 879 * rp_id - Rendezvous point ID 880 * Returns: 881 * BCM_E_xxx 882 */ 883 int 884 bcm_td2_ipmc_rp_ref_count_incr( 885 int unit, 886 int rp_id) 887 { 888 int rv = BCM_E_NONE; 889 890 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 891 return BCM_E_INIT; 892 } 893 894 if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) { 895 return BCM_E_PARAM; 896 } 897 898 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 899 return BCM_E_NOT_FOUND; 900 } 901 902 IPMC_RP_INFO(unit, rp_id)->ref_count++; 903 904 return rv; 905 } 906 907 /* 908 * Function: 909 * bcm_td2_ipmc_rp_ref_count_decr 910 * Purpose: 911 * Decrement reference count of rendezvous point. 912 * Parameters: 913 * unit - StrataSwitch unit # 914 * rp_id - Rendezvous point ID 915 * Returns: 916 * BCM_E_xxx 917 */ 918 int 919 bcm_td2_ipmc_rp_ref_count_decr( 920 int unit, 921 int rp_id) 922 { 923 int rv = BCM_E_NONE; 924 925 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 926 return BCM_E_INIT; 927 } 928 929 if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) { 930 return BCM_E_PARAM; 931 } 932 933 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 934 return BCM_E_NOT_FOUND; 935 } 936 937 if (IPMC_RP_INFO(unit, rp_id)->ref_count == 0) { 938 return BCM_E_INTERNAL; 939 } 940 941 IPMC_RP_INFO(unit, rp_id)->ref_count--; 942 943 return rv; 944 } 945 946 /* 947 * Function: 948 * bcm_td2_ipmc_range_add 949 * Purpose: 950 * Add a range of PIM-BIDIR IPMC addresses. 951 * Parameters: 952 * unit - StrataSwitch unit # 953 * range_id - (IN/OUT) Range ID 954 * range - IPMC address range info 955 * Returns: 956 * BCM_E_xxx 957 */ 958 int 959 bcm_td2_ipmc_range_add( 960 int unit, 961 int *range_id, 962 bcm_ipmc_range_t *range) 963 { 964 int rv = BCM_E_NONE; 965 int tcam_index = 0; 966 int i, valid_bit=1; 967 ip_multicast_tcam_entry_t tcam_entry; 968 uint32 group_addr[4], group_addr_mask[4]; 969 970 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 971 return BCM_E_INIT; 972 } 973 974 /* Input check */ 975 if (NULL == range_id || NULL == range) { 976 return BCM_E_PARAM; 977 } 978 if (range->flags & BCM_IPMC_RANGE_WITH_ID) { 979 if (*range_id < 0 || 980 *range_id > soc_mem_index_max(unit, IP_MULTICAST_TCAMm)) { 981 return BCM_E_PARAM; 982 } 983 } 984 if (!(range->flags & BCM_IPMC_RANGE_PIM_BIDIR)) { 985 /* On Trident2, only PIM-BIDIR eligible addresses can be specified. 986 * Addresses not eligible for PIM-BIDIR cannot be specified. 987 */ 988 return BCM_E_PARAM; 989 } 990 if (range->priority != 0) { 991 /* On Trident2, only PIM-BIDIR eligible addresses can be specified. 992 * Hence, there is no need to specify relative priority among the 993 * ranges of PIM-BIDIR eligible addresses. 994 */ 995 return BCM_E_PARAM; 996 } 997 if ((range->vrf > SOC_VRF_MAX(unit)) || 998 (range->vrf < BCM_L3_VRF_DEFAULT)) { 999 return BCM_E_PARAM; 1000 } 1001 1002 /* Get index to IP_MULTICAST_TCAM */ 1003 if (range->flags & BCM_IPMC_RANGE_REPLACE) { 1004 if (!(range->flags & BCM_IPMC_RANGE_WITH_ID)) { 1005 return BCM_E_PARAM; 1006 } 1007 tcam_index = *range_id; 1008 if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) { 1009 return BCM_E_NOT_FOUND; 1010 } 1011 } else { 1012 if (range->flags & BCM_IPMC_RANGE_WITH_ID) { 1013 tcam_index = *range_id; 1014 if (SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) { 1015 return BCM_E_EXISTS; 1016 } 1017 SHR_BITSET(IPMC_TCAM_BITMAP(unit), tcam_index); 1018 } else { 1019 /* Find a free TCAM index */ 1020 for (i = 0; i < soc_mem_index_count(unit, IP_MULTICAST_TCAMm); i++) { 1021 if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), i)) { 1022 SHR_BITSET(IPMC_TCAM_BITMAP(unit), i); 1023 tcam_index = i; 1024 *range_id = tcam_index; 1025 break; 1026 } 1027 } 1028 if (i == soc_mem_index_count(unit, IP_MULTICAST_TCAMm)) { 1029 return BCM_E_RESOURCE; 1030 } 1031 } 1032 } 1033 1034 /* Write entry to IP_MULTICAST_TCAM */ 1035 sal_memset(&tcam_entry, 0, sizeof(tcam_entry)); 1036 #if defined(BCM_TOMAHAWK2_SUPPORT) 1037 if (SOC_IS_TOMAHAWK2(unit)) { 1038 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VALIDf, 3); 1039 } else 1040 #endif 1041 { 1042 valid_bit = 1 << soc_mem_field_length(unit, IP_MULTICAST_TCAMm, VALIDf); 1043 valid_bit -= 1; 1044 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VALIDf, valid_bit); 1045 } 1046 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VRFf, 1047 range->vrf); 1048 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VRF_MASKf, 1049 range->vrf_mask); 1050 if (range->flags & BCM_IPMC_RANGE_IP6) { 1051 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, 1052 MODEf, 1); 1053 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, 1054 MODE_MASKf, 1); 1055 soc_mem_ip6_addr_set(unit, IP_MULTICAST_TCAMm, &tcam_entry, 1056 GROUP_ADDRf, range->mc_ip6_addr, 0); 1057 soc_mem_ip6_addr_set(unit, IP_MULTICAST_TCAMm, &tcam_entry, 1058 GROUP_ADDR_MASKf, range->mc_ip6_addr_mask, 0); 1059 } else { 1060 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, 1061 MODEf, 0); 1062 soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, 1063 MODE_MASKf, 1); 1064 sal_memset(group_addr, 0, sizeof(group_addr)); 1065 group_addr[0] = range->mc_ip_addr; 1066 soc_IP_MULTICAST_TCAMm_field_set(unit, &tcam_entry, 1067 GROUP_ADDRf, group_addr); 1068 sal_memset(group_addr_mask, 0, sizeof(group_addr_mask)); 1069 group_addr_mask[0] = range->mc_ip_addr_mask; 1070 soc_IP_MULTICAST_TCAMm_field_set(unit, &tcam_entry, 1071 GROUP_ADDR_MASKf, group_addr_mask); 1072 } 1073 SOC_IF_ERROR_RETURN(WRITE_IP_MULTICAST_TCAMm(unit, MEM_BLOCK_ALL, 1074 tcam_index, &tcam_entry)); 1075 1076 return rv; 1077 } 1078 1079 /* 1080 * Function: 1081 * bcm_td2_ipmc_range_delete 1082 * Purpose: 1083 * Delete a range of PIM-BIDIR IPMC addresses. 1084 * Parameters: 1085 * unit - StrataSwitch unit # 1086 * range_id - Range ID 1087 * Returns: 1088 * BCM_E_xxx 1089 */ 1090 int 1091 bcm_td2_ipmc_range_delete( 1092 int unit, 1093 int range_id) 1094 { 1095 int rv = BCM_E_NONE; 1096 int tcam_index; 1097 1098 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 1099 return BCM_E_INIT; 1100 } 1101 1102 /* Input check */ 1103 if (range_id < 0 || 1104 range_id > soc_mem_index_max(unit, IP_MULTICAST_TCAMm)) { 1105 return BCM_E_PARAM; 1106 } 1107 1108 /* Delete the TCAM entry referenced by range_id */ 1109 tcam_index = range_id; 1110 if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) { 1111 return BCM_E_NOT_FOUND; 1112 } 1113 SOC_IF_ERROR_RETURN(WRITE_IP_MULTICAST_TCAMm(unit, MEM_BLOCK_ALL, 1114 tcam_index, soc_mem_entry_null(unit, IP_MULTICAST_TCAMm))); 1115 SHR_BITCLR(IPMC_TCAM_BITMAP(unit), tcam_index); 1116 1117 return rv; 1118 } 1119 1120 /* 1121 * Function: 1122 * bcm_td2_ipmc_range_delete_all 1123 * Purpose: 1124 * Delete all ranges of PIM-BIDIR IPMC addresses. 1125 * Parameters: 1126 * unit - StrataSwitch unit # 1127 * Returns: 1128 * BCM_E_xxx 1129 */ 1130 int 1131 bcm_td2_ipmc_range_delete_all( 1132 int unit) 1133 { 1134 int rv = BCM_E_NONE; 1135 int ipmc_tcam_bitmap_length; 1136 1137 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 1138 return BCM_E_INIT; 1139 } 1140 1141 /* Clear IP Multicast TCAM table */ 1142 SOC_IF_ERROR_RETURN 1143 (soc_mem_clear(unit, IP_MULTICAST_TCAMm, MEM_BLOCK_ALL, 0)); 1144 1145 /* Clear bitmap indicating which IP_MULTICAST_TCAM entry is valid */ 1146 ipmc_tcam_bitmap_length = soc_mem_index_count(unit, IP_MULTICAST_TCAMm); 1147 sal_memset(IPMC_TCAM_BITMAP(unit), 0, 1148 SHR_BITALLOCSIZE(ipmc_tcam_bitmap_length)); 1149 1150 return rv; 1151 } 1152 1153 /* 1154 * Function: 1155 * bcm_td2_ipmc_range_get 1156 * Purpose: 1157 * Get a range of PIM-BIDIR IPMC addresses. 1158 * Parameters: 1159 * unit - StrataSwitch unit # 1160 * range_id - Range ID 1161 * range - (OUT) Range info 1162 * Returns: 1163 * BCM_E_xxx 1164 */ 1165 int 1166 bcm_td2_ipmc_range_get( 1167 int unit, 1168 int range_id, 1169 bcm_ipmc_range_t *range) 1170 { 1171 int rv = BCM_E_NONE; 1172 int tcam_index; 1173 ip_multicast_tcam_entry_t tcam_entry; 1174 uint32 group_addr[4], group_addr_mask[4]; 1175 1176 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 1177 return BCM_E_INIT; 1178 } 1179 1180 /* Input check */ 1181 if (range_id < 0 || 1182 range_id > soc_mem_index_max(unit, IP_MULTICAST_TCAMm)) { 1183 return BCM_E_PARAM; 1184 } 1185 if (NULL == range) { 1186 return BCM_E_PARAM; 1187 } 1188 1189 /* Read the TCAM entry referenced by range_id */ 1190 tcam_index = range_id; 1191 if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) { 1192 return BCM_E_NOT_FOUND; 1193 } 1194 SOC_IF_ERROR_RETURN 1195 (READ_IP_MULTICAST_TCAMm(unit, MEM_BLOCK_ANY, tcam_index, &tcam_entry)); 1196 if (!soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry, VALIDf)) { 1197 return BCM_E_INTERNAL; 1198 } 1199 1200 /* Fill in the bcm_ipmc_range_t structure */ 1201 bcm_ipmc_range_t_init(range); 1202 range->flags |= BCM_IPMC_RANGE_PIM_BIDIR; 1203 if (soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry, MODEf)) { 1204 /* IPv6 entry */ 1205 range->flags |= BCM_IPMC_RANGE_IP6; 1206 soc_mem_ip6_addr_get(unit, IP_MULTICAST_TCAMm, &tcam_entry, 1207 GROUP_ADDRf, range->mc_ip6_addr, 0); 1208 soc_mem_ip6_addr_get(unit, IP_MULTICAST_TCAMm, &tcam_entry, 1209 GROUP_ADDR_MASKf, range->mc_ip6_addr_mask, 0); 1210 } else { 1211 /* IPv4 entry */ 1212 soc_IP_MULTICAST_TCAMm_field_get(unit, &tcam_entry, GROUP_ADDRf, 1213 group_addr); 1214 soc_IP_MULTICAST_TCAMm_field_get(unit, &tcam_entry, GROUP_ADDR_MASKf, 1215 group_addr_mask); 1216 range->mc_ip_addr = group_addr[0]; 1217 range->mc_ip_addr_mask = group_addr_mask[0]; 1218 } 1219 range->vrf = soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry, 1220 VRFf); 1221 range->vrf_mask = soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry, 1222 VRF_MASKf); 1223 1224 return rv; 1225 } 1226 1227 /* 1228 * Function: 1229 * bcm_td2_ipmc_range_size_get 1230 * Purpose: 1231 * Get the number of PIM-BIDIR IPMC address ranges supported by the device. 1232 * Parameters: 1233 * unit - StrataSwitch unit # 1234 * size - (OUT) Number of ranges 1235 * Returns: 1236 * BCM_E_xxx 1237 */ 1238 int 1239 bcm_td2_ipmc_range_size_get( 1240 int unit, 1241 int *size) 1242 { 1243 int rv = BCM_E_NONE; 1244 1245 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 1246 return BCM_E_INIT; 1247 } 1248 1249 /* Input check */ 1250 if (NULL == size) { 1251 return BCM_E_PARAM; 1252 } 1253 1254 *size = soc_mem_index_count(unit, IP_MULTICAST_TCAMm); 1255 1256 return rv; 1257 } 1258 1259 /* 1260 * Function: 1261 * _bcm_td2_ipmc_stat_get_table_info 1262 * Description: 1263 * Provides relevant flex table information(table-name,index with 1264 * direction) for given IPMC group 1265 * 1266 * Parameters: 1267 * unit - (IN) unit number 1268 * port - (IN) GPORT ID 1269 * num_of_tables - (OUT) Number of flex counter tables 1270 * table_info - (OUT) Flex counter tables information 1271 * 1272 * Return Value: 1273 * BCM_E_XXX 1274 * Notes: 1275 */ 1276 STATIC bcm_error_t 1277 _bcm_td2_ipmc_stat_get_table_info( 1278 int unit, 1279 bcm_ipmc_addr_t *info, 1280 uint32 *num_of_tables, 1281 bcm_stat_flex_table_info_t *table_info) 1282 { 1283 int rv; 1284 soc_mem_t mem; 1285 _bcm_l3_cfg_t l3cfg; 1286 1287 if (NULL == info) { 1288 return (BCM_E_PARAM); 1289 } 1290 1291 mem = INVALIDm; 1292 1293 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1294 l3cfg.l3c_flags = BCM_L3_IPMC; 1295 if (info->flags & BCM_IPMC_IP6) { 1296 l3cfg.l3c_flags |= BCM_L3_IP6; 1297 } 1298 l3cfg.l3c_ing_intf = info->ing_intf; 1299 l3cfg.l3c_vid = info->vid; 1300 l3cfg.l3c_vrf = info->vrf; 1301 1302 if (l3cfg.l3c_flags & BCM_L3_IP6) { 1303 sal_memcpy(l3cfg.l3c_ip6, info->mc_ip6_addr, BCM_IP6_ADDRLEN); 1304 sal_memcpy(l3cfg.l3c_sip6, info->s_ip6_addr, BCM_IP6_ADDRLEN); 1305 } else { 1306 l3cfg.l3c_ip_addr = info->mc_ip_addr; 1307 l3cfg.l3c_src_ip_addr = info->s_ip_addr; 1308 } 1309 1310 rv = _bcm_td2_l3_ipmc_get(unit, &l3cfg); 1311 1312 if (BCM_SUCCESS(rv)) { /* Entry found */ 1313 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 1314 mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_QUADm : 1315 L3_ENTRY_DOUBLEm; 1316 } else { 1317 mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_IPV6_MULTICASTm : 1318 L3_ENTRY_IPV4_MULTICASTm; 1319 } 1320 1321 table_info[*num_of_tables].table = mem; 1322 table_info[*num_of_tables].index = l3cfg.l3c_hw_index; 1323 table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress; 1324 (*num_of_tables)++; 1325 } 1326 1327 return rv; 1328 } 1329 1330 1331 /* 1332 * Function: 1333 * _bcm_td2_ipmc_stat_attach 1334 * Description: 1335 * Attach counters entries to the given IPMC group 1336 * 1337 * Parameters: 1338 * unit - (IN) unit number 1339 * info - (IN) IPMC group information 1340 * stat_counter_id - (IN) Stat Counter ID. 1341 * 1342 * Return Value: 1343 * BCM_E_XXX 1344 */ 1345 bcm_error_t 1346 _bcm_td2_ipmc_stat_attach( 1347 int unit, 1348 bcm_ipmc_addr_t *info, 1349 uint32 stat_counter_id) 1350 { 1351 soc_mem_t table[4]={0}; 1352 uint32 flex_table_index=0; 1353 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 1354 uint32 pool_number=0; 1355 uint32 base_index=0; 1356 bcm_stat_flex_mode_t offset_mode=0; 1357 bcm_stat_object_t object=bcmStatObjectIngPort; 1358 bcm_stat_group_mode_t group_mode= bcmStatGroupModeSingle; 1359 uint32 count=0; 1360 uint32 actual_num_tables=0; 1361 uint32 num_of_tables=0; 1362 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1363 1364 _bcm_esw_stat_get_counter_id_info( 1365 unit, stat_counter_id, 1366 &group_mode,&object,&offset_mode,&pool_number,&base_index); 1367 1368 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction)); 1369 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode)); 1370 1371 BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info( 1372 unit,object,4,&actual_num_tables,&table[0],&direction)); 1373 1374 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info( 1375 unit, info,&num_of_tables,&table_info[0])); 1376 for (count=0; count < num_of_tables ; count++) { 1377 for (flex_table_index=0; 1378 flex_table_index < actual_num_tables ; 1379 flex_table_index++) { 1380 if ((table_info[count].direction == direction) && 1381 (table_info[count].table == table[flex_table_index]) ) { 1382 if (direction == bcmStatFlexDirectionIngress) { 1383 return _bcm_esw_stat_flex_attach_ingress_table_counters( 1384 unit, 1385 table_info[count].table, 1386 table_info[count].index, 1387 offset_mode, 1388 base_index, 1389 pool_number); 1390 } else { 1391 return _bcm_esw_stat_flex_attach_egress_table_counters( 1392 unit, 1393 table_info[count].table, 1394 table_info[count].index, 1395 0, 1396 offset_mode, 1397 base_index, 1398 pool_number); 1399 } 1400 } 1401 } 1402 } 1403 return BCM_E_NOT_FOUND; 1404 } 1405 1406 /* 1407 * Function: 1408 * _bcm_td2_ipmc_stat_detach 1409 * Description: 1410 * Detach counters entries to the given IPMC group 1411 * 1412 * Parameters: 1413 * unit - (IN) unit number 1414 * info - (IN) L3 host description 1415 * 1416 * Return Value: 1417 * BCM_E_XXX 1418 * Notes: 1419 */ 1420 bcm_error_t 1421 _bcm_td2_ipmc_stat_detach( 1422 int unit, 1423 bcm_ipmc_addr_t *info) 1424 { 1425 uint32 count=0; 1426 uint32 num_of_tables=0; 1427 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1428 bcm_error_t rv = BCM_E_NONE; 1429 bcm_error_t err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE}; 1430 1431 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info( 1432 unit, info,&num_of_tables,&table_info[0])); 1433 1434 for (count=0; count < num_of_tables ; count++) { 1435 if (table_info[count].direction == bcmStatFlexDirectionIngress) { 1436 rv = _bcm_esw_stat_flex_detach_ingress_table_counters( 1437 unit, 1438 table_info[count].table, 1439 table_info[count].index); 1440 if (BCM_E_NONE != rv && 1441 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) { 1442 err_code[bcmStatFlexDirectionIngress] = rv; 1443 } 1444 } else { 1445 rv = _bcm_esw_stat_flex_detach_egress_table_counters( 1446 unit, 1447 0, 1448 table_info[count].table, 1449 table_info[count].index); 1450 if (BCM_E_NONE != rv && 1451 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) { 1452 err_code[bcmStatFlexDirectionEgress] = rv; 1453 } 1454 } 1455 } 1456 1457 BCM_STAT_FLEX_DETACH_RETURN(err_code) 1458 } 1459 1460 /* 1461 * Function: 1462 * _bcm_td2_ipmc_stat_counter_get 1463 * Description: 1464 * Get counter statistic values for specific IPMC group 1465 * if sync_mode is set, sync the sw accumulated count 1466 * with hw count value first, else return sw count. 1467 * 1468 * Parameters: 1469 * unit - (IN) unit number 1470 * sync_mode - (IN) hwcount is to be synced to sw count 1471 * info - (IN) IPMC group information 1472 * stat - (IN) Type of the counter to retrieve 1473 * I.e. ingress/egress byte/packet) 1474 * num_entries - (IN) Number of counter Entries 1475 * counter_indexes - (IN) Pointer to Counter indexes entries 1476 * counter_values - (OUT) Pointer to counter values 1477 * 1478 * Return Value: 1479 * BCM_E_XXX 1480 * Notes: 1481 */ 1482 bcm_error_t 1483 _bcm_td2_ipmc_stat_counter_get( 1484 int unit, 1485 int sync_mode, 1486 bcm_ipmc_addr_t *info, 1487 bcm_ipmc_stat_t stat, 1488 uint32 num_entries, 1489 uint32 *counter_indexes, 1490 bcm_stat_value_t *counter_values) 1491 { 1492 uint32 table_count=0; 1493 uint32 index_count=0; 1494 uint32 num_of_tables=0; 1495 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 1496 uint32 byte_flag=0; 1497 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1498 1499 if ((stat == bcmIpmcInPackets) || 1500 (stat == bcmIpmcInBytes)) { 1501 direction = bcmStatFlexDirectionIngress; 1502 } else { 1503 /* direction = bcmStatFlexDirectionEgress; */ 1504 return BCM_E_PARAM; 1505 } 1506 if (stat == bcmIpmcInPackets) { 1507 byte_flag=0; 1508 } else { 1509 byte_flag=1; 1510 } 1511 1512 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info( 1513 unit, info,&num_of_tables,&table_info[0])); 1514 1515 for (table_count=0; table_count < num_of_tables ; table_count++) { 1516 if (table_info[table_count].direction == direction) { 1517 for (index_count=0; index_count < num_entries ; index_count++) { 1518 /*ctr_offset_info.offset_index = counter_indexes[index_count];*/ 1519 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get( 1520 unit, sync_mode, 1521 table_info[table_count].index, 1522 table_info[table_count].table, 1523 0, 1524 byte_flag, 1525 counter_indexes[index_count], 1526 &counter_values[index_count])); 1527 } 1528 } 1529 } 1530 return BCM_E_NONE; 1531 } 1532 1533 /* 1534 * Function: 1535 * _bcm_td2_ipmc_stat_counter_set 1536 * Description: 1537 * Set counter statistic values for specific IPMC group 1538 * 1539 * Parameters: 1540 * unit - (IN) unit number 1541 * info - (IN) IPMC group information 1542 * stat - (IN) Type of the counter to retrieve 1543 * I.e. ingress/egress byte/packet) 1544 * num_entries - (IN) Number of counter Entries 1545 * counter_indexes - (IN) Pointer to Counter indexes entries 1546 * counter_values - (IN) Pointer to counter values 1547 * 1548 * Return Value: 1549 * BCM_E_XXX 1550 * Notes: 1551 */ 1552 bcm_error_t 1553 _bcm_td2_ipmc_stat_counter_set( 1554 int unit, 1555 bcm_ipmc_addr_t *info, 1556 bcm_ipmc_stat_t stat, 1557 uint32 num_entries, 1558 uint32 *counter_indexes, 1559 bcm_stat_value_t *counter_values) 1560 { 1561 uint32 table_count=0; 1562 uint32 index_count=0; 1563 uint32 num_of_tables=0; 1564 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 1565 uint32 byte_flag=0; 1566 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1567 1568 if ((stat == bcmIpmcInPackets) || 1569 (stat == bcmIpmcInBytes)) { 1570 direction = bcmStatFlexDirectionIngress; 1571 } else { 1572 /* direction = bcmStatFlexDirectionEgress; */ 1573 return BCM_E_PARAM; 1574 } 1575 if (stat == bcmIpmcInPackets) { 1576 byte_flag=0; 1577 } else { 1578 byte_flag=1; 1579 } 1580 1581 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info( 1582 unit, info,&num_of_tables,&table_info[0])); 1583 1584 for (table_count=0; table_count < num_of_tables ; table_count++) { 1585 if (table_info[table_count].direction == direction) { 1586 for (index_count=0; index_count < num_entries ; index_count++) { 1587 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set( 1588 unit, 1589 table_info[table_count].index, 1590 table_info[table_count].table, 1591 0, 1592 byte_flag, 1593 counter_indexes[index_count], 1594 &counter_values[index_count])); 1595 } 1596 } 1597 } 1598 return BCM_E_NONE; 1599 } 1600 1601 /* 1602 * Function: 1603 * _bcm_td2_ipmc_stat_multi_get 1604 * 1605 * Description: 1606 * Get Multiple IPMC group counter value for specified IPMC group index for multiple stat 1607 * types 1608 * 1609 * Parameters: 1610 * unit - (IN) unit number 1611 * info - (IN) IPMC group Info 1612 * nstat - (IN) Number of elements in stat array 1613 * stat_arr - (IN) Collected statistics descriptors array 1614 * value_arr - (OUT) Collected counters values 1615 * 1616 * Return Value: 1617 * BCM_E_XXX 1618 * Notes: 1619 */ 1620 bcm_error_t _bcm_td2_ipmc_stat_multi_get( 1621 int unit, 1622 bcm_ipmc_addr_t *info, 1623 int nstat, 1624 bcm_ipmc_stat_t *stat_arr, 1625 uint64 *value_arr) 1626 { 1627 int rv = BCM_E_NONE; 1628 int idx; 1629 uint32 counter_indexes = 0; 1630 bcm_stat_value_t counter_values = {0}; 1631 int sync_mode = 0; 1632 1633 /* Iterate of all stats array to retrieve flex counter values */ 1634 for (idx = 0; idx < nstat ;idx++) { 1635 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_get( 1636 unit, sync_mode, info, stat_arr[idx], 1637 1, &counter_indexes, &counter_values)); 1638 if ((stat_arr[idx] == bcmIpmcInPackets)) { 1639 COMPILER_64_SET(value_arr[idx], 1640 COMPILER_64_HI(counter_values.packets64), 1641 COMPILER_64_LO(counter_values.packets64)); 1642 } else { 1643 COMPILER_64_SET(value_arr[idx], 1644 COMPILER_64_HI(counter_values.bytes), 1645 COMPILER_64_LO(counter_values.bytes)); 1646 } 1647 } 1648 return rv; 1649 } 1650 1651 /* 1652 * Function: 1653 * _bcm_td2_ipmc_stat_multi_get32 1654 * 1655 * Description: 1656 * Get 32bit IPMC group counter value for specified IPMC group index for multiple stat 1657 * types 1658 * 1659 * Parameters: 1660 * unit - (IN) unit number 1661 * info - (IN) IPMC group Info 1662 * nstat - (IN) Number of elements in stat array 1663 * stat_arr - (IN) Collected statistics descriptors array 1664 * value_arr - (OUT) Collected counters values 1665 * 1666 * Return Value: 1667 * BCM_E_XXX 1668 * Notes: 1669 */ 1670 bcm_error_t _bcm_td2_ipmc_stat_multi_get32( 1671 int unit, 1672 bcm_ipmc_addr_t *info, 1673 int nstat, 1674 bcm_ipmc_stat_t *stat_arr, 1675 uint32 *value_arr) 1676 { 1677 int rv = BCM_E_NONE; 1678 int idx; 1679 uint32 counter_indexes = 0; 1680 bcm_stat_value_t counter_values = {0}; 1681 int sync_mode = 0; 1682 1683 /* Iterate of all stats array to retrieve flex counter values */ 1684 for (idx = 0; idx < nstat ;idx++) { 1685 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_get( 1686 unit, sync_mode, info, stat_arr[idx], 1687 1, &counter_indexes, &counter_values)); 1688 if ((stat_arr[idx] == bcmIpmcInPackets)) { 1689 value_arr[idx] = counter_values.packets; 1690 } else { 1691 value_arr[idx] = COMPILER_64_LO(counter_values.bytes); 1692 } 1693 } 1694 return rv; 1695 } 1696 1697 /* 1698 * Function: 1699 * _bcm_td2_ipmc_stat_multi_set 1700 * 1701 * Description: 1702 * Set IPMC group counter value for specified IPMC group index for multiple stat 1703 * types 1704 * 1705 * Parameters: 1706 * unit - (IN) unit number 1707 * info - (IN) IPMC group Info 1708 * stat - (IN) IPMC group counter stat types 1709 * num_entries - (IN) Number of counter Entries 1710 * counter_indexes - (IN) Pointer to Counter indexes entries 1711 * counter_values - (OUT) Pointer to counter values 1712 * 1713 * Return Value: 1714 * BCM_E_XXX 1715 * Notes: 1716 */ 1717 bcm_error_t _bcm_td2_ipmc_stat_multi_set( 1718 int unit, 1719 bcm_ipmc_addr_t *info, 1720 int nstat, 1721 bcm_ipmc_stat_t *stat_arr, 1722 uint64 *value_arr) 1723 { 1724 int rv = BCM_E_NONE; 1725 int idx; 1726 uint32 counter_indexes = 0; 1727 bcm_stat_value_t counter_values = {0}; 1728 1729 /* Iterate f all stats array to retrieve flex counter values */ 1730 for (idx = 0; idx < nstat ;idx++) { 1731 if ((stat_arr[idx] == bcmIpmcInPackets)) { 1732 counter_values.packets = COMPILER_64_LO(value_arr[idx]); 1733 } else { 1734 COMPILER_64_SET(counter_values.bytes, 1735 COMPILER_64_HI(value_arr[idx]), 1736 COMPILER_64_LO(value_arr[idx])); 1737 } 1738 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_set( 1739 unit, info, stat_arr[idx], 1740 1, &counter_indexes, &counter_values)); 1741 } 1742 return rv; 1743 1744 } 1745 1746 /* 1747 * Function: 1748 * _bcm_td2_ipmc_stat_multi_set32 1749 * 1750 * Description: 1751 * Set 32bit IPMC group counter value for specified IPMC group index for multiple stat 1752 * types 1753 * 1754 * Parameters: 1755 * unit - (IN) unit number 1756 * info - (IN) IPMC group Info 1757 * stat - (IN) IPMC group counter stat types 1758 * num_entries - (IN) Number of counter Entries 1759 * counter_indexes - (IN) Pointer to Counter indexes entries 1760 * counter_values - (OUT) Pointer to counter values 1761 * 1762 * Return Value: 1763 * BCM_E_XXX 1764 * Notes: 1765 */ 1766 1767 bcm_error_t _bcm_td2_ipmc_stat_multi_set32( 1768 int unit, 1769 bcm_ipmc_addr_t *info, 1770 int nstat, 1771 bcm_ipmc_stat_t *stat_arr, 1772 uint32 *value_arr) 1773 { 1774 int rv = BCM_E_NONE; 1775 int idx; 1776 uint32 counter_indexes = 0; 1777 bcm_stat_value_t counter_values = {0}; 1778 1779 /* Iterate of all stats array to retrieve flex counter values */ 1780 for (idx = 0; idx < nstat ;idx++) { 1781 if ((stat_arr[idx] == bcmIpmcInPackets)) { 1782 counter_values.packets = value_arr[idx]; 1783 } else { 1784 COMPILER_64_SET(counter_values.bytes,0,value_arr[idx]); 1785 } 1786 1787 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_set( 1788 unit, info, stat_arr[idx], 1789 1, &counter_indexes, &counter_values)); 1790 } 1791 return rv; 1792 } 1793 1794 /* 1795 * Function: 1796 * _bcm_td2_ipmc_stat_id_get 1797 * Description: 1798 * Get stat counter id associated with given IPMC group 1799 * 1800 * Parameters: 1801 * unit - (IN) unit number 1802 * info - (IN) IPMC group information 1803 * stat - (IN) Type of the counter to retrieve 1804 * I.e. ingress/egress byte/packet) 1805 * Stat_counter_id - (OUT) Stat Counter ID 1806 * Return Value: 1807 * BCM_E_XXX 1808 * Notes: 1809 */ 1810 bcm_error_t 1811 _bcm_td2_ipmc_stat_id_get( 1812 int unit, 1813 bcm_ipmc_addr_t *info, 1814 bcm_ipmc_stat_t stat, 1815 uint32 *stat_counter_id) 1816 { 1817 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 1818 uint32 num_of_tables=0; 1819 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1820 uint32 index=0; 1821 uint32 num_stat_counter_ids=0; 1822 1823 if ((stat == bcmIpmcInPackets) || 1824 (stat == bcmIpmcInBytes)) { 1825 direction = bcmStatFlexDirectionIngress; 1826 } else { 1827 /* direction = bcmStatFlexDirectionEgress; */ 1828 return BCM_E_PARAM; 1829 } 1830 1831 BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info( 1832 unit,info,&num_of_tables,&table_info[0])); 1833 for (index=0; index < num_of_tables ; index++) { 1834 if (table_info[index].direction == direction) 1835 return _bcm_esw_stat_flex_get_counter_id( 1836 unit, 1, &table_info[index], 1837 &num_stat_counter_ids,stat_counter_id); 1838 } 1839 return BCM_E_NOT_FOUND; 1840 } 1841 1842 #ifdef BCM_WARM_BOOT_SUPPORT 1843 1844 /* 1845 * Function: 1846 * bcm_td2_ipmc_pim_bidir_scache_size_get 1847 * Purpose: 1848 * Get the required scache size for PIM-BIDIR feature. 1849 * Parameters: 1850 * unit - StrataSwitch unit # 1851 * size - (OUT) Number of bytes 1852 * Returns: 1853 * BCM_E_xxx 1854 */ 1855 int 1856 bcm_td2_ipmc_pim_bidir_scache_size_get( 1857 int unit, 1858 uint32 *size) 1859 { 1860 int num_rp; 1861 1862 *size = 0; 1863 num_rp = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm, 1864 RPA_ID_PROFILEf); 1865 *size += SHR_BITALLOCSIZE(num_rp); 1866 1867 return BCM_E_NONE; 1868 } 1869 1870 /* 1871 * Function: 1872 * bcm_td2_ipmc_pim_bidir_sync 1873 * Purpose: 1874 * Record PIM-BIDIR persistent info into the scache. 1875 * Parameters: 1876 * unit - StrataSwitch unit # 1877 * scache_ptr - (IN/OUT) Scache pointer 1878 * Returns: 1879 * BCM_E_xxx 1880 */ 1881 int 1882 bcm_td2_ipmc_pim_bidir_sync( 1883 int unit, 1884 uint8 **scache_ptr) 1885 { 1886 int num_rp, i; 1887 SHR_BITDCL *rp_bitmap = NULL; 1888 1889 if (_bcm_td2_pim_bidir_info[unit] == NULL) { 1890 return BCM_E_INIT; 1891 } 1892 /* Create a bitmap of valid rendezvous points */ 1893 num_rp = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm, 1894 RPA_ID_PROFILEf); 1895 rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_rp), "RP bitmap"); 1896 if (NULL == rp_bitmap) { 1897 return BCM_E_MEMORY; 1898 } 1899 sal_memset(rp_bitmap, 0, SHR_BITALLOCSIZE(num_rp)); 1900 for (i = 0; i < num_rp; i++) { 1901 if (IPMC_RP_INFO(unit, i)->valid) { 1902 SHR_BITSET(rp_bitmap, i); 1903 } 1904 } 1905 1906 /* Store the bitmap of valid rendezvous points into scache */ 1907 sal_memcpy((*scache_ptr), rp_bitmap, SHR_BITALLOCSIZE(num_rp)); 1908 (*scache_ptr) += SHR_BITALLOCSIZE(num_rp); 1909 1910 sal_free(rp_bitmap); 1911 return BCM_E_NONE; 1912 } 1913 1914 /* 1915 * Function: 1916 * bcm_td2_ipmc_pim_bidir_scache_recover 1917 * Purpose: 1918 * Recover PIM-BIDIR info from scache. 1919 * Parameters: 1920 * unit - (IN) SOC unit number. 1921 * scache_ptr - (IN/OUT) Scache pointer 1922 * Returns: 1923 * BCM_E_XXX 1924 */ 1925 int 1926 bcm_td2_ipmc_pim_bidir_scache_recover(int unit, uint8 **scache_ptr) 1927 { 1928 int num_rp, i; 1929 SHR_BITDCL *rp_bitmap = NULL; 1930 1931 /* Recover a bitmap of valid rendezvous points */ 1932 num_rp = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm, 1933 RPA_ID_PROFILEf); 1934 rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_rp), "RP bitmap"); 1935 if (NULL == rp_bitmap) { 1936 return BCM_E_MEMORY; 1937 } 1938 sal_memcpy(rp_bitmap, (*scache_ptr), SHR_BITALLOCSIZE(num_rp)); 1939 for (i = 0; i < num_rp; i++) { 1940 if (SHR_BITGET(rp_bitmap, i)) { 1941 IPMC_RP_INFO(unit, i)->valid = 1; 1942 } 1943 } 1944 (*scache_ptr) += SHR_BITALLOCSIZE(num_rp); 1945 1946 sal_free(rp_bitmap); 1947 return BCM_E_NONE; 1948 } 1949 1950 /* 1951 * Function: 1952 * _bcm_td2_ipmc_pim_bidir_recover 1953 * Purpose: 1954 * Recover PIM-BIDIR info from hardware. 1955 * Parameters: 1956 * unit - StrataSwitch unit # 1957 * Returns: 1958 * BCM_E_xxx 1959 */ 1960 STATIC int 1961 _bcm_td2_ipmc_pim_bidir_recover(int unit) 1962 { 1963 int rv = BCM_E_NONE; 1964 int buf_size; 1965 uint8 *l3_iif_buf = NULL; 1966 int i; 1967 iif_entry_t *l3_iif_entry_ptr = NULL; 1968 int profile_index; 1969 ing_active_l3_iif_profile_entry_t profile_entry; 1970 int rp_bitmap_length; 1971 SHR_BITDCL *rp_bitmap = NULL; 1972 int rp_id; 1973 _bcm_td2_l3_iif_t *current_ptr; 1974 uint8 *tcam_buf = NULL; 1975 ip_multicast_tcam_entry_t *tcam_entry_ptr = NULL; 1976 1977 /* Read L3 IIF table */ 1978 buf_size = sizeof(iif_entry_t) * soc_mem_index_count(unit, L3_IIFm); 1979 l3_iif_buf = soc_cm_salloc(unit, buf_size, "L3 IIF buffer"); 1980 if (NULL == l3_iif_buf) { 1981 rv = BCM_E_MEMORY; 1982 goto clean_up; 1983 } 1984 rv = soc_mem_read_range(unit, L3_IIFm, MEM_BLOCK_ANY, 1985 soc_mem_index_min(unit, L3_IIFm), 1986 soc_mem_index_max(unit, L3_IIFm), l3_iif_buf); 1987 if (SOC_FAILURE(rv)) { 1988 goto clean_up; 1989 } 1990 1991 /* Traverse each entry of L3 IIF table */ 1992 for (i = soc_mem_index_min(unit, L3_IIFm); 1993 i <= soc_mem_index_max(unit, L3_IIFm); i++) { 1994 l3_iif_entry_ptr = soc_mem_table_idx_to_pointer(unit, L3_IIFm, 1995 iif_entry_t *, l3_iif_buf, i); 1996 1997 /* Recover active L3 IIF profile reference count */ 1998 profile_index = soc_L3_IIFm_field32_get(unit, l3_iif_entry_ptr, 1999 ACTIVE_L3_IIF_PROFILE_INDEXf); 2000 SOC_PROFILE_MEM_REFERENCE(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit), 2001 profile_index, 1); 2002 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit), 2003 profile_index, 1); 2004 2005 /* Get a bitmap of the rendezvous points L3 IIF belongs to */ 2006 rv = READ_ING_ACTIVE_L3_IIF_PROFILEm(unit, MEM_BLOCK_ANY, 2007 profile_index, &profile_entry); 2008 if (SOC_FAILURE(rv)) { 2009 goto clean_up; 2010 } 2011 rp_bitmap_length = soc_mem_field_length(unit, 2012 ING_ACTIVE_L3_IIF_PROFILEm, RPA_ID_PROFILEf); 2013 if (NULL == rp_bitmap) { 2014 rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(rp_bitmap_length), 2015 "RP bitmap"); 2016 if (NULL == rp_bitmap) { 2017 rv = BCM_E_MEMORY; 2018 goto clean_up; 2019 } 2020 } 2021 soc_ING_ACTIVE_L3_IIF_PROFILEm_field_get(unit, &profile_entry, 2022 RPA_ID_PROFILEf, rp_bitmap); 2023 2024 /* For each rendezvous point the L3 IIF belongs to, 2025 * insert the L3 IIF into the rendezvous point's linked list 2026 * of L3 IIFs. 2027 */ 2028 for (rp_id = 0; rp_id < rp_bitmap_length; rp_id++) { 2029 if (SHR_BITGET(rp_bitmap, rp_id)) { 2030 IPMC_RP_INFO(unit, rp_id)->valid = 1; 2031 current_ptr = sal_alloc(sizeof(_bcm_td2_l3_iif_t), 2032 "Active L3 IIF"); 2033 if (NULL == current_ptr) { 2034 rv = BCM_E_MEMORY; 2035 goto clean_up; 2036 } 2037 current_ptr->l3_iif = i; 2038 current_ptr->next = IPMC_RP_INFO(unit, rp_id)->l3_iif_list; 2039 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr; 2040 } 2041 } 2042 } 2043 2044 /* Recover bitmap of valid IPMC TCAM entries */ 2045 buf_size = sizeof(ip_multicast_tcam_entry_t) * 2046 soc_mem_index_count(unit, IP_MULTICAST_TCAMm); 2047 tcam_buf = soc_cm_salloc(unit, buf_size, "IP Multicast TCAM buffer"); 2048 if (NULL == tcam_buf) { 2049 rv = BCM_E_MEMORY; 2050 goto clean_up; 2051 } 2052 rv = soc_mem_read_range(unit, IP_MULTICAST_TCAMm, MEM_BLOCK_ANY, 2053 soc_mem_index_min(unit, IP_MULTICAST_TCAMm), 2054 soc_mem_index_max(unit, IP_MULTICAST_TCAMm), tcam_buf); 2055 if (SOC_FAILURE(rv)) { 2056 goto clean_up; 2057 } 2058 for (i = soc_mem_index_min(unit, IP_MULTICAST_TCAMm); 2059 i <= soc_mem_index_max(unit, IP_MULTICAST_TCAMm); i++) { 2060 tcam_entry_ptr = soc_mem_table_idx_to_pointer(unit, IP_MULTICAST_TCAMm, 2061 ip_multicast_tcam_entry_t *, tcam_buf, i); 2062 if (soc_IP_MULTICAST_TCAMm_field32_get(unit, tcam_entry_ptr, VALIDf)) { 2063 SHR_BITSET(IPMC_TCAM_BITMAP(unit), i); 2064 } 2065 } 2066 2067 clean_up: 2068 if (NULL != l3_iif_buf) { 2069 soc_cm_sfree(unit, l3_iif_buf); 2070 } 2071 if (NULL != rp_bitmap) { 2072 sal_free(rp_bitmap); 2073 } 2074 if (NULL != tcam_buf) { 2075 soc_cm_sfree(unit, tcam_buf); 2076 } 2077 return rv; 2078 } 2079 2080 /* 2081 * Function: 2082 * bcm_td2_ipmc_rp_ref_count_recover 2083 * Purpose: 2084 * Increment reference count of rendezvous point. If the rendezvous point 2085 * is invalid, set it to valid. 2086 * Parameters: 2087 * unit - StrataSwitch unit # 2088 * rp_id - Rendezvous point ID 2089 * Returns: 2090 * BCM_E_xxx 2091 * Notes: 2092 * During warm boot recovery, the IPMC address table is traversed to 2093 * recover how many IPMC address entries are referencing the rendezvous 2094 * points. This function is called to update the reference count. 2095 * The traversal of IPCM address table occurs before recovery of 2096 * rendezvous point info from scache. Hence, when this function is 2097 * called, it's possible that the rendezvous point is not yet marked 2098 * valid. 2099 */ 2100 int 2101 bcm_td2_ipmc_rp_ref_count_recover( 2102 int unit, 2103 int rp_id) 2104 { 2105 int rv = BCM_E_NONE; 2106 2107 if (NULL == _bcm_td2_pim_bidir_info[unit]) { 2108 return BCM_E_INIT; 2109 } 2110 2111 if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) { 2112 return BCM_E_PARAM; 2113 } 2114 2115 if (!IPMC_RP_INFO(unit, rp_id)->valid) { 2116 IPMC_RP_INFO(unit, rp_id)->valid = 1; 2117 } 2118 2119 IPMC_RP_INFO(unit, rp_id)->ref_count++; 2120 2121 return rv; 2122 } 2123 2124 #endif /* BCM_WARM_BOOT_SUPPORT */ 2125 2126 #ifndef BCM_SW_STATE_DUMP_DISABLE 2127 /* 2128 * Function: 2129 * _bcm_td2_ipmc_pim_bidir_sw_dump 2130 * Purpose: 2131 * Displays PIM-BIDIR information maintained by software. 2132 * Parameters: 2133 * unit - Device unit number 2134 * Returns: 2135 * None 2136 */ 2137 void 2138 _bcm_td2_ipmc_pim_bidir_sw_dump(int unit) 2139 { 2140 int rv; 2141 int i, j; 2142 int num_profiles, ref_count; 2143 2144 LOG_CLI((BSL_META_U(unit, 2145 " PIM-BIDIR Rendezvous Points Size: %d\n"), 2146 IPMC_NUM_RP(unit))); 2147 2148 LOG_CLI((BSL_META_U(unit, 2149 " Allocated Rendezvous Points (ID:reference count):"))); 2150 for (i = 0, j = 0; i < IPMC_NUM_RP(unit); i++) { 2151 if (!IPMC_RP_INFO(unit, i)->valid) { 2152 continue; 2153 } 2154 if (!(j % 10)) { 2155 LOG_CLI((BSL_META_U(unit, 2156 "\n "))); 2157 } 2158 LOG_CLI((BSL_META_U(unit, 2159 " %2d:%-6d"), i, IPMC_RP_INFO(unit, i)->ref_count)); 2160 j++; 2161 } 2162 LOG_CLI((BSL_META_U(unit, 2163 "\n"))); 2164 2165 LOG_CLI((BSL_META_U(unit, 2166 " Active L3 IIF profile (index:reference count):"))); 2167 num_profiles = soc_mem_index_count(unit, ING_ACTIVE_L3_IIF_PROFILEm); 2168 for (i = 0, j = 0; i < num_profiles; i++) { 2169 rv = soc_profile_mem_ref_count_get(unit, 2170 IPMC_ACTIVE_L3_IIF_PROFILE(unit), i, &ref_count); 2171 if (SOC_FAILURE(rv)) { 2172 continue; 2173 } 2174 if (0 == ref_count) { 2175 continue; 2176 } 2177 if (!(j % 10)) { 2178 LOG_CLI((BSL_META_U(unit, 2179 "\n "))); 2180 } 2181 LOG_CLI((BSL_META_U(unit, 2182 " %4d:%-4d"), i, ref_count)); 2183 j++; 2184 } 2185 LOG_CLI((BSL_META_U(unit, 2186 "\n"))); 2187 2188 return; 2189 } 2190 2191 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 2192 2193 /* 2194 * Function: 2195 * _bcm_td2_ipv6_reserved_multicast_addr_set 2196 * Description: 2197 * Set ipv6 reserved multicast address and mask. 2198 * 2199 * Parameters: 2200 * unit - (IN) unit number 2201 * ip6_addr - (IN) ipv6 address 2202 * ip6_mask - (IN) ipv6 addres mask 2203 * 2204 * Return Value: 2205 * BCM_E_XXX 2206 * Notes: 2207 */ 2208 int 2209 _bcm_td2_ipv6_reserved_multicast_addr_set(int unit, 2210 bcm_ip6_t ip6_addr, 2211 bcm_ip6_t ip6_mask) 2212 { 2213 2214 soc_mem_t mem; 2215 uint32 ip6_fields[4]; 2216 uint32 entry_buf[SOC_MAX_MEM_FIELD_WORDS]; 2217 2218 mem = ING_IPV6_MC_RESERVED_ADDRESSm; 2219 if (soc_mem_is_valid(unit, PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm)) { 2220 mem = PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm; 2221 } 2222 /* clear entry memory */ 2223 sal_memset(entry_buf, 0, sizeof(entry_buf)); 2224 /* encode v6 address into ip6_fields */ 2225 SAL_IP6_ADDR_TO_UINT32(ip6_addr, ip6_fields); 2226 /* set address in entry */ 2227 soc_mem_field_set(unit, mem, entry_buf, ADDRESSf, &(ip6_fields[0])); 2228 /* encode v6 mask into ip6_fields */ 2229 SAL_IP6_ADDR_TO_UINT32(ip6_mask, ip6_fields); 2230 /* set the mask in entry */ 2231 soc_mem_field_set(unit, mem, entry_buf, MASKf, &(ip6_fields[0])); 2232 /* write entry to hardware */ 2233 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 0, 2234 entry_buf)); 2235 return BCM_E_NONE; 2236 } 2237 2238 /* 2239 * Function: 2240 * _bcm_td2_ipv6_reserved_multicast_addr_get 2241 * Description: 2242 * get the ipv6 reserved multicast address and mask 2243 * 2244 * Parameters: 2245 * unit - (IN) unit number 2246 * ip6_addr - (OUT) ipv6 address 2247 * ip6_mask - (OUT) ipv6 addres mask 2248 * 2249 * Return Value: 2250 * BCM_E_XXX 2251 * Notes: 2252 */ 2253 int 2254 _bcm_td2_ipv6_reserved_multicast_addr_get(int unit, 2255 bcm_ip6_t *ip6_addr, 2256 bcm_ip6_t *ip6_mask) 2257 { 2258 soc_mem_t mem; 2259 uint32 ip6_fields[4]; 2260 uint32 entry_buf[SOC_MAX_MEM_FIELD_WORDS]; 2261 2262 /* sanity checks first */ 2263 if (!ip6_addr) { 2264 return BCM_E_PARAM; 2265 } 2266 2267 if (!ip6_mask) { 2268 return BCM_E_PARAM; 2269 } 2270 2271 mem = ING_IPV6_MC_RESERVED_ADDRESSm; 2272 if (soc_mem_is_valid(unit, PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm)) { 2273 mem = PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm; 2274 } 2275 /* clear entry memory */ 2276 sal_memset(entry_buf, 0, sizeof(entry_buf)); 2277 /* read entry from hardware */ 2278 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, 0, entry_buf)); 2279 /* deduce the address from entry */ 2280 soc_mem_field_get(unit, mem, entry_buf, ADDRESSf, &(ip6_fields[0])); 2281 /* set the address in user buf */ 2282 SAL_IP6_ADDR_FROM_UINT32(*ip6_addr, ip6_fields); 2283 2284 /* deduce the mask from entry */ 2285 soc_mem_field_get(unit, mem, entry_buf, MASKf, &(ip6_fields[0])); 2286 /* set the mask in user buf */ 2287 SAL_IP6_ADDR_FROM_UINT32(*ip6_mask, ip6_fields); 2288 2289 return BCM_E_NONE; 2290 } 2291 2292 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */