From 57c509a9d7f0c8140ffb099a8e981e2cdde19fc2 Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Mon, 3 Oct 2022 16:58:06 -0700 Subject: [PATCH] [show] vnet endpoint [ip/ipv6] command (#2342) --- doc/Command-Reference.md | 36 +++++++++++++ show/vnet.py | 84 ++++++++++++++++++++++++++++++- tests/mock_tables/appl_db.json | 12 +++-- tests/mock_tables/state_db.json | 18 +++++++ tests/show_bfd_test.py | 24 +++++---- tests/show_vnet_vxlan_cli_test.py | 74 +++++++++++++++++++++++++++ 6 files changed, 233 insertions(+), 15 deletions(-) create mode 100644 tests/show_vnet_vxlan_cli_test.py diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index e6d0a554bc..0dc426ea70 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -9524,6 +9524,42 @@ This command displays brief information about all the vnets configured in the de Vnet_3000 tunnel1 3000 Vnet_2000,Vnet4000 ``` +**show vnet endpoint ** + +This command displays the list or vxlan tunnel endpoints and their status. In addition it also shows the number of prefixes associated with each endpoints in the tunnels. If an IP address of an endpoint is provided, this command also shows the associated prefixes a well. + +- Usage: + + ``` + show vnet endpoint + + ``` + +- Example: + + ``` + admin@sonic:~$ show vnet endpoint + Endpoint prefix count status + --------------------- -------------- -------- + fddd:a100:a251::a10:1 1 Down + fddd:a101:a251::a10:1 1 Up + 100.251.7.1 3 Up + + or + + admin@sonic:~$ show vnet endpoint fddd:a101:a251::a10:1 + Endpoint prefix status + --------------------- ---------------------------- -------- + fddd:a101:a251::a10:1 ['fddd:a150:a251::a6:1/128'] Up + + or + + admin@sonic:~$ show vnet endpoint 100.251.7.1 + Endpoint prefix status + ----------- --------------------------------------------------------- -------- + 100.251.7.1 ['160.62.191.1/32', '160.63.191.1/32', '160.64.191.1/32'] Up + ``` + **show vnet name ** This command displays brief information about configured in the device. diff --git a/show/vnet.py b/show/vnet.py index 4b5674cb62..46970e26f8 100644 --- a/show/vnet.py +++ b/show/vnet.py @@ -3,7 +3,7 @@ from natsort import natsorted from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector from tabulate import tabulate - +import ipaddress # # 'vnet' command ("show vnet") @@ -195,6 +195,88 @@ def neighbors(): if not bool(vnet_intfs): click.echo(tabulate(table, header)) +@vnet.command() +@click.argument('args', metavar='[IPADDRESS]', nargs=1, required=False) +def endpoint(args): + """Show Vxlan tunnel endpoint status""" + """Specify IPv4 or IPv6 address for detail""" + + state_db = SonicV2Connector() + state_db.connect(state_db.STATE_DB) + appl_db = SonicV2Connector() + appl_db.connect(appl_db.APPL_DB) + filter_by_ip = '' + if args and len(args) > 0: + try: + filter_by_ip = ipaddress.ip_network(args) + except ValueError: + # Not ip address just ignore it + print ("wrong parameter",args) + return + # Fetching data from appl_db for VNET TUNNEL ROUTES + vnet_rt_keys = appl_db.keys(appl_db.APPL_DB, "VNET_ROUTE_TUNNEL_TABLE:*") + vnet_rt_keys = natsorted(vnet_rt_keys) if vnet_rt_keys else [] + bfd_keys = state_db.keys(state_db.STATE_DB, "BFD_SESSION_TABLE|*") + if not filter_by_ip: + header = ['Endpoint', 'Endpoint Monitor', 'prefix count', 'status'] + prefix_count = {} + monitor_dict = {} + table = [] + for k in vnet_rt_keys: + val = appl_db.get_all(appl_db.APPL_DB, k) + endpoints = val.get('endpoint').split(',') if 'endpoint' in val else [] + if 'endpoint_monitor' in val: + monitors = val.get('endpoint_monitor').split(',') + else: + continue + for idx, endpoint in enumerate(endpoints): + monitor_dict[endpoint] = monitors[idx] + if endpoint not in prefix_count: + prefix_count[endpoint] = 0 + prefix_count[endpoint] += 1 + for endpoint in prefix_count: + r = [] + r.append(endpoint) + r.append(monitor_dict[endpoint]) + r.append(prefix_count[endpoint]) + bfd_session_key = "BFD_SESSION_TABLE|default|default|" + monitor_dict[endpoint] + if bfd_session_key in bfd_keys: + val_state = state_db.get_all(state_db.STATE_DB, bfd_session_key) + r.append(val_state.get('state')) + else: + r.append('Unknown') + table.append(r) + else: + table = [] + header = ['Endpoint', 'Endpoint Monitor', 'prefix', 'status'] + state = 'Unknown' + prefix = [] + monitor_list = [] + have_status = False + for k in vnet_rt_keys: + val = appl_db.get_all(appl_db.APPL_DB, k) + endpoints = val.get('endpoint').split(',') + monitors = val.get('endpoint_monitor').split(',') + for idx, endpoint in enumerate(endpoints): + if args == endpoint: + prefix.append(k.split(":", 2)[2]) + if not have_status: + bfd_session_key = "BFD_SESSION_TABLE|default|default|" + monitors[idx] + if bfd_session_key in bfd_keys: + val_state = state_db.get_all(state_db.STATE_DB, bfd_session_key) + state = val_state.get('state') + have_status = True + monitor_list.append( monitors[idx]) + break + if prefix: + r = [] + r.append(args) + r.append(monitor_list) + r.append(prefix) + r.append(state) + table.append(r) + click.echo(tabulate(table, header)) + @vnet.group() def routes(): diff --git a/tests/mock_tables/appl_db.json b/tests/mock_tables/appl_db.json index e72cb47a73..df2e25173f 100644 --- a/tests/mock_tables/appl_db.json +++ b/tests/mock_tables/appl_db.json @@ -315,15 +315,19 @@ "alias": "Vlan1000" }, "VNET_ROUTE_TUNNEL_TABLE:test_v4_in_v4-0:160.163.191.1/32": { - "endpoint":"100.251.7.1" + "endpoint":"100.251.7.1", + "endpoint_monitor":"100.251.7.1" }, "VNET_ROUTE_TUNNEL_TABLE:Vnet_v6_in_v6-0:fddd:a156:a251::a6:1/128": { - "endpoint": "fddd:a100:a251::a10:1,fddd:a101:a251::a10:1" + "endpoint": "fddd:a100:a251::a10:1,fddd:a101:a251::a10:1", + "endpoint_monitor":"fddd:a100:a251::a10:1,fddd:a101:a251::a10:1" }, "VNET_ROUTE_TUNNEL_TABLE:test_v4_in_v4-0:160.162.191.1/32": { - "endpoint":"100.251.7.1" + "endpoint":"100.251.7.1", + "endpoint_monitor":"100.251.7.1" }, "VNET_ROUTE_TUNNEL_TABLE:test_v4_in_v4-0:160.164.191.1/32": { - "endpoint":"100.251.7.1" + "endpoint":"100.251.7.1", + "endpoint_monitor":"100.251.7.1" } } diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index beecb681fc..8d2f25c1e2 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -890,5 +890,23 @@ "VNET_ROUTE_TUNNEL_TABLE|Vnet_v6_in_v6-0|fddd:a156:a251::a6:1/128": { "active_endpoints":"fddd:a100:a251::a10:1,fddd:a101:a251::a10:1", "state":"active" + }, + "BFD_SESSION_TABLE|default|default|100.251.7.1": { + "state":"Up", + "type": "async_active", + "local_addr" : "10.0.0.1", + "tx_interval" :"300", + "rx_interval" : "500", + "multiplier" : "3", + "multihop": "true" + }, + "BFD_SESSION_TABLE|default|default|fddd:a101:a251::a10:1": { + "state":"Down", + "type": "async_active", + "local_addr" : "fddd:c101:a251::a10:2", + "tx_interval" :"300", + "rx_interval" : "500", + "multiplier" : "3", + "multihop": "true" } } diff --git a/tests/show_bfd_test.py b/tests/show_bfd_test.py index fdf4fbe5e2..bd2df5f58b 100644 --- a/tests/show_bfd_test.py +++ b/tests/show_bfd_test.py @@ -38,13 +38,15 @@ def test_bfd_show(self): "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 +Total number of BFD sessions: 6 +Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop +--------------------- ----------- ------- ------- ------------ --------------------- ------------- ------------- ------------ ---------- +100.251.7.1 default default Up async_active 10.0.0.1 300 500 3 true +fddd:a101:a251::a10:1 default default Down async_active fddd:c101:a251::a10:2 300 500 3 true +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) @@ -88,9 +90,11 @@ def test_bfd_show_no_session(self): db = Db() expected_output = """\ -Total number of BFD sessions: 0 -Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop ------------ ----------- ----- ------- ------ ------------ ------------- ------------- ------------ ---------- +Total number of BFD sessions: 2 +Peer Addr Interface Vrf State Type Local Addr TX Interval RX Interval Multiplier Multihop +--------------------- ----------- ------- ------- ------------ --------------------- ------------- ------------- ------------ ---------- +100.251.7.1 default default Up async_active 10.0.0.1 300 500 3 true +fddd:a101:a251::a10:1 default default Down async_active fddd:c101:a251::a10:2 300 500 3 true """ result = runner.invoke(show.cli.commands['bfd'].commands['summary'], [], obj=db) diff --git a/tests/show_vnet_vxlan_cli_test.py b/tests/show_vnet_vxlan_cli_test.py new file mode 100644 index 0000000000..f0cee3b257 --- /dev/null +++ b/tests/show_vnet_vxlan_cli_test.py @@ -0,0 +1,74 @@ +import os +import sys +import traceback +import mock_tables.dbconnector +from click.testing import CliRunner +from unittest import mock +from utilities_common.db import Db +import show.main as show + +#test_path = os.path.dirname(os.path.abspath(__file__)) + + + +class TestShowVnet(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + def test_show_vnet_routes_all_basic(self): + runner = CliRunner() + db = Db() + result = runner.invoke(show.cli.commands['vnet'].commands['routes'].commands['all'], [], obj=db) + assert result.exit_code == 0 + expected_output = """\ +vnet name prefix nexthop interface +----------- -------- --------- ----------- + +vnet name prefix endpoint mac address vni status +--------------- ------------------------ ------------------------------------------- ------------- ----- -------- +Vnet_v6_in_v6-0 fddd:a156:a251::a6:1/128 fddd:a100:a251::a10:1,fddd:a101:a251::a10:1 active +test_v4_in_v4-0 160.162.191.1/32 100.251.7.1 active +test_v4_in_v4-0 160.163.191.1/32 100.251.7.1 active +test_v4_in_v4-0 160.164.191.1/32 100.251.7.1 +""" + assert result.output == expected_output + + def test_show_vnet_endpoint(self): + runner = CliRunner() + db = Db() + result = runner.invoke(show.cli.commands['vnet'].commands['endpoint'], [], obj=db) + assert result.exit_code == 0 + expected_output = """\ +Endpoint Endpoint Monitor prefix count status +--------------------- --------------------- -------------- -------- +fddd:a100:a251::a10:1 fddd:a100:a251::a10:1 1 Unknown +fddd:a101:a251::a10:1 fddd:a101:a251::a10:1 1 Down +100.251.7.1 100.251.7.1 3 Up +""" + assert result.output == expected_output + + def test_show_vnet_endpoint_ipv4(self): + runner = CliRunner() + db = Db() + result = runner.invoke(show.cli.commands['vnet'].commands['endpoint'], ['100.251.7.1'], obj=db) + assert result.exit_code == 0 + expected_output = """\ +Endpoint Endpoint Monitor prefix status +----------- ------------------ ------------------------------------------------------------ -------- +100.251.7.1 ['100.251.7.1'] ['160.162.191.1/32', '160.163.191.1/32', '160.164.191.1/32'] Up +""" + assert result.output == expected_output + + def test_show_vnet_endpoint_ipv6(self): + runner = CliRunner() + db = Db() + result = runner.invoke(show.cli.commands['vnet'].commands['endpoint'], ['fddd:a101:a251::a10:1'], obj=db) + assert result.exit_code == 0 + expected_output = """\ +Endpoint Endpoint Monitor prefix status +--------------------- ------------------------- ---------------------------- -------- +fddd:a101:a251::a10:1 ['fddd:a101:a251::a10:1'] ['fddd:a156:a251::a6:1/128'] Down +""" + assert result.output == expected_output