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

hash.c (26098B)


      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  * HashDestination 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 <bcm/error.h>
     15 #include <bcm/stack.h>
     16 #ifdef INCLUDE_L3
     17 #include <bcm/l3.h>
     18 #ifdef BCM_TOMAHAWK_SUPPORT
     19 #include <bcm_int/esw/firebolt.h>
     20 #endif
     21 #endif
     22 #include <bcm/trunk.h>
     23 #include <bcm/switch.h>
     24 
     25 #if defined(BCM_ESW_SUPPORT) 
     26 #include <bcm_int/esw/port.h>
     27 #endif
     28 
     29 #define   HASH_DESTINATION_ERROR_PRINT(_r) \
     30     do { \
     31         cli_out(\
     32                 "HashDestination: %s\n", bcm_errmsg(_r)); \
     33 } while(0)
     34 
     35 
     36 #define   DYNAMIC_ETHERTYPE_ELIGIBLE 0x1
     37 #define   DYNAMIC_ETHERTYPE_INNER    0x2
     38 
     39 #define   ETHERTYPE_ELIGIBILITY_MAP_TABLE_SIZE_MAX  16 /* maximum ELIGIBILITY ethertype size */
     40 
     41 #define   ETHERTYPE_IPV6 0x86dd /* ipv6 ethertype */
     42 #define   ETHERTYPE_IPV4 0x0800 /* ipv4 ethertype */
     43 #define   ETHERTYPE_MIN  0x0600 /* minimum ethertype for hashing */
     44 
     45 #define   IP_PROT_TCP 0x6  /* TCP protocol number */
     46 #define   IP_PROT_UDP 0x11 /* TCP protocol number */
     47 
     48 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_ENDURO_SUPPORT) || \
     49     defined(BCM_GREYHOUND2_SUPPORT)
     50 /* Packet info flags for HashDestination. */
     51 #define BCM_HD_FLAGS_STR \
     52     "SRC_GPORT", \
     53     "VLAN", \
     54     "ETHERTYPE", \
     55     "SRC_MAC", \
     56     "DST_MAC", \
     57     "SRC_IP", \
     58     "DST_IP", \
     59     "SRC_IPV6", \
     60     "DST_IPV6", \
     61     "PROTOCOL", \
     62     "SRC_L4_PORT", \
     63     "DST_L4_PORT", \
     64     "HASH_TRUNK", \
     65     "HASH_MULTIPATH", \
     66     "UDP_SOURCE_PORT", \
     67     "LBID"
     68 
     69 STATIC char *hd_flags_names[] = {
     70     BCM_HD_FLAGS_STR
     71 };
     72 
     73 
     74 STATIC char *hd_resource_group_names[] = {
     75 #ifdef INCLUDE_L3
     76     "ECMP",
     77 #endif
     78     "LAG",
     79     "HGT",
     80     "ANY",
     81     NULL
     82 };
     83 
     84 STATIC char *hd_pkt_forward_reason_names[] = {
     85     BCM_SWITCH_PKT_HASH_INFO_FWD_REASON_STRINGS,
     86     NULL
     87 };
     88 
     89 STATIC char *hd_calc_info_names[] = {
     90     "UDP_SOURCE_PORT",
     91     "LBID",
     92     NULL
     93 };
     94 
     95 #ifdef BCM_TRIUMPH3_SUPPORT
     96 STATIC int (*bcm_hd_ethertype_set[])(int, 
     97                 uint32, int, int*) = {
     98 #ifdef INCLUDE_L3
     99     bcm_l3_egress_ecmp_ethertype_set,
    100 #endif
    101     bcm_trunk_ethertype_set,
    102     bcm_trunk_ethertype_set,
    103     NULL
    104 };
    105 
    106 STATIC int (*bcm_hd_ethertype_get[])(int, 
    107                 uint32*, int, int*, int*) = {
    108 #ifdef INCLUDE_L3
    109     bcm_l3_egress_ecmp_ethertype_get,
    110 #endif
    111     bcm_trunk_ethertype_get,
    112     bcm_trunk_ethertype_get,
    113     NULL
    114 };
    115 #endif
    116 
    117 char hash_destination_usage[] =
    118     "Usages:\n\t"
    119 #ifdef COMPILER_STRING_CONST_LIMIT
    120     "hd <option> [args...]\n\t"
    121 #else
    122 #ifdef BCM_TRIUMPH3_SUPPORT
    123     "hd ethertype mode [Group=ECMP|LAG|HGT] [Eligible=T|F] [Inner=T|F]\n\t"
    124     "hd ethertype add [Group=ECMP|LAG|HGT] [EtherType=<0xHHHH>]\n\t"
    125     "hd ethertype delete [Group=ECMP|LAG|HGT] [EtherType=<0xHHHH>]\n\t"
    126     "hd ethertype show [Group=ECMP|LAG|HGT]\n\t"
    127 #endif
    128     "hd dest get [Group=ECMP|LAG|HGT|ANY] [GID=<id>]\n\t"
    129     "         [Port=<port#>] [Module=<modid>] [Untagged=T|F]\n\t"
    130     "         [DestMac=<mac>] [SrcMac=<mac>] [Vlan=<vid>] [EtherType=<0xHHHH>]\n\t"
    131     "         [SrcIp=<ip4>] [DestIp=<ip4>] [SIp6=<ip6>] [DIp6=<ip6>]\n\t"
    132     "         [PROTocol=<Pid>] [L4SrcPort=<num>] [L4DstPort=<num>]\n\t"
    133     "         [FwdReason=Unicast|Ipmc|L2mc|Bcast|Dlf]\n\t"
    134     "         [CalcInfo=UDP_SOURCE_PORT|LBID]\n\t"
    135 #endif
    136     "\n"
    137     ;
    138 
    139 
    140 #ifdef BCM_TRIUMPH3_SUPPORT
    141 STATIC cmd_result_t
    142 _cmd_hd_ethertype(int unit, args_t *a)
    143 {
    144     char *subcmd = NULL;
    145     parse_table_t  pt;
    146     int            r = BCM_E_UNAVAIL;
    147     int            i, gid, retCode = CMD_OK;
    148     int            group_all = 0, arg_group = -1,
    149                    arg_eligible = -1, arg_inner = -1, arg_ethertype = 0xffff;
    150     uint32         flags, origin_flags;
    151     int ethertype_count = -1, cnt = 0;
    152     int ethertype_array[ETHERTYPE_ELIGIBILITY_MAP_TABLE_SIZE_MAX];
    153 
    154     if ((subcmd = ARG_GET(a)) == NULL) {
    155         return CMD_USAGE;
    156     }
    157     
    158     if (ARG_CNT(a) == 0) {
    159         group_all = 1;
    160     } else {
    161         parse_table_init(unit, &pt);
    162         parse_table_add(&pt, "Group", PQ_DFL|PQ_MULTI,
    163                 0, &arg_group, hd_resource_group_names);
    164 
    165         if (!sal_strcasecmp(subcmd, "mode")) {
    166             /* BCM.0> hd eth mode ... */
    167             parse_table_add(&pt, "Eligible", PQ_DFL|PQ_BOOL,
    168                     0, &arg_eligible, NULL);
    169             parse_table_add(&pt, "Inner", PQ_DFL|PQ_BOOL,
    170                     0, &arg_inner, NULL);
    171         } else 
    172         if (!sal_strcasecmp(subcmd, "add") ||
    173             !sal_strcasecmp(subcmd, "delete")) {
    174             /* BCM.0> hd eth add/delete ... */
    175             parse_table_add(&pt, "EtherType", PQ_DFL|PQ_HEX,
    176                     0, &arg_ethertype, NULL);
    177         }
    178 
    179         if (!parseEndOk(a, &pt, &retCode)) {
    180             return retCode;
    181         }
    182 
    183         if (arg_group < 0) {
    184             group_all = 1;
    185         }
    186     }
    187 
    188     for (gid = 0; gid < COUNTOF(hd_resource_group_names) - 1; gid++) {
    189         if (group_all == 1 || arg_group == gid) {
    190 #ifdef INCLUDE_L3
    191             if (!sal_strcasecmp(hd_resource_group_names[gid], "ECMP")) {
    192                 flags = BCM_L3_ECMP_DYNAMIC_ETHERTYPE_RESILIENT;
    193             } else 
    194 #endif
    195             {
    196                 flags = BCM_TRUNK_DYNAMIC_ETHERTYPE_RESILIENT;
    197                 if (!sal_strcasecmp(hd_resource_group_names[gid], "LAG")) {
    198                     flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_TRUNK;
    199                 } else if (!sal_strcasecmp(hd_resource_group_names[gid], "HGT")) {
    200                     flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_FABRIC_TRUNK; /*HGT*/
    201                 } else {
    202                     r = BCM_E_PARAM;
    203                     HASH_DESTINATION_ERROR_PRINT(r);
    204                     return CMD_FAIL;
    205                 }
    206             }
    207 
    208             ethertype_count = -1;
    209 
    210             r = bcm_hd_ethertype_get[gid](unit, 
    211                     &flags, ethertype_count, ethertype_array, &ethertype_count);
    212             if (BCM_FAILURE(r)) {
    213                 HASH_DESTINATION_ERROR_PRINT(r);
    214                 return CMD_FAIL;
    215             }
    216 
    217             origin_flags = flags;
    218 
    219             if (!sal_strcasecmp(subcmd, "mode")) {
    220                 if (arg_eligible < 0 && arg_inner < 0) {
    221                     return CMD_USAGE;
    222                 }
    223 
    224                 flags &= ~(DYNAMIC_ETHERTYPE_INNER | DYNAMIC_ETHERTYPE_ELIGIBLE);
    225 
    226                 if (arg_eligible) {
    227                     flags |= DYNAMIC_ETHERTYPE_ELIGIBLE;
    228                 }
    229 
    230                 if (arg_inner) {
    231                     flags |= DYNAMIC_ETHERTYPE_INNER;
    232                 }
    233 
    234                 if (flags == origin_flags) {
    235                     continue;
    236                 }
    237             } else 
    238             if (!sal_strcasecmp(subcmd, "add")) {
    239                 if (arg_ethertype == 0xffff) {
    240                     return CMD_USAGE;
    241                 }
    242                 
    243                 if (ethertype_count >= ETHERTYPE_ELIGIBILITY_MAP_TABLE_SIZE_MAX) {
    244                     r = BCM_E_FULL;
    245                     HASH_DESTINATION_ERROR_PRINT(r);
    246                     return CMD_FAIL;
    247                 }
    248                 for (i = 0; i < ethertype_count; i++) {
    249                     if (ethertype_array[i] == arg_ethertype) {
    250                         r = BCM_E_EXISTS;
    251                         HASH_DESTINATION_ERROR_PRINT(r);
    252                         return CMD_FAIL;
    253                     }
    254                 }
    255                 ethertype_array[i] = arg_ethertype;
    256                 ethertype_count++;
    257             } else
    258             if (!sal_strcasecmp(subcmd, "delete")) {
    259                 if (arg_ethertype == 0xffff) {
    260                     return CMD_USAGE;
    261                 }
    262 
    263                 if (ethertype_count <= 0) {
    264                     r = BCM_E_EMPTY;
    265                     HASH_DESTINATION_ERROR_PRINT(r);
    266                     return CMD_FAIL;
    267                 }
    268 
    269                 for (i = 0; i < ethertype_count; i++) {
    270                     if (ethertype_array[i] == arg_ethertype) {
    271                         break;
    272                     }
    273                 }
    274                 if (i == ethertype_count) {
    275                     r = BCM_E_NOT_FOUND;
    276                     HASH_DESTINATION_ERROR_PRINT(r);
    277                     return CMD_FAIL;
    278                 }
    279                 
    280                 ethertype_array[i] = ethertype_array[ethertype_count - 1];
    281                 ethertype_count--;
    282             }
    283 
    284             r = bcm_hd_ethertype_set[gid](unit, 
    285                     flags, ethertype_count, ethertype_array);
    286             if (BCM_FAILURE(r)) {
    287                 HASH_DESTINATION_ERROR_PRINT(r);
    288                 return CMD_FAIL;
    289             }
    290 
    291             if (!sal_strcasecmp(subcmd, "show")) {
    292                 /* BCM.0> hd eth show ... */
    293                 cli_out("  %s:\n", hd_resource_group_names[gid]);
    294                 cli_out("    EtherType: %s %s    Cnt:%d\n\t", 
    295                         flags & DYNAMIC_ETHERTYPE_INNER ? "INNER":"OUTER",
    296                         flags & DYNAMIC_ETHERTYPE_ELIGIBLE ? "Eligible":"Ineligible",
    297                         ethertype_count);
    298                 for (i = 0, cnt = 0; i < ethertype_count; i++) {
    299                     cnt++;
    300                     cli_out("0x%04x %s",
    301                             ethertype_array[i], (cnt % 4 == 0) ? "\n\t":"");
    302                 }
    303                 cli_out("\n");
    304             }
    305         }
    306     }
    307     
    308     return CMD_OK;
    309 }
    310 #endif
    311 
    312 
    313 STATIC cmd_result_t
    314 _cmd_hd_dest_get(int unit, args_t *a)
    315 {
    316     parse_table_t  pt;
    317     int            r = BCM_E_UNAVAIL;
    318     int            i, retCode = CMD_OK;
    319     int            arg_group = -1, arg_gid = -1;
    320     int            arg_untagged = FALSE;
    321     int            arg_port = BCM_GPORT_INVALID, arg_modid = BCM_MODID_INVALID,
    322                    arg_vlan = VLAN_ID_INVALID, arg_ethertype = 0xffff; 
    323     int            arg_fwd_reason = bcmSwitchPktHashInfoFwdReasonUnicast;
    324     int            arg_calc_info = -1;
    325     sal_mac_addr_t default_macaddr = {0, 0, 0, 0, 0, 0x1};
    326     sal_mac_addr_t arg_srcmac = {0, 0, 0, 0, 0, 0x1};
    327     sal_mac_addr_t arg_dstmac = {0, 0, 0, 0, 0, 0x1};
    328     bcm_trunk_t    tid;
    329     bcm_trunk_chip_info_t   ti;
    330     bcm_trunk_info_t   t_add_info;
    331     bcm_trunk_member_t *member_array = NULL;
    332     int            member_count = 0;
    333 #ifdef INCLUDE_L3
    334     bcm_ip_t       arg_sip_addr = 0, arg_ip_addr = 0;
    335     bcm_ip6_t      arg_sip6_addr, arg_ip6_addr, default_ip6_addr;
    336     int            arg_protocol = -1, arg_l4srcport = -1, arg_l4dstport = -1;
    337 
    338     int            intf_count = 0;
    339     bcm_if_t       *mpath_egr = NULL;
    340 #endif
    341 
    342     bcm_switch_pkt_info_t pkt_info;
    343     bcm_gport_t    dst_gport = BCM_GPORT_INVALID;
    344     bcm_if_t       dst_intf = BCM_IF_INVALID;
    345 
    346     if (ARG_CNT(a) == 0) {
    347         return CMD_USAGE;
    348     }
    349 
    350 #ifdef INCLUDE_L3
    351     sal_memset(arg_sip6_addr, 0, BCM_IP6_ADDRLEN);
    352     sal_memset(arg_ip6_addr, 0, BCM_IP6_ADDRLEN);
    353     sal_memset(default_ip6_addr, 0, BCM_IP6_ADDRLEN);
    354 #endif
    355 
    356     parse_table_init(unit, &pt);
    357     parse_table_add(&pt, "Group",     PQ_DFL|PQ_MULTI,
    358             0, &arg_group, hd_resource_group_names);
    359     parse_table_add(&pt, "GID",       PQ_DFL|PQ_HEX,
    360             0, &arg_gid, NULL);
    361     parse_table_add(&pt, "Port",      PQ_DFL|PQ_PORT, 
    362             0, &arg_port, NULL);
    363     parse_table_add(&pt, "Modid",     PQ_DFL|PQ_INT, 
    364             0, &arg_modid, NULL);
    365     parse_table_add(&pt, "Untagged",  PQ_DFL|PQ_BOOL,
    366             0, &arg_untagged, NULL);
    367     parse_table_add(&pt, "DestMac",   PQ_DFL|PQ_MAC,
    368             0, &arg_dstmac, NULL);
    369     parse_table_add(&pt, "SrcMac",    PQ_DFL|PQ_MAC,
    370             0, &arg_srcmac, NULL);
    371     parse_table_add(&pt, "Vlan",      PQ_DFL|PQ_INT,
    372             0, &arg_vlan, NULL);
    373     parse_table_add(&pt, "EtherType", PQ_DFL|PQ_HEX,
    374             0, &arg_ethertype, NULL);
    375 #ifdef INCLUDE_L3
    376     parse_table_add(&pt, "SrcIp",     PQ_DFL|PQ_IP,
    377             0, &arg_sip_addr, NULL);
    378     parse_table_add(&pt, "DestIp",    PQ_DFL|PQ_IP,
    379             0, &arg_ip_addr, NULL);
    380     parse_table_add(&pt, "SIp6",      PQ_DFL|PQ_IP6,
    381             0, (void *)&arg_sip6_addr, NULL);
    382     parse_table_add(&pt, "DIp6",      PQ_DFL|PQ_IP6,
    383             0, (void *)&arg_ip6_addr, NULL);
    384     parse_table_add(&pt, "PROTocol",  PQ_DFL|PQ_INT, 
    385             0, &arg_protocol, NULL);
    386     parse_table_add(&pt, "L4SrcPort", PQ_DFL|PQ_INT, 
    387             0, &arg_l4srcport, NULL);
    388     parse_table_add(&pt, "L4DstPort", PQ_DFL|PQ_INT, 
    389             0, &arg_l4dstport, NULL);
    390 #endif
    391     parse_table_add(&pt, "FwdReason", PQ_DFL|PQ_MULTI,
    392             0, &arg_fwd_reason, hd_pkt_forward_reason_names);
    393     parse_table_add(&pt, "CalcInfo",  PQ_DFL|PQ_MULTI,
    394             0, &arg_calc_info, hd_calc_info_names);
    395 
    396     if (!parseEndOk(a, &pt, &retCode)) {
    397         return retCode;
    398     }
    399 
    400     if (arg_group < 0 || 
    401         arg_group > (COUNTOF(hd_resource_group_names) - 1) ||
    402         (arg_gid < 0 && sal_strcasecmp(hd_resource_group_names[arg_group], "ANY"))) {
    403         return CMD_USAGE;
    404     }
    405 
    406     bcm_switch_pkt_info_t_init(&pkt_info);
    407 
    408 #ifdef INCLUDE_L3
    409     if (!sal_strcasecmp(hd_resource_group_names[arg_group], "ECMP")) {
    410         pkt_info.flags |= BCM_SWITCH_PKT_INFO_HASH_MULTIPATH;
    411 
    412         r = bcm_l3_egress_multipath_get(unit, arg_gid, 0, NULL,
    413                                          &intf_count);
    414         mpath_egr = sal_alloc((intf_count * sizeof(int)), 
    415                 "ecmp group");
    416         if (mpath_egr == NULL) {
    417             r = BCM_E_MEMORY;
    418             HASH_DESTINATION_ERROR_PRINT(r);
    419             return CMD_FAIL;
    420         }
    421         r = bcm_l3_egress_multipath_get(unit, arg_gid, intf_count, 
    422                                          mpath_egr, &intf_count);
    423         if (BCM_FAILURE(r)) {
    424             HASH_DESTINATION_ERROR_PRINT(r);
    425             retCode = CMD_FAIL;
    426             goto error_cleanup;
    427         }
    428 
    429         pkt_info.mpintf = arg_gid;
    430     } else
    431 #endif
    432     if (!sal_strcasecmp(hd_resource_group_names[arg_group], "LAG") || 
    433         !sal_strcasecmp(hd_resource_group_names[arg_group], "HGT")) {
    434 
    435         pkt_info.flags |= BCM_SWITCH_PKT_INFO_HASH_TRUNK;
    436 
    437         if (BCM_GPORT_IS_TRUNK(arg_gid)) {
    438             tid = BCM_GPORT_TRUNK_GET(arg_gid);
    439         } else {
    440             tid = arg_gid;
    441         }
    442 
    443         if ((r = bcm_trunk_chip_info_get(unit, &ti)) < 0) {
    444             HASH_DESTINATION_ERROR_PRINT(r);
    445             return CMD_FAIL;
    446         }
    447 
    448         if ((!sal_strcasecmp(hd_resource_group_names[arg_group], "LAG") &&
    449             (tid < ti.trunk_id_min || tid > ti.trunk_id_max)) ||
    450             (!sal_strcasecmp(hd_resource_group_names[arg_group], "HGT") &&
    451             (tid < ti.trunk_fabric_id_min || tid > ti.trunk_fabric_id_max))) {
    452             r = BCM_E_PARAM;
    453             HASH_DESTINATION_ERROR_PRINT(r);
    454             return CMD_FAIL;
    455         }
    456 
    457         member_array = sal_alloc(
    458                 sizeof(bcm_trunk_member_t) * BCM_TRUNK_MAX_PORTCNT,
    459                 "member array");
    460         if (NULL == member_array) {
    461             r = BCM_E_MEMORY;
    462             HASH_DESTINATION_ERROR_PRINT(r);
    463             return CMD_FAIL;
    464         }
    465 
    466         r = bcm_trunk_get(unit, tid, &t_add_info, BCM_TRUNK_MAX_PORTCNT,
    467                 member_array, &member_count);
    468         if (BCM_FAILURE(r)) {
    469             HASH_DESTINATION_ERROR_PRINT(r);
    470             retCode = CMD_FAIL;
    471             goto error_cleanup;
    472         }
    473 
    474         BCM_GPORT_TRUNK_SET(pkt_info.trunk_gport, 
    475                             tid);
    476     } else if (!sal_strcasecmp(hd_resource_group_names[arg_group], "ANY")) {
    477         if (arg_calc_info < 0 || 
    478             arg_calc_info > (COUNTOF(hd_calc_info_names) - 1)) {
    479             r = BCM_E_PARAM;
    480             HASH_DESTINATION_ERROR_PRINT(r);
    481             return CMD_FAIL;
    482         }
    483         if (!sal_strcasecmp(hd_calc_info_names[arg_calc_info], "UDP_SOURCE_PORT")) {
    484             pkt_info.flags |= BCM_SWITCH_PKT_INFO_HASH_UDP_SOURCE_PORT;
    485         } else if (!sal_strcasecmp(hd_calc_info_names[arg_calc_info], "LBID")) {
    486             pkt_info.flags |= BCM_SWITCH_PKT_INFO_HASH_LBID;
    487         } else {
    488             r = BCM_E_PARAM;
    489             HASH_DESTINATION_ERROR_PRINT(r);
    490             return CMD_FAIL;
    491         }
    492     } else {
    493         r = BCM_E_PARAM;
    494         HASH_DESTINATION_ERROR_PRINT(r);
    495         return CMD_FAIL;
    496     }
    497 
    498     if (BCM_GPORT_IS_SET(arg_port)) {
    499 #if defined(BCM_ESW_SUPPORT)
    500         if (SOC_IS_ESW(unit)) {
    501             int tgid, id;
    502 
    503             r = _bcm_esw_gport_resolve(unit, arg_port, &arg_modid, 
    504                                        &arg_port, &tgid, &id);
    505             if ((tgid != BCM_TRUNK_INVALID) || (id != -1)) {
    506                 r = BCM_E_PORT;
    507                 HASH_DESTINATION_ERROR_PRINT(r);
    508                 retCode = CMD_FAIL;
    509                 goto error_cleanup;
    510             }
    511 
    512             pkt_info.src_gport = arg_port;
    513         } else 
    514 #endif
    515         {
    516             HASH_DESTINATION_ERROR_PRINT(r);
    517             retCode = CMD_FAIL;
    518             goto error_cleanup;
    519         }
    520     } else if (arg_modid == BCM_MODID_INVALID) {
    521         (void)bcm_stk_my_modid_get(unit, 
    522                                 &arg_modid);
    523         r = _bcm_esw_port_gport_validate(unit, arg_port, 
    524                                 &arg_port);
    525         if (BCM_FAILURE(r)) {
    526             HASH_DESTINATION_ERROR_PRINT(r);
    527             retCode = CMD_FAIL;
    528             goto error_cleanup;
    529         }
    530 
    531         BCM_GPORT_LOCAL_SET(pkt_info.src_gport, arg_port);
    532     } else if (arg_modid >= 0 && arg_port >= 0) {
    533         int mod_is_local;
    534 
    535         r = _bcm_esw_modid_is_local(unit, arg_modid, &mod_is_local);
    536         if (BCM_FAILURE(r)) {
    537             HASH_DESTINATION_ERROR_PRINT(r);
    538             retCode = CMD_FAIL;
    539             goto error_cleanup;
    540         }
    541         if (mod_is_local) {
    542             BCM_GPORT_MODPORT_SET(pkt_info.src_gport, 
    543                                     arg_modid, arg_port);
    544         } else {
    545             BCM_GPORT_PROXY_SET(pkt_info.src_gport, 
    546                                     arg_modid, arg_port);
    547         }
    548     } else {
    549         r = BCM_E_PORT;
    550         HASH_DESTINATION_ERROR_PRINT(r);
    551         retCode = CMD_FAIL;
    552         goto error_cleanup;
    553     }
    554 
    555     pkt_info.flags |= BCM_SWITCH_PKT_INFO_SRC_GPORT;
    556 
    557     if (ENET_CMP_MACADDR(arg_dstmac, default_macaddr)) {
    558         pkt_info.flags |= BCM_SWITCH_PKT_INFO_DST_MAC;
    559         sal_memcpy(pkt_info.dst_mac, 
    560                             arg_dstmac, sizeof(sal_mac_addr_t));
    561     }
    562 
    563     if (ENET_CMP_MACADDR(arg_srcmac, default_macaddr)) {
    564         pkt_info.flags |= BCM_SWITCH_PKT_INFO_SRC_MAC;
    565         sal_memcpy(pkt_info.src_mac, 
    566                             arg_srcmac, sizeof(sal_mac_addr_t));
    567     }
    568 
    569     if (arg_untagged) {
    570         pkt_info.flags |= BCM_SWITCH_PKT_INFO_VLAN;
    571         pkt_info.vid = VLAN_ID_NONE;
    572     } else {
    573         if (VLAN_ID_VALID(arg_vlan)) {
    574             pkt_info.flags |= BCM_SWITCH_PKT_INFO_VLAN;
    575             pkt_info.vid = arg_vlan;
    576         }
    577     }
    578 
    579     if ((arg_ethertype < 0xffff) &&
    580         (arg_ethertype >= ETHERTYPE_MIN)) {
    581         pkt_info.flags |= BCM_SWITCH_PKT_INFO_ETHERTYPE;
    582         pkt_info.ethertype = arg_ethertype;
    583 
    584 #ifdef INCLUDE_L3
    585         if (pkt_info.ethertype == ETHERTYPE_IPV4 ||
    586             pkt_info.ethertype == ETHERTYPE_IPV6) {
    587 
    588             if (pkt_info.ethertype == ETHERTYPE_IPV4 && 
    589                 arg_sip_addr != 0) {
    590                 pkt_info.flags |= BCM_SWITCH_PKT_INFO_SRC_IP;
    591                 pkt_info.sip = arg_sip_addr;
    592             }
    593 
    594             if (pkt_info.ethertype == ETHERTYPE_IPV4 && 
    595                 arg_ip_addr != 0) {
    596                 pkt_info.flags |= BCM_SWITCH_PKT_INFO_DST_IP;
    597                 pkt_info.dip = arg_ip_addr;
    598             }
    599 
    600             if (pkt_info.ethertype == ETHERTYPE_IPV6 && 
    601                 !BCM_IP6_ADDR_EQ(arg_sip6_addr, default_ip6_addr)) {
    602                 pkt_info.flags |= BCM_SWITCH_PKT_INFO_SRC_IPV6;
    603                 sal_memcpy(pkt_info.sip6, arg_sip6_addr, BCM_IP6_ADDRLEN);
    604             }
    605 
    606             if (pkt_info.ethertype == ETHERTYPE_IPV6 && 
    607                 !BCM_IP6_ADDR_EQ(arg_ip6_addr, default_ip6_addr)) {
    608                 pkt_info.flags |= BCM_SWITCH_PKT_INFO_DST_IPV6;
    609                 sal_memcpy(pkt_info.dip6, arg_ip6_addr, BCM_IP6_ADDRLEN);
    610             }
    611 
    612             if (arg_protocol >= 0 && arg_protocol <= 0xff) {
    613                 pkt_info.flags |= BCM_SWITCH_PKT_INFO_PROTOCOL;
    614                 pkt_info.protocol = arg_protocol & 0xff;
    615 
    616                 if (pkt_info.protocol == IP_PROT_TCP ||
    617                     pkt_info.protocol == IP_PROT_UDP) {
    618                     if (arg_l4srcport != -1) {
    619                         pkt_info.flags |= BCM_SWITCH_PKT_INFO_SRC_L4_PORT;
    620                         pkt_info.src_l4_port = arg_l4srcport & 0xffff;
    621                     }
    622                     if (arg_l4dstport != -1) {
    623                         pkt_info.flags |= BCM_SWITCH_PKT_INFO_DST_L4_PORT;
    624                         pkt_info.dst_l4_port = arg_l4dstport & 0xffff;
    625                     }
    626                 }
    627             }
    628         }
    629 #endif
    630     }
    631 
    632     pkt_info.fwd_reason = arg_fwd_reason;
    633 
    634     if (LOG_CHECK(BSL_LS_APPL_COMMON | BSL_VERBOSE)) {
    635         cli_out("flags:  0x%08x\n", pkt_info.flags);
    636         for (i = 0; i < 8 * sizeof(pkt_info.flags); i++) {
    637             if (pkt_info.flags & (0x1 << i)) {
    638                 if (i < COUNTOF(hd_flags_names)) {
    639                     cli_out("%s ", hd_flags_names[i]);
    640                 } else {
    641                     cli_out("%s (%d) ", "UNKNOWN", i);
    642                 }
    643             }
    644         }
    645         cli_out("\n");
    646     }
    647 
    648     if ((r = bcm_switch_pkt_info_hash_get(unit, &pkt_info, 
    649                  &dst_gport, &dst_intf)) < 0) {
    650         HASH_DESTINATION_ERROR_PRINT(r);
    651         retCode = CMD_FAIL;
    652         goto error_cleanup;
    653     }
    654 
    655 #ifdef INCLUDE_L3
    656     if (pkt_info.flags & BCM_SWITCH_PKT_INFO_HASH_MULTIPATH) {
    657         cli_out("\n%s (%s):\n", 
    658                 "HashDestination", 
    659                 hd_resource_group_names[arg_group]);
    660         for (i = 0; i < intf_count; i++) {
    661 #ifdef BCM_TOMAHAWK_SUPPORT
    662             if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
    663                 BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpath_egr[i])) {
    664                 bcm_if_t *mpath_egr_l2 = NULL;
    665                 int intf_count_l2 = 0, j;
    666                 r = bcm_l3_egress_multipath_get(unit, mpath_egr[i], 0, NULL,
    667                                                 &intf_count_l2);
    668                 mpath_egr_l2 = sal_alloc((intf_count_l2 * sizeof(int)),
    669                                           "ecmp group level2");
    670                 if (mpath_egr_l2 == NULL) {
    671                     r = BCM_E_MEMORY;
    672                     HASH_DESTINATION_ERROR_PRINT(r);
    673                     return CMD_FAIL;
    674                 }
    675                 r = bcm_l3_egress_multipath_get(unit, mpath_egr[i], intf_count_l2,
    676                                                 mpath_egr_l2, &intf_count_l2);
    677                 if (BCM_FAILURE(r)) {
    678                     HASH_DESTINATION_ERROR_PRINT(r);
    679                     sal_free(mpath_egr_l2);
    680                     retCode = CMD_FAIL;
    681                     goto error_cleanup;
    682                 }
    683                 for (j = 0; j < intf_count_l2; j++) {
    684                     cli_out("        %d %s\n", mpath_egr_l2[j],
    685                             mpath_egr_l2[j] == dst_intf ? "destination":"");
    686                 }
    687                 sal_free(mpath_egr_l2);
    688             } else
    689 #endif
    690             {
    691                 cli_out("        %d %s\n", mpath_egr[i],
    692                         mpath_egr[i] == dst_intf ? "destination":"");
    693             }
    694         }
    695     } else
    696 #endif
    697     if (pkt_info.flags & BCM_SWITCH_PKT_INFO_HASH_TRUNK) {
    698         cli_out("\n%s (%s):\n", 
    699                 "HashDestination", 
    700                 hd_resource_group_names[arg_group]);
    701 
    702         for (i = 0; i < member_count; i++) {
    703             bcm_gport_t gport = member_array[i].gport;
    704             if (BCM_GPORT_IS_DEVPORT(gport)) {
    705                 cli_out("        0x%08x (tp[%d]=%d,tdev[%d]=%d) %s\n",
    706                         gport, 
    707                         i, BCM_GPORT_DEVPORT_PORT_GET(gport), 
    708                         i, BCM_GPORT_DEVPORT_DEVID_GET(gport),
    709                         gport == dst_gport ? "destination":"");
    710             } else {
    711                 cli_out("        0x%08x (tp[%d]=%d,tmod[%d]=%d) %s\n",
    712                         gport, 
    713                         i, BCM_GPORT_MODPORT_PORT_GET(gport), 
    714                         i, BCM_GPORT_MODPORT_MODID_GET(gport),
    715                         gport == dst_gport ? "destination":"");
    716             }
    717         }
    718     } else 
    719     if ((pkt_info.flags & BCM_SWITCH_PKT_INFO_HASH_UDP_SOURCE_PORT) ||
    720         (pkt_info.flags & BCM_SWITCH_PKT_INFO_HASH_LBID)) {
    721         cli_out("\n%s (%s):\n", 
    722                 "HashDestination", 
    723                 hd_resource_group_names[arg_group]);
    724 
    725         cli_out("        CalcInfo (%s):  %d(0x%x)\n", 
    726             hd_calc_info_names[arg_calc_info], dst_intf, dst_intf);
    727     } 
    728 
    729 error_cleanup:
    730     if (member_array != NULL) {
    731         sal_free(member_array);
    732     }
    733 #ifdef INCLUDE_L3
    734     if (mpath_egr != NULL) {
    735         sal_free(mpath_egr);
    736     }
    737 #endif
    738 
    739     return retCode;
    740 }
    741 
    742 
    743 STATIC cmd_result_t
    744 _cmd_hd_dest(int unit, args_t *a)
    745 {
    746     char *subcmd = NULL;
    747 
    748     if ((subcmd = ARG_GET(a)) == NULL) {
    749         return CMD_USAGE;
    750     }
    751     /* BCM.0> hd dest get ... */
    752     if (!sal_strcasecmp(subcmd, "get") ||
    753         !sal_strcasecmp(subcmd, "calc")) {
    754         return _cmd_hd_dest_get(unit, a);
    755     }
    756 
    757     return CMD_USAGE;
    758 }
    759 
    760 
    761 cmd_result_t
    762 cmd_hash_destination(int unit, args_t *a)
    763 {
    764     char           *subcmd = NULL;
    765 
    766     if (!sh_check_attached(ARG_CMD(a), unit)) {
    767         return CMD_FAIL;
    768     }
    769 
    770     if ((subcmd = ARG_GET(a)) == NULL) {
    771         return CMD_USAGE;
    772     }
    773 
    774 #ifdef BCM_TRIUMPH3_SUPPORT
    775     if (!sal_strcasecmp(subcmd, "eth") ||
    776         !sal_strcasecmp(subcmd, "ethertype")) {
    777         /* BCM.0> hd eth ... */
    778         return _cmd_hd_ethertype(unit, a);
    779     }
    780 #endif
    781 
    782     if (!sal_strcasecmp(subcmd, "dest") ||
    783         !sal_strcasecmp(subcmd, "info")) {
    784         /* BCM.0> hd dest ... */
    785         return _cmd_hd_dest(unit, a);
    786     }
    787 
    788     return CMD_USAGE;
    789 }
    790 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
    791