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

mirror.c (30245B)


      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/mirror.c
      8  * Purpose:     BCMX Mirroring APIs
      9  */
     10 
     11 #include <sal/core/libc.h>
     12 #include <bcm/types.h>
     13 #include <bcm/topo.h>
     14 
     15 #include <bcmx/mirror.h>
     16 #include <bcmx/lport.h>
     17 #include <bcmx/bcmx.h>
     18 #include <bcmx/lplist.h>
     19 
     20 #include "bcmx_int.h"
     21 
     22 #define BCMX_MIRROR_INIT_CHECK    BCMX_READY_CHECK
     23 
     24 #define BCMX_MIRROR_ERROR_CHECK(_unit, _check, _rv)    \
     25     BCMX_ERROR_CHECK(_unit, _check, _rv)
     26 
     27 #define BCMX_MIRROR_SET_ERROR_CHECK(_unit, _check, _rv)    \
     28     BCMX_SET_ERROR_CHECK(_unit, _check, _rv)
     29 
     30 #define BCMX_MIRROR_DELETE_ERROR_CHECK(_unit, _check, _rv)    \
     31     BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv)
     32 
     33 #define BCMX_MIRROR_GET_IS_VALID(_unit, _rv)    \
     34     BCMX_ERROR_IS_VALID(_unit, _rv)
     35 
     36 
     37 #define BCMX_MIRROR_DESTINATION_T_PTR_TO_BCM(_dest)    \
     38     ((bcm_mirror_destination_t *)(_dest))
     39 
     40 
     41 /* Mirror-to port and preserve-format are cached locally */
     42 static bcmx_lport_t mirror_to_lport = BCMX_LPORT_INVALID;
     43 
     44 /*
     45   Get system-wide state of directed mirroring from the first switch
     46   found.
     47 */
     48 
     49 STATIC int
     50 _bcmx_mirror_directed_get(int *directed)
     51 {
     52     int bcm_unit, i, rv;
     53     bcm_info_t info;
     54 
     55     rv = BCM_E_NONE;
     56     *directed = 0;
     57 
     58     BCMX_UNIT_ITER(bcm_unit, i) {
     59 
     60         BCM_IF_ERROR_RETURN(bcm_info_get(bcm_unit, &info));
     61 
     62         if (info.capability & BCM_INFO_SWITCH) {
     63             rv = bcm_switch_control_get(bcm_unit,
     64                                         bcmSwitchDirectedMirroring,
     65                                         directed);
     66             if (rv == BCM_E_NONE || rv != BCM_E_UNAVAIL) {
     67                 break;
     68             }
     69         }
     70     }
     71 
     72     if (rv == BCM_E_UNAVAIL) {
     73         rv = BCM_E_NONE;
     74     }
     75 
     76     return rv;
     77 }
     78 
     79 
     80 /*
     81  * Function:
     82  *     bcmx_mirror_destination_t_init
     83  */
     84 void
     85 bcmx_mirror_destination_t_init(bcmx_mirror_destination_t *mirror_dest)
     86 {
     87     if (mirror_dest != NULL) {
     88         bcm_mirror_destination_t_init
     89             (BCMX_MIRROR_DESTINATION_T_PTR_TO_BCM(mirror_dest));
     90     }
     91 }
     92 
     93 
     94 /*
     95  * Function:
     96  *      bcmx_mirror_init
     97  */
     98 
     99 int
    100 bcmx_mirror_init(void)
    101 {
    102     int rv = BCM_E_UNAVAIL, tmp_rv;
    103     int i, bcm_unit;
    104 
    105     BCMX_MIRROR_INIT_CHECK;
    106 
    107     BCMX_UNIT_ITER(bcm_unit, i) {
    108         tmp_rv = bcm_mirror_init(bcm_unit);
    109         if (BCM_FAILURE(BCMX_MIRROR_ERROR_CHECK(bcm_unit, tmp_rv, &rv))) {
    110             break;
    111         }
    112     }
    113 
    114     mirror_to_lport = BCMX_LPORT_INVALID;
    115 
    116     return rv;
    117 }
    118 
    119 /*
    120  * Function:
    121  *      bcmx_mirror_mode_set
    122  */
    123 
    124 int
    125 bcmx_mirror_mode_set(int mode)
    126 {
    127     int rv = BCM_E_UNAVAIL, tmp_rv;
    128     int i, bcm_unit;
    129 
    130     BCMX_MIRROR_INIT_CHECK;
    131 
    132     BCMX_UNIT_ITER(bcm_unit, i) {
    133         tmp_rv = bcm_mirror_mode_set(bcm_unit, mode);
    134         BCM_IF_ERROR_RETURN(BCMX_MIRROR_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    135     }
    136 
    137     return rv;
    138 }
    139 
    140 /*
    141  * Function:
    142  *      bcmx_mirror_mode_get
    143  */
    144 
    145 int
    146 bcmx_mirror_mode_get(int *mode)
    147 {
    148     int rv;
    149     int i, bcm_unit;
    150 
    151     BCMX_MIRROR_INIT_CHECK;
    152 
    153     BCMX_PARAM_NULL_CHECK(mode);
    154 
    155     BCMX_UNIT_ITER(bcm_unit, i) {
    156         rv = bcm_mirror_mode_get(bcm_unit, mode);
    157         if (BCMX_MIRROR_GET_IS_VALID(bcm_unit, rv)) {
    158             return rv;
    159         }
    160     }
    161 
    162     *mode = BCM_MIRROR_DISABLE;
    163     return BCM_E_UNAVAIL;
    164 }
    165 
    166 /*
    167  * Function:
    168  *      _bcmx_port_info
    169  *
    170  * A device is a switch if it has one or more Ethernet ports.
    171  * A device is a fabric if it has two or more stack ports.
    172  * A device could be both a switch and a fabric at the same time.
    173  */
    174 
    175 STATIC void
    176 _bcmx_device_info(bcm_port_config_t *config, int *switchlike, int *fabriclike)
    177 {
    178     int eport, sport;
    179 
    180     BCM_PBMP_COUNT(config->e, eport);
    181     BCM_PBMP_COUNT(config->stack_ext, sport);
    182     *switchlike = (eport > 0);
    183     *fabriclike = (sport > 1);
    184 }
    185 
    186 STATIC int
    187 _bcmx_undirected_mirror_fabric_set(int unit,
    188                                    bcm_port_config_t *config,
    189                                    bcm_module_t mirror_modid)
    190 {
    191     int               rv;
    192     bcm_port_t        hport;
    193     bcm_pbmp_t        pbmp;
    194 
    195     BCM_PBMP_ITER(config->stack_ext, hport) {
    196         /*
    197          *  Fabric device needs to use the UC bitmap
    198          *  to set each stack port individually
    199          */
    200         BCM_PBMP_CLEAR(pbmp);
    201         BCM_IF_ERROR_RETURN
    202             (bcm_stk_ucbitmap_get(unit, hport,
    203                                   mirror_modid, &pbmp));
    204         /* Remove the CMIC from the bitmap */
    205         BCM_PBMP_REMOVE(pbmp, config->cpu);
    206         rv = bcm_mirror_to_pbmp_set(unit, hport, pbmp);
    207         if (rv != BCM_E_UNAVAIL) {
    208             BCM_IF_ERROR_RETURN(rv);
    209         }
    210     }
    211     return BCM_E_NONE;
    212 }
    213 
    214 /*
    215  * Function:
    216  *      _bcmx_undirected_mirror_stk_clear
    217  *
    218  * Clear stack ports of any undirected mirroring forwarding
    219  * configuration.
    220  */
    221 
    222 STATIC int
    223 _bcmx_undirected_mirror_stk_clear(int unit)
    224 {
    225     int               rv;
    226     bcm_port_config_t config;
    227     bcm_port_t        hport;
    228     bcm_pbmp_t        pbmp;
    229 
    230 
    231     BCM_PBMP_CLEAR(pbmp);
    232     BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
    233     BCM_PBMP_ITER(config.stack_ext, hport) {
    234         rv = bcm_mirror_to_pbmp_set(unit, hport, pbmp);
    235         if (rv != BCM_E_UNAVAIL) {
    236             BCM_IF_ERROR_RETURN(rv);
    237         }
    238     }
    239     return BCM_E_NONE;
    240 }
    241 
    242 /*
    243  * Function:
    244  *      bcmx_mirror_to_set
    245  */
    246 
    247 int
    248 bcmx_mirror_to_set(bcmx_lport_t port)
    249 {
    250     int bcm_unit, i;
    251     bcm_port_t port_on_src;
    252     bcm_module_t mirror_modid;
    253     int unit_src;
    254     bcm_port_t modport;
    255     bcm_port_config_t config;
    256     int switchlike, fabriclike;
    257 
    258     BCMX_MIRROR_INIT_CHECK;
    259 
    260     BCM_IF_ERROR_RETURN
    261         (_bcmx_dest_to_unit_port(port,
    262                                  &unit_src, &port_on_src,
    263                                  BCMX_DEST_CONVERT_DEFAULT));
    264 
    265     BCM_IF_ERROR_RETURN
    266         (_bcmx_dest_to_modid_port(port,
    267                                   &mirror_modid, &modport,
    268                                   BCMX_DEST_CONVERT_DEFAULT));
    269 
    270     mirror_to_lport = port;
    271     BCMX_UNIT_ITER(bcm_unit, i) {
    272         if (bcm_unit == unit_src) {
    273             BCM_IF_ERROR_RETURN(bcm_mirror_to_set(bcm_unit, port_on_src));
    274         } else {
    275             BCM_IF_ERROR_RETURN(bcm_port_config_get(bcm_unit, &config));
    276             _bcmx_device_info(&config, &switchlike, &fabriclike);
    277 
    278             if (fabriclike) {
    279                 BCM_IF_ERROR_RETURN
    280                     (_bcmx_undirected_mirror_fabric_set(bcm_unit, &config,
    281                                                         mirror_modid));
    282             }
    283             if (switchlike) {
    284                 int port_on_src;
    285 
    286                 BCM_IF_ERROR_RETURN
    287                     (bcm_topo_port_get(bcm_unit, mirror_modid,
    288                                        &port_on_src));
    289                 BCM_IF_ERROR_RETURN
    290                     (bcm_mirror_to_set(bcm_unit, port_on_src));
    291             }
    292         }
    293     }
    294 
    295     return BCM_E_NONE;
    296 }
    297 
    298 
    299 /*
    300  * Function:
    301  *      bcmx_mirror_to_get
    302  */
    303 
    304 int
    305 bcmx_mirror_to_get(bcmx_lport_t *port)
    306 {
    307     BCMX_MIRROR_INIT_CHECK;
    308 
    309     BCMX_PARAM_NULL_CHECK(port);
    310 
    311     *port = mirror_to_lport;
    312 
    313     return BCM_E_NONE;
    314 }
    315 
    316 
    317 /*
    318  * Function:
    319  *      bcmx_mirror_ingress_set
    320  */
    321 
    322 int
    323 bcmx_mirror_ingress_set(bcmx_lport_t port, int val)
    324 {
    325     int         bcm_unit;
    326     bcm_port_t  bcm_port;
    327 
    328     BCMX_MIRROR_INIT_CHECK;
    329 
    330     BCM_IF_ERROR_RETURN
    331         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    332                                  BCMX_DEST_CONVERT_DEFAULT));
    333 
    334     return bcm_mirror_ingress_set(bcm_unit, bcm_port, val);
    335 }
    336 
    337 
    338 /*
    339  * Function:
    340  *      bcmx_mirror_ingress_get
    341  */
    342 
    343 int
    344 bcmx_mirror_ingress_get(bcmx_lport_t port, int *val)
    345 {
    346     int         bcm_unit;
    347     bcm_port_t  bcm_port;
    348 
    349     BCMX_MIRROR_INIT_CHECK;
    350 
    351     BCM_IF_ERROR_RETURN
    352         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    353                                  BCMX_DEST_CONVERT_DEFAULT));
    354 
    355     return bcm_mirror_ingress_get(bcm_unit, bcm_port, val);
    356 }
    357 
    358 
    359 /*
    360  * Function:
    361  *      bcmx_mirror_egress_set
    362  */
    363 
    364 int
    365 bcmx_mirror_egress_set(bcmx_lport_t port, int val)
    366 {
    367     int         bcm_unit;
    368     bcm_port_t  bcm_port;
    369 
    370     BCMX_MIRROR_INIT_CHECK;
    371 
    372     BCM_IF_ERROR_RETURN
    373         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    374                                  BCMX_DEST_CONVERT_DEFAULT));
    375 
    376     return bcm_mirror_egress_set(bcm_unit, bcm_port, val);
    377 }
    378 
    379 
    380 /*
    381  * Function:
    382  *      bcmx_mirror_egress_get
    383  */
    384 
    385 int
    386 bcmx_mirror_egress_get(bcmx_lport_t port, int *val)
    387 {
    388     int         bcm_unit;
    389     bcm_port_t  bcm_port;
    390 
    391     BCMX_MIRROR_INIT_CHECK;
    392 
    393     BCM_IF_ERROR_RETURN
    394         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    395                                  BCMX_DEST_CONVERT_DEFAULT));
    396 
    397     return bcm_mirror_egress_get(bcm_unit, bcm_port, val);
    398 }
    399 
    400 
    401 /*
    402  * Function:
    403  *      bcmx_mirror_fabric_list_set
    404  */
    405 
    406 int
    407 bcmx_mirror_fabric_list_set(bcmx_lport_t port, bcmx_lplist_t lplist)
    408 {
    409     int bcm_unit, i;
    410     int rv = BCM_E_UNAVAIL, tmp_rv;
    411     bcm_pbmp_t pbmp;
    412     int         lport_unit;
    413     bcm_port_t  lport_port;
    414 
    415     BCMX_MIRROR_INIT_CHECK;
    416 
    417     BCM_IF_ERROR_RETURN
    418         (_bcmx_dest_to_unit_port(port,
    419                                  &lport_unit, &lport_port,
    420                                  BCMX_DEST_CONVERT_DEFAULT));
    421 
    422     BCMX_UNIT_ITER(bcm_unit, i) {
    423         BCMX_LPLIST_TO_PBMP(lplist, bcm_unit, pbmp);
    424         if (BCM_PBMP_NOT_NULL(pbmp)) {
    425             tmp_rv = bcm_mirror_to_pbmp_set(bcm_unit, lport_port,
    426                                             pbmp);
    427             BCM_IF_ERROR_RETURN
    428                 (BCMX_MIRROR_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    429         }
    430     }
    431 
    432     return rv;
    433 }
    434 
    435 
    436 /*
    437  * Function:
    438  *      bcmx_mirror_fabric_list_get
    439  */
    440 
    441 int
    442 bcmx_mirror_fabric_list_get(bcmx_lport_t port, bcmx_lplist_t *lplist)
    443 {
    444     int bcm_unit, i;
    445     int rv = BCM_E_UNAVAIL, tmp_rv;
    446     bcm_pbmp_t pbmp;
    447     int         lport_unit;
    448     bcm_port_t  lport_port;
    449 
    450     BCMX_MIRROR_INIT_CHECK;
    451 
    452     BCM_IF_ERROR_RETURN
    453         (_bcmx_dest_to_unit_port(port,
    454                                  &lport_unit, &lport_port,
    455                                  BCMX_DEST_CONVERT_DEFAULT));
    456 
    457     if (BCMX_LPLIST_IS_NULL(lplist)) {
    458         return BCM_E_PARAM;
    459     }
    460 
    461     BCMX_UNIT_ITER(bcm_unit, i) {
    462         tmp_rv = bcm_mirror_to_pbmp_get(bcm_unit,
    463                                         lport_port,
    464                                         &pbmp);
    465         if (BCMX_MIRROR_GET_IS_VALID(bcm_unit, tmp_rv)) {
    466             rv = tmp_rv;
    467             if (BCM_FAILURE(tmp_rv)) {
    468                 break;
    469             }
    470             if (BCM_PBMP_NOT_NULL(pbmp)) {
    471                 BCMX_LPLIST_PBMP_ADD(lplist, bcm_unit, pbmp);
    472             }
    473         }
    474     }
    475 
    476     return rv;
    477 }
    478 
    479 
    480 /*
    481  * Function:
    482  *      _bcmx_directed_mirror_port_set
    483  *
    484  * When the system supports directed mirroring, program the mirrored
    485  * port and the MTP on the unit with the mirrored port.
    486  */
    487 
    488 STATIC int
    489 _bcmx_directed_mirror_port_set(bcmx_lport_t lport,
    490                                bcmx_lport_t dest_lport,
    491                                uint32 flags)
    492 {
    493     int          bcm_unit, i;
    494     int          lport_unit;
    495     bcm_port_t   lport_port;
    496     bcm_module_t dest_modid;
    497     bcm_port_t   dest_modport;
    498 
    499     BCM_IF_ERROR_RETURN
    500         (_bcmx_dest_to_unit_port(lport,
    501                                  &lport_unit, &lport_port,
    502                                  BCMX_DEST_CONVERT_DEFAULT));
    503     BCM_IF_ERROR_RETURN
    504         (_bcmx_dest_to_modid_port(dest_lport,
    505                                   &dest_modid, &dest_modport,
    506                                   BCMX_DEST_CONVERT_DEFAULT));
    507 
    508     /* Clear any existing undirected mirroring settings */
    509     BCMX_UNIT_ITER(bcm_unit, i) {
    510         BCM_IF_ERROR_RETURN
    511             (_bcmx_undirected_mirror_stk_clear(bcm_unit));
    512 
    513     }
    514 
    515     /* set mirror port and MTP */
    516     BCM_IF_ERROR_RETURN(bcm_mirror_port_set(lport_unit, lport_port,
    517                                             dest_modid, dest_modport,
    518                                             flags));
    519     
    520     return BCM_E_NONE;
    521 }
    522 
    523 /*
    524  * Function:
    525  *      _bcmx_undirected_mirror_port_set
    526  *
    527  * When the system does not support directed mirroring, program the
    528  * stack ports to be MTPs on all units that are not the unit the
    529  * system MTP is on.
    530  *
    531  * If mirroring is being disabled, only disable the mirror port
    532  * not any intermediate fabrics or MTP only units, as they may still
    533  * be in use by other mirrored ports.
    534  */
    535 
    536 STATIC int
    537 _bcmx_undirected_mirror_port_set(bcmx_lport_t lport,
    538                                  bcmx_lport_t dest_lport,
    539                                  uint32 flags)
    540 {
    541     int               bcm_unit, i;
    542     bcm_module_t      mirror_modid;
    543     int               enable;
    544     int               lport_unit, dest_unit;
    545     bcm_port_t        lport_port, dest_port, dest_modport;
    546     bcm_port_config_t config;
    547     int               switchlike, fabriclike;
    548     
    549 
    550     BCM_IF_ERROR_RETURN
    551         (_bcmx_dest_to_unit_port(lport,
    552                                  &lport_unit, &lport_port,
    553                                  BCMX_DEST_CONVERT_DEFAULT));
    554     BCM_IF_ERROR_RETURN
    555         (_bcmx_dest_to_unit_port(dest_lport,
    556                                  &dest_unit, &dest_port,
    557                                  BCMX_DEST_CONVERT_DEFAULT));
    558     BCM_IF_ERROR_RETURN
    559         (_bcmx_dest_to_modid_port(dest_lport,
    560                                   &mirror_modid, &dest_modport,
    561                                   BCMX_DEST_CONVERT_DEFAULT));
    562 
    563     enable = ((flags & (BCM_MIRROR_PORT_INGRESS |
    564                         BCM_MIRROR_PORT_EGRESS  |
    565                         BCM_MIRROR_PORT_ENABLE)) != 0);
    566 
    567     BCMX_UNIT_ITER(bcm_unit, i) {
    568         if (bcm_unit == lport_unit) {
    569             /* bcm_unit is the mirrored port unit. If this happens to
    570                be the MTP unit, too, then the MTP will be taken care
    571                of here. */
    572             BCM_IF_ERROR_RETURN
    573                 (bcm_mirror_port_set(bcm_unit, lport_port,
    574                                      mirror_modid, dest_modport, flags));
    575         } else if (bcm_unit == dest_unit) {
    576             BCM_IF_ERROR_RETURN
    577                 (bcm_mirror_port_set(bcm_unit, BCM_GPORT_INVALID,
    578                                      mirror_modid, dest_modport, flags));
    579         } else {
    580             /* bcm_unit is neither a mirrored port unit or an MTP unit */
    581             if (enable) {
    582                 BCM_IF_ERROR_RETURN(bcm_port_config_get(bcm_unit, &config));
    583                 _bcmx_device_info(&config, &switchlike, &fabriclike);
    584 
    585                 if (fabriclike) {
    586                     BCM_IF_ERROR_RETURN
    587                         (_bcmx_undirected_mirror_fabric_set(bcm_unit, &config,
    588                                                             mirror_modid));
    589                 }
    590                 if (switchlike) {
    591                     BCM_IF_ERROR_RETURN
    592                         (bcm_mirror_port_set(bcm_unit, BCM_GPORT_INVALID,
    593                                              mirror_modid, dest_modport,
    594                                              flags));
    595                 }
    596             }
    597         }
    598     }
    599 
    600     return BCM_E_NONE;
    601 }
    602 
    603 /*
    604  * Function:
    605  *      bcmx_mirror_port_set
    606  */
    607 
    608 int
    609 bcmx_mirror_port_set(bcmx_lport_t lport,
    610 		     bcmx_lport_t dest_lport,
    611 		     uint32 flags)
    612 {
    613     int directed;
    614 
    615     BCMX_MIRROR_INIT_CHECK;
    616 
    617     BCMX_LPORT_CHECK(lport);
    618     BCMX_LPORT_CHECK(dest_lport);
    619 
    620     BCM_IF_ERROR_RETURN(_bcmx_mirror_directed_get(&directed));
    621 
    622     return directed ?
    623         _bcmx_directed_mirror_port_set(lport, dest_lport, flags) :
    624         _bcmx_undirected_mirror_port_set(lport, dest_lport, flags);
    625 }
    626 
    627 
    628 /*
    629  * Function:
    630  *      bcmx_mirror_port_get
    631  * Notes:
    632  *      dest_lport is undefined when no flags are set in returning function.
    633  */
    634 
    635 int
    636 bcmx_mirror_port_get(bcmx_lport_t lport,
    637 		     bcmx_lport_t *dest_lport,
    638 		     uint32 *flags)
    639 {
    640     bcm_module_t  dest_mod;
    641     bcm_port_t    dest_port;
    642     int           bcm_unit;
    643     bcm_port_t    bcm_port;
    644 
    645     BCMX_MIRROR_INIT_CHECK;
    646 
    647     BCMX_PARAM_NULL_CHECK(dest_lport);
    648     BCMX_PARAM_NULL_CHECK(flags);
    649 
    650     BCM_IF_ERROR_RETURN
    651         (_bcmx_dest_to_unit_port(lport, &bcm_unit, &bcm_port,
    652                                  BCMX_DEST_CONVERT_DEFAULT));
    653 
    654     BCM_IF_ERROR_RETURN(bcm_mirror_port_get(bcm_unit, bcm_port,
    655                                             &dest_mod, &dest_port,
    656                                             flags));
    657 
    658     /*
    659      * Convert only when flags is set, since dest_mod/dest_port are
    660      * undefined when BCM returns no flags set.
    661      */
    662     if (*flags != 0) {
    663         BCM_IF_ERROR_RETURN
    664             (_bcmx_dest_from_modid_port(dest_lport, dest_mod, dest_port,
    665                                         BCMX_DEST_CONVERT_DEFAULT));
    666     }
    667 
    668     return BCM_E_NONE;
    669 }
    670 
    671 
    672 /*
    673  * Function:
    674  *      bcmx_mirror_vlan_set
    675  */
    676 
    677 int
    678 bcmx_mirror_vlan_set(bcmx_lport_t lport,
    679 		     uint16 tpid,
    680 		     uint16 vlan)
    681 {
    682     int         bcm_unit;
    683     bcm_port_t  bcm_port;
    684 
    685     BCMX_MIRROR_INIT_CHECK;
    686 
    687     BCM_IF_ERROR_RETURN
    688         (_bcmx_dest_to_unit_port(lport, &bcm_unit, &bcm_port,
    689                                  BCMX_DEST_CONVERT_DEFAULT));
    690 
    691     return bcm_mirror_vlan_set(bcm_unit, bcm_port, tpid, vlan);
    692 }
    693 
    694 
    695 /*
    696  * Function:
    697  *      bcmx_mirror_vlan_get
    698  */
    699 
    700 int
    701 bcmx_mirror_vlan_get(bcmx_lport_t lport,
    702 		     uint16 *tpid,
    703 		     uint16 *vlan)
    704 {
    705     int         bcm_unit;
    706     bcm_port_t  bcm_port;
    707 
    708     BCMX_MIRROR_INIT_CHECK;
    709 
    710     BCMX_PARAM_NULL_CHECK(tpid);
    711     BCMX_PARAM_NULL_CHECK(vlan);
    712 
    713     BCM_IF_ERROR_RETURN
    714         (_bcmx_dest_to_unit_port(lport, &bcm_unit, &bcm_port,
    715                                  BCMX_DEST_CONVERT_DEFAULT));
    716 
    717     return bcm_mirror_vlan_get(bcm_unit, bcm_port, tpid, vlan);
    718 }
    719 
    720 
    721 /*
    722  * Function:
    723  *     _bcmx_directed_mirror_port_dest_add
    724  *
    725  * Notes:
    726  *     When the system supports directed mirroring, add the
    727  *     destination mirror on the unit with the mirrored port.
    728  */
    729 STATIC int
    730 _bcmx_directed_mirror_port_dest_add(bcmx_lport_t port, uint32 flags,
    731                                     bcm_gport_t mirror_dest_id)
    732 {
    733     int         i;
    734     int         bcm_unit;
    735     bcm_port_t  bcm_port;
    736 
    737     /* Clear any existing undirected mirroring settings */
    738     BCMX_UNIT_ITER(bcm_unit, i) {
    739         BCM_IF_ERROR_RETURN
    740             (_bcmx_undirected_mirror_stk_clear(bcm_unit));
    741 
    742     }
    743 
    744     BCM_IF_ERROR_RETURN
    745         (_bcmx_dest_to_unit_port(port,
    746                                  &bcm_unit, &bcm_port,
    747                                  BCMX_DEST_CONVERT_DEFAULT));
    748 
    749     return bcm_mirror_port_dest_add(bcm_unit, bcm_port,
    750                                     flags, mirror_dest_id);
    751 }
    752 
    753 /*
    754  * Function:
    755  *     _bcmx_undirected_mirror_port_dest_add
    756  * Notes:
    757  *     Non-direct (undirected) mirroring mode only supports
    758  *     single mirroring destination.
    759  *
    760  *     Assumes that BCM API will handle cases where
    761  *     the 'same' port is being added (need to check if BCM returns
    762  *     an error, if so, it should at least return BCM_E_EXISTS.
    763  */
    764 STATIC int
    765 _bcmx_undirected_mirror_port_dest_add(bcmx_lport_t port, uint32 flags,
    766                                       bcm_gport_t mirror_dest_id)
    767 {
    768     int          bcm_unit, i;
    769     int          mirrored_unit;
    770     bcm_port_t   mirrored_port;
    771     bcm_port_config_t config;
    772     bcmx_mirror_destination_t mirror_dest;
    773     bcm_module_t mirror_modid;
    774     int          switchlike, fabriclike;
    775 
    776     BCM_IF_ERROR_RETURN
    777         (_bcmx_dest_to_unit_port(port,
    778                                  &mirrored_unit, &mirrored_port,
    779                                  BCMX_DEST_CONVERT_DEFAULT));
    780 
    781     bcmx_mirror_destination_t_init(&mirror_dest);
    782     BCM_IF_ERROR_RETURN
    783         (bcmx_mirror_destination_get(mirror_dest_id, &mirror_dest));
    784 
    785     mirror_modid = BCM_GPORT_MODPORT_MODID_GET(mirror_dest.gport);
    786 
    787     if (mirror_modid < 0) {
    788         return BCM_E_PORT;
    789     }
    790 
    791     BCMX_UNIT_ITER(bcm_unit, i) {
    792         if (bcm_unit == mirrored_unit) {
    793             /* bcm_unit is the mirrored port unit. If this happens to
    794                be the MTP unit, too, then the MTP will be taken care
    795                of here. */
    796             BCM_IF_ERROR_RETURN
    797                 (bcm_mirror_port_dest_add(mirrored_unit, mirrored_port,
    798                                           flags, mirror_dest_id));
    799         } else {
    800             /* bcm_unit is not a mirrored port unit */
    801             BCM_IF_ERROR_RETURN(bcm_port_config_get(bcm_unit, &config));
    802             _bcmx_device_info(&config, &switchlike, &fabriclike);
    803 
    804             if (fabriclike) {
    805                 BCM_IF_ERROR_RETURN
    806                     (_bcmx_undirected_mirror_fabric_set(bcm_unit, &config,
    807                                                         mirror_modid));
    808             }
    809             if (switchlike) {
    810                 BCM_IF_ERROR_RETURN
    811                     (bcm_mirror_port_dest_add(bcm_unit,BCM_GPORT_INVALID,
    812                                               flags, mirror_dest_id));
    813             }
    814         }
    815     }
    816 
    817     return BCM_E_NONE;
    818 }
    819 
    820 /*
    821  * Function:
    822  *     bcmx_mirror_port_dest_add
    823  */
    824 int
    825 bcmx_mirror_port_dest_add(bcmx_lport_t port, uint32 flags,
    826                           bcm_gport_t mirror_dest_id)
    827 {
    828     int directed;
    829 
    830     BCMX_MIRROR_INIT_CHECK;
    831 
    832     BCMX_LPORT_CHECK(port);
    833 
    834     BCM_IF_ERROR_RETURN(_bcmx_mirror_directed_get(&directed));
    835 
    836     return directed ?
    837         _bcmx_directed_mirror_port_dest_add(port, flags, mirror_dest_id)   :
    838         _bcmx_undirected_mirror_port_dest_add(port, flags, mirror_dest_id);
    839 
    840 }
    841 
    842 /*
    843  * Function:
    844  *     _bcmx_undirected_dest_delete_transit
    845  *
    846  * Delete any "transit device" settings programmed by
    847  *   _bcmx_undirected_mirror_port_dest_add()
    848  */
    849 STATIC int
    850 _bcmx_undirected_dest_delete_transit(bcmx_lport_t port,
    851                                      uint32 flags,
    852                                      bcm_gport_t mirror_dest_id)
    853 {
    854     int        i, bcm_unit;
    855     int        mirrored_unit;
    856     bcm_port_t mirrored_port;
    857     int        switchlike, fabriclike;
    858     bcm_port_config_t config;
    859 
    860     BCM_IF_ERROR_RETURN
    861         (_bcmx_dest_to_unit_port(port,
    862                                  &mirrored_unit, &mirrored_port,
    863                                  BCMX_DEST_CONVERT_DEFAULT));
    864 
    865     BCMX_UNIT_ITER(bcm_unit, i) {
    866         if (bcm_unit != mirrored_unit) {
    867             BCM_IF_ERROR_RETURN(bcm_port_config_get(bcm_unit, &config));
    868             _bcmx_device_info(&config, &switchlike, &fabriclike);
    869             if (switchlike) {
    870                 BCM_IF_ERROR_RETURN
    871                     (bcm_mirror_port_dest_delete(bcm_unit,
    872                                                  BCM_GPORT_INVALID,
    873                                                  flags, mirror_dest_id));
    874             }
    875         }
    876     }
    877 
    878     return BCM_E_NONE;
    879 }
    880 
    881 
    882 /*
    883  * Function:
    884  *     bcmx_mirror_port_dest_delete
    885  */
    886 int
    887 bcmx_mirror_port_dest_delete(bcmx_lport_t port, uint32 flags,
    888                              bcm_gport_t mirror_dest_id)
    889 {
    890     int         bcm_unit;
    891     bcm_port_t  bcm_port;
    892     int         directed;
    893 
    894     BCMX_MIRROR_INIT_CHECK;
    895 
    896     BCM_IF_ERROR_RETURN(_bcmx_mirror_directed_get(&directed));
    897     if (!directed) {
    898         BCM_IF_ERROR_RETURN
    899             (_bcmx_undirected_dest_delete_transit(port,
    900                                                   flags,
    901                                                   mirror_dest_id));
    902     }
    903     BCM_IF_ERROR_RETURN
    904         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    905                                  BCMX_DEST_CONVERT_DEFAULT));
    906 
    907     return bcm_mirror_port_dest_delete(bcm_unit, bcm_port, flags,
    908                                        mirror_dest_id);
    909 }
    910 
    911 /*
    912  * Function:
    913  *     bcmx_mirror_port_dest_delete_all
    914  */
    915 int
    916 bcmx_mirror_port_dest_delete_all(bcmx_lport_t port, uint32 flags)
    917 {
    918     int         bcm_unit;
    919     bcm_port_t  bcm_port;
    920     int         directed;
    921 
    922     BCMX_MIRROR_INIT_CHECK;
    923 
    924     BCM_IF_ERROR_RETURN(_bcmx_mirror_directed_get(&directed));
    925     if (!directed) {
    926         bcm_gport_t mirror_dest_id;
    927         int mirror_dest_count;
    928 
    929         /* Delete any transit device configuration */
    930         BCM_IF_ERROR_RETURN
    931             (bcmx_mirror_port_dest_get(port, flags,
    932                                        1, &mirror_dest_id,
    933                                        &mirror_dest_count));
    934 
    935         if (mirror_dest_count > 0) {
    936             BCM_IF_ERROR_RETURN
    937                 (_bcmx_undirected_dest_delete_transit(port,
    938                                                       flags,
    939                                                       mirror_dest_id));
    940         }
    941     }
    942 
    943     BCM_IF_ERROR_RETURN
    944         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    945                                  BCMX_DEST_CONVERT_DEFAULT));
    946 
    947     return bcm_mirror_port_dest_delete_all(bcm_unit, bcm_port, flags);
    948 }
    949 
    950 
    951 /*
    952  * Function:
    953  *     bcmx_mirror_port_dest_get
    954  */
    955 int
    956 bcmx_mirror_port_dest_get(bcmx_lport_t port, uint32 flags,
    957                           int mirror_dest_size, bcm_gport_t *mirror_dest_id,
    958                           int *mirror_dest_count)
    959 {
    960     int         bcm_unit;
    961     bcm_port_t  bcm_port;
    962 
    963     BCMX_MIRROR_INIT_CHECK;
    964 
    965     BCMX_PARAM_ARRAY_NULL_CHECK(mirror_dest_size, mirror_dest_id);
    966     BCMX_PARAM_NULL_CHECK(mirror_dest_count);
    967 
    968     BCM_IF_ERROR_RETURN
    969         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    970                                  BCMX_DEST_CONVERT_DEFAULT));
    971 
    972     return bcm_mirror_port_dest_get(bcm_unit, bcm_port, flags,
    973                                     mirror_dest_size, mirror_dest_id,
    974                                     mirror_dest_count);
    975 }
    976 
    977 
    978 /*
    979  * Function:
    980  *     bcmx_mirror_destination_create
    981  */
    982 int
    983 bcmx_mirror_destination_create(bcmx_mirror_destination_t *mirror_dest)
    984 {
    985     int          rv = BCM_E_UNAVAIL, tmp_rv;
    986     int          i, bcm_unit;
    987     bcm_gport_t  gport_orig;
    988     uint32       flags_orig;
    989 
    990     BCMX_MIRROR_INIT_CHECK;
    991 
    992     BCMX_PARAM_NULL_CHECK(mirror_dest);
    993 
    994     /*
    995      * Need to save original 'gport' value and copy it back to structure
    996      * for each iteration since BCM API may change its value (this happens
    997      * when the MTP does not reside in the local unit).
    998      */
    999     gport_orig = mirror_dest->gport;
   1000 
   1001     /* Store original 'xxx_WITH_ID' flag bit */
   1002     flags_orig = mirror_dest->flags & BCM_MIRROR_DEST_WITH_ID;
   1003 
   1004     BCMX_UNIT_ITER(bcm_unit, i) {
   1005         mirror_dest->gport = gport_orig;
   1006 
   1007         tmp_rv = bcm_mirror_destination_create
   1008             (bcm_unit,
   1009              BCMX_MIRROR_DESTINATION_T_PTR_TO_BCM(mirror_dest));
   1010 
   1011         if (BCM_FAILURE(BCMX_MIRROR_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv))) {
   1012             break;
   1013         }
   1014 
   1015         /*
   1016          * Use the ID from first successful 'create' if mirror destination ID
   1017          * is not specified.
   1018          */
   1019         if (!(mirror_dest->flags & BCM_MIRROR_DEST_WITH_ID)) {
   1020             if (BCM_SUCCESS(tmp_rv)) {
   1021                 mirror_dest->flags |= BCM_MIRROR_DEST_WITH_ID;
   1022             }
   1023         }
   1024     }
   1025 
   1026     /* Restore 'xxx_WITH_ID' flag bit */
   1027     mirror_dest->flags &= ~BCM_MIRROR_DEST_WITH_ID;
   1028     mirror_dest->flags |= flags_orig;
   1029 
   1030     return rv;
   1031 }
   1032 
   1033 /*
   1034  * Function:
   1035  *     bcmx_mirror_destination_destroy
   1036  */
   1037 int
   1038 bcmx_mirror_destination_destroy(bcm_gport_t mirror_dest_id)
   1039 {
   1040     int  rv = BCM_E_UNAVAIL, tmp_rv;
   1041     int  i, bcm_unit;
   1042 
   1043     BCMX_MIRROR_INIT_CHECK;
   1044 
   1045     BCMX_UNIT_ITER(bcm_unit, i) {
   1046         tmp_rv = bcm_mirror_destination_destroy(bcm_unit, mirror_dest_id);
   1047         BCM_IF_ERROR_RETURN
   1048             (BCMX_MIRROR_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1049     }
   1050 
   1051     return rv;
   1052 }
   1053 
   1054 
   1055 /*
   1056  * Function:
   1057  *     _bcmx_undirected_mirror_destination_get
   1058  *
   1059  * Iterate on units and return mirror destination information from
   1060  * first successful call on unit that returns an MTP that is
   1061  * a front-panel (ethernet) port.
   1062  */
   1063 int
   1064 _bcmx_undirected_mirror_destination_get(bcm_gport_t mirror_dest_id, 
   1065                                         bcmx_mirror_destination_t *mirror_dest)
   1066 {
   1067     int           rv;
   1068     int           i, bcm_unit;
   1069     bcm_port_encap_config_t mode;
   1070     uint32        stk_mode;
   1071 
   1072     BCMX_UNIT_ITER(bcm_unit, i) {
   1073         rv = bcm_mirror_destination_get(bcm_unit, mirror_dest_id,
   1074                                         BCMX_MIRROR_DESTINATION_T_PTR_TO_BCM
   1075                                         (mirror_dest));
   1076 
   1077         if (!BCMX_MIRROR_GET_IS_VALID(bcm_unit, rv)) {
   1078             continue;
   1079         }
   1080 
   1081         /*
   1082          * The MTP must be a modport, so skip if not.
   1083          */
   1084         if (BCM_FAILURE(rv) || !BCM_GPORT_IS_MODPORT(mirror_dest->gport)) {
   1085             continue;
   1086         }
   1087             
   1088         /* make sure the mirror_dest is an Ethernet port. In
   1089            undirected mode, that's the only kind of port an MTP can
   1090            be. */
   1091 
   1092         sal_memset(&mode, 0, sizeof(mode));
   1093         rv = bcm_port_encap_config_get(bcm_unit, mirror_dest->gport, &mode);
   1094         if (BCM_FAILURE(rv)) {
   1095             continue;
   1096         }
   1097         
   1098         rv = bcm_stk_mode_get(bcm_unit, &stk_mode);
   1099         if (BCM_FAILURE(rv)) {
   1100             continue;
   1101         }
   1102         
   1103         if (mode.encap == BCM_PORT_ENCAP_IEEE && stk_mode != BCM_STK_SL) {
   1104             /* Ethernet port found */
   1105             return BCM_E_NONE;
   1106         }
   1107     }
   1108 
   1109     return BCM_E_UNAVAIL;
   1110 }
   1111 
   1112 
   1113 /*
   1114  * Function:
   1115  *     bcmx_mirror_destination_get
   1116  */
   1117 int
   1118 bcmx_mirror_destination_get(bcm_gport_t mirror_dest_id, 
   1119                             bcmx_mirror_destination_t *mirror_dest)
   1120 {
   1121     int  rv;
   1122     int  i, bcm_unit;
   1123     int  directed;
   1124 
   1125     BCMX_MIRROR_INIT_CHECK;
   1126 
   1127     BCMX_PARAM_NULL_CHECK(mirror_dest);
   1128 
   1129     /*
   1130      * Directed Mirroring -
   1131      *   Return information from the first successful call on a unit.
   1132      *
   1133      * Non-Directed Mirroring -
   1134      *   Needs special handling.
   1135      *   Iterate over units until a front-panel MTP is found.
   1136      */
   1137 
   1138     BCM_IF_ERROR_RETURN(_bcmx_mirror_directed_get(&directed));
   1139 
   1140     if (directed) {
   1141         BCMX_UNIT_ITER(bcm_unit, i) {
   1142             rv = bcm_mirror_destination_get(bcm_unit, mirror_dest_id,
   1143                                             BCMX_MIRROR_DESTINATION_T_PTR_TO_BCM
   1144                                             (mirror_dest));
   1145             if (BCMX_MIRROR_GET_IS_VALID(bcm_unit, rv)) {
   1146                 return rv;
   1147             }
   1148         }
   1149 
   1150     } else {
   1151         return _bcmx_undirected_mirror_destination_get(mirror_dest_id,
   1152                                                        mirror_dest);
   1153     }
   1154 
   1155     return BCM_E_UNAVAIL;
   1156 }
   1157