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 (28435B)


      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:        l2.c
      8  * Purpose:
      9  * Requires:
     10  */
     11 
     12 #include <sal/types.h>
     13 #include <sal/appl/sal.h>
     14 #include <sal/appl/io.h>
     15 #include <sal/core/libc.h>
     16 #include <sal/core/thread.h>
     17 #include <shared/bsl.h>
     18 #include <bcmx/lplist.h>
     19 #include <bcmx/lport.h>
     20 #include <bcmx/bcmx.h>
     21 #include <bcmx/l2.h>
     22 
     23 #include <bcm/l2.h>
     24 #include <bcm/error.h>
     25 
     26 #include <appl/diag/shell.h>
     27 #include <appl/diag/system.h>
     28 #include <appl/diag/parse.h>
     29 
     30 #if defined(INCLUDE_BCMX)
     31 
     32 #include "bcmx.h"
     33 
     34 static int l2n_report = TRUE;
     35 static int l2n_inserts = 0;
     36 static int l2n_deletes = 0;
     37 static int l2n_insert_calls = 0;
     38 static int l2n_delete_calls = 0;
     39 static int l2n_native_inserts = 0;
     40 static int l2n_native_deletes = 0;
     41 static int l2n_insert = FALSE;
     42 
     43 STATIC void
     44 bcmxdiag_l2_notify(bcmx_l2_addr_t *addr, int insert, void *cookie)
     45 {
     46     char flags_str[200];
     47     int  flag_str_left;
     48     int count = 0;
     49     int i;
     50     int rv;
     51 
     52     if (insert) {
     53         l2n_inserts++;
     54     } else {
     55         l2n_deletes++;
     56     }
     57     if (addr->flags & BCM_L2_NATIVE) {
     58         if (insert) {
     59             l2n_native_inserts++;
     60         } else {
     61             l2n_native_deletes++;
     62         }
     63     }
     64 
     65     if (l2n_report) {
     66         cli_out("BCMX L2 %s: V=0x%03x MAC=0x%02x%02x%02x"
     67                 "%02x%02x%02x %s uport %s (0x%x) unit %d\n",
     68                 insert ? "ADD" : "DEL",
     69                 addr->vid,
     70                 addr->mac[0], addr->mac[1], addr->mac[2],
     71                 addr->mac[3], addr->mac[4], addr->mac[5],
     72                 insert ? "to" : "from", 
     73                 bcmx_lport_to_uport_str(addr->lport),
     74                 addr->lport, addr->bcm_unit);
     75 
     76         if (addr->flags != 0) {
     77             flags_str[0] = '\0';
     78             flag_str_left = sizeof(flags_str) - 1;
     79             for (i = 0; i < bcm_l2_flags_count; i++) {
     80                 if ((1 << i) & addr->flags) {
     81                     if (flag_str_left > 0) {
     82                         strncat(flags_str, bcm_l2_flags_str[i], flag_str_left);
     83                         flag_str_left -= strlen(bcm_l2_flags_str[i]);
     84                     }
     85                     if (flag_str_left > 0) {
     86                         strncat(flags_str, " ", flag_str_left);
     87                         flag_str_left -= 1;
     88                     }
     89                     if (!(++count % 4)) {
     90                         if (flag_str_left > 0) {
     91                             strncat(flags_str, "\n            ",
     92                                     flag_str_left);
     93                             flag_str_left -= 13;
     94                         }
     95                     }
     96                 }
     97             }
     98             cli_out("    Flags 0x%x:  %s\n", addr->flags, flags_str);
     99         }
    100     }
    101 
    102     if (l2n_insert) {  /* Propagate native inserts/deletes */
    103         if (addr->flags & BCM_L2_NATIVE) {
    104             if (insert) {
    105                 ++l2n_insert_calls;
    106                 rv = bcmx_l2_addr_add(addr, NULL);
    107                 if (rv < 0) {
    108                     cli_out("ERROR L2 notify insert %d: %s\n", rv,
    109                             bcm_errmsg(rv));
    110                 }
    111             } else {
    112                 ++l2n_delete_calls;
    113                 rv = bcmx_l2_addr_delete(addr->mac, addr->vid);
    114                 if (rv < 0) {
    115                     cli_out("ERROR L2 notify delete %d: %s\n", rv,
    116                             bcm_errmsg(rv));
    117                 }
    118             }
    119         }
    120     }
    121 }
    122 
    123 
    124 /*
    125  * Add an L2 address to the switch, remove an L2 address from the
    126  * switch, show addresses, and clear addresses on a per port basis.
    127  */
    128 
    129 char bcmx_cmd_l2_usage[] =
    130     "Usages:\n"
    131 #ifdef COMPILER_STRING_CONST_LIMIT
    132     "  l2 add | del | remove | notify | age | lookup\n"
    133 #else
    134     "  l2 add [Ports=<user-port-list>] [MACaddress=<mac>] [Vlanid=<id>]\n"
    135     "         [Trunk=true|false] [TrunkGroupId=<id>] [STatic=true|false]\n"
    136     "         [SourceCosPriority=true|false] [DiscardSource=true|false]\n"
    137     "         [DiscardDest]=true|false] [L3=true|false]\n"
    138     "         [CPUmirror=true|false]\n"
    139     "        - Add incrementing L2 addresses associated with port(s)\n"
    140     "  l2 del [MACaddress=<mac>] [Count=<value>] [Vlanid=<id>]\n"
    141     "        - Delete incrementing L2 address(s)\n"
    142     "  l2 remove [Vlanid=<id>] [TrunkGroupId=<id>]\n"
    143     "        - Remove all L2 addresses with VlanID or TrunkGroupId\n"
    144     "  l2 notify [start | stop | reg | unreg | [+|-]report [+|-]insert]\n"
    145     "        - Start, stop, register or unregister L2 change notification\n"
    146     "          'report' means report learns as they happen\n"
    147     "          'insert' means call bcmx_l2_addr_add on notify callback\n"
    148     "  l2 age [<seconds>]\n"
    149     "        - Set L2 aging interval if <seconds> provided,\n"
    150     "          otherwise return current aging interval.\n"
    151     "  l2 lookup MACaddress=<mac> Vlanid=<id>\n"
    152     "        - Lookup an l2 entry\n"
    153 #ifdef BCM_XGS3_SWITCH_SUPPORT
    154     "  l2 cache add CacheIndex=<index>\n"
    155     "         [MACaddress=<mac>] [MACaddressMask=<mac>]\n"
    156     "         [Vlanid=<id>] [VlanidMask=<mask>]\n"
    157     "         [Port=<uport>] [Trunk=true|false] [TrunkGroupId=<id>]\n"
    158     "         [SetPriority=true|false] [PRIOrity=<prio>]\n"
    159     "         [DiscardDest]=true|false] [CPUmirror=true|false]\n"
    160     "         [MIRror=true|false] [BPDU=true|false] [L3=true|false]\n"
    161     "        - Add L2 cache entry\n"
    162     "  l2 cache del CacheIndex=<index> [Count=<value>]\n"
    163     "        - Delete L2 cache entry\n"
    164     "  l2 cache clear\n"
    165     "        - Delete all L2 cache entries\n"
    166 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    167 #endif
    168     ;
    169 
    170 cmd_result_t
    171 bcmx_cmd_l2(int unit, args_t *args)
    172 {
    173     int                 idx;
    174     char                *subcmd = NULL;
    175     static int          initted = 0;
    176     static sal_mac_addr_t arg_macaddr;
    177     static int          arg_static=0, arg_trunk=0, arg_l3if=0,
    178                         arg_scp=0, arg_ds=0, arg_dd=0, arg_count=0,
    179                         arg_vlan=VLAN_ID_DEFAULT, arg_tgid=0, arg_cbit=0;
    180     int                 arg_vlan_temp = -1, arg_tgid_temp = -1,
    181                         arg_age_seconds = 0;
    182     char                *argage;
    183     int                 rv = CMD_OK;
    184     parse_table_t       pt;
    185     cmd_result_t        retCode;
    186     bcmx_l2_addr_t      l2addr;
    187     char                *plist_str;
    188     static bcmx_lplist_t       plist;
    189     int                 count;
    190     bcmx_lport_t        lport;
    191 
    192     /*
    193      * Initialize MAC address field for the user to the first real
    194      * address which does not conflict
    195      */
    196     if (! initted) {
    197         arg_macaddr[0] = 0;
    198         arg_macaddr[1] = 0;
    199         arg_macaddr[2] = 0;
    200         arg_macaddr[3] = 0;
    201         arg_macaddr[4] = 0;
    202         arg_macaddr[5] = 0x1;
    203 
    204         if (bcmx_lplist_init(&plist, 0, 0) < 0) {
    205             cli_out("%s: Error: could not init plist\n", ARG_CMD(args));
    206             return CMD_FAIL;
    207         }
    208 
    209         initted = 1;
    210     }
    211 
    212     if ((subcmd = ARG_GET(args)) == NULL) {
    213         return CMD_USAGE;
    214     }
    215 
    216     if (! sal_strcasecmp(subcmd, "add") || ! sal_strcasecmp(subcmd, "+")) {
    217 
    218         parse_table_init(unit, &pt);
    219         parse_table_add(&pt, "Ports",      PQ_STRING,
    220                     0, &plist_str, NULL);
    221         parse_table_add(&pt, "MACaddress",      PQ_DFL|PQ_MAC,
    222                     0, &arg_macaddr,NULL);
    223         parse_table_add(&pt, "Vlanid",          PQ_DFL|PQ_HEX,
    224                     0, &arg_vlan,       NULL);
    225         parse_table_add(&pt, "Trunk",           PQ_DFL|PQ_BOOL,
    226                     0, &arg_trunk,      NULL);
    227         parse_table_add(&pt, "TrunkGroupID",    PQ_DFL|PQ_INT,
    228                     0, &arg_tgid,       NULL);
    229         parse_table_add(&pt, "STatic",          PQ_DFL|PQ_BOOL,
    230                     0, &arg_static,     NULL);
    231         parse_table_add(&pt, "SourceCosPriority",       PQ_DFL|PQ_BOOL,
    232                     0, &arg_scp,        NULL);
    233         parse_table_add(&pt, "DiscardSource",   PQ_DFL|PQ_BOOL,
    234                     0, &arg_ds, NULL);
    235         parse_table_add(&pt, "DiscardDest",PQ_DFL|PQ_BOOL,
    236                     0, &arg_dd, NULL);
    237         parse_table_add(&pt, "L3",                      PQ_DFL|PQ_BOOL,
    238                     0, &arg_l3if,       NULL);
    239         parse_table_add(&pt, "CPUmirror",       PQ_DFL|PQ_BOOL,
    240                     0, &arg_cbit,       NULL);
    241 
    242 
    243         if (!parse_arg_eq(args, &pt)) {
    244             cli_out("%s ERROR: parsing arguments\n", ARG_CMD(args));
    245             parse_arg_eq_done(&pt);
    246             return CMD_FAIL;
    247         }
    248 
    249         bcmx_lplist_clear(&plist);
    250 
    251         if (bcmx_lplist_parse(&plist, plist_str) < 0) {
    252             cli_out("%s: Error: could not parse portlist: %s\n",
    253                     ARG_CMD(args), plist_str);
    254             parse_arg_eq_done(&pt);
    255             return CMD_FAIL;
    256         }
    257         parse_arg_eq_done(&pt);
    258 
    259         /*
    260          * If we are setting the range, the MAC address is incremented by
    261          * 1 for each port.
    262          */
    263         BCMX_LPLIST_ITER(plist, lport, count) {
    264             bcmx_l2_addr_t_init(&l2addr, arg_macaddr, arg_vlan);
    265 
    266             l2addr.tgid = arg_tgid;
    267 
    268             /* Configure flags for SDK call */
    269             if (arg_static)
    270                 l2addr.flags |= BCM_L2_STATIC;
    271             if (arg_scp)
    272                 l2addr.flags |= BCM_L2_COS_SRC_PRI;
    273             if (arg_dd)
    274                 l2addr.flags |= BCM_L2_DISCARD_DST;
    275             if (arg_ds)
    276                 l2addr.flags |= BCM_L2_DISCARD_SRC;
    277             if (arg_l3if)
    278                 l2addr.flags |= BCM_L2_L3LOOKUP;
    279             if (arg_trunk)
    280                 l2addr.flags |= BCM_L2_TRUNK_MEMBER;
    281             if (arg_cbit)
    282                 l2addr.flags |= BCM_L2_COPY_TO_CPU;
    283 
    284             l2addr.lport = lport;
    285             
    286             bcmx_dump_l2_addr("ADD: ", &l2addr, NULL);
    287 
    288             if ((rv = bcmx_l2_addr_add(&l2addr, NULL))!= BCM_E_NONE) {
    289                 cli_out("%s ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    290                 return CMD_FAIL;
    291             }
    292 
    293             /* Set up for next call */
    294             increment_macaddr(arg_macaddr, 1);
    295         }
    296 
    297         return CMD_OK;
    298     }
    299 
    300     else if (! sal_strcasecmp(subcmd, "del") || ! sal_strcasecmp(subcmd, "-")) {
    301 
    302         arg_count = 1;  /* Default count */
    303 
    304         parse_table_init(unit, &pt);
    305         parse_table_add(&pt, "MACaddress",      PQ_DFL|PQ_MAC,
    306                         0, &arg_macaddr,NULL);
    307         parse_table_add(&pt, "Count",   PQ_DFL|PQ_INT,
    308                         0, &arg_count, NULL);
    309         parse_table_add(&pt, "Vlanid",          PQ_DFL|PQ_HEX,
    310                         0, &arg_vlan,       NULL);
    311 
    312         if (!parseEndOk(args, &pt, &retCode))
    313             return retCode;
    314 
    315         for (idx = 0; idx < arg_count; idx++) {
    316             rv = bcmx_l2_addr_get(arg_macaddr, arg_vlan, &l2addr, NULL);
    317 
    318             if (rv < 0) {
    319                 cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    320                 return CMD_FAIL;
    321             }
    322 
    323             bcmx_dump_l2_addr("DEL: ", &l2addr, NULL);
    324 
    325             if ((rv = bcmx_l2_addr_delete(arg_macaddr, arg_vlan)) < 0) {
    326                 cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    327                 return CMD_FAIL;
    328             }
    329 
    330             increment_macaddr(arg_macaddr, 1);
    331         }
    332 
    333         return CMD_OK;
    334     }
    335 
    336     else if (! sal_strcasecmp(subcmd, "remove") || ! sal_strcasecmp(subcmd, "rem")) {
    337         parse_table_init(unit, &pt);
    338         parse_table_add(&pt, "Vlanid",          PQ_DFL|PQ_HEX,
    339                     (void *) -1, &arg_vlan_temp,       NULL);
    340         parse_table_add(&pt, "TrunkGroupID",    PQ_DFL|PQ_INT,
    341                     (void *) -1, &arg_tgid_temp,       NULL);
    342         if (!parseEndOk(args, &pt, &retCode))
    343             return retCode;
    344 
    345         if (arg_vlan_temp > 0) {
    346             rv = bcmx_l2_addr_delete_by_vlan(arg_vlan_temp, 0);
    347 
    348             if (rv < 0) {
    349                 cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    350                 return CMD_FAIL;
    351             }
    352         }
    353 
    354         if (arg_tgid_temp > 0) {
    355             rv = bcmx_l2_addr_delete_by_trunk(arg_tgid_temp, 0);
    356 
    357             if (rv < 0) {
    358                 cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    359                 return CMD_FAIL;
    360             }
    361         }
    362 
    363         return CMD_OK;
    364     }
    365 
    366     else if (! sal_strcasecmp(subcmd, "age")) {
    367 
    368         if ((argage = ARG_GET(args)) == NULL) {
    369             rv = bcmx_l2_age_timer_get(&arg_age_seconds);
    370 
    371             if (rv < 0) {
    372                 cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    373                 return CMD_FAIL;
    374             } else {
    375                 cli_out("Current age timer setting: %d seconds\n",
    376                         arg_age_seconds);
    377             }
    378         } else {
    379             arg_age_seconds = sal_ctoi(argage, 0);
    380             rv = bcmx_l2_age_timer_set(arg_age_seconds);
    381 
    382             if (rv < 0) {
    383                 cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    384                 return CMD_FAIL;
    385             }
    386         }
    387 
    388         return CMD_OK;
    389     }
    390 
    391     else if (! sal_strcasecmp(subcmd, "lookup") || ! sal_strcasecmp(subcmd, "lkup")) {
    392 
    393         /*
    394          * Lookup an arl entry
    395          */
    396         parse_table_init(unit, &pt);
    397         parse_table_add(&pt, "MACaddress",      PQ_DFL|PQ_MAC,
    398                     0, &arg_macaddr,NULL);
    399         parse_table_add(&pt, "Vlanid",          PQ_DFL|PQ_HEX,
    400                     0, &arg_vlan,       NULL);
    401         if (!parseEndOk(args, &pt, &retCode))
    402             return retCode;
    403 
    404         rv = bcmx_l2_addr_get(arg_macaddr, arg_vlan, &l2addr, NULL);
    405 
    406         if (rv < 0) {
    407             cli_out("ERROR: %s\n", bcm_errmsg(rv));
    408             return CMD_FAIL;
    409         } else { /* Found it.  Display. */
    410             lport = l2addr.lport;
    411             cli_out("Found on uport %s:", bcmx_lport_to_uport_str(lport));
    412             bcmx_dump_l2_addr("lookup", &l2addr, NULL);
    413             return CMD_OK;
    414         }
    415     }
    416 
    417     else if (! sal_strcasecmp(subcmd, "dump")) {
    418         cli_out("L2 dump not yet implemented.\n");
    419         return CMD_OK;
    420     }
    421 
    422     else if (! sal_strcasecmp(subcmd, "notify")) {
    423         int rv = BCM_E_NONE;
    424 
    425         if ((subcmd = ARG_GET(args)) == NULL) {
    426             cli_out("L2 notify: Ins %d (tot %d). "
    427                     "Del %d (tot %d). Ins calls %d. Del calls %d\n",
    428                     l2n_native_inserts, l2n_inserts,
    429                     l2n_native_deletes, l2n_deletes,
    430                     l2n_insert_calls, l2n_delete_calls);
    431                          
    432             return CMD_OK;
    433         } else {
    434             while (subcmd) {
    435                 if (!sal_strcasecmp(subcmd, "start")) {
    436                     rv = bcmx_l2_notify_start();
    437                     if (rv < 0) {
    438                         cli_out("Could not start BCMX L2 notify: %s",
    439                                 bcm_errmsg(rv));
    440                         return CMD_FAIL;
    441                     }
    442                 } else if (!sal_strcasecmp(subcmd, "stop")) {
    443                     rv = bcmx_l2_notify_stop();
    444                     if (rv < 0) {
    445                         cli_out("Could not stop BCMX L2 notify: %s",
    446                                 bcm_errmsg(rv));
    447                         return CMD_FAIL;
    448                     }
    449                 } else if (!sal_strcasecmp(subcmd, "reg")) {
    450                     rv = bcmx_l2_notify_register(bcmxdiag_l2_notify, NULL);
    451                     if (rv < 0) {
    452                         cli_out("Could not register BCMX L2 notify "
    453                                 "handler: %s", bcm_errmsg(rv));
    454                         return CMD_FAIL;
    455                     }
    456                 } else if (!sal_strcasecmp(subcmd, "unreg")) {
    457                     rv = bcmx_l2_notify_unregister(bcmxdiag_l2_notify, NULL);
    458                     if (rv < 0) {
    459                         cli_out("Could not register BCMX L2 notify "
    460                                 "handler: %s", bcm_errmsg(rv));
    461                         return CMD_FAIL;
    462                     }
    463                 } else if (!sal_strcasecmp(subcmd, "report")) {
    464                     l2n_report = !l2n_report;
    465                     cli_out("L2 notify report is %s\n", l2n_report ?
    466                             "on" : "off");
    467                 } else if (!sal_strcasecmp(subcmd, "+report")) {
    468                     l2n_report = TRUE;
    469                 } else if (!sal_strcasecmp(subcmd, "-report")) {
    470                     l2n_report = FALSE;
    471                 } else if (!sal_strcasecmp(subcmd, "insert")) {
    472                     l2n_insert = !l2n_insert;
    473                     cli_out("L2 notify insert is %s\n", l2n_insert ?
    474                             "on" : "off");
    475                 } else if (!sal_strcasecmp(subcmd, "+insert")) {
    476                     l2n_insert = TRUE;
    477                 } else if (!sal_strcasecmp(subcmd, "-insert")) {
    478                     l2n_insert = FALSE;
    479                 } else {
    480                     cli_out("Bad notify subcommand: %s\n", subcmd);
    481                     return CMD_USAGE;
    482                 }
    483                 subcmd = ARG_GET(args);
    484             }
    485         }
    486 
    487         return CMD_OK;
    488     }
    489 
    490 #ifdef BCM_XGS3_SWITCH_SUPPORT
    491     else if (!sal_strcasecmp(subcmd, "cache") ||
    492              !sal_strcasecmp(subcmd, "c") ) {
    493         int cidx;
    494         char *cachecmd = NULL;
    495         char str[16];
    496         static sal_mac_addr_t arg_macaddr, arg_macaddr_mask;
    497         static int arg_setpri = 0, arg_bpdu = 0, arg_mirror = 0, arg_prio = -1;
    498         static int arg_lport = 0;
    499         int arg_vlan_mask, arg_cidx, arg_ccount, idx_max;
    500         int arg_lookup_class = 0;
    501         bcmx_l2_cache_addr_t l2caddr;
    502         char *port_str = NULL;
    503 
    504         if ((cachecmd = ARG_GET(args)) == NULL) {
    505             return CMD_USAGE;
    506         }
    507 
    508         /* Masks always default to full mask */
    509         arg_vlan_mask = BCM_L2_VID_MASK_ALL;
    510         sal_memset(arg_macaddr_mask, 0xff, sizeof (sal_mac_addr_t));
    511 
    512         arg_cidx = -1;
    513         arg_ccount = 1;
    514 
    515         if (!sal_strcasecmp(cachecmd, "add") ||
    516             !sal_strcasecmp(cachecmd, "+") ) {
    517 
    518             parse_table_init(unit, &pt);
    519             parse_table_add(&pt, "LookupClass",         PQ_DFL|PQ_INT,
    520                             0, &arg_lookup_class, NULL);
    521             parse_table_add(&pt, "CacheIndex",          PQ_DFL|PQ_INT,
    522                             0, &arg_cidx,       NULL);
    523             parse_table_add(&pt, "MACaddress",          PQ_DFL|PQ_MAC,
    524                             0, &arg_macaddr,    NULL);
    525             parse_table_add(&pt, "MACaddressMask",      PQ_DFL|PQ_MAC,
    526                             0, &arg_macaddr_mask, NULL);
    527             parse_table_add(&pt, "Vlanid",              PQ_DFL|PQ_HEX,
    528                             0, &arg_vlan,       NULL);
    529             parse_table_add(&pt, "VlanidMask",          PQ_DFL|PQ_HEX,
    530                             0, &arg_vlan_mask,  NULL);
    531             parse_table_add(&pt, "Port",                PQ_DFL|PQ_STRING,
    532                             0, &port_str,       NULL);
    533             parse_table_add(&pt, "Trunk",               PQ_DFL|PQ_BOOL,
    534                             0, &arg_trunk,      NULL);
    535             parse_table_add(&pt, "TrunkGroupID",        PQ_DFL|PQ_INT,
    536                             0, &arg_tgid,       NULL);
    537             parse_table_add(&pt, "SetPriority",         PQ_DFL|PQ_BOOL,
    538                             0, &arg_trunk,      NULL);
    539             parse_table_add(&pt, "PRIOrity",            PQ_DFL|PQ_INT,
    540                             0, &arg_tgid,       NULL);
    541             parse_table_add(&pt, "DiscardDest",         PQ_DFL|PQ_BOOL,
    542                             0, &arg_dd,         NULL);
    543             parse_table_add(&pt, "L3",                  PQ_DFL|PQ_BOOL,
    544                             0, &arg_l3if,       NULL);
    545             parse_table_add(&pt, "CPUmirror",           PQ_DFL|PQ_BOOL,
    546                             0, &arg_cbit,       NULL);
    547             parse_table_add(&pt, "MIRror",              PQ_DFL|PQ_BOOL,
    548                             0, &arg_mirror,     NULL);
    549             parse_table_add(&pt, "BPDU",                PQ_DFL|PQ_BOOL,
    550                             0, &arg_bpdu,       NULL);
    551             if (parse_arg_eq(args, &pt) < 0) {
    552                 cli_out("%s ERROR: parsing arguments\n", ARG_CMD(args));
    553                 parse_arg_eq_done(&pt);
    554                 return CMD_FAIL;
    555             }
    556 
    557             if (port_str != NULL) {
    558                 arg_lport = bcmx_uport_to_lport(bcmx_uport_parse(port_str,
    559                                                                  NULL));
    560                 if (arg_lport == BCMX_NO_SUCH_LPORT) {
    561                     sal_printf("%s: Error: could not parse port: %s\n",
    562                                ARG_CMD(args), port_str);
    563                     parse_arg_eq_done(&pt);
    564                     return CMD_FAIL;
    565                 }
    566             }
    567             parse_arg_eq_done(&pt);    /* No longer needed */
    568 
    569             if (arg_cidx == -1) {
    570                 cli_out("%s ERROR: no cache index specified\n", ARG_CMD(args));
    571                 return CMD_FAIL;
    572             }
    573             if (arg_setpri && arg_prio == -1) {
    574                 cli_out("%s ERROR: no priority specified\n", ARG_CMD(args));
    575                 return CMD_FAIL;
    576             }
    577             if (!arg_setpri) {
    578                 arg_prio = -1;
    579             }
    580 
    581             bcmx_l2_cache_addr_t_init(&l2caddr);
    582 
    583             l2caddr.vlan = arg_vlan;
    584             l2caddr.vlan_mask = arg_vlan_mask;
    585 
    586             ENET_COPY_MACADDR(arg_macaddr, l2caddr.mac);
    587             ENET_COPY_MACADDR(arg_macaddr_mask, l2caddr.mac_mask);
    588 
    589             l2caddr.lookup_class = arg_lookup_class;
    590 
    591             l2caddr.dest_lport = arg_lport;
    592 
    593             l2caddr.dest_trunk = arg_tgid;
    594 
    595             /* Configure flags for SDK call */
    596             if (arg_dd || arg_ds)
    597                 l2caddr.flags |= BCM_L2_CACHE_DISCARD;
    598             if (arg_l3if)
    599                 l2caddr.flags |= BCM_L2_CACHE_L3;
    600             if (arg_trunk)
    601                 l2caddr.flags |= BCM_L2_CACHE_TRUNK;
    602             if (arg_cbit)
    603                 l2caddr.flags |= BCM_L2_CACHE_CPU;
    604             if (arg_bpdu)
    605                 l2caddr.flags |= BCM_L2_CACHE_BPDU;
    606             if (arg_mirror)
    607                 l2caddr.flags |= BCM_L2_CACHE_MIRROR;
    608 
    609             bcmx_dump_l2_cache_addr("ADD CACHE: ", &l2caddr);
    610 
    611             if ((rv = bcmx_l2_cache_set(arg_cidx, &l2caddr, 
    612                                         &cidx)) != BCM_E_NONE) {
    613                 cli_out("%s ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    614                 return CMD_FAIL;
    615             }
    616 
    617             if (cidx == -1) {
    618                 cli_out(" => using index %d\n", cidx);
    619             }
    620 
    621             /* Set up for next call */
    622             increment_macaddr(arg_macaddr, 1);
    623             if (arg_cidx >= 0) {
    624                 arg_cidx++;
    625             }
    626 
    627             return CMD_OK;
    628         }
    629 
    630         else if (!sal_strcasecmp(cachecmd, "del") ||
    631                  !sal_strcasecmp(cachecmd, "-")) {
    632 
    633             if (ARG_CNT(args)) {
    634                 parse_table_init(unit, &pt);
    635                 parse_table_add(&pt, "CacheIndex",      PQ_DFL|PQ_INT,
    636                                 0, &arg_cidx,   NULL);
    637                 parse_table_add(&pt, "Count",           PQ_DFL|PQ_INT,
    638                                 0, &arg_ccount, NULL);
    639                 if (!parseEndOk(args, &pt, &retCode)) {
    640                     return retCode;
    641                 }
    642             }
    643 
    644             if (arg_cidx == -1) {
    645                 cli_out("%s ERROR: no index specified\n", ARG_CMD(args));
    646                 return CMD_FAIL;
    647             }
    648 
    649             for (idx = 0; idx < arg_ccount; idx++) {
    650                 if ((rv = bcmx_l2_cache_get(arg_cidx, &l2caddr)) < 0) {
    651                     cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    652                     return CMD_FAIL;
    653                 }
    654 
    655                 bcmx_dump_l2_cache_addr("DEL CACHE: ", &l2caddr);
    656 
    657                 if ((rv = bcmx_l2_cache_delete(arg_cidx)) != BCM_E_NONE) {
    658                     cli_out("%s ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    659                     return CMD_FAIL;
    660                 }
    661                 arg_cidx++;
    662             }
    663 
    664             return CMD_OK;
    665         }
    666 
    667         else if (!sal_strcasecmp(cachecmd, "show") ||
    668                  !sal_strcasecmp(cachecmd, "-d")) {
    669 
    670             if ((rv = bcmx_l2_cache_size_get(&idx_max)) < 0) {
    671                 cli_out("%s: ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    672                 return CMD_FAIL;
    673             }
    674 
    675             for (idx = 0; idx <= idx_max; idx++) {
    676                 if (bcmx_l2_cache_get(idx, &l2caddr) == BCM_E_NONE) {
    677                     sal_sprintf(str, " %4d : ", idx);
    678                     bcmx_dump_l2_cache_addr(str, &l2caddr);
    679                 }
    680             }
    681 
    682             return CMD_OK;
    683         }
    684 
    685         else if (!sal_strcasecmp(cachecmd, "clear") ||
    686                  !sal_strcasecmp(cachecmd, "clr")) {
    687 
    688             if (ARG_CNT(args)) {
    689                 return CMD_USAGE;
    690             }
    691 
    692             if ((rv = bcmx_l2_cache_delete_all()) != BCM_E_NONE) {
    693                 cli_out("%s ERROR: %s\n", ARG_CMD(args), bcm_errmsg(rv));
    694                 return CMD_FAIL;
    695             }
    696 
    697             return CMD_OK;
    698         }
    699 
    700         else {
    701             return CMD_USAGE;
    702         }
    703     }
    704 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    705 
    706     return CMD_USAGE;
    707 }
    708 
    709 
    710 void
    711 bcmx_dump_l2_addr(char *pfx, bcmx_l2_addr_t *l2addr, bcmx_lplist_t *port_block)
    712 {
    713     bcmx_lport_t lport;
    714     int          count;
    715 
    716     
    717     cli_out("%smac=%02x:%02x:%02x:%02x:%02x:%02x vlan=%d uport=%s",
    718             pfx,
    719             l2addr->mac[0], l2addr->mac[1], l2addr->mac[2],
    720             l2addr->mac[3], l2addr->mac[4], l2addr->mac[5],
    721             l2addr->vid,
    722             bcmx_lport_to_uport_str(l2addr->lport));
    723 
    724 
    725     if (l2addr->flags & BCM_L2_TRUNK_MEMBER) {
    726         cli_out(" Trunk=%d Rtag=%d", l2addr->tgid, l2addr->trunk_sel);
    727     }
    728 
    729     if (l2addr->flags & BCM_L2_STATIC) {
    730         cli_out(" Static");
    731     }
    732 
    733     if (l2addr->flags & BCM_L2_HIT) {
    734         cli_out(" Hit");
    735     }
    736 
    737     if (l2addr->cos_src != 0 || l2addr->cos_dst != 0) {
    738         cli_out(" COS(src=%d,dst=%d)", l2addr->cos_src, l2addr->cos_dst);
    739     }
    740 
    741     if (l2addr->flags & BCM_L2_COS_SRC_PRI) {
    742         cli_out(" SCP");
    743     }
    744 
    745     if (l2addr->flags & BCM_L2_COPY_TO_CPU) {
    746         cli_out(" CPU");
    747     }
    748 
    749     if (l2addr->flags & BCM_L2_L3LOOKUP) {
    750         cli_out(" L3");
    751     }
    752 
    753     if (l2addr->flags & BCM_L2_DISCARD_SRC) {
    754         cli_out(" DiscardSrc");
    755     }
    756 
    757     if (l2addr->flags & BCM_L2_DISCARD_DST) {
    758         cli_out(" DiscardDest");
    759     }
    760 
    761     if (l2addr->flags & BCM_L2_MCAST) {
    762         cli_out(" MCast=%d", l2addr->l2mc_group);
    763     }
    764 
    765     if (!BCMX_LPLIST_IS_EMPTY(port_block)) {
    766         BCMX_LPLIST_ITER(*(port_block), lport, count) {
    767             cli_out("    Uport blocked: %s\n", bcmx_lport_to_uport_str(lport));
    768             cli_out("\n");
    769         }
    770     }
    771 
    772     cli_out("\n");
    773 }
    774 
    775 #ifdef BCM_XGS3_SWITCH_SUPPORT
    776 void
    777 bcmx_dump_l2_cache_addr(char *pfx, bcmx_l2_cache_addr_t *l2caddr)
    778 {
    779     cli_out("%smac=%02x:%02x:%02x:%02x:%02x:%02x",
    780             pfx,
    781             l2caddr->mac[0], l2caddr->mac[1], l2caddr->mac[2],
    782             l2caddr->mac[3], l2caddr->mac[4], l2caddr->mac[5]);
    783 
    784     if (!ENET_MACADDR_BROADCAST(l2caddr->mac_mask)) {
    785         cli_out("/%02x:%02x:%02x:%02x:%02x:%02x", 
    786                 l2caddr->mac_mask[0], l2caddr->mac_mask[1], l2caddr->mac_mask[2],
    787                 l2caddr->mac_mask[3], l2caddr->mac_mask[4], l2caddr->mac_mask[5]);
    788     }
    789 
    790     cli_out(" vlan=%d", l2caddr->vlan);
    791 
    792     if (l2caddr->vlan_mask != BCM_L2_VID_MASK_ALL) {
    793         cli_out("/0x%03x", l2caddr->vlan_mask);
    794     }
    795 
    796     if (l2caddr->flags & BCM_L2_CACHE_TRUNK) {
    797         cli_out(" trunk=%d", l2caddr->dest_trunk);
    798     } else {
    799         cli_out(" uport=%s", bcmx_lport_to_uport_str(l2caddr->dest_lport));
    800     }
    801 
    802     if (l2caddr->flags & BCM_L2_CACHE_SETPRI) {
    803         cli_out(" prio=%d", l2caddr->prio);
    804     }
    805 
    806     if (l2caddr->flags & BCM_L2_CACHE_BPDU) {
    807         cli_out(" BPDU");
    808     }
    809 
    810     if ((l2caddr->flags & BCM_L2_CACHE_CPU) ||
    811         (l2caddr->dest_lport == BCMX_LPORT_LOCAL_CPU)) {
    812         cli_out(" CPU");
    813     }
    814 
    815     if (l2caddr->flags & BCM_L2_CACHE_L3) {
    816         cli_out(" L3");
    817     }
    818 
    819     if (l2caddr->flags & BCM_L2_CACHE_DISCARD) {
    820         cli_out(" Discard");
    821     }
    822 
    823     if (l2caddr->flags & BCM_L2_CACHE_MIRROR) {
    824         cli_out(" Mirror");
    825     }
    826 
    827     cli_out("\n");
    828 }
    829 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    830 
    831 #endif