diff --git a/scripts/fabricstat b/scripts/fabricstat new file mode 100755 index 0000000000..18200785ff --- /dev/null +++ b/scripts/fabricstat @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 + +import argparse +from collections import OrderedDict, namedtuple +import os +import sys + +from utilities_common import constants +from natsort import natsorted +from tabulate import tabulate +from sonic_py_common import multi_asic +from swsscommon.swsscommon import APP_FABRIC_PORT_TABLE_NAME, COUNTERS_TABLE, COUNTERS_FABRIC_PORT_NAME_MAP, COUNTERS_FABRIC_QUEUE_NAME_MAP +import utilities_common.multi_asic as multi_asic_util + +# mock the redis for unit test purposes # +try: + if os.environ["UTILITIES_UNIT_TESTING"] == "2": + modules_path = os.path.join(os.path.dirname(__file__), "..") + tests_path = os.path.join(modules_path, "tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, tests_path) + import mock_tables.dbconnector + if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic": + import mock_tables.mock_multi_asic + mock_tables.dbconnector.load_namespace_config() +except KeyError: + pass + +PORT_NAME_PREFIX = 'PORT' +COUNTER_TABLE_PREFIX = COUNTERS_TABLE+":" +FABRIC_PORT_STATUS_TABLE_PREFIX = APP_FABRIC_PORT_TABLE_NAME+"|" +FABRIC_PORT_STATUS_FIELD = "STATUS" +STATUS_NA = 'N/A' + +class FabricStat(object): + def __init__(self, namespace): + self.db = None + self.namespace = namespace + self.multi_asic = multi_asic_util.MultiAsic(constants.DISPLAY_ALL, namespace) + + def get_cnstat_dict(self): + self.cnstat_dict = OrderedDict() + self.collect_stat() + return self.cnstat_dict + + @multi_asic_util.run_on_multi_asic + def collect_stat(self): + """ + Collect the statisitics from all the asics present on the + device and store in a dict + """ + self.cnstat_dict.update(self.get_cnstat()) + + def get_port_state(self, port_name): + """ + Get the port state + """ + full_table_id = FABRIC_PORT_STATUS_TABLE_PREFIX + port_name + oper_state = self.db.get(self.db.STATE_DB, full_table_id, FABRIC_PORT_STATUS_FIELD) + if oper_state is not None: + return oper_state + return STATUS_NA + + def get_counters(self, counter_bucket_dict, table_id): + fields = ["0"] * len(counter_bucket_dict) + for pos, counter_name in counter_bucket_dict.items(): + full_table_id = COUNTER_TABLE_PREFIX + table_id + counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, counter_name) + if counter_data is None: + fields[pos] = STATUS_NA + elif fields[pos] != STATUS_NA: + fields[pos] = str(int(fields[pos]) + int(counter_data)) + return fields + + def get_cnstat(self): + """ + Get the counters info from database. + """ + assert False, 'Need to override this method' + + def cnstat_print(self, cnstat_dict, errors_only=False): + """ + Print the counter stat. + """ + assert False, 'Need to override this method' + +PortStat = namedtuple("PortStat", "in_cell, in_octet, out_cell, out_octet,\ + crc, fec_correctable, fec_uncorrectable, symbol_err") +port_counter_bucket_list = [ + 'SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS', + 'SAI_PORT_STAT_IF_IN_OCTETS', + 'SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS', + 'SAI_PORT_STAT_IF_OUT_OCTETS', + 'SAI_PORT_STAT_IF_IN_ERRORS', + 'SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES', + 'SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES', + 'SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS', + ] +port_counter_bucket_dict = {k : v for k, v in enumerate(port_counter_bucket_list)} + +portstat_header_all = ['ASIC', 'PORT', 'STATE', + 'IN_CELL', 'IN_OCTET', 'OUT_CELL', 'OUT_OCTET', + 'CRC', 'FEC_CORRECTABLE', 'FEC_UNCORRECTABLE', 'SYMBOL_ERR'] +portstat_header_errors_only = ['ASIC', 'PORT', 'STATE', + 'CRC', 'FEC_CORRECTABLE', 'FEC_UNCORRECTABLE', 'SYMBOL_ERR'] + +class FabricPortStat(FabricStat): + def get_cnstat(self): + counter_port_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_FABRIC_PORT_NAME_MAP) + cnstat_dict = OrderedDict() + if counter_port_name_map is None: + return cnstat_dict + for port_name in natsorted(counter_port_name_map): + cntr = self.get_counters(port_counter_bucket_dict, counter_port_name_map[port_name]) + cnstat_dict[port_name] = PortStat._make(cntr) + return cnstat_dict + + def cnstat_print(self, cnstat_dict, errors_only=False): + if len(cnstat_dict) == 0: + print("Counters %s empty" % self.namespace) + return + + table = [] + header = None + asic = multi_asic.get_asic_id_from_name(self.namespace) + for key, data in cnstat_dict.items(): + port_id = key[len(PORT_NAME_PREFIX):] + if errors_only: + header = portstat_header_errors_only + table.append((asic, port_id, self.get_port_state(key), + data.crc, data.fec_correctable, data.fec_uncorrectable, + data.symbol_err)) + else: + header = portstat_header_all + table.append((asic, port_id, self.get_port_state(key), + data.in_cell, data.in_octet, data.out_cell, data.out_octet, + data.crc, data.fec_correctable, data.fec_uncorrectable, + data.symbol_err)) + + print(tabulate(table, header, tablefmt='simple', stralign='right')) + print() + +QueueStat = namedtuple("QueueStat", "curlevel, watermarklevel, curbyte") + +queue_counter_bucket_list = [ + 'SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL', + 'SAI_QUEUE_STAT_WATERMARK_LEVEL', + 'SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES', +] +queue_counter_bucket_dict = {k : v for k, v in enumerate(queue_counter_bucket_list)} + +queuestat_header = ['ASIC', 'PORT', 'STATE', 'QUEUE_ID', 'CURRENT_BYTE', 'CURRENT_LEVEL', 'WATERMARK_LEVEL'] + +class FabricQueueStat(FabricStat): + def get_cnstat(self): + counter_queue_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_FABRIC_QUEUE_NAME_MAP) + cnstat_dict = OrderedDict() + if counter_queue_name_map is None: + return cnstat_dict + for port_queue_name in natsorted(counter_queue_name_map): + cntr = self.get_counters(queue_counter_bucket_dict, counter_queue_name_map[port_queue_name]) + cnstat_dict[port_queue_name] = QueueStat._make(cntr) + return cnstat_dict + + def cnstat_print(self, cnstat_dict, errors_only=False): + if len(cnstat_dict) == 0: + print("Counters %s empty" % self.namespace) + return + + table = [] + asic = multi_asic.get_asic_id_from_name(self.namespace) + for key, data in cnstat_dict.items(): + port_name, queue_id = key.split(':') + port_id = port_name[len(PORT_NAME_PREFIX):] + table.append((asic, port_id, self.get_port_state(port_name), queue_id, + data.curbyte, data.curlevel, data.watermarklevel)) + + print(tabulate(table, queuestat_header, tablefmt='simple', stralign='right')) + print() + +def main(): + parser = argparse.ArgumentParser(description='Display the fabric port state and counters', + formatter_class=argparse.RawTextHelpFormatter, + epilog=""" +Examples: + fabricstat + fabricstat --namespace asic0 + fabricstat -p -n asic0 -e + fabricstat -q + fabricstat -q -n asic0 +""") + + parser.add_argument('-q','--queue', action='store_true', help='Display fabric queue stat, otherwise port stat') + parser.add_argument('-n','--namespace', default=None, help='Display fabric ports counters for specific namespace') + parser.add_argument('-e', '--errors', action='store_true', help='Display errors') + + args = parser.parse_args() + queue = args.queue + namespace = args.namespace + errors_only = args.errors + + def nsStat(ns, errors_only): + stat = FabricQueueStat(ns) if queue else FabricPortStat(ns) + cnstat_dict = stat.get_cnstat_dict() + stat.cnstat_print(cnstat_dict, errors_only) + + if namespace is None: + # All asics or all fabric asics + multi_asic = multi_asic_util.MultiAsic() + for ns in multi_asic.get_ns_list_based_on_options(): + nsStat(ns, errors_only) + else: + # Asic with namespace + nsStat(namespace, errors_only) + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 7f617905da..c8f7ceff7c 100644 --- a/setup.py +++ b/setup.py @@ -97,6 +97,7 @@ 'scripts/dropstat', 'scripts/dump_nat_entries.py', 'scripts/ecnconfig', + 'scripts/fabricstat', 'scripts/fanshow', 'scripts/fast-reboot', 'scripts/fast-reboot-dump.py', diff --git a/show/fabric.py b/show/fabric.py new file mode 100644 index 0000000000..8dfbc50f7a --- /dev/null +++ b/show/fabric.py @@ -0,0 +1,35 @@ +import click + +import utilities_common.multi_asic as multi_asic_util +import utilities_common.cli as clicommon + +@click.group(cls=clicommon.AliasedGroup) +def fabric(): + """Show fabric information""" + pass + +@fabric.group(invoke_without_command=True) +def counters(): + """Show fabric port counters""" + pass + +@counters.command() +@multi_asic_util.multi_asic_click_option_namespace +@click.option('-e', '--errors', is_flag=True) +def port(namespace, errors): + """Show fabric port stat""" + cmd = "fabricstat" + if namespace is not None: + cmd += " -n {}".format(namespace) + if errors: + cmd += " -e" + clicommon.run_command(cmd) + +@counters.command() +@multi_asic_util.multi_asic_click_option_namespace +def queue(namespace): + """Show fabric queue stat""" + cmd = "fabricstat -q" + if namespace is not None: + cmd += " -n {}".format(namespace) + clicommon.run_command(cmd) diff --git a/show/main.py b/show/main.py index 9c07d92080..ff49334597 100755 --- a/show/main.py +++ b/show/main.py @@ -41,6 +41,7 @@ from . import bgp_common from . import chassis_modules from . import dropcounters +from . import fabric from . import feature from . import fgnhg from . import flow_counters @@ -263,6 +264,7 @@ def cli(ctx): cli.add_command(acl.acl) cli.add_command(chassis_modules.chassis) cli.add_command(dropcounters.dropcounters) +cli.add_command(fabric.fabric) cli.add_command(feature.feature) cli.add_command(fgnhg.fgnhg) cli.add_command(flow_counters.flowcnt_route) diff --git a/tests/fabricstat_test.py b/tests/fabricstat_test.py new file mode 100644 index 0000000000..23bb37d2ed --- /dev/null +++ b/tests/fabricstat_test.py @@ -0,0 +1,142 @@ +import os +import shutil + +from click.testing import CliRunner + +import clear.main as clear +import show.main as show +from .utils import get_result_and_return_code + +root_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(root_path) +scripts_path = os.path.join(modules_path, "scripts") + +multi_asic_fabric_counters = """\ + ASIC PORT STATE IN_CELL IN_OCTET OUT_CELL OUT_OCTET CRC FEC_CORRECTABLE FEC_UNCORRECTABLE SYMBOL_ERR +------ ------ ------- --------- ---------- ---------- ----------- ----- ----------------- ------------------- ------------ + 0 0 up 6 1113 0 0 0 5 1759692040 5 + 0 1 down 0 0 0 0 0 0 58977677898 0 + 0 2 up 2 371 0 0 0 0 1769448760 0 + 0 3 down 0 0 0 0 0 0 58976477608 0 + 0 4 up 10 1855 0 0 0 73 1763293100 73 + 0 5 down 0 0 0 0 0 44196 58975150569 0 + 0 6 up 4 742 0 0 0 10 1763174090 0 + 0 7 up 10 1855 0 0 0 187 1768439529 1331 + + ASIC PORT STATE IN_CELL IN_OCTET OUT_CELL OUT_OCTET CRC FEC_CORRECTABLE FEC_UNCORRECTABLE SYMBOL_ERR +------ ------ ------- --------- ---------- ---------- ----------- ----- ----------------- ------------------- ------------ + 1 0 up 16 2968 0 0 0 0 1763890500 0 + 1 1 down 0 0 0 0 0 0 105269481425 0 + 1 2 down 0 0 0 0 0 0 105268895944 0 + 1 3 down 0 0 0 0 0 0 105268290607 0 + 1 4 up 14 2597 0 0 0 0 1762188940 0 + 1 5 down 0 0 0 0 0 968 105267020477 0 + 1 6 down 0 0 0 0 0 53192703023 1422986 41913682074 + 1 7 down 0 0 0 0 0 0 105264567398 0 + +""" +multi_asic_fabric_counters_asic0 = """\ + ASIC PORT STATE IN_CELL IN_OCTET OUT_CELL OUT_OCTET CRC FEC_CORRECTABLE FEC_UNCORRECTABLE SYMBOL_ERR +------ ------ ------- --------- ---------- ---------- ----------- ----- ----------------- ------------------- ------------ + 0 0 up 6 1113 0 0 0 5 1759692040 5 + 0 1 down 0 0 0 0 0 0 58977677898 0 + 0 2 up 2 371 0 0 0 0 1769448760 0 + 0 3 down 0 0 0 0 0 0 58976477608 0 + 0 4 up 10 1855 0 0 0 73 1763293100 73 + 0 5 down 0 0 0 0 0 44196 58975150569 0 + 0 6 up 4 742 0 0 0 10 1763174090 0 + 0 7 up 10 1855 0 0 0 187 1768439529 1331 + +""" + +fabric_invalid_asic_error = """ValueError: Unknown Namespace asic99""" + +multi_asic_fabric_counters_queue = """\ + ASIC PORT STATE QUEUE_ID CURRENT_BYTE CURRENT_LEVEL WATERMARK_LEVEL +------ ------ ------- ---------- -------------- --------------- ----------------- + 0 0 up 0 763 12 20 + 0 1 down 0 0 0 0 + 0 2 up 0 104 8 8 + 0 3 down 0 0 0 0 + 0 4 up 0 1147 14 22 + 0 5 down 0 0 0 0 + 0 6 up 0 527 8 10 + 0 7 up 0 1147 14 17 + + ASIC PORT STATE QUEUE_ID CURRENT_BYTE CURRENT_LEVEL WATERMARK_LEVEL +------ ------ ------- ---------- -------------- --------------- ----------------- + 1 0 up 0 1942 18 24 + 1 1 down 0 0 0 0 + 1 2 down 0 0 0 0 + 1 3 down 0 0 0 0 + 1 4 up 0 1362 15 24 + 1 5 down 0 0 0 0 + 1 6 down 0 0 0 0 + 1 7 down 0 0 0 0 + +""" + +multi_asic_fabric_counters_queue_asic0 = """\ + ASIC PORT STATE QUEUE_ID CURRENT_BYTE CURRENT_LEVEL WATERMARK_LEVEL +------ ------ ------- ---------- -------------- --------------- ----------------- + 0 0 up 0 763 12 20 + 0 1 down 0 0 0 0 + 0 2 up 0 104 8 8 + 0 3 down 0 0 0 0 + 0 4 up 0 1147 14 22 + 0 5 down 0 0 0 0 + 0 6 up 0 527 8 10 + 0 7 up 0 1147 14 17 + +""" + +class TestMultiAsicFabricStat(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "2" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" + + def test_multi_show_fabric_counters(self): + return_code, result = get_result_and_return_code('fabricstat') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_fabric_counters + + def test_multi_show_fabric_counters_asic(self): + return_code, result = get_result_and_return_code('fabricstat -n asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_fabric_counters_asic0 + + def test_multi_asic_invalid_asic(self): + return_code, result = get_result_and_return_code('fabricstat -n asic99') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 1 + assert result == fabric_invalid_asic_error + + def test_multi_show_fabric_counters_queue(self): + return_code, result = get_result_and_return_code('fabricstat -q') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_fabric_counters_queue + + def test_multi_show_fabric_counters_queue_asic(self): + return_code, result = get_result_and_return_code('fabricstat -q -n asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_fabric_counters_queue_asic0 + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join( + os.environ["PATH"].split(os.pathsep)[:-1]) + os.environ["UTILITIES_UNIT_TESTING"] = "0" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" diff --git a/tests/mock_tables/asic0/counters_db.json b/tests/mock_tables/asic0/counters_db.json index 5c144393f2..2e26810929 100644 --- a/tests/mock_tables/asic0/counters_db.json +++ b/tests/mock_tables/asic0/counters_db.json @@ -1693,6 +1693,146 @@ "Ethernet-BP4:14": "oid:0x1000000004014", "Ethernet-BP4:15": "oid:0x1000000004015" }, + "COUNTERS_FABRIC_PORT_NAME_MAP" : { + "PORT0": "oid:0x1000000000143", + "PORT1": "oid:0x1000000000144", + "PORT2": "oid:0x1000000000145", + "PORT3": "oid:0x1000000000146", + "PORT4": "oid:0x1000000000147", + "PORT5": "oid:0x1000000000148", + "PORT6": "oid:0x1000000000149", + "PORT7": "oid:0x100000000014a" + }, + "COUNTERS:oid:0x1000000000143": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "1113", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "6", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "5", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1759692040", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "5" + }, + "COUNTERS:oid:0x1000000000144": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "58977677898", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000145": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "371", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "2", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1769448760", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000146": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "58976477608", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000147": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "1855", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "10", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "73", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1763293100", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "73" + }, + "COUNTERS:oid:0x1000000000148": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "44196", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "58975150569", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000149": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "742", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "4", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "10", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1763174090", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x100000000014a": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "1855", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "10", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "187", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1768439529", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "1331" + }, + "COUNTERS_FABRIC_QUEUE_NAME_MAP" : { + "PORT0:0": "oid:0x15000000000186", + "PORT1:0": "oid:0x15000000000187", + "PORT2:0": "oid:0x15000000000188", + "PORT3:0": "oid:0x15000000000189", + "PORT4:0": "oid:0x1500000000018a", + "PORT5:0": "oid:0x1500000000018b", + "PORT6:0": "oid:0x1500000000018c", + "PORT7:0": "oid:0x1500000000018d" + }, + "COUNTERS:oid:0x15000000000186": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "20", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "763", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "12" + }, + "COUNTERS:oid:0x15000000000187": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x15000000000188": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "8", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "104", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "8" + }, + "COUNTERS:oid:0x15000000000189": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x1500000000018a": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "22", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "1147", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "14" + }, + "COUNTERS:oid:0x1500000000018b": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x1500000000018c": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "10", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "527", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "8" + }, + "COUNTERS:oid:0x1500000000018d": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "17", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "1147", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "14" + }, "COUNTERS_DEBUG_NAME_PORT_STAT_MAP": { "DEBUG_0": "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE", "DEBUG_2": "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS" diff --git a/tests/mock_tables/asic0/state_db.json b/tests/mock_tables/asic0/state_db.json index 97fbb3d33c..8766f43d65 100644 --- a/tests/mock_tables/asic0/state_db.json +++ b/tests/mock_tables/asic0/state_db.json @@ -213,5 +213,39 @@ }, "MUX_CABLE_TABLE|Ethernet0": { "state": "active" + }, + "FABRIC_PORT_TABLE|PORT0" : { + "STATUS": "up", + "REMOTE_MOD": "0", + "REMOTE_PORT": "79" + }, + "FABRIC_PORT_TABLE|PORT1" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT2" : { + "STATUS": "up", + "REMOTE_MOD": "0", + "REMOTE_PORT": "94" + }, + "FABRIC_PORT_TABLE|PORT3" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT4" : { + "STATUS": "up", + "REMOTE_MOD": "0", + "REMOTE_PORT": "85" + }, + "FABRIC_PORT_TABLE|PORT5" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT6" : { + "STATUS": "up", + "REMOTE_MOD": "0", + "REMOTE_PORT": "84" + }, + "FABRIC_PORT_TABLE|PORT7" : { + "STATUS": "up", + "REMOTE_MOD": "0", + "REMOTE_PORT": "93" } } diff --git a/tests/mock_tables/asic1/counters_db.json b/tests/mock_tables/asic1/counters_db.json index aed3b22b58..c364d8599e 100644 --- a/tests/mock_tables/asic1/counters_db.json +++ b/tests/mock_tables/asic1/counters_db.json @@ -888,6 +888,146 @@ "PFC_WD_QUEUE_STATS_RX_PACKETS_LAST": "8343", "PFC_WD_QUEUE_STATS_RX_DROPPED_PACKETS_LAST": "72" }, + "COUNTERS_FABRIC_PORT_NAME_MAP" : { + "PORT0": "oid:0x1000000000143", + "PORT1": "oid:0x1000000000144", + "PORT2": "oid:0x1000000000145", + "PORT3": "oid:0x1000000000146", + "PORT4": "oid:0x1000000000147", + "PORT5": "oid:0x1000000000148", + "PORT6": "oid:0x1000000000149", + "PORT7": "oid:0x100000000014a" + }, + "COUNTERS:oid:0x1000000000143": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "2968", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "16", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1763890500", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000144": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "105269481425", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000145": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "105268895944", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000146": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "105268290607", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000147": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "2597", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "14", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1762188940", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000148": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "968", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "105267020477", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS:oid:0x1000000000149": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "53192703023", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1422986", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "41913682074" + }, + "COUNTERS:oid:0x100000000014a": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "105264567398", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0" + }, + "COUNTERS_FABRIC_QUEUE_NAME_MAP" : { + "PORT0:0": "oid:0x15000000000186", + "PORT1:0": "oid:0x15000000000187", + "PORT2:0": "oid:0x15000000000188", + "PORT3:0": "oid:0x15000000000189", + "PORT4:0": "oid:0x1500000000018a", + "PORT5:0": "oid:0x1500000000018b", + "PORT6:0": "oid:0x1500000000018c", + "PORT7:0": "oid:0x1500000000018d" + }, + "COUNTERS:oid:0x15000000000186": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "24", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "1942", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "18" + }, + "COUNTERS:oid:0x15000000000187": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x15000000000188": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x15000000000189": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x1500000000018a": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "24", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "1362", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "15" + }, + "COUNTERS:oid:0x1500000000018b": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x1500000000018c": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, + "COUNTERS:oid:0x1500000000018d": { + "SAI_QUEUE_STAT_WATERMARK_LEVEL": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL": "0" + }, "COUNTERS_DEBUG_NAME_PORT_STAT_MAP": { "DEBUG_0": "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE", "DEBUG_2": "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS" diff --git a/tests/mock_tables/asic1/state_db.json b/tests/mock_tables/asic1/state_db.json index 354f66f708..f288bc1a6c 100644 --- a/tests/mock_tables/asic1/state_db.json +++ b/tests/mock_tables/asic1/state_db.json @@ -213,5 +213,33 @@ }, "MUX_CABLE_TABLE|Ethernet0": { "state": "active" + }, + "FABRIC_PORT_TABLE|PORT0" : { + "STATUS": "up", + "REMOTE_MOD": "0", + "REMOTE_PORT": "69" + }, + "FABRIC_PORT_TABLE|PORT1" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT2" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT3" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT4" : { + "STATUS": "up", + "REMOTE_MOD": "0", + "REMOTE_PORT": "75" + }, + "FABRIC_PORT_TABLE|PORT5" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT6" : { + "STATUS": "down" + }, + "FABRIC_PORT_TABLE|PORT7" : { + "STATUS": "down" } } diff --git a/utilities_common/multi_asic.py b/utilities_common/multi_asic.py index 7e704befe7..9e213f67f1 100644 --- a/utilities_common/multi_asic.py +++ b/utilities_common/multi_asic.py @@ -96,19 +96,21 @@ def multi_asic_display_default_option(): return constants.DISPLAY_EXTERNAL +_multi_asic_click_option_display = click.option('--display', + '-d', 'display', + default=multi_asic_display_default_option(), + show_default=True, + type=click.Choice(multi_asic_display_choices()), + help='Show internal interfaces') +_multi_asic_click_option_namespace = click.option('--namespace', + '-n', 'namespace', + default=None, + type=click.Choice(multi_asic_ns_choices()), + show_default=True, + help='Namespace name or all') _multi_asic_click_options = [ - click.option('--display', - '-d', 'display', - default=multi_asic_display_default_option(), - show_default=True, - type=click.Choice(multi_asic_display_choices()), - help='Show internal interfaces'), - click.option('--namespace', - '-n', 'namespace', - default=None, - type=click.Choice(multi_asic_ns_choices()), - show_default=True, - help='Namespace name or all'), + _multi_asic_click_option_display, + _multi_asic_click_option_namespace, ] def multi_asic_namespace_validation_callback(ctx, param, value): @@ -122,6 +124,9 @@ def multi_asic_click_options(func): func = option(func) return func +def multi_asic_click_option_namespace(func): + func = _multi_asic_click_option_namespace(func) + return func def run_on_multi_asic(func): '''