diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index 69a3fb98b8a..0567b787bac 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -28,6 +28,8 @@ * [ARP & NDP](#arp--ndp) * [ARP show commands](#arp-show-commands) * [NDP show commands](#ndp-show-commands) +* [BFD](#bfd) + * [BFD show commands](#bfd-show-commands) * [BGP](#bgp) * [BGP show commands](#bgp-show-commands) * [BGP config commands](#bgp-config-commands) @@ -1546,6 +1548,45 @@ This command displays either all the IPv6 neighbor mac addresses, or for a parti Go Back To [Beginning of the document](#) or [Beginning of this section](#arp--ndp) +## BFD + +### BFD show commands + +**show bfd summary** + +This command displays the state and key parameters of all BFD sessions. + +- Usage: + ``` + show bgp summary + ``` +- Example: + ``` + >> show bfd summary + Total number of BFD sessions: 3 + Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop + ----------- ----------- ------- ------- ------------ ------------ ------------- ------------- ------------ ---------- + 10.0.1.1 default default DOWN async_active 10.0.0.1 300 500 3 true + 10.0.2.1 Ethernet12 default UP async_active 10.0.0.1 200 600 3 false + 2000::10:1 default default UP async_active 2000::1 100 700 3 false + ``` + +**show bfd peer** + +This command displays the state and key parameters of all BFD sessions that match an IP address. + +- Usage: + ``` + show bgp peer + ``` +- Example: + ``` + >> show bfd peer 10.0.1.1 + Total number of BFD sessions for peer IP 10.0.1.1: 1 + Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop + ----------- ----------- ------- ------- ------------ ------------ ------------- ------------- ------------ ---------- + 10.0.1.1 default default DOWN async_active 10.0.0.1 300 500 3 true + ``` ## BGP diff --git a/show/main.py b/show/main.py index b68f0f6fa89..11c74637888 100755 --- a/show/main.py +++ b/show/main.py @@ -1701,6 +1701,67 @@ def ztp(status, verbose): cmd = cmd + " --verbose" run_command(cmd, display_cmd=verbose) + +# +# 'bfd' group ("show bfd ...") +# +@cli.group(cls=clicommon.AliasedGroup) +def bfd(): + """Show details of the bfd sessions""" + pass + +# 'summary' subcommand ("show bfd summary") +@bfd.command() +@clicommon.pass_db +def summary(db): + """Show bfd session information""" + bfd_headers = ["Peer Addr", "Interface", "Vrf", "State", "Type", "Local Addr", + "TX Interval", "RX Interval", "Multiplier", "Multihop"] + + bfd_keys = db.db.keys(db.db.STATE_DB, "BFD_SESSION_TABLE|*") + + click.echo("Total number of BFD sessions: {}".format(0 if bfd_keys is None else len(bfd_keys))) + + bfd_body = [] + if bfd_keys is not None: + for key in bfd_keys: + key_values = key.split('|') + values = db.db.get_all(db.db.STATE_DB, key) + bfd_body.append([key_values[3], key_values[2], key_values[1], values["state"], values["type"], values["local_addr"], + values["tx_interval"], values["rx_interval"], values["multiplier"], values["multihop"]]) + + click.echo(tabulate(bfd_body, bfd_headers)) + + +# 'peer' subcommand ("show bfd peer ...") +@bfd.command() +@clicommon.pass_db +@click.argument('peer_ip', required=True) +def peer(db, peer_ip): + """Show bfd session information for BFD peer""" + bfd_headers = ["Peer Addr", "Interface", "Vrf", "State", "Type", "Local Addr", + "TX Interval", "RX Interval", "Multiplier", "Multihop"] + + bfd_keys = db.db.keys(db.db.STATE_DB, "BFD_SESSION_TABLE|*|{}".format(peer_ip)) + delimiter = db.db.get_db_separator(db.db.STATE_DB) + + if bfd_keys is None or len(bfd_keys) == 0: + click.echo("No BFD sessions found for peer IP {}".format(peer_ip)) + return + + click.echo("Total number of BFD sessions for peer IP {}: {}".format(peer_ip, len(bfd_keys))) + + bfd_body = [] + if bfd_keys is not None: + for key in bfd_keys: + key_values = key.split(delimiter) + values = db.db.get_all(db.db.STATE_DB, key) + bfd_body.append([key_values[3], key_values[2], key_values[1], values.get("state"), values.get("type"), values.get("local_addr"), + values.get("tx_interval"), values.get("rx_interval"), values.get("multiplier"), values.get("multihop")]) + + click.echo(tabulate(bfd_body, bfd_headers)) + + # Load plugins and register them helper = util_base.UtilHelper() helper.load_and_register_plugins(plugins, cli) diff --git a/tests/show_bfd_test.py b/tests/show_bfd_test.py new file mode 100644 index 00000000000..fdf4fbe5e20 --- /dev/null +++ b/tests/show_bfd_test.py @@ -0,0 +1,98 @@ +import os +import sys +from click.testing import CliRunner +from swsscommon.swsscommon import SonicV2Connector +from utilities_common.db import Db + +import show.main as show + +test_path = os.path.dirname(os.path.abspath(__file__)) +mock_db_path = os.path.join(test_path, "bfd_input") + +class TestShowBfd(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + def set_db_values(self, db, key, kvs): + for field, value in kvs.items(): + db.set(db.STATE_DB, key, field, value) + + def test_bfd_show(self): + runner = CliRunner() + db = Db() + dbconnector = db.db + + self.set_db_values(dbconnector, "BFD_SESSION_TABLE|default|default|10.0.1.1", + {"state": "DOWN", "type": "async_active", "local_addr" : "10.0.0.1", + "tx_interval" :"300", "rx_interval" : "500", "multiplier" : "3", "multihop": "true"}) + self.set_db_values(dbconnector, "BFD_SESSION_TABLE|default|Ethernet12|10.0.2.1", + {"state": "UP", "type": "async_active", "local_addr" : "10.0.0.1", + "tx_interval" :"200", "rx_interval" : "600", "multiplier" : "3", "multihop": "false"}) + self.set_db_values(dbconnector, "BFD_SESSION_TABLE|default|default|2000::10:1", + {"state": "UP", "type": "async_active", "local_addr" : "2000::1", + "tx_interval" :"100", "rx_interval" : "700", "multiplier" : "3", "multihop": "false"}) + self.set_db_values(dbconnector, "BFD_SESSION_TABLE|VrfRed|default|10.0.1.1", + {"state": "UP", "type": "async_active", "local_addr" : "10.0.0.1", + "tx_interval" :"400", "rx_interval" : "500", "multiplier" : "5", "multihop": "false"}) + + expected_output = """\ +Total number of BFD sessions: 4 +Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop +----------- ----------- ------- ------- ------------ ------------ ------------- ------------- ------------ ---------- +10.0.1.1 default default DOWN async_active 10.0.0.1 300 500 3 true +10.0.2.1 Ethernet12 default UP async_active 10.0.0.1 200 600 3 false +2000::10:1 default default UP async_active 2000::1 100 700 3 false +10.0.1.1 default VrfRed UP async_active 10.0.0.1 400 500 5 false +""" + + result = runner.invoke(show.cli.commands['bfd'].commands['summary'], [], obj=db) + assert result.exit_code == 0 + assert result.output == expected_output + + expected_output = """\ +Total number of BFD sessions for peer IP 10.0.1.1: 2 +Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop +----------- ----------- ------- ------- ------------ ------------ ------------- ------------- ------------ ---------- +10.0.1.1 default default DOWN async_active 10.0.0.1 300 500 3 true +10.0.1.1 default VrfRed UP async_active 10.0.0.1 400 500 5 false +""" + + result = runner.invoke(show.cli.commands['bfd'].commands['peer'], ['10.0.1.1'], obj=db) + assert result.exit_code == 0 + assert result.output == expected_output + + expected_output = """\ +Total number of BFD sessions for peer IP 10.0.2.1: 1 +Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop +----------- ----------- ------- ------- ------------ ------------ ------------- ------------- ------------ ---------- +10.0.2.1 Ethernet12 default UP async_active 10.0.0.1 200 600 3 false +""" + + result = runner.invoke(show.cli.commands['bfd'].commands['peer'], ['10.0.2.1'], obj=db) + assert result.exit_code == 0 + assert result.output == expected_output + + expected_output = """\ +No BFD sessions found for peer IP 10.0.3.1 +""" + + result = runner.invoke(show.cli.commands['bfd'].commands['peer'], ['10.0.3.1'], obj=db) + assert result.exit_code == 0 + assert result.output == expected_output + + + def test_bfd_show_no_session(self): + runner = CliRunner() + db = Db() + + expected_output = """\ +Total number of BFD sessions: 0 +Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop +----------- ----------- ----- ------- ------ ------------ ------------- ------------- ------------ ---------- +""" + + result = runner.invoke(show.cli.commands['bfd'].commands['summary'], [], obj=db) + assert result.exit_code == 0 + assert result.output == expected_output