#!/usr/bin/env python
# Copyright 2016-2020 Cumulus Networks, LLC
#
"""
mlxcmd - command line utility for accessing the Mellanox SDK

Written by: Ken Yin
"""

import os
import sys
import argparse
import getopt
import json
import cumulus.platforms
import subprocess
import re
import pickle
from collections import OrderedDict
from tabulate import tabulate
from __builtin__ import False

sys.path.append("/usr/lib/python2.7/site-packages/python_sdk_api")
sys.path.append("/usr/lib/python2.7/dist-packages/python_sdk_api")
from sx_api import *

import nclu.NetDaemon
from nclu.netshow2 import is_bond_member,is_bond
import cumulus.vxlan_check_mlx

from cumulus.mlx import mlx_open_connection
from cumulus.mlx import mlx_close_connection
from cumulus.mlx import mlx_invalid_port_id
from cumulus.mlx import mlx_get_ecmp
from cumulus.mlx import mlx_get_interface
from cumulus.mlx import mlx_set_interface
from cumulus.mlx import mlx_get_neighbor
from cumulus.mlx import mlx_get_uc_route
from cumulus.mlx import mlx_get_uc_route_count
from cumulus.mlx import mlx_get_vlan_ids
from cumulus.mlx import mlx_get_vlan_ports
from cumulus.mlx import mlx_get_free_buffer_counters
from cumulus.mlx import mlx_get_roce_counters
from cumulus.mlx import mlx_get_qos_mapping
from cumulus.mlx import mlx_get_roce_status
from cumulus.mlx import mlx_get_parser_length
from cumulus.mlx import mlx_get_pool_buffer_counters
from cumulus.mlx import mlx_clear_pool_buffer_counters
from cumulus.mlx import mlx_get_pool_buffer_limits
from cumulus.mlx import mlx_get_port_reserved_buffer_limits
from cumulus.mlx import mlx_get_port_shared_buffer_limits
from cumulus.mlx import mlx_get_pcpdei_prio_map
from cumulus.mlx import mlx_get_pcpdei_rewrite_map
from cumulus.mlx import mlx_get_dscp_prio_map
from cumulus.mlx import mlx_get_dscp_rewrite_map
from cumulus.mlx import mlx_get_port_priority_trust
from cumulus.mlx import mlx_get_port_priority_rewrite
from cumulus.mlx import mlx_set_port_priority_rewrite
from cumulus.mlx import mlx_set_port_dscp_remark
from cumulus.mlx import mlx_get_pg_prio_map
from cumulus.mlx import mlx_get_prio_tc_map
from cumulus.mlx import mlx_get_prio_ieee_map
from cumulus.mlx import mlx_get_mc_aware
from cumulus.mlx import mlx_get_flow_control
from cumulus.mlx import mlx_get_port_scheduler
from cumulus.mlx import mlx_get_port_counters
from cumulus.mlx import mlx_get_port_discards
from cumulus.mlx import mlx_clear_port_counters
from cumulus.mlx import mlx_clear_port_qos_counters
from cumulus.mlx import mlx_clear_port_prio_counters
from cumulus.mlx import mlx_clear_port_tc_counters
from cumulus.mlx import mlx_get_port_pkt_size_counters
from cumulus.mlx import mlx_get_port_buffer_counters
from cumulus.mlx import mlx_clear_port_buffer_counters
from cumulus.mlx import mlx_get_port_ids
from cumulus.mlx import mlx_get_port_isolate
from cumulus.mlx import mlx_set_port_isolate
from cumulus.mlx import mlx_get_port_status
from cumulus.mlx import mlx_get_port_speed
from cumulus.mlx import mlx_get_port_rate
from cumulus.mlx import mlx_get_port_mtu
from cumulus.mlx import mlx_get_port_fec
from cumulus.mlx import mlx_get_fdb
from cumulus.mlx import mlx_get_mc_fdb
from cumulus.mlx import mlx_get_fdb_age_time
from cumulus.mlx import mlx_set_fdb_age_time
from cumulus.mlx import mlx_flush_uc_fdb_all
from cumulus.mlx import mlx_flush_uc_fdb_fid
from cumulus.mlx import mlx_flush_uc_fdb_log_port
from cumulus.mlx import mlx_get_all_mstp_instances
from cumulus.mlx import mlx_get_mstp_instance_vlans
from cumulus.mlx import mlx_get_mstp_port_state
from cumulus.mlx import mlx_get_lag_member_ids
from cumulus.mlx import mlx_get_lag_parameters
from cumulus.mlx import mlx_set_port_sflow
from cumulus.mlx import mlx_get_port_sflow
from cumulus.mlx import mlx_get_port_sflow_statistics
from cumulus.mlx import mlx_get_port_sflow_sample_rate_max
from cumulus.mlx import mlx_get_bridge_vports
from cumulus.mlx import mlx_get_port_ecn_config
from cumulus.mlx import mlx_get_shared_buff_buffer_unit_size
from cumulus.mlx import noRoce
from cumulus.mlx import ingressEgressIdentical
from cumulus.mlx import mlx_clear_all_trap_stats
from cumulus.mlx import mlx_show_trap_stats
from cumulus.mlx import mlx_show_trap_group_stats
from cumulus.mlx import mlx_get_roce_mode_wrapper
from cumulus.mlx import mlx_get_hw_bondInfo
import cumulus.porttab


port_shared_buffer_alpha_dict = {0: "ALPHA_0",
                                 1: "ALPHA_1_128",
                                 2: "ALPHA_1_64",
                                 3: "ALPHA_1_32",
                                 4: "ALPHA_1_16",
                                 5: "ALPHA_1_8",
                                 6: "ALPHA_1_4",
                                 7: "ALPHA_1_2",
                                 8: "ALPHA_1",
                                 9: "ALPHA_2",
                                 10: "ALPHA_4",
                                 11: "ALPHA_8",
                                 12: "ALPHA_16",
                                 13: "ALPHA_32",
                                 14: "ALPHA_64",
                                 255: "ALPHA_INFINITY"}

# QoS mapping
sp_num    = 8 # 0..7
color_num = 3 # 0..2

na_string = 'N/A'

port_wildcard1 = "swp*"
port_wildcard2 = "swp+"

g_pers_trap_stats_file = '/var/run/mlx_trap_stats_db'
mlxcmd_sx_sdk_pidfile = '/var/run/mlxcmd_sx_sdk.pid'
sx_sdk_pidfile = '/var/run/sx_sdk.pid'

roce_disabled = "0"
roce_lossy = "1"
roce_semi_lossless = "2"
roce_lossless = "3"
roce_legacy = "4"

# Collect and dump all the bond info
global gBondInfo
global gBondInfo_set
gBondInfo_set = 0

switchd_bonds_file = "/cumulus/switchd/debug/bond/sw_bonds"
switchd_debug_info = "/cumulus/switchd/ctrl/debug"
hwLagDumpCtrl = "/cumulus/switchd/ctrl/hw/lag"
hwDumpCtrl= "/cumulus/switchd/ctrl/hw/enable"

def is_hw_dump_enabled(DumpCtrlFile):
    try:
        with open(DumpCtrlFile) as f:
            for line in f:
                if not line.startswith('#') and 'TRUE' in line.upper():
                    return True
            return False
    except:
        raise Exception("Failed to read {}".format(DumpCtrlFile))

def enable_hw_dump(ControlFile):
    try:
        os.system("echo TRUE > "+ControlFile)
    except:
        raise Exception("Failed to enable hardware dump")


def disable_hw_dump(ControlFile):
    try:
        os.system("echo FALSE > "+ControlFile)
    except:
        raise Exception("Failed to enable hardware dump")

def toggle_switchd_debug():
    try:
        os.system("echo 1 > "+switchd_debug_info)
    except:
        raise Exception("Failed to toggle switchd debug info")

def get_bond_info():
    global gBondInfo
    global gBondInfo_set
    if not gBondInfo_set:

        hw_dump_enabled = is_hw_dump_enabled(hwDumpCtrl)
        if not hw_dump_enabled:
            enable_hw_dump(hwDumpCtrl)

        hw_lag_dump_enabled = is_hw_dump_enabled(hwLagDumpCtrl)
        if not hw_lag_dump_enabled:
            enable_hw_dump(hwLagDumpCtrl)

        debug_enabled = os.path.isfile(switchd_bonds_file)
        if not debug_enabled:
            toggle_switchd_debug()

        gBondInfo = mlx_get_hw_bondInfo()

        if not hw_dump_enabled:
            disable_hw_dump(hwDumpCtrl)

        if not hw_lag_dump_enabled:
            disable_hw_dump(hwLagDumpCtrl)

        if not debug_enabled:
            toggle_switchd_debug()

        gBondInfo_set = 1
    return gBondInfo

def _print_json_output(_dict):
    # Dump JSON output without any indentation to help with parsing muti-line JSON outputs in script
    print(json.dumps(_dict))

def get_sdk_to_linux():
    sdk_to_linux = {}
    swid = 0
    pt = cumulus.porttab.porttab(use_hw=False)
    for p in pt.get_linux_ports():
        sdk_to_linux[pt.linux2mlx(p)] = p
    for p in mlx_get_port_ids([swid])[swid]:
        if not sdk_to_linux.get(p,None):
            bondInfo = get_bond_info()
            # Get the bond name if it is bond member
            if bondInfo:
                bond_list = [bondInfo[_id]['linuxIntfName'] for _id in bondInfo.keys() if int(p) == bondInfo[_id]['logicalPortId']]
            else:
                bond_list = []
            if bond_list:
                sdk_to_linux[p] = bond_list[0]
            else:
                # Populate portids for unknown ports to avoid KeyError
                sdk_to_linux[p] = 'Unknown'
    return sdk_to_linux

def get_linux_to_sdk():
    linux_to_sdk = {}
    sdk_to_linux = get_sdk_to_linux()
    for sdkport in sdk_to_linux.keys():
        linux_to_sdk[sdk_to_linux.get(sdkport)] = sdkport 
    return linux_to_sdk

def _port_is_bond(sdk_to_linux, portid, use_json, ret):
    if sdk_to_linux and portid in sdk_to_linux and is_bond(sdk_to_linux[portid]):
        if use_json:
            if 'output' in ret:
                ret['output'] = {'port': sdk_to_linux[portid], 'exception': 'portIsBond'}
        else:
            bond_name = sdk_to_linux[portid]
            print 'port %s (0x%x) is a bond. Check the config on the bond members.' % (bond_name, portid)
        return True
    return False

def _get_bond_id_from_mem_intf(sdk_to_linux, portid):
    bond_id = ''
    if sdk_to_linux and portid in sdk_to_linux and is_bond_member(sdk_to_linux[portid]):
        bondInfo = get_bond_info()
        if bondInfo:
            bond_id = [bondInfo[_id]['logicalPortId'] for _id in bondInfo.keys() if int(portid) in list(bondInfo[_id]['slaveLogIds'])]
            if bond_id:
                bond_id = bond_id[0]
    return bond_id

def _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
    if sdk_to_linux and portid in sdk_to_linux and is_bond_member(sdk_to_linux[portid]):
        if use_json:
            if 'output' in ret:
                ret['output'] = {'port': sdk_to_linux[portid], 'exception': 'portIsBondMember'}
        else:
            bondInfo = get_bond_info()
            if bondInfo:
                bond_name = [bondInfo[_id]['linuxIntfName'] for _id in bondInfo.keys() if int(portid) in list(bondInfo[_id]['slaveLogIds'])]
                if bond_name:
                    bond_name = ' %s' % bond_name[0]
                else:
                    bond_name = ''
            else:
                bond_name = ''
            print 'port %s (0x%x) is a bond member. Check the config on the bond intf%s itself.' % (sdk_to_linux[portid], portid, bond_name)
        return True
    return False

def _add_port_to_dict(sdk_to_linux, _dict, _key, portid):
    if sdk_to_linux.get(portid,None):
        _dict[_key] = sdk_to_linux[portid]
    else:
        _dict[_key] = portid

def _show_interface_table(use_json=False) :
    data = mlx_get_interface()
    if use_json:
        _print_json_output(data)
    else:
        print 'Interface Table'
        print 'ID\t',
        for label in data['labels'] :
            print '%s\t' % label,
        print ''
        for rif, entry in data['entries'].items():
            print '%s\t' % rif,
            for label in data['labels'] :
                value = entry[label]
                print '%s\t' % value,
            print ''

def _set_router_interface(vrid=None, rif=0, use_json=False) :
    data = mlx_set_router_interface(vrid,rif)
    
def _show_uc_route_table(vrid=None, version=None, use_json=False) :
    rt_dict   = {}
    tabs_dict = { 4: '\t', 6: '\t\t\t\t\t'}
    if version == None :
        rt_dict[4] = mlx_get_uc_route(4, vrid);
        rt_dict[6] = mlx_get_uc_route(6, vrid);
    else :
        rt_dict[version] = mlx_get_uc_route(version, vrid);

    if use_json:
        for version, rt in rt_dict.items() :
            _print_json_output(rt)
    else:
        for version, rt in rt_dict.items() :
            print "\nVRF\tNetwork Address%sNext Hops\tAction\t\tType\t\tIntf ID\tECMP ID" % tabs_dict[version]
            for entry in rt:
                next_hop_count = rt[entry]['next_hop_cnt']
                spacing1 = "\t\t"
                spacing2 = "\t\t"
                intf_id = '<none>'
                ecmp_id = '<none>'
                if next_hop_count > 0 :
                    first_next_hop = rt[entry]['next_hops'][0]
                    if len(rt[entry]['next_hops'][0]) > 3:
                        spacing = "\t"
                    if (rt[entry]['ecmp_id'] > 0) and \
                       (next_hop_count > 1):
                        ecmp_id = '%d' % rt[entry]['ecmp_id']
                    elif (rt[entry]['ecmp_id'] > 0) and \
                         (next_hop_count == 1):
                        intf_id = '%d' % rt[entry]['erif']
                else :
                    first_next_hop = '<none>'
                if rt[entry]['type'] == 'LOCAL' :
                    intf_id = '%d' % rt[entry]['erif']        

                if len(rt[entry]['type']) > 5:
                    spacing2 = '\t'

                print "%d\t%s\t%s%s%s\t\t%s%s%s\t%s" % (rt[entry]['vrid'], entry.split()[1],
                                                        first_next_hop,
                                                        spacing1,
                                                        rt[entry]['action'],
                                                        rt[entry]['type'],
                                                        spacing2,
                                                        intf_id,
                                                        ecmp_id)

                for i in range(1,next_hop_count) :
                    if len(rt[entry]['next_hops'][i]) > 3:
                        nspace = "\t"
                    else:
                        nspace = "\t\t"

                    print "\t\t\t\t%s%s%s\t\t%s%s%s\t%s" % (rt[entry]['next_hops'][i],
                                                            nspace,
                                                            rt[entry]['action'],
                                                            rt[entry]['type'],
                                                            spacing2,
                                                            intf_id,
                                                            ecmp_id)

def _show_uc_route_count(vrid=None, version=None, use_json=False) :
    rt_dict   = {}
    tabs_dict = { 4: '\t', 6: '\t\t\t\t\t'}
    if version == None :
        rt_dict[4] = mlx_get_uc_routei_count(4, vrid);
        rt_dict[6] = mlx_get_uc_route_count(6, vrid);
    else :
        rt_dict[version] = mlx_get_uc_route_count(version, vrid);

    if use_json:
        for version, rt in rt_dict.items() :
            _print_json_output(rt)
    else:
        for version, rt in rt_dict.items() :
            print "number of routes for IPv%d: %d" % (version, rt['route_count'])

def _show_mc_route_table(vrid=None, version=4, use_json=False):
    pass

def _show_ip_neighbor_table(version=None, rif=0, use_json=False):

    nt_dict   = {}
    tabs_dict = { 4: '\t', 6: '\t\t\t\t'}

    if version == None :
        nt_dict[4] = mlx_get_neighbor(4, rif)
        nt_dict[6] = mlx_get_neighbor(6, rif)
    else :
        nt_dict[version] = mlx_get_neighbor(version, rif)

    if use_json:
        for version, nt in nt_dict.items() :
            _print_json_output(nt)
    else:
        for version, nt in nt_dict.items() :
            print "\nVRID\tIP Address%sMAC Address\t\tAction\tPrio\tRtr Intf" % tabs_dict[version]
            for neigh in nt:
                print "%d\t%s\t%s\t%s\t%d\t%d" % (nt[neigh]['vrid'],neigh.split()[0],
                                                  nt[neigh]['mac'],
                                                  nt[neigh]['action'],
                                                  nt[neigh]['prio'],
                                                  nt[neigh]['rif'])

def _show_fdb_table(swid=0, filter_type = (None, None), use_json=False):

    fdb = mlx_get_fdb(swid, filter_type)

    if use_json:
        _print_json_output(fdb)
    else:
        print "Swid\tMAC Address\t\tAction\t\tEntry Type\tFID_VID\tVLAN ID\t Port"
        for mac in fdb:
            for fdb_info in fdb[mac]:
                if len(fdb_info['action']) > 3:
                    spacing = "\t"
                else:
                    spacing = "\t\t"

                print "%d\t%s\t%s%s%s\t%d\t%d\t %s" % (fdb_info['swid'], mac,
                                                       fdb_info['action'],
                                                       spacing,
                                                       fdb_info['entry_type'],
                                                       fdb_info['fid_vid'],
                                                       fdb_info['vlan_id'],
                                                       fdb_info['port_id'])

def _show_mc_fdb_table(swid=0, filter_type = (None, None), use_json=False):

    mc_fdb = mlx_get_mc_fdb(swid, filter_type)

    if use_json:
        _print_json_output(fdb)
    else:
        print "Multicast FDB table:"
        print "===================="

        for mac in mc_fdb:
            for fdb_info in mc_fdb[mac]:
                spacing = "\t\t"

                print "Swid: %d\tMAC: %s\tFID: %d\t" % (fdb_info['swid'], mac,
                                          fdb_info['vid'])
                print spacing
                print "\tport-list:"
                print "\t----------"
                print "\t    logical port \t vlan_id \t port_id"
                print "\t    --------------------------------------------"
                for port_count in range(fdb_info['count']):
                    print("\t    %s \t\t %d \t\t %d" % (hex(fdb_info['port_list'][port_count]),
                            fdb_info['vlan_id'][port_count],
                            fdb_info['port_id'][port_count]))
                print spacing

def _show_fdb_age_time(swid_list=[0], use_json=False):
    age = mlx_get_fdb_age_time(swid_list)

    if use_json:
        print(json.dump(age, strean=screen))
    else:
        print "Swid\tAge Time (sec)"
        for swid in age:
            print "%d\t%d" % (swid, age[swid])

def _show_vlan_ids(swid_list=[0], use_json=False):
    vlan_id_in_use = mlx_get_vlan_ids(swid_list)

    if use_json:
        _print_json_output(vlan_id_in_use)
    else:
        print "Swid\tVLAN ID"
        for swid, vid in vlan_id_in_use:
            print "%d\t%d" % (swid, vid)

def _show_bridge_vports(swid=0, br_vid=None, use_json=False):
    vports = mlx_get_bridge_vports(swid, br_vid)

    if use_json:
        _print_json_output(vports)
    else:
        print "Logical Port ID"
        for port in vports:
            print port

def _show_vlan_ports(swid=0, vids=[], use_json=False):
    vlan_port_map = mlx_get_vlan_ports(swid, vids)

    if use_json:
        _print_json_output(vlan_port_map)
    else:
        print "Swid\tVLAN ID\t\tType\tDevice/VLAN ID\tPort ID\tSub-Port ID\tUntagged"
        for vid in vlan_port_map:
            for entry in vlan_port_map[vid]:
                print "%d\t%d\t\t%d\t%d\t\t%d\t%d\t\t%s" % (swid, vid, entry['type'],
                                                            entry['device_vlan_id'],
                                                            entry['port_id'],
                                                            entry['sub_port_id'],
                                                            str(bool(entry['untagged'])))

def __expand_port_name_or_id(port_id_cb, port_name_or_id, wc_name_allowed=False, use_json=False, params=None):
    port_list = _get_port_list_from_name_or_id(port_name_or_id, wc_name_allowed, use_json)
    sdk_to_linux = get_sdk_to_linux()
    one_large_list = []
    for portid in port_list:
        if (params == None):
            out_dict = port_id_cb(sdk_to_linux, portid, use_json)
        else:
            out_dict = port_id_cb(sdk_to_linux, portid, use_json, params)
        # Combine the output of all dicts and print one line of json output
        if use_json and out_dict:
            one_large_list.append(out_dict)

    if one_large_list:
        if params and 'ret_out' in params and params['ret_out']:
            return one_large_list
        else:
            if len(one_large_list) == 1:
                # For ensuring backwards compatible output for CLIs with single line json output
                _print_json_output(one_large_list[0])
            else:
                _print_json_output(one_large_list)

    return None

def _show_port_counters(sdk_to_linux, portid, use_json=False):
    counter_info = mlx_get_port_counters(portid)

    if use_json:
        return counter_info
    else:
        print "Counters for port %s (%d)" % (sdk_to_linux.get(portid), portid)
        cntr_type_list = ['per_port', 'perf', 'ieee', 'per_prio', 'per_tc']
        for cntr_type in cntr_type_list :
            for label in counter_info[cntr_type]['labels']:
                for counter_set_idx in range(len(counter_info[cntr_type]['values'])) :
                    if cntr_type == 'ieee':
                        print 'IEEE cntr',
                    elif cntr_type == 'per_prio':
                        print "switch priority %d" % counter_info[cntr_type]['values'][counter_set_idx]['switch priority'],
                    elif cntr_type == 'per_tc' :
                        print "traffic class   %d" % counter_info[cntr_type]['values'][counter_set_idx]['traffic class'],
                    counter_value = counter_info[cntr_type]['values'][counter_set_idx][label]
                    if len(label) > 6:
                        space = "\t"
                    else:
                        space = "\t\t"
                    print "%s%s%d" % (label, space, counter_value)

def _show_port_counters_name_or_id(port_name_or_id, use_json=False):
    __expand_port_name_or_id(_show_port_counters, port_name_or_id, True, use_json)

def _show_port_pkt_size_counters(sdk_to_linux, portid, use_json=False):
    counter_info = mlx_get_port_pkt_size_counters(portid)

    if use_json:
        return counter_info
    else:
        print "Counters for port %s (%d)" % (sdk_to_linux.get(portid), portid)
        for cntr in counter_info:
            if cntr != 'port':
                if len(cntr) > 15:
                    space = "\t"
                elif len(cntr) < 8:
                    space = "\t\t\t"
                else:
                    space = "\t\t"
                print "%s%s%d" % (cntr, space, counter_info[cntr])

def _show_port_pkt_size_counters_name_or_id(port_name_or_id, use_json=False):
    __expand_port_name_or_id(_show_port_pkt_size_counters, port_name_or_id, True, use_json)

def _clear_port_counters(sdk_to_linux, portid, use_json=False, params=None):
    mlx_clear_port_counters(portid, group_type=params['group_type'])

def _show_port_discards(sdk_to_linux, portid, use_json=False):
    discard_info = mlx_get_port_discards(portid)

    if use_json:
        return discard_info
    else:
        print "Discards from port %s (%d)" % (sdk_to_linux.get(portid), portid)
        for discard in discard_info:
            if discard != 'port':
                if len(discard) > 6:
                    space = "\t"
                else:
                    space = "\t\t"
                print "%s%s%d" % (discard, space, discard_info[discard])

def _show_port_discards_name_or_id(port_name_or_id, use_json=False):
    __expand_port_name_or_id(_show_port_discards, port_name_or_id, True, use_json)

def _find_buffer_entry(limit_list, reg, pool_id='', pg_id='', tc_id='', sp_id=''):
    item_list = []
    for item in limit_list:
	if reg == 'INGRESS_PORT' and item['type'] == 'INGRESS_PORT':
	    if item['pool'] == pool_id:
		item_list = item
		break
	if reg == 'EGRESS_PORT' and item['type'] == 'EGRESS_PORT':
	    if item['pool'] == pool_id:
		item_list = item
		break
	if reg == 'INGRESS_PORT_PRIORITY_GROUP' and item['type'] == 'INGRESS_PORT_PRIORITY_GROUP':
	    if item['pg'] == pg_id:
		item_list = item
		break
	if reg == 'EGRESS_PORT_TRAFFIC_CLASS' and item['type'] == 'EGRESS_PORT_TRAFFIC_CLASS':
	    if item['tc'] == tc_id:
		item_list = item
		break
	if reg == 'MULTICAST' and item['type'] == 'MULTICAST':
	    if item['sp'] == sp_id:
		item_list = item
		break
	if reg == 'MULTICAST_PORT' and item['type'] == 'MULTICAST_PORT':
	    item_list = item
	    break
    return item_list
	
def print_port_buffer_legends():
    cell_size = mlx_get_shared_buff_buffer_unit_size()
    print "Legends:"
    print "========"
    print "  Region: iPort.PG/ePort.TC/iPort/ePort/ePort.MC/Multicast.SP"
    print "  PoolID: Corresponding pool id where the regions are mapped to"
    print "  PoolMode: Dynamic/Static pool mode which governs the usage of the region mapped to it"
    print "  PG-Id: Corresponding PG id for iPort.PG region"
    print "  Lossy/Lossless: Only valid for iPort.PG region - lossless in case of PFC enabled"
    print "  XON Th: xon threshold value - only valid for lossless iPort.PG region"
    print "  XOFF Th: xoff threshold value - only valid for lossless iPort.PG region"
    print "  TC: Traffic Class corresponding to ePort.TC region"
    print "  HR: Headroom size corresponding to each iPort.PG region"
    print "  Reserved Size: Min guaranteed quota from shared buffer for corresponding region"
    print "  Shared_Max: Max quota of shared buffer buffer for packets in corresponding region - alpha in case of dynamic pool, cells in case of static pools"
    print "  HR/PL Usage: Current usage of headroom for iPort.PG region(in cells)"
    print "  HR/PL Max: Max peak usage of headroom for iPort.PG region(in cells)"
    print "  Current Usage: Current shared buffer usage of corresponding region(in cells)"
    print "  Max Usage: Maximum shared buffer usage of corresponding region(in cells)"
    print "  SP: Internal switch priority of the packet"
    print "     1 cell == %d bytes" % (cell_size)

def _show_port_buffer_counters_name_or_id(port_name_or_id, use_json=False):
    return __expand_port_name_or_id(_show_port_buffer_counters, port_name_or_id, True, use_json, params={'ret_out': use_json})

def _clear_port_buffer_counters(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    mlx_clear_port_buffer_counters(portid)

def _show_port_buffer_counters(sdk_to_linux, portid, use_json=False, params=None):
    ret = {'output': {}}
    if _port_is_bond(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    counter_info = mlx_get_port_buffer_counters(portid)
    shared_limit_list = mlx_get_port_shared_buffer_limits(portid)
    res_limit_list = mlx_get_port_reserved_buffer_limits(portid)

    table_list = []
    idx = 0
    for item in counter_info['counter_list'] :
        reg = item['type']
        res = '-'
        sp = '-'
        mode = '-'
        tc = '-'
        pool = '-'
        pg = '-'
        lossy = '-'
        xon = '-'
        xoff = '-'
        size = '-'
        hr = '-'
        hr_usage = '-'
        hr_max = '-'
        if (item['type'] == 'INGRESS_PORT' or item['type'] == 'EGRESS_PORT'):
            #Pool-Id
            pool = item['index']
            res_entry = _find_buffer_entry(res_limit_list,item['type'],pool_id=item['index'])
            sha_entry = _find_buffer_entry(shared_limit_list,item['type'],pool_id=item['index'])
            if 'cells' in res_entry:
                res = res_entry['cells']
            if 'mode' in sha_entry:
                mode = sha_entry['mode']
            if 'cells' in sha_entry:
                size = sha_entry['cells']
        if (item['type'] == 'INGRESS_PORT_PRIORITY_GROUP'):
            #PG-Id
            pg = item['index']
            res_entry = _find_buffer_entry(res_limit_list,item['type'],pg_id=item['index'])
            sha_entry = _find_buffer_entry(shared_limit_list,item['type'],pg_id=item['index'])
            if 'lossy' in res_entry:
                lossy = res_entry['lossy']
            if 'hr' in res_entry:
                hr = res_entry['hr']
            if 'cells' in res_entry:
                res = res_entry['cells']
            if not lossy:
                hr = res_entry['cells']
                res = '-'
                if 'lossless_hr_curr' in item:
                    hr_usage = item['lossless_hr_curr']
                if 'lossless_hr_watermark' in item:
                    hr_max = item['lossless_hr_watermark']
            else:
                if 'lossy_hr_curr' in item:
                    hr_usage = item['lossy_hr_curr']
                if 'lossy_hr_watermark' in item:
                    hr_max = item['lossy_hr_watermark']
            if 'xon' in res_entry:
                xon = res_entry['xon']
            if 'xoff' in res_entry:
                xoff = res_entry['xoff']
            if 'mode' in sha_entry:
                mode = sha_entry['mode']
            if 'cells' in sha_entry:
                size = sha_entry['cells']
            if 'pool' in sha_entry:
                pool = sha_entry['pool']
        if (item['type'] == 'MULTICAST'):
            #MC-SP
            sp = item['index']
            res_entry = _find_buffer_entry(res_limit_list,item['type'],sp_id=item['index'])
            sha_entry = _find_buffer_entry(shared_limit_list,item['type'],sp_id=item['index'])
            if 'cells' in res_entry:
                res = res_entry['cells']
            if 'mode' in sha_entry:
                mode = sha_entry['mode']
            if 'cells' in sha_entry:
                size = sha_entry['cells']
            if 'pool' in sha_entry:
                pool = sha_entry['pool']
        if (item['type'] == 'MULTICAST_PORT'):
            #MC-Port
            res_entry = _find_buffer_entry(res_limit_list,item['type'])
            sha_entry = _find_buffer_entry(shared_limit_list,item['type'])
            if 'cells' in res_entry:
                res = res_entry['cells']
            if 'mode' in sha_entry:
                mode = sha_entry['mode']
            if 'cells' in sha_entry:
                size = sha_entry['cells']
            if 'pool' in sha_entry:
                pool = sha_entry['pool']
        if (item['type'] == 'EGRESS_PORT_TRAFFIC_CLASS'):
            #TC-Id
            tc = item['index']
            res_entry = _find_buffer_entry(res_limit_list,item['type'],tc_id=item['index'])
            sha_entry = _find_buffer_entry(shared_limit_list,item['type'],tc_id=item['index'])
            if 'cells' in res_entry:
                res = res_entry['cells']
            if 'mode' in sha_entry:
                mode = sha_entry['mode']
            if 'cells' in sha_entry:
                size = sha_entry['cells']
            if 'pool' in sha_entry:
                pool = sha_entry['pool']

        curr = item['current']
        max_usage = item['watermark']

        table_row = []
        table_row.append(reg)
        table_row.append(pool)
        item['pool_id'] = pool
        table_row.append(mode)
        item['mode'] = mode
        if (item['type'] == 'MULTICAST'):
            table_row.append(sp)
            item['switch_prio'] = sp
        else:
            table_row.append(pg)
            item['pg_id'] = pg
            if (lossy == 1):
                table_row.append("Lossy")
            elif (lossy == 0):
                table_row.append("Lossless")
            else:
                table_row.append(lossy)
            item['lossy'] = lossy
            table_row.append(xon)
            item['xon_th'] = xon
            table_row.append(xoff)
            item['xoff_th'] = xoff
            table_row.append(tc)
            item['tclass'] = tc
            if hr != '-':
                table_row.append(str(hr) + " cells")
            else:
                table_row.append(hr)
            item['headroom'] = hr
            table_row.append(hr_usage)
            item['hr_curr_usage'] = hr_usage
            table_row.append(hr_max)
            item['hr_max_usage'] = hr_max
        if res != 0:
            table_row.append(str(res) + " cells")
        else:
            table_row.append(res)
        item['reserved'] = res
        if mode == 'DYNAMIC':
            table_row.append(port_shared_buffer_alpha_dict[size])
            item['shared_max'] = port_shared_buffer_alpha_dict[size]
        else:
            table_row.append(str(size) + " cells")
            item['shared_max'] = size
        table_row.append(curr)
        table_row.append(max_usage)
        # Change the index field to reflect the counter index instead
        idx += 1
        item['index'] = idx
        if size == 0 and res == 0:
            # Do not print the regions for which no buffer is configured
            continue
        
        table_list.append(table_row)

    # Modify the port to reflect the meaningful port id as swp*
    if (portid == SX_MC_PORT_LOG_ID):
        counter_info['port'] = 'MC_PORT'
    elif (sdk_to_linux):
        counter_info['port'] = sdk_to_linux.get(portid)

    if use_json:
        return counter_info
    else:
	if (portid == SX_MC_PORT_LOG_ID):
            print "Reserved + shared buffer counters for port 0x%x" % (portid)
            print "==============================================="
            print(tabulate(table_list, headers=['Region', 'PoolID', 'PoolMode', 'SP', 'Reserved Size', 'Shared_Max/Dynamic_Quota', 'Current Usage', 'Max Usage']))
            print "==============================================="
            print_port_buffer_legends()
	else:
            if sdk_to_linux:
                print "Reserved + shared buffer counters for port %s" % (sdk_to_linux.get(portid))
            else:
                print "Reserved + shared buffer counters for port 0x%x" % (portid)
            print "==============================================="
            print(tabulate(table_list, headers=['Region', 'PoolID', 'PoolMode', 'PG-Id', 'Lossy/Lossless', 'XON Th', 'XOFF Th', 'TC', 'HR', 'HR/PL Usage', 'HR/PL Max', 'Reserved Size', 'Shared_Max', 'Current Usage', 'Max Usage']))
            print "==============================================="

def _show_port_shared_buffer_limits(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond(sdk_to_linux, portid, use_json, ret):
        return ret['output']

    limit_list = mlx_get_port_shared_buffer_limits(portid)
    cell_size = mlx_get_shared_buff_buffer_unit_size()

    limits_dict = {}
    _add_port_to_dict(sdk_to_linux, limits_dict, 'port', portid)

    limits_dict['list'] = limit_list
    limits_dict['cell_unit_size'] = cell_size

    if use_json:
        return limits_dict
    else:
        print "\nShared cell limit for port %s(0x%x) (1 cell == %d bytes)" % (limits_dict['port'],portid,cell_size)
        print 'items: %d' % len(limit_list)
        for limit_item in limit_list :
            space = '\t'
            print limit_item['type'],
            print 'pool ID',
            print limit_item['pool'],
            if 'sp' in limit_item:
                print 'switch priority',
                print limit_item['sp'],
            if 'pg' in limit_item:
                print 'priority group',
                print limit_item['pg'],
            if 'tc' in limit_item:
                print 'traffic class',
                print limit_item['tc'],
            print space,
            print limit_item['mode'],
            print 'cells',
            print limit_item['cells']

def _show_port_reserved_buffer_limits(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond(sdk_to_linux, portid, use_json, ret):
        return ret['output']

    limit_list = mlx_get_port_reserved_buffer_limits(portid)
    cell_size = mlx_get_shared_buff_buffer_unit_size()

    limits_dict = {}
    _add_port_to_dict(sdk_to_linux, limits_dict, 'port', portid)

    limits_dict['list'] = limit_list
    limits_dict['cell_unit_size'] = cell_size

    if use_json:
        return limits_dict
    else:
        print "\nReserved cell limit for port %s(0x%x) (1 cell == %d bytes)" % (limits_dict['port'],portid,cell_size)
        print 'items: %d' % len(limit_list)
        for limit_item in limit_list :
            space = '\t'
            print limit_item['type'],
            print 'pool ID',
            print limit_item['pool'],
            if 'sp' in limit_item:
                print 'switch priority',
                print limit_item['sp'],
            if 'pg' in limit_item:
                print 'priority group',
                print limit_item['pg'],
            if 'tc' in limit_item:
                print 'traffic class',
                print limit_item['tc'],
            if 'lossy' in limit_item:
                print 'is lossy:',
                print limit_item['lossy'],
            if 'xon' in limit_item:
                print 'xon:',
                print limit_item['xon'],
            if 'xoff' in limit_item:
                print 'xoff:',
                print limit_item['xoff'],
            print space,
            print 'cells',
            print limit_item['cells']

def _show_pool_buffer_limits(use_json=False):
    buffer_info = mlx_get_pool_buffer_limits()
    cell_size = mlx_get_shared_buff_buffer_unit_size()
    if use_json:
        return buffer_info
    else :
        print "\nPool buffer limits (1 cell == %d bytes)" % (cell_size)
        for pool_id, pool_item in buffer_info.items() :
            print '%s Pool %d' % (pool_item['type'], pool_id),
            space = '\t'
            print 'mode',
            print pool_item['mode'],
            print 'cells',
            print pool_item['cells']

def _clear_pool_buffer_counters(use_json=False):
    mlx_clear_pool_buffer_counters()

def _get_pool_buffer_counters(buffer_info,cells=False):
    pool_info = mlx_get_pool_buffer_limits()
    table_list = []
    cell_size = mlx_get_shared_buff_buffer_unit_size()
    for idx,usage_stat in buffer_info.items() :
        pool = usage_stat['id']
        pool_type = usage_stat['type']
        mode = pool_info[pool]['mode']
        direction = pool_info[pool]['dir']
        size = pool_info[pool]['cells']
        size_bytes = pool_info[pool]['bytes']
        infinite_flag = pool_info[pool]['infinite']
        curr = usage_stat['current']
        max_usage = usage_stat['watermark']
        table_row = []
        table_row.append(pool)
        table_row.append(pool_type)
        table_row.append(direction)
        usage_stat['direction'] = direction
        table_row.append(mode)
        usage_stat['mode'] = mode
        if cells:
            table_row.append(str(size) + " cells")
            usage_stat['pool_size'] = size
            table_row.append(curr)
            table_row.append(max_usage)
        else:
            table_row.append(formatBytes(size_bytes))
            usage_stat['pool_size_bytes'] = size_bytes
            table_row.append(formatBytes(curr * cell_size))
            table_row.append(formatBytes(max_usage * cell_size))
        table_list.append(table_row)
    return table_list

def _show_pool_buffer_counters(cells, swid=0, use_json=False):
    buffer_info = mlx_get_pool_buffer_counters()
    if use_json:
        _print_json_output(buffer_info)
    else :
        cell_size = mlx_get_shared_buff_buffer_unit_size()
        print "\nPool buffer occupancy counters (1 cell == %d bytes)" % (cell_size)
        table_list = _get_pool_buffer_counters(buffer_info,cells)
        print(tabulate(table_list, headers=['PoolID', 'Pool Type', 'Direction', 'Mode', 'Pool Size', 'Current Usage', 'Max Usage']))

def _show_free_buffer_counters(use_json=False):
    buffer_info = mlx_get_free_buffer_counters()
    if use_json:
        return buffer_info
    else :
        if 'cell_unit_size' in buffer_info.keys() :
            print "\nUnallocated packet buffer cells (1 cell == %d bytes)" % (buffer_info['cell_unit_size'])
        else:
            print "\nUnallocated packet buffer cells"
        if 'ingress' in buffer_info.keys() :
            print 'Ingress cells: %d' % buffer_info['ingress']
        if 'egress' in buffer_info.keys() :
            print 'Egress  cells: %d' % buffer_info['egress']

def _show_roce_counters(sdk_to_linux, portid, use_json=False, params=None):
    if params == None:
        clear = False
        show_output = True
        cells = False
    else:
        clear = params['clear']
        show_output = params['show_output']
        cells = params['cells']

    ret = {'output': {}}
    if _port_is_bond(sdk_to_linux, portid, use_json, ret):
        return ret['output']

    roce_info = mlx_get_roce_counters(portid, clear)

    if show_output:
        if use_json:
            return roce_info
        else:
            print
            print "Port: %s (%d)" % (sdk_to_linux.get(roce_info['port_id']), roce_info['port_id'])
            print
            print 'Rx:'
            print 'RoCE PG packets: %d' % roce_info['rx_roce_pg_packets']
            if cells:
                print 'RoCE PG cells: %d' % int(roce_info['rx_roce_pg_bytes']/roce_info['cell_unit_size'])
            else:
                print 'RoCE PG bytes: %s' % formatBytes(roce_info['rx_roce_pg_bytes'])
            print 'RoCE no buffer discard: %d' % roce_info['rx_roce_no_buffer_discard']
            print 'General+CNP PG packets: %d' % roce_info['rx_cnp_pg_packets']
            if cells:
                print 'General+CNP PG cells: %d' % int(roce_info['rx_cnp_pg_bytes']/roce_info['cell_unit_size'])
            else:
                print 'General+CNP PG bytes: %s' % formatBytes(roce_info['rx_cnp_pg_bytes'])
            print 'General+CNP no buffer discard: %d' % roce_info['rx_cnp_no_buffer_discard']
            print 'RoCE PFC pause packets: %d' % roce_info['rx_roce_pfc_pause_packets']
            print 'RoCE PFC pause duration: %d' % roce_info['rx_roce_pfc_pause_duration']
            if cells:
                print 'RoCE buffer usage : %d cells' % roce_info['rx_roce_buffer_usage_cells']
                print 'RoCE buffer max usage : %d cells' % roce_info['rx_roce_buffer_max_usage_cells']
                print 'General+CNP buffer usage : %d cells' % roce_info['rx_cnp_buffer_usage_cells']
                print 'General+CNP buffer max usage : %d cells' % roce_info['rx_cnp_buffer_max_usage_cells']
                print 'RoCE PG usage : %d cells' % roce_info['rx_roce_pg_usage_cells']
                print 'RoCE PG max usage : %d cells' % roce_info['rx_roce_pg_max_usage_cells']
                print 'General+CNP PG usage : %d cells' % roce_info['rx_cnp_pg_usage_cells']
                print 'General+CNP PG max usage : %d cells' % roce_info['rx_cnp_pg_max_usage_cells']
            else:
                print 'RoCE buffer usage : %s' % formatBytes(roce_info['rx_roce_buffer_usage_bytes'])
                print 'RoCE buffer max usage : %s' % formatBytes(roce_info['rx_roce_buffer_max_usage_bytes'])
                print 'General+CNP buffer usage : %s' % formatBytes(roce_info['rx_cnp_buffer_usage_bytes'])
                print 'General+CNP buffer max usage : %s' % formatBytes(roce_info['rx_cnp_buffer_max_usage_bytes'])
                print 'RoCE PG usage : %s' % formatBytes(roce_info['rx_roce_pg_usage_bytes'])
                print 'RoCE PG max usage : %s' % formatBytes(roce_info['rx_roce_pg_max_usage_bytes'])
                print 'General+CNP PG usage : %s' % formatBytes(roce_info['rx_cnp_pg_usage_bytes'])
                print 'General+CNP PG max usage : %s' % formatBytes(roce_info['rx_cnp_pg_max_usage_bytes'])
            print
            print 'Tx:'
            if (roce_info['tx_ecn_marked_packets'] == None):
                tx_ecn_marked_packets = na_string
            else:
                tx_ecn_marked_packets = str(roce_info['tx_ecn_marked_packets'])
            print 'Port ECN marked packets: %s' % tx_ecn_marked_packets
            print 'RoCE TC packets: %d' % roce_info['tx_roce_tc_packets']
            if cells:
                print 'RoCE TC cells: %d' % int(roce_info['tx_roce_tc_bytes']/roce_info['cell_unit_size'])
            else:
                print 'RoCE TC bytes: %s' % formatBytes(roce_info['tx_roce_tc_bytes'])
            print 'RoCE unicast no buffer discard: %d' % roce_info['tx_roce_unicast_no_buffer_discard']
            print 'CNP TC packets: %d' % roce_info['tx_cnp_tc_packets']
            if cells:
                print 'CNP TC cells: %d' % int(roce_info['tx_cnp_tc_bytes']/roce_info['cell_unit_size'])
            else:
                print 'CNP TC bytes: %s' % formatBytes(roce_info['tx_cnp_tc_bytes'])
            print 'CNP unicast no buffer discard: %d' % roce_info['tx_cnp_unicast_no_buffer_discard']
            print 'RoCE PFC pause packets: %d' % roce_info['tx_roce_pfc_pause_packets']
            print 'RoCE PFC pause duration: %d' % roce_info['tx_roce_pfc_pause_duration']
            if cells:    
                print 'RoCE buffer usage :%d cells' % roce_info['tx_roce_buffer_usage_cells']
                print 'RoCE buffer max usage : %d cells' % roce_info['tx_roce_buffer_max_usage_cells']
                print 'General+CNP buffer usage : %d cells' % roce_info['tx_cnp_buffer_usage_cells']
                print 'General+CNP buffer max usage : %d cells' % roce_info['tx_cnp_buffer_max_usage_cells']
                print 'RoCE TC usage : %d cells' % roce_info['tx_roce_tc_usage_cells']
                print 'RoCE TC max usage : %d cells' % roce_info['tx_roce_tc_max_usage_cells']
                print 'CNP TC usage : %d cells' % roce_info['tx_cnp_tc_usage_cells']
                print 'CNP TC max usage : %d cells' % roce_info['tx_cnp_tc_max_usage_cells']
            else:
                print 'RoCE buffer usage :%s' % formatBytes(roce_info['tx_roce_buffer_usage_bytes'])
                print 'RoCE buffer max usage : %s' % formatBytes(roce_info['tx_roce_buffer_max_usage_bytes'])
                print 'General+CNP buffer usage : %s' % formatBytes(roce_info['tx_cnp_buffer_usage_bytes'])
                print 'General+CNP buffer max usage : %s' % formatBytes(roce_info['tx_cnp_buffer_max_usage_bytes'])
                print 'RoCE TC usage : %s' % formatBytes(roce_info['tx_roce_tc_usage_bytes'])
                print 'RoCE TC max usage : %s' % formatBytes(roce_info['tx_roce_tc_max_usage_bytes'])
                print 'CNP TC usage : %s' % formatBytes(roce_info['tx_cnp_tc_usage_bytes'])
                print 'CNP TC max usage : %s' % formatBytes(roce_info['tx_cnp_tc_max_usage_bytes'])
            print
            print '1 cell == %d bytes' % roce_info['cell_unit_size']
            print

# Index the ingress priority map by SP and color
def _index_ingress_prio_map(pcp_dei_prio_map, dscp_prio_map):
    sp = {}
    # Create the index
    for current_sp in range(sp_num):
        sp[current_sp] = {}
        for current_color in range(color_num):
            sp[current_sp][current_color] = {}
            sp[current_sp][current_color]['pcp_dei'] = []
            sp[current_sp][current_color]['dscp'] = []
    # Add PCP/DEI values
    for prio_item in pcp_dei_prio_map:
        pcp_dei = {}
        pcp_dei['pcp'] = prio_item['pcp']
        pcp_dei['dei'] = prio_item['dei']
        sp[prio_item['sp']][prio_item['color']]['pcp_dei'].append(pcp_dei)
    # Add DSCP values
    for prio_item in dscp_prio_map:
        sp[prio_item['sp']][prio_item['color']]['dscp'].append(prio_item['dscp'])
    return sp

# Get the ingress priority map table
# This table is used for both textual and json display formats.
def _get_ingress_prio_map(pcp_dei_prio_map, dscp_prio_map, l2_trust, l3_trust):
    sp = _index_ingress_prio_map(pcp_dei_prio_map, dscp_prio_map)
    ingress_prio_map_table = []
    for current_sp in range(sp_num):
        for current_color in range(color_num):
            table_row = {}

            # PCP/DEI
            if (l2_trust == 'yes'):
                table_row['pcp_dei'] = sp[current_sp][current_color]['pcp_dei']
            else:
                table_row['pcp_dei'] = None

            # DSCP
            if (l3_trust == 'yes'):
                table_row['dscp'] = sp[current_sp][current_color]['dscp']
            else:
                table_row['dscp'] = None

            table_row['sp'] = current_sp
            table_row['color'] = current_color
            ingress_prio_map_table.append(table_row)
    return ingress_prio_map_table

# Print the ingress priority map in textual display format.
def _show_ingress_prio_map(ingress_prio_map_table):
    table_list = []
    for map_row in ingress_prio_map_table:
        table_row = []

        # PCP/DEI
        if map_row['pcp_dei'] == None:
            pcp_dei_list = na_string
        else:
            pcp_dei_list = ''
            for pcp_dei in map_row['pcp_dei']:
                pcp_dei_list += '%d(%d) ' % (pcp_dei['pcp'], pcp_dei['dei'])
        table_row.append(pcp_dei_list)

        # DSCP
        if map_row['dscp'] == None:
            dscp_list = na_string
        else:
            dscp_list = ''
            for dscp in map_row['dscp']:
                dscp_list += '%d ' % dscp
        table_row.append(dscp_list)

        table_row.append(map_row['sp'])
        table_row.append(map_row['color'])
        table_list.append(table_row)
    print 'PCP,DEI and DSCP to switch-priority, color mapping:'
    print
    print(tabulate(table_list, headers=['PCP(DEI)', 'DSCP', 'switch-priority', 'color']))

# Index the egress priority map by SP and color
def _index_egress_prio_map(tc_prio_map, pcpdei_rewrite_map, dscp_rewrite_map):
    sp_num = 8
    sp = {}
    # Create the index
    for current_sp in range(sp_num):
        sp[current_sp] = {}
        for current_color in range(color_num):
            sp[current_sp][current_color] = {}
    # Add TC values
    for prio_item in tc_prio_map:
        if prio_item['sp'] in sp:
            for current_color in range(color_num):
                sp[prio_item['sp']][current_color]['tc'] = prio_item['tc']
    # Add PCP/DEI rewrite values
    for prio_item in pcpdei_rewrite_map:
        if prio_item['sp'] in sp:
            sp[prio_item['sp']][prio_item['color']]['pcp'] = prio_item['pcp']
            sp[prio_item['sp']][prio_item['color']]['dei'] = prio_item['dei']
    # Add DSCP rewrite values
    for prio_item in dscp_rewrite_map:
        if prio_item['sp'] in sp:
            sp[prio_item['sp']][prio_item['color']]['dscp'] = prio_item['dscp']
    return sp

# Get the egress priority map table
# This table is used for both textual and json display formats.
def _get_egress_prio_map(tc_prio_map, pcpdei_rewrite_map, dscp_rewrite_map,
                          port_rewrite_pcpdei, port_rewrite_dscp, router_rewrite_pcpdei):
    sp = _index_egress_prio_map(tc_prio_map, pcpdei_rewrite_map, dscp_rewrite_map)
    egress_prio_map_table = []
    for current_sp in range(sp_num):
        for current_color in range(color_num):
            table_row = {}
            table_row['sp'] = current_sp
            table_row['color'] = current_color

            # PCP/DEI
            pcp_dei = {}
            pcp_dei['pcp'] = sp[current_sp][current_color]['pcp']
            pcp_dei['dei'] = sp[current_sp][current_color]['dei']
            if (port_rewrite_pcpdei == 'yes' or router_rewrite_pcpdei == 'enable'):
                table_row['pcp_dei'] = pcp_dei
            else:
                table_row['pcp_dei'] = None

            # DSCP
            if (port_rewrite_dscp == 'yes'):
                table_row['dscp'] = sp[current_sp][current_color]['dscp']
            else:
                table_row['dscp'] = None

            table_row['tc'] = sp[current_sp][current_color]['tc']
            egress_prio_map_table.append(table_row)
    return egress_prio_map_table

# Print the egress priority map in textual display format.
def _show_egress_prio_map(egress_prio_map_table):
    table_list = []
    for map_row in egress_prio_map_table:
        table_row = []
        table_row.append(map_row['sp'])
        table_row.append(map_row['color'])

        # PCP/DEI
        if map_row['pcp_dei'] == None:
            pcp_dei = na_string
        else:
            pcp_dei = '%d(%d)' % (map_row['pcp_dei']['pcp'],
                                  map_row['pcp_dei']['dei'])
        table_row.append(pcp_dei)

        # DSCP
        if map_row['dscp'] == None:
            dscp = na_string
        else:
            dscp = map_row['dscp']
        table_row.append(dscp)

        table_row.append(map_row['tc'])
        table_list.append(table_row)
    print(tabulate(table_list, headers=['switch-priority', 'color', 'PCP(DEI) rewrite', 'DSCP rewrite', 'TC']))

# Show end-to-end (ingress to egress) QoS mapping
def _show_qos_mapping(ingress_port, egress_port, use_json=False):
    # Validate the ingress_port and egress_port parameters
    if not ingress_port:
        if use_json:
            _print_json_output({'exception': 'ingressPortRequired'})
        else:
            print "Ingress port is a required parameter for qos mapping"
        return
    if not egress_port:
        if use_json:
            _print_json_output({'exception': 'egressPortRequired'})
        else:
            print "Egress port is a required parameter for qos mapping"
        return

    # Find the ingress and egress port IDs.
    ingress_port_list = _get_port_list_from_name_or_id(ingress_port, False, use_json)
    if type(ingress_port_list) is not list or len(ingress_port_list) != 1:
        print 'ERROR: illegal ingress_port_list =', ingress_port_list
        return
    ingress_port_id = ingress_port_list[0]
    egress_port_list = _get_port_list_from_name_or_id(egress_port, False, use_json)
    if type(egress_port_list) is not list or len(egress_port_list) != 1:
        print 'ERROR: illegal egress_port_list =', egress_port_list
        return
    egress_port_id = egress_port_list[0]

    # Get the raw unindexed mapping data.
    qos_mapping = mlx_get_qos_mapping(ingress_port_id, egress_port_id)

    # Index and build the display data.
    prio_map = {}
    prio_map['ingress'] = {}
    prio_map['ingress']['l2_trust'] = qos_mapping['ingress']['trust']['pcpdei']
    prio_map['ingress']['l3_trust'] = qos_mapping['ingress']['trust']['dscp']
    prio_map['ingress']['default_priority'] = qos_mapping['ingress']['default_priority']
    prio_map['ingress']['port_rewrite_pcpdei'] = qos_mapping['ingress']['port_rewrite']['pcpdei']
    prio_map['ingress']['port_rewrite_dscp'] = qos_mapping['ingress']['port_rewrite']['dscp']
    prio_map['ingress']['router_rewrite_pcpdei'] = qos_mapping['ingress']['router_rewrite']
    prio_map['ingress_table'] = _get_ingress_prio_map(qos_mapping['ingress']['pcp_dei_prio_map'],
                                                      qos_mapping['ingress']['dscp_prio_map'],
                                                      prio_map['ingress']['l2_trust'],
                                                      prio_map['ingress']['l3_trust'])
    prio_map['egress_table'] = _get_egress_prio_map(qos_mapping['egress']['tc_prio_map'],
                                                    qos_mapping['egress']['pcpdei_rewrite_map'],
                                                    qos_mapping['egress']['dscp_rewrite_map'],
                                                    prio_map['ingress']['port_rewrite_pcpdei'],
                                                    prio_map['ingress']['port_rewrite_dscp'],
                                                    prio_map['ingress']['router_rewrite_pcpdei'])

    if use_json:
        _print_json_output(prio_map)
    else:
        sdk_to_linux = get_sdk_to_linux()
        print
        print "Ingress port: %s (%d)" % (sdk_to_linux.get(ingress_port_id), ingress_port_id)
        print
        print 'L2 trust (PCP/DEI): %s' % prio_map['ingress']['l2_trust']
        print 'L3 trust (DSCP): %s' % prio_map['ingress']['l3_trust']
        print 'Port Default Switch Priority: %s' % prio_map['ingress']['default_priority']
        print 'Rewrite PCP,DEI: %s' % prio_map['ingress']['port_rewrite_pcpdei']
        print 'Rewrite DSCP: %s' % prio_map['ingress']['port_rewrite_dscp']
        print 'Global Rewrite mode: %s' % prio_map['ingress']['router_rewrite_pcpdei']
        print
        _show_ingress_prio_map(prio_map['ingress_table'])
        print

        print "Egress port: %s (%d)" % (sdk_to_linux.get(egress_port_id), egress_port_id)
        print
        _show_egress_prio_map(prio_map['egress_table'])
        print

def _show_roce_status(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}, 'bond_name': {}}
    if sdk_to_linux and portid in sdk_to_linux and is_bond(sdk_to_linux[portid]):
        roce_status_dict = mlx_get_roce_status(portid, bond_id=portid, is_bond=True)
    elif sdk_to_linux and portid in sdk_to_linux and is_bond_member(sdk_to_linux[portid]):
        bondid = _get_bond_id_from_mem_intf(sdk_to_linux, portid)
        roce_status_dict = mlx_get_roce_status(portid, bondid, is_bond=False)
    else:
        roce_status_dict = mlx_get_roce_status(portid, portid, is_bond=False)
    if use_json:
        return roce_status_dict
    else:
        print "Port: %s (%d)" % (sdk_to_linux.get(roce_status_dict['port_id']), roce_status_dict['port_id'])
        print

        print 'RoCE mode: %s' % roce_status_dict['roce_mode']

        print 'PFC %d TX enabled: %s, RX enabled: %s' % (roce_status_dict['pfc_priority'],
                                                         roce_status_dict['pfc_enabled']['tx_enabled'],
                                                         roce_status_dict['pfc_enabled']['rx_enabled'])     

        tc_list_str = ""
        for tc in roce_status_dict['ecn_tcs']:
            tc_list_str += " " + str(tc)
        if len(tc_list_str) == 0:
            tc_list_str = " NONE"
        print 'ECN enabled TCs:%s' % tc_list_str

        print 'L3 trust (DSCP): %s' % roce_status_dict['trust']['dscp']
        print 'L2 trust (PCP/DEI): %s' % roce_status_dict['trust']['pcpdei']

        print 'DSCP->SP Map:',
        print 'DSCP %d' % roce_status_dict['dscp']['dscp'],
        print 'switch priority %d' % roce_status_dict['dscp']['sp'],
        print 'color %d' % roce_status_dict['dscp']['color']
        
        print 'SP->PG Map:',
        print 'Switch priority %d' % roce_status_dict['pg_map']['sp'],
        print 'priority group %d' % roce_status_dict['pg_map']['pg']

        print 'SP->TC Map:',
        print 'switch priority %d' % roce_status_dict['tc_map']['sp'],
        print 'traffic class %d' % roce_status_dict['tc_map']['tc']

        print

# Show only the RoCE and CNP related pools.
def _show_roce_pools(cells,use_json=False):
    roce_pools = {}
    pool_temp_cnt = {}
    elem = {}
    roce_pool_key = 0
    pool_counters = mlx_get_pool_buffer_counters()
    for pool_key in pool_counters:
        pool_id = pool_counters[pool_key]['id']
        if (pool_id == cumulus.mlx.ingress_cnp_port_pool or 
            pool_id == cumulus.mlx.ingress_roce_port_pool or 
            pool_id == cumulus.mlx.egress_cnp_port_pool or 
            pool_id == cumulus.mlx.egress_roce_port_pool): 
            elem['current'] = pool_counters[pool_key]['current']
            elem['watermark'] = pool_counters[pool_key]['watermark']
            pool_temp_cnt[pool_id] = elem
    
    pool_info = mlx_get_pool_buffer_limits()
    for pool_key in pool_info:
        # If the pool is RoCE or CNP, set its name.
        pool_id = pool_key
        pool_name = None
        if pool_id == cumulus.mlx.ingress_cnp_port_pool:
            pool_name = 'lossy-default-ingress'
        if pool_id == cumulus.mlx.ingress_roce_port_pool:
            pool_name = 'roce-reserved-ingress'
        if pool_id == cumulus.mlx.egress_cnp_port_pool:
            pool_name = 'lossy-default-egress'
        if pool_id == cumulus.mlx.egress_roce_port_pool:
            pool_name = 'roce-reserved-egress'
        if pool_name != None:
            # Add the pool to roce_pools with its name.
            roce_pool = pool_info[pool_key].copy()
            roce_pool['name'] = pool_name
            roce_pool['current-usage'] = pool_temp_cnt[pool_id]['current']
            roce_pool['max-usage'] = pool_temp_cnt[pool_id]['watermark']
            roce_pool['current-usage-bytes'] = pool_temp_cnt[pool_id]['current'] * roce_pool['cell_unit_size']
            roce_pool['max-usage-bytes'] = pool_temp_cnt[pool_id]['watermark'] * roce_pool['cell_unit_size']
            roce_pools[pool_id] = roce_pool

    if use_json:
        return roce_pools
    else:     
        cell_size = mlx_get_shared_buff_buffer_unit_size()
        # Tabulate the pools info.
        table_list = _get_pool_buffer_counters_roce(roce_pools,cells)
        print "\nRoCE Pool buffer occupancy counters (1 cell == %d bytes)" % (cell_size)
        print(tabulate(table_list, headers=['Pool Name', 'PoolID', 'Pool Type', 'Direction', 'Mode', 'Pool Size', 'Current Usage', 'Max Usage']))

def formatBytes(B):
    B = float(B)
    KB = float(1024)
    MB = float(KB ** 2) 
    GB = float(KB ** 3) 

    if B < KB:
        return '{0} {1}'.format(B,'Bytes' if 0 == B > 1 else 'Byte')
    elif KB <= B < MB:
        return '{0:.2f} kB'.format(B/KB)
    elif MB <= B < GB:
        return '{0:.2f} MB'.format(B/MB)
    elif GB <= B:
        return '{0:.2f} GB'.format(B/GB)

def _get_pool_buffer_counters_roce(buffer_info,cells=False):
    table_list = []
    for idx,usage_stat in buffer_info.items() :
        pool = idx
        table_row = []
        table_row.append(usage_stat['name'])
        table_row.append(pool)
        table_row.append(usage_stat['type'])
        table_row.append(usage_stat['dir'])
        table_row.append(usage_stat['mode'])
        if cells:
            table_row.append(str(usage_stat['cells']) + " cells")
            table_row.append(usage_stat['current-usage'])
            table_row.append(usage_stat['max-usage'])
        else:
            table_row.append(formatBytes(usage_stat['bytes']))
            table_row.append(formatBytes(usage_stat['current-usage'] * usage_stat['cell_unit_size']))
            table_row.append(formatBytes(usage_stat['max-usage'] * usage_stat['cell_unit_size']))
        table_list.append(table_row)
    return table_list

# Show RoCE system wide status, not related to a specific port.
def _show_roce_status_system(cells, use_json=False):
    roce_mode = mlx_get_roce_mode_wrapper()
    if (roce_mode == roce_disabled or roce_mode == roce_legacy):
        if use_json:
            _print_json_output({'exception': 'noRoce'})
        else:
            print "RoCE is not configured"    
    else:
        roce_status_system = {}
        roce_status_system['pools'] = _show_roce_pools(cells, use_json)
        if use_json:
            _print_json_output(roce_status_system)

def _show_parser_length(use_json=False):
    parser_length = mlx_get_parser_length()
    if use_json:
        return {'parser_length': parser_length}
    else :
        print 'Parser length = %d' % parser_length 

def _show_port_priority_trust(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    trust_info = mlx_get_port_priority_trust(portid)

    _add_port_to_dict(sdk_to_linux, trust_info, 'port', portid)

    if use_json:
        return trust_info
    else :
        print '\nPort %s(0x%x) priority trust configuration' % (trust_info['port'],portid)
        print 'L3 (DSCP):   %s' % trust_info['dscp']
        print 'L2 (PCPDEI): %s' % trust_info['pcpdei']

def _show_priority_group_map(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    pg_map_list = mlx_get_pg_prio_map(portid)
    if use_json:
        return pg_map_list
    else :
        print '\nPort 0x%x switch priority to priority group map' % portid
        for pg_map in pg_map_list :
            print 'Switch priority %d' % pg_map['sp'],
            print 'priority group %d' % pg_map['pg']

def _show_port_priority_rewrite(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    rewrite_info = mlx_get_port_priority_rewrite(portid)
    _add_port_to_dict(sdk_to_linux, rewrite_info, 'port', portid)

    if use_json:
        return rewrite_info
    else :
        print '\nPort %s(0x%x) priority rewrite configuration' % (rewrite_info['port'], portid)
        print 'DSCP:   %s' % rewrite_info['dscp']
        print 'PCPDEI: %s' % rewrite_info['pcpdei']
        print 'EXP:    %s' % rewrite_info['exp']

def _show_pcpdei_prio_map(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    prio_list = mlx_get_pcpdei_prio_map(portid)

    prio_map = {}
    _add_port_to_dict(sdk_to_linux, prio_map, 'port', portid)

    prio_map['list'] = prio_list

    if use_json:
        return prio_map
    else :
        print '\nPort %s(0x%x) PCPDEI packet priority to switch priority map' % (prio_map['port'],portid)
        for prio_item in prio_map['list']:
            print 'PCP %d' % prio_item['pcp'],
            print 'DEI %d' % prio_item['dei'], 
            print 'switch priority %d' % prio_item['sp'],
            print 'color %d' % prio_item['color']

def _show_pcpdei_remark_map(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    pcpdei_list = mlx_get_pcpdei_rewrite_map(portid)
    pcpdei_map = {}
    _add_port_to_dict(sdk_to_linux, pcpdei_map, 'port', portid)

    pcpdei_map['list'] = pcpdei_list
    if use_json:
        return pcpdei_map
    else :
        print '\nPort %s(0x%x) switch priority to PCPDEI packet priority remark' % (pcpdei_map['port'],portid)
        for pcpdei_item in pcpdei_map['list']:
            print 'switch priority %d' % pcpdei_item['sp'],
            print 'color %d' % pcpdei_item['color'],
            print 'PCP %d' % pcpdei_item['pcp'],
            print 'DEI %d' % pcpdei_item['dei'] 

def _show_dscp_prio_map(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    prio_list = mlx_get_dscp_prio_map(portid)

    prio_map = {}
    _add_port_to_dict(sdk_to_linux, prio_map, 'port', portid)

    prio_map['list'] = prio_list

    if use_json:
        return prio_map
    else :
        print '\nPort %s(0x%x) DSCP packet priority to switch priority map' % (prio_map['port'],portid)
        for prio_item in prio_map['list']:
            print 'DSCP %d' % prio_item['dscp'],
            print 'switch priority %d' % prio_item['sp'],
            print 'color %d' % prio_item['color']

def _show_dscp_remark_map(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    dscp_list = mlx_get_dscp_rewrite_map(portid)
    dscp_map = {}
    _add_port_to_dict(sdk_to_linux, dscp_map, 'port', portid)

    dscp_map['list'] = dscp_list
    if use_json:
        return dscp_map
    else :
        print '\nPort %s(0x%x) switch priority to DSCP packet priority remark' % (dscp_map['port'],portid)
        for dscp_item in dscp_list:
            print 'switch priority %d' % dscp_item['sp'],
            print 'color %d' % dscp_item['color'],
            print 'DSCP %d' % dscp_item['dscp']

def _clear_qos_port_counters(port, ingress_port, egress_port, use_json=False):
    if port:
        if ingress_port or egress_port:
            if use_json:
                _print_json_output({'exception': 'ingressPortEgressPortNotRequired'})
            else:
                print 'ERROR: With --port option, --ingress_port OR --egress_port are not required'
            return
        # Find the port ID
        port_list = _get_port_list_from_name_or_id(port, True, use_json)
        ingress_port_list = port_list
        egress_port_list = port_list
    elif ingress_port and egress_port:
        # Find the ingress and egress port ID.
        ingress_port_list = _get_port_list_from_name_or_id(ingress_port, False, use_json)
        if type(ingress_port_list) is not list or len(ingress_port_list) != 1:
            print 'ERROR: illegal ingress_port_list =', ingress_port_list
            return
        egress_port_list = _get_port_list_from_name_or_id(egress_port, False, use_json)
        if type(egress_port_list) is not list or len(egress_port_list) != 1:
            print 'ERROR: illegal egress_port_list =', egress_port_list
            return
    else:
        if use_json:
            _print_json_output({'exception': 'portInputRequired'})
        else:
            print 'ERROR: Either give --port or give both --ingress_port and --egress_port as argument'
        return

    sdk_to_linux = get_sdk_to_linux()
    for ingress_port_id in ingress_port_list:
        if sdk_to_linux and ingress_port_id in sdk_to_linux and is_bond(sdk_to_linux[ingress_port_id]):
            continue

        mlx_clear_port_prio_counters(ingress_port_id)
        mlx_clear_port_qos_counters(ingress_port_id)

    for egress_port_id in egress_port_list:
        if sdk_to_linux and egress_port_id in sdk_to_linux and is_bond(sdk_to_linux[egress_port_id]):
            continue

        mlx_clear_port_tc_counters(egress_port_id)
        mlx_clear_port_prio_counters(egress_port_id)
        mlx_clear_port_qos_counters(egress_port_id)

    if use_json:
        _print_json_output({'result': 'success'})

# Show RED ECN config
def _show_qos_port_redecn_config(sdk_to_linux, port_id, use_json= False):
    redecn_info = {}
    redecn_info = mlx_get_port_ecn_config(port_id, redecn_info)
    redecn_table_list = []
    redecn_flow_table = {SX_COS_REDECN_FLOW_TYPE_TCP_GREEN: 'TCP_GREEN', SX_COS_REDECN_FLOW_TYPE_TCP_YELLOW: 'TCP_YELLOW', SX_COS_REDECN_FLOW_TYPE_TCP_RED: 'TCP_RED', SX_COS_REDECN_FLOW_TYPE_NON_TCP_GREEN: 'NON_TCP_GREEN', SX_COS_REDECN_FLOW_TYPE_NON_TCP_YELLOW: 'NON_TCP_YELLOW', SX_COS_REDECN_FLOW_TYPE_NON_TCP_RED:'NON_TCP_RED'}
    redecn_mode_table = {SX_COS_REDECN_MODE_ABSOLUTE: 'REDECN_MODE_ABSOLUTE', SX_COS_REDECN_MODE_RELATIVE: 'REDECN_MODE_RELATIVE'}
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, port_id, use_json, ret):
        return ret['output']
    for tc in redecn_info['config']:
        for flow in redecn_info['config'][tc]['flow']:
            table_row = []
            table_row.append(tc)
            if redecn_info['config'][tc]['ecn_enabled']:
                table_row.append('TRUE')
            else:
                table_row.append('FALSE')
            if redecn_info['config'][tc]['red_enabled']:
                table_row.append('TRUE')
            else:
                table_row.append('FALSE')
            redecn_flow_dict = redecn_info['config'][tc]['flow'][flow]
            table_row.append(redecn_flow_table[flow])
            if redecn_flow_dict['mode'] in redecn_mode_table:
                table_row.append(redecn_mode_table[redecn_flow_dict['mode']])
            else:
                table_row.append(redecn_flow_dict['mode'])
            table_row.append(redecn_flow_dict['high_drop_percent'])
            if redecn_flow_dict['mode'] == SX_COS_REDECN_MODE_ABSOLUTE:
                table_row.append('{} cells'.format(redecn_flow_dict['min']))
                table_row.append('{} cells'.format(redecn_flow_dict['max']))
            elif redecn_flow_dict['mode'] == SX_COS_REDECN_MODE_RELATIVE:
                table_row.append('{} %'.format(redecn_flow_dict['min']))
                table_row.append('{} %'.format(redecn_flow_dict['max']))
            else:
                # Do not expect to get here
                table_row.append('NA')
                table_row.append('NA')
            redecn_table_list.append(table_row)

    if use_json:
        return redecn_info
    else:
        if len(redecn_table_list) == 0:
            print 'No RED/ECN config on the port %s (0x%x)' % (sdk_to_linux[port_id], port_id)
            return

        print '-------------------------------------------------'
        print 'REDECN config for port %s (0x%x) (1 cell == %d bytes)' % (sdk_to_linux[port_id], port_id, redecn_info['cell_unit_size'])
        print '-------------------------------------------------'
        print(tabulate(redecn_table_list, headers=['Traffic-Class', 'ECN', 'RED', 'Flow', 'Mode', 'High Drop Percent', 'Min', 'Max']))
        print '----------------------------------------'

def _show_qos_port_counters(sdk_to_linux, port_id, use_json=False, params=None):
    if params:
        ingress_port = params['ingress_port']
        egress_port = params['egress_port']
    if port_id:
        if params and (ingress_port or egress_port):
            if use_json:
                return {'exception': 'ingressPortEgressPortNotRequired'}
            else:
                print 'ERROR: With --port option, --ingress_port OR --egress_port are not required'
            return
        ingress_port = sdk_to_linux[port_id]
        egress_port = sdk_to_linux[port_id]
    elif params and ingress_port and egress_port:
        pass
    else:
        if use_json:
            return {'exception': 'portInputRequired'}
        else:
            print 'ERROR: Either give --port or give both --ingress_port and --egress_port as argument'
        return

    # Find the ingress and egress port ID.
    ingress_port_list = _get_port_list_from_name_or_id(ingress_port, False, use_json)
    if type(ingress_port_list) is not list or len(ingress_port_list) != 1:
        print 'ERROR: illegal ingress_port_list =', ingress_port_list
        return
    ingress_port_id = ingress_port_list[0]
    egress_port_list = _get_port_list_from_name_or_id(egress_port, False, use_json)
    if type(egress_port_list) is not list or len(egress_port_list) != 1:
        print 'ERROR: illegal egress_port_list =', egress_port_list
        return
    egress_port_id = egress_port_list[0]
    
    ret = {'output': {}}
    if _port_is_bond(sdk_to_linux, ingress_port_id, use_json, ret):
        return ret['output']

    if _port_is_bond(sdk_to_linux, egress_port_id, use_json, ret):
        return ret['output']

    ing_port_counters = mlx_get_port_counters(ingress_port_id)
    egr_port_counters = mlx_get_port_counters(egress_port_id)
    tc_table_list = []
    prio_table_list = []
    port_table_list = []

    qos_counters = {}
    for counter_set_idx in range(len(ing_port_counters['per_port']['values'])) :
        table_row = []
        qos_counters['port'] = {}
        qos_counters['port']['ingress_port'] = ingress_port
        table_row.append(ing_port_counters['per_port']['values'][counter_set_idx]['rx_frames'])
        qos_counters['port']['rx_frames'] = ing_port_counters['per_port']['values'][counter_set_idx]['rx_frames']
        table_row.append(ing_port_counters['per_port']['values'][counter_set_idx]['rx_uc'])
        qos_counters['port']['rx_uc'] = ing_port_counters['per_port']['values'][counter_set_idx]['rx_uc']
        table_row.append(ing_port_counters['per_port']['values'][counter_set_idx]['rx_mc'])
        qos_counters['port']['rx_mc'] = ing_port_counters['per_port']['values'][counter_set_idx]['rx_mc']
        table_row.append(ing_port_counters['per_port']['values'][counter_set_idx]['rx_bc'])
        qos_counters['port']['rx_bc'] = ing_port_counters['per_port']['values'][counter_set_idx]['rx_bc']

        qos_counters['port']['egress_port'] = egress_port
        table_row.append(egr_port_counters['per_port']['values'][counter_set_idx]['tx_frames'])
        qos_counters['port']['tx_frames'] = egr_port_counters['per_port']['values'][counter_set_idx]['tx_frames']
        table_row.append(egr_port_counters['per_port']['values'][counter_set_idx]['tx_uc'])
        qos_counters['port']['tx_uc'] = egr_port_counters['per_port']['values'][counter_set_idx]['tx_uc']
        table_row.append(egr_port_counters['per_port']['values'][counter_set_idx]['tx_mc'])
        qos_counters['port']['tx_mc'] = egr_port_counters['per_port']['values'][counter_set_idx]['tx_mc']
        table_row.append(egr_port_counters['per_port']['values'][counter_set_idx]['tx_bc'])
        qos_counters['port']['tx_bc'] = egr_port_counters['per_port']['values'][counter_set_idx]['tx_bc']
        table_row.append(ing_port_counters['per_port']['values'][counter_set_idx]['rx_buffer'])
        qos_counters['port']['rx_buffer_discards'] = ing_port_counters['per_port']['values'][counter_set_idx]['rx_buffer']
        table_row.append(egr_port_counters['perf']['values'][counter_set_idx]['mc_no_buffer'])
        qos_counters['port']['tx_mc_buffer_discards'] = egr_port_counters['perf']['values'][counter_set_idx]['mc_no_buffer']

        table_row.append(egr_port_counters['ieee']['values'][counter_set_idx]['rx_pause_mac_ctrl_frames'])
        qos_counters['port']['rx_pause_frames'] = egr_port_counters['ieee']['values'][counter_set_idx]['rx_pause_mac_ctrl_frames']
        table_row.append(ing_port_counters['ieee']['values'][counter_set_idx]['tx_pause_mac_ctrl_frames'])
        qos_counters['port']['tx_pause_frames'] = ing_port_counters['ieee']['values'][counter_set_idx]['tx_pause_mac_ctrl_frames']
        port_table_list.append(table_row)
    for counter_set_idx in range(len(egr_port_counters['per_tc']['values'])) :
        table_row = []
        tc_idx = 'tc_{}'.format(egr_port_counters['per_tc']['values'][counter_set_idx]['traffic class'])
        qos_counters[tc_idx] = {}
        table_row.append(egr_port_counters['per_tc']['values'][counter_set_idx]['traffic class'])
        table_row.append(egr_port_counters['per_tc']['values'][counter_set_idx]['tx_frames'])
        qos_counters[tc_idx]['tx_frames'] = egr_port_counters['per_tc']['values'][counter_set_idx]['tx_frames']
        table_row.append(egr_port_counters['per_tc']['values'][counter_set_idx]['tx_bytes'])
        qos_counters[tc_idx]['tx_bytes'] = egr_port_counters['per_tc']['values'][counter_set_idx]['tx_bytes']
        table_row.append(egr_port_counters['per_tc']['values'][counter_set_idx]['tx_no_buffer_discard_uc'])
        qos_counters[tc_idx]['tx_uc_buffer_discards'] = egr_port_counters['per_tc']['values'][counter_set_idx]['tx_no_buffer_discard_uc']
        table_row.append(egr_port_counters['per_tc']['values'][counter_set_idx]['tx_wred_discard'])
        qos_counters[tc_idx]['tx_wred_discard'] = egr_port_counters['per_tc']['values'][counter_set_idx]['tx_wred_discard']
        tc_table_list.append(table_row)
    for counter_set_idx in range(len(ing_port_counters['per_prio']['values'])) :
        table_row = []
        sp_idx = 'sp_{}'.format(ing_port_counters['per_prio']['values'][counter_set_idx]['switch priority'])
        qos_counters[sp_idx] = {}
        table_row.append(ing_port_counters['per_prio']['values'][counter_set_idx]['switch priority'])
        table_row.append(ing_port_counters['per_prio']['values'][counter_set_idx]['rx_pause'])
        qos_counters[sp_idx]['rx_pause'] = ing_port_counters['per_prio']['values'][counter_set_idx]['rx_pause']
        table_row.append(ing_port_counters['per_prio']['values'][counter_set_idx]['rx_pause_duration'])
        qos_counters[sp_idx]['rx_pause_duration'] = ing_port_counters['per_prio']['values'][counter_set_idx]['rx_pause_duration']
        table_row.append(ing_port_counters['per_prio']['values'][counter_set_idx]['tx_pause'])
        qos_counters[sp_idx]['tx_pause'] = ing_port_counters['per_prio']['values'][counter_set_idx]['tx_pause']
        table_row.append(ing_port_counters['per_prio']['values'][counter_set_idx]['tx_pause_duration'])
        qos_counters[sp_idx]['tx_pause_duration'] = ing_port_counters['per_prio']['values'][counter_set_idx]['tx_pause_duration']
        prio_table_list.append(table_row)
    if use_json:
        return qos_counters
    else:
        print '-------------------------------------------------'
        print 'Egress Queue statistics for port %s (0x%x)' % (egress_port, egress_port_id)
        print '-------------------------------------------------'
        print(tabulate(tc_table_list, headers=['Traffic-Class', 'Tx Frames', 'Tx Bytes', 'Tx UC Buffer Discards', 'WRED Discards']))
        print '----------------------------------------'
        print 'PFC statistics for port %s (0x%x)' % (ingress_port, ingress_port_id)
        print '----------------------------------------'
        print(tabulate(prio_table_list, headers=['Switch Prio', 'Rx Pause Frames', 'Rx Pause Duration', 'Tx Pause Frames', 'Tx Pause Duration']))
        print '------------------------------------------------------------------------------------------------------------------------------'
        if ingress_port_id == egress_port_id:
            print 'Port statistics for port %s (0x%x)' % (ingress_port, ingress_port_id)
        else:
            print 'Port statistics for ingress port(Rx) %s (0x%x) and egress port(Tx) %s (0x%x)' % (ingress_port, ingress_port_id, egress_port, egress_port_id)
        print '------------------------------------------------------------------------------------------------------------------------------'
        print(tabulate(port_table_list, headers=['Rx Frames', 'Rx UC Frames', 'Rx MC Frames', 'Rx BC Frames', 'Tx Frames', 'Tx UC Frames', 'Tx MC Frames', 'Tx BC Frames', 'Rx Buffer Discards', 'Tx MC Buffer Discards', 'Rx Pause Frames', 'Tx Pause Frames']))

def _show_priority_tc_map(sdk_to_linux, portid, use_json=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    tc_list = mlx_get_prio_tc_map(portid)

    tc_map = {}
    _add_port_to_dict(sdk_to_linux, tc_map, 'port', portid)

    tc_map['list'] = tc_list
    if use_json:
        return tc_map
    else :
        print '\nPort %s(0x%x) switch priority to traffic class' % (tc_map['port'],portid)
        for tc_item in tc_map['list']:
            print 'switch priority %d' % tc_item['sp'],
            print 'traffic class %d' % tc_item['tc']

def _show_priority_ieee_map(use_json=False):
    ieee_list = mlx_get_prio_ieee_map()
    if use_json:
        return ieee_list
    else :
        print '\nGlobal switch priority to IEEE priority map'
        for ieee_item in ieee_list:
            print 'switch priority %d' % ieee_item['sp'],
            print 'IEEE priority %d' % ieee_item['ieee']

def _show_port_scheduler(sdk_to_linux, portid, use_json=False, verbose=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    element_list = mlx_get_port_scheduler(portid)

    sched_dict = {}
    _add_port_to_dict(sdk_to_linux, sched_dict, 'port', portid)

    sched_dict['list'] = element_list

    if use_json:
        return sched_dict
    else :
        print '\nPort %s(0x%x) scheduler configuration' % (sched_dict['port'],portid)
        if verbose == True:
            print 'Per-port hierarchical scheduler:'
            print '\tLevel 0: root node'
            print '\tLevel 1: groups'
            print '\tLevel 2: sub-groups'
            print '\tLevel 3: port egress queues (a.k.a. traffic classes)'
            print '\'DWRR enable\' enables the DWRR mode and weight fields'
            print '\'DWRR mode\' selects between DWRR and strict priority'
            print '\'DWRR weight\' sets a weight 1..100 OR 0, which denotes strict priority (requires DWRR mode == SP)'

        current_level = -1
        for element in element_list:
            if current_level != element['level'] :
                print ''
                current_level = element['level']
            print '%s: %s,' % ('level', element['level']),
            print '%s: %s,' % ('index', element['index']),
            print '%s: %s,' % ('parent index', element['parent_index']),
            print '%s: %s,' % ('DWRR enabled', element['dwrr_enable']),
            print '%s: %s,' % ('DWRR mode', element['dwrr_mode']),
            print '%s: %s,' % ('DWRR weight', element['dwrr_weight']),
            print '%s: %s,' % ('min shaper enabled', element['min_shaper_enable']),
            print '%s: %s,' % ('min shaper rate', element['min_shaper_rate']),
            print '%s: %s,' % ('max shaper enabled', element['max_shaper_enable']),
            print '%s: %s,' % ('max shaper rate', element['max_shaper_rate']),
            print '%s: %s'  % ('shaper mode', element['shaper_mode'])

def _show_mc_aware(sdk_to_linux, portid, use_json=False, verbose=False):
    ret = {'output': {}}
    if _port_is_bond_member(sdk_to_linux, portid, use_json, ret):
        return ret['output']
    mc_aware_dict = mlx_get_mc_aware(portid)
    _add_port_to_dict(sdk_to_linux, mc_aware_dict, 'port', portid)

    if use_json:
        return mc_aware_dict
    else :
        if verbose == True:
            print '\nMC aware mode assigns multicast packets to separate egress queues'
            print 'from unicast packets. This only changes how packets are scheduled,'
            print 'not the packet buffer use, since multicast packets occupy the egress'
            print 'buffers of the Multicast pseudo-port (logical port ID 0x40000000).'
        print '\nPort %s(0x%x) MC Aware configuration' % (mc_aware_dict['port'],portid)
        print 'MC aware: %s' % mc_aware_dict['mc_aware']

def _show_flow_control(sdk_to_linux, portid, use_json=False, verbose=False):

    fc_dict = mlx_get_flow_control(portid)
    _add_port_to_dict(sdk_to_linux, fc_dict, 'port', portid)

    if use_json:
        return fc_dict
    else :
        print '\nPort %s(0x%x) flow control configuration' % (fc_dict['port'],portid)
        print 'Link pause TX enabled: %s, RX enabled %s' % (fc_dict['link_tx_enabled'],
                                                            fc_dict['link_rx_enabled'])
        for priority in fc_dict['pfc'].keys() :
            print 'PFC %d TX enabled: %s, RX enabled %s' % (priority,
                                                            fc_dict['pfc'][priority]['tx_enabled'],
                                                            fc_dict['pfc'][priority]['rx_enabled'])     

def _show_datapath_config(sdk_to_linux, portid, use_json=False, verbose=False):

    mc_logical_port = SX_MC_PORT_LOG_ID
    json_out = []
    if not use_json:
        print 'Datapath configuration for port %s and MC logical port 0x%x' % (sdk_to_linux.get(portid), mc_logical_port)
        print '\n---- Priority mapping ----- '
    # _show_priority_group_map(sdk_to_linux, portid, use_json)
    ret = _show_port_priority_trust(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_pcpdei_prio_map(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_dscp_prio_map(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_port_priority_rewrite(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_pcpdei_remark_map(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_dscp_remark_map(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_priority_tc_map(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_priority_ieee_map(use_json)
    if use_json:
        json_out.append(ret)

    if not use_json:
        print '\n------ Flow Control ----- '
    ret = _show_flow_control(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)

    if not use_json:
        print '\n----- Unallocated packet buffer cells -------'
    ret = _show_free_buffer_counters(use_json)
    if use_json:
        json_out.append(ret)
    
    if not use_json:
        print '\n----- Parser length -------'
    ret = _show_parser_length(use_json)
    if use_json:
        json_out.append(ret)

    if not use_json:
        print '\n----- Allocated packet buffer cells -------'
    ret = _show_pool_buffer_limits(use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_mc_aware(sdk_to_linux, portid, use_json, verbose)
    if use_json:
        json_out.append(ret)
    ret = _show_port_reserved_buffer_limits(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_port_reserved_buffer_limits(sdk_to_linux, mc_logical_port, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_port_shared_buffer_limits(sdk_to_linux, portid, use_json)
    if use_json:
        json_out.append(ret)
    ret = _show_port_shared_buffer_limits(sdk_to_linux, mc_logical_port, use_json)
    if use_json:
        json_out.append(ret)

    if not use_json:
        print '\n ------- Scheduler Configuration ------- '
    ret = _show_port_scheduler(sdk_to_linux, portid, use_json, verbose)
    if use_json:
        json_out.append(ret)

    if use_json:
        return json_out

def _get_ecmp_table_(use_json=False):
    rt = {}
    versions = [4, 6]
    ecmp_ids = []
    table = {}

    for vrsn in versions:
        #rt = json.loads(_show_uc_route_table(version=vrsn, use_json=True))
        rt = mlx_get_uc_route(vrsn, None)

        for r in rt:
            if rt[r]['ecmp_id'] != 0 and rt[r]['next_hop_cnt'] != 0:
                if rt[r]['ecmp_id'] not in ecmp_ids:
                    ecmp_ids.append(rt[r]['ecmp_id'])

    for eid in ecmp_ids:
        t = mlx_get_ecmp(eid)
        if t:
            table[eid] = {}
            table[eid]['nh_list'] = t[eid]

    if use_json:
        _print_json_output(table)
    else:
        print "ECMP ID\t\tRIF\t\tWEIGHT\t\tACTION"
        for eid in table:
            for i, (rif, weight, action) in enumerate(table[eid]['nh_list']):
                if i == 0:
                    print "%d\t\t%d\t\t%d\t\t%s" % (eid, rif, weight, action)
                else:
                    print "\t\t%d\t\t%d\t\t%s" % (rif, weight, action)

def _show_lag_member_port_ids_(swid, logical_bond_id, use_json=False):
    lag_member_ports = mlx_get_lag_member_ids(swid, logical_bond_id)

    if use_json:
        _print_json_output(lag_member_ports)
    else:
        output = ""
        for pid in lag_member_ports:
            output += "%d " % pid

        output = output.strip()
        print output

def _show_lag_paramters(param_type, use_json=False):
    lag_params = mlx_get_lag_parameters()

    output = {}
    if param_type == 'type':
        output['type'] = lag_params['type']
    elif param_type == 'flow_parameters':
        output['flow_params'] = lag_params['flow_params']
    elif param_type == 'seed':
        output['seed'] = lag_params['seed']
    else:
        output = lag_params

    if use_json:
        _print_json_output(output)
    else:
        print "Flag\t\tValue"
        for f in output:
            if len(f) < 5:
                print "%s\t\t%s" % (f, str(output[f]))
            else:
                print "%s\t%s" % (f, str(output[f]))

def _show_all_mstp_instances_(swid, use_json=False):
    mstp_inst = mlx_get_all_mstp_instances(swid)

    if use_json:
        _print_json_output(mstp_inst)
    else:
        print "Switch ID\t\tMSTP Instance ID"
        for i in range(len(mstp_inst)):
            if i == 0:
                print "%d\t\t\t%d" % (swid, mstp_inst[i])
            else:
                print "\t\t\t%d" % mstp_inst[i]

def _show_mstp_instance_vids_(swid, inst_id, use_json=False):
    vids = mlx_get_mstp_instance_vlans(swid, inst_id)

    if use_json:
        _print_json_output(vids)
    else:
        print "Switch ID\tMSTP Instance\tVLAN ID"
        for i in range(len(vids)):
            if i == 0:
                print "%d\t\t%d\t\t%d" % (swid, inst_id, vids[i])
            else:
                print "\t\t\t\t%d" % vids[i]

def _get_mstp_instance_port_state_(swid, inst_id, port_list, use_json=False):
    state = {'discarding': [],
             'learning': [],
             'forwarding': []}

    for port_id in port_list:
        port_state = mlx_get_mstp_port_state(swid, inst_id, port_id)
        if port_state in state:
            state[port_state].append(port_id)

    if use_json:
        _print_json_output(state)
    else:
        begin = True
        print "Switch ID\tMSTP ID\tPort ID\tState"
        for i in range(len(state['discarding'])):
            if i == 0:
                print "%d\t\t%d\t\t%d\t\tdiscarding" % \
                      (swid, inst_id, state['discarding'][i])
            else:
                print "\t\t\t\t\t%d\t\tdiscarding" % state['discarding'][i]

        for i in range(len(state['learning'])):
            if (i == 0) and begin:
                print "%d\t\t%d\t\t%d\t\tlearning" % \
                      (swid, inst_id, state['learning'][i])
            else:
                print "\t\t\t\t\t%d\t\tlearning" % state['learning'][i]

        for i in range(len(state['forwarding'])):
            if (i == 0) and begin:
                print "%d\t\t%d\t\t%d\t\tforwarding" % \
                      (swid, inst_id, state['forwarding'][i])
            else:
                print "\t\t\t\t\t%d\t\tforwarding" % state['forwarding'][i]

def _show_port_ids(swid_list=[0], use_json=False):
    port_id_dict = mlx_get_port_ids(swid_list)

    if use_json:
        _print_json_output(port_id_dict)
    else:
        print "Swid\tPort ID\tHex Port ID"
        for swid in sorted(port_id_dict.keys()):
            for portid in sorted(port_id_dict[swid]):
                print "%d\t%d\t0x%08x" % (swid, portid, portid)

def _show_port_isolate(swid_list=[0], use_json=False):
    port_iso_dict = mlx_get_port_isolate(swid_list)

    if use_json:
        _print_json_output(port_iso_dict)
    else:
        print "Destination\tIsolated Sources"
        for portid in sorted(port_iso_dict.keys()):
            iso_ports = ""
            for iso_port in port_iso_dict[portid]:
                iso_ports += " 0x%08x" % (iso_port)
            print "0x%08x\t%s" % (portid, iso_ports)

def _set_port_isolate(portid, iso_port_list=[], use_json=False):
    mlx_set_port_isolate(portid, iso_port_list)

def _set_port_priority_rewrite(portid, dscp='no', pcpdei='no', exp='no'):
    mlx_set_port_priority_rewrite(portid, dscp, pcpdei, exp)

def _set_port_dscp_remark(portid, priority, color, dscp):
    mlx_set_port_dscp_remark(portid, priority, color, dscp)

# Will return a tuple (result,msg): 
# msg: return message to let user know of the issue
# result: bool True/False for status
def _traffic_fuse_node_reload(use_json=False, traffic_file=None, datapath_file=None):
    script_dir      = '/usr/cumulus/bin/'
    usr_config_dir  = '/etc/cumulus/'
    chip_config_dir = '/usr/lib/python2.7/dist-packages/cumulus/__chip_config/mlx/'
    traffic_reload_fuse_node = '/cumulus/switchd/config/traffic/reload'
    mlx_datapath_file = '/etc/mlx/datapath/datapath.conf'

    ret_msg = ''

    if traffic_file == None:
        traffic_file    = usr_config_dir  + 'datapath/traffic.conf'

    if datapath_file == None:
        datapath_file    = chip_config_dir + 'datapath.conf'

    command_str = [ script_dir + 'cl-consistency-check',
                    '--datapath-syntax-check', '-t', traffic_file,
                    '-d', datapath_file ]
    try:
        with open(os.devnull, 'w') as devnull:
            ret = subprocess.call(command_str,stdout=devnull,stderr=devnull)
    except BaseException as e:
        if use_json:
            ret_msg += 'CCFailedQoS:{0}'.format(e)
        else:
            ret_msg += 'Exception: {0}\n'.format(e)
            ret_msg += 'Errors detected while running consistency-checker with traffic config file %s. and datapath config file %s\n' % (traffic_file,datapath_file)
        return (False,ret_msg)

    if ret:
        if use_json:
            ret_msg += 'CCFailedQoS'
        else:
            ret_msg += 'Errors detected while running consistency-checker with traffic config file %s. and datapath config file %s\n' % (traffic_file,datapath_file)
        return (False,ret_msg)

    # Copy over the user datapath file to mlx datapath file
    command_str = [ 'cp', datapath_file, mlx_datapath_file ]
    try:
        with open(os.devnull, 'w') as devnull:
            ret = subprocess.call(command_str,stdout=devnull,stderr=devnull)
    except BaseException as e:
        if use_json:
            ret_msg += 'CopyDatapathFileFailed:{0}'.format(e)
        else:
            ret_msg += 'Exception: {0}\n'.format(e)
            ret_msg += 'Errors detected while copying usr datapath config file %s to mlx file %s\n' % (datapath_file, mlx_datapath_file)
        return (False,ret_msg)

    if ret:
        if use_json:
            ret_msg += 'CopyDatapathFileFailed'
        else:
            ret_msg += 'Errors detected while copying usr datapath config file %s to mlx file %s\n' % (datapath_file, mlx_datapath_file)
        return (False,ret_msg)

    if os.path.exists(traffic_reload_fuse_node):
        try:
            with open(traffic_reload_fuse_node, "w") as f:
                f.write("1")
        except BaseException as e:
            if use_json:
                ret_msg += 'TrafficFuseNodeReloadFailed:{0}'.format(e)
            else:
                ret_msg += 'Exception: {0}\n'.format(e)
                ret_msg += 'Errors detected while reconfiguring QoS config in traffic fuse node reload\n'
            return (False,ret_msg)
    else:
        if use_json:
            ret_msg += 'TrafficFuseNodeFileNotFound'
        else:
            ret_msg += "Traffic Fuse node reload file {} does not exists\n".format(traffic_reload_fuse_node)
        return (False,ret_msg)

    command_str = [ 'echo', '$?' ]

    try:
        with open(os.devnull, 'w') as devnull:
            ret = subprocess.call(command_str,stdout=devnull,stderr=devnull)
    except BaseException as e:
        if use_json:
            ret_msg += 'TrafficFuseNodeReloadFailed:{0}'.format(e)
        else:
            ret_msg += 'Exception: {0}\n'.format(e)
            ret_msg += 'Errors detected while reconfiguring QoS config in traffic fuse node reload\n'
        return (False,ret_msg)

    if ret:
        if use_json:
            ret_msg += 'TrafficFuseNodeReloadFailed'
        else:
            ret_msg += 'Errors detected while reconfiguring QoS config in traffic fuse node reload\n'
        return (False,ret_msg)
    
    return (True,ret_msg)

def _ports_info(swid_list=[0], use_json=False):
    try:
        platform = cumulus.platforms.probe()
    except cumulus.platforms.NoSuchPlatform, e:
        sys.stderr.write('WARNING: unknown platform: %s\n' % str(e))
        sys.exit(-1)
    use_rate_api = platform.use_rate_api
    port_id_dict = mlx_get_port_ids(swid_list)

    port_info_dict = {}
    sdk_to_lnx = get_sdk_to_linux()
    for swid in port_id_dict:
        for portid in port_id_dict[swid]:
            port_info_dict[portid] = {}
            port_info_dict[portid]["ifname"] = sdk_to_lnx.get(portid,"None")
            port_info_dict[portid]["status"] = mlx_get_port_status(portid)
            if use_rate_api == True:
                port_info_dict[portid]["speed"]  = mlx_get_port_rate(portid)
            else:
                port_info_dict[portid]["speed"]  = mlx_get_port_speed(portid)
            port_info_dict[portid]["mtu"]    = mlx_get_port_mtu(portid)
            port_info_dict[portid]["fec"]    = mlx_get_port_fec(portid, use_rate_api)
    if use_json:
        _print_json_output(port_info_dict)
    else:
        print "Port ID\tHex Port ID\tPort\tStatus\tMTU\tSpeed\tFEC"
        for portid in sorted(port_info_dict.keys()):
            print "%9d\t0x%08x\t%s\t%s\t%s\t%d Gbps\t%s" % (portid, portid, \
                port_info_dict.get(portid,{}).get("ifname", "None"), \
                port_info_dict.get(portid,{}).get("status", "None"), \
                port_info_dict.get(portid,{}).get("mtu", "None"), \
                port_info_dict.get(portid,{}).get("speed", 0)/(1*1000*1000*1000), \
                port_info_dict.get(portid,{}).get("fec", "Unknown"))

# Get the port and split numbers from a formatted or unformatted linux port name.
def _get_port_split_from_linux_port(linux_port):
    port = None
    split = None
    match = re.match("swp(\d+)s(\d+)", linux_port)
    if match:
        # Split port
        port = int(match.group(1))
        split = int(match.group(2))
    else:
        match = re.match("swp(\d+)", linux_port)
        if match:
            # Non-split port
            port = int(match.group(1))
    return port, split

def _get_port_list_from_name_or_id(string, wc_name_allowed=False, use_json=False):
    '''
    A valid port_name_or_id can be a port number, decimal or 
    hexadecimal (starts with "0x"), a swp name such as "swp12", or
    if wc_name_allowed is True, a wildcard name such as "swp*" or "swp+".
    '''
    port_list = []
    swid = 0

    if string.startswith("0x"):
        try:
            portid = int(string,16)
        except:
            portid = mlx_invalid_port_id()
    else:
        try:
            portid = int(string)
        except:
            portid = mlx_invalid_port_id()

    if portid != mlx_invalid_port_id():
        sdk_to_linux = get_sdk_to_linux()
        if sdk_to_linux.get(portid,None):
            port_list.append(portid)
        elif portid in mlx_get_port_ids([swid])[swid]:
            # Accept port-channel logid as input
            port_list.append(portid)

    elif string == port_wildcard1 or string == port_wildcard2:
        if wc_name_allowed:
            swid_list=[0]
            port_id_dict = mlx_get_port_ids(swid_list)
            sdk_to_linux = get_sdk_to_linux()
            linux_to_sdk = get_linux_to_sdk()

            # Add all swp ports and exclude LAGs
            formatted_port_list = []
            # Number of digits to reserve for port and split for sorting format.
            digits = '3'
            for swid in port_id_dict:
                for portid in port_id_dict[swid]:
                    linux_port = sdk_to_linux.get(portid,None)
                    if linux_port:
                        # Format the port and slot numbers to fixed length for sorting.
                        port, split = _get_port_split_from_linux_port(linux_port)
                        if port != None and split != None:
                            # Split port
                            formatted_port = ("swp%0" + digits + "ds%0" + digits + "d") % (port, split)
                        elif port != None:
                            # Non-split port
                            formatted_port = ("swp%0" + digits + "d") % port
                        else:
                            # Non-physical port
                            formatted_port = linux_port
                        formatted_port_list.append(formatted_port)
            # After fixed length formatting, we can sort according to real system port order.
            formatted_port_list.sort()
            for formatted_port in formatted_port_list:
                # Convert back to unformatted linux port name.
                port, split = _get_port_split_from_linux_port(formatted_port)
                if port != None and split != None:
                    # Split port
                    linux_port = "swp%ds%d" % (port, split)
                elif port != None:
                    # Non-split port
                    linux_port = "swp%d" % port
                else:
                    # Non-physical port
                    linux_port = formatted_port
                if is_bond(linux_port):
                    # We need to exclude LAG
                    continue
                # Convert back to SDK port ID.
                portid = linux_to_sdk.get(linux_port, None)
                # Now add to the port list in true system port order.
                port_list.append(portid)
    else:
        linux_to_sdk = get_linux_to_sdk()
        portid = linux_to_sdk.get(string,None)
        if portid is not None:
            port_list.append(portid)

    if len(port_list) == 0:
        if use_json:
            _print_json_output({'port': string, 'exception': 'inputPortNotSupported'})
        else:
            print "%s is not a supported port_name_or_id" % string
        exit(-1)

    return port_list

def _set_port_sflow(port_name_or_id, ing_rate, egr_rate, use_json=False):
    rate_max = mlx_get_port_sflow_sample_rate_max()
    if ing_rate > rate_max:
        print "ing_rate %u exceeds maximum sampling rate of %u" % (ing_rate, rate_max)
        exit(-1)

    if egr_rate > rate_max:
        print "egr_rate %u exceeds maximum sampling rate of %u" % (egr_rate, rate_max)
        exit(-1)

    port_list = _get_port_list_from_name_or_id(port_name_or_id, True, use_json)
    for portid in port_list:
        mlx_set_port_sflow(portid, ing_rate, egr_rate)

def _show_port_sflow(sdk_to_linux, portid, use_json=False):
    sflow_params = mlx_get_port_sflow(portid)
    if use_json:
        return sflow_params
    else:
        print "%s (0x%x):" % (sdk_to_linux.get(portid), portid)
        print "  ing_rate  %d" % sflow_params.get('ing_rate')
        print "  egr_rate  %d" % sflow_params.get('egr_rate')
        print "  deviation %d\n" % sflow_params.get('deviation')

def _show_port_sflow_name_or_id(port_name_or_id, use_json=False):
    __expand_port_name_or_id(_show_port_sflow, port_name_or_id, True, use_json)

def _show_port_sflow_stats(sdk_to_linux, portid, use_json=False):
    sflow_statistics = mlx_get_port_sflow_statistics(portid)
    if use_json:
        return sflow_statistics
    else:
        print "%s (0x%x):" % (sdk_to_linux.get(portid), portid)
        print "  count_sample_drop  %d\n" % sflow_statistics.get('count_sample_drop')

def _show_port_sflow_stats_name_or_id(port_name_or_id, use_json=False):
    __expand_port_name_or_id(_show_port_sflow_stats, port_name_or_id, True, use_json)

def intBase(intStr):
    '''
    Allow an integer to be specified with standard base representations:
    37 = decimal, 0x25 = hex, 045 = octal, 0b100101 = binary
    '''
    try:
        intVal = int(intStr,0)
    except:
        msg = "%s is not a valid integer" % (intStr,)
        raise argparse.ArgumentTypeError(msg)
    return intVal

def _store_pers_data(data, file_name):
    try:
        pers_db_file = open(file_name,'wb')
    except:
        return

    pickle.dump(data, pers_db_file)
    pers_db_file.close()

def _fetch_pers_data(file_name):
    try:
        pers_db_file = open(file_name,'rb')
    except:
        return ''

    try:
        data = pickle.load(pers_db_file)
    except:
        return ''
    pers_db_file.close()
    return data

def _read_sx_sdk_pid(filename):
    try:
        f = open(filename, 'r')
    except:
        return 0
    l = f.readlines();
    try:
        sx_sdk_pid = int(l[0])
    except:
        f.close()
        return 0
    f.close()
    return sx_sdk_pid

def _get_trap_stats_diff(old_data, new_data):
    cur_pid = _read_sx_sdk_pid(sx_sdk_pidfile)
    old_pid = _read_sx_sdk_pid(mlxcmd_sx_sdk_pidfile)
    if old_data != '' and cur_pid == old_pid:
        for trap_id, trap_stats_item in new_data.items():
            cpu_pkts_diff = trap_stats_item['to_cpu_pkts'] - old_data[trap_id]['to_cpu_pkts']
            trap_stats_item['to_cpu_pkts_diff'] =  cpu_pkts_diff if cpu_pkts_diff >= 0 else '-' 
            cpu_bytes_diff = trap_stats_item['to_cpu_bytes'] - old_data[trap_id]['to_cpu_bytes']
            trap_stats_item['to_cpu_bytes_diff'] = cpu_bytes_diff if cpu_bytes_diff >= 0 else '-' 
            violation_pkts_diff = trap_stats_item['violation_counter_pkts'] - old_data[trap_id]['violation_counter_pkts']
            trap_stats_item['violation_counter_pkts_diff'] = violation_pkts_diff if violation_pkts_diff >= 0 else '-' 
    else:
        for trap_id, trap_stats_item in new_data.items():
            trap_stats_item['to_cpu_pkts_diff'] = '-'
            trap_stats_item['to_cpu_bytes_diff'] = '-'
            trap_stats_item['violation_counter_pkts_diff'] = '-'
        if cur_pid != old_pid and cur_pid != 0:
            f = open(mlxcmd_sx_sdk_pidfile,'w')
            f.write(str(cur_pid)+'\n')
            f.close()

def _clear_trap_stats(use_json=False):
    mlx_clear_all_trap_stats()
    pers_trap_stats_file = g_pers_trap_stats_file
    try:
        os.remove(pers_trap_stats_file)
    except:
        return
    
def _show_trap_stats(use_json=False, show_diff=True):
    pers_trap_stats_file = g_pers_trap_stats_file
    prev_buffer_info = _fetch_pers_data(pers_trap_stats_file)

    buffer_info = mlx_show_trap_stats()
    _store_pers_data(buffer_info, pers_trap_stats_file)
    _get_trap_stats_diff(prev_buffer_info, buffer_info)

    if use_json:
        _print_json_output(buffer_info)
    else:
        table_list = []
        for trap_id, trap_item in buffer_info.items():
            table_row = []
            table_row.append(trap_item['trap_name'])
            table_row.append(trap_id)
            table_row.append(trap_item['trap_group_id'])
            table_row.append(trap_item['to_cpu_pkts'])
            if show_diff == True:
                table_row.append(trap_item['to_cpu_pkts_diff'])
            table_row.append(trap_item['to_cpu_bytes'])
            if show_diff == True:
                table_row.append(trap_item['to_cpu_bytes_diff'])
            table_row.append(trap_item['violation_counter_pkts'])
            if show_diff == True:
                table_row.append(trap_item['violation_counter_pkts_diff'])
            table_list.append(table_row)
        
        if show_diff == True:
            print(tabulate(table_list, headers=['Trap Name', 'Trap Id', 'Trap Group Id', 'To CPU Pkts', 'Diff', 'To CPU Bytes', 'Diff', 'Violated Pkts', 'Diff']))
        else:
            print(tabulate(table_list, headers=['Trap Name', 'Trap Id', 'Trap Group Id', 'To CPU Pkts', 'To CPU Bytes', 'Violated Pkts']))
    
def _show_trap_group_stats(use_json=False):
    buffer_info = mlx_show_trap_group_stats()
    if use_json:
        _print_json_output(buffer_info)
    else:
        table_list = []
        for trap_grp_id, trap_grp_item in buffer_info.items():
            table_row = []
            table_row.append(trap_grp_item['trap_group_id'])
            table_row.append(trap_grp_item['to_cpu_pkts'])
            table_row.append(trap_grp_item['to_cpu_bytes'])
            table_row.append(trap_grp_item['violation_counter_pkts'])
            table_list.append(table_row)
        
        print(tabulate(table_list, headers=['Trap Group Id', 'To CPU Pkts', 'To CPU Bytes', 'Violated Packets']))

def mlxcmd_main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--json', action="store_true", help="Enable JSON output")
    parser.add_argument('--verbose', action="store_true", help='use more words')
    
    subparser = parser.add_subparsers()

    # L2 command set
    l2_parser = subparser.add_parser('l2', help="commands that are related to Layer 2")
    l2_subparser = l2_parser.add_subparsers(help="l2 choices")

    # Bridge command set under L2
    bridge_subparser = l2_subparser.add_parser('bridge')
    bridge_cmds = bridge_subparser.add_subparsers()
    bridge_vport = bridge_cmds.add_parser('vports')
    bridge_vport.add_argument('br_swid', type=int,
                                  metavar='<swid for bridge>')
    bridge_vport.add_argument('br_vid', type=int,
                              help='VLAN ID of the bridge')

    # FDB command set Under L2
    fdb_subparser = l2_subparser.add_parser('fdb', help='different commands for the fdb')

    fdb_cmds = fdb_subparser.add_subparsers()
    fdb_show = fdb_cmds.add_parser('show')
    fdb_sub_show = fdb_show.add_subparsers(help="l2 fdb show help")
    tbl_cmd = fdb_sub_show.add_parser('table')
    tbl_cmd.add_argument('switch_id', type=int, nargs='?', default=0,
                         help="switch ID of the FDB table to display")
    timers_cmd = fdb_sub_show.add_parser('timers', help="display the FDB aging time")
    timers_cmd.add_argument('fdb_timer_show', nargs='*', default=[0])

    fdb_mcshow = fdb_cmds.add_parser('mcshow')
    fdb_sub_mcshow = fdb_mcshow.add_subparsers(help="l2 fdb mcshow help")
    mtbl_cmd = fdb_sub_mcshow.add_parser('table')
    mtbl_cmd.add_argument('mcswitch_id', type=int, nargs='?', default=0,
                          help="switch ID of the MC FDB table to display")

    fdb_set = fdb_cmds.add_parser('set')
    fdb_sub_set = fdb_set.add_subparsers(help="l2 fdb set help")
    set_age_timer = fdb_sub_set.add_parser('aging')
    set_age_timer.add_argument('aging_timer', type=int,
                               help="value for the aging time to be set")
    set_age_timer.add_argument('swid_list', nargs="*", default=[0],
                               metavar="<swid>",
                               help="list of switch ID to change aging timers on")

    fdb_flush = fdb_cmds.add_parser('flush')
    fdb_sub_flush = fdb_flush.add_subparsers(help="l2 fdb flush help")
    uc_fdb = fdb_sub_flush.add_parser('uc', help="commnds for flushing unicast FDBs")
    uc_all_fdb = uc_fdb.add_subparsers(help="options for flushing unicast FDBs")
    uc_all_opts = uc_all_fdb.add_parser('all')
    uc_all_opts.add_argument('all_fdb_flush_swids', type=int, nargs="*", default=[0],
                             metavar='swid')
    uc_fid_opts = uc_all_fdb.add_parser('fid')
    uc_fid_opts.add_argument('fdb_fids', type=int, nargs=2,
                             metavar=('switch_id', 'fid'),
                             help="<switch ID> <fid>")
    uc_port_opts = uc_all_fdb.add_parser('port')
    uc_port_opts.add_argument('fdb_log_port_id', type=int,
                              metavar="logical_port_ID",
                              help="<logical port ID>")

    mc_fdb = fdb_sub_flush.add_parser('mc', help="commands for flushing multicast FDBs")

    # L3 command set
    l3_parser = subparser.add_parser('l3', help="Layer 3 commands")
    l3_parser.add_argument('l3_sub_cmd', choices=['route', 'neighbor', 
                                                  'route6', 'neighbor6', 'ecmp_table',
                                                  'interface', 'route_count', 'route6_count'],
                            help="l3 choices")

    # LAG commands
    lag_parser = subparser.add_parser('lag')
    lag_sub_parser = lag_parser.add_subparsers()
    lag_show = lag_sub_parser.add_parser('show')
    lag_sub_show = lag_show.add_subparsers()
    lag_show_members = lag_sub_show.add_parser('members')
    lag_show_members.add_argument('lag_member_swid', type=int,
                                  metavar='<swid lag port is on>')
    lag_show_members.add_argument('lag_member_port_id', type=int,
                                 metavar="<logical port ID for lag>")
    lag_show_hash_flow_params = lag_sub_show.add_parser('hash')
    lag_show_hash_flow_params.add_argument('hash_params', choices=['type', 
                                                                   'flow_parameters',
                                                                   'seed', 'all'])

    # MSTP command set
    mstp_parser = subparser.add_parser('mstp')
    mstp_sub_parser = mstp_parser.add_subparsers()
    mstp_inst_show = mstp_sub_parser.add_parser('instances')
    mstp_inst_show.add_argument('mstp_swid', type=int, nargs="?", default=0)
    mstp_inst_port_state = mstp_sub_parser.add_parser('port_state')
    mstp_inst_port_state.add_argument('port_state_swid', type=int,
                                      metavar="<switch id>")
    mstp_inst_port_state.add_argument('port_state_mstp_inst', type=int,
                                      metavar="<mstp instance>")
    mstp_inst_port_state.add_argument('port_state_ids', type=int, nargs="*",
                                      metavar="<logical port id>")
    mstp_inst_vids = mstp_sub_parser.add_parser('vids')
    mstp_inst_vids.add_argument('vid_swid', type=int)
    mstp_inst_vids.add_argument('vid_inst', type=int)

    # packet buffers command set
    buffers_parser = subparser.add_parser('buffers', help="Packet buffer commands")
    buffers_parser.add_argument('buffer_sub_cmd',
                                choices=['pool',
                                         'port_reserved',
                                         'port_shared',
                                         'free',
                                         'mc_aware'],
                                help='buffer choices')
    buffers_parser.add_argument('buffer_type', choices=['limits', 'counters', 'other'], help='buffer type choices')
    buffers_parser.add_argument('--port', metavar='<port_name_or_id>', default='0x13d00', help='logical port ID (default is 0x13d00)')
    buffers_parser.add_argument('--swid', type=int, default=0, help='switch ID (default is 0)')
    buffers_parser.add_argument('--clear', action="store_true", help='Clear the counters')
    buffers_parser.add_argument('--cells',action="store_true", help='Show storage in cells')

    # datapath configuration command set
    datapath_parser = subparser.add_parser('datapath', help='datapath configuration commands')
    datapath_parser.add_argument('datapath_sub_cmd',
                                 choices=['show'],
                                 help='datapath configuration actions')
    datapath_parser.add_argument('--port', metavar='<port_name_or_id>', default='0x13d00', help='logical port ID (default is 0x13d00)')
    datapath_parser.add_argument('--cells',action="store_true", help='Show storage in cells')

    # QoS command set
    qos_parser = subparser.add_parser('qos', help="QoS commands")
    qos_parser.add_argument('qos_sub_cmd',
                                choices=['mapping',
                                         'redecn',
                                         'counters',
                                         'config'],
                                help='QoS choices')
    qos_parser.add_argument('qos_config_type', choices=['reload'], nargs='?', help='qos config choices.')
    qos_parser.add_argument('--clear', action="store_true", help='Clear the counters')
    qos_parser.add_argument('--ingress_port', metavar='<port_name_or_id>', help='logical ingress port name or ID - single port name only supported.')
    qos_parser.add_argument('--egress_port', metavar='<port_name_or_id>', help='logical egress port name or ID - single port name only supported.')
    qos_parser.add_argument('--port', metavar='<port_name_or_id>', help='logical port name or ID - supports wild card swp*. Only used for qos counters')
    qos_parser.add_argument('--cells',action="store_true", help='Show storage in cells')

    # RoCE command set
    roce_parser = subparser.add_parser('roce', help="RoCE commands")
    roce_parser.add_argument('roce_sub_cmd',
                                choices=['counters', 'status'],
                                help='RoCE choices')
    roce_parser.add_argument('--port', metavar='<port_name_or_id>', default=port_wildcard1, help='logical port name or ID (default is all ports)')
    roce_parser.add_argument('--system', action="store_true", help='Show global system RoCE status, not related to a specific port')
    roce_parser.add_argument('--cells',action="store_true", help='Show storage in cells')
    roce_clear_group = roce_parser.add_mutually_exclusive_group()
    roce_clear_group.add_argument('--clear', action="store_true", help="Clear the counters")
    roce_clear_group.add_argument('--read_clear', action="store_true", help="Read and clear the counters")

    # priority map command set
    prio_parser = subparser.add_parser('priority', help='switch priority map commands')
    prio_parser.add_argument('prio_sub_cmd',
                             choices=['pcpdei',
                                      'dscp',
                                      'traffic_class',
                                      'ieee',
                                      'priority_group',
                                      'trust',
                                      'rewrite'],
                             help='packet priority choices')
    prio_parser.add_argument('--remark', action='store_true', help='show priority remark mapping')
    prio_parser.add_argument('--port', metavar='<port_name_or_id>', default='0x13d00', help='logical port ID (default is 0x13d00)')

    # scheduler command set
    sched_parser = subparser.add_parser('scheduler', help='port scheduler commands')
    sched_parser.add_argument('sched_sub_cmd', choices=['show'], help='port scheduler choices')
    sched_parser.add_argument('--port', metavar='<port_name_or_id>', default='0x13d00', help='logical port ID (default is 0x13d00)')

    # flow control command set
    fc_parser = subparser.add_parser('flow_control', help='flow control commands')
    fc_parser.add_argument('fc_sub_cmd', choices=['show'], help='flow control choices')
    fc_parser.add_argument('--port', metavar='<port_name_or_id>', default='0x13d00', help='logical port ID (default is 0x13d00)')
    
    # Ports command set
    ports_parser = subparser.add_parser('ports', help='Port configuration and counters')
    ports_sub_parser = ports_parser.add_subparsers()
    ports_show = ports_sub_parser.add_parser('show')
    ports_sub_show = ports_show.add_subparsers()
    ports_show_cntr = ports_sub_show.add_parser('counters')
    ports_show_cntr.add_argument('show_port_counters_port_name', metavar='<port_name_or_id>')
    ports_show_dist = ports_sub_show.add_parser('pktdist')
    ports_show_dist.add_argument('show_port_pkt_dist_port_name', metavar='<port_name_or_id>')
    ports_show_discards = ports_sub_show.add_parser('discards')
    ports_show_discards.add_argument('show_port_discards_port_name', metavar='<port_name_or_id>')
    ports_show_ids = ports_sub_show.add_parser('ids')
    ports_show_ids.add_argument('port_swids_list', type=int, nargs="*",
                          default=[0], metavar="<switch id>")
    ports_show_isolate = ports_sub_show.add_parser('isolate')
    ports_show_isolate.add_argument('show_port_isolate_swids', type=int, nargs="*",
                                    default=[0], metavar="<switch id>")
    ports_show_sflow = ports_sub_show.add_parser('sflow')
    ports_show_sflow.add_argument('show_port_sflow_port_name', metavar='<port_name_or_id>')
    ports_show_sflow_stats = ports_sub_show.add_parser('sflow_statistics')
    ports_show_sflow_stats.add_argument('show_port_sflow_stats_port_name', metavar='<port_name_or_id>')

    ports_clear = ports_sub_parser.add_parser('clear')
    ports_clear.add_argument('clear_port_id', metavar='<port_name_or_id>')
    ports_clear.add_argument('clear_cntr_grp_type', metavar="<type of counters to clear>",
                             type=int, nargs='?', default=SX_PORT_CNTR_GRP_ALL)
    ports_info = ports_sub_parser.add_parser('info')
    ports_info.add_argument('port_info_swids', type=int, nargs="*",
                          default=[0], metavar="<switch id>")
    ports_set = ports_sub_parser.add_parser('set')
    ports_sub_set = ports_set.add_subparsers()
    ports_set_isolate = ports_sub_set.add_parser('isolate')
    ports_set_isolate.add_argument('isolate_portid', metavar='<portid>', type=intBase)
    ports_set_isolate.add_argument('isolate_port_list', metavar='<portids>', type=intBase, 
                                   nargs="*", default=[])
    ports_set_sflow = ports_sub_set.add_parser('sflow')
    ports_set_sflow.add_argument('set_port_sflow_port_name', metavar='<port_name_or_id>')
    ports_set_sflow.add_argument('set_port_sflow_ing_rate', metavar='<ing_rate>', type=intBase)
    ports_set_sflow.add_argument('set_port_sflow_egr_rate', metavar='<egr_rate>', type=intBase)

    ports_set_priority_rewrite = ports_sub_set.add_parser('priority_rewrite')
    ports_set_priority_rewrite.add_argument('set_port_priority_rewrite_port', metavar='<portid>', type=intBase)
    ports_set_priority_rewrite.add_argument('set_port_priority_rewrite_dscp', metavar='<dscp>')
    ports_set_priority_rewrite.add_argument('set_port_priority_rewrite_pcpdei', metavar='<pcpdei>')
    ports_set_priority_rewrite.add_argument('set_port_priority_rewrite_exp', metavar='<exp>')
    ports_set_dscp_remark = ports_sub_set.add_parser('dscp_remark')
    ports_set_dscp_remark.add_argument('set_port_dscp_remark_port_name', metavar='<portid>', type=intBase)
    ports_set_dscp_remark.add_argument('set_port_dscp_remark_priority', metavar='<priority>', type=intBase)
    ports_set_dscp_remark.add_argument('set_port_dscp_remark_color', metavar='<color>', type=intBase)
    ports_set_dscp_remark.add_argument('set_port_dscp_remark_dscp', metavar='<dscp>', type=intBase)
    # VLAN command set
    vlan_parser = subparser.add_parser('vlan', help='VLAN configuration')
    vlan_sub_parser = vlan_parser.add_subparsers()
    vlan_ids = vlan_sub_parser.add_parser('ids')
    vlan_ids.add_argument('vlan_swids_list', type=int, nargs="*",
                          default=[0], metavar="<switch id>")
    vlan_ports = vlan_sub_parser.add_parser('ports')
    vlan_ports.add_argument('swid_vlan_ports', metavar='<swid>', type=int,
                            nargs="?")
    vlan_ports.add_argument('vids_vlan_ports', metavar="<vid>", type=int,
                            nargs="*", default=[])

    #Traps command set
    traps_parser = subparser.add_parser('traps', help='TRAP operations')
    traps_sub_parser = traps_parser.add_subparsers()

    #Traps show command set
    traps_show = traps_sub_parser.add_parser('show')
    traps_show.add_argument('traps_show_sub_cmd',
                                choices=['stats', 'group-stats'],
                                help='Show Trap Statistics choices')

    #Traps clear command set
    traps_clear = traps_sub_parser.add_parser('clear')
    traps_clear.add_argument('traps_clear_sub_cmd',
                                choices=['stats'],
                                help='Clear Trap Statistics choices')

    args = parser.parse_args()

    if args.json:
        JSON = True
    else:
        JSON = False

    if args.verbose:
        VERBOSE = True
    else :
        VERBOSE = False

    # Open the connection to the MLX SDK
    mlx_open_connection()

    if hasattr(args, 'br_swid') and \
       hasattr(args, 'br_vid'):
        _show_bridge_vports(swid=args.br_swid, br_vid=args.br_vid, use_json=JSON)

    if hasattr(args, 'switch_id'):
        _show_fdb_table(swid=args.switch_id, use_json=JSON)

    if hasattr(args, 'fdb_timer_show'):
        _show_fdb_age_time(swid_list=args.fdb_timer_show, use_json=JSON)

    if hasattr(args, 'mcswitch_id'):
        _show_mc_fdb_table(swid=args.mcswitch_id, use_json=JSON)

    if hasattr(args, 'aging_timer') and \
       hasattr(args, 'swid_list'):
        mlx_set_fdb_age_time(args.aging_timer,
                             swid_list=args.swid_list)

    if hasattr(args, 'all_fdb_flush_swids'):
        mlx_flush_uc_fdb_all(swid_list=args.all_fdb_flush_swids)

    if hasattr(args, 'fdb_fids'):
        mlx_flush_uc_fdb_fid(args.fdb_fids[1], swid=args.fdb_fids[0])

    if hasattr(args, 'l3_sub_cmd'):
        if args.l3_sub_cmd == 'route':
            _show_uc_route_table(version=4, use_json=JSON)
        elif args.l3_sub_cmd == 'neighbor':
            _show_ip_neighbor_table(version=4, use_json=JSON)
        elif args.l3_sub_cmd == 'route6':
            _show_uc_route_table(version=6, use_json=JSON)
        elif args.l3_sub_cmd == 'neighbor6':
            _show_ip_neighbor_table(version=6, use_json=JSON)
        elif args.l3_sub_cmd == 'ecmp_table':
            _get_ecmp_table_(use_json=JSON)
        elif args.l3_sub_cmd == 'route_count':
            _show_uc_route_count(version=4, use_json=JSON)
        elif args.l3_sub_cmd == 'route6_count':
            _show_uc_route_count(version=6, use_json=JSON)
        if args.l3_sub_cmd == 'interface':
            _show_interface_table(use_json=JSON)

    if hasattr(args, 'lag_member_swid') and \
       hasattr(args, 'lag_member_port_id'):
        _show_lag_member_port_ids_(args.lag_member_swid, args.lag_member_port_id,
                                   use_json=JSON)

    if hasattr(args, 'hash_params'):
        _show_lag_paramters(args.hash_params, use_json=JSON)

    if hasattr(args, 'mstp_swid'):
         _show_all_mstp_instances_(args.mstp_swid, use_json=JSON)

    if hasattr(args, 'port_state_swid') and \
       hasattr(args, 'port_state_mstp_inst') and \
       hasattr(args, 'port_state_ids'):
        _get_mstp_instance_port_state_(args.port_state_swid,
                                       args.port_state_mstp_inst,
                                       args.port_state_ids, use_json=JSON)

    if hasattr(args, 'vid_swid') and \
       hasattr(args, 'vid_inst'):
        _show_mstp_instance_vids_(args.vid_swid, args.vid_inst, use_json=JSON)

    if hasattr(args, 'sched_sub_cmd') :
        if args.sched_sub_cmd == 'show':
            __expand_port_name_or_id(_show_port_scheduler, args.port, True, use_json=JSON)

    if hasattr(args, 'fc_sub_cmd'):
        if args.fc_sub_cmd == 'show':
            __expand_port_name_or_id(_show_flow_control, args.port, True, use_json=JSON)

    if hasattr(args, 'datapath_sub_cmd'):
        if args.datapath_sub_cmd == 'show':
            __expand_port_name_or_id(_show_datapath_config, args.port, True, use_json=JSON)

    if hasattr(args, 'prio_sub_cmd'):
        if args.prio_sub_cmd == 'trust':
            __expand_port_name_or_id(_show_port_priority_trust, args.port, True, use_json=JSON)
        if args.prio_sub_cmd == 'rewrite':
            __expand_port_name_or_id(_show_port_priority_rewrite, args.port, True, use_json=JSON)
        if args.prio_sub_cmd == 'priority_group':
            __expand_port_name_or_id(_show_priority_group_map, args.port, True, use_json=JSON)
        if args.prio_sub_cmd == 'pcpdei':
            if args.remark == True:
                __expand_port_name_or_id(_show_pcpdei_remark_map, args.port, True, use_json=JSON)
            else :
                __expand_port_name_or_id(_show_pcpdei_prio_map, args.port, True, use_json=JSON)
        elif args.prio_sub_cmd == 'dscp' :
            if args.remark == True:
                __expand_port_name_or_id(_show_dscp_remark_map, args.port, True, use_json=JSON)
            else :
                __expand_port_name_or_id(_show_dscp_prio_map, args.port, True, use_json=JSON)
        elif args.prio_sub_cmd == 'traffic_class':
            __expand_port_name_or_id(_show_priority_tc_map, args.port, True, use_json=JSON)
        elif args.prio_sub_cmd == 'ieee':
            ret = _show_priority_ieee_map(use_json=JSON)
            if JSON:
                _print_json_output(ret)
            
    if hasattr(args, 'buffer_sub_cmd'):
        if args.buffer_sub_cmd == 'mc_aware' :
            __expand_port_name_or_id(_show_mc_aware, args.port, True, use_json=JSON)
        if args.buffer_sub_cmd == 'free':
            ret = _show_free_buffer_counters(use_json=JSON)
            if JSON:
                _print_json_output(ret)
        elif args.buffer_sub_cmd == 'pool':
            if hasattr(args, 'buffer_type') :
                if args.buffer_type == 'limits' :
                    ret = _show_pool_buffer_limits(use_json=JSON)
                    if JSON:
                        _print_json_output(ret)
                if args.buffer_type == 'counters' :
                    if args.clear:
                        _clear_pool_buffer_counters(use_json=JSON)
                    else:
                        _show_pool_buffer_counters(args.cells, use_json=JSON)
        elif args.buffer_sub_cmd == 'port_reserved':
            if hasattr(args, 'buffer_type') :
                if args.buffer_type == 'limits' :
                    __expand_port_name_or_id(_show_port_reserved_buffer_limits, args.port, True, use_json=JSON)
                if args.buffer_type == 'counters' :
                    if args.clear:
                        __expand_port_name_or_id(_clear_port_buffer_counters, args.port, True, use_json=JSON)
                        _clear_port_buffer_counters(None, SX_MC_PORT_LOG_ID, use_json=JSON)
                    else:
                        _port_buff_cnt = _show_port_buffer_counters_name_or_id(port_name_or_id=args.port, use_json=JSON)
                        _mc_port_buff_cnt = _show_port_buffer_counters(None, SX_MC_PORT_LOG_ID, use_json=JSON)
                        if _mc_port_buff_cnt:
                            _port_buff_cnt.append(_mc_port_buff_cnt)
                        if JSON:
                            _print_json_output(_port_buff_cnt)

        elif args.buffer_sub_cmd == 'port_shared':
            if hasattr(args, 'buffer_type') :
                if args.buffer_type == 'limits' :
                    __expand_port_name_or_id(_show_port_shared_buffer_limits, args.port, True, use_json=JSON)
                if args.buffer_type == 'counters' :
                    if args.clear:
                        __expand_port_name_or_id(_clear_port_buffer_counters, args.port, True, use_json=JSON)
                        _clear_port_buffer_counters(None, SX_MC_PORT_LOG_ID, use_json=JSON)
                    else:
                        _port_buff_cnt = _show_port_buffer_counters_name_or_id(port_name_or_id=args.port, use_json=JSON)
                        _mc_port_buff_cnt = _show_port_buffer_counters(None, SX_MC_PORT_LOG_ID, use_json=JSON)
                        if _mc_port_buff_cnt:
                            _port_buff_cnt.append(_mc_port_buff_cnt)
                        if JSON:
                            _print_json_output(_port_buff_cnt)

    if hasattr(args, 'qos_sub_cmd'):
        try:
            if args.qos_sub_cmd == 'mapping':
                _show_qos_mapping(args.ingress_port, args.egress_port, use_json=JSON)
            if args.qos_sub_cmd == 'redecn' :
                if args.ingress_port or args.egress_port:
                    if JSON:
                        _print_json_output({'exception': 'invalidInputPortParam'})
                    else:
                        print "--ingress_port or --egress_port not required as input param"
                    return
                if args.port:
                    __expand_port_name_or_id(_show_qos_port_redecn_config, args.port, True, use_json=JSON)
                else:
                    if JSON:
                        _print_json_output({'exception': 'inputPortParamRequired'})
                    else:
                        print "--port is required param for dumping redecn config"
            if args.qos_sub_cmd == 'counters' :
                if args.clear:
                    _clear_qos_port_counters(args.port, args.ingress_port, args.egress_port, use_json=JSON)
                else:
                    if args.port:
                        __expand_port_name_or_id(_show_qos_port_counters, args.port, True, use_json=JSON, params={'ingress_port': args.ingress_port, 'egress_port': args.egress_port})
                    else:
                        ret = _show_qos_port_counters(None, None, use_json=JSON, params={'ingress_port': args.ingress_port, 'egress_port': args.egress_port})
                        if JSON:
                            _print_json_output(ret)

            if args.qos_sub_cmd == 'config' :
                if hasattr(args, 'qos_config_type'):
                    if args.qos_config_type == 'reload':
                        if args.ingress_port or args.egress_port or args.port:
                            if JSON:
                                _print_json_output({'exception': 'invalidInputPortParam'})
                            else:
                                print "input port param is not required input for this command"
                            return False
                        ret,msg = _traffic_fuse_node_reload(use_json=JSON)
                        if ret:
                            if JSON:
                                _print_json_output({'result': 'success'})
                            else:
                                print "Traffic fuse node reload successful"
                        else:
                            if JSON:
                                _print_json_output({'exception': msg, 'result': 'failed'})
                            else:
                                print "Traffic fuse node reload failed.\n msg:{}".format(msg)
                        return ret
                    else:
                        if JSON:
                            _print_json_output({'exception': 'invalidInputQoSConfigType'})
                        else:
                            print "Invalid QoS config type mlxcmd"
                else:
                    if JSON:
                        _print_json_output({'exception': 'invalidInputQoSConfig'})
                    else:
                        print "Invalid QoS config mlxcmd"

        except ingressEgressIdentical:
            if JSON:
                _print_json_output({'exception': 'ingressEgressIdentical'})
            else:
                print "Ingresss and egress ports cannot be identical"

    if hasattr(args, 'roce_sub_cmd'):
        try:
            if args.roce_sub_cmd == 'counters':
                __expand_port_name_or_id(_show_roce_counters, args.port, True, use_json=JSON, \
                                         params={'clear': args.clear or args.read_clear, 'show_output': not args.clear, 'cells': args.cells})
            elif args.roce_sub_cmd == 'status' and (args.clear == 0 and args.read_clear == 0):
                if args.system:
                    _show_roce_status_system(args.cells,use_json=JSON)
                else:
                    __expand_port_name_or_id(_show_roce_status, args.port, True, use_json=JSON)
            elif args.roce_sub_cmd == 'status' and args.clear == 1:
                if JSON:
                    _print_json_output({'exception': 'syntaxError'})
                else:
                    print "mlxcmd roce: error: argument --clear: not allowed with argument status"
            elif args.roce_sub_cmd == 'status' and args.read_clear == 1:
                if JSON:
                    _print_json_output({'exception': 'syntaxError'})
                else:
                    print "mlxcmd roce: error: argument --read_clear: not allowed with argument status"
        except noRoce:
            if JSON:
                _print_json_output({'exception': 'noRoce'})
            else:
                print "RoCE is not configured"

    if hasattr(args, 'show_port_counters_port_name'):
        _show_port_counters_name_or_id(port_name_or_id=args.show_port_counters_port_name, use_json=JSON)

    if hasattr(args, 'show_port_buffers'):
        _show_port_buffers(args.show_port_buffers, use_json=JSON)

    if hasattr(args, 'show_port_discards_port_name'):
        _show_port_discards_name_or_id(port_name_or_id=args.show_port_discards_port_name, use_json=JSON)

    if hasattr(args, 'show_port_pkt_dist_port_name'):
        _show_port_pkt_size_counters_name_or_id(port_name_or_id=args.show_port_pkt_dist_port_name, use_json=JSON)

    if hasattr(args, 'clear_port_id'):
        grp_type = args.clear_cntr_grp_type
        __expand_port_name_or_id(_clear_port_counters, args.clear_port_id, True, use_json=JSON, params={'group_type': grp_type})

    if hasattr(args, 'vlan_swids_list'):
        _show_vlan_ids(swid_list=args.vlan_swids_list,
                       use_json=JSON)

    if hasattr(args, 'swid_vlan_ports') and \
       hasattr(args, 'vids_vlan_ports'):
        _show_vlan_ports(swid=args.swid_vlan_ports,
                         vids=args.vids_vlan_ports,
                         use_json=JSON)

    if hasattr(args, 'port_swids_list'):
        _show_port_ids(swid_list=args.port_swids_list, use_json=JSON)

    if hasattr(args, 'show_port_isolate_swids'):
        _show_port_isolate(swid_list=args.show_port_isolate_swids, use_json=JSON)

    if hasattr(args, 'isolate_portid') and \
       hasattr(args, 'isolate_port_list'):
        _set_port_isolate(portid=args.isolate_portid, 
                          iso_port_list=args.isolate_port_list, use_json=JSON)

    if hasattr(args, 'set_port_priority_rewrite_port'):
        _set_port_priority_rewrite(portid=args.set_port_priority_rewrite_port,
                                   dscp=args.set_port_priority_rewrite_dscp,
                                   pcpdei=args.set_port_priority_rewrite_pcpdei,
                                   exp=args.set_port_priority_rewrite_exp)

    if hasattr(args, 'set_port_dscp_remark_port_name') :
        _set_port_dscp_remark(portid=args.set_port_dscp_remark_port_name,
                              priority=args.set_port_dscp_remark_priority,
                              color=args.set_port_dscp_remark_color,
                              dscp=args.set_port_dscp_remark_dscp)

    if hasattr(args, 'show_port_sflow_port_name'):
        _show_port_sflow_name_or_id(port_name_or_id=args.show_port_sflow_port_name, use_json=JSON)

    if hasattr(args, 'show_port_sflow_stats_port_name'):
        _show_port_sflow_stats_name_or_id(port_name_or_id=args.show_port_sflow_stats_port_name, use_json=JSON)

    if hasattr(args, 'set_port_sflow_port_name') and \
       hasattr(args, 'set_port_sflow_ing_rate') and \
       hasattr(args, 'set_port_sflow_egr_rate'):
        _set_port_sflow(port_name_or_id=args.set_port_sflow_port_name, 
                        ing_rate=args.set_port_sflow_ing_rate,
                        egr_rate=args.set_port_sflow_egr_rate, use_json=JSON)

    if hasattr(args, 'port_info_swids'):
        _ports_info(swid_list=args.port_info_swids, use_json=JSON)

    if hasattr(args, 'traps_clear_sub_cmd'):
        if args.traps_clear_sub_cmd == 'stats':
            _clear_trap_stats(use_json=JSON)

    if hasattr(args, 'traps_show_sub_cmd'):
        if args.traps_show_sub_cmd == 'stats':
            _show_trap_stats(use_json=JSON)

        if args.traps_show_sub_cmd == 'group-stats':
            _show_trap_group_stats(use_json=JSON)

        
    # Close the connection
    mlx_close_connection()

if __name__ == '__main__':
    ret = mlxcmd_main()
    if ret is not None:
        # Need this for NCLU to support calling mlxcmd
        if ret == True:
            sys.exit(0)
        else:
            sys.exit(1)
