l2.c (30594B)
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: bcmx/l2.c 8 * Purpose: BCMX L2 APIs 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <sal/core/libc.h> 14 #include <shared/alloc.h> 15 16 #include <bcm/types.h> 17 18 #include <bcmx/l2.h> 19 #include <bcmx/lport.h> 20 #include <bcmx/bcmx.h> 21 #include <bcmx/lplist.h> 22 23 #include "bcmx_int.h" 24 25 #define BCMX_L2_INIT_CHECK BCMX_READY_CHECK 26 27 #define BCMX_L2_SET_ERROR_CHECK(_unit, _check, _rv) \ 28 BCMX_SET_ERROR_CHECK(_unit, _check, _rv) 29 30 #define BCMX_L2_DELETE_ERROR_CHECK(_unit, _check, _rv) \ 31 BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv) 32 33 #define BCMX_L2_GET_IS_VALID(_unit, _rv) \ 34 BCMX_ERROR_IS_VALID(_unit, _rv) 35 36 37 STATIC INLINE void 38 _bcmx_l2_addr_t_init(bcmx_l2_addr_t *l2addr, 39 bcm_mac_t mac_addr, 40 bcm_vlan_t vid) 41 { 42 if (l2addr != NULL) { 43 sal_memset(l2addr, 0, sizeof (*l2addr)); 44 sal_memcpy(l2addr->mac, mac_addr, sizeof(bcm_mac_t)); 45 l2addr->vid = vid; 46 } 47 } 48 49 STATIC INLINE int 50 _bcmx_l2_addr_to_bcm(int bcm_unit, 51 bcm_l2_addr_t *dest, 52 bcmx_l2_addr_t *source, 53 bcmx_lplist_t *port_block) 54 { 55 uint32 flags = BCMX_DEST_CONVERT_DEFAULT; 56 _bcmx_dest_bcm_t to_bcm; 57 _bcmx_dest_bcmx_t from_bcmx; 58 59 bcm_l2_addr_t_init(dest, source->mac, source->vid); 60 dest->flags = source->flags; 61 62 /* 63 * Convert destination data 64 */ 65 _bcmx_dest_bcmx_t_init(&from_bcmx); 66 67 /* Set flags and data to convert */ 68 if (source->flags & BCM_L2_MCAST) { 69 flags |= BCMX_DEST_MCAST; 70 } else if (source->flags & BCM_L2_TRUNK_MEMBER) { 71 flags |= BCMX_DEST_TRUNK; 72 } 73 from_bcmx.port = source->lport; 74 from_bcmx.trunk = source->tgid; 75 from_bcmx.mcast = source->l2mc_group; 76 77 /* Convert */ 78 BCM_IF_ERROR_RETURN(_bcmx_dest_to_bcm(&from_bcmx, &to_bcm, &flags)); 79 80 /* Set converted flags and data */ 81 if (flags & BCMX_DEST_MCAST) { 82 dest->flags |= BCM_L2_MCAST; 83 } else if (flags & BCMX_DEST_TRUNK) { 84 dest->flags |= BCM_L2_TRUNK_MEMBER; 85 } else if (flags & BCMX_DEST_DISCARD) { 86 dest->flags |= BCM_L2_DISCARD_DST; 87 } 88 dest->modid = (int)to_bcm.module_id; 89 dest->port = (int)to_bcm.module_port; 90 dest->tgid = to_bcm.trunk; 91 dest->l2mc_group = to_bcm.mcast; 92 93 /* Set remaining fields */ 94 dest->cos_dst = source->cos_dst; 95 dest->cos_src = source->cos_src; 96 dest->auth = source->auth; 97 dest->group = source->group; 98 99 BCM_PBMP_CLEAR(dest->block_bitmap); 100 if (!BCMX_LPLIST_IS_EMPTY(port_block)) { 101 BCMX_LPLIST_TO_PBMP(*port_block, bcm_unit, 102 dest->block_bitmap); 103 } 104 105 return BCM_E_NONE; 106 } 107 108 STATIC INLINE int 109 _bcmx_l2_addr_from_bcm(bcmx_l2_addr_t *dest, 110 bcmx_lplist_t *port_block, 111 bcm_l2_addr_t *source) 112 { 113 uint32 flags = BCMX_DEST_CONVERT_DEFAULT; 114 _bcmx_dest_bcm_t from_bcm; 115 _bcmx_dest_bcmx_t to_bcmx; 116 117 _bcmx_l2_addr_t_init(dest, source->mac, source->vid); 118 dest->flags = source->flags; 119 120 /* 121 * Convert destination data 122 */ 123 _bcmx_dest_bcm_t_init(&from_bcm); 124 125 /* Set flags and data to convert */ 126 if (source->flags & BCM_L2_MCAST) { 127 flags |= BCMX_DEST_MCAST; 128 } else if (source->flags & BCM_L2_TRUNK_MEMBER) { 129 flags |= BCMX_DEST_TRUNK; 130 } 131 from_bcm.module_id = (bcm_module_t)source->modid; 132 from_bcm.module_port = (bcm_port_t)source->port; 133 from_bcm.trunk = source->tgid; 134 from_bcm.mcast = source->l2mc_group; 135 136 /* Convert */ 137 BCM_IF_ERROR_RETURN(_bcmx_dest_from_bcm(&to_bcmx, &from_bcm, &flags)); 138 139 /* Set converted flags and data */ 140 if (flags & BCMX_DEST_MCAST) { 141 dest->flags |= BCM_L2_MCAST; 142 } else if (flags & BCMX_DEST_TRUNK) { 143 dest->flags |= BCM_L2_TRUNK_MEMBER; 144 } else if (flags & BCMX_DEST_DISCARD) { 145 dest->flags |= BCM_L2_DISCARD_DST; 146 } 147 dest->lport = to_bcmx.port; 148 dest->tgid = to_bcmx.trunk; 149 dest->l2mc_group = to_bcmx.mcast; 150 151 /* Set remaining fields */ 152 dest->cos_dst = source->cos_dst; 153 dest->cos_src = source->cos_src; 154 dest->auth = source->auth; 155 dest->group = source->group; 156 157 if (port_block != NULL && BCMX_LPORT_VALID(dest->lport)) { 158 bcmx_lplist_init(port_block, -1, 0); 159 BCMX_LPLIST_PBMP_ADD(port_block, 160 bcmx_lport_bcm_unit(dest->lport), 161 source->block_bitmap); 162 bcmx_lplist_uniq(port_block); 163 } 164 165 return BCM_E_NONE; 166 } 167 168 STATIC INLINE int 169 _bcmx_l2_learn_limit_to_bcm(bcm_l2_learn_limit_t *dest, 170 int *dest_unit, 171 bcmx_l2_learn_limit_t *source) 172 { 173 bcm_l2_learn_limit_t_init(dest); 174 175 *dest_unit = -1; 176 dest->flags = source->flags; 177 dest->vlan = source->vlan; 178 dest->port = source->lport; 179 dest->trunk = source->trunk; 180 dest->limit = source->limit; 181 182 if (source->flags & BCM_L2_LEARN_LIMIT_PORT) { 183 BCM_IF_ERROR_RETURN 184 (_bcmx_dest_to_unit_port(source->lport, 185 dest_unit, &dest->port, 186 BCMX_DEST_CONVERT_DEFAULT)); 187 } 188 189 return BCM_E_NONE; 190 } 191 192 STATIC INLINE int 193 _bcmx_l2_learn_limit_from_bcm(bcmx_l2_learn_limit_t *dest, 194 bcm_l2_learn_limit_t *source, 195 int bcm_unit) 196 { 197 bcmx_l2_learn_limit_t_init(dest); 198 199 dest->flags = source->flags; 200 dest->vlan = source->vlan; 201 dest->lport = source->port; 202 dest->trunk = source->trunk; 203 dest->limit = source->limit; 204 205 if (source->flags & BCM_L2_LEARN_LIMIT_PORT) { 206 BCM_IF_ERROR_RETURN 207 (_bcmx_dest_from_unit_port(&dest->lport, 208 bcm_unit, source->port, 209 BCMX_DEST_CONVERT_DEFAULT)); 210 } 211 212 return BCM_E_NONE; 213 } 214 215 216 /* 217 * Function: 218 * bcmx_l2_addr_t_init 219 */ 220 221 void 222 bcmx_l2_addr_t_init(bcmx_l2_addr_t *l2addr, 223 bcm_mac_t mac_addr, 224 bcm_vlan_t vid) 225 { 226 _bcmx_l2_addr_t_init(l2addr, mac_addr, vid); 227 } 228 229 230 /* 231 * Function: 232 * bcmx_l2_learn_limit_t_init 233 */ 234 235 void 236 bcmx_l2_learn_limit_t_init(bcmx_l2_learn_limit_t *limit) 237 { 238 if (limit != NULL) { 239 sal_memset(limit, 0, sizeof(*limit)); 240 } 241 return; 242 } 243 244 245 /* 246 * Function: 247 * bcmx_l2_addr_add 248 */ 249 250 int 251 bcmx_l2_addr_add(bcmx_l2_addr_t *l2addr, bcmx_lplist_t *port_block) 252 { 253 int rv = BCM_E_UNAVAIL, tmp_rv; 254 int i, bcm_unit; 255 bcm_l2_addr_t bcm_l2; 256 int map_local_cpu; /* Is local CPU port mapping required? */ 257 bcmx_lport_t cpu_lport; 258 bcm_module_t modid; 259 bcm_port_t modport; 260 261 BCMX_L2_INIT_CHECK; 262 263 BCMX_PARAM_NULL_CHECK(l2addr); 264 265 map_local_cpu = ((!(l2addr->flags & BCM_L2_TRUNK_MEMBER)) && 266 (l2addr->lport == BCMX_LPORT_LOCAL_CPU)); 267 268 BCMX_UNIT_ITER(bcm_unit, i) { 269 if (_bcmx_l2_addr_to_bcm(bcm_unit, &bcm_l2, l2addr, port_block) < 0) { 270 LOG_WARN(BSL_LS_BCMX_COMMON, 271 (BSL_META("BCMX L2 WARN: Failed to convert " 272 "L2 address to BCM\n"))); 273 } else { 274 if (map_local_cpu) { 275 cpu_lport = BCMX_LPORT_LOCAL_CPU_GET(bcm_unit); 276 if (BCM_FAILURE 277 (_bcmx_dest_to_modid_port(cpu_lport, 278 &modid, 279 &modport, 280 BCMX_DEST_CONVERT_DEFAULT))) { 281 /* Skip if can't find local CPU port */ 282 continue; 283 } 284 bcm_l2.modid = (int)modid; 285 bcm_l2.port = (int)modport; 286 } 287 tmp_rv = bcm_l2_addr_add(bcm_unit, &bcm_l2); 288 289 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 290 } 291 } 292 293 return rv; 294 } 295 296 /* 297 * Function: 298 * bcmx_l2_addr_refresh 299 * Purpose: 300 * The address is first looked up on the native unit. If found, 301 * the address is updated on all other units. 302 * Notes: 303 * This allows the hit-bit state not to be changed on the native unit. 304 * 305 * No consistency checking is done to see if the addr shows up 306 * on multiple units as native. 307 */ 308 309 int 310 bcmx_l2_addr_refresh(bcmx_l2_addr_t *l2addr, bcmx_lplist_t *port_block) 311 { 312 int rv = BCM_E_UNAVAIL, tmp_rv; 313 int i, bcm_unit; 314 bcm_l2_addr_t bcm_l2; 315 bcmx_l2_addr_t bcmx_l2_native; 316 317 BCMX_L2_INIT_CHECK; 318 319 BCMX_PARAM_NULL_CHECK(l2addr); 320 321 rv = bcmx_l2_addr_native_get(l2addr->mac, l2addr->vid, &bcmx_l2_native); 322 323 if (BCM_SUCCESS(rv)) {/* Address exists on native device. Update */ 324 BCMX_UNIT_ITER(bcm_unit, i) { 325 if (_bcmx_l2_addr_to_bcm(bcm_unit, &bcm_l2, 326 l2addr, port_block) < 0) { 327 LOG_WARN(BSL_LS_BCMX_COMMON, 328 (BSL_META("BCMX L2 WARN: Failed to convert " 329 "L2 address to BCM\n"))); 330 } 331 tmp_rv = bcm_l2_addr_add(bcm_unit, &bcm_l2); 332 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 333 } 334 } 335 336 return rv; 337 } 338 339 340 int 341 bcmx_l2_addr_delete(bcm_mac_t mac, bcm_vlan_t vid) 342 { 343 int rv = BCM_E_UNAVAIL, tmp_rv; 344 int i, bcm_unit; 345 346 BCMX_L2_INIT_CHECK; 347 348 BCMX_UNIT_ITER(bcm_unit, i) { 349 tmp_rv = bcm_l2_addr_delete(bcm_unit, mac, vid); 350 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 351 } 352 353 return rv; 354 } 355 356 int 357 bcmx_l2_addr_delete_by_port(bcmx_lport_t port, uint32 flags) 358 { 359 int rv = BCM_E_UNAVAIL, tmp_rv; 360 int i, bcm_unit; 361 bcm_module_t modid; 362 bcm_port_t modport; 363 364 BCMX_L2_INIT_CHECK; 365 366 BCM_IF_ERROR_RETURN 367 (_bcmx_dest_to_modid_port(port, 368 &modid, &modport, 369 BCMX_DEST_CONVERT_DEFAULT)); 370 371 BCMX_UNIT_ITER(bcm_unit, i) { 372 tmp_rv = bcm_l2_addr_delete_by_port(bcm_unit, 373 modid, 374 modport, 375 flags); 376 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 377 } 378 379 return rv; 380 } 381 382 int 383 bcmx_l2_addr_delete_by_mac(bcm_mac_t mac, uint32 flags) 384 { 385 int rv = BCM_E_UNAVAIL, tmp_rv; 386 int i, bcm_unit; 387 388 BCMX_L2_INIT_CHECK; 389 390 BCMX_UNIT_ITER(bcm_unit, i) { 391 tmp_rv = bcm_l2_addr_delete_by_mac(bcm_unit, mac, flags); 392 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 393 } 394 395 return rv; 396 } 397 398 int 399 bcmx_l2_addr_delete_by_vlan(bcm_vlan_t vid, uint32 flags) 400 { 401 int rv = BCM_E_UNAVAIL, tmp_rv; 402 int i, bcm_unit; 403 404 BCMX_L2_INIT_CHECK; 405 406 BCMX_UNIT_ITER(bcm_unit, i) { 407 tmp_rv = bcm_l2_addr_delete_by_vlan(bcm_unit, vid, flags); 408 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 409 } 410 411 return rv; 412 } 413 414 int 415 bcmx_l2_addr_delete_by_trunk(bcm_trunk_t tid, uint32 flags) 416 { 417 int rv = BCM_E_UNAVAIL, tmp_rv; 418 int i, bcm_unit; 419 420 BCMX_L2_INIT_CHECK; 421 422 BCMX_UNIT_ITER(bcm_unit, i) { 423 tmp_rv = bcm_l2_addr_delete_by_trunk(bcm_unit, tid, flags); 424 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 425 } 426 427 return rv; 428 } 429 430 int 431 bcmx_l2_addr_delete_by_mac_port(bcm_mac_t mac, 432 bcmx_lport_t port, 433 uint32 flags) 434 { 435 int rv = BCM_E_UNAVAIL, tmp_rv; 436 int i, bcm_unit; 437 bcm_module_t modid; 438 bcm_port_t modport; 439 440 BCMX_L2_INIT_CHECK; 441 442 BCM_IF_ERROR_RETURN 443 (_bcmx_dest_to_modid_port(port, 444 &modid, &modport, 445 BCMX_DEST_CONVERT_DEFAULT)); 446 447 BCMX_UNIT_ITER(bcm_unit, i) { 448 tmp_rv = bcm_l2_addr_delete_by_mac_port(bcm_unit, 449 mac, 450 modid, 451 modport, 452 flags); 453 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 454 } 455 456 return rv; 457 } 458 459 int 460 bcmx_l2_addr_delete_by_vlan_port(bcm_vlan_t vid, 461 bcmx_lport_t port, 462 uint32 flags) 463 { 464 int rv = BCM_E_UNAVAIL, tmp_rv; 465 int i, bcm_unit; 466 bcm_module_t modid; 467 bcm_port_t modport; 468 469 BCMX_L2_INIT_CHECK; 470 471 BCM_IF_ERROR_RETURN 472 (_bcmx_dest_to_modid_port(port, 473 &modid, &modport, 474 BCMX_DEST_CONVERT_DEFAULT)); 475 476 BCMX_UNIT_ITER(bcm_unit, i) { 477 tmp_rv = bcm_l2_addr_delete_by_vlan_port(bcm_unit, 478 vid, 479 modid, 480 modport, 481 flags); 482 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 483 } 484 485 return rv; 486 } 487 488 int 489 bcmx_l2_addr_delete_by_vlan_trunk(bcm_vlan_t vid, 490 bcm_trunk_t tid, 491 uint32 flags) 492 { 493 int rv = BCM_E_UNAVAIL, tmp_rv; 494 int i, bcm_unit; 495 496 BCMX_L2_INIT_CHECK; 497 498 BCMX_UNIT_ITER(bcm_unit, i) { 499 tmp_rv = bcm_l2_addr_delete_by_vlan_trunk(bcm_unit, 500 vid, 501 tid, 502 flags); 503 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 504 } 505 506 return rv; 507 } 508 509 /* 510 * Function: 511 * bcmx_l2_addr_get 512 */ 513 514 int 515 bcmx_l2_addr_get(bcm_mac_t mac_addr, 516 bcm_vlan_t vid, 517 bcmx_l2_addr_t *l2addr, 518 bcmx_lplist_t *port_block) 519 { 520 int rv = BCM_E_UNAVAIL, tmp_rv; 521 int i, bcm_unit; 522 bcm_l2_addr_t bcm_l2; 523 int first_time = TRUE; 524 uint32 merged_flags = 0; 525 526 BCMX_L2_INIT_CHECK; 527 528 BCMX_PARAM_NULL_CHECK(l2addr); 529 530 BCMX_UNIT_ITER(bcm_unit, i) { 531 bcm_l2_addr_t_init (&bcm_l2, mac_addr, vid); 532 tmp_rv = bcm_l2_addr_get(bcm_unit, mac_addr, vid, &bcm_l2); 533 534 if (BCMX_L2_GET_IS_VALID(bcm_unit, tmp_rv)) { 535 536 /* If not found in this unit, try the next one */ 537 if (tmp_rv == BCM_E_NOT_FOUND) { 538 /* 539 * Set BCM_E_NOT_FOUND if entry has not been found yet, 540 * in case it is not found in any unit. 541 */ 542 if (rv != BCM_E_NONE) { 543 rv = tmp_rv; 544 } 545 continue; 546 } 547 548 rv = tmp_rv; 549 if (BCM_FAILURE(tmp_rv)) { 550 break; 551 } 552 553 /* Successfully found addr */ 554 merged_flags |= bcm_l2.flags; 555 if (first_time) { /* Call address conversion */ 556 first_time = FALSE; 557 tmp_rv = bcmx_l2_addr_from_bcm(l2addr, port_block, &bcm_l2); 558 if (BCM_FAILURE(tmp_rv)) { 559 rv = tmp_rv; 560 break; 561 } 562 } else if (port_block != NULL) { 563 /* Not first time, add to port block list for address */ 564 BCMX_LPLIST_PBMP_ADD(port_block, 565 bcm_unit, 566 bcm_l2.block_bitmap); 567 } 568 } 569 } 570 571 if (BCM_SUCCESS(rv)) { 572 l2addr->flags |= merged_flags; 573 } 574 575 return rv; 576 } 577 578 /* 579 * Function: 580 * bcmx_l2_addr_native_get 581 * Notes: 582 * Like l2_addr_get, but look for the (a) device which 583 * has the unit on a front panel port. 584 * 585 * Does not provide any information about the blocked ports for 586 * the L2 entry. 587 * 588 * Will return if L2 addr found on CPU port. 589 */ 590 591 int 592 bcmx_l2_addr_native_get(bcm_mac_t mac_addr, 593 bcm_vlan_t vid, 594 bcmx_l2_addr_t *l2addr) 595 596 { 597 int rv; 598 int i, bcm_unit; 599 bcm_l2_addr_t bcm_l2; 600 601 BCMX_L2_INIT_CHECK; 602 603 BCMX_PARAM_NULL_CHECK(l2addr); 604 605 BCMX_UNIT_ITER(bcm_unit, i) { 606 bcm_l2_addr_t_init (&bcm_l2, mac_addr, vid); 607 rv = bcm_l2_addr_get(bcm_unit, mac_addr, vid, &bcm_l2); 608 609 if (BCMX_L2_GET_IS_VALID(bcm_unit, rv)) { 610 611 if (BCM_SUCCESS(rv)) { /* Device knows addr; front panel? */ 612 /* Get the port configuration for the device */ 613 rv = bcm_l2_port_native(bcm_unit, bcm_l2.modid, bcm_l2.port); 614 615 if (BCM_SUCCESS(rv)) { 616 /* Okay, found a device with the port on the front panel */ 617 rv = bcmx_l2_addr_from_bcm(l2addr, NULL, &bcm_l2); 618 } 619 } 620 621 return rv; 622 } 623 } 624 625 return BCM_E_UNAVAIL; 626 } 627 628 /* 629 * Function: 630 * bcmx_l2_addr_port_get 631 * Notes: 632 * Like l2_addr_get, but gets the l2 entry from a unit specified 633 * by an lport. Most often used to get unit specific hit bit status. 634 */ 635 636 int 637 bcmx_l2_addr_port_get(bcmx_lport_t port, 638 bcm_mac_t mac_addr, 639 bcm_vlan_t vid, 640 bcmx_l2_addr_t *l2addr) 641 { 642 int rv, bcm_unit; 643 bcm_l2_addr_t bcm_l2; 644 645 BCMX_L2_INIT_CHECK; 646 647 BCMX_PARAM_NULL_CHECK(l2addr); 648 649 if (!BCMX_LPORT_VALID(port)) { 650 return BCM_E_PORT; 651 } 652 653 bcm_unit = bcmx_lport_bcm_unit(port); 654 655 bcm_l2_addr_t_init (&bcm_l2, mac_addr, vid); 656 rv = bcm_l2_addr_get(bcm_unit, mac_addr, vid, &bcm_l2); 657 if (BCM_SUCCESS(rv)) { 658 rv = _bcmx_l2_addr_from_bcm(l2addr, NULL, &bcm_l2); 659 } 660 661 return rv; 662 } 663 664 /* 665 * Function: 666 * bcmx_l2_age_timer_set 667 */ 668 669 int 670 bcmx_l2_age_timer_set(int age_seconds) 671 { 672 int rv = BCM_E_UNAVAIL, tmp_rv; 673 int i, bcm_unit; 674 675 BCMX_L2_INIT_CHECK; 676 677 BCMX_UNIT_ITER(bcm_unit, i) { 678 tmp_rv = bcm_l2_age_timer_set(bcm_unit, age_seconds); 679 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 680 } 681 682 return rv; 683 } 684 685 686 /* 687 * Function: 688 * bcmx_l2_age_timer_get 689 * Notes: 690 * Return results from first BCM unit that returns success 691 */ 692 693 int 694 bcmx_l2_age_timer_get(int *age_seconds) 695 { 696 int rv; 697 int i, bcm_unit; 698 699 BCMX_L2_INIT_CHECK; 700 701 BCMX_PARAM_NULL_CHECK(age_seconds); 702 703 BCMX_UNIT_ITER(bcm_unit, i) { 704 rv = bcm_l2_age_timer_get(bcm_unit, age_seconds); 705 if (BCMX_L2_GET_IS_VALID(bcm_unit, rv)) { 706 return rv; 707 } 708 } 709 710 return BCM_E_UNAVAIL; 711 } 712 713 714 /* 715 * Function: 716 * bcmx_l2_addr_freeze 717 */ 718 719 int 720 bcmx_l2_addr_freeze(void) 721 { 722 int rv = BCM_E_UNAVAIL, tmp_rv; 723 int i, bcm_unit; 724 725 BCMX_L2_INIT_CHECK; 726 727 BCMX_UNIT_ITER(bcm_unit, i) { 728 tmp_rv = bcm_l2_addr_freeze(bcm_unit); 729 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 730 } 731 732 return rv; 733 } 734 735 736 /* 737 * Function: 738 * bcmx_l2_addr_thaw 739 */ 740 741 int 742 bcmx_l2_addr_thaw(void) 743 { 744 int rv = BCM_E_UNAVAIL, tmp_rv; 745 int i, bcm_unit; 746 747 BCMX_L2_INIT_CHECK; 748 749 BCMX_UNIT_ITER(bcm_unit, i) { 750 tmp_rv = bcm_l2_addr_thaw(bcm_unit); 751 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 752 } 753 754 return rv; 755 } 756 757 758 /* 759 * Function: 760 * bcmx_l2_conflict_get 761 * Notes: 762 * Returns data from first successful call. 763 */ 764 765 int 766 bcmx_l2_conflict_get(bcmx_l2_addr_t *addr, 767 bcmx_l2_addr_t *cf_array, 768 int cf_max, 769 int *cf_count) 770 { 771 int rv = BCM_E_UNAVAIL, tmp_rv; 772 int i, bcm_unit; 773 bcm_l2_addr_t bcm_addr; 774 bcm_l2_addr_t *bcm_cf_ptr, *bcm_cf_base; 775 int tmp_size; 776 777 BCMX_L2_INIT_CHECK; 778 779 BCMX_PARAM_NULL_CHECK(addr); 780 BCMX_PARAM_NULL_CHECK(cf_count); 781 BCMX_PARAM_ARRAY_NULL_CHECK(cf_max, cf_array); 782 783 tmp_size = sizeof(bcm_l2_addr_t) * cf_max; 784 bcm_cf_ptr = bcm_cf_base = sal_alloc(tmp_size, "bcmx_l2_conflict_get"); 785 if (bcm_cf_ptr == NULL) { 786 return BCM_E_MEMORY; 787 } 788 sal_memset(bcm_cf_ptr, 0, tmp_size); 789 790 BCMX_UNIT_ITER(bcm_unit, i) { 791 /* Convert L2 address to bcm type */ 792 tmp_rv = bcmx_l2_addr_to_bcm(bcm_unit, &bcm_addr, addr, NULL); 793 if (BCM_FAILURE(tmp_rv)) { 794 continue; 795 } 796 797 /* 798 * On first successful call, convert data to bcmx type 799 * and return information from the unit 800 */ 801 tmp_rv = bcm_l2_conflict_get(bcm_unit, &bcm_addr, bcm_cf_ptr, 802 cf_max, cf_count); 803 if (BCMX_L2_GET_IS_VALID(bcm_unit, tmp_rv)) { 804 rv = tmp_rv; 805 if (BCM_SUCCESS(tmp_rv)) { 806 for (i = 0; i < *cf_count; i++, cf_array++, bcm_cf_ptr++) { 807 bcmx_l2_addr_from_bcm(cf_array, NULL, bcm_cf_ptr); 808 cf_array->bcm_unit = bcm_unit; /* Set unit */ 809 } 810 break; 811 } 812 } 813 } 814 815 sal_free(bcm_cf_base); 816 return rv; 817 } 818 819 /* 820 * Function: 821 * bcmx_l2_tunnel_add 822 * Purpose: 823 * Add a (MAC, VLAN) for tunnel/MPLS processing, frames 824 * destined to (MAC, VLAN) is subjected to TUNNEL/MPLS processing. 825 * Parameters: 826 * mac - MAC address 827 * vlan - VLAN ID 828 */ 829 830 int 831 bcmx_l2_tunnel_add(bcm_mac_t mac, bcm_vlan_t vlan) 832 { 833 int rv = BCM_E_UNAVAIL, tmp_rv; 834 int i, bcm_unit; 835 836 BCMX_L2_INIT_CHECK; 837 838 BCMX_UNIT_ITER(bcm_unit, i) { 839 tmp_rv = bcm_l2_tunnel_add(bcm_unit, mac, vlan); 840 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 841 } 842 843 return rv; 844 } 845 846 /* 847 * Function: 848 * bcmx_l2_tunnel_delete 849 * Purpose: 850 * Remove a tunnel processing indicator for an L2 address 851 * Parameters: 852 * mac - MAC address 853 * vlan - VLAN ID 854 */ 855 856 int 857 bcmx_l2_tunnel_delete(bcm_mac_t mac, bcm_vlan_t vlan) 858 { 859 int rv = BCM_E_UNAVAIL, tmp_rv; 860 int i, bcm_unit; 861 862 BCMX_L2_INIT_CHECK; 863 864 BCMX_UNIT_ITER(bcm_unit, i) { 865 tmp_rv = bcm_l2_tunnel_delete(bcm_unit, mac, vlan); 866 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 867 } 868 869 return rv; 870 } 871 872 /* 873 * Function: 874 * bcmx_l2_tunnel_delete_all 875 * Purpose: 876 * Remove all tunnel processing indicating L2 addresses 877 * Parameters: 878 * None 879 */ 880 881 int 882 bcmx_l2_tunnel_delete_all(void) 883 { 884 int rv = BCM_E_UNAVAIL, tmp_rv; 885 int i, bcm_unit; 886 887 BCMX_L2_INIT_CHECK; 888 889 BCMX_UNIT_ITER(bcm_unit, i) { 890 tmp_rv = bcm_l2_tunnel_delete_all(bcm_unit); 891 BCM_IF_ERROR_RETURN(BCMX_L2_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 892 } 893 894 return rv; 895 } 896 897 898 /**************************************************************** 899 * 900 * Convert L2 data types between BCM and BCMX 901 * 902 * Information is lost because the bcm_l2_addr only contains 903 * the block bitmap on the local unit. 904 * 905 * The bcm_unit is used to determine which block ports to check 906 */ 907 908 int 909 bcmx_l2_addr_to_bcm(int bcm_unit, 910 bcm_l2_addr_t *dest, 911 bcmx_l2_addr_t *source, 912 bcmx_lplist_t *port_block) 913 { 914 BCMX_L2_INIT_CHECK; 915 916 return _bcmx_l2_addr_to_bcm(bcm_unit, dest, source, port_block); 917 } 918 919 int 920 bcmx_l2_addr_from_bcm(bcmx_l2_addr_t *dest, 921 bcmx_lplist_t *port_block, 922 bcm_l2_addr_t *source) 923 { 924 BCMX_L2_INIT_CHECK; 925 926 return _bcmx_l2_addr_from_bcm(dest, port_block, source); 927 } 928 929 930 /* 931 * Function: 932 * bcmx_l2_learn_limit_set 933 * Purpose: 934 * Set the L2 MAC learning limit 935 * Parameters: 936 * limit - BCMX learn limit control info structure 937 * Return: 938 * BCM_E_NONE Success 939 * BCM_E_XXX Fail 940 */ 941 int 942 bcmx_l2_learn_limit_set(bcmx_l2_learn_limit_t *limit) 943 { 944 int rv = BCM_E_UNAVAIL, tmp_rv; 945 int i, bcm_unit; 946 bcm_l2_learn_limit_t bcm_l2; 947 948 949 BCMX_L2_INIT_CHECK; 950 951 BCMX_PARAM_NULL_CHECK(limit); 952 953 BCM_IF_ERROR_RETURN(_bcmx_l2_learn_limit_to_bcm(&bcm_l2, &bcm_unit, 954 limit)); 955 956 /* This is for a specific unit/port */ 957 if (bcm_unit >= 0) { 958 tmp_rv = bcm_l2_learn_limit_set(bcm_unit, &bcm_l2); 959 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 960 } else { 961 /* Do it for all units */ 962 BCMX_UNIT_ITER(bcm_unit, i) { 963 tmp_rv = bcm_l2_learn_limit_set(bcm_unit, &bcm_l2); 964 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 965 } 966 } 967 968 return rv; 969 } 970 971 972 /* 973 * Function: 974 * bcmx_l2_learn_limit_get 975 * Purpose: 976 * Get the L2 MAC learning limit 977 * Parameters: 978 * limit - BCMX learn limit control info structure 979 * Return: 980 * BCM_E_NONE Success 981 * BCM_E_XXX Fail 982 * Notes: 983 * Returns on first successful find 984 */ 985 int 986 bcmx_l2_learn_limit_get(bcmx_l2_learn_limit_t *limit) 987 { 988 int rv = BCM_E_UNAVAIL; 989 int i, bcm_unit; 990 bcm_l2_learn_limit_t bcm_l2; 991 992 BCMX_L2_INIT_CHECK; 993 994 BCMX_PARAM_NULL_CHECK(limit); 995 996 BCM_IF_ERROR_RETURN(_bcmx_l2_learn_limit_to_bcm(&bcm_l2, &bcm_unit, 997 limit)); 998 999 /* This is for a specific unit/port */ 1000 if (bcm_unit >= 0) { 1001 rv = bcm_l2_learn_limit_get(bcm_unit, &bcm_l2); 1002 } else { 1003 bcm_l2_learn_limit_t bcm_l2_orig; 1004 1005 bcm_l2_orig = bcm_l2; 1006 1007 BCMX_UNIT_ITER(bcm_unit, i) { 1008 rv = bcm_l2_learn_limit_get(bcm_unit, &bcm_l2); 1009 1010 if (BCMX_L2_GET_IS_VALID(bcm_unit, rv)) { 1011 break; 1012 } 1013 bcm_l2 = bcm_l2_orig; 1014 } 1015 } 1016 1017 if (BCM_SUCCESS(rv)) { 1018 rv = _bcmx_l2_learn_limit_from_bcm(limit, &bcm_l2, bcm_unit); 1019 } 1020 1021 return rv; 1022 } 1023 1024 1025 /* 1026 * Function: 1027 * bcmx_l2_learn_class_set 1028 */ 1029 int 1030 bcmx_l2_learn_class_set(int lclass, int lclass_prio, uint32 flags) 1031 { 1032 int rv = BCM_E_UNAVAIL, tmp_rv; 1033 int i, bcm_unit; 1034 1035 BCMX_L2_INIT_CHECK; 1036 1037 BCMX_UNIT_ITER(bcm_unit, i) { 1038 tmp_rv = bcm_l2_learn_class_set(bcm_unit, lclass, lclass_prio, flags); 1039 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 1040 } 1041 1042 return rv; 1043 } 1044 1045 /* 1046 * Function: 1047 * bcmx_l2_learn_class_get 1048 */ 1049 int 1050 bcmx_l2_learn_class_get(int lclass, int *lclass_prio, uint32 *flags) 1051 { 1052 int rv; 1053 int i, bcm_unit; 1054 1055 BCMX_L2_INIT_CHECK; 1056 1057 BCMX_PARAM_NULL_CHECK(lclass_prio); 1058 BCMX_PARAM_NULL_CHECK(flags); 1059 1060 BCMX_UNIT_ITER(bcm_unit, i) { 1061 rv = bcm_l2_learn_class_get(bcm_unit, lclass, lclass_prio, flags); 1062 if (BCMX_L2_GET_IS_VALID(bcm_unit, rv)) { 1063 return rv; 1064 } 1065 } 1066 1067 return BCM_E_UNAVAIL; 1068 } 1069 1070 /* 1071 * Function: 1072 * bcmx_l2_learn_port_class_set 1073 * Notes: 1074 * The port is globally significant, 1075 * so this must be set for all units. 1076 */ 1077 int 1078 bcmx_l2_learn_port_class_set(bcmx_lport_t port, int lclass) 1079 { 1080 int rv = BCM_E_UNAVAIL, tmp_rv; 1081 int i, bcm_unit; 1082 1083 BCMX_L2_INIT_CHECK; 1084 1085 BCMX_LPORT_CHECK(port); 1086 1087 BCMX_UNIT_ITER(bcm_unit, i) { 1088 tmp_rv = bcm_l2_learn_port_class_set(bcm_unit, port, lclass); 1089 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 1090 } 1091 1092 return rv; 1093 } 1094 1095 /* 1096 * Function: 1097 * bcmx_l2_learn_port_class_get 1098 */ 1099 int 1100 bcmx_l2_learn_port_class_get(bcmx_lport_t port, int *lclass) 1101 { 1102 int rv; 1103 int i, bcm_unit; 1104 1105 BCMX_L2_INIT_CHECK; 1106 1107 BCMX_LPORT_CHECK(port); 1108 BCMX_PARAM_NULL_CHECK(lclass); 1109 1110 BCMX_UNIT_ITER(bcm_unit, i) { 1111 rv = bcm_l2_learn_port_class_get(bcm_unit, port, lclass); 1112 if (BCMX_L2_GET_IS_VALID(bcm_unit, rv)) { 1113 return rv; 1114 } 1115 } 1116 1117 return BCM_E_UNAVAIL; 1118 } 1119 1120 1121 /* 1122 * Function: 1123 * bcmx_l2_replace 1124 */ 1125 int 1126 bcmx_l2_replace(uint32 flags, bcmx_l2_addr_t *match_addr, 1127 bcmx_lport_t new_port, bcm_trunk_t new_trunk) 1128 { 1129 int rv = BCM_E_UNAVAIL, tmp_rv; 1130 int i, bcm_unit; 1131 bcm_l2_addr_t bcm_l2; 1132 bcm_module_t modid; 1133 bcm_port_t modport; 1134 bcmx_lport_t cpu_lport; 1135 int match_local_cpu; 1136 int new_local_cpu; 1137 bcm_module_t new_bcm_module; 1138 bcm_port_t new_bcm_port; 1139 1140 BCMX_L2_INIT_CHECK; 1141 1142 BCMX_PARAM_NULL_CHECK(match_addr); 1143 1144 match_local_cpu = (match_addr->lport == BCMX_LPORT_LOCAL_CPU) ? 1145 TRUE : FALSE; 1146 1147 if (BCM_FAILURE(_bcmx_l2_addr_to_bcm(0, &bcm_l2, match_addr, NULL))) { 1148 LOG_WARN(BSL_LS_BCMX_COMMON, 1149 (BSL_META("BCMX L2 WARN: Failed to convert " 1150 "L2 address to BCM\n"))); 1151 return BCM_E_PARAM; 1152 } 1153 1154 new_local_cpu = (new_port == BCMX_LPORT_LOCAL_CPU) ? TRUE : FALSE; 1155 1156 if (!new_local_cpu) { 1157 if (flags & BCM_L2_REPLACE_NEW_TRUNK) { 1158 if (!BCM_GPORT_IS_TRUNK(new_port)) { 1159 BCM_GPORT_TRUNK_SET(new_bcm_port, new_trunk); 1160 } 1161 } 1162 else { 1163 BCM_IF_ERROR_RETURN 1164 (_bcmx_dest_to_modid_port(new_port, 1165 &new_bcm_module, &new_bcm_port, 1166 BCMX_DEST_CONVERT_DEFAULT)); 1167 } 1168 } 1169 1170 BCMX_UNIT_ITER(bcm_unit, i) { 1171 if (match_local_cpu) { 1172 cpu_lport = BCMX_LPORT_LOCAL_CPU_GET(bcm_unit); 1173 1174 if (BCM_FAILURE 1175 (_bcmx_dest_to_modid_port(cpu_lport, 1176 &modid, &modport, 1177 BCMX_DEST_CONVERT_DEFAULT))) { 1178 continue; 1179 } 1180 bcm_l2.modid = (int)modid; 1181 bcm_l2.port = (int)modport; 1182 } 1183 1184 if (new_local_cpu) { 1185 cpu_lport = BCMX_LPORT_LOCAL_CPU_GET(bcm_unit); 1186 if (BCM_FAILURE 1187 (_bcmx_dest_to_modid_port(cpu_lport, 1188 &new_bcm_module, &new_bcm_port, 1189 BCMX_DEST_CONVERT_DEFAULT))) { 1190 /* Skip if can't find local CPU port */ 1191 continue; 1192 } 1193 } 1194 1195 tmp_rv = bcm_l2_replace(bcm_unit, flags, &bcm_l2, 1196 new_bcm_module, new_bcm_port, new_trunk); 1197 1198 BCM_IF_ERROR_RETURN(BCMX_L2_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 1199 } 1200 1201 return rv; 1202 }