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


      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  * L2 CLI commands
      8  */
      9 
     10 #include <appl/diag/system.h>
     11 #include <appl/diag/parse.h>
     12 #include <appl/diag/dport.h>
     13 #include <shared/bsl.h>
     14 #include <soc/l2x.h>
     15 #include <soc/l2u.h>
     16 #include <soc/debug.h>
     17 #include <soc/hash.h>
     18 
     19 #include <bcm/error.h>
     20 #include <bcm/l2.h>
     21 #include <bcm/stack.h>
     22 #include <bcm/mcast.h>
     23 #include <bcm/debug.h>
     24 
     25 #include <bcm_int/esw/trunk.h>
     26 #include <bcm_int/esw/mbcm.h>
     27 #include <bcm_int/esw/hercules.h>
     28 #include <bcm_int/esw/firebolt.h>
     29 #if defined(BCM_TRIUMPH_SUPPORT) /* BCM_TRIUMPH_SUPPORT*/
     30 #include <bcm_int/esw/triumph.h>
     31 #endif /* !BCM_TRIUMPH_SUPPORT */
     32 #if defined(BCM_TOMAHAWK_SUPPORT)
     33 #include <bcm_int/esw/switch.h>
     34 #endif
     35 #if defined(BCM_TOMAHAWK3_SUPPORT)
     36 #include <soc/tomahawk3.h>
     37 #endif
     38 
     39 static sal_usecs_t prev_l2x_interval[SOC_MAX_NUM_DEVICES];
     40 #if defined(BCM_TOMAHAWK3_SUPPORT)
     41 static sal_usecs_t prev_l2x_lrn_interval[SOC_MAX_NUM_DEVICES];
     42 #endif
     43 
     44 #if defined(BCM_TRIUMPH_SUPPORT) 
     45 /*
     46  * Macro:
     47  *     L2_CHECK_RETURN
     48  * Purpose:
     49  *     Check the return value from an API call. Output either a failed
     50  *     message or okay along with the function name.
     51  */
     52 #define L2_CHECK_RETURN(unit, rv, func_name)                            \
     53             do {                                                        \
     54                 if (BCM_FAILURE(rv)) {                                  \
     55                     cli_out("L2(unit %d) Error: %s() failed - %s. \n",  \
     56                             (unit), (func_name), bcm_errmsg(rv));       \
     57                     return (CMD_FAIL);                                  \
     58                 } else {                                                \
     59                     if (LOG_CHECK(BSL_LS_BCM_L2 | BSL_VERBOSE)) {       \
     60                         cli_out("L2(unit %d) Info: %s() success. \n",   \
     61                                 (unit), (func_name));                   \
     62                     }                                                   \
     63                 }                                                       \
     64             } while(0)
     65 #endif
     66 
     67 
     68 #if defined(BCM_TRIDENT2_SUPPORT)
     69 #define L2_MAX_BANKS  6
     70 #endif
     71 
     72 /*
     73  * Used with the 'l2 watch' command below.
     74  */
     75 static void
     76 _l2_watch_cb(int unit,
     77 	     bcm_l2_addr_t *l2addr,
     78 	     int insert,
     79 	     void *userdata)
     80 {
     81     int s;
     82     sal_thread_t main_thread;
     83 
     84     s = sal_splhi();
     85 
     86     main_thread = sal_thread_main_get();
     87     sal_thread_main_set(sal_thread_self());
     88 
     89     if(insert) {
     90 	dump_l2_addr(unit, "L2 ADD: ", l2addr);
     91     }
     92     else {
     93 	dump_l2_addr(unit, "L2 DEL: ", l2addr);
     94     }
     95 
     96     sal_thread_main_set(main_thread);
     97 
     98     sal_spl(s);
     99 }
    100 
    101 
    102 /* CB function to print L2 Entry */
    103 int _l2addr_dump(int unit, bcm_l2_addr_t *l2addr, void *user_data)
    104 {
    105     /* Don't dump individual entries when just the 'count' is desired, the
    106        user of this callback will print the counts */
    107 #if defined(BCM_TRIUMPH3_SUPPORT)
    108     if (soc_feature(unit, soc_feature_ism_memory)) {
    109         if(!(_l2_addr_counts.flags & L2_DUMP_COUNT)) {
    110             dump_l2_addr(unit, "", l2addr);
    111         }
    112     } else {
    113         dump_l2_addr(unit, "", l2addr);
    114     }
    115 #else
    116     dump_l2_addr(unit, "", l2addr);
    117 #endif
    118 
    119     return BCM_E_NONE;
    120 }
    121 
    122 
    123 #if defined(BCM_TRIUMPH_SUPPORT) /* BCM_TRIUMPH_SUPPORT */
    124 /*
    125  * Function:
    126  *    _l2_station_add
    127  * Purpose:
    128  *    Add L2 station entry.
    129  * Parmameters:
    130  *    unit - (IN) BCM device number
    131  *    args - (IN) input parameters passed as arguments
    132  * Returns:
    133  *     CMD_XXX
    134  */
    135 STATIC int
    136 _l2_station_add(int unit, args_t *args)
    137 {
    138     int rv;
    139     int sid = -1;
    140     int prio = 0;
    141     bcm_mac_t dst_mac;
    142     bcm_mac_t dst_mac_mask;
    143     int vlan = 0;
    144     int vlan_mask = 0;
    145     int src_port = 0;
    146     int src_port_mask = 0;
    147     int ipv4 = 0;
    148     int ipv6 = 0;
    149     int arp_rarp = 0;
    150     int mpls_term = 0;
    151     int mim_term = 0;
    152     int trill_term = 0;
    153     int fcoe_term = 0;
    154     int oam_term = 0;
    155     int replace = 0;
    156     int copy_to_cpu = 0;
    157     int discard = 0;
    158     parse_table_t pt;
    159     bcm_l2_station_t s_ent;
    160     int station_id = -1;
    161     cmd_result_t retCode = CMD_OK;
    162 
    163     sal_memset(dst_mac, 0x00, sizeof(bcm_mac_t));
    164     sal_memset(dst_mac_mask, 0x00, sizeof(bcm_mac_t));
    165 
    166     bcm_l2_station_t_init(&s_ent);
    167 
    168     parse_table_init(unit, &pt);
    169 
    170     parse_table_add(&pt, "Priority", PQ_DFL|PQ_INT,
    171                     0, (void *)&prio,  NULL);
    172 
    173     parse_table_add(&pt, "ID", PQ_DFL|PQ_INT,
    174                     (void *)-1, (void *)&sid,  NULL);
    175 
    176     parse_table_add(&pt, "MACaddress", PQ_DFL|PQ_MAC,
    177                     0, (void *)&dst_mac, NULL);
    178 
    179     parse_table_add(&pt, "MACaddressMask", PQ_DFL|PQ_MAC,
    180                     0, (void *)&dst_mac_mask, NULL);
    181 
    182     parse_table_add(&pt, "Vlanid", PQ_DFL|PQ_HEX,
    183                     0, (void *)&vlan, NULL);
    184 
    185     parse_table_add(&pt, "VlanidMask", PQ_DFL|PQ_HEX,
    186                     0, (void *)&vlan_mask, NULL);
    187 
    188     parse_table_add(&pt, "SourcePort", PQ_DFL|PQ_PORT|PQ_BCM,
    189                     0, (void *)&src_port, NULL);
    190 
    191     parse_table_add(&pt, "SourcePortMask", PQ_DFL|PQ_HEX,
    192                     0, (void *)&src_port_mask, NULL);
    193 
    194     parse_table_add(&pt, "IPv4", PQ_DFL|PQ_BOOL,
    195                     0, (void *)&ipv4, NULL);
    196 
    197     parse_table_add(&pt, "IPv6", PQ_DFL|PQ_BOOL,
    198                     0, (void *)&ipv6, NULL);
    199 
    200     parse_table_add(&pt, "ArpRarp", PQ_DFL|PQ_BOOL,
    201                     0, (void *)&arp_rarp, NULL);
    202 
    203     parse_table_add(&pt, "MPLS", PQ_DFL|PQ_BOOL,
    204                     0, (void *)&mpls_term, NULL);
    205 
    206     parse_table_add(&pt, "MiM", PQ_DFL|PQ_BOOL,
    207                     0, (void *)&mim_term, NULL);
    208 
    209     parse_table_add(&pt, "TRILL", PQ_DFL|PQ_BOOL,
    210                     0, (void *)&trill_term, NULL);
    211 
    212     parse_table_add(&pt, "FCoE", PQ_DFL|PQ_BOOL,
    213                     0, (void *)&fcoe_term, NULL);
    214 
    215     parse_table_add(&pt, "OAM", PQ_DFL|PQ_BOOL,
    216                     0, (void *)&oam_term, NULL);
    217 
    218     parse_table_add(&pt, "Replace", PQ_DFL|PQ_BOOL,
    219                     0, (void *)&replace, NULL);
    220 
    221     parse_table_add(&pt, "CPUmirror", PQ_DFL|PQ_BOOL,
    222                     0, (void *)&copy_to_cpu, NULL);
    223 
    224     parse_table_add(&pt, "Discard", PQ_DFL|PQ_BOOL,
    225                     0, (void *)&discard, NULL);
    226 
    227     if (!parseEndOk(args, &pt, &retCode)) {
    228         return retCode;
    229     }
    230 
    231     s_ent.priority = prio;
    232 
    233     if (-1 != sid) {
    234         station_id = sid;
    235         s_ent.flags |= BCM_L2_STATION_WITH_ID;
    236     }
    237     sal_memcpy(s_ent.dst_mac, dst_mac, sizeof(bcm_mac_t));
    238     sal_memcpy(s_ent.dst_mac_mask, dst_mac_mask, sizeof(bcm_mac_t));
    239 
    240     s_ent.vlan = vlan;
    241     s_ent.vlan_mask = vlan_mask;
    242 
    243     s_ent.src_port = src_port;
    244     s_ent.src_port_mask = src_port_mask;
    245 
    246     if (1 == ipv4) {
    247         s_ent.flags |= BCM_L2_STATION_IPV4;
    248     }
    249 
    250     if (1 == ipv6) {
    251         s_ent.flags |= BCM_L2_STATION_IPV6;
    252     }
    253 
    254     if (1 == arp_rarp) {
    255         s_ent.flags |= BCM_L2_STATION_ARP_RARP;
    256     }
    257 
    258     if (1 == mpls_term) {
    259         s_ent.flags |= BCM_L2_STATION_MPLS;
    260     }
    261 
    262     if (1 == mim_term) {
    263         s_ent.flags |= BCM_L2_STATION_MIM;
    264     }
    265 
    266     if (1 == trill_term) {
    267         s_ent.flags |= BCM_L2_STATION_TRILL;
    268     }
    269 
    270     if (1 == oam_term) {
    271         s_ent.flags |= BCM_L2_STATION_OAM;
    272     }
    273 
    274     if (1 == fcoe_term) {
    275         s_ent.flags |= BCM_L2_STATION_FCOE;
    276     }
    277 
    278     if (1 == replace) {
    279         s_ent.flags |= BCM_L2_STATION_REPLACE;
    280     }
    281 
    282     if (1 == copy_to_cpu) {
    283         s_ent.flags |= BCM_L2_STATION_COPY_TO_CPU;
    284     }
    285 
    286     if (1 == discard) {
    287         s_ent.flags |= BCM_L2_STATION_DISCARD;
    288     }
    289 
    290     rv =  bcm_l2_station_add(unit, &station_id, &s_ent);
    291     L2_CHECK_RETURN(unit, rv, "bcm_l2_station_add");
    292 
    293     if (-1 == sid) {
    294         cli_out("Created SID=0x%08x\n", station_id);
    295     }
    296 
    297     return (retCode);
    298 }
    299 
    300 /*
    301  * Function:
    302  *    _l2_station_delete
    303  * Purpose:
    304  *    Delete L2 station entry.
    305  * Parmameters:
    306  *    unit - (IN) BCM device number
    307  *    args - (IN) input parameters passed as arguments
    308  * Returns:
    309  *     CMD_XXX
    310  */
    311 STATIC int
    312 _l2_station_delete(int unit, args_t *args)
    313 {
    314     int rv;
    315     parse_table_t pt;
    316     int station_id = -1;
    317     cmd_result_t retCode = CMD_OK;
    318 
    319     parse_table_init(unit, &pt);
    320 
    321     parse_table_add(&pt, "ID", PQ_DFL|PQ_INT,
    322                     (void *)-1, (void *)&station_id,  NULL);
    323     if (!parseEndOk(args, &pt, &retCode)) {
    324         return retCode;
    325     }
    326 
    327     rv =  bcm_l2_station_delete(unit, station_id);
    328 
    329     L2_CHECK_RETURN(unit, rv, "bcm_l2_station_delete");
    330 
    331     return (retCode);
    332 }
    333 
    334 /*
    335  * Function:
    336  *    _l2_station_clear
    337  * Purpose:
    338  *    Delete all L2 station entries.
    339  * Parmameters:
    340  *    unit - (IN) BCM device number
    341  *    args - (IN) input parameters passed as arguments
    342  * Returns:
    343  *     CMD_XXX
    344  */
    345 STATIC int
    346 _l2_station_clear(int unit, args_t *args)
    347 {
    348     cmd_result_t retCode = CMD_OK;
    349     int rv;
    350 
    351     rv =  bcm_l2_station_delete_all(unit);
    352     L2_CHECK_RETURN(unit, rv, "bcm_l2_station_delete_all");
    353 
    354     return (retCode);
    355 }
    356 
    357 /*
    358  * Function:
    359  *    _l2_station_show
    360  * Purpose:
    361  *    Show L2 station entry value.
    362  * Parmameters:
    363  *    unit - (IN) BCM device number
    364  *    args - (IN) input parameters passed as arguments
    365  * Returns:
    366  *     CMD_XXX
    367  */
    368 STATIC int
    369 _l2_station_show(int unit, args_t *args)
    370 {
    371     int rv;
    372     parse_table_t pt;
    373     int station_id = -1;
    374     cmd_result_t retCode = CMD_OK;
    375     bcm_l2_station_t s_ent;
    376 
    377     parse_table_init(unit, &pt);
    378 
    379     parse_table_add(&pt, "ID", PQ_DFL|PQ_INT,
    380                     (void *)-1, (void *)&station_id,  NULL);
    381     if (!parseEndOk(args, &pt, &retCode)) {
    382         return retCode;
    383     }
    384 
    385     bcm_l2_station_t_init(&s_ent);
    386  
    387     rv = bcm_l2_station_get(unit, station_id, &s_ent);
    388     L2_CHECK_RETURN(unit, rv, "bcm_l2_station_get");
    389 
    390     cli_out("\tSID=0x%08x, priority=%d\n", station_id, s_ent.priority);
    391     cli_out("\tMAC=%x:%x:%x:%x:%x:%x\n", s_ent.dst_mac[0], s_ent.dst_mac[1],
    392             s_ent.dst_mac[2], s_ent.dst_mac[3], s_ent.dst_mac[4],
    393             s_ent.dst_mac[5]);
    394     cli_out("\tMAC MASK=%x:%x:%x:%x:%x:%x\n", s_ent.dst_mac_mask[0],
    395             s_ent.dst_mac_mask[1], s_ent.dst_mac_mask[2], s_ent.dst_mac_mask[3],
    396             s_ent.dst_mac_mask[4], s_ent.dst_mac_mask[5]);
    397     cli_out("\tVLAN=0x%x\n", s_ent.vlan);
    398     cli_out("\tVLAN MASK=0x%x\n", s_ent.vlan_mask);
    399     cli_out("\tSourcePort=0x%x\n", s_ent.src_port);
    400     cli_out("\tSourcePort MASK=0x%x\n", s_ent.src_port_mask);
    401     cli_out("\tFlags=0x%x\n", s_ent.flags);
    402 
    403     return (rv);
    404 }
    405 
    406 /*
    407  * Function:
    408  *    _l2_station_cmd_process
    409  * Purpose:
    410  *    Add/Delete/Clear/Show L2 station entry values.
    411  * Parmameters:
    412  *    unit - (IN) BCM device number
    413  *    args - (IN) input parameters passed as arguments
    414  * Returns:
    415  *     CMD_XXX
    416  */
    417 STATIC int
    418 _l2_station_cmd_process(int unit, args_t *args)
    419 {
    420     char *subcmd = NULL;
    421 
    422     if ((subcmd = ARG_GET(args)) == NULL) {
    423         return CMD_USAGE;
    424     }
    425 
    426     /* BCM.0> l2 station add ... */
    427     if (!sal_strcasecmp(subcmd, "add")) {
    428         return _l2_station_add(unit, args);
    429     }
    430 
    431     /* BCM.0> l2 station delete ... */
    432     if (!sal_strcasecmp(subcmd, "delete")) {
    433         return _l2_station_delete(unit, args);
    434     }
    435 
    436     /* BCM.0> l2 station clear ... */
    437     if (!sal_strcasecmp(subcmd, "clear")) {
    438         return _l2_station_clear(unit, args);
    439     }
    440 
    441     /* BCM.0> l2 station show ... */
    442     if (!sal_strcasecmp(subcmd, "show")) {
    443         return _l2_station_show(unit, args);
    444     }
    445 
    446     return CMD_USAGE;
    447 }
    448 #endif /* !BCM_TRIUMPH_SUPPORT */
    449 
    450 /*
    451  * Add an L2 address to the switch, remove an L2 address from the
    452  * switch, show addresses, and clear addresses on a per port basis.
    453  */
    454 cmd_result_t
    455 if_esw_l2(int unit, args_t *a)
    456 {
    457     int                 idx;
    458     char 		*subcmd = NULL;
    459     pbmp_t 	arg_pbmp, arg_pbmp_mb;
    460     int		arg_static = 0, arg_trunk = 0, arg_l3if = 0,
    461 	arg_scp = 0, arg_ds = 0, arg_dd = 0, arg_count = 1, arg_modid = 0,
    462     arg_newmodid = 0, arg_vlan = VLAN_ID_DEFAULT, arg_tgid = 0, arg_newtgid = 0, 
    463     arg_cbit = 0, arg_hit = 0, arg_replace = 0, arg_port = 0, arg_newport = 0, 
    464         arg_group = 0, arg_pending = 0, arg_limitexempt = 0, arg_mirror = 0;
    465 #ifdef BCM_XGS_SWITCH_SUPPORT
    466     int          arg_hash = XGS_HASH_COUNT;
    467 #endif
    468     int          arg_rpe = TRUE;
    469     soc_port_t		p, dport;
    470     int			rv = BCM_E_NONE;
    471     parse_table_t	pt;
    472     cmd_result_t	retCode;
    473     bcm_l2_addr_t	l2addr;
    474     uint32              flags;
    475     bcm_module_t    mymodid;
    476     /*
    477      * Initialize MAC address field for the user to the first real
    478      * address which does not conflict
    479      */
    480 
    481     sal_mac_addr_t default_macaddr = {0, 0, 0, 0, 0, 0X1};
    482     sal_mac_addr_t arg_macaddr = {0, 0, 0, 0, 0, 0X1};
    483 
    484     BCM_PBMP_CLEAR(arg_pbmp);
    485     BCM_PBMP_CLEAR(arg_pbmp_mb);
    486     sal_memset(&l2addr, 0, sizeof(bcm_l2_addr_t));
    487 
    488     UNSUPPORTED_COMMAND(unit, SOC_CHIP_BCM5670, a);
    489 
    490 
    491     if ((subcmd = ARG_GET(a)) == NULL) {
    492 	return CMD_USAGE;
    493     }
    494 
    495     /* Check valid device to operation on ...*/
    496     if (!sh_check_attached(ARG_CMD(a), unit)) {
    497 	return CMD_FAIL;
    498     }
    499 
    500     if (!sal_strcasecmp(subcmd, "replace")) {
    501         uint32 flags = 0;
    502 
    503         arg_modid = arg_port = arg_vlan = arg_tgid = arg_newmodid = arg_newport = arg_newtgid = -1;
    504         parse_table_init(unit, &pt);
    505         parse_table_add(&pt, "Module",          PQ_DFL|PQ_INT,
    506                 0, &arg_modid,  NULL);
    507         parse_table_add(&pt, "Port",            PQ_DFL|PQ_PORT,
    508                 0, &arg_port,   NULL);
    509         parse_table_add(&pt, "MACaddress", 	    PQ_DFL|PQ_MAC,
    510                 0, &arg_macaddr, NULL);
    511         parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
    512                 0, &arg_vlan,	NULL);
    513         parse_table_add(&pt, "Trunk",           PQ_DFL|PQ_BOOL,
    514                 0, &arg_trunk,	NULL);
    515         parse_table_add(&pt, "TrunkGroupID",    PQ_DFL|PQ_INT,
    516                 0, &arg_tgid,	NULL);
    517         parse_table_add(&pt, "STatic", 	        PQ_DFL|PQ_BOOL,
    518                 0, &arg_static,	NULL);
    519         parse_table_add(&pt, "PENDing",	        PQ_DFL|PQ_BOOL,
    520                 0, &arg_pending, NULL);
    521         parse_table_add(&pt, "NewModule",       PQ_DFL|PQ_INT,
    522                 0, &arg_newmodid,  NULL);
    523         parse_table_add(&pt, "NewPort",         PQ_DFL|PQ_PORT,
    524                 0, &arg_newport,   NULL);
    525         parse_table_add(&pt, "NewTrunkGroupID", PQ_DFL|PQ_INT,
    526                 0, &arg_newtgid,	NULL);
    527         if (!parseEndOk(a, &pt, &retCode)) {
    528             return retCode;
    529         }
    530 
    531         bcm_l2_addr_t_init(&l2addr, arg_macaddr, arg_vlan);
    532         if (arg_static) {
    533             flags |= BCM_L2_REPLACE_MATCH_STATIC;
    534         }
    535         if (arg_pending) {
    536             flags |= BCM_L2_REPLACE_PENDING;
    537         }
    538         if (ENET_CMP_MACADDR(arg_macaddr, default_macaddr)) {
    539             flags |= BCM_L2_REPLACE_MATCH_MAC;
    540         }
    541         if (arg_vlan != -1) {
    542             flags |= BCM_L2_REPLACE_MATCH_VLAN;
    543         }
    544         if (arg_newtgid != - 1) {
    545             flags |= BCM_L2_REPLACE_NEW_TRUNK; 
    546         }
    547         if (BCM_GPORT_IS_SET(arg_port)) {
    548             flags |= BCM_L2_REPLACE_MATCH_DEST;
    549             l2addr.port = arg_port;
    550         } else {
    551             if ((arg_port != - 1) && (arg_modid != - 1)) {
    552                 flags |= BCM_L2_REPLACE_MATCH_DEST;
    553                 l2addr.modid = arg_modid;
    554                 l2addr.port = arg_port;
    555             }
    556             if (arg_trunk && (arg_tgid != -1)) {
    557                 flags |= BCM_L2_REPLACE_MATCH_DEST;
    558                 l2addr.tgid = arg_tgid;
    559             }
    560         }
    561 
    562         rv = bcm_l2_replace(unit, flags, &l2addr, arg_newmodid, 
    563                                 arg_newport, arg_newtgid); 
    564 
    565         if (BCM_FAILURE(rv)) {
    566             cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
    567             return CMD_FAIL;
    568         }
    569 
    570         return CMD_OK;
    571     } else if (!sal_strcasecmp(subcmd, "add") ||
    572 	!sal_strcasecmp(subcmd, "+")) {
    573 
    574 	parse_table_init(unit, &pt);
    575 	parse_table_add(&pt, "Module",          PQ_DFL|PQ_INT,
    576 			0, &arg_modid,  NULL);
    577         parse_table_add(&pt, "Port",          PQ_DFL|PQ_PORT,
    578                         0, &arg_port,  NULL);
    579 	parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP,
    580 			(void *)(0), &arg_pbmp, NULL);
    581     	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,0, 
    582                         &arg_macaddr,   NULL);
    583 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
    584 			0, &arg_vlan,	NULL);
    585 	parse_table_add(&pt, "Trunk",           PQ_DFL|PQ_BOOL,
    586 			0, &arg_trunk,	NULL);
    587 	parse_table_add(&pt, "TrunkGroupID", 	PQ_DFL|PQ_INT,
    588 			0, &arg_tgid,	NULL);
    589 	parse_table_add(&pt, "STatic", 	        PQ_DFL|PQ_BOOL,
    590 			0, &arg_static,	NULL);
    591 	parse_table_add(&pt, "HIT", 	        PQ_DFL|PQ_BOOL,
    592 			0, &arg_hit,	NULL);
    593 	parse_table_add(&pt, "Replace",         PQ_DFL|PQ_BOOL,
    594                         0, &arg_replace,    NULL);
    595 	parse_table_add(&pt, "SourceCosPriority",	PQ_DFL|PQ_BOOL,
    596 			0, &arg_scp,	NULL);
    597 	parse_table_add(&pt, "DiscardSource", 	PQ_DFL|PQ_BOOL,
    598 			0, &arg_ds,	NULL);
    599 	parse_table_add(&pt, "DiscardDest",PQ_DFL|PQ_BOOL,
    600 			0, &arg_dd,	NULL);
    601 	parse_table_add(&pt, "L3", 			PQ_DFL|PQ_BOOL,
    602 			0, &arg_l3if,	NULL);
    603 	parse_table_add(&pt, "CPUmirror", 	PQ_DFL|PQ_BOOL,
    604 			0, &arg_cbit,	NULL);
    605         parse_table_add(&pt, "MIRror", 	        PQ_DFL|PQ_BOOL,
    606                         0, &arg_mirror,	NULL);
    607 	parse_table_add(&pt, "MacBlockPortBitMap", PQ_DFL|PQ_PBMP|PQ_BCM,
    608 			(void *)(0), &arg_pbmp_mb, NULL);
    609 	parse_table_add(&pt, "Group",          PQ_DFL|PQ_INT,
    610 			0, &arg_group,  NULL);
    611 	parse_table_add(&pt, "PENDing",	        PQ_DFL|PQ_BOOL,
    612 			0, &arg_pending, NULL);
    613 	parse_table_add(&pt, "LearnLimitExempt", PQ_DFL|PQ_BOOL,
    614 			0, &arg_limitexempt, NULL);
    615 
    616         if (SOC_IS_XGS3_SWITCH(unit)) {
    617             parse_table_add(&pt, "ReplacePriority", 	PQ_DFL|PQ_BOOL,
    618                             0, &arg_rpe,	NULL);
    619         }
    620 	if (!parseEndOk(a, &pt, &retCode)) {
    621 	    return retCode;
    622 	}
    623     
    624 
    625         /* Configure flags for SDK call */
    626         flags = 0;
    627         if (arg_static)
    628             flags |= BCM_L2_STATIC;
    629         if (arg_hit)
    630             flags |= BCM_L2_HIT;
    631         if (arg_replace)
    632             flags |= BCM_L2_REPLACE_DYNAMIC;
    633         if (arg_scp)
    634             flags |= BCM_L2_COS_SRC_PRI;
    635         if (arg_dd)
    636             flags |= BCM_L2_DISCARD_DST;
    637         if (arg_ds)
    638             flags |= BCM_L2_DISCARD_SRC;
    639         if (arg_l3if)
    640             flags |= BCM_L2_L3LOOKUP;
    641         if (arg_trunk)
    642             flags |= BCM_L2_TRUNK_MEMBER;
    643         if (arg_cbit)
    644             flags |= BCM_L2_COPY_TO_CPU;
    645         if (arg_mirror)
    646             flags |= BCM_L2_MIRROR;
    647         if (arg_rpe)
    648             flags |= BCM_L2_SETPRI;
    649         if (arg_pending)
    650             flags |= BCM_L2_PENDING;
    651         if (arg_limitexempt)
    652             flags |= BCM_L2_LEARN_LIMIT_EXEMPT;
    653     
    654         if (SOC_PBMP_IS_NULL(arg_pbmp)) {
    655             /* Fill l2addr structure */
    656             bcm_l2_addr_t_init(&l2addr, arg_macaddr, arg_vlan);
    657             l2addr.tgid = arg_tgid;
    658             l2addr.group = arg_group;
    659             l2addr.flags = flags;
    660             l2addr.port = arg_port;
    661             if (!BCM_GPORT_IS_SET(arg_port)) {
    662                 l2addr.modid = arg_modid;
    663                 bcm_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    664                                    l2addr.modid, l2addr.port, 
    665                                    &l2addr.modid, &l2addr.port);
    666             }
    667             BCM_PBMP_ASSIGN(l2addr.block_bitmap, arg_pbmp_mb);
    668             if ((rv = bcm_l2_addr_add(unit, &l2addr))!= BCM_E_NONE) {
    669                 cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
    670                 return CMD_FAIL;
    671             }
    672             dump_l2_addr(unit, "ADD: ", &l2addr);
    673         } else {
    674             /*
    675              * If we are setting the range, the MAC address is incremented by
    676              * 1 for each port.
    677              */
    678             /* coverity[overrun-local : FALSE] */
    679             DPORT_SOC_PBMP_ITER(unit, arg_pbmp, dport, p) {
    680                 bcm_error_t rv;
    681                 /* Fill l2addr structure */
    682                 bcm_l2_addr_t_init(&l2addr, arg_macaddr, arg_vlan);
    683                 l2addr.tgid = arg_tgid;
    684                 l2addr.group = arg_group;
    685                 l2addr.flags = flags;
    686         
    687                 SOC_IF_ERROR_RETURN(bcm_stk_my_modid_get(unit, &mymodid));
    688 
    689                 /*
    690                  * Handle devices that don't support port stacking by
    691                  * ignoring BCM_E_UNAVAIL status
    692                  */
    693                 rv = bcm_stk_modmap_map(unit, BCM_STK_MODMAP_GET, mymodid,
    694                                         p, &mymodid, &p);
    695 
    696                 if ((BCM_FAILURE(rv)) && (rv != BCM_E_UNAVAIL)) {
    697                     cli_out("%s ERROR: bcm_stk_modmap_map returned %d(%s)\n",
    698                             ARG_CMD(a), rv, bcm_errmsg(rv));
    699                     return CMD_FAIL;
    700                 }
    701 
    702                 l2addr.port = p;
    703                 l2addr.modid = mymodid;
    704                 BCM_PBMP_ASSIGN(l2addr.block_bitmap, arg_pbmp_mb);
    705         	    
    706                 if ((rv = bcm_l2_addr_add(unit, &l2addr))!= BCM_E_NONE) {
    707                     cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
    708                     return CMD_FAIL;
    709                 }
    710 
    711                 dump_l2_addr(unit, "ADD: ", &l2addr);
    712 
    713                 /* Set up for next call */
    714                 increment_macaddr(arg_macaddr, 1);
    715             }
    716     	} 
    717     
    718 	return CMD_OK;
    719     } else if (!sal_strcasecmp(subcmd, "del") ||
    720 	     !sal_strcasecmp(subcmd, "-")) {
    721 
    722 	parse_table_init(unit, &pt);
    723 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
    724 			0, &arg_macaddr,NULL);
    725 	parse_table_add(&pt, "Count", 	PQ_DFL|PQ_INT,
    726 			(void *)(1), &arg_count, NULL);
    727         parse_table_add(&pt, "Vlanid",  PQ_DFL|PQ_HEX,
    728 			0, &arg_vlan,	NULL);
    729 	if (!parseEndOk(a, &pt, &retCode)) {
    730 	    return retCode;
    731 	}
    732 
    733 	for (idx = 0; idx < arg_count; idx++) {
    734             bcm_l2_addr_t_init(&l2addr, arg_macaddr, arg_vlan);
    735 	    rv = bcm_l2_addr_get(unit, arg_macaddr, arg_vlan, &l2addr);
    736 	    if (rv < 0) {
    737 		cli_out("%s: ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
    738 		return CMD_FAIL;
    739 	    }
    740 
    741             if (LOG_CHECK(BSL_LS_BCM_L2 | BSL_VERBOSE)) {
    742                 dump_l2_addr(unit, "DEL: ", &l2addr);
    743             }
    744 
    745 	    if ((rv = bcm_l2_addr_delete(unit, arg_macaddr, arg_vlan)) < 0) {
    746 		cli_out("%s: ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
    747 		return CMD_FAIL;
    748 	    }
    749 
    750 	    increment_macaddr(arg_macaddr, 1);
    751 
    752         }
    753         arg_count = 1;
    754 	return CMD_OK;
    755     }
    756 
    757     else if (!sal_strcasecmp(subcmd, "show") ||
    758              !sal_strcasecmp(subcmd, "-d") ||
    759              !sal_strcasecmp(subcmd, "count")) {
    760 
    761 #ifdef BCM_XGS_SWITCH_SUPPORT
    762     if (SOC_IS_XGS_SWITCH(unit)) {
    763 
    764 #if defined(BCM_TRIUMPH3_SUPPORT)
    765         if (soc_feature(unit, soc_feature_ism_memory)) {
    766             sal_memset(&_l2_addr_counts, 0, sizeof(_l2_addr_counts));
    767             if(!sal_strcasecmp(subcmd, "count")) {
    768                 _l2_addr_counts.flags = L2_DUMP_COUNT;
    769             }
    770         } else if(!sal_strcasecmp(subcmd, "count")) {
    771             cli_out("ERROR: %s %s not implemented on this unit\n",
    772                     ARG_CMD(a), subcmd);
    773             return BCM_E_UNAVAIL;
    774         }
    775 #else
    776         if(!sal_strcasecmp(subcmd, "count")) {
    777             cli_out("ERROR: %s %s not implemented on this unit\n",
    778                     ARG_CMD(a), subcmd);
    779             return BCM_E_UNAVAIL;
    780         }
    781 #endif
    782 
    783         rv = bcm_l2_traverse(unit, _l2addr_dump, NULL);
    784 
    785         if (rv < 0) {
    786             cli_out("%s: ERROR: bcm_l2_traverse failed %s\n",
    787                     ARG_CMD(a), bcm_errmsg(rv));
    788         }
    789 
    790 #if defined(BCM_TRIUMPH3_SUPPORT)
    791             if (soc_feature(unit, soc_feature_ism_memory)) {
    792                 if(_l2_addr_counts.flags & L2_DUMP_COUNT) {
    793                     cli_out("\n L2 Counts:");
    794                     cli_out("\n  L2_ENTRY_1: %d",
    795                             _l2_addr_counts.l2_count.l2_entry_1);
    796                     cli_out("\n  L2_ENTRY_2: %d\n",
    797                             _l2_addr_counts.l2_count.l2_entry_2);
    798                     if ((soc_feature(unit, soc_feature_esm_support)) ) {
    799                         cli_out("\n  EXT_L2_ENTRY_1: %d",
    800                                 _l2_addr_counts.l2_count.ext_l2_entry_1);
    801                         cli_out("\n  EXT_L2_ENTRY_1: %d\n\n",
    802                                 _l2_addr_counts.l2_count.ext_l2_entry_2);
    803                     }
    804                 }
    805 
    806                 /* Reset the L2 counts structure for subsequent runs */
    807                 sal_memset(&_l2_addr_counts, 0, sizeof(_l2_addr_counts));
    808             }
    809 #endif
    810 
    811         return CMD_OK;
    812 
    813     }
    814 
    815 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    816 
    817 	cli_out("ERROR: %s %s not implemented on this unit\n",
    818                 ARG_CMD(a), subcmd);
    819 	return CMD_FAIL;
    820     }
    821 
    822     else if (!sal_strcasecmp(subcmd, "check")) {
    823         int i, rv, min, max;
    824         l2x_entry_t entry;
    825         char *sscmd;
    826         soc_mem_t mem;
    827         soc_field_t fld;
    828 
    829         mem = INVALIDm;
    830         fld = INVALIDf;
    831         if ((sscmd = ARG_GET(a)) != NULL) {
    832             cli_out("Subcommands not supported\n");
    833             return CMD_USAGE;
    834         } else {
    835             if (SOC_IS_TRIUMPH3(unit)) {
    836                 mem = L2_ENTRY_1m; 
    837             }else {   
    838                mem = L2Xm;
    839             } 
    840             fld = VALIDf;
    841 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    842             if(SOC_MEM_FIELD_VALID(unit, mem, BASE_VALIDf)) {
    843                 fld = BASE_VALIDf;
    844             }
    845 #endif 
    846         }
    847         if (!SOC_IS_XGS_SWITCH(unit)) {
    848             cli_out("Command only valid for XGS switches\n");
    849             return CMD_FAIL;
    850         }
    851 
    852         if (!SOC_MEM_IS_VALID(unit, mem)) {
    853             cli_out("Error: Memory %s not valid for chip %s.\n",
    854                     SOC_MEM_UFNAME(unit, mem), SOC_UNIT_NAME(unit));
    855             return CMD_FAIL;
    856         }
    857 
    858         min = soc_mem_index_min(unit, mem);
    859         max = soc_mem_index_max(unit, mem);
    860 
    861         cli_out("Dumping %s entries.  From %d to %d.\n",
    862                 sscmd, min, max);
    863 
    864         cli_out("Progress . marks 100 memory table entries.\n");
    865         for (i = min; i < max; i++) {
    866             if (!((i+1)%100)) {
    867                 cli_out(".");
    868                 if (!((i+1)%4000)) {
    869                     cli_out("\n");
    870                 }
    871             }
    872             rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, i, &entry);
    873             if (SOC_SUCCESS(rv)) {
    874                if (soc_mem_field32_get(unit, mem, &entry, fld)) {
    875                   cli_out("Index %d (0x%x) has valid entries (H: %x, E: %d)\n",
    876                           i, i, i>>3, i&0x3);
    877                   soc_mem_entry_dump(unit, mem, &entry, BSL_LSS_CLI);
    878                   cli_out("\n");
    879                }
    880             }
    881         }
    882         cli_out("Done.\n");
    883     }
    884 
    885     else if (!sal_strcasecmp(subcmd, "clear") ||
    886 	     !sal_strcasecmp(subcmd, "clr")) {
    887         char *static_str;
    888         int old_modid, old_port, old_vlan, old_tgid, old_static, old_pending;
    889         enum {
    890             MAC_PRESENT         = 0x00000001,
    891             MODID_PRESENT       = 0x00000002,
    892             PORT_PRESENT        = 0x00000004,
    893             VLANID_PRESENT      = 0x00000008,
    894             TGID_PRESENT        = 0x00000010
    895         } arg_combination;
    896         
    897 	/*
    898 	 * Clear the ARL on a per port or per switch basis. Walk ARL
    899 	 * memory finding matching ports such as the user specified,
    900 	 * issue BCM L2 SDK calls for clearing the entries.
    901 	 */
    902 
    903         /* Save current arguments */
    904         old_modid = arg_modid;
    905 	old_port = arg_port;
    906 	old_vlan = arg_vlan;
    907 	old_tgid = arg_tgid;
    908 	old_static = arg_static;
    909 	old_pending = arg_pending;
    910 
    911 	arg_modid = -1;
    912 	arg_port = -1;
    913 	arg_vlan = -1;
    914 	arg_tgid = -1;
    915 	arg_static = TRUE;
    916 	arg_pending = FALSE;
    917         ENET_SET_MACADDR(arg_macaddr, _soc_mac_all_zeroes);
    918         arg_combination = 0;
    919 
    920 	parse_table_init(unit, &pt);
    921 	parse_table_add(&pt, "Module",          PQ_DFL|PQ_INT,
    922 			0, &arg_modid,  NULL);
    923 	parse_table_add(&pt, "Port",            PQ_DFL|PQ_PORT,
    924 			0, &arg_port,   NULL);
    925 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
    926 			0, &arg_vlan,	NULL);
    927 	parse_table_add(&pt, "TrunkGroupID", 	PQ_DFL|PQ_INT,
    928 			0, &arg_tgid,	NULL);
    929         parse_table_add(&pt, "MACaddress",      PQ_DFL|PQ_MAC,
    930                         0, &arg_macaddr,NULL);
    931 	parse_table_add(&pt, "STatic", 	        PQ_DFL|PQ_BOOL,
    932 			0, &arg_static,	NULL);
    933 	parse_table_add(&pt, "PENDing",         PQ_DFL|PQ_BOOL,
    934 			0, &arg_pending, NULL);
    935 
    936         retCode = CMD_OK;
    937 
    938         if (!ARG_CNT(a)) {
    939             /*
    940              * Restore arguments for parseEndOk below to print
    941              * correct settings.
    942              */
    943             if (arg_modid == -1) arg_modid = old_modid;
    944             if (arg_port == -1) arg_port = old_port;
    945             if (arg_vlan == -1) arg_vlan = old_vlan;
    946             if (arg_tgid == -1) arg_tgid = old_tgid;
    947             if (arg_static == -1) arg_static = old_static;
    948             if (arg_pending == -1) arg_pending = old_pending;
    949         }
    950 
    951 	if (!parseEndOk(a, &pt, &retCode)) {
    952 	    goto done;
    953         }
    954 
    955         /*
    956          * Notice which arguments were supplied
    957          */
    958         if (arg_modid >=0) {
    959             arg_combination |= MODID_PRESENT;
    960         }
    961 
    962         if (arg_port >= 0) {
    963             arg_combination |= PORT_PRESENT;
    964         }
    965 
    966         if (ENET_CMP_MACADDR(arg_macaddr, _soc_mac_all_zeroes)) {
    967             arg_combination |= MAC_PRESENT;
    968         }
    969 
    970         if (arg_tgid >= 0) {
    971             arg_combination |= TGID_PRESENT;
    972         }
    973 
    974         if (arg_vlan >= 0) {
    975             arg_combination |= VLANID_PRESENT;
    976         }
    977 
    978         arg_static = arg_static ? BCM_L2_DELETE_STATIC : 0;
    979         if (arg_pending == TRUE) {
    980             static_str = arg_static ? "static and pending" : "pending";
    981             arg_static |= BCM_L2_DELETE_PENDING;
    982         } else {
    983             static_str = arg_static ? "static and non-static" : "non-static";
    984         }
    985         switch ((int)arg_combination) {
    986         case PORT_PRESENT:
    987 	    cli_out("%s: Deleting %s addresses by port, local module ID\n",
    988                     ARG_CMD(a), static_str);
    989 	    rv = bcm_l2_addr_delete_by_port(unit,
    990 					    -1, arg_port,
    991 					    arg_static);
    992             break;
    993 
    994         case PORT_PRESENT | MODID_PRESENT:
    995 	    cli_out("%s: Deleting %s addresses by module/port\n",
    996                     ARG_CMD(a), static_str);
    997 	    rv = bcm_l2_addr_delete_by_port(unit,
    998 					    arg_modid, arg_port,
    999 					    arg_static);
   1000             break;
   1001 
   1002         case VLANID_PRESENT:
   1003 	    cli_out("%s: Deleting %s addresses by VLAN\n",
   1004                     ARG_CMD(a), static_str);
   1005 	    rv = bcm_l2_addr_delete_by_vlan(unit,
   1006 					    arg_vlan,
   1007 					    arg_static);
   1008             break;
   1009 
   1010         case TGID_PRESENT:
   1011 	    cli_out("%s: Deleting %s addresses by trunk ID\n",
   1012                     ARG_CMD(a), static_str);
   1013 	    rv = bcm_l2_addr_delete_by_trunk(unit,
   1014 					     arg_tgid,
   1015 					     arg_static);
   1016 
   1017 	    break;
   1018 
   1019         case MAC_PRESENT:
   1020             cli_out("%s: Deleting %s addresses by MAC\n",
   1021                     ARG_CMD(a), static_str);
   1022             rv = bcm_l2_addr_delete_by_mac(unit, 
   1023                                            arg_macaddr, 
   1024                                            arg_static);
   1025             break;
   1026 
   1027         case MAC_PRESENT | VLANID_PRESENT:
   1028             cli_out("%s: Deleting an address by MAC and VLAN\n",
   1029                     ARG_CMD(a));
   1030             rv = bcm_l2_addr_delete(unit, 
   1031                                     arg_macaddr, 
   1032                                     arg_vlan);
   1033 
   1034             break;
   1035 
   1036         case MAC_PRESENT | PORT_PRESENT:
   1037             cli_out("%s: Deleting %s addresses by MAC and port\n",
   1038                     ARG_CMD(a), static_str);
   1039             rv = bcm_l2_addr_delete_by_mac_port(unit, 
   1040                                                 arg_macaddr, 
   1041                                                 -1, arg_port,
   1042                                                 arg_static);
   1043             break;
   1044 
   1045         case MAC_PRESENT | PORT_PRESENT | MODID_PRESENT:
   1046             cli_out("%s: Deleting %s addresses by MAC and module/port\n",
   1047                     ARG_CMD(a), static_str);
   1048             rv = bcm_l2_addr_delete_by_mac_port(unit, 
   1049                                                 arg_macaddr, 
   1050                                                 arg_modid, arg_port,
   1051                                                 arg_static);
   1052             break;
   1053 
   1054         case VLANID_PRESENT | PORT_PRESENT:
   1055 	    cli_out("%s: Deleting %s addresses by VLAN and port\n",
   1056                     ARG_CMD(a), static_str);
   1057 	    rv = bcm_l2_addr_delete_by_vlan_port(unit,
   1058 						 arg_vlan,
   1059 						 -1, arg_port,
   1060 						 arg_static);
   1061             break;
   1062 
   1063         case VLANID_PRESENT | PORT_PRESENT | MODID_PRESENT:
   1064 	    cli_out("%s: Deleting %s addresses by VLAN and module/port\n",
   1065                     ARG_CMD(a), static_str);
   1066 	    rv = bcm_l2_addr_delete_by_vlan_port(unit,
   1067 						 arg_vlan,
   1068 						 arg_modid, arg_port,
   1069 						 arg_static);
   1070             break;
   1071 
   1072         case VLANID_PRESENT | TGID_PRESENT:
   1073             cli_out("%s: Deleting %s addresses by VLAN and trunk ID\n",
   1074                     ARG_CMD(a), static_str);
   1075             rv = bcm_l2_addr_delete_by_vlan_trunk(unit,
   1076                                                   arg_vlan,
   1077                                                   arg_tgid,
   1078                                                   arg_static);
   1079             break;
   1080 
   1081         default:
   1082 	    cli_out("%s: Unknown argument combination\n", ARG_CMD(a));
   1083 	    retCode = CMD_USAGE;
   1084             break;
   1085 	}
   1086 
   1087 done:
   1088         /* Restore unused arguments */
   1089         if (arg_modid == -1) arg_modid = old_modid;
   1090 	if (arg_port == -1) arg_port = old_port;
   1091 	if (arg_vlan == -1) arg_vlan = old_vlan;
   1092 	if (arg_tgid == -1) arg_tgid = old_tgid;
   1093 	if (arg_static == -1) arg_static = old_static;
   1094 	if (arg_pending == -1) arg_pending = old_pending;
   1095 
   1096         if ((retCode == CMD_OK) && (rv < 0)) {
   1097             cli_out("ERROR: %s\n", bcm_errmsg(rv));
   1098             return CMD_FAIL;
   1099         }
   1100 
   1101 	return retCode;
   1102     }
   1103 
   1104     else if (!sal_strcasecmp(subcmd, "watch")) {
   1105 	static int watch = 0;
   1106 	char* opt = ARG_GET(a);
   1107 	if(opt == NULL) {
   1108 	    cli_out("L2 watch is%srunning.\n",
   1109                     (watch) ? " " : " not ");
   1110 	    return CMD_OK;
   1111 	}
   1112 	else if(!sal_strcasecmp(opt, "start")) {
   1113 	    watch = 1;
   1114 	    bcm_l2_addr_register(unit, _l2_watch_cb, NULL);
   1115 	    return CMD_OK;
   1116 	}
   1117 	else if(!sal_strcasecmp(opt, "stop")) {
   1118 	    watch = 0;
   1119 	    bcm_l2_addr_unregister(unit, _l2_watch_cb, NULL);
   1120 	    return CMD_OK;
   1121 	}
   1122 	else {
   1123 	    return CMD_USAGE;
   1124 	}
   1125     }
   1126 
   1127 #ifdef BCM_XGS_SWITCH_SUPPORT
   1128     else if (!sal_strcasecmp(subcmd, "conflict")) {
   1129 	bcm_l2_addr_t		addr;
   1130 	bcm_l2_addr_t		cf[SOC_L2X_BUCKET_SIZE];
   1131 	int			cf_count, i;
   1132 
   1133 	parse_table_init(unit, &pt);
   1134 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   1135 			0, &arg_macaddr,NULL);
   1136 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   1137 			0, &arg_vlan,	NULL);
   1138 	if (!parseEndOk(a, &pt, &retCode))
   1139 	    return retCode;
   1140 
   1141 	bcm_l2_addr_t_init(&addr, arg_macaddr, arg_vlan);
   1142 
   1143 	if ((rv = bcm_l2_conflict_get(unit, &addr,
   1144 				      cf, sizeof (cf) / sizeof (cf[0]),
   1145 				      &cf_count)) < 0) {
   1146 	    cli_out("%s: bcm_l2_conflict_get failed: %s\n",
   1147                     ARG_CMD(a), bcm_errmsg(rv));
   1148 	    return CMD_FAIL;
   1149 	}
   1150 
   1151 	for (i = 0; i < cf_count; i++) {
   1152 	    dump_l2_addr(unit, "conflict: ", &cf[i]);
   1153 	}
   1154 
   1155 	return CMD_OK;
   1156     }
   1157 
   1158     else if (!sal_strcasecmp(subcmd, "hash") ||
   1159 	     !sal_strcasecmp(subcmd, "-h") ) {
   1160 	int hash_select;
   1161 	int hash_bucket = 0;
   1162 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT) || \
   1163     defined(BCM_TOMAHAWK_SUPPORT)
   1164     int num_l2_banks                  = 0;
   1165     int bank                          = 0;
   1166     int l2_index_array[L2_MAX_BANKS]  = {0};
   1167     int l2_bucket_array[L2_MAX_BANKS] = {0};
   1168 #endif
   1169 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
   1170         defined(BCM_TRX_SUPPORT)
   1171 	int hash_select2 = -1;
   1172 	int hash_bucket2 = -1;
   1173 #endif
   1174 	uint32 regval;
   1175 	uint8 key[XGS_HASH_KEY_SIZE];
   1176 
   1177 	parse_table_init(unit, &pt);
   1178 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   1179 			0, &arg_macaddr,NULL);
   1180 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   1181 			0, &arg_vlan,	NULL);
   1182 	parse_table_add(&pt, "Hash", 	PQ_DFL|PQ_INT,
   1183 			(void *)(0), &arg_hash, NULL);
   1184 	if (!parseEndOk(a, &pt, &retCode))
   1185 	    return retCode;
   1186 
   1187 	hash_select = arg_hash;
   1188 #ifdef BCM_XGS3_SWITCH_SUPPORT
   1189         if (SOC_IS_XGS3_SWITCH(unit)) {
   1190 #ifdef BCM_ISM_SUPPORT
   1191             if (soc_feature(unit, soc_feature_ism_memory)) {
   1192                 int b, rc, index;
   1193                 l2_entry_1_entry_t entry;
   1194                 soc_field_t keyflds[MAX_FIELDS], lsbfld;
   1195                 uint32 bucket, sizes[_SOC_ISM_MAX_BANKS];
   1196                 uint8 act_zero_lsb, act_offset, zero_lsb = 0, offset = 48;
   1197                 uint8 banks[_SOC_ISM_MAX_BANKS], bcount, num_flds;
   1198                 
   1199                 sal_memset(&entry, 0, sizeof(entry));
   1200                 soc_L2_ENTRY_1m_field32_set(unit, &entry, VALIDf, 1);
   1201                 soc_L2_ENTRY_1m_field32_set(unit, &entry, VLAN_IDf, arg_vlan);
   1202                 soc_L2_ENTRY_1m_mac_addr_set(unit, &entry, MAC_ADDRf, arg_macaddr);
   1203                 
   1204                 rc = soc_ism_get_banks_for_mem(unit, L2_ENTRY_1m, banks, sizes, &bcount);
   1205                 if (rc || !bcount) {
   1206                     cli_out("Error retreiving bank info: Test aborted.\n");
   1207                     return CMD_FAIL;
   1208                 }
   1209                 rc = soc_generic_get_hash_key(unit, L2_ENTRY_1m, &entry, keyflds, &lsbfld,
   1210                                               &num_flds);
   1211                 if (rc) {
   1212                     cli_out("Error constructing key: Test aborted.\n");
   1213                     return CMD_FAIL;
   1214                 }
   1215                 sal_memset(key, 0, sizeof(key));
   1216                 soc_ism_gen_key_from_keyfields(unit, L2_ENTRY_1m, &entry, keyflds, key, num_flds);
   1217                 cli_out("Hash[%d] of key "
   1218                         "0x%02x%02x%02x%02x%02x%02x%02x%02x is \n", hash_select,
   1219                         key[7], key[6], key[5], key[4],
   1220                         key[3], key[2], key[1], key[0]);
   1221                 for (b = 0; b < bcount; b++) {
   1222                     rc = soc_ism_mem_hash_config_get(unit, L2_ENTRY_1m, &act_zero_lsb);
   1223                     if (rc) {
   1224                         cli_out("Error retreiving hash config: Test aborted.\n");
   1225                         return CMD_FAIL;
   1226                     }
   1227                     rc = soc_ism_hash_offset_config_get(unit, banks[b], &act_offset);
   1228                     if (rc) {
   1229                         cli_out("Error retreiving hash offset: Test aborted.\n");
   1230                         return CMD_FAIL;
   1231                     }
   1232                     switch(hash_select) {
   1233                     case XGS_HASH_CRC16_UPPER: offset = 48 - soc_ism_get_hash_bits(sizes[b]);
   1234                         break;
   1235                     case XGS_HASH_CRC16_LOWER: offset = 32;
   1236                         break;
   1237                     case XGS_HASH_LSB: offset = 48; zero_lsb = 1;
   1238                         break;
   1239                     case XGS_HASH_ZERO:
   1240                         break;
   1241                     case XGS_HASH_CRC32_UPPER: offset = 32 - soc_ism_get_hash_bits(sizes[b]);
   1242                         break;
   1243                     case XGS_HASH_CRC32_LOWER: offset = 0;
   1244                         break;
   1245                     case XGS_HASH_COUNT: offset = act_offset; zero_lsb = act_zero_lsb;
   1246                         break;
   1247                     default: if (hash_select > 63) {
   1248                                  cli_out("Invalid hash offset value !!\n");
   1249                                  return CMD_FAIL;
   1250                              }
   1251                         offset = hash_select; if (hash_select >= 48) { zero_lsb = 1; }
   1252                         break;
   1253                     }
   1254                     /* get config */
   1255                     if (zero_lsb != act_zero_lsb) {
   1256                         rc = soc_ism_mem_hash_config(unit, L2_ENTRY_1m, zero_lsb);
   1257                         if (rc) {
   1258                             cli_out("Error setting hash config: Test aborted.\n");
   1259                             return CMD_FAIL;
   1260                         }
   1261                     }
   1262                     if (offset != act_offset) {
   1263                         rc = soc_ism_hash_offset_config(unit, banks[b], offset);
   1264                         if (rc) {
   1265                             cli_out("Error setting hash offset: Test aborted.\n");
   1266                             return CMD_FAIL;
   1267                         }
   1268                     }
   1269                     rc = soc_generic_hash(unit, L2_ENTRY_1m, &entry, 1 << banks[b], 0,
   1270                                           &index, NULL, &bucket, NULL);
   1271                     if (rc) {
   1272                         cli_out("Error calculating hash: Test aborted.\n");
   1273                         return CMD_FAIL;
   1274                     }
   1275                     cli_out("\tBank[%d] num: %d, bucket: %d, index: %d\n", b, 
   1276                             banks[b], bucket, index);
   1277                     /* restore config */
   1278                     if (zero_lsb != act_zero_lsb) {
   1279                         rc = soc_ism_mem_hash_config(unit, L2_ENTRY_1m, act_zero_lsb);
   1280                         if (rc) {
   1281                             cli_out("Error setting hash config: Test aborted.\n");
   1282                             return CMD_FAIL;
   1283                         }
   1284                     }
   1285                     if (offset != act_offset) {
   1286                         rc = soc_ism_hash_offset_config(unit, banks[b], act_offset);
   1287                         if (rc) {
   1288                             cli_out("Error setting hash offset: Test aborted.\n");
   1289                             return CMD_FAIL;
   1290                         }
   1291                     }
   1292                 }
   1293                 return CMD_OK;
   1294             }
   1295 #endif /* BCM_ISM_SUPPORT */
   1296 	    if (
   1297 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1298 	       (!SOC_IS_TOMAHAWK3(unit)) &&
   1299 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1300 	       (hash_select == XGS_HASH_COUNT)) {
   1301 	        /* Get the hash selection from hardware */
   1302 	        if ( (rv = READ_HASH_CONTROLr(unit, &regval)) < 0) {
   1303 		    cli_out("%s: ERROR: %s\n", ARG_CMD(a), soc_errmsg(rv));
   1304 		    return CMD_FAIL;
   1305 	        }
   1306 	        hash_select = soc_reg_field_get(unit, HASH_CONTROLr, regval,
   1307 					        L2_AND_VLAN_MAC_HASH_SELECTf);
   1308 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
   1309         defined(BCM_TRX_SUPPORT)
   1310                 if (soc_feature(unit, soc_feature_dual_hash)) {
   1311 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT) || \
   1312     defined(BCM_TOMAHAWK_SUPPORT)
   1313                     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)) {
   1314                         if ( (rv = READ_L2_TABLE_HASH_CONTROLr(unit,
   1315                                                              &regval)) < 0) {
   1316                             cli_out("%s: ERROR: %s\n", ARG_CMD(a),
   1317                                     soc_errmsg(rv));
   1318                             return CMD_FAIL;
   1319                         }
   1320                         hash_select2 =
   1321                             soc_reg_field_get(unit, L2_TABLE_HASH_CONTROLr,
   1322                                               regval, HASH_ZERO_OR_LSBf);
   1323                         if (0 == hash_select2) {
   1324                             hash_select2 = FB_HASH_ZERO;
   1325                         } else if (1 == hash_select2) {
   1326                             hash_select2 = FB_HASH_LSB;
   1327                         }
   1328                     } else 
   1329 #endif
   1330                     {
   1331                         if ( (rv = READ_L2_AUX_HASH_CONTROLr(unit,
   1332                                                              &regval)) < 0) {
   1333                             cli_out("%s: ERROR: %s\n", ARG_CMD(a),
   1334                                     soc_errmsg(rv));
   1335                             return CMD_FAIL;
   1336                         }
   1337                         hash_select2 =
   1338                             soc_reg_field_get(unit, L2_AUX_HASH_CONTROLr,
   1339                                               regval, HASH_SELECTf);
   1340                     }
   1341                 }
   1342 #endif
   1343 	    }
   1344 
   1345 #ifdef BCM_TRX_SUPPORT
   1346             if (SOC_IS_TRX(unit)) {
   1347                 int bits;
   1348                 l2x_entry_t entry;
   1349 
   1350                 sal_memset(&entry, 0, sizeof(entry));
   1351                 soc_L2Xm_field32_set(unit, &entry, VLAN_IDf, arg_vlan);
   1352                 soc_L2Xm_mac_addr_set(unit, &entry, MAC_ADDRf, arg_macaddr);
   1353             bits = soc_tr_l2x_base_entry_to_key(unit, &entry, key);
   1354 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TOMAHAWK_SUPPORT) ||   \
   1355     defined(BCM_TRIDENT2_SUPPORT)
   1356             if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)) {
   1357                 if ((rv = soc_td2x_th_l2x_hash(unit, (uint32 *)&entry,
   1358                                                &num_l2_banks, l2_bucket_array,
   1359                                                l2_index_array, key)) < 0) {
   1360                     cli_out("%s ERROR: %s\n", ARG_CMD(a), soc_errmsg(rv));
   1361                     return CMD_FAIL;
   1362                 }
   1363 
   1364                 if (num_l2_banks > L2_MAX_BANKS) {
   1365                     cli_out("%s ERROR: the number of banks overflow\n",
   1366                             ARG_CMD(a));
   1367                     return CMD_FAIL;
   1368                 }
   1369             } else
   1370 #endif
   1371             {
   1372                 hash_bucket = soc_tr_l2x_hash(unit, hash_select, bits, &entry,
   1373                                                   key);
   1374             }
   1375                 if (hash_select2 >= 0) {
   1376                     hash_bucket2 =
   1377                         soc_tr_l2x_hash(unit, hash_select2, bits, &entry, key);
   1378                 }
   1379             } else
   1380 #endif
   1381 #ifdef BCM_FIREBOLT_SUPPORT
   1382             if (SOC_IS_FBX(unit)) {
   1383 	        soc_draco_l2x_param_to_key(arg_macaddr, arg_vlan, key);
   1384 	        hash_bucket = soc_fb_l2_hash(unit, hash_select, key);
   1385 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT)
   1386                 if (hash_select2 >= 0) {
   1387                     hash_bucket2 = soc_fb_l2_hash(unit, hash_select2, key);
   1388                 }
   1389 #endif
   1390             } else
   1391 #endif
   1392             {
   1393 	        return CMD_FAIL;
   1394             } 
   1395         }
   1396 #endif
   1397 
   1398 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TRIDENT2_SUPPORT) || \
   1399     defined(BCM_TOMAHAWK_SUPPORT)
   1400     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)) {
   1401         cli_out("Hash[%d] of key "
   1402                 "0x%02x%02x%02x%02x%02x%02x%02x%01x:\n",
   1403                 hash_select,
   1404                 key[7], key[6], key[5], key[4],
   1405                 key[3], key[2], key[1], (key[0] >> 4) & 0xf);
   1406 
   1407         for (bank = 0; bank < num_l2_banks; bank++) {
   1408             cli_out("bank%d bucket 0x%06x (%06d) index 0x%06x (%06d)\n",
   1409                      bank, l2_bucket_array[bank], l2_bucket_array[bank],
   1410                      l2_index_array[bank], l2_index_array[bank]);
   1411           
   1412         }
   1413 
   1414     } else
   1415 #endif
   1416     {
   1417         cli_out("Hash[%d] of key "
   1418                     "0x%02x%02x%02x%02x%02x%02x%02x%01x "
   1419                     "is bucket 0x%03x (%d)\n", hash_select,
   1420                     key[7], key[6], key[5], key[4],
   1421                     key[3], key[2], key[1], (key[0] >> 4) & 0xf,
   1422                     hash_bucket, hash_bucket);
   1423     }
   1424 
   1425 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
   1426         defined(BCM_TRX_SUPPORT)
   1427         if (hash_select2 >= 0) {
   1428             cli_out("Dual hash[%d] of key "
   1429                     "0x%02x%02x%02x%02x%02x%02x%02x%01x "
   1430                     "is bucket 0x%03x (%d)\n", hash_select2,
   1431                     key[7], key[6], key[5], key[4],
   1432                     key[3], key[2], key[1], (key[0] >> 4) & 0xf,
   1433                     hash_bucket2, hash_bucket2);
   1434         }
   1435 #endif
   1436     }
   1437 #endif /* BCM_XGS_SWITCH_SUPPORT */
   1438 
   1439 #ifdef BCM_XGS3_SWITCH_SUPPORT
   1440     else if (!sal_strcasecmp(subcmd, "cache") ||
   1441 	     !sal_strcasecmp(subcmd, "c") ) {
   1442         int cidx;
   1443         char *cachecmd = NULL;
   1444         char str[16];
   1445         sal_mac_addr_t arg_macaddr, arg_macaddr_mask;
   1446         int arg_setpri = 0, arg_bpdu = 0;
   1447         int arg_prio = -1, arg_lrndis = FALSE, arg_tunnel = FALSE;
   1448         int arg_vlan_mask, arg_cidx, arg_ccount, arg_reinit, idx_max;
   1449         int arg_sport = -1, arg_sport_mask;
   1450         int arg_lookup_class = 0;
   1451         int arg_protocolPkt = 0;
   1452         bcm_l2_cache_addr_t l2caddr;
   1453 
   1454         if ((cachecmd = ARG_GET(a)) == NULL) {
   1455             return CMD_USAGE;
   1456         }
   1457 
   1458         /* Masks always default to full mask */
   1459         arg_vlan_mask = BCM_L2_VID_MASK_ALL;
   1460         arg_sport_mask = BCM_L2_SRCPORT_MASK_ALL;
   1461         sal_memset(arg_macaddr, 0, sizeof (sal_mac_addr_t));
   1462         sal_memset(arg_macaddr_mask, 0xff, sizeof (sal_mac_addr_t));
   1463 
   1464         arg_cidx = -1;
   1465         arg_ccount = 1;
   1466 
   1467         if (!sal_strcasecmp(cachecmd, "add") ||
   1468             !sal_strcasecmp(cachecmd, "+") ) {
   1469 
   1470             parse_table_init(unit, &pt);
   1471             parse_table_add(&pt, "LookupClass",         PQ_DFL|PQ_INT,
   1472                             0, &arg_lookup_class, NULL);
   1473             parse_table_add(&pt, "CacheIndex",          PQ_DFL|PQ_INT,
   1474                             0, &arg_cidx,       NULL);
   1475             parse_table_add(&pt, "MACaddress",          PQ_DFL|PQ_MAC,
   1476                             0, &arg_macaddr,    NULL);
   1477             parse_table_add(&pt, "MACaddressMask",      PQ_DFL|PQ_MAC,
   1478                             0, &arg_macaddr_mask, NULL);
   1479             parse_table_add(&pt, "Vlanid",              PQ_DFL|PQ_HEX,
   1480                             0, &arg_vlan,       NULL);
   1481             parse_table_add(&pt, "VlanidMask",          PQ_DFL|PQ_HEX,
   1482                             0, &arg_vlan_mask,  NULL);
   1483             parse_table_add(&pt, "SourcePort",          PQ_DFL|PQ_PORT|PQ_BCM,
   1484                             0, &arg_sport,      NULL);
   1485             parse_table_add(&pt, "SourcePortMask",      PQ_DFL|PQ_HEX,
   1486                             0, &arg_sport_mask, NULL);
   1487             parse_table_add(&pt, "Module",              PQ_DFL|PQ_INT,
   1488                             0, &arg_modid,      NULL);
   1489             parse_table_add(&pt, "Port",                PQ_DFL|PQ_PORT,
   1490                             (void *)(0), &arg_port, NULL);
   1491             parse_table_add(&pt, "Trunk",               PQ_DFL|PQ_BOOL,
   1492                             0, &arg_trunk,	NULL);
   1493             parse_table_add(&pt, "TrunkGroupID",        PQ_DFL|PQ_INT,
   1494                             0, &arg_tgid,	NULL);
   1495             parse_table_add(&pt, "SetPriority",         PQ_DFL|PQ_BOOL,
   1496                             0, &arg_setpri,	NULL);
   1497             parse_table_add(&pt, "PRIOrity",            PQ_DFL|PQ_INT,
   1498                             0, &arg_prio,       NULL);
   1499             parse_table_add(&pt, "DiscardDest",         PQ_DFL|PQ_BOOL,
   1500                             0, &arg_dd,	NULL);
   1501             parse_table_add(&pt, "L3",                  PQ_DFL|PQ_BOOL,
   1502                             0, &arg_l3if,       NULL);
   1503             parse_table_add(&pt, "CPUmirror",           PQ_DFL|PQ_BOOL,
   1504                             0, &arg_cbit,       NULL);
   1505             parse_table_add(&pt, "MIRror",              PQ_DFL|PQ_BOOL,
   1506                             0, &arg_mirror,     NULL);
   1507             parse_table_add(&pt, "BPDU",                PQ_DFL|PQ_BOOL,
   1508                             0, &arg_bpdu,       NULL);
   1509             parse_table_add(&pt, "ReplacePriority",  PQ_DFL|PQ_BOOL,
   1510                             0, &arg_rpe,	NULL);
   1511             if (SOC_IS_FIREBOLT2(unit) || SOC_IS_TRX(unit)) {
   1512                 parse_table_add(&pt, "LearnDisable",   PQ_DFL|PQ_BOOL,
   1513                                 0, &arg_lrndis,	NULL);
   1514             }
   1515             parse_table_add(&pt, "PROTocolPacKeT",  PQ_DFL|PQ_BOOL,
   1516                             0, &arg_protocolPkt,	NULL);
   1517             if (!parseEndOk(a, &pt, &retCode)) {
   1518                 return retCode;
   1519             }
   1520 
   1521             if (arg_setpri && arg_prio == -1) {
   1522                 cli_out("%s ERROR: no priority specified\n", ARG_CMD(a));
   1523                 return CMD_FAIL;
   1524             }
   1525             if (!arg_setpri) {
   1526                 arg_prio = -1;
   1527             }
   1528 
   1529             bcm_l2_cache_addr_t_init(&l2caddr);
   1530 
   1531             l2caddr.vlan = arg_vlan_mask ? arg_vlan : 0;
   1532             l2caddr.vlan_mask = arg_vlan_mask;
   1533 
   1534             ENET_COPY_MACADDR(arg_macaddr, l2caddr.mac);
   1535             ENET_COPY_MACADDR(arg_macaddr_mask, l2caddr.mac_mask);
   1536 
   1537             if (arg_sport >= 0) {
   1538                 l2caddr.src_port = arg_sport;
   1539                 l2caddr.src_port_mask = arg_sport_mask;
   1540             }
   1541 
   1542             l2caddr.lookup_class = arg_lookup_class;
   1543 
   1544             l2caddr.dest_modid = arg_modid;
   1545             l2caddr.dest_port = arg_port;
   1546             l2caddr.prio = arg_prio;
   1547             l2caddr.dest_trunk = arg_tgid;
   1548 
   1549             /* Configure flags for SDK call */
   1550             if (arg_dd || arg_ds)
   1551                 l2caddr.flags |= BCM_L2_CACHE_DISCARD;
   1552             if (arg_l3if)
   1553                 l2caddr.flags |= BCM_L2_CACHE_L3;
   1554             if (arg_trunk)
   1555                 l2caddr.flags |= BCM_L2_CACHE_TRUNK;
   1556             if (arg_cbit)
   1557                 l2caddr.flags |= BCM_L2_CACHE_CPU;
   1558             if (arg_bpdu)
   1559                 l2caddr.flags |= BCM_L2_CACHE_BPDU;
   1560             if (arg_mirror)
   1561                 l2caddr.flags |= BCM_L2_CACHE_MIRROR;
   1562             if (arg_rpe || arg_setpri)
   1563                 l2caddr.flags |= BCM_L2_CACHE_SETPRI;
   1564             if (arg_lrndis)
   1565                 l2caddr.flags |= BCM_L2_CACHE_LEARN_DISABLE;
   1566             if (arg_tunnel)
   1567                 l2caddr.flags |= BCM_L2_CACHE_TUNNEL;
   1568             if (arg_protocolPkt)
   1569                 l2caddr.flags |= BCM_L2_CACHE_PROTO_PKT;
   1570 
   1571             dump_l2_cache_addr(unit, "ADD CACHE: ", &l2caddr);
   1572 
   1573             if ((rv = bcm_l2_cache_set(unit, arg_cidx, &l2caddr, 
   1574                                        &cidx)) != BCM_E_NONE) {
   1575                 cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1576                 return CMD_FAIL;
   1577             }
   1578 
   1579             if (arg_cidx == -1) {
   1580                 cli_out(" => using index %d\n", cidx);
   1581             }
   1582 
   1583 	    /* Set up for next call */
   1584 	    increment_macaddr(arg_macaddr, 1);
   1585             if (arg_cidx >= 0) {
   1586                 arg_cidx++;
   1587             }
   1588 
   1589             return CMD_OK;
   1590         }
   1591 
   1592         else if (!sal_strcasecmp(cachecmd, "del") ||
   1593                  !sal_strcasecmp(cachecmd, "-")) {
   1594 
   1595             if (ARG_CNT(a)) {
   1596                 parse_table_init(unit, &pt);
   1597                 parse_table_add(&pt, "CacheIndex",      PQ_DFL|PQ_INT,
   1598                                 0, &arg_cidx,   NULL);
   1599                 parse_table_add(&pt, "Count",           PQ_DFL|PQ_INT,
   1600                                 0, &arg_ccount, NULL);
   1601                 if (!parseEndOk(a, &pt, &retCode)) {
   1602                     return retCode;
   1603                 }
   1604             }
   1605 
   1606             if (arg_cidx == -1) {
   1607                 cli_out("%s ERROR: no index specified\n", ARG_CMD(a));
   1608                 return CMD_FAIL;
   1609             }
   1610 
   1611             for (idx = 0; idx < arg_ccount; idx++) {
   1612                 if ((rv = bcm_l2_cache_get(unit, arg_cidx, &l2caddr)) < 0) {
   1613                     cli_out("%s: ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1614                     return CMD_FAIL;
   1615                 }
   1616 
   1617                 if (LOG_CHECK(BSL_LS_BCM_L2 | BSL_VERBOSE)) {
   1618                     dump_l2_cache_addr(unit, "DEL CACHE: ", &l2caddr);
   1619                 }
   1620 
   1621                 if ((rv = bcm_l2_cache_delete(unit, arg_cidx)) != BCM_E_NONE) {
   1622                     cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1623                     return CMD_FAIL;
   1624                 }
   1625                 arg_cidx++;
   1626             }
   1627 
   1628             return CMD_OK;
   1629         }
   1630 
   1631         else if (!sal_strcasecmp(cachecmd, "show") ||
   1632                  !sal_strcasecmp(cachecmd, "-d")) {
   1633 
   1634 	    if ((rv = bcm_l2_cache_size_get(unit, &idx_max)) < 0) {
   1635 		cli_out("%s: ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1636 		return CMD_FAIL;
   1637 	    }
   1638 
   1639 	    for (idx = 0; idx < idx_max; idx++) {
   1640                 if (bcm_l2_cache_get(unit, idx, &l2caddr) == BCM_E_NONE) {
   1641                     sal_sprintf(str, " %4d : ", idx);
   1642                     dump_l2_cache_addr(unit, str, &l2caddr);
   1643                 }
   1644             }
   1645 
   1646             return CMD_OK;
   1647         }
   1648 
   1649         else if (!sal_strcasecmp(cachecmd, "clear") ||
   1650                  !sal_strcasecmp(cachecmd, "clr")) {
   1651 
   1652             arg_reinit = 0;
   1653 
   1654             if (ARG_CNT(a)) {
   1655                 parse_table_init(unit, &pt);
   1656                 parse_table_add(&pt, "ReInit",              PQ_DFL|PQ_BOOL,
   1657                                 0, &arg_reinit,     NULL);
   1658                 if (!parseEndOk(a, &pt, &retCode)) {
   1659                     return retCode;
   1660                 }
   1661             }
   1662 
   1663             if ((rv = bcm_l2_cache_delete_all(unit)) != BCM_E_NONE) {
   1664                 cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1665                 return CMD_FAIL;
   1666             }
   1667 
   1668             if (arg_reinit && (rv = bcm_l2_cache_init(unit)) != BCM_E_NONE) {
   1669                 cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1670                 return CMD_FAIL;
   1671             }
   1672 
   1673             return CMD_OK;
   1674         }
   1675 
   1676         else {
   1677             return CMD_USAGE;
   1678         }
   1679     }
   1680 #if defined(BCM_TRIUMPH_SUPPORT) /* BCM_TRIUMPH_SUPPORT */
   1681     else if (!sal_strcasecmp(subcmd, "station")) {
   1682         /* BCM.0> l2 station ... */
   1683         return _l2_station_cmd_process(unit, a);
   1684     }
   1685 #endif /* !BCM_TRIUMPH_SUPPORT */
   1686 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1687 
   1688     else {
   1689         return CMD_USAGE;
   1690     }
   1691 
   1692     return CMD_FAIL;
   1693 }
   1694 
   1695 
   1696 /*
   1697  * Add an L2 address to the switch, remove an L2 address from the
   1698  * switch, show addresses, and clear addresses on a per port basis.
   1699  */
   1700 
   1701 cmd_result_t
   1702 if_esw_bpdu(int unit, args_t *a)
   1703 {
   1704     int                 idx, count;
   1705     char 		*subcmd = NULL;
   1706     sal_mac_addr_t	arg_macaddr, maczero;
   1707     bcm_l2_cache_addr_t addr;
   1708     int		arg_index = 0, idx_used = 0;
   1709     cmd_result_t   retCode;
   1710     int rv;
   1711     parse_table_t	pt;
   1712     char		buf[SAL_MACADDR_STR_LEN];
   1713 
   1714     /*
   1715      * Initialize MAC address field for the user to the first real
   1716      * address which does not conflict
   1717      */
   1718     maczero[0] = arg_macaddr[0] = 0;
   1719     maczero[1] = arg_macaddr[1] = 0;
   1720     maczero[2] = arg_macaddr[2] = 0;
   1721     maczero[3] = arg_macaddr[3] = 0;
   1722     maczero[4] = arg_macaddr[4] = 0;
   1723     maczero[5] = 0;
   1724     arg_macaddr[5] = 0x1;
   1725 
   1726     if ((subcmd = ARG_GET(a)) == NULL) {
   1727 	return CMD_USAGE;
   1728     }
   1729 
   1730     /* Check valid device to operation on ...*/
   1731     if (!sh_check_attached(ARG_CMD(a), unit)) {
   1732 	return CMD_FAIL;
   1733     }
   1734 
   1735     if (!sal_strcasecmp(subcmd, "add") ||
   1736 	!sal_strcasecmp(subcmd, "+")) {
   1737 	parse_table_init(unit, &pt);
   1738 	parse_table_add(&pt, "Index", 	PQ_DFL|PQ_INT,
   1739 			(void *)(0), &arg_index, NULL);
   1740 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   1741 		    0, &arg_macaddr,NULL);
   1742 
   1743 	if (!parseEndOk(a, &pt, &retCode)) {
   1744 	    return retCode;
   1745 	}
   1746 
   1747         ENET_COPY_MACADDR(arg_macaddr, addr.mac);
   1748         addr.flags = BCM_L2_CACHE_BPDU;
   1749 	rv = bcm_l2_cache_set(unit, arg_index, &addr, &idx_used);
   1750 	if (rv != BCM_E_NONE) {
   1751 	    cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1752 	    return CMD_FAIL;
   1753 	}
   1754 	return CMD_OK;
   1755     }
   1756 
   1757     if (!sal_strcasecmp(subcmd, "del") ||
   1758 	!sal_strcasecmp(subcmd, "-")) {
   1759 	parse_table_init(unit, &pt);
   1760 	parse_table_add(&pt, "Index", 	PQ_DFL|PQ_INT,
   1761 			(void *)(0), &arg_index, NULL);
   1762 
   1763 	if (!parseEndOk(a, &pt, &retCode)) {
   1764 	    return retCode;
   1765 	}
   1766 
   1767         ENET_COPY_MACADDR(maczero, addr.mac);
   1768         addr.flags = BCM_L2_CACHE_BPDU;
   1769 	rv = bcm_l2_cache_set(unit, arg_index, &addr, &idx_used);
   1770 	if (rv != BCM_E_NONE) {
   1771 	    cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1772 	    return CMD_FAIL;
   1773 	}
   1774 	return CMD_OK;
   1775     }
   1776 
   1777     if (!sal_strcasecmp(subcmd, "show") ||
   1778 	!sal_strcasecmp(subcmd, "-d")) {
   1779 	rv = bcm_l2_cache_size_get(unit, &count);
   1780 	if (rv != BCM_E_NONE) {
   1781 	    cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1782 	    return CMD_FAIL;
   1783 	}   
   1784 	cli_out("unit %d has %d BPDU entries\n", unit, count);
   1785 	for (idx = 0; idx < count; idx++) {
   1786             rv = bcm_l2_cache_get(unit, idx, &addr);
   1787 	    if (rv == BCM_E_NOT_FOUND) {
   1788                 continue;
   1789 	    } else if (rv != BCM_E_NONE) {
   1790 		cli_out("%s ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
   1791 		return CMD_FAIL;
   1792 	    }
   1793 
   1794 	    format_macaddr(buf, addr.mac);
   1795 	    cli_out("\tBPDU %d: %s\n", idx, buf);
   1796 	}
   1797 	return CMD_OK ;
   1798     }
   1799     return CMD_USAGE;
   1800 }
   1801 
   1802 /*
   1803  * Multicast command
   1804  */
   1805 
   1806 cmd_result_t
   1807 if_esw_mcast(int unit, args_t *a)
   1808 {
   1809     char                *subcmd;
   1810     int			r;
   1811     sal_mac_addr_t	mac_address;
   1812     int		vid=1;
   1813     int		cos_dst=0;
   1814     int		mcindex = -1;
   1815     bcm_pbmp_t	pbmp;
   1816     bcm_pbmp_t	ubmp;
   1817     parse_table_t	pt;
   1818     cmd_result_t	retCode;
   1819     bcm_mcast_addr_t	mcaddr;
   1820     pbmp_t		rtrpbmp;
   1821     int			port, dport;
   1822 
   1823     mac_address[0] = 0x1;
   1824     mac_address[1] = 0;
   1825     mac_address[2] = 0;
   1826     mac_address[3] = 0;
   1827     mac_address[4] = 0;
   1828     mac_address[5] = 0x1;
   1829 
   1830     BCM_PBMP_CLEAR(pbmp);
   1831 
   1832     if (!sh_check_attached(ARG_CMD(a), unit)) {
   1833         return CMD_FAIL;
   1834     }
   1835 
   1836     if ((subcmd = ARG_GET(a)) == NULL) {
   1837 	return CMD_USAGE;
   1838     }
   1839 
   1840     if (!sal_strcasecmp(subcmd, "init")) {
   1841 	if ((r = bcm_mcast_init(unit)) < 0) {
   1842             cli_out("ERROR: %s\n", bcm_errmsg(r));
   1843             return CMD_FAIL;
   1844 	}
   1845         return CMD_OK;
   1846     }
   1847 
   1848     if (sal_strcasecmp(subcmd, "bitmap") == 0) {
   1849         if ((subcmd = ARG_GET(a)) == NULL) {
   1850             return CMD_USAGE;
   1851         }
   1852 
   1853         if (!SOC_IS_XGS_FABRIC(unit)) {
   1854 	    cli_out("Mcast bitmap operations only valid on XGS fabric devices\n");
   1855 	    return CMD_FAIL;
   1856         }
   1857 
   1858         if (sal_strcasecmp(subcmd, "max") == 0) {
   1859             if ((r = bcm_mcast_bitmap_max_get(unit, &mcindex)) < 0) {
   1860                 cli_out("bcm_mcast_bitmap_max_set failed ERROR: %s\n",
   1861                         bcm_errmsg(r));
   1862                 return CMD_FAIL;
   1863             }
   1864             cli_out("Unit %d: Maximum multicast index of %d\n",
   1865                     unit, mcindex);
   1866             return CMD_OK;
   1867         }
   1868 
   1869         if (sal_strcasecmp(subcmd, "set") == 0) {
   1870             parse_table_init(unit, &pt);
   1871             parse_table_add(&pt, "Port", PQ_DFL|PQ_PORT|PQ_BCM,
   1872                             (void *)(0), &port, NULL);
   1873             parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   1874                             (void *)(0), &pbmp, NULL);
   1875             parse_table_add(&pt, "Index", 	PQ_DFL|PQ_INT,
   1876                             0, &mcindex,	NULL);
   1877             if (!parseEndOk(a, &pt, &retCode))
   1878                 return retCode;
   1879 
   1880             if ((r = bcm_mcast_bitmap_set(unit, mcindex, port, pbmp)) < 0) {
   1881                 cli_out("bcm_mcast_bitmap_set failed ERROR: %s\n",
   1882                         bcm_errmsg(r));
   1883                 return CMD_FAIL;
   1884             }
   1885             return CMD_OK;
   1886         }
   1887 
   1888         if (sal_strcasecmp(subcmd, "del") == 0) {
   1889             parse_table_init(unit, &pt);
   1890             parse_table_add(&pt, "Port", PQ_DFL|PQ_PORT|PQ_BCM,
   1891                             (void *)(0), &port, NULL);
   1892             parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   1893                             (void *)(0), &pbmp, NULL);
   1894             parse_table_add(&pt, "Index", 	PQ_DFL|PQ_INT,
   1895                             0, &mcindex,	NULL);
   1896             if (!parseEndOk(a, &pt, &retCode))
   1897                 return retCode;
   1898 
   1899             if ((r = bcm_mcast_bitmap_del(unit, mcindex, port, pbmp)) < 0) {
   1900                 cli_out("bcm_mcast_bitmap_del failed ERROR: %s\n",
   1901                         bcm_errmsg(r));
   1902                 return CMD_FAIL;
   1903             }
   1904             return CMD_OK;
   1905         }
   1906 
   1907         if (sal_strcasecmp(subcmd, "get") == 0) {
   1908             char	buf[FORMAT_PBMP_MAX];
   1909             parse_table_init(unit, &pt);
   1910             parse_table_add(&pt, "Port", PQ_DFL|PQ_PORT|PQ_BCM,
   1911                             (void *)(0), &port, NULL);
   1912             parse_table_add(&pt, "Index", 	PQ_DFL|PQ_INT,
   1913                             0, &mcindex,	NULL);
   1914             if (!parseEndOk(a, &pt, &retCode))
   1915                 return retCode;
   1916 
   1917             if ((r = bcm_mcast_bitmap_get(unit, mcindex, port, &pbmp)) < 0) {
   1918                 cli_out("bcm_mcast_bitmap_get failed ERROR: %s\n",
   1919                         bcm_errmsg(r));
   1920                 return CMD_FAIL;
   1921             }
   1922             format_pbmp(unit, buf, sizeof (buf), pbmp);
   1923             cli_out("Unit %d: MC index=%d, Port=%d, Bitmap=%s\n",
   1924                     unit, mcindex, port, buf);
   1925             return CMD_OK;
   1926         }
   1927         return CMD_USAGE;
   1928     }
   1929 
   1930     if (SOC_IS_XGS_FABRIC(unit)) {
   1931         cli_out("Non-bitmap mcast operations only valid on XGS switch devices\n\n");
   1932         return CMD_USAGE;
   1933     }
   1934 
   1935     if (sal_strcasecmp(subcmd, "add") == 0) {
   1936 	parse_table_init(unit, &pt);
   1937 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   1938 			0, &mac_address,NULL);
   1939 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   1940 			0, &vid,	NULL);
   1941 	parse_table_add(&pt, "Cos", 	PQ_DFL|PQ_INT,
   1942 			0, &cos_dst,	NULL);
   1943 	parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   1944 			(void *)(0), &pbmp, NULL);
   1945 	parse_table_add(&pt, "UntagBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   1946 			(void *)(0), &ubmp, NULL);
   1947 	parse_table_add(&pt, "Index", 	PQ_DFL|PQ_INT,
   1948 			0, &mcindex,	NULL);
   1949 	if (!parseEndOk(a, &pt, &retCode))
   1950 	    return retCode;
   1951 
   1952 	bcm_mcast_addr_t_init(&mcaddr, mac_address, vid);
   1953 	mcaddr.cos_dst = cos_dst;
   1954 	BCM_PBMP_ASSIGN(mcaddr.pbmp, pbmp);
   1955 	BCM_PBMP_ASSIGN(mcaddr.ubmp, ubmp);
   1956 	mcaddr.l2mc_index = mcindex;
   1957 	if (mcindex < 0) {
   1958 	    r = bcm_mcast_addr_add(unit, &mcaddr);
   1959 	} else {
   1960 	    r = bcm_mcast_addr_add_w_l2mcindex(unit, &mcaddr);
   1961 	}
   1962 	if (r < 0) {
   1963 	    cli_out("bcm_mcast_addr_add failed ERROR: %s\n", bcm_errmsg(r));
   1964 	    return CMD_FAIL;
   1965 	}
   1966 	return CMD_OK;
   1967     }
   1968 
   1969     if (sal_strncasecmp(subcmd, "del", 3) == 0) {
   1970 	parse_table_init(unit, &pt);
   1971 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   1972 			0, &mac_address,NULL);
   1973 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   1974 			0, &vid,	NULL);
   1975 	if (!parseEndOk(a, &pt, &retCode))
   1976 	    return retCode;
   1977         if ((r = bcm_mcast_addr_remove(unit, mac_address, vid)) < 0) {
   1978             cli_out("bcm_mcast_addr_remove failed ERROR: %s\n",
   1979                     bcm_errmsg(r));
   1980             return CMD_FAIL;
   1981         }
   1982 	return CMD_OK;
   1983     }
   1984 
   1985     if (sal_strcasecmp(subcmd, "join") == 0) {
   1986 	parse_table_init(unit, &pt);
   1987 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   1988 			0, &mac_address,NULL);
   1989 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   1990 			0, &vid,	NULL);
   1991 	parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   1992 			(void *)(0), &pbmp, NULL);
   1993 	if (!parseEndOk(a, &pt, &retCode))
   1994 	    return retCode;
   1995         /* coverity[overrun-local : FALSE] */
   1996         DPORT_BCM_PBMP_ITER(unit, pbmp, dport, port) {
   1997 	    r = bcm_mcast_join(unit, mac_address, vid, port,
   1998 			       &mcaddr, &rtrpbmp);
   1999 	    if (r < 0) {
   2000 		cli_out("ERROR: %s %s port %s failed: %s\n",
   2001                         ARG_CMD(a), subcmd, BCM_PORT_NAME(unit, port),
   2002                         bcm_errmsg(r));
   2003 		return CMD_FAIL;
   2004 	    }
   2005 	    switch (r) {
   2006 	    case BCM_MCAST_JOIN_ADDED:
   2007 		cli_out("port %s added\n", BCM_PORT_NAME(unit, port));
   2008 		break;
   2009 	    case BCM_MCAST_JOIN_UPDATED:
   2010 		cli_out("port %s updated\n", BCM_PORT_NAME(unit, port));
   2011 		break;
   2012 	    default:
   2013 		cli_out("port %s complete, return %d\n",
   2014                         BCM_PORT_NAME(unit, port), r);
   2015 		break;
   2016 	    }
   2017 	}
   2018 	return CMD_OK;
   2019     }
   2020 
   2021     if (sal_strcasecmp(subcmd, "leave") == 0) {
   2022 	parse_table_init(unit, &pt);
   2023 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   2024 			0, &mac_address,NULL);
   2025 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   2026 			0, &vid,	NULL);
   2027 	parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   2028 			(void *)(0), &pbmp, NULL);
   2029 	if (!parseEndOk(a, &pt, &retCode))
   2030 	    return retCode;
   2031         DPORT_BCM_PBMP_ITER(unit, pbmp, dport, port) {
   2032 	    r = bcm_mcast_leave(unit, mac_address, vid, port);
   2033 	    if (r < 0) {
   2034 		cli_out("ERROR: %s %s port %s failed: %s\n",
   2035                         ARG_CMD(a), subcmd, BCM_PORT_NAME(unit, port),
   2036                         bcm_errmsg(r));
   2037 		return CMD_FAIL;
   2038 	    }
   2039 	    switch (r) {
   2040 	    case BCM_MCAST_LEAVE_NOTFOUND:
   2041 		cli_out("port %s not found\n", BCM_PORT_NAME(unit, port));
   2042 		break;
   2043 	    case BCM_MCAST_LEAVE_DELETED:
   2044 		cli_out("port %s deleted\n", BCM_PORT_NAME(unit, port));
   2045 		break;
   2046 	    case BCM_MCAST_LEAVE_UPDATED:
   2047 		cli_out("port %s updated\n", BCM_PORT_NAME(unit, port));
   2048 		break;
   2049 	    default:
   2050 		cli_out("port %s complete, return %d\n",
   2051                         BCM_PORT_NAME(unit, port), r);
   2052 		break;
   2053 	    }
   2054 	}
   2055 	return CMD_OK;
   2056     }
   2057 
   2058     if (sal_strcasecmp(subcmd, "padd") == 0) {
   2059 	parse_table_init(unit, &pt);
   2060 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   2061 			0, &mac_address, NULL);
   2062 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   2063 			0, &vid,	NULL);
   2064 	parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   2065 			(void *)(0), &pbmp, NULL);
   2066 	parse_table_add(&pt, "UntagBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   2067 			(void *)(0), &ubmp, NULL);
   2068 	if (!parseEndOk(a, &pt, &retCode))
   2069 	    return retCode;
   2070 	bcm_mcast_addr_t_init(&mcaddr, mac_address, vid);
   2071 	BCM_PBMP_ASSIGN(mcaddr.pbmp, pbmp);
   2072 	BCM_PBMP_ASSIGN(mcaddr.ubmp, ubmp);
   2073 	r = bcm_mcast_port_add(unit, &mcaddr);
   2074 	if (r < 0) {
   2075 	    cli_out("ERROR: %s %s ports failed: %s\n",
   2076                     ARG_CMD(a), subcmd, bcm_errmsg(r));
   2077 	    return CMD_FAIL;
   2078 	}
   2079 	return CMD_OK;
   2080     }
   2081 
   2082     if (sal_strcasecmp(subcmd, "premove") == 0) {
   2083 	parse_table_init(unit, &pt);
   2084 	parse_table_add(&pt, "MACaddress", 	PQ_DFL|PQ_MAC,
   2085 			0, &mac_address, NULL);
   2086 	parse_table_add(&pt, "Vlanid", 	        PQ_DFL|PQ_HEX,
   2087 			0, &vid,	NULL);
   2088 	parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP|PQ_BCM,
   2089 			(void *)(0), &pbmp, NULL);
   2090 	if (!parseEndOk(a, &pt, &retCode))
   2091 	    return retCode;
   2092 	bcm_mcast_addr_t_init(&mcaddr, mac_address, vid);
   2093 	BCM_PBMP_ASSIGN(mcaddr.pbmp, pbmp);
   2094 	r = bcm_mcast_port_remove(unit, &mcaddr);
   2095 	if (r < 0) {
   2096 	    cli_out("ERROR: %s %s ports failed: %s\n",
   2097                     ARG_CMD(a), subcmd, bcm_errmsg(r));
   2098 	    return CMD_FAIL;
   2099 	}
   2100 	return CMD_OK;
   2101     }
   2102 
   2103     return CMD_USAGE;
   2104 }
   2105 
   2106 /*
   2107  * AGE timer
   2108  */
   2109 
   2110 cmd_result_t
   2111 cmd_esw_age(int unit, args_t *a)
   2112 {
   2113     int seconds;
   2114     int r;
   2115 
   2116     if (!sh_check_attached(ARG_CMD(a), unit)) {
   2117         return CMD_FAIL;
   2118     }
   2119 
   2120     UNSUPPORTED_COMMAND(unit, SOC_CHIP_BCM5670, a);
   2121     UNSUPPORTED_COMMAND(unit, SOC_CHIP_BCM5675, a);
   2122 
   2123     if (!ARG_CNT(a)) {			/* Display settings */
   2124         if ((r = bcm_l2_age_timer_get(unit, &seconds)) != BCM_E_NONE) {
   2125             cli_out("%s ERROR: could not get age time: %s\n",
   2126                     ARG_CMD(a), bcm_errmsg(r));
   2127             return CMD_FAIL;
   2128         }
   2129 
   2130     	cli_out("Current age timer is %d.\n", seconds);
   2131 
   2132 	return CMD_OK;
   2133     }
   2134 
   2135     seconds = sal_ctoi(ARG_GET(a), 0);
   2136 
   2137     if ((r = bcm_l2_age_timer_set(unit, seconds)) != BCM_E_NONE) {
   2138         cli_out("%s ERROR: could not set age time: %s\n",
   2139                 ARG_CMD(a), bcm_errmsg(r));
   2140         return CMD_FAIL;
   2141     }
   2142 
   2143     cli_out("Set age timer to %d. %s\n", seconds, seconds ? "":"(disabled)");
   2144 
   2145     return CMD_OK;
   2146 }
   2147 
   2148 #ifdef BCM_XGS_SWITCH_SUPPORT
   2149 
   2150 /*
   2151  * L2 Mode
   2152  */
   2153 
   2154 char l2mode_usage[] =
   2155     "Parameters: [on] [off] [Interval=<interval>]\n\t"
   2156     "Starts the L2 shadow table update thread running every <interval>\n\t"
   2157     "microseconds.  The task reads the entire L2 table and issues updates\n\t"
   2158     "to the L2 shadow table and associated callbacks.  If <interval> is 0,\n\t"
   2159     "stops the task.  If <interval> is omitted, prints current setting.\n";
   2160 
   2161 cmd_result_t
   2162 cmd_l2mode(int unit, args_t *a)
   2163 {
   2164     soc_control_t	*soc = SOC_CONTROL(unit);
   2165     sal_usecs_t		usec;
   2166     parse_table_t	pt;
   2167     int			r;
   2168     uint32		flags = 0;	/* no flags yet */
   2169 
   2170     if (!sh_check_attached(ARG_CMD(a), unit)) {
   2171 	return CMD_FAIL;
   2172     }
   2173 
   2174     UNSUPPORTED_COMMAND(unit, SOC_CHIP_BCM5670, a);
   2175     UNSUPPORTED_COMMAND(unit, SOC_CHIP_BCM5675, a);
   2176 
   2177     if (!soc_feature(unit, soc_feature_arl_hashed)) {
   2178 	cli_out("%s: No L2X on this chip\n", ARG_CMD(a));
   2179 	return CMD_FAIL;
   2180     }
   2181 
   2182     if (soc == NULL) {
   2183         return CMD_FAIL;
   2184     }
   2185     usec = soc->l2x_interval;
   2186 
   2187     parse_table_init(unit, &pt);
   2188     parse_table_add(&pt, "Interval", PQ_DFL|PQ_INT,
   2189 		    (void *) 0, &usec, NULL);
   2190 
   2191     if (!ARG_CNT(a)) {			/* Display settings */
   2192 	cli_out("Current settings:\n");
   2193 	parse_eq_format(&pt);
   2194 	parse_arg_eq_done(&pt);
   2195 	return CMD_OK;
   2196     }
   2197 
   2198     if (parse_arg_eq(a, &pt) < 0) {
   2199 	cli_out("%s: Error: Unknown option: %s\n", ARG_CMD(a), ARG_CUR(a));
   2200 	parse_arg_eq_done(&pt);
   2201 	return CMD_FAIL;
   2202     }
   2203     parse_arg_eq_done(&pt);
   2204 
   2205     if (ARG_CNT(a) > 0 && !sal_strcasecmp(_ARG_CUR(a), "on")) {
   2206         usec = prev_l2x_interval[unit];
   2207         ARG_NEXT(a);
   2208     }
   2209     if (ARG_CNT(a) > 0 && !sal_strcasecmp(_ARG_CUR(a), "off")) {
   2210 	ARG_NEXT(a);
   2211 	usec = 0;
   2212     }
   2213 
   2214     if (ARG_CNT(a) > 0) {
   2215 	return CMD_USAGE;
   2216     }
   2217 
   2218     if (usec > 0) {
   2219         r = soc_l2x_start(unit, flags, usec);
   2220     } else {
   2221         sal_usecs_t prev_interval;
   2222 
   2223         r = soc_l2x_running(unit, NULL, &prev_interval);
   2224         if (r < 0 || prev_interval <= 0) {
   2225             prev_interval = SOC_L2X_INTERVAL_DEFAULT;
   2226         }
   2227         prev_l2x_interval[unit] = prev_interval;
   2228         r = soc_l2x_stop(unit);
   2229     }
   2230 
   2231     if (r < 0) {
   2232 	cli_out("%s: Error: Could not set L2X mode: %s\n",
   2233                 ARG_CMD(a), soc_errmsg(r));
   2234 	return CMD_FAIL;
   2235     }
   2236 
   2237     return CMD_OK;
   2238 }
   2239 
   2240 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2241 char l2learn_usage[] =
   2242     "Parameters: [on] [off] [Interval=<interval>]\n\t"
   2243     "Starts L2 learning thread running every <interval>\n\t"
   2244     "microseconds. If <interval> is 0, stops the task.\n\t"
   2245     "If <interval> is omitted, prints current setting.\n\t"
   2246     "Note: If this thread is stopped, L2 learning is stopped\n";
   2247 
   2248 cmd_result_t
   2249 cmd_l2learn(int unit, args_t *a)
   2250 {
   2251     soc_control_t *soc = SOC_CONTROL(unit);
   2252     sal_usecs_t   usec;
   2253     parse_table_t pt;
   2254     int           r;
   2255 
   2256     if (!(SOC_IS_TOMAHAWK3(unit))) {
   2257         cli_out("%s: Command supported on Tomahawk3 chip only\n", ARG_CMD(a));
   2258         return CMD_FAIL;
   2259     }
   2260 
   2261     if (!sh_check_attached(ARG_CMD(a), unit)) {
   2262         return CMD_FAIL;
   2263     }
   2264 
   2265     if (!soc_feature(unit, soc_feature_arl_hashed)) {
   2266         cli_out("%s: No L2X on this chip\n", ARG_CMD(a));
   2267         return CMD_FAIL;
   2268     }
   2269 
   2270     if (soc == NULL) {
   2271         return CMD_FAIL;
   2272     }
   2273 
   2274     usec = soc->l2x_learn_interval;
   2275 
   2276     parse_table_init(unit, &pt);
   2277     parse_table_add(&pt, "Interval", PQ_DFL|PQ_INT,
   2278                     (void *) 0, &usec, NULL);
   2279 
   2280     if (!ARG_CNT(a)) { /* Display settings */
   2281         cli_out("Current settings:\n");
   2282         parse_eq_format(&pt);
   2283         parse_arg_eq_done(&pt);
   2284         cli_out("Note: If this thread is stopped, L2 learning is stopped\n");
   2285         return CMD_OK;
   2286     }
   2287 
   2288     if (parse_arg_eq(a, &pt) < 0) {
   2289         cli_out("%s: Error: Unknown option: %s\n", ARG_CMD(a), ARG_CUR(a));
   2290         parse_arg_eq_done(&pt);
   2291         return CMD_FAIL;
   2292     }
   2293 
   2294     parse_arg_eq_done(&pt);
   2295 
   2296     if (ARG_CNT(a) > 0 && !sal_strcasecmp(_ARG_CUR(a), "on")) {
   2297         usec = prev_l2x_lrn_interval[unit];
   2298         ARG_NEXT(a);
   2299     }
   2300 
   2301     if (ARG_CNT(a) > 0 && !sal_strcasecmp(_ARG_CUR(a), "off")) {
   2302         ARG_NEXT(a);
   2303         usec = 0;
   2304     }
   2305 
   2306     if (ARG_CNT(a) > 0) {
   2307         return CMD_USAGE;
   2308     }
   2309 
   2310     if (usec > 0) {
   2311         r = soc_th3_l2_learn_thread_start(unit, usec);
   2312     } else {
   2313         sal_usecs_t prev_interval;
   2314 
   2315         cli_out("Stopping L2 Learn thread\n");
   2316         cli_out("Note this command can take longer to complete depending"
   2317                 " on configured interval\n");
   2318         r = soc_th3_l2_learn_thread_running(unit, &prev_interval);
   2319         /* Thread is not running */
   2320         if (r == 0 || prev_interval <= 0) {
   2321             /* Set to default value */
   2322             prev_interval = BCMSIM_L2XLRN_INTERVAL;
   2323         }
   2324         prev_l2x_lrn_interval[unit] = prev_interval;
   2325         r = soc_th3_l2_learn_thread_stop(unit);
   2326     }
   2327 
   2328     if (r < 0) {
   2329         cli_out("%s: Error: Could not set L2X mode: %s\n",
   2330             ARG_CMD(a), soc_errmsg(r));
   2331         return CMD_FAIL;
   2332     } else {
   2333         cli_out("L2 Learn thread %s\n", usec ? "started" : "stopped");
   2334     }
   2335 
   2336     return CMD_OK;
   2337 }
   2338 #endif /* BCM_TOMAHAWK3_SUPPORT */
   2339 #endif /* BCM_XGS_SWITCH_SUPPORT */
   2340 
   2341 #if defined(BCM_TOMAHAWK_SUPPORT)
   2342 cmd_result_t
   2343 if_esw_latency(int unit, args_t *a)
   2344 {
   2345     int rv = 0, support;
   2346     char *arg, **list = NULL;
   2347     uint32 resource, count = 0, idx = 0;
   2348     char *rstr[3] = {"feature", "memory", "register"};
   2349     char *sstr[2] = {"not ", ""};
   2350 
   2351     if (!sh_check_attached(ARG_CMD(a), unit)) {
   2352         return CMD_FAIL;
   2353     }
   2354     if ((arg = ARG_GET(a)) == NULL) {
   2355         return (CMD_USAGE);
   2356     }
   2357 
   2358     /* latency show */
   2359     if (arg && !sal_strcasecmp(arg, "show")) {
   2360         rv = bcmi_esw_switch_latency_show(unit);
   2361         if ((arg = ARG_GET(a)) == NULL) {
   2362             return (CMD_OK);
   2363         }
   2364 
   2365 #ifdef SOC_NO_NAMES
   2366         return CMD_OK;
   2367 #else
   2368         if (!sal_strcasecmp(arg, "feature")) {
   2369             count = soc_feature_count;
   2370             list = soc_feature_name;
   2371             idx = 0;
   2372         } else if (!sal_strcasecmp(arg, "mem")) {
   2373             count = NUM_SOC_MEM;
   2374             list = soc_mem_name;
   2375             idx = 1;
   2376         } else if (!sal_strcasecmp(arg, "reg")) {
   2377             count = NUM_SOC_REG;
   2378             list = soc_reg_name;
   2379             idx = 2;
   2380         }
   2381 #endif
   2382 
   2383         if ((arg = ARG_GET(a)) == NULL) {
   2384             return (CMD_USAGE);
   2385         }
   2386 
   2387         /* generic resource iterator */
   2388         for (resource = 0; resource < count; resource++) {
   2389             if (!sal_strcasecmp(arg, list[resource])) {
   2390                 break;
   2391             }
   2392         }
   2393         if (!(resource < count)) {
   2394             cli_out("invalid %s: %s\n", rstr[idx], arg);
   2395             return CMD_FAIL;
   2396         }
   2397 
   2398         switch(idx)
   2399         {
   2400             case 0:   /* latency show feature */
   2401                 support = soc_feature(unit, resource) ? 1 : 0;
   2402                 break;
   2403             case 1:   /* latency show mem */
   2404                 support = bcmi_esw_switch_latency_mem_avail(unit, resource) ? 1 : 0;
   2405                 break;
   2406             case 2:   /* latency show reg */
   2407                 support = bcmi_esw_switch_latency_reg_avail(unit, resource) ? 1 : 0;
   2408                 break;
   2409             default:
   2410                 return CMD_USAGE;
   2411         }
   2412 
   2413         cli_out("%s '%s' is %savailable in this latency mode\n",
   2414                  rstr[idx], arg, sstr[support]);
   2415         return CMD_OK;
   2416     } else if (arg && !sal_strcasecmp(arg, "diag")) {   /* latency diag */
   2417         rv = bcmi_esw_switch_latency_diag(unit);
   2418     }
   2419     else {
   2420         cli_out("error: incorrect argument\n");
   2421         return CMD_USAGE;
   2422     }
   2423 
   2424     if (BCM_FAILURE(rv)) {
   2425         return CMD_FAIL;
   2426     } else {
   2427         return CMD_OK;
   2428     }
   2429 }
   2430 #endif
   2431