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

trunk.c (22342B)


      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/trunk.c
      8  * Purpose: BCMX Trunk APIs
      9  *
     10  * BCMX trunking takes place on switch ports, not fabric ports.
     11  * Fabric port trunking may be controlled by the stack/toppology
     12  * code, so we are careful to skip any fabric devices and ports.
     13  */
     14 
     15 #include <sal/core/libc.h>
     16 #include <sal/core/alloc.h>
     17 
     18 #include <bcm/types.h>
     19 
     20 #include <bcmx/trunk.h>
     21 #include <bcmx/lport.h>
     22 #include <bcmx/bcmx.h>
     23 #include <bcmx/lplist.h>
     24 
     25 #include <bcm_int/control.h>
     26 #include "bcmx_int.h"
     27 
     28 #define BCMX_TRUNK_INIT_CHECK    BCMX_READY_CHECK
     29 
     30 #define BCMX_TRUNK_ERROR_CHECK(_unit, _check, _rv)    \
     31     BCMX_ERROR_CHECK(_unit, _check, _rv)
     32 
     33 #define BCMX_TRUNK_SET_ERROR_CHECK(_unit, _check, _rv)    \
     34     BCMX_SET_ERROR_CHECK(_unit, _check, _rv)
     35 
     36 #define BCMX_TRUNK_DELETE_ERROR_CHECK(_unit, _check, _rv)    \
     37     BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv)
     38 
     39 #define BCMX_TRUNK_GET_IS_VALID(_unit, _rv)    \
     40     BCMX_ERROR_IS_VALID(_unit, _rv)
     41 
     42 
     43 #define BCMX_TRUNK_MEMBER_T_PTR_TO_BCM(_trunk_member)   \
     44     ((bcm_trunk_member_t *)(_trunk_member))
     45 
     46 
     47 /*
     48  * Function:
     49  *      bcmx_trunk_add_info_t_init
     50  * Purpose:
     51  *      Initialize the bcmx_trunk_add_info_t structure.
     52  * Parameters:
     53  *      trunk_add_info - Pointer to structure to be initialized.
     54  * Returns:
     55  *      None
     56  * Notes:
     57  *      Memory is allocated for the port list member in this
     58  *      call.  The corresponding 'free' API needs to be called
     59  *      when structure is no longer needed.
     60  */
     61 void
     62 bcmx_trunk_add_info_t_init(bcmx_trunk_add_info_t *trunk_add_info)
     63 {
     64     if (trunk_add_info != NULL) {
     65         sal_memset(trunk_add_info, 0, sizeof(bcmx_trunk_add_info_t));
     66         bcmx_lplist_t_init(&trunk_add_info->ports);
     67     }
     68 }
     69 
     70 
     71 /*
     72  * Function:
     73  *      bcmx_trunk_add_info_t_free
     74  * Purpose:
     75  *      Free memory allocated by bcmx_trunk_add_info_t_init().
     76  * Parameters:
     77  *      trunk_add_info - Pointer to structure to free memory.
     78  * Returns:
     79  *      None
     80  */
     81 void
     82 bcmx_trunk_add_info_t_free(bcmx_trunk_add_info_t *trunk_add_info)
     83 {
     84     if (trunk_add_info != NULL) {
     85         bcmx_lplist_free(&trunk_add_info->ports);
     86     }
     87 }
     88 
     89 /*
     90  * Function:
     91  *      bcmx_trunk_member_t_init
     92  * Purpose:
     93  *      Trunk member structure initializer.
     94  * Parameters:
     95  *      trunk_member - (IN/OUT) Pointer to structure to be initialized.
     96  * Returns:
     97  *      None
     98  */
     99 void
    100 bcmx_trunk_member_t_init(bcmx_trunk_member_t *trunk_member)
    101 {
    102     if (trunk_member != NULL) {
    103         bcm_trunk_member_t_init(BCMX_TRUNK_MEMBER_T_PTR_TO_BCM(trunk_member));
    104     }
    105 }
    106 
    107 
    108 /*
    109  * Function:
    110  *      bcmx_trunk_init
    111  */
    112 
    113 int
    114 bcmx_trunk_init(void)
    115 {
    116     int rv = BCM_E_UNAVAIL, tmp_rv;
    117     int i, bcm_unit;
    118 
    119     BCMX_TRUNK_INIT_CHECK;
    120 
    121     BCMX_UNIT_ITER(bcm_unit, i) {
    122         if (BCM_IS_FABRIC(bcm_unit)) {
    123             continue;
    124         }
    125         tmp_rv = bcm_trunk_init(bcm_unit);
    126         BCM_IF_ERROR_RETURN(BCMX_TRUNK_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    127     }
    128 
    129     return rv;
    130 }
    131 
    132 
    133 /*
    134  * Function:
    135  *      bcmx_trunk_detach
    136  */
    137 
    138 int
    139 bcmx_trunk_detach(void)
    140 {
    141     int rv = BCM_E_UNAVAIL, tmp_rv;
    142     int i, bcm_unit;
    143 
    144     BCMX_TRUNK_INIT_CHECK;
    145 
    146     BCMX_UNIT_ITER(bcm_unit, i) {
    147         if (BCM_IS_FABRIC(bcm_unit)) {
    148             continue;
    149         }
    150         tmp_rv = bcm_trunk_detach(bcm_unit);
    151         BCM_IF_ERROR_RETURN(BCMX_TRUNK_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    152     }
    153 
    154     return rv;
    155 }
    156 
    157 
    158 /*
    159  * Function:
    160  *      bcmx_trunk_create
    161  */
    162 
    163 int
    164 bcmx_trunk_create(bcm_trunk_t *tid)
    165 {
    166     int rv = BCM_E_UNAVAIL, tmp_rv;
    167     int i, bcm_unit;
    168 
    169     BCMX_TRUNK_INIT_CHECK;
    170 
    171     BCMX_UNIT_ITER(bcm_unit, i) {
    172         if (BCM_IS_FABRIC(bcm_unit)) {
    173             continue;
    174         }
    175         tmp_rv = bcm_trunk_create(bcm_unit, 0, tid);
    176         BCM_IF_ERROR_RETURN(BCMX_TRUNK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    177     }
    178 
    179     return rv;
    180 }
    181 
    182 
    183 /*
    184  * Function:
    185  *      bcmx_trunk_create_id
    186  */
    187 
    188 int
    189 bcmx_trunk_create_id(bcm_trunk_t tid)
    190 {
    191     int rv = BCM_E_UNAVAIL, tmp_rv;
    192     int i, bcm_unit;
    193 
    194     BCMX_TRUNK_INIT_CHECK;
    195 
    196     BCMX_UNIT_ITER(bcm_unit, i) {
    197         if (BCM_IS_FABRIC(bcm_unit)) {
    198             continue;
    199         }
    200         tmp_rv = bcm_trunk_create(bcm_unit, BCM_TRUNK_FLAG_WITH_ID, &tid);
    201         BCM_IF_ERROR_RETURN(BCMX_TRUNK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    202     }
    203 
    204     return rv;
    205 }
    206 
    207 
    208 /*
    209  * Function:
    210  *      bcmx_trunk_psc_set
    211  */
    212 
    213 int
    214 bcmx_trunk_psc_set(bcm_trunk_t tid, int psc)
    215 {
    216     int rv = BCM_E_UNAVAIL, tmp_rv;
    217     int i, bcm_unit;
    218 
    219     BCMX_TRUNK_INIT_CHECK;
    220 
    221     BCMX_UNIT_ITER(bcm_unit, i) {
    222         if (BCM_IS_FABRIC(bcm_unit)) {
    223             continue;
    224         }
    225         tmp_rv = bcm_trunk_psc_set(bcm_unit, tid, psc);
    226         BCM_IF_ERROR_RETURN(BCMX_TRUNK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    227     }
    228 
    229     return rv;
    230 }
    231 
    232 
    233 /*
    234  * Function:
    235  *      bcmx_trunk_psc_get
    236  */
    237 
    238 int
    239 bcmx_trunk_psc_get(bcm_trunk_t tid, int *psc)
    240 {
    241     int rv;
    242     int i, bcm_unit;
    243 
    244     BCMX_TRUNK_INIT_CHECK;
    245 
    246     BCMX_PARAM_NULL_CHECK(psc);
    247 
    248     BCMX_UNIT_ITER(bcm_unit, i) {
    249         if (BCM_IS_FABRIC(bcm_unit)) {
    250             continue;
    251         }
    252         rv = bcm_trunk_psc_get(bcm_unit, tid, psc);
    253         if (BCMX_TRUNK_GET_IS_VALID(bcm_unit, rv)) {
    254             return rv;
    255         }
    256     }
    257 
    258     return BCM_E_UNAVAIL;
    259 }
    260 
    261 
    262 /*
    263  * Function:
    264  *      bcmx_trunk_chip_info_get
    265  * Notes:
    266  *      Returns the common denominator from all switch devices.
    267  */
    268 
    269 int
    270 bcmx_trunk_chip_info_get(bcm_trunk_chip_info_t *ta_info)
    271 {
    272     int rv = BCM_E_UNAVAIL, tmp_rv;
    273     int i, bcm_unit;
    274     bcm_trunk_chip_info_t tmp_info;
    275     int first = TRUE;
    276 
    277     BCMX_TRUNK_INIT_CHECK;
    278 
    279     BCMX_PARAM_NULL_CHECK(ta_info);
    280 
    281     BCMX_UNIT_ITER(bcm_unit, i) {
    282         if (BCM_IS_FABRIC(bcm_unit)) {
    283             continue;
    284         }
    285 
    286         tmp_rv = bcm_trunk_chip_info_get(bcm_unit, &tmp_info);
    287         if (BCMX_TRUNK_GET_IS_VALID(bcm_unit, rv)) {
    288             rv = tmp_rv;
    289 
    290             BCM_IF_ERROR_RETURN(rv);
    291 
    292             if (first) {
    293                 *ta_info = tmp_info;
    294                 first = FALSE;
    295                 continue;
    296             }
    297 
    298             if (tmp_info.trunk_group_count < ta_info->trunk_group_count) {
    299                 ta_info->trunk_group_count = tmp_info.trunk_group_count;
    300             }
    301             if (tmp_info.trunk_id_min > ta_info->trunk_id_min) {
    302                 ta_info->trunk_id_min = tmp_info.trunk_id_min;
    303             }
    304             if (tmp_info.trunk_id_max < ta_info->trunk_id_max) {
    305                 ta_info->trunk_id_max = tmp_info.trunk_id_max;
    306             }
    307             if (tmp_info.trunk_ports_max < ta_info->trunk_ports_max) {
    308                 ta_info->trunk_ports_max = tmp_info.trunk_ports_max;
    309             }
    310             if (tmp_info.trunk_fabric_id_min > ta_info->trunk_fabric_id_min) {
    311                 ta_info->trunk_fabric_id_min = tmp_info.trunk_fabric_id_min;
    312             }
    313             if (tmp_info.trunk_fabric_id_max < ta_info->trunk_fabric_id_max) {
    314                 ta_info->trunk_fabric_id_max = tmp_info.trunk_fabric_id_max;
    315             }
    316             if (tmp_info.trunk_fabric_ports_max < ta_info->trunk_fabric_ports_max) {
    317                 ta_info->trunk_fabric_ports_max = tmp_info.trunk_fabric_ports_max;
    318             }
    319         }
    320     }
    321 
    322     return rv;
    323 }
    324 
    325 
    326 /*
    327  * Function:
    328  *      bcmx_trunk_set
    329  */
    330 
    331 int
    332 bcmx_trunk_set(bcm_trunk_t tid, bcmx_trunk_add_info_t *add_info)
    333 {
    334     int                   rv = BCM_E_UNAVAIL, tmp_rv;
    335     bcm_trunk_info_t      badd;
    336     int                   i, bcm_unit, count;
    337     bcmx_lport_t          lport;
    338     int                   member_count;
    339     bcm_trunk_member_t    *member_array = NULL;
    340     bcm_module_t          mod;
    341     bcm_port_t            port;
    342 
    343     BCMX_TRUNK_INIT_CHECK;
    344 
    345     BCMX_PARAM_NULL_CHECK(add_info);
    346 
    347     sal_memset(&badd, 0, sizeof(bcm_trunk_info_t));
    348     badd.psc = add_info->psc;
    349     badd.ipmc_psc = add_info->ipmc_psc;
    350     badd.dlf_index = -1;
    351     badd.mc_index = -1;
    352     badd.ipmc_index = -1;
    353 
    354     member_count = BCMX_LPLIST_COUNT(&(add_info->ports));
    355     member_array = sal_alloc(member_count * sizeof(bcm_trunk_member_t),
    356             "trunk member array");
    357     if (NULL == member_array) {
    358         return BCM_E_MEMORY;
    359     }
    360     sal_memset(member_array, 0, member_count * sizeof(bcm_trunk_member_t));
    361 
    362     BCMX_LPLIST_ITER(add_info->ports, lport, count) {
    363         if (count >= BCM_TRUNK_MAX_PORTCNT) {
    364             sal_free(member_array);
    365             return BCM_E_PARAM;
    366         }
    367         if (lport == add_info->dlf_port) {
    368             badd.dlf_index = count;
    369         }
    370         if (lport == add_info->mc_port) {
    371             badd.mc_index = count;
    372         }
    373         if (lport == add_info->ipmc_port) {
    374             badd.ipmc_index = count;
    375         }
    376 
    377         tmp_rv = _bcmx_dest_to_modid_port(lport,
    378                                       &mod, &port,
    379                                       BCMX_DEST_CONVERT_DEFAULT);
    380         if (BCM_FAILURE(tmp_rv)) {
    381             sal_free(member_array);
    382             return tmp_rv;
    383         }
    384 
    385         bcm_trunk_member_t_init(&member_array[count]);
    386         BCM_GPORT_MODPORT_SET(member_array[count].gport, mod, port);
    387     }
    388     
    389     BCMX_UNIT_ITER(bcm_unit, i) {
    390         if (BCM_IS_FABRIC(bcm_unit)) {
    391             continue;
    392         }
    393         tmp_rv = bcm_trunk_set(bcm_unit, tid, &badd, member_count,
    394                                member_array);
    395         tmp_rv = BCMX_TRUNK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv);
    396         if (BCM_FAILURE(tmp_rv)) {
    397             sal_free(member_array);
    398             return tmp_rv;
    399         }
    400     }
    401 
    402     sal_free(member_array);
    403     return rv;
    404 }
    405 
    406 
    407 /*
    408  * Function:
    409  *      bcmx_trunk_destroy
    410  */
    411 
    412 int
    413 bcmx_trunk_destroy(bcm_trunk_t tid)
    414 {
    415     int rv = BCM_E_UNAVAIL, tmp_rv;
    416     int i, bcm_unit;
    417 
    418     BCMX_TRUNK_INIT_CHECK;
    419 
    420     BCMX_UNIT_ITER(bcm_unit, i) {
    421         if (BCM_IS_FABRIC(bcm_unit)) {
    422             continue;
    423         }
    424         tmp_rv = bcm_trunk_destroy(bcm_unit, tid);
    425         BCM_IF_ERROR_RETURN
    426             (BCMX_TRUNK_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    427     }
    428 
    429     return rv;
    430 }
    431 
    432 
    433 /*
    434  * Function:
    435  *      bcmx_trunk_get
    436  */
    437 
    438 int
    439 bcmx_trunk_get(bcm_trunk_t tid, bcmx_trunk_add_info_t *t_data)
    440 {
    441     bcm_trunk_info_t   badd;
    442     int                rv, i, bcm_unit;
    443     bcmx_lport_t       lport;
    444     int                member_count, unused_count;
    445     bcm_trunk_member_t *member_array = NULL;
    446     bcm_module_t       mod;
    447     bcm_port_t         port;
    448 
    449     BCMX_TRUNK_INIT_CHECK;
    450 
    451     BCMX_PARAM_NULL_CHECK(t_data);
    452 
    453     BCMX_UNIT_ITER(bcm_unit, i) {
    454         if (BCM_IS_FABRIC(bcm_unit)) {
    455             continue;
    456         }
    457 
    458         rv = bcm_trunk_get(bcm_unit, tid, &badd, 0, NULL, &member_count);
    459         if (!BCMX_TRUNK_GET_IS_VALID(bcm_unit, rv)) {
    460             continue;
    461         }
    462 
    463         if (member_count > 0) {
    464             member_array = sal_alloc(member_count * sizeof(bcm_trunk_member_t),
    465                                      "trunk member array"); 
    466             if (NULL == member_array) {
    467                 return BCM_E_MEMORY;
    468             }
    469         }
    470         rv = bcm_trunk_get(bcm_unit, tid, &badd, member_count, member_array,
    471                            &unused_count);
    472         if (BCMX_TRUNK_GET_IS_VALID(bcm_unit, rv)) {
    473             if (BCM_SUCCESS(rv)) {
    474                 sal_memset(t_data, 0, sizeof(bcmx_trunk_add_info_t));
    475                 bcmx_lplist_init(&t_data->ports, member_count, 0);
    476                 t_data->psc = badd.psc;
    477                 t_data->ipmc_psc = badd.ipmc_psc;
    478                 t_data->dlf_port = BCMX_LPORT_INVALID;
    479                 t_data->mc_port = BCMX_LPORT_INVALID;
    480                 t_data->ipmc_port = BCMX_LPORT_INVALID;
    481 
    482                 for (i = 0; i < member_count; i++) {
    483                     /* Convert to lport */
    484                     mod = BCM_GPORT_MODPORT_MODID_GET(member_array[i].gport);
    485                     port = BCM_GPORT_MODPORT_PORT_GET(member_array[i].gport);
    486                     rv = _bcmx_dest_from_modid_port(&lport,
    487                                                     mod, port,
    488                                                     BCMX_DEST_CONVERT_DEFAULT);
    489                     if (BCM_FAILURE(rv)) {
    490                         sal_free(member_array);
    491                         return rv;
    492                     }
    493                     bcmx_lplist_add(&t_data->ports, lport);
    494                     if (i == badd.dlf_index) {
    495                         t_data->dlf_port = lport;
    496                     }
    497                     if (i == badd.mc_index) {
    498                         t_data->mc_port = lport;
    499                     }
    500                     if (i == badd.ipmc_index) {
    501                         t_data->ipmc_port = lport;
    502                     }
    503                 }
    504             }
    505 
    506             if (NULL != member_array) {
    507                 sal_free(member_array);
    508             }
    509             return rv;
    510         }
    511 
    512         if (NULL != member_array) {
    513             sal_free(member_array);
    514             member_array = NULL;
    515         }
    516     }
    517 
    518     return BCM_E_UNAVAIL;
    519 }
    520 
    521 
    522 
    523 /*
    524  * Function:
    525  *      bcmx_trunk_mcast_join
    526  */
    527 
    528 int
    529 bcmx_trunk_mcast_join(bcm_trunk_t tid,
    530                       bcm_vlan_t vid,
    531                       bcm_mac_t mac)
    532 {
    533     int rv = BCM_E_UNAVAIL, tmp_rv;
    534     int i, bcm_unit;
    535 
    536     BCMX_TRUNK_INIT_CHECK;
    537 
    538     BCMX_UNIT_ITER(bcm_unit, i) {
    539         if (BCM_IS_FABRIC(bcm_unit)) {
    540             continue;
    541         }
    542         tmp_rv = bcm_trunk_mcast_join(bcm_unit, tid, vid, mac);
    543         BCM_IF_ERROR_RETURN(BCMX_TRUNK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    544     }
    545 
    546     return rv;
    547 }
    548 
    549 
    550 /*
    551  * Function:
    552  *      bcmx_trunk_egress_set
    553  */
    554 
    555 int
    556 bcmx_trunk_egress_set(bcm_trunk_t tid, bcmx_lplist_t lplist)
    557 {
    558     int         rv = BCM_E_UNAVAIL, tmp_rv;
    559     bcm_pbmp_t  pbm;
    560     int         bcm_unit, i;
    561 
    562     BCMX_TRUNK_INIT_CHECK;
    563 
    564     BCMX_UNIT_ITER(bcm_unit, i) {
    565         if (BCM_IS_FABRIC(bcm_unit)) {
    566             continue;
    567         }
    568         BCM_PBMP_CLEAR(pbm);
    569         BCMX_LPLIST_TO_PBMP(lplist, bcm_unit, pbm);
    570         tmp_rv = bcm_trunk_egress_set(bcm_unit, tid, pbm);
    571         BCM_IF_ERROR_RETURN(BCMX_TRUNK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    572     }
    573 
    574     return rv;
    575 }
    576 
    577 
    578 /*
    579  * Function:
    580  *      bcmx_trunk_egress_get
    581  */
    582 
    583 int
    584 bcmx_trunk_egress_get(bcm_trunk_t tid, bcmx_lplist_t *lplist)
    585 {
    586     int         rv = BCM_E_UNAVAIL, tmp_rv;
    587     bcm_pbmp_t  pbm;
    588     int         bcm_unit, i;
    589 
    590     BCMX_TRUNK_INIT_CHECK;
    591 
    592     bcmx_lplist_clear(lplist);
    593     BCMX_UNIT_ITER(bcm_unit, i) {
    594         if (BCM_IS_FABRIC(bcm_unit)) {
    595             continue;
    596         }
    597 
    598         tmp_rv = bcm_trunk_egress_get(bcm_unit, tid, &pbm);
    599         if (BCMX_TRUNK_GET_IS_VALID(bcm_unit, tmp_rv)) {
    600             rv = tmp_rv;
    601             if (BCM_SUCCESS(tmp_rv)) {
    602                 BCMX_LPLIST_PBMP_ADD(lplist, bcm_unit, pbm);
    603             } else {
    604                 break;
    605             }
    606         }
    607     }
    608 
    609     return rv;
    610 }
    611 
    612 /*
    613  * Function:
    614  *      bcmx_trunk_find
    615  */
    616 int
    617 bcmx_trunk_find(bcmx_lport_t lport, bcm_trunk_t *tid)
    618 {
    619     int rv = BCM_E_UNAVAIL, bcm_unit, i;
    620     bcm_module_t modid;
    621     bcm_port_t   modport;
    622 
    623     BCMX_TRUNK_INIT_CHECK;
    624 
    625     BCM_IF_ERROR_RETURN
    626         (_bcmx_dest_to_modid_port(lport, &modid, &modport,
    627                                   BCMX_DEST_CONVERT_DEFAULT));
    628 
    629     BCMX_UNIT_ITER(bcm_unit, i) {
    630         rv = bcm_trunk_find(bcm_unit,
    631                             modid,
    632                             modport,
    633                             tid);
    634 
    635         if (BCM_SUCCESS(rv)) {
    636             break;
    637         }
    638     }
    639 
    640     return rv;
    641 }
    642 
    643 /*
    644  * Function:
    645  *     bcmx_trunk_failover_set
    646  * Purpose:
    647  *     Assign the failover port list for a specific trunk port.
    648  * Parameters:
    649  *     tid           - Trunk id
    650  *     failport      - Port in trunk for which to specify failover port list
    651  *     psc           - Port selection criteria for failover port list
    652  *     flags         - BCM_TRUNK_FLAG_FAILOVER_xxx
    653  *     count         - Number of ports in failover port list
    654  *     fail_to_array - Failover port list
    655  * Returns:
    656  *      BCM_E_XXX
    657  * Notes:
    658  */
    659 int
    660 bcmx_trunk_failover_set(bcm_trunk_t tid, bcm_gport_t failport, 
    661                         int psc, uint32 flags, int count, 
    662                         bcm_gport_t *fail_to_array)
    663 {
    664     int         bcm_unit;
    665     bcm_port_t  bcm_port;
    666 
    667     BCMX_TRUNK_INIT_CHECK;
    668 
    669     BCMX_PARAM_ARRAY_NULL_CHECK(count, fail_to_array);
    670 
    671     BCM_IF_ERROR_RETURN(_bcmx_dest_to_unit_port(failport, &bcm_unit, &bcm_port,
    672                                                 BCMX_DEST_CONVERT_DEFAULT));
    673 
    674     return bcm_trunk_failover_set(bcm_unit, tid, failport, 
    675                                   psc, flags, count, fail_to_array);
    676 }
    677 
    678 /*
    679  * Function:
    680  *     bcmx_trunk_failover_get
    681  * Purpose:
    682  *     Retrieve the failover port list for a specific trunk port.
    683  * Parameters:
    684  *     tid           - Trunk id
    685  *     failport      - Port in trunk for which to retrieve failover port list
    686  *     psc           - (OUT) Port selection criteria for failover port list
    687  *     flags         - (OUT) BCM_TRUNK_FLAG_FAILOVER_xxx
    688  *     array_size    - Maximum number of ports in provided failover port list
    689  *     fail_to_array - (OUT) Failover port list
    690  *     array_count   - (OUT) Number of ports in returned failover port list
    691  * Returns:
    692  *     BCM_E_XXX
    693  * Notes:
    694  */
    695 int
    696 bcmx_trunk_failover_get(bcm_trunk_t tid, bcm_gport_t failport, 
    697                         int *psc, uint32 *flags, int array_size, 
    698                         bcm_gport_t *fail_to_array, int *array_count)
    699 {
    700     int         bcm_unit;
    701     bcm_port_t  bcm_port;
    702 
    703     BCMX_TRUNK_INIT_CHECK;
    704 
    705     BCMX_PARAM_NULL_CHECK(psc);
    706     BCMX_PARAM_NULL_CHECK(flags);
    707     BCMX_PARAM_ARRAY_NULL_CHECK(array_size, fail_to_array);
    708     BCMX_PARAM_NULL_CHECK(array_count);
    709 
    710     BCM_IF_ERROR_RETURN(_bcmx_dest_to_unit_port(failport, &bcm_unit, &bcm_port,
    711                                                 BCMX_DEST_CONVERT_DEFAULT));
    712 
    713     return bcm_trunk_failover_get(bcm_unit, tid, failport, 
    714                                   psc, flags, array_size,
    715                                   fail_to_array, array_count);
    716 }
    717 
    718 /*
    719  * Function:
    720  *     bcmx_trunk_member_add
    721  * Purpose:
    722  *     Add a member to a trunk group.
    723  * Parameters:
    724  *     tid    - Trunk id
    725  *     member - Pointer to a trunk member structure.
    726  * Returns:
    727  *      BCM_E_XXX
    728  */
    729 int
    730 bcmx_trunk_member_add(bcm_trunk_t tid, bcmx_trunk_member_t *member)
    731 {
    732     int         bcm_unit;
    733     bcm_port_t  bcm_port;
    734 
    735     BCMX_TRUNK_INIT_CHECK;
    736 
    737     BCMX_PARAM_NULL_CHECK(member);
    738 
    739     BCM_IF_ERROR_RETURN(_bcmx_dest_to_unit_port(member->gport,
    740                                                 &bcm_unit, &bcm_port,
    741                                                 BCMX_DEST_CONVERT_DEFAULT));
    742 
    743     return bcm_trunk_member_add(bcm_unit, tid,
    744                                 BCMX_TRUNK_MEMBER_T_PTR_TO_BCM(member));
    745 }
    746 
    747 /*
    748  * Function:
    749  *     bcmx_trunk_member_delete
    750  * Purpose:
    751  *     Remove a member from a trunk group.
    752  * Parameters:
    753  *     tid    - Trunk id
    754  *     member - Pointer to a trunk member structure.
    755  * Returns:
    756  *      BCM_E_XXX
    757  */
    758 int
    759 bcmx_trunk_member_delete(bcm_trunk_t tid, bcmx_trunk_member_t *member)
    760 {
    761     int         bcm_unit;
    762     bcm_port_t  bcm_port;
    763 
    764     BCMX_TRUNK_INIT_CHECK;
    765 
    766     BCMX_PARAM_NULL_CHECK(member);
    767 
    768     BCM_IF_ERROR_RETURN(_bcmx_dest_to_unit_port(member->gport,
    769                                                 &bcm_unit, &bcm_port,
    770                                                 BCMX_DEST_CONVERT_DEFAULT));
    771 
    772     return bcm_trunk_member_delete(bcm_unit, tid,
    773                                    BCMX_TRUNK_MEMBER_T_PTR_TO_BCM(member));
    774 }
    775 
    776 /*
    777  * Function:
    778  *     bcmx_trunk_member_delete_all
    779  * Purpose:
    780  *     Remove all members of a trunk group.
    781  * Parameters:
    782  *     tid - Trunk id
    783  * Returns:
    784  *     BCM_E_XXX
    785  */
    786 int
    787 bcmx_trunk_member_delete_all(bcm_trunk_t tid)
    788 {
    789     int  rv = BCM_E_UNAVAIL, tmp_rv;
    790     int  i, bcm_unit;
    791 
    792     BCMX_TRUNK_INIT_CHECK;
    793 
    794     BCMX_UNIT_ITER(bcm_unit, i) {
    795         tmp_rv = bcm_trunk_member_delete_all(bcm_unit, tid);
    796         BCM_IF_ERROR_RETURN
    797             (BCMX_TRUNK_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    798     }
    799 
    800     return rv;
    801 }
    802 
    803 /*
    804  * Function:
    805  *     bcmx_trunk_member_set
    806  * Purpose:
    807  *     Assign a set of members to a trunk group.
    808  * Parameters:
    809  *     tid          - Trunk id
    810  *     member_count - Number of trunk members in member_array.
    811  *     member_array - Array of trunk member structures.
    812  * Returns:
    813  *     BCM_E_XXX
    814  * Notes:
    815  *     Assumes all ports are in the same device (pick first one).
    816  *     BCM will report an error if a port is not local to designated device.
    817  */
    818 int
    819 bcmx_trunk_member_set(bcm_trunk_t tid, int member_count, 
    820                       bcmx_trunk_member_t *member_array)
    821 {
    822     int         bcm_unit;
    823     bcm_port_t  bcm_port;
    824 
    825     BCMX_TRUNK_INIT_CHECK;
    826 
    827     BCMX_PARAM_NULL_CHECK(member_array);
    828 
    829     BCM_IF_ERROR_RETURN(_bcmx_dest_to_unit_port(member_array[0].gport,
    830                                                 &bcm_unit, &bcm_port,
    831                                                 BCMX_DEST_CONVERT_DEFAULT));
    832     /* bcm_trunk_member_set is deprecated.
    833      *
    834      * return bcm_trunk_member_set(bcm_unit, tid, member_count,
    835      *                           BCMX_TRUNK_MEMBER_T_PTR_TO_BCM(member_array));
    836      */
    837     return BCM_E_UNAVAIL;
    838 }
    839 
    840 /*
    841  * Function:
    842  *     bcmx_trunk_member_get
    843  * Purpose:
    844  *     Retrieve members of a trunk group. If member_max is 0,
    845  *     the number of member ports in the given trunk group
    846  *     is returned in member_count.
    847  * Parameters:
    848  *     tid          - Trunk id
    849  *     member_max   - Size of member_array
    850  *     member_array - (OUT) Array of trunk member structures.
    851  *     member_count - (OUT) Number of trunk members returned.
    852  * Returns:
    853  *     BCM_E_XXX
    854  */
    855 int
    856 bcmx_trunk_member_get(bcm_trunk_t tid, int member_max, 
    857                       bcmx_trunk_member_t *member_array, int *member_count)
    858 {
    859     BCMX_TRUNK_INIT_CHECK;
    860 
    861     BCMX_PARAM_ARRAY_NULL_CHECK(member_max, member_array);
    862     BCMX_PARAM_NULL_CHECK(member_count);
    863 
    864     /* bcm_trunk_member_get is deprecated.
    865      *
    866      * BCMX_UNIT_ITER(bcm_unit, i) {
    867      *     rv = bcm_trunk_member_get(bcm_unit, tid, member_max,
    868      *                             BCMX_TRUNK_MEMBER_T_PTR_TO_BCM(member_array),
    869      *                             member_count);
    870      *     if (BCMX_TRUNK_GET_IS_VALID(bcm_unit, rv)) {
    871      *         return rv;
    872      *     }
    873      * }
    874      */
    875 
    876     return BCM_E_UNAVAIL;
    877 }
    878