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

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 }