#!/usr/bin/env python
# Copyright 2016 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
from pprint import pprint
from collections import OrderedDict

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 SX_MC_PORT_LOG_ID

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_parser_length
from cumulus.mlx import mlx_get_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_get_port_pkt_size_counters
from cumulus.mlx import mlx_get_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_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
import cumulus.porttab

def get_sdk_to_linux():
    sdk_to_linux = {}
    pt = cumulus.porttab.porttab(use_hw=False)
    for p in pt.get_linux_ports():
        sdk_to_linux[pt.linux2mlx(p)] = p
    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 _show_interface_table(use_json=False) :
    data = mlx_get_interface()
    if use_json:
        pprint(json.dumps(data), indent=1)
    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() :
            pprint(json.dumps(rt), indent=1)
    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() :
            pprint(json.dumps(rt), indent=1)
    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() :
            pprint(json.dumps(nt), indent=1)
    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:
        pprint(json.dumps(fdb), indent=1)
    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:
        pprint(json.dumps(fdb), indent=1)
    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:
        pprint(json.dump(age, strean=screen, indent=1))
    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:
        pprint(json.dumps(vlan_id_in_use), indent=1)
    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:
        pprint(json.dumps(vports), indent=1)
    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:
        pprint(json.dumps(vlan_port_map), indent=1)
    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):
    port_list = _get_port_list_from_name_or_id(port_name_or_id, wc_name_allowed)
    sdk_to_linux = get_sdk_to_linux()
    for portid in port_list:
        port_id_cb(sdk_to_linux, portid, use_json)

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

    if use_json:
        pprint(json.dumps(counter_info), indent=1)
    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:
        pprint(json.dumps(counter_info), indent=1)
    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(portid, use_json=False, group_type=63):
    mlx_clear_port_counters(portid, group_type=group_type)

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

    if use_json:
        pprint(json.dumps(discard_info), indent=1)
    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 _show_port_buffer_counters(portid, use_json=False):
    counter_info = mlx_get_port_buffer_counters(portid)

    if use_json:
        pprint(json.dumps(counter_info), indent=1)
    else:
        print "Reserved + shared buffer counters for port 0x%x" % portid
        print 'items: %d' % len(counter_info['counter_list'])
        for item in counter_info['counter_list'] :
            space = '\t'
            print item['type'],
            print '[%d]:' % item['index'],
            print space,
            print item['current'],
            print 'watermark',
            print item['watermark']

def _show_port_shared_buffer_limits(portid, use_json=False):
    limit_list = mlx_get_port_shared_buffer_limits(portid)

    if use_json:
        pprint(json.dumps(limit_list), indent=1)
    else:
        print "\nShared cell limit for port 0x%x" % portid
        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(portid, use_json=False):
    limit_list = mlx_get_port_reserved_buffer_limits(portid)

    if use_json:
        pprint(json.dumps(limit_list), indent=1)
    else:
        print "\nReserved cell limit for port 0x%x" % portid
        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(swid=0, use_json=False):
    buffer_info = mlx_get_pool_buffer_limits()
    if use_json:
        pprint(json.dumps(buffer_info), indent=1)
    else :
        print "\nPool buffer limits (1 cell == 96 bytes)"
        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 _show_pool_buffer_counters(swid=0, use_json=False):
    buffer_info = mlx_get_pool_buffer_counters()
    if use_json:
        pprint(json.dumps(buffer_info), indent=1)
    else :
        print "\nPool buffer occupancy counters (1 cell == 96 bytes)"
        for idx,usage_stat in buffer_info.items() :
            print '%s Pool %d' % (usage_stat['type'], usage_stat['id']),
            space = '\t'
            print 'current',
            print usage_stat['current'],
            print ', watermark',
            print usage_stat['watermark']

def _show_free_buffer_counters(swid=0, use_json=False):
    buffer_info = mlx_get_free_buffer_counters()
    if use_json:
        pprint(json.dumps(buffer_info), indent=1)
    else :
        print "\nUnallocated packet buffer cells (1 cell == 96 bytes)"
        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_parser_length(use_json=False):
    parser_length = mlx_get_parser_length()
    if use_json:
        pprint(json.dumps(parser_length), indent=1)
    else :
        print 'Parser length = %d' % parser_length

def _show_port_priority_trust(portid, use_json=False):
    trust_info = mlx_get_port_priority_trust(portid)
    if use_json:
        pprint(json.dumps(trust_info), indent=1)
    else :
        print '\nPort 0x%x priority trust configuration'
        print 'L3 (DSCP):   %s' % trust_info['dscp']
        print 'L2 (PCPDEI): %s' % trust_info['pcpdei']

def _show_priority_group_map(portid, use_json=False):
    pg_map_list = mlx_get_pg_prio_map(portid)
    if use_json:
        pprint(json.dumps(pg_map), indent=1)
    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(portid, use_json=False):
    rewrite_info = mlx_get_port_priority_rewrite(portid)
    if use_json:
        pprint(json.dumps(rewrite_info), indent=1)
    else :
        print '\nPort 0x%x priority rewrite configuration' % portid
        print 'DSCP:   %s' % rewrite_info['dscp']
        print 'PCPDEI: %s' % rewrite_info['pcpdei']
        print 'EXP:    %s' % rewrite_info['exp']

def _show_pcpdei_prio_map(portid, use_json=False):
    prio_list = mlx_get_pcpdei_prio_map(portid)
    if use_json:
        pprint(json.dumps(prio_list), indent=1)
    else :
        print '\nPort 0x%x PCPDEI packet priority to switch priority map' % portid
        for prio_item in prio_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(portid, use_json=False):
    pcpdei_list = mlx_get_pcpdei_rewrite_map(portid)
    if use_json:
        pprint(json.dumps(pcpdei_list), indent=1)
    else :
        print '\nPort 0x%x switch priority to PCPDEI packet priority remark' % portid
        for pcpdei_item in pcpdei_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(portid, use_json=False):
    prio_list = mlx_get_dscp_prio_map(portid)
    if use_json:
        pprint(json.dumps(prio_list), indent=1)
    else :
        print '\nPort 0x%x DSCP packet priority to switch priority map' % portid
        for prio_item in prio_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(portid, use_json=False):
    dscp_list = mlx_get_dscp_rewrite_map(portid)
    if use_json:
        pprint(json.dumps(dscp_list), indent=1)
    else :
        print '\nPort 0x%x switch priority to DSCP packet priority remark' % 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 _show_priority_tc_map(portid, use_json=False):
    tc_list = mlx_get_prio_tc_map(portid)
    if use_json:
        pprint(json.dumps(tc_list), indent=1)
    else :
        print '\nPort 0x%x switch priority to traffic class' % portid
        for tc_item in tc_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:
        pprint(json.dumps(ieee_list), indent=1)
    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(portid, use_json=False, verbose=False):
    element_list = mlx_get_port_scheduler(portid)
    if use_json:
        pprint(json.dumps(element_list), indent=1)
    else :
        print '\nPort 0x%x scheduler configuration' % 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'  % ('min shaper mode', element['min_shaper_mode'])

def _show_mc_aware(portid, use_json=False, verbose=False):
    mc_aware_dict = mlx_get_mc_aware(portid)
    if use_json:
        pprint(json.dumps(mc_aware_dict), indent=1)
    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 0x%x MC Aware configuration' % portid
        print 'MC aware: %s' % mc_aware_dict['mc_aware']

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

    fc_dict = mlx_get_flow_control(portid)
    if use_json:
        pprint(json.dumps(fc_dict), indent=1)
    else :
        print '\nPort 0x%x flow control configuration' % 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(portid, use_json=False, verbose=False):

    mc_logical_port = SX_MC_PORT_LOG_ID
    print 'Datapath configuration for port 0x%x and MC logical port 0x%x' % (portid, mc_logical_port)

    print '\n---- Priority mapping ----- '
    # _show_priority_group_map(portid, use_json)
    _show_port_priority_trust(portid, use_json)
    _show_pcpdei_prio_map(portid, use_json)
    _show_dscp_prio_map(portid, use_json)
    _show_port_priority_rewrite(portid, use_json)
    _show_pcpdei_remark_map(portid, use_json)
    _show_dscp_remark_map(portid, use_json)
    _show_priority_tc_map(portid, use_json)
    _show_priority_ieee_map(use_json)

    print '\n------ Flow Control ----- '
    _show_flow_control(portid, use_json)

    print '\n----- Unallocated packet buffer cells -------'
    _show_free_buffer_counters(use_json)

    print '\n----- Parser length -------'
    _show_parser_length(use_json)

    print '\n----- Allocated packet buffer cells -------'
    _show_pool_buffer_limits(use_json)
    _show_mc_aware(portid, use_json, verbose)
    _show_port_reserved_buffer_limits(portid, use_json)
    _show_port_reserved_buffer_limits(mc_logical_port, use_json)
    _show_port_shared_buffer_limits(portid, use_json)
    _show_port_shared_buffer_limits(mc_logical_port, use_json)

    print '\n ------- Scheduler Configuration ------- '
    _show_port_scheduler(portid, use_json, verbose)

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]['rif_list'] = t[eid]

    if use_json:
        pprint(json.dumps(table), indent=1)
    else:
        print "ECMP ID\t\tRIF"
        for eid in table:
            for i, rif in enumerate(table[eid]['rif_list']):
                if i == 0:
                    print "%d\t\t%d" % (eid, rif)
                else:
                    print "\t\t%d" % rif

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:
        pprint(json.dumps(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:
        pprint(json.dumps(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:
        pprint(json.dumps(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:
        pprint(json.dumps(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:
        pprint(json.dumps(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:
        pprint(json.dumps(port_id_dict), indent=1)
    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:
        pprint(json.dumps(port_iso_dict), indent=1)
    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)

def _ports_info(swid_list=[0], use_json=False):
    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)
            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)
    if use_json:
        pprint(json.dumps(port_info_dict), indent=1)
    else:
        print "Port ID\tHex Port ID\tPort\tStatus\tSpeed\tFEC"
        for portid in sorted(port_info_dict.keys()):
            print "%d\t0x%08x\t%s\t%s\%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"))

def _get_port_list_from_name_or_id(string, wc_name_allowed=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 = []

    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 string == "swp*" or string == "swp+":
        if wc_name_allowed:
            swid_list=[0]
            port_id_dict = mlx_get_port_ids(swid_list)
            sdk_to_linux = get_sdk_to_linux()

            # Add all swp ports and exclude LAGs
            for swid in port_id_dict:
                for portid in port_id_dict[swid]:
                    if sdk_to_linux.get(portid,None):
                        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:
        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)
    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:
        pprint(json.dumps(sflow_params), indent=1)
    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:
        pprint(json.dumps(sflow_statistics), indent=1)
    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 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_id', type=int, default=81152, help='logical port ID (default is 81152)')
    buffers_parser.add_argument('--swid', type=int, default=0, help='switch ID (default is 0)')

    # 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_id', type=int, default=81152, help='logical port ID (default is 81152)')

    # 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_id', type=int, default=81152, help='logical port ID (default is 81152)')

    # 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_id', type=int, default=81152, help='logical port ID (default is 81152)')

    # 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_id', type=int, default=81152, help='logical port ID (default is 81152)')
    
    # 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='<portid>', type=int)
    ports_clear.add_argument('clear_cntr_grp_type', metavar="<type of counters to clear>",
                             type=int, nargs='?', default=63)
    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=[])

    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':
            _show_port_scheduler(args.port_id, use_json=JSON, verbose=VERBOSE)

    if hasattr(args, 'fc_sub_cmd'):
        if args.fc_sub_cmd == 'show':
            _show_flow_control(args.port_id, use_json=JSON, verbose=VERBOSE)                

    if hasattr(args, 'datapath_sub_cmd'):
        _show_datapath_config(args.port_id, use_json=JSON, verbose=VERBOSE)

    if hasattr(args, 'prio_sub_cmd'):
        if args.prio_sub_cmd == 'trust':
            _show_port_priority_trust(args.port_id, use_json=JSON)
        if args.prio_sub_cmd == 'rewrite':
            _show_port_priority_rewrite(args.port_id, use_json=JSON)
        if args.prio_sub_cmd == 'priority_group':
            _show_priority_group_map(args.port_id, use_json=JSON)
        if args.prio_sub_cmd == 'pcpdei':
            if args.remark == True:
                _show_pcpdei_remark_map(args.port_id,use_json=JSON)
            else :
                _show_pcpdei_prio_map(args.port_id,use_json=JSON)
        elif args.prio_sub_cmd == 'dscp' :
            if args.remark == True:
                _show_dscp_remark_map(args.port_id,use_json=JSON)
            else :
                _show_dscp_prio_map(args.port_id,use_json=JSON)
        elif args.prio_sub_cmd == 'traffic_class':
            _show_priority_tc_map(args.port_id, use_json=JSON)
        elif args.prio_sub_cmd == 'ieee':
            _show_priority_ieee_map(use_json=JSON)
            
    if hasattr(args, 'buffer_sub_cmd'):
        if args.buffer_sub_cmd == 'mc_aware' :
            _show_mc_aware(args.port_id, use_json=JSON, verbose=VERBOSE)
        if args.buffer_sub_cmd == 'free':
            _show_free_buffer_counters(use_json=JSON)
        elif args.buffer_sub_cmd == 'pool':
            if hasattr(args, 'buffer_type') :
                if args.buffer_type == 'limits' :
                    _show_pool_buffer_limits(use_json=JSON)
                if args.buffer_type == 'counters' :
                    _show_pool_buffer_counters(use_json=JSON)
        elif args.buffer_sub_cmd == 'port_reserved':
            if hasattr(args, 'buffer_type') :
                if args.buffer_type == 'limits' :
                    _show_port_reserved_buffer_limits(args.port_id, use_json=JSON)
                if args.buffer_type == 'counters' :
                    _show_port_buffer_counters(args.port_id, use_json=JSON)
        elif args.buffer_sub_cmd == 'port_shared':
            if hasattr(args, 'buffer_type') :
                if args.buffer_type == 'limits' :
                    _show_port_shared_buffer_limits(args.port_id, use_json=JSON)
                if args.buffer_type == 'counters' :
                    _show_port_buffer_counters(args.port_id, use_json=JSON)

    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
        _clear_port_counters(args.clear_port_id, use_json=JSON, 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)

    # Close the connection
    mlx_close_connection()

if __name__ == '__main__':
    mlxcmd_main()
