mcast.c (11920B)
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/mcast.c 8 * Purpose: BCMX L2 Multicasting APIs 9 */ 10 11 #include <sal/core/libc.h> 12 13 #include <bcm/types.h> 14 15 #include <bcm_int/control.h> 16 17 #include <bcmx/mcast.h> 18 #include <bcmx/lport.h> 19 #include <bcmx/bcmx.h> 20 #include <bcmx/lplist.h> 21 22 #include "bcmx_int.h" 23 24 #define BCMX_MCAST_INIT_CHECK BCMX_READY_CHECK 25 26 #define BCMX_MCAST_ERROR_CHECK(_unit, _check, _rv) \ 27 BCMX_ERROR_CHECK(_unit, _check, _rv) 28 29 #define BCMX_MCAST_SET_ERROR_CHECK(_unit, _check, _rv) \ 30 BCMX_SET_ERROR_CHECK(_unit, _check, _rv) 31 32 #define BCMX_MCAST_DELETE_ERROR_CHECK(_unit, _check, _rv) \ 33 BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv) 34 35 #define BCMX_MCAST_GET_IS_VALID(_unit, _rv) \ 36 BCMX_ERROR_IS_VALID(_unit, _rv) 37 38 39 /* 40 * Function: 41 * bcmx_mcast_addr_t_init 42 */ 43 44 void 45 bcmx_mcast_addr_t_init(bcmx_mcast_addr_t *mcaddr, 46 bcm_mac_t mac, 47 bcm_vlan_t vid) 48 { 49 sal_memset(mcaddr, 0, sizeof(*mcaddr)); 50 sal_memcpy(mcaddr->mac, mac, sizeof(mcaddr->mac)); 51 mcaddr->vid = vid; 52 bcmx_lplist_init(&mcaddr->ports, 0, 0); 53 bcmx_lplist_init(&mcaddr->untag_ports, 0, 0); 54 } 55 56 void 57 bcmx_mcast_addr_t_free(bcmx_mcast_addr_t * mcaddr) 58 { 59 bcmx_lplist_free(&mcaddr->ports); 60 bcmx_lplist_free(&mcaddr->untag_ports); 61 } 62 63 64 /* 65 * Function: 66 * bcmx_mcast_init 67 */ 68 69 int 70 bcmx_mcast_init(void) 71 { 72 int rv = BCM_E_UNAVAIL, tmp_rv; 73 int i, bcm_unit; 74 75 BCMX_MCAST_INIT_CHECK; 76 77 BCMX_UNIT_ITER(bcm_unit, i) { 78 tmp_rv = bcm_mcast_init(bcm_unit); 79 BCM_IF_ERROR_RETURN(BCMX_MCAST_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 80 } 81 82 return rv; 83 } 84 85 86 /* 87 * Function: 88 * bcmx_mcast_addr_add 89 * Returns: 90 * BCM_E_CONFIG if conflict is found in existing chips 91 */ 92 93 int 94 bcmx_mcast_addr_add(bcmx_mcast_addr_t *mcaddr) 95 { 96 int rv = BCM_E_UNAVAIL, tmp_rv; 97 int i, bcm_unit, mcindex, port; 98 bcm_mcast_addr_t bcm_mca, bcm_mca2; 99 bcmx_lport_t lport; 100 bcm_pbmp_t pbmp; 101 bcm_unit_bmp_t unit_bmp; 102 int lport_unit; 103 bcm_port_t lport_port; 104 int mcindex_conflict = FALSE; 105 106 BCMX_MCAST_INIT_CHECK; 107 108 BCMX_PARAM_NULL_CHECK(mcaddr); 109 110 /* 111 * First, look to see if the entry exists in any chip. Set 112 * mcindex if so. Record chips which should not have entry 113 * added. 114 */ 115 mcindex = -1; 116 BCM_UNIT_BMP_CLEAR(unit_bmp); 117 BCMX_UNIT_ITER(bcm_unit, i) { 118 tmp_rv = 119 bcm_mcast_port_get(bcm_unit, mcaddr->mac, mcaddr->vid, &bcm_mca); 120 if (tmp_rv == BCM_E_NONE) { /* Found a chip holding entry */ 121 BCM_UNIT_BMP_ADD(unit_bmp, bcm_unit); 122 if (mcindex < 0) { 123 mcindex = bcm_mca.l2mc_index; 124 } else if (mcindex != bcm_mca.l2mc_index) { 125 /* 126 * Indicate to caller that current mc indexes disagree 127 * between different chips. 128 */ 129 mcindex_conflict = TRUE; 130 } 131 } 132 133 } 134 135 bcm_mcast_addr_t_init(&bcm_mca, mcaddr->mac, mcaddr->vid); 136 bcm_mca.cos_dst = mcaddr->cos_dst; 137 bcm_mca.l2mc_index = mcindex; 138 139 /* 140 * Add the mcast entry to any non-fabric switches that 141 * do not already have it 142 */ 143 BCMX_UNIT_ITER(bcm_unit, i) { 144 if (BCM_IS_FABRIC(bcm_unit)) { 145 continue; 146 } 147 if (BCM_UNIT_BMP_TEST(unit_bmp, bcm_unit)) { /* Already present */ 148 continue; 149 } 150 BCMX_LPLIST_TO_PBMP(mcaddr->ports, bcm_unit, bcm_mca.pbmp); 151 BCMX_LPLIST_TO_PBMP(mcaddr->untag_ports, bcm_unit, bcm_mca.ubmp); 152 /* add stack and higig ports */ 153 BCMX_FOREACH_QUALIFIED_LPORT(lport, 154 BCMX_PORT_F_HG| 155 BCMX_PORT_F_STACK_INT| 156 BCMX_PORT_F_STACK_EXT) { 157 if (BCM_SUCCESS(_bcmx_dest_to_unit_port(lport, 158 &lport_unit, &lport_port, 159 BCMX_DEST_CONVERT_NON_GPORT))) { 160 if (lport_unit == bcm_unit) { 161 BCM_PBMP_PORT_ADD(bcm_mca.pbmp, lport_port); 162 } 163 } 164 } 165 if (mcindex < 0) { /* get allocated mcast index */ 166 tmp_rv = bcm_mcast_addr_add(bcm_unit, &bcm_mca); 167 if (tmp_rv >= 0) { 168 bcm_mca2.l2mc_index = -1; 169 (void)bcm_mcast_port_get(bcm_unit, mcaddr->mac, mcaddr->vid, 170 &bcm_mca2); 171 mcindex = bcm_mca2.l2mc_index; 172 bcm_mca.l2mc_index = mcindex; 173 } 174 } else { 175 tmp_rv = bcm_mcast_addr_add_w_l2mcindex(bcm_unit, &bcm_mca); 176 } 177 BCM_IF_ERROR_RETURN(BCMX_MCAST_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 178 } 179 180 /* 181 * Add the mcast entry to fabric switches 182 */ 183 BCMX_UNIT_ITER(bcm_unit, i) { 184 if (!BCM_IS_FABRIC(bcm_unit)) { 185 continue; 186 } 187 BCM_PBMP_CLEAR(pbmp); 188 BCMX_FOREACH_QUALIFIED_LPORT(lport, 189 BCMX_PORT_F_HG| 190 BCMX_PORT_F_STACK_INT| 191 BCMX_PORT_F_STACK_EXT) { 192 if (BCM_SUCCESS(_bcmx_dest_to_unit_port(lport, 193 &lport_unit, &lport_port, 194 BCMX_DEST_CONVERT_NON_GPORT))) { 195 if (lport_unit == bcm_unit) { 196 BCM_PBMP_PORT_ADD(pbmp, lport_port); 197 } 198 } 199 } 200 BCM_PBMP_ITER(pbmp, port) { 201 tmp_rv = bcm_mcast_bitmap_set(bcm_unit, mcindex, port, pbmp); 202 BCM_IF_ERROR_RETURN(BCMX_MCAST_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 203 } 204 } 205 206 if (BCM_SUCCESS(rv) && mcindex_conflict) { 207 rv = BCM_E_CONFIG; 208 } 209 210 return rv; 211 } 212 213 214 /* 215 * Function: 216 * bcmx_mcast_addr_remove 217 */ 218 219 int 220 bcmx_mcast_addr_remove(bcm_mac_t mac, bcm_vlan_t vid) 221 { 222 int rv = BCM_E_UNAVAIL, tmp_rv; 223 int i, bcm_unit, mcindex; 224 bcm_mcast_addr_t bcm_mca; 225 bcmx_lport_t lport; 226 bcm_pbmp_t empty; 227 bcm_port_t bcm_port; 228 229 BCMX_MCAST_INIT_CHECK; 230 231 mcindex = -1; 232 BCMX_UNIT_ITER(bcm_unit, i) { 233 if (BCM_IS_FABRIC(bcm_unit)) { 234 continue; 235 } 236 if (mcindex < 0) { /* get mcast index if available */ 237 tmp_rv = bcm_mcast_port_get(bcm_unit, mac, vid, &bcm_mca); 238 if (tmp_rv >= 0) { 239 mcindex = bcm_mca.l2mc_index; 240 } 241 } 242 tmp_rv = bcm_mcast_addr_remove(bcm_unit, mac, vid); 243 BCM_IF_ERROR_RETURN(BCMX_MCAST_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 244 } 245 246 if (mcindex < 0) { 247 return rv; 248 } 249 250 /* 251 * Delete mcast index from fabric 252 */ 253 BCM_PBMP_CLEAR(empty); 254 BCMX_FOREACH_QUALIFIED_LPORT(lport, 255 BCMX_PORT_F_HG| 256 BCMX_PORT_F_STACK_INT| 257 BCMX_PORT_F_STACK_EXT) { 258 if (BCM_SUCCESS(_bcmx_dest_to_unit_port(lport, 259 &bcm_unit, &bcm_port, 260 BCMX_DEST_CONVERT_DEFAULT))) { 261 if (!BCM_IS_FABRIC(bcm_unit)) { 262 continue; 263 } 264 tmp_rv = bcm_mcast_bitmap_set(bcm_unit, mcindex, bcm_port, 265 empty); 266 BCM_IF_ERROR_RETURN 267 (BCMX_MCAST_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 268 } 269 } 270 271 return rv; 272 } 273 274 275 /* 276 * Function: 277 * bcmx_mcast_port_get 278 */ 279 280 int 281 bcmx_mcast_port_get(bcm_mac_t mac, 282 bcm_vlan_t vid, 283 bcmx_mcast_addr_t *mcaddr) 284 { 285 int rv = BCM_E_UNAVAIL, tmp_rv, i, bcm_unit; 286 bcm_mcast_addr_t bcm_mca; 287 288 BCMX_MCAST_INIT_CHECK; 289 290 BCMX_PARAM_NULL_CHECK(mcaddr); 291 292 bcmx_mcast_addr_t_init(mcaddr, mac, vid); 293 294 BCMX_UNIT_ITER(bcm_unit, i) { 295 tmp_rv = bcm_mcast_port_get(bcm_unit, mac, vid, &bcm_mca); 296 297 if (BCMX_MCAST_GET_IS_VALID(bcm_unit, tmp_rv)) { 298 rv = tmp_rv; 299 if (BCM_SUCCESS(tmp_rv)) { 300 mcaddr->cos_dst = bcm_mca.cos_dst; 301 mcaddr->l2mc_index = bcm_mca.l2mc_index; 302 BCMX_LPLIST_PBMP_ADD(&mcaddr->ports, bcm_unit, bcm_mca.pbmp); 303 BCMX_LPLIST_PBMP_ADD(&mcaddr->untag_ports, bcm_unit, bcm_mca.ubmp); 304 } else { 305 break; 306 } 307 } 308 } 309 310 return rv; 311 } 312 313 314 /* 315 * Function: 316 * bcmx_mcast_join 317 */ 318 319 int 320 bcmx_mcast_join(bcm_mac_t mac, 321 bcm_vlan_t vid, 322 bcmx_lport_t port, 323 bcmx_mcast_addr_t *mcaddr, 324 bcmx_lplist_t *allrtr) 325 { 326 int rv = BCM_E_UNAVAIL; 327 int bcm_unit; 328 bcm_mcast_addr_t bcm_mca; 329 bcm_pbmp_t pbmp; 330 bcm_port_t bcm_port; 331 332 BCMX_MCAST_INIT_CHECK; 333 334 BCM_IF_ERROR_RETURN 335 (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port, 336 BCMX_DEST_CONVERT_DEFAULT)); 337 338 rv = bcm_mcast_join(bcm_unit, mac, vid, 339 bcm_port, 340 mcaddr ? &bcm_mca : NULL, 341 allrtr ? &pbmp : NULL); 342 if (BCM_SUCCESS(rv)) { 343 if (mcaddr) { 344 bcmx_mcast_addr_t_init(mcaddr, mac, vid); 345 mcaddr->cos_dst = bcm_mca.cos_dst; 346 mcaddr->l2mc_index = bcm_mca.l2mc_index; 347 BCMX_LPLIST_PBMP_ADD(&mcaddr->ports, bcm_unit, bcm_mca.pbmp); 348 BCMX_LPLIST_PBMP_ADD(&mcaddr->untag_ports, bcm_unit, bcm_mca.ubmp); 349 } 350 if (allrtr) { 351 BCMX_LPLIST_PBMP_ADD(allrtr, bcm_unit, pbmp); 352 } 353 } 354 355 return rv; 356 } 357 358 359 /* 360 * Function: 361 * bcmx_mcast_leave 362 */ 363 364 int 365 bcmx_mcast_leave(bcm_mac_t mac, 366 bcm_vlan_t vid, 367 bcmx_lport_t port) 368 { 369 int bcm_unit; 370 bcm_port_t bcm_port; 371 372 BCMX_MCAST_INIT_CHECK; 373 374 BCM_IF_ERROR_RETURN 375 (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port, 376 BCMX_DEST_CONVERT_DEFAULT)); 377 378 return bcm_mcast_leave(bcm_unit, mac, vid, bcm_port); 379 } 380 381 382 /* 383 * Function: 384 * bcmx_mcast_port_remove 385 */ 386 387 int 388 bcmx_mcast_port_remove(bcmx_mcast_addr_t *mcaddr) 389 { 390 int rv = BCM_E_UNAVAIL, tmp_rv; 391 int i, bcm_unit; 392 bcm_mcast_addr_t bcm_mca; 393 394 BCMX_MCAST_INIT_CHECK; 395 396 BCMX_PARAM_NULL_CHECK(mcaddr); 397 398 bcm_mcast_addr_t_init(&bcm_mca, mcaddr->mac, mcaddr->vid); 399 bcm_mca.cos_dst = mcaddr->cos_dst; 400 bcm_mca.l2mc_index = mcaddr->l2mc_index; 401 402 BCMX_UNIT_ITER(bcm_unit, i) { 403 BCMX_LPLIST_TO_PBMP(mcaddr->ports, bcm_unit, bcm_mca.pbmp); 404 BCMX_LPLIST_TO_PBMP(mcaddr->untag_ports, bcm_unit, bcm_mca.ubmp); 405 if (BCM_PBMP_IS_NULL(bcm_mca.pbmp)) { 406 continue; 407 } 408 tmp_rv = bcm_mcast_port_remove(bcm_unit, &bcm_mca); 409 BCM_IF_ERROR_RETURN 410 (BCMX_MCAST_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 411 } 412 413 return rv; 414 } 415 416 417 /* 418 * Function: 419 * bcmx_mcast_port_add 420 */ 421 422 int 423 bcmx_mcast_port_add(bcmx_mcast_addr_t *mcaddr) 424 { 425 int rv = BCM_E_UNAVAIL, tmp_rv; 426 int i, bcm_unit; 427 bcm_mcast_addr_t bcm_mca; 428 429 BCMX_MCAST_INIT_CHECK; 430 431 BCMX_PARAM_NULL_CHECK(mcaddr); 432 433 bcm_mcast_addr_t_init(&bcm_mca, mcaddr->mac, mcaddr->vid); 434 bcm_mca.cos_dst = mcaddr->cos_dst; 435 bcm_mca.l2mc_index = mcaddr->l2mc_index; 436 437 BCMX_UNIT_ITER(bcm_unit, i) { 438 BCMX_LPLIST_TO_PBMP(mcaddr->ports, bcm_unit, bcm_mca.pbmp); 439 BCMX_LPLIST_TO_PBMP(mcaddr->untag_ports, bcm_unit, bcm_mca.ubmp); 440 if (BCM_PBMP_IS_NULL(bcm_mca.pbmp)) { 441 continue; 442 } 443 tmp_rv = bcm_mcast_port_add(bcm_unit, &bcm_mca); 444 BCM_IF_ERROR_RETURN(BCMX_MCAST_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 445 } 446 447 return rv; 448 }