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

multicast.c (21524B)


      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/multicast.c
      8  * Purpose:     BCMX Multicast APIs
      9  */
     10 
     11 #include <shared/alloc.h>
     12 
     13 #include <bcm/types.h>
     14 
     15 #include <bcmx/lport.h>
     16 #include <bcmx/multicast.h>
     17 
     18 #include "bcmx_int.h"
     19 
     20 #define BCMX_MULTICAST_INIT_CHECK    BCMX_READY_CHECK
     21 
     22 #define BCMX_MULTICAST_ERROR_CHECK(_unit, _check, _rv)    \
     23     BCMX_ERROR_CHECK(_unit, _check, _rv)
     24 
     25 #define BCMX_MULTICAST_SET_ERROR_CHECK(_unit, _check, _rv)    \
     26     BCMX_SET_ERROR_CHECK(_unit, _check, _rv)
     27 
     28 #define BCMX_MULTICAST_DELETE_ERROR_CHECK(_unit, _check, _rv)    \
     29     BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv)
     30 
     31 #define BCMX_MULTICAST_GET_IS_VALID(_unit, _rv)    \
     32     BCMX_ERROR_IS_VALID(_unit, _rv)
     33 
     34 
     35 /*
     36  * Function:
     37  *     bcmx_multicast_init
     38  */
     39 int
     40 bcmx_multicast_init(void)
     41 {
     42     int  rv = BCM_E_UNAVAIL, tmp_rv;
     43     int  i, bcm_unit;
     44 
     45     BCMX_MULTICAST_INIT_CHECK;
     46 
     47     BCMX_UNIT_ITER(bcm_unit, i) {
     48         tmp_rv = bcm_multicast_init(bcm_unit);
     49         BCM_IF_ERROR_RETURN(BCMX_MULTICAST_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
     50     }
     51 
     52     return rv;
     53 }
     54 
     55 /*
     56  * Function:
     57  *     bcmx_multicast_detach
     58  */
     59 int
     60 bcmx_multicast_detach(void)
     61 {
     62     int  rv = BCM_E_UNAVAIL, tmp_rv;
     63     int  i, bcm_unit;
     64 
     65     BCMX_MULTICAST_INIT_CHECK;
     66 
     67     BCMX_UNIT_ITER(bcm_unit, i) {
     68         tmp_rv = bcm_multicast_detach(bcm_unit);
     69         BCM_IF_ERROR_RETURN(BCMX_MULTICAST_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
     70     }
     71 
     72     return rv;
     73 }
     74 
     75 /*
     76  * Function:
     77  *     bcmx_multicast_create
     78  * Notes:
     79  *     If group ID is not specified, the ID returned
     80  *     from the first successful 'create' is used for the remaining
     81  *     units.
     82  */
     83 int
     84 bcmx_multicast_create(uint32 flags, bcm_multicast_t *group)
     85 {
     86     int  rv = BCM_E_UNAVAIL, tmp_rv;
     87     int  i, bcm_unit;
     88 
     89     BCMX_MULTICAST_INIT_CHECK;
     90 
     91     BCMX_PARAM_NULL_CHECK(group);
     92 
     93     BCMX_UNIT_ITER(bcm_unit, i) {
     94 
     95         tmp_rv = bcm_multicast_create(bcm_unit, flags, group);
     96         BCM_IF_ERROR_RETURN
     97             (BCMX_MULTICAST_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
     98 
     99         /*
    100          * Use the ID from first successful 'create' if policer ID
    101          * is not specified.
    102          */
    103         if (!(flags & BCM_MULTICAST_WITH_ID)) {
    104             if (BCM_SUCCESS(tmp_rv)) {
    105                 flags |= BCM_MULTICAST_WITH_ID;
    106             }
    107         }
    108     }
    109 
    110     return rv;
    111 }
    112 
    113 /*
    114  * Function:
    115  *    bcmx_multicast_destroy
    116  */
    117 int
    118 bcmx_multicast_destroy(bcm_multicast_t group)
    119 {
    120     int  rv = BCM_E_UNAVAIL, tmp_rv;
    121     int  i, bcm_unit;
    122 
    123     BCMX_MULTICAST_INIT_CHECK;
    124 
    125     BCMX_UNIT_ITER(bcm_unit, i) {
    126         tmp_rv = bcm_multicast_destroy(bcm_unit, group);
    127         BCM_IF_ERROR_RETURN
    128             (BCMX_MULTICAST_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    129     }
    130 
    131     return rv;
    132 }
    133 
    134 /*
    135  * Function:
    136  *     bcmx_multicast_group_get
    137  * Purpose:
    138  *     Retrieve the flags associated with a multicast group.
    139  * Parameters:
    140  *     group - (IN) Multicast group ID
    141  *     flags - (OUT) BCM_MULTICAST_*
    142  * Returns:
    143  *     BCM_E_xxx
    144  */
    145 int
    146 bcmx_multicast_group_get(bcm_multicast_t group, uint32 *flags)
    147 {
    148     int  rv;
    149     int  i, bcm_unit;
    150 
    151     BCMX_MULTICAST_INIT_CHECK;
    152 
    153     BCMX_PARAM_NULL_CHECK(flags);
    154 
    155     BCMX_UNIT_ITER(bcm_unit, i) {
    156         rv = bcm_multicast_group_get(bcm_unit, group, flags);
    157         if (BCMX_MULTICAST_GET_IS_VALID(bcm_unit, rv)) {
    158             return rv;
    159         }
    160     }
    161 
    162     return BCM_E_UNAVAIL;
    163 }
    164      
    165 /*
    166  * Function:
    167  *     bcmx_multicast_l3_encap_get
    168  * Notes:
    169  *     Gport 'port' is a physical local port.
    170  */
    171 int
    172 bcmx_multicast_l3_encap_get(bcm_multicast_t group,
    173                             bcm_gport_t port, bcm_if_t intf, 
    174                             bcm_if_t *encap_id)
    175 {
    176     int         bcm_unit;
    177     bcm_port_t  bcm_port;
    178 
    179     BCMX_MULTICAST_INIT_CHECK;
    180 
    181     BCMX_PARAM_NULL_CHECK(encap_id);
    182 
    183     BCM_IF_ERROR_RETURN
    184         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    185                                  BCMX_DEST_CONVERT_DEFAULT));
    186 
    187     return bcm_multicast_l3_encap_get(bcm_unit, group, port, intf, encap_id);
    188 }
    189 
    190 /*
    191  * Function:
    192  *     bcmx_multicast_l2_encap_get
    193  * Notes:
    194  *     Gport 'port' is a physical local port.
    195  */
    196 int
    197 bcmx_multicast_l2_encap_get(bcm_multicast_t group, 
    198                             bcm_gport_t port, bcm_vlan_t vlan, 
    199                             bcm_if_t *encap_id)
    200 {
    201     int         bcm_unit;
    202     bcm_port_t  bcm_port;
    203 
    204     BCMX_MULTICAST_INIT_CHECK;
    205 
    206     BCMX_PARAM_NULL_CHECK(encap_id);
    207 
    208     BCM_IF_ERROR_RETURN
    209         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    210                                  BCMX_DEST_CONVERT_DEFAULT));
    211 
    212     return bcm_multicast_l2_encap_get(bcm_unit, group, port, vlan, encap_id);
    213 }
    214 
    215 /*
    216  * Function:
    217  *     bcmx_multicast_vpls_encap_get
    218  * Notes:
    219  *     Gport 'port' is a physical local port.
    220  */
    221 int
    222 bcmx_multicast_vpls_encap_get(bcm_multicast_t group, 
    223                               bcm_gport_t port, bcm_gport_t mpls_port_id, 
    224                               bcm_if_t *encap_id)
    225 {
    226     int         bcm_unit;
    227     bcm_port_t  bcm_port;
    228 
    229     BCMX_MULTICAST_INIT_CHECK;
    230 
    231     BCMX_PARAM_NULL_CHECK(encap_id);
    232 
    233     BCM_IF_ERROR_RETURN
    234         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    235                                  BCMX_DEST_CONVERT_DEFAULT));
    236 
    237     return bcm_multicast_vpls_encap_get(bcm_unit, group,
    238                                         port, mpls_port_id, encap_id);
    239 }
    240 
    241 /*
    242  * Function:
    243  *     bcmx_multicast_trill_encap_get
    244  * Notes:
    245  *     Gport 'port' is a physical local port.
    246  */
    247 int
    248 bcmx_multicast_trill_encap_get(bcm_multicast_t group, 
    249                                bcm_gport_t port, bcm_if_t intf, 
    250                                bcm_if_t *encap_id)
    251 {
    252     int         bcm_unit;
    253     bcm_port_t  bcm_port;
    254 
    255     BCMX_MULTICAST_INIT_CHECK;
    256 
    257     BCMX_PARAM_NULL_CHECK(encap_id);
    258 
    259     BCM_IF_ERROR_RETURN
    260         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    261                                  BCMX_DEST_CONVERT_DEFAULT));
    262 
    263     return bcm_multicast_trill_encap_get(bcm_unit, group,
    264                                          port, intf, encap_id);
    265 }
    266 
    267 /*
    268  * Function:
    269  *     bcmx_multicast_subport_encap_get
    270  * Notes:
    271  *     Gport 'port' is a physical local port.
    272  */
    273 int
    274 bcmx_multicast_subport_encap_get(bcm_multicast_t group, 
    275                                  bcm_gport_t port, bcm_gport_t subport, 
    276                                  bcm_if_t *encap_id)
    277 {
    278     int         bcm_unit;
    279     bcm_port_t  bcm_port;
    280 
    281     BCMX_MULTICAST_INIT_CHECK;
    282 
    283     BCMX_PARAM_NULL_CHECK(encap_id);
    284 
    285     BCM_IF_ERROR_RETURN
    286         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    287                                  BCMX_DEST_CONVERT_DEFAULT));
    288 
    289     return bcm_multicast_subport_encap_get(bcm_unit, group,
    290                                            port, subport, encap_id);
    291 }
    292 
    293 /*
    294  * Function:
    295  *     bcmx_multicast_mim_encap_get
    296  * Notes:
    297  *     Gport 'port' can be a physical local port or a virtual port.
    298  *     If 'port' is a physical port, apply to device where port resides.
    299  *     If 'port' is a virtual port, apply to all devices.
    300  */
    301 int
    302 bcmx_multicast_mim_encap_get(bcm_multicast_t group,
    303                              bcm_gport_t port, bcm_gport_t mim_port_id,
    304                              bcm_if_t *encap_id)
    305 {
    306     int         rv;
    307     int         i;
    308     int         bcm_unit;
    309     bcm_port_t  bcm_port;
    310 
    311     BCMX_MULTICAST_INIT_CHECK;
    312 
    313     BCMX_PARAM_NULL_CHECK(encap_id);
    314 
    315     BCMX_LPORT_CHECK(port);
    316 
    317     /* Physical port */
    318     if (BCMX_LPORT_IS_PHYSICAL(port)) {
    319         BCM_IF_ERROR_RETURN
    320             (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    321                                      BCMX_DEST_CONVERT_DEFAULT));
    322         return bcm_multicast_mim_encap_get(bcm_unit, group,
    323                                            port, mim_port_id, encap_id);
    324     }
    325 
    326     /* Virtual port */
    327     BCMX_UNIT_ITER(bcm_unit, i) {
    328         rv = bcm_multicast_mim_encap_get(bcm_unit, group,
    329                                          port, mim_port_id, encap_id);
    330         if (BCMX_MULTICAST_GET_IS_VALID(bcm_unit, rv)) {
    331             return rv;
    332         }
    333     }
    334 
    335     return BCM_E_UNAVAIL;
    336 }
    337 
    338 /*
    339  * Function:
    340  *     bcmx_multicast_wlan_encap_get
    341  * Notes:
    342  *     Gport 'port' can be a physical local port or a virtual port.
    343  *     If 'port' is a physical port, apply to device where port resides.
    344  *     If 'port' is a virtual port, apply to all devices.
    345  */
    346 int
    347 bcmx_multicast_wlan_encap_get(bcm_multicast_t group,
    348                               bcm_gport_t port, bcm_gport_t wlan_port_id,
    349                               bcm_if_t *encap_id)
    350 {
    351     int         rv;
    352     int         i, bcm_unit;
    353     bcm_port_t  bcm_port;
    354 
    355     BCMX_MULTICAST_INIT_CHECK;
    356 
    357     BCMX_PARAM_NULL_CHECK(encap_id);
    358 
    359     BCMX_LPORT_CHECK(port);
    360 
    361     /* Physical port */
    362     if (BCMX_LPORT_IS_PHYSICAL(port)) {
    363         BCM_IF_ERROR_RETURN
    364             (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    365                                      BCMX_DEST_CONVERT_DEFAULT));
    366         return bcm_multicast_wlan_encap_get(bcm_unit, group,
    367                                             port, wlan_port_id, encap_id);
    368     }
    369 
    370     /* Virtual port */
    371     BCMX_UNIT_ITER(bcm_unit, i) {
    372         rv = bcm_multicast_wlan_encap_get(bcm_unit, group,
    373                                           port, wlan_port_id, encap_id);
    374         if (BCMX_MULTICAST_GET_IS_VALID(bcm_unit, rv)) {
    375             return rv;
    376         }
    377     }
    378 
    379     return BCM_E_UNAVAIL;
    380 }
    381 
    382 /*
    383  * Function:
    384  *     bcmx_multicast_vlan_encap_get
    385  * Notes:
    386  *     Gport 'port' can be a physical local port or a virtual port.
    387  *     If 'port' is a physical port, apply to device where port resides.
    388  *     If 'port' is a virtual port, apply to all devices.
    389  */
    390 int
    391 bcmx_multicast_vlan_encap_get(bcm_multicast_t group,
    392                               bcm_gport_t port, bcm_gport_t vlan_port_id,
    393                               bcm_if_t *encap_id)
    394 {
    395     int         rv;
    396     int         i, bcm_unit;
    397     bcm_port_t  bcm_port;
    398 
    399     BCMX_MULTICAST_INIT_CHECK;
    400 
    401     BCMX_PARAM_NULL_CHECK(encap_id);
    402 
    403     BCMX_LPORT_CHECK(port);
    404 
    405     /* Physical port */
    406     if (BCMX_LPORT_IS_PHYSICAL(port)) {
    407         BCM_IF_ERROR_RETURN
    408             (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    409                                      BCMX_DEST_CONVERT_DEFAULT));
    410         return bcm_multicast_vlan_encap_get(bcm_unit, group,
    411                                             port, vlan_port_id, encap_id);
    412     }
    413 
    414     /* Virtual port */
    415     BCMX_UNIT_ITER(bcm_unit, i) {
    416         rv = bcm_multicast_vlan_encap_get(bcm_unit, group,
    417                                           port, vlan_port_id, encap_id);
    418         if (BCMX_MULTICAST_GET_IS_VALID(bcm_unit, rv)) {
    419             return rv;
    420         }
    421     }
    422 
    423     return BCM_E_UNAVAIL;
    424 }
    425 
    426 /*
    427  * Function:
    428  *     bcmx_multicast_niv_encap_get
    429  * Notes:
    430  *     Gport 'port' can be a physical local port or a virtual port.
    431  *     If 'port' is a physical port, apply to device where port resides.
    432  *     If 'port' is a virtual port, apply to all devices.
    433  */
    434 int
    435 bcmx_multicast_niv_encap_get(bcm_multicast_t group, bcm_gport_t port, 
    436                              bcm_gport_t niv_port_id, bcm_if_t *encap_id)
    437 {
    438     int         rv;
    439     int         i, bcm_unit;
    440     bcm_port_t  bcm_port;
    441 
    442     BCMX_MULTICAST_INIT_CHECK;
    443 
    444     BCMX_PARAM_NULL_CHECK(encap_id);
    445 
    446     BCMX_LPORT_CHECK(port);
    447 
    448     /* Physical port */
    449     if (BCMX_LPORT_IS_PHYSICAL(port)) {
    450         BCM_IF_ERROR_RETURN
    451             (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    452                                      BCMX_DEST_CONVERT_DEFAULT));
    453         return bcm_multicast_niv_encap_get(bcm_unit, group,
    454                                            port, niv_port_id, encap_id);
    455     }
    456 
    457     /* Virtual port */
    458     BCMX_UNIT_ITER(bcm_unit, i) {
    459         rv = bcm_multicast_niv_encap_get(bcm_unit, group,
    460                                          port, niv_port_id, encap_id);
    461         if (BCMX_MULTICAST_GET_IS_VALID(bcm_unit, rv)) {
    462             return rv;
    463         }
    464     }
    465 
    466     return BCM_E_UNAVAIL;
    467 }
    468 
    469 
    470 /*
    471  * Function:
    472  *     bcmx_multicast_egress_add
    473  * Notes:
    474  *     Gport 'port' can be a physical local port or a virtual port.
    475  *     If 'port' is a physical port, apply to device where port resides.
    476  *     If 'port' is a virtual port, apply to all devices.
    477  */
    478 int
    479 bcmx_multicast_egress_add(bcm_multicast_t group,
    480                           bcm_gport_t port, bcm_if_t encap_id)
    481 {
    482     int         rv = BCM_E_UNAVAIL, tmp_rv;
    483     int         i;
    484     int         bcm_unit;
    485     bcm_port_t  bcm_port;
    486 
    487     BCMX_MULTICAST_INIT_CHECK;
    488 
    489     BCMX_LPORT_CHECK(port);
    490 
    491     /* Physical port */
    492     if (BCMX_LPORT_IS_PHYSICAL(port)) {
    493         BCM_IF_ERROR_RETURN
    494             (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    495                                      BCMX_DEST_CONVERT_DEFAULT));
    496         return bcm_multicast_egress_add(bcm_unit, group, port, encap_id);
    497     }
    498 
    499     /* Virtual port */
    500     BCMX_UNIT_ITER(bcm_unit, i) {
    501         tmp_rv = bcm_multicast_egress_add(bcm_unit, group, port, encap_id);
    502         BCM_IF_ERROR_RETURN
    503             (BCMX_MULTICAST_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    504     }
    505 
    506     return rv;
    507 }
    508 
    509 /*
    510  * Function:
    511  *     bcmx_multicast_egress_delete
    512  * Notes:
    513  *     Gport 'port' can be a physical local port or a virtual port.
    514  *     If 'port' is a physical port, apply to device where port resides.
    515  *     If 'port' is a virtual port, apply to all devices.
    516  */
    517 int
    518 bcmx_multicast_egress_delete(bcm_multicast_t group, 
    519                              bcm_gport_t port, bcm_if_t encap_id)
    520 {
    521     int         rv = BCM_E_UNAVAIL, tmp_rv;
    522     int         i;
    523     int         bcm_unit;
    524     bcm_port_t  bcm_port;
    525 
    526     BCMX_MULTICAST_INIT_CHECK;
    527 
    528     BCMX_LPORT_CHECK(port);
    529 
    530     /* Physical port */
    531     if (BCMX_LPORT_IS_PHYSICAL(port)) {
    532         BCM_IF_ERROR_RETURN
    533             (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    534                                      BCMX_DEST_CONVERT_DEFAULT));
    535 
    536         return bcm_multicast_egress_delete(bcm_unit, group, port, encap_id);
    537     }
    538 
    539     /* Virtual port */
    540     BCMX_UNIT_ITER(bcm_unit, i) {
    541         tmp_rv = bcm_multicast_egress_delete(bcm_unit, group, port, encap_id);
    542         BCM_IF_ERROR_RETURN
    543             (BCMX_MULTICAST_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    544     }
    545 
    546     return rv;
    547 }
    548 
    549 /*
    550  * Function:
    551  *    bcmx_multicast_egress_delete_all
    552  */
    553 int
    554 bcmx_multicast_egress_delete_all(bcm_multicast_t group)
    555 {
    556     int  rv = BCM_E_UNAVAIL, tmp_rv;
    557     int  i, bcm_unit;
    558 
    559     BCMX_MULTICAST_INIT_CHECK;
    560 
    561     BCMX_UNIT_ITER(bcm_unit, i) {
    562         tmp_rv = bcm_multicast_egress_delete_all(bcm_unit, group);
    563         BCM_IF_ERROR_RETURN
    564             (BCMX_MULTICAST_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    565     }
    566 
    567     return rv;
    568 }
    569 
    570 /*
    571  * Function:
    572  *     bcmx_multicast_egress_set
    573  * Notes:
    574  *     Each gport 'port' in array is a physical local port.
    575  */
    576 int
    577 bcmx_multicast_egress_set(bcm_multicast_t group, int port_count, 
    578                           bcm_gport_t *port_array, bcm_if_t *encap_id_array)
    579 {
    580     int          rv = BCM_E_UNAVAIL;
    581     int          tmp_rv;
    582     int          i, bcm_unit;
    583     int          j, unit;
    584     bcm_port_t   unit_port;
    585     int          unit_port_count;
    586     bcm_gport_t  *unit_port_array;
    587     bcm_if_t     *unit_encap_id_array;
    588 
    589     BCMX_MULTICAST_INIT_CHECK;
    590 
    591     BCMX_PARAM_ARRAY_NULL_CHECK(port_count, port_array);
    592     BCMX_PARAM_ARRAY_NULL_CHECK(port_count, encap_id_array);
    593 
    594     if ((unit_port_array = sal_alloc(port_count * sizeof(*port_array),
    595                                      "bcmx_multicast_egress_set")) == NULL) {
    596         return BCM_E_MEMORY;
    597     }
    598 
    599     if ((unit_encap_id_array = sal_alloc(port_count * sizeof(*encap_id_array),
    600                                          "bcmx_multicast_egress_set")) == NULL) {
    601         sal_free(unit_port_array);
    602         return BCM_E_MEMORY;
    603     }        
    604 
    605     /* Need to gather all ports in a unit, then do a 'set' */
    606     BCMX_UNIT_ITER(bcm_unit, i) {
    607         unit_port_count = 0;
    608 
    609         /* Get all ports that belong to a unit */
    610         for (j = 0; j < port_count; j++) {
    611             if (BCM_FAILURE
    612                 (_bcmx_dest_to_unit_port(port_array[j],
    613                                          &unit, &unit_port,
    614                                          BCMX_DEST_CONVERT_DEFAULT))) {
    615                 continue;
    616             }
    617             if (unit != bcm_unit) {
    618                 continue;
    619             }
    620 
    621             unit_port_array[unit_port_count] = port_array[j];
    622             unit_encap_id_array[unit_port_count] = encap_id_array[j];
    623             unit_port_count++;
    624         }
    625 
    626         if (unit_port_count == 0) {
    627             continue;
    628         }
    629 
    630         tmp_rv = bcm_multicast_egress_set(bcm_unit, group, unit_port_count,
    631                                           unit_port_array, unit_encap_id_array);
    632 
    633         if (BCM_FAILURE
    634             (BCMX_MULTICAST_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv))) {
    635             break;
    636         }
    637     }
    638 
    639     sal_free(unit_port_array);
    640     sal_free(unit_encap_id_array);
    641 
    642     return rv;
    643 }
    644 
    645 /*
    646  * Function:
    647  *     bcmx_multicast_egress_get
    648  * Notes:
    649  *     Each gport 'port' is a physical local port.
    650  */
    651 int
    652 bcmx_multicast_egress_get(bcm_multicast_t group, int port_max, 
    653                           bcm_gport_t *port_array, bcm_if_t *encap_id_array, 
    654                           int *port_count)
    655 {
    656     int          rv = BCM_E_UNAVAIL;
    657     int          tmp_rv;
    658     int          i, bcm_unit;
    659     int          port_max_left;
    660     int          unit_port_count;
    661     bcm_gport_t  *unit_port_array;
    662     bcm_if_t     *unit_encap_id_array;
    663 
    664     BCMX_MULTICAST_INIT_CHECK;
    665 
    666     BCMX_PARAM_ARRAY_NULL_CHECK(port_max, port_array);
    667     BCMX_PARAM_ARRAY_NULL_CHECK(port_max, encap_id_array);
    668     BCMX_PARAM_NULL_CHECK(port_count);
    669 
    670     *port_count   = 0;
    671     port_max_left = port_max;
    672 
    673     /* Need to gather egress ports from all units */
    674     BCMX_UNIT_ITER(bcm_unit, i) {
    675 
    676         if (port_max_left <= 0) {
    677             break;
    678         }
    679 
    680         unit_port_count = 0;
    681         unit_port_array = &port_array[*port_count];
    682         unit_encap_id_array = &encap_id_array[*port_count];
    683 
    684         tmp_rv = bcm_multicast_egress_get(bcm_unit, group, port_max_left,
    685                                           unit_port_array, unit_encap_id_array,
    686                                           &unit_port_count);
    687         
    688         if (BCMX_MULTICAST_GET_IS_VALID(bcm_unit, tmp_rv)) {
    689             /*
    690              * Ignore BCM_E_NOT_FOUND since objects are physical ports
    691              * and are added for specific unit.  Exit on other failure.
    692              */
    693             if (tmp_rv == BCM_E_NOT_FOUND) {
    694                 if (rv == BCM_E_UNAVAIL) {
    695                     rv = tmp_rv;
    696                 }
    697                 continue;
    698             }
    699             rv = tmp_rv;
    700             if (BCM_FAILURE(tmp_rv)) {
    701                 break;
    702             }
    703             *port_count   += unit_port_count;
    704             port_max_left -= unit_port_count;
    705         }
    706     }
    707 
    708     return rv;
    709 }
    710 
    711 /*
    712  * Function:
    713  *     bcmx_multicast_repl_set
    714  * Notes:
    715  *     Each gport 'port' is a physical local port.
    716  */
    717 int
    718 bcmx_multicast_repl_set(int index,
    719 		   bcmx_lport_t port,
    720 		   bcm_vlan_vector_t vlan_vec)
    721 {
    722     int         bcm_unit;
    723     bcm_port_t  bcm_port;
    724 
    725     BCMX_MULTICAST_INIT_CHECK;
    726 
    727     BCM_IF_ERROR_RETURN(_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    728                                                 BCMX_DEST_CONVERT_DEFAULT));
    729 
    730     return bcm_multicast_repl_set(bcm_unit, index, bcm_port, vlan_vec);
    731 }
    732 
    733 /*
    734  * Function:
    735  *     bcmx_multicast_repl_get
    736  * Notes:
    737  *     Each gport 'port' is a physical local port.
    738  */
    739 int
    740 bcmx_multicast_repl_get(int index,
    741 		   bcmx_lport_t port,
    742 		   bcm_vlan_vector_t vlan_vec)
    743 {
    744     int         bcm_unit;
    745     bcm_port_t  bcm_port;
    746 
    747     BCMX_MULTICAST_INIT_CHECK;
    748 
    749     BCM_IF_ERROR_RETURN(_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    750                                                 BCMX_DEST_CONVERT_DEFAULT));
    751 
    752     return bcm_multicast_repl_get(bcm_unit, index, bcm_port, vlan_vec);
    753 }
    754 
    755 /*
    756  * Function:
    757  *      bcmx_multicast_control_set
    758  * Purpose:
    759  *      Set multicast group control.
    760  * Parameters:
    761  *      group - (IN) Multicast group ID.
    762  *      type  - (IN) Multicast group control type.
    763  *      arg   - (IN) Multicast group control argument.
    764  * Returns:
    765  *      BCM_E_XXX
    766  */
    767 int
    768 bcmx_multicast_control_set(bcm_multicast_t group,
    769                            bcm_multicast_control_t type, int arg)
    770 {
    771     int rv = BCM_E_UNAVAIL, tmp_rv;
    772     int i, bcm_unit;
    773 
    774     BCMX_MULTICAST_INIT_CHECK;
    775 
    776     BCMX_UNIT_ITER(bcm_unit, i) {
    777         tmp_rv = bcm_multicast_control_set(bcm_unit, group, type, arg);
    778         BCM_IF_ERROR_RETURN
    779             (BCMX_MULTICAST_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    780     }
    781 
    782     return rv;
    783 }
    784 
    785 /*
    786  * Function:
    787  *      bcmx_multicast_control_get
    788  * Purpose:
    789  *      Get multicast group control.
    790  * Parameters:
    791  *      group - (IN) Multicast group ID.
    792  *      type  - (IN) Multicast group control type.
    793  *      arg   - (OUT) Multicast group control argument.
    794  * Returns:
    795  *      BCM_E_XXX
    796  */
    797 int
    798 bcmx_multicast_control_get(bcm_multicast_t group,
    799                            bcm_multicast_control_t type, int *arg)
    800 {
    801     int    rv;
    802     int    i, bcm_unit;
    803 
    804     BCMX_MULTICAST_INIT_CHECK;
    805 
    806     BCMX_PARAM_NULL_CHECK(arg);
    807 
    808     BCMX_UNIT_ITER(bcm_unit, i) {
    809         rv = bcm_multicast_control_get(bcm_unit, group, type, arg);
    810         if (BCMX_MULTICAST_GET_IS_VALID(bcm_unit, rv)) {
    811             return rv;
    812         }
    813     }
    814 
    815     return BCM_E_UNAVAIL;
    816 }