openbcm

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

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 }