diff --git a/scripts/fabricstat b/scripts/fabricstat index 18200785ff..e5c7d09f3b 100755 --- a/scripts/fabricstat +++ b/scripts/fabricstat @@ -178,6 +178,33 @@ class FabricQueueStat(FabricStat): print(tabulate(table, queuestat_header, tablefmt='simple', stralign='right')) print() +class FabricReachability(FabricStat): + def reachability_print(self): + # Connect to database + self.db = multi_asic.connect_to_all_dbs_for_ns(self.namespace) + # Get the set of all fabric port keys + port_keys = self.db.keys(self.db.STATE_DB, FABRIC_PORT_STATUS_TABLE_PREFIX + '*') + # Create a new dictionary. The key values are the local port values + # in integer format. Only ports that have remote port data are added. + # Only ports that are "up" will be connected to a remote peer. + port_dict = {} + for port_key in port_keys: + port_data = self.db.get_all(self.db.STATE_DB, port_key) + if "REMOTE_PORT" in port_data: + port_number = int(port_key.replace("FABRIC_PORT_TABLE|PORT", "")) + port_dict.update({port_number: port_data}) + # Create ordered table of port data + header = ["Local Link", "Remote Module", "Remote Link", "Status"] + body = [] + for port_number in sorted(port_dict.keys()): + port_data = port_dict[port_number] + body.append((port_number, port_data["REMOTE_MOD"], \ + port_data["REMOTE_PORT"], port_data["STATUS"])) + if self.namespace: + print(f"\n{self.namespace}") + print(tabulate(body, header, tablefmt='simple', stralign='right')) + return + def main(): parser = argparse.ArgumentParser(description='Display the fabric port state and counters', formatter_class=argparse.RawTextHelpFormatter, @@ -191,16 +218,25 @@ Examples: """) parser.add_argument('-q','--queue', action='store_true', help='Display fabric queue stat, otherwise port stat') + parser.add_argument('-r','--reachability', action='store_true', help='Display reachability, 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 + reachability = args.reachability namespace = args.namespace errors_only = args.errors def nsStat(ns, errors_only): - stat = FabricQueueStat(ns) if queue else FabricPortStat(ns) + if queue: + stat = FabricQueueStat(ns) + elif reachability: + stat = FabricReachability(ns) + stat.reachability_print() + return + else: + stat = FabricPortStat(ns) cnstat_dict = stat.get_cnstat_dict() stat.cnstat_print(cnstat_dict, errors_only) diff --git a/show/fabric.py b/show/fabric.py index 8dfbc50f7a..2e55887a0f 100644 --- a/show/fabric.py +++ b/show/fabric.py @@ -13,6 +13,18 @@ def counters(): """Show fabric port counters""" pass +@fabric.group(invoke_without_command=True) +@multi_asic_util.multi_asic_click_option_namespace +@click.option('-e', '--errors', is_flag=True) +def reachability(namespace, errors): + """Show fabric reachability""" + cmd = "fabricstat -r" + 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 @click.option('-e', '--errors', is_flag=True) diff --git a/tests/fabricstat_test.py b/tests/fabricstat_test.py index 23bb37d2ed..fb76bb41d7 100644 --- a/tests/fabricstat_test.py +++ b/tests/fabricstat_test.py @@ -90,6 +90,36 @@ """ +multi_asic_fabric_reachability = """\ + +asic0 + Local Link Remote Module Remote Link Status +------------ --------------- ------------- -------- + 0 0 79 up + 2 0 94 up + 4 0 85 up + 6 0 84 up + 7 0 93 up + +asic1 + Local Link Remote Module Remote Link Status +------------ --------------- ------------- -------- + 0 0 69 up + 4 0 75 up +""" + +multi_asic_fabric_reachability_asic0 = """\ + +asic0 + Local Link Remote Module Remote Link Status +------------ --------------- ------------- -------- + 0 0 79 up + 2 0 94 up + 4 0 85 up + 6 0 84 up + 7 0 93 up +""" + class TestMultiAsicFabricStat(object): @classmethod def setup_class(cls): @@ -133,6 +163,20 @@ def test_multi_show_fabric_counters_queue_asic(self): assert return_code == 0 assert result == multi_asic_fabric_counters_queue_asic0 + def test_multi_show_fabric_reachability(self): + return_code, result = get_result_and_return_code('fabricstat -r') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_fabric_reachability + + def test_multi_show_fabric_reachability_asic(self): + return_code, result = get_result_and_return_code('fabricstat -r -n asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_fabric_reachability_asic0 + @classmethod def teardown_class(cls): print("TEARDOWN")