From d740d14440cfe2a3a5e3aacf05b6bc8be84ef18e Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Thu, 20 Aug 2020 10:01:01 -0700 Subject: [PATCH 1/3] Add support for multi asic changes Add Unit test for "show ip bgp summary" and "show ipv6 bgp summary" Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- show/bgp_frr_v4.py | 23 +- show/bgp_frr_v6.py | 16 +- show/bgp_quagga_v4.py | 3 +- show/bgp_quagga_v6.py | 3 +- show/main.py | 136 +----- tests/bgp_commands_test.py | 99 +++++ tests/conftest.py | 24 ++ tests/mock_tables/config_db.json | 550 ++++++++++++++++++++++-- tests/mock_tables/ipv4_bgp_summary.json | 447 +++++++++++++++++++ tests/mock_tables/ipv6_bgp_summary.json | 447 +++++++++++++++++++ utilities_common/bgp_util.py | 222 ++++++++++ utilities_common/constants.py | 2 + 12 files changed, 1777 insertions(+), 195 deletions(-) create mode 100644 tests/bgp_commands_test.py create mode 100644 tests/mock_tables/ipv4_bgp_summary.json create mode 100644 tests/mock_tables/ipv6_bgp_summary.json create mode 100644 utilities_common/bgp_util.py diff --git a/show/bgp_frr_v4.py b/show/bgp_frr_v4.py index 9d2fc57dd4..e369056472 100644 --- a/show/bgp_frr_v4.py +++ b/show/bgp_frr_v4.py @@ -1,9 +1,14 @@ +import json +from utilities_common import constants +from utilities_common import bgp_util import click import utilities_common.cli as clicommon -from show.main import ip, run_command, get_bgp_summary_extended - +from show.main import ip, run_command +import utilities_common.multi_asic as multi_asic_util +import utilities_common.bgp_util as bgp_util +import utilities_common.constants as constants ############################################################################### # @@ -12,6 +17,7 @@ ############################################################################### + @ip.group(cls=clicommon.AliasedGroup) def bgp(): """Show IPv4 BGP (Border Gateway Protocol) information""" @@ -20,14 +26,11 @@ def bgp(): # 'summary' subcommand ("show ip bgp summary") @bgp.command() -def summary(): - """Show summarized information of IPv4 BGP state""" - try: - device_output = run_command('sudo vtysh -c "show ip bgp summary"', return_cmd=True) - get_bgp_summary_extended(device_output) - except Exception: - run_command('sudo vtysh -c "show ip bgp summary"') - +@multi_asic_util.multi_asic_click_options +def summary(namespace, display): + bgp_summary = bgp_util.get_bgp_summary_from_all_bgp_instances(constants.IPV4, namespace,display) + bgp_util.display_bgp_summary(bgp_summary=bgp_summary, af=constants.IPV4) + # 'neighbors' subcommand ("show ip bgp neighbors") @bgp.command() diff --git a/show/bgp_frr_v6.py b/show/bgp_frr_v6.py index 37d13a8690..39be295b18 100644 --- a/show/bgp_frr_v6.py +++ b/show/bgp_frr_v6.py @@ -1,8 +1,10 @@ import click import utilities_common.cli as clicommon -from show.main import ipv6, run_command, get_bgp_summary_extended - +from show.main import ipv6, run_command +import utilities_common.multi_asic as multi_asic_util +import utilities_common.bgp_util as bgp_util +import utilities_common.constants as constants ############################################################################### # @@ -19,13 +21,11 @@ def bgp(): # 'summary' subcommand ("show ipv6 bgp summary") @bgp.command() -def summary(): +@multi_asic_util.multi_asic_click_options +def summary(namespace, display): """Show summarized information of IPv6 BGP state""" - try: - device_output = run_command('sudo vtysh -c "show bgp ipv6 summary"', return_cmd=True) - get_bgp_summary_extended(device_output) - except Exception: - run_command('sudo vtysh -c "show bgp ipv6 summary"') + bgp_summary = bgp_util.get_bgp_summary_from_all_bgp_instances(constants.IPV6, namespace,display) + bgp_util.display_bgp_summary(bgp_summary=bgp_summary, af=constants.IPV6) # 'neighbors' subcommand ("show ipv6 bgp neighbors") diff --git a/show/bgp_quagga_v4.py b/show/bgp_quagga_v4.py index bddcf891d9..21444f3e2c 100644 --- a/show/bgp_quagga_v4.py +++ b/show/bgp_quagga_v4.py @@ -1,5 +1,6 @@ import click -from show.main import AliasedGroup, ip, run_command, get_bgp_summary_extended +from show.main import AliasedGroup, ip, run_command, +from utilities_common.bgp_util import get_bgp_summary_extended ############################################################################### diff --git a/show/bgp_quagga_v6.py b/show/bgp_quagga_v6.py index 78c06988c9..73b9570d9d 100644 --- a/show/bgp_quagga_v6.py +++ b/show/bgp_quagga_v6.py @@ -1,5 +1,6 @@ import click -from show.main import AliasedGroup, ipv6, run_command, get_bgp_summary_extended +from show.main import AliasedGroup, ipv6, run_command, +from utilities_common.bgp_util import get_bgp_summary_extended ############################################################################### diff --git a/show/main.py b/show/main.py index 712ae674a4..b94a522db7 100755 --- a/show/main.py +++ b/show/main.py @@ -7,7 +7,7 @@ import re import subprocess import sys -import ipaddress + import click from natsort import natsorted @@ -35,7 +35,7 @@ # location (configdb?), so that we prevent the continous execution of this # bash oneliner. To be revisited once routing-stack info is tracked somewhere. def get_routing_stack(): - command = "sudo docker ps | grep bgp | awk '{print$2}' | cut -d'-' -f3 | cut -d':' -f1" + command = "sudo docker ps | grep bgp | awk '{print$2}' | cut -d'-' -f3 | cut -d':' -f1 | head -n 1" try: proc = subprocess.Popen(command, @@ -95,33 +95,6 @@ def run_command(command, display_cmd=False, return_cmd=False): iface_alias_converter = clicommon.InterfaceAliasConverter() -def get_bgp_summary_extended(command_output): - """ - Adds Neighbor name to the show ip[v6] bgp summary command - :param command: command to get bgp summary - """ - static_neighbors, dynamic_neighbors = get_bgp_neighbors_dict() - modified_output = [] - my_list = iter(command_output.splitlines()) - for element in my_list: - if element.startswith("Neighbor"): - element = "{}\tNeighborName".format(element) - modified_output.append(element) - elif not element or element.startswith("Total number "): - modified_output.append(element) - elif re.match(r"(\*?([0-9A-Fa-f]{1,4}:|\d+.\d+.\d+.\d+))", element.split()[0]): - first_element = element.split()[0] - ip = first_element[1:] if first_element.startswith("*") else first_element - name = get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors) - if len(element.split()) == 1: - modified_output.append(element) - element = next(my_list) - element = "{}\t{}".format(element, name) - modified_output.append(element) - else: - modified_output.append(element) - click.echo("\n".join(modified_output)) - def connect_config_db(): """ @@ -132,108 +105,6 @@ def connect_config_db(): return config_db -def get_neighbor_dict_from_table(db,table_name): - """ - returns a dict with bgp neighbor ip as key and neighbor name as value - :param table_name: config db table name - :param db: config_db - """ - neighbor_dict = {} - neighbor_data = db.get_table(table_name) - try: - for entry in neighbor_data.keys(): - neighbor_dict[entry] = neighbor_data[entry].get( - 'name') if 'name' in neighbor_data[entry].keys() else 'NotAvailable' - return neighbor_dict - except Exception: - return neighbor_dict - - -def is_ipv4_address(ipaddress): - """ - Checks if given ip is ipv4 - :param ipaddress: unicode ipv4 - :return: bool - """ - try: - ipaddress.IPv4Address(ipaddress) - return True - except ipaddress.AddressValueError as err: - return False - - -def is_ipv6_address(ipaddress): - """ - Checks if given ip is ipv6 - :param ipaddress: unicode ipv6 - :return: bool - """ - try: - ipaddress.IPv6Address(ipaddress) - return True - except ipaddress.AddressValueError as err: - return False - - -def get_dynamic_neighbor_subnet(db): - """ - Returns dict of description and subnet info from bgp_peer_range table - :param db: config_db - """ - dynamic_neighbor = {} - v4_subnet = {} - v6_subnet = {} - neighbor_data = db.get_table('BGP_PEER_RANGE') - try: - for entry in neighbor_data.keys(): - new_key = neighbor_data[entry]['ip_range'][0] - new_value = neighbor_data[entry]['name'] - if is_ipv4_address(unicode(neighbor_data[entry]['src_address'])): - v4_subnet[new_key] = new_value - elif is_ipv6_address(unicode(neighbor_data[entry]['src_address'])): - v6_subnet[new_key] = new_value - dynamic_neighbor["v4"] = v4_subnet - dynamic_neighbor["v6"] = v6_subnet - return dynamic_neighbor - except Exception: - return neighbor_data - - -def get_bgp_neighbors_dict(): - """ - Uses config_db to get the bgp neighbors and names in dictionary format - :return: - """ - dynamic_neighbors = {} - config_db = connect_config_db() - static_neighbors = get_neighbor_dict_from_table(config_db, 'BGP_NEIGHBOR') - bgp_monitors = get_neighbor_dict_from_table(config_db, 'BGP_MONITORS') - static_neighbors.update(bgp_monitors) - dynamic_neighbors = get_dynamic_neighbor_subnet(config_db) - return static_neighbors, dynamic_neighbors - - -def get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors): - """ - return neighbor name for the ip provided - :param ip: ip address unicode - :param static_neighbors: statically defined bgp neighbors dict - :param dynamic_neighbors: subnet of dynamically defined neighbors dict - :return: name of neighbor - """ - if ip in static_neighbors.keys(): - return static_neighbors[ip] - elif is_ipv4_address(unicode(ip)): - for subnet in dynamic_neighbors["v4"].keys(): - if ipaddress.IPv4Address(unicode(ip)) in ipaddress.IPv4Network(unicode(subnet)): - return dynamic_neighbors["v4"][subnet] - elif is_ipv6_address(unicode(ip)): - for subnet in dynamic_neighbors["v6"].keys(): - if ipaddress.IPv6Address(unicode(ip)) in ipaddress.IPv6Network(unicode(subnet)): - return dynamic_neighbors["v6"][subnet] - else: - return "NotAvailable" - CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help', '-?']) @@ -1038,7 +909,6 @@ def protocol(verbose): cmd = 'sudo vtysh -c "show ipv6 protocol"' run_command(cmd, display_cmd=verbose) - # # Inserting BGP functionality into cli's show parse-chain. # BGP commands are determined by the routing-stack being elected. @@ -1048,7 +918,7 @@ def protocol(verbose): ip.add_command(bgp) from .bgp_quagga_v6 import bgp ipv6.add_command(bgp) -elif routing_stack == "frr": +else: from .bgp_frr_v4 import bgp ip.add_command(bgp) from .bgp_frr_v6 import bgp diff --git a/tests/bgp_commands_test.py b/tests/bgp_commands_test.py new file mode 100644 index 0000000000..64f25a2d70 --- /dev/null +++ b/tests/bgp_commands_test.py @@ -0,0 +1,99 @@ +import pytest +from click.testing import CliRunner +import show.main as show + +show_bgp_summary_v4="""\ + +IPv4 Unicast Summary: +BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0 +BGP table version 12811 +RIB entries 12817, using 2358328 bytes of memory +Peers 24, using 502080 KiB of memory +Peer groups 4, using 256 bytes of memory + + +Neighbhor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName +----------- --- ----- --------- --------- -------- ----- ------ --------- -------------- -------------- +10.0.0.1 4 65200 5919 2717 0 0 0 1d21h11m 6402 ARISTA01T2 +10.0.0.5 4 65200 5916 2714 0 0 0 1d21h10m 6402 ARISTA03T2 +10.0.0.9 4 65200 5915 2713 0 0 0 1d21h09m 6402 ARISTA05T2 +10.0.0.13 4 65200 5917 2716 0 0 0 1d21h11m 6402 ARISTA07T2 +10.0.0.17 4 65200 5916 2713 0 0 0 1d21h09m 6402 ARISTA09T2 +10.0.0.21 4 65200 5917 2716 0 0 0 1d21h11m 6402 ARISTA11T2 +10.0.0.25 4 65200 5917 2716 0 0 0 1d21h11m 6402 ARISTA13T2 +10.0.0.29 4 65200 5916 2714 0 0 0 1d21h10m 6402 ARISTA15T2 +10.0.0.33 4 64001 0 0 0 0 0 never Active ARISTA01T0 +10.0.0.35 4 64002 0 0 0 0 0 never Active ARISTA02T0 +10.0.0.37 4 64003 0 0 0 0 0 never Active ARISTA03T0 +10.0.0.39 4 64004 0 0 0 0 0 never Active ARISTA04T0 +10.0.0.41 4 64005 0 0 0 0 0 never Active ARISTA05T0 +10.0.0.43 4 64006 0 0 0 0 0 never Active ARISTA06T0 +10.0.0.45 4 64007 0 0 0 0 0 never Active ARISTA07T0 +10.0.0.47 4 64008 0 0 0 0 0 never Active ARISTA08T0 +10.0.0.49 4 64009 0 0 0 0 0 never Active ARISTA09T0 +10.0.0.51 4 64010 0 0 0 0 0 never Active ARISTA10T0 +10.0.0.53 4 64011 0 0 0 0 0 never Active ARISTA11T0 +10.0.0.55 4 64012 0 0 0 0 0 never Active ARISTA12T0 +10.0.0.57 4 64013 0 0 0 0 0 never Active ARISTA13T0 +10.0.0.59 4 64014 0 0 0 0 0 never Active ARISTA14T0 +10.0.0.61 4 64015 0 0 0 0 0 never Active ARISTA15T0 +10.0.0.63 4 64016 0 0 0 0 0 never Active ARISTA16T0 +""" + +show_bgp_summary_v6="""\ + +IPv6 Unicast Summary: +BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0 +BGP table version 8972 +RIB entries 12817, using 2358328 bytes of memory +Peers 24, using 502080 KiB of memory +Peer groups 4, using 256 bytes of memory + + +Neighbhor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName +----------- --- ----- --------- --------- -------- ----- ------ --------- -------------- -------------- +fc00::1a 4 65200 6665 6672 0 0 0 2d09h39m 6402 ARISTA07T2 +fc00::2 4 65200 6666 7913 0 0 0 2d09h39m 6402 ARISTA01T2 +fc00::2a 4 65200 6666 7913 0 0 0 2d09h39m 6402 ARISTA11T2 +fc00::3a 4 65200 6666 7912 0 0 0 2d09h39m 6402 ARISTA15T2 +fc00::4a 4 64003 0 0 0 0 0 never Active ARISTA03T0 +fc00::4e 4 64004 0 0 0 0 0 never Active ARISTA04T0 +fc00::5a 4 64007 0 0 0 0 0 never Active ARISTA07T0 +fc00::5e 4 64008 0 0 0 0 0 never Active ARISTA08T0 +fc00::6a 4 64011 0 0 0 0 0 never Connect ARISTA11T0 +fc00::6e 4 64012 0 0 0 0 0 never Active ARISTA12T0 +fc00::7a 4 64015 0 0 0 0 0 never Active ARISTA15T0 +fc00::7e 4 64016 0 0 0 0 0 never Active ARISTA16T0 +fc00::12 4 65200 6666 7915 0 0 0 2d09h39m 6402 ARISTA05T2 +fc00::22 4 65200 6667 7915 0 0 0 2d09h39m 6402 ARISTA09T2 +fc00::32 4 65200 6663 6669 0 0 0 2d09h36m 6402 ARISTA13T2 +fc00::42 4 64001 0 0 0 0 0 never Active ARISTA01T0 +fc00::46 4 64002 0 0 0 0 0 never Active ARISTA02T0 +fc00::52 4 64005 0 0 0 0 0 never Active ARISTA05T0 +fc00::56 4 64006 0 0 0 0 0 never Active ARISTA06T0 +fc00::62 4 64009 0 0 0 0 0 never Active ARISTA09T0 +fc00::66 4 64010 0 0 0 0 0 never Active ARISTA10T0 +fc00::72 4 64013 0 0 0 0 0 never Active ARISTA13T0 +fc00::76 4 64014 0 0 0 0 0 never Active ARISTA14T0 +fc00::a 4 65200 6665 6671 0 0 0 2d09h38m 6402 ARISTA03T2 +""" +class TestBgpCommands(object): + @classmethod + def setup_class(cls): + print("SETUP") + import mock_tables.dbconnector + + @pytest.mark.parametrize('setup_single_bgp_instance', ['v4'], indirect=['setup_single_bgp_instance']) + def test_bgp_summary_v4(self, setup_single_bgp_instance): + #reload(show) + runner = CliRunner() + result = runner.invoke(show.cli.commands["ip"].commands["bgp"].commands["summary"]) + print("Result : {}".format(result.output)) + assert result.output == show_bgp_summary_v4 + + @pytest.mark.parametrize('setup_single_bgp_instance', ['v6'], indirect=['setup_single_bgp_instance']) + def test_bgp_summary_v6(self, setup_single_bgp_instance): + runner = CliRunner() + result = runner.invoke(show.cli.commands["ipv6"].commands["bgp"].commands["summary"]) + print("Result : {}".format(result.output)) + assert result.output == show_bgp_summary_v6 \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index e46e6605fd..a24fe68d55 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,7 @@ import os import sys +import json + import mock import pytest @@ -54,6 +56,11 @@ def get_cmd_module(): return (config, show) +@pytest.fixture +def get_show_module(): + import show.main as show + return show + @pytest.fixture def setup_single_broacom_asic(): import config.main as config @@ -65,3 +72,20 @@ def setup_single_broacom_asic(): config.asic_type = mock.MagicMock(return_value = "broadcom") config._get_device_type = mock.MagicMock(return_value = "ToRRouter") + +@pytest.fixture +def setup_single_bgp_instance(monkeypatch, request): + import utilities_common.bgp_util as bgp_util + + if request.param == 'v4': + bgp_summary_json = 'mock_tables/ipv4_bgp_summary.json' + else: + bgp_summary_json = 'mock_tables/ipv6_bgp_summary.json' + + def mock_run_bgp_command(vtysh_cmd, bgp_namespace): + with open(bgp_summary_json) as json_data: + mock_frr_data = json_data.read() + return mock_frr_data + + monkeypatch.setattr(bgp_util, "run_bgp_command", mock_run_bgp_command) + diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index c069493216..d5777bddd4 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -5,12 +5,12 @@ "polling_interval": "0" }, "SFLOW_COLLECTOR|prod": { - "collector_ip": "fe80::6e82:6aff:fe1e:cd8e", - "collector_port": "6343" + "collector_ip": "fe80::6e82:6aff:fe1e:cd8e", + "collector_port": "6343" }, "SFLOW_COLLECTOR|ser5": { - "collector_ip": "172.21.35.15", - "collector_port": "6343" + "collector_ip": "172.21.35.15", + "collector_port": "6343" }, "BREAKOUT_CFG|Ethernet0": { "brkout_mode": "4x25G[10G]" @@ -446,52 +446,86 @@ "tagging_mode": "untagged" }, "PORTCHANNEL|PortChannel1001": { - "admin_status": "up", + "admin_status": "up", "members@": "Ethernet32", - "min_links": "1", - "mtu": "9100" - }, + "min_links": "1", + "mtu": "9100" + }, "PORTCHANNEL|PortChannel0001": { - "admin_status": "up", + "admin_status": "up", "members@": "Ethernet112", - "min_links": "1", - "mtu": "9100" - }, + "min_links": "1", + "mtu": "9100" + }, "PORTCHANNEL|PortChannel0002": { - "admin_status": "up", + "admin_status": "up", "members@": "Ethernet116", - "min_links": "1", - "mtu": "9100" - }, + "min_links": "1", + "mtu": "9100" + }, "PORTCHANNEL|PortChannel0003": { - "admin_status": "up", + "admin_status": "up", "members@": "Ethernet120", - "min_links": "1", - "mtu": "9100" - }, + "min_links": "1", + "mtu": "9100" + }, "PORTCHANNEL|PortChannel0004": { - "admin_status": "up", + "admin_status": "up", "members@": "Ethernet124", - "min_links": "1", - "mtu": "9100" - }, - "PORTCHANNEL_MEMBER|PortChannel1001|Ethernet32": {"NULL": "NULL"}, - "PORTCHANNEL_MEMBER|PortChannel0001|Ethernet112": {"NULL": "NULL"}, - "PORTCHANNEL_MEMBER|PortChannel0002|Ethernet116": {"NULL": "NULL"}, - "PORTCHANNEL_MEMBER|PortChannel0003|Ethernet120": {"NULL": "NULL"}, - "PORTCHANNEL_MEMBER|PortChannel0004|Ethernet124": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0001": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0002": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0003": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0004": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0001|10.0.0.56/31": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0001|FC00::71/126": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0002|10.0.0.58/31": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0002|FC00::75/126": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0003|10.0.0.60/31": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0003|FC00::79/126": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0004|10.0.0.62/31": {"NULL": "NULL"}, - "PORTCHANNEL_INTERFACE|PortChannel0004|FC00::7D/126": {"NULL": "NULL"}, + "min_links": "1", + "mtu": "9100" + }, + "PORTCHANNEL_MEMBER|PortChannel1001|Ethernet32": { + "NULL": "NULL" + }, + "PORTCHANNEL_MEMBER|PortChannel0001|Ethernet112": { + "NULL": "NULL" + }, + "PORTCHANNEL_MEMBER|PortChannel0002|Ethernet116": { + "NULL": "NULL" + }, + "PORTCHANNEL_MEMBER|PortChannel0003|Ethernet120": { + "NULL": "NULL" + }, + "PORTCHANNEL_MEMBER|PortChannel0004|Ethernet124": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0001": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0002": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0003": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0004": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0001|10.0.0.56/31": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0001|FC00::71/126": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0002|10.0.0.58/31": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0002|FC00::75/126": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0003|10.0.0.60/31": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0003|FC00::79/126": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0004|10.0.0.62/31": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel0004|FC00::7D/126": { + "NULL": "NULL" + }, "DEBUG_COUNTER|DEBUG_0": { "type": "PORT_INGRESS_DROPS" }, @@ -714,5 +748,437 @@ "lo_addr": "None", "mgmt_addr": "10.250.0.54", "type": "LeafRouter" + }, + "BGP_NEIGHBOR|10.0.0.1": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.0", + "name": "ARISTA01T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.5": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.4", + "name": "ARISTA03T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.9": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.8", + "name": "ARISTA05T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.13": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.12", + "name": "ARISTA07T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.17": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.16", + "name": "ARISTA09T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.21": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.20", + "name": "ARISTA11T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.25": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.24", + "name": "ARISTA13T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.29": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.28", + "name": "ARISTA15T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.33": { + "asn": "64001", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.32", + "name": "ARISTA01T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.35": { + "asn": "64002", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.34", + "name": "ARISTA02T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.37": { + "asn": "64003", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.36", + "name": "ARISTA03T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.39": { + "asn": "64004", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.38", + "name": "ARISTA04T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.41": { + "asn": "64005", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.40", + "name": "ARISTA05T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.43": { + "asn": "64006", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.42", + "name": "ARISTA06T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.45": { + "asn": "64007", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.44", + "name": "ARISTA07T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.47": { + "asn": "64008", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.46", + "name": "ARISTA08T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.49": { + "asn": "64009", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.48", + "name": "ARISTA09T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.51": { + "asn": "64010", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.50", + "name": "ARISTA10T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.53": { + "asn": "64011", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.52", + "name": "ARISTA11T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.55": { + "asn": "64012", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.54", + "name": "ARISTA12T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.57": { + "asn": "64013", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.56", + "name": "ARISTA13T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.59": { + "asn": "64014", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.58", + "name": "ARISTA14T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.61": { + "asn": "64015", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.60", + "name": "ARISTA15T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|10.0.0.63": { + "asn": "64016", + "holdtime": "10", + "keepalive": "3", + "local_addr": "10.0.0.62", + "name": "ARISTA16T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::1a": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::19", + "name": "ARISTA07T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::2": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::1", + "name": "ARISTA01T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::2a": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::29", + "name": "ARISTA11T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::3a": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::39", + "name": "ARISTA15T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::4a": { + "asn": "64003", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::49", + "name": "ARISTA03T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::4e": { + "asn": "64004", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::4d", + "name": "ARISTA04T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::5a": { + "asn": "64007", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::59", + "name": "ARISTA07T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::5e": { + "asn": "64008", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::5d", + "name": "ARISTA08T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::6a": { + "asn": "64011", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::69", + "name": "ARISTA11T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::6e": { + "asn": "64012", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::6d", + "name": "ARISTA12T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::7a": { + "asn": "64015", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::79", + "name": "ARISTA15T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::7e": { + "asn": "64016", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::7d", + "name": "ARISTA16T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::12": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::11", + "name": "ARISTA05T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::22": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::21", + "name": "ARISTA09T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::32": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::31", + "name": "ARISTA13T2", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::42": { + "asn": "64001", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::41", + "name": "ARISTA01T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::46": { + "asn": "64002", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::45", + "name": "ARISTA02T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::52": { + "asn": "64005", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::51", + "name": "ARISTA05T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::56": { + "asn": "64006", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::55", + "name": "ARISTA06T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::62": { + "asn": "64009", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::61", + "name": "ARISTA09T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::66": { + "asn": "64010", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::65", + "name": "ARISTA10T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::72": { + "asn": "64013", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::71", + "name": "ARISTA13T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::76": { + "asn": "64014", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::75", + "name": "ARISTA14T0", + "nhopself": "0", + "rrclient": "0" + }, + "BGP_NEIGHBOR|fc00::a": { + "asn": "65200", + "holdtime": "10", + "keepalive": "3", + "local_addr": "fc00::9", + "name": "ARISTA03T2", + "nhopself": "0", + "rrclient": "0" } -} +} \ No newline at end of file diff --git a/tests/mock_tables/ipv4_bgp_summary.json b/tests/mock_tables/ipv4_bgp_summary.json new file mode 100644 index 0000000000..ea6eeb3936 --- /dev/null +++ b/tests/mock_tables/ipv4_bgp_summary.json @@ -0,0 +1,447 @@ +{ +"ipv4Unicast":{ + "routerId":"10.1.0.32", + "as":65100, + "vrfId":0, + "vrfName":"default", + "tableVersion":12811, + "ribCount":12817, + "ribMemory":2358328, + "peerCount":24, + "peerMemory":502080, + "peerGroupCount":4, + "peerGroupMemory":256, + "peers":{ + "10.0.0.33":{ + "remoteAs":64001, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.35":{ + "remoteAs":64002, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.37":{ + "remoteAs":64003, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.39":{ + "remoteAs":64004, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.41":{ + "remoteAs":64005, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.43":{ + "remoteAs":64006, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.45":{ + "remoteAs":64007, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.47":{ + "remoteAs":64008, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.49":{ + "remoteAs":64009, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.51":{ + "remoteAs":64010, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.53":{ + "remoteAs":64011, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.55":{ + "remoteAs":64012, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.57":{ + "remoteAs":64013, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.59":{ + "remoteAs":64014, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.61":{ + "remoteAs":64015, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.63":{ + "remoteAs":64016, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.1":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5919, + "msgSent":2717, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h11m", + "peerUptimeMsec":162683000, + "peerUptimeEstablishedEpoch":1597732920, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.5":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5916, + "msgSent":2714, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h10m", + "peerUptimeMsec":162638000, + "peerUptimeEstablishedEpoch":1597732965, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.9":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5915, + "msgSent":2713, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h09m", + "peerUptimeMsec":162580000, + "peerUptimeEstablishedEpoch":1597733023, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.13":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5917, + "msgSent":2716, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h11m", + "peerUptimeMsec":162683000, + "peerUptimeEstablishedEpoch":1597732920, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.17":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5916, + "msgSent":2713, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h09m", + "peerUptimeMsec":162594000, + "peerUptimeEstablishedEpoch":1597733009, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.21":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5917, + "msgSent":2716, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h11m", + "peerUptimeMsec":162682000, + "peerUptimeEstablishedEpoch":1597732921, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.25":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5917, + "msgSent":2716, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h11m", + "peerUptimeMsec":162682000, + "peerUptimeEstablishedEpoch":1597732921, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "10.0.0.29":{ + "remoteAs":65200, + "version":4, + "msgRcvd":5916, + "msgSent":2714, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"1d21h10m", + "peerUptimeMsec":162658000, + "peerUptimeEstablishedEpoch":1597732945, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":1, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + } + }, + "failedPeers":16, + "totalPeers":24, + "dynamicPeers":0, + "bestPath":{ + "multiPathRelax":"true" + } +} +} diff --git a/tests/mock_tables/ipv6_bgp_summary.json b/tests/mock_tables/ipv6_bgp_summary.json new file mode 100644 index 0000000000..1c9d165425 --- /dev/null +++ b/tests/mock_tables/ipv6_bgp_summary.json @@ -0,0 +1,447 @@ +{ +"ipv6Unicast":{ + "routerId":"10.1.0.32", + "as":65100, + "vrfId":0, + "vrfName":"default", + "tableVersion":8972, + "ribCount":12817, + "ribMemory":2358328, + "peerCount":24, + "peerMemory":502080, + "peerGroupCount":4, + "peerGroupMemory":256, + "peers":{ + "fc00::42":{ + "remoteAs":64001, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::46":{ + "remoteAs":64002, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::4a":{ + "remoteAs":64003, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::4e":{ + "remoteAs":64004, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::52":{ + "remoteAs":64005, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::56":{ + "remoteAs":64006, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::5a":{ + "remoteAs":64007, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::5e":{ + "remoteAs":64008, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::62":{ + "remoteAs":64009, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::66":{ + "remoteAs":64010, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::6a":{ + "remoteAs":64011, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Connect", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::6e":{ + "remoteAs":64012, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::72":{ + "remoteAs":64013, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::76":{ + "remoteAs":64014, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::7a":{ + "remoteAs":64015, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::7e":{ + "remoteAs":64016, + "version":4, + "msgRcvd":0, + "msgSent":0, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"never", + "peerUptimeMsec":0, + "prefixReceivedCount":0, + "pfxRcd":0, + "state":"Active", + "connectionsEstablished":0, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::2":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6666, + "msgSent":7913, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h39m", + "peerUptimeMsec":207559000, + "peerUptimeEstablishedEpoch":1597732922, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::a":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6665, + "msgSent":6671, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h38m", + "peerUptimeMsec":207508000, + "peerUptimeEstablishedEpoch":1597732973, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::12":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6666, + "msgSent":7915, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h39m", + "peerUptimeMsec":207559000, + "peerUptimeEstablishedEpoch":1597732922, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::1a":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6665, + "msgSent":6672, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h39m", + "peerUptimeMsec":207543000, + "peerUptimeEstablishedEpoch":1597732938, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::22":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6667, + "msgSent":7915, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h39m", + "peerUptimeMsec":207560000, + "peerUptimeEstablishedEpoch":1597732921, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::2a":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6666, + "msgSent":7913, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h39m", + "peerUptimeMsec":207559000, + "peerUptimeEstablishedEpoch":1597732922, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::32":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6663, + "msgSent":6669, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h36m", + "peerUptimeMsec":207403000, + "peerUptimeEstablishedEpoch":1597733078, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + }, + "fc00::3a":{ + "remoteAs":65200, + "version":4, + "msgRcvd":6666, + "msgSent":7912, + "tableVersion":0, + "outq":0, + "inq":0, + "peerUptime":"2d09h39m", + "peerUptimeMsec":207559000, + "peerUptimeEstablishedEpoch":1597732922, + "prefixReceivedCount":6402, + "pfxRcd":6402, + "pfxSnt":6410, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv6" + } + }, + "failedPeers":16, + "totalPeers":24, + "dynamicPeers":0, + "bestPath":{ + "multiPathRelax":"true" + } +} +} diff --git a/utilities_common/bgp_util.py b/utilities_common/bgp_util.py new file mode 100644 index 0000000000..f0b71245c5 --- /dev/null +++ b/utilities_common/bgp_util.py @@ -0,0 +1,222 @@ +import ipaddress +import json +import os +import re + +import click +import utilities_common.cli as clicommon +import utilities_common.multi_asic as multi_asic_util +from natsort import natsorted +from sonic_py_common import multi_asic +from tabulate import tabulate +from utilities_common import constants + + +def is_ipv4_address(ipaddress): + """ + Checks if given ip is ipv4 + :param ipaddress: unicode ipv4 + :return: bool + """ + try: + ipaddress.IPv4Address(ipaddress) + return True + except ipaddress.AddressValueError as err: + return False + + +def is_ipv6_address(ipaddress): + """ + Checks if given ip is ipv6 + :param ipaddress: unicode ipv6 + :return: bool + """ + try: + ipaddress.IPv6Address(ipaddress) + return True + except ipaddress.AddressValueError as err: + return False + + +def get_dynamic_neighbor_subnet(db): + """ + Returns dict of description and subnet info from bgp_peer_range table + :param db: config_db + """ + dynamic_neighbor = {} + v4_subnet = {} + v6_subnet = {} + neighbor_data = db.get_table('BGP_PEER_RANGE') + try: + for entry in neighbor_data.keys(): + new_key = neighbor_data[entry]['ip_range'][0] + new_value = neighbor_data[entry]['name'] + if is_ipv4_address(unicode(neighbor_data[entry]['src_address'])): + v4_subnet[new_key] = new_value + elif is_ipv6_address(unicode(neighbor_data[entry]['src_address'])): + v6_subnet[new_key] = new_value + dynamic_neighbor[constants.IPV4] = v4_subnet + dynamic_neighbor[constants.IPV6] = v6_subnet + return dynamic_neighbor + except Exception: + return neighbor_data + + +def get_bgp_neighbors_dict(namespace=multi_asic.DEFAULT_NAMESPACE): + """ + Uses config_db to get the bgp neighbors and names in dictionary format + :return: + """ + dynamic_neighbors = {} + config_db = multi_asic.connect_config_db_for_ns(namespace) + static_neighbors = get_neighbor_dict_from_table(config_db, 'BGP_NEIGHBOR') + bgp_monitors = get_neighbor_dict_from_table(config_db, 'BGP_MONITORS') + static_neighbors.update(bgp_monitors) + dynamic_neighbors = get_dynamic_neighbor_subnet(config_db) + return static_neighbors, dynamic_neighbors + +def get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors): + """ + return neighbor name for the ip provided + :param ip: ip address unicode + :param static_neighbors: statically defined bgp neighbors dict + :param dynamic_neighbors: subnet of dynamically defined neighbors dict + :return: name of neighbor + """ + if ip in static_neighbors.keys(): + return static_neighbors[ip] + elif is_ipv4_address(unicode(ip)): + for subnet in dynamic_neighbors[constants.IPV4].keys(): + if ipaddress.IPv4Address(unicode(ip)) in ipaddress.IPv4Network(unicode(subnet)): + return dynamic_neighbors[constants.IPV4][subnet] + elif is_ipv6_address(unicode(ip)): + for subnet in dynamic_neighbors[constants.IPV6].keys(): + if ipaddress.IPv6Address(unicode(ip)) in ipaddress.IPv6Network(unicode(subnet)): + return dynamic_neighbors[constants.IPV6][subnet] + else: + return "NotAvailable" + +def get_bgp_summary_extended(command_output): + """ + Adds Neighbor name to the show ip[v6] bgp summary command + :param command: command to get bgp summary + """ + static_neighbors, dynamic_neighbors = get_bgp_neighbors_dict() + modified_output = [] + my_list = iter(command_output.splitlines()) + for element in my_list: + if element.startswith("Neighbor"): + element = "{}\tNeighborName".format(element) + modified_output.append(element) + elif not element or element.startswith("Total number "): + modified_output.append(element) + elif re.match(r"(\*?([0-9A-Fa-f]{1,4}:|\d+.\d+.\d+.\d+))", element.split()[0]): + first_element = element.split()[0] + ip = first_element[1:] if first_element.startswith("*") else first_element + name = get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors) + if len(element.split()) == 1: + modified_output.append(element) + element = next(my_list) + element = "{}\t{}".format(element, name) + modified_output.append(element) + else: + modified_output.append(element) + click.echo("\n".join(modified_output)) + +def get_neighbor_dict_from_table(db,table_name): + """ + returns a dict with bgp neighbor ip as key and neighbor name as value + :param table_name: config db table name + :param db: config_db + """ + neighbor_dict = {} + neighbor_data = db.get_table(table_name) + try: + for entry in neighbor_data.keys(): + neighbor_dict[entry] = neighbor_data[entry].get( + 'name') if 'name' in neighbor_data[entry].keys() else 'NotAvailable' + return neighbor_dict + except Exception: + return neighbor_dict + +def run_bgp_command(vtysh_cmd, bgp_namespace=multi_asic.DEFAULT_NAMESPACE): + bgp_instance_id = ' ' + + if bgp_namespace is not multi_asic.DEFAULT_NAMESPACE: + bgp_instance_id = multi_asic.get_asic_id_from_name(bgp_namespace) + + cmd = 'sudo docker exec bgp{} vtysh -c "{}"'.format(bgp_instance_id, vtysh_cmd) + output = clicommon.run_command(cmd, return_cmd=True) + return output + +def get_bgp_summary_from_all_bgp_instances(af,namespace, display): + device = multi_asic_util.MultiAsic(display, namespace) + if af is constants.IPV4: + vtysh_cmd = "show ip bgp summary json" + key = 'ipv4Unicast' + else: + vtysh_cmd = "show bgp ipv6 summary json" + key = 'ipv6Unicast' + bgp_summary = {} + for ns in device.get_ns_list_based_on_options(): + cmd_output = json.loads(run_bgp_command(vtysh_cmd, ns)) + device.current_namespace = ns + process_bgp_summary_json(bgp_summary, cmd_output[key], device) + return bgp_summary + + +def display_bgp_summary(bgp_summary, af): + headers = ["Neighbhor", "V", "AS", "MsgRcvd", "MsgSent", "TblVer", "InQ", "OutQ", "Up/Down", "State/PfxRcd", "NeighborName"] + click.echo("\nIP{} Unicast Summary:".format(af)) + for router_info in bgp_summary['router_info']: + for k in router_info.keys(): + v = router_info[k] + instance = "{}: ".format(k) if k is not "" else "" + click.echo("{}BGP router identifier {}, local AS number {} vrf-id {}"\ + .format(instance, v['router_id'], v['as'], v['vrf'] )) + click.echo("BGP table version {} ".format(v['tbl_ver'])) + click.echo("RIB entries {}, using {} bytes of memory".format(bgp_summary['ribCount'], bgp_summary['ribMemory'])) + click.echo("Peers {}, using {} KiB of memory".format(bgp_summary['peerCount'], bgp_summary['peerMemory']) ) + click.echo("Peer groups {}, using {} bytes of memory".format(bgp_summary['peerGroupCount'], bgp_summary['peerGroupMemory'])) + click.echo("\n") + click.echo(tabulate(natsorted(bgp_summary['peers']), headers = headers)) + +def process_bgp_summary_json(bgp_summary, cmd_output, device): + static_neighbors, dynamic_neighbors = get_bgp_neighbors_dict(device.current_namespace) + bgp_summary['peerCount'] = bgp_summary.get('peerCount', 0) + cmd_output['peerCount'] + bgp_summary['peerMemory'] = bgp_summary.get('peerMemory', 0) + cmd_output['peerMemory'] + bgp_summary['ribCount'] = bgp_summary.get('ribCount', 0) + cmd_output['ribCount'] + bgp_summary['ribMemory'] = bgp_summary.get('ribMemory', 0) + cmd_output['ribMemory'] + bgp_summary['peerGroupCount'] = bgp_summary.get('peerGroupCount', 0) + cmd_output['peerGroupCount'] + bgp_summary['peerGroupMemory'] = bgp_summary.get('peerGroupMemory', 0) + cmd_output['peerGroupMemory'] + + router_info = {} + router_info['router_id'] = cmd_output['routerId'] + router_info['vrf'] = cmd_output['vrfId'] + router_info['as'] = cmd_output['as'] + router_info['tbl_ver'] = cmd_output['tableVersion'] + bgp_summary.setdefault('router_info', []).append({device.current_namespace: router_info}) + + for peer_ip, value in cmd_output['peers'].iteritems(): + peers = [] + if device.skip_display(constants.BGP_NEIGH_OBJ, peer_ip): + continue + + peers.append(peer_ip) + neigh_name = get_bgp_neighbor_ip_to_name(peer_ip, static_neighbors, dynamic_neighbors) + peers.append( value['version']) + peers.append(value['remoteAs']) + peers.append(value['msgRcvd']) + peers.append(value['msgSent']) + peers.append(value['tableVersion']) + + peers.append(value['inq']) + peers.append(value['outq']) + peers.append(value['peerUptime']) + if value['state'] == 'Established': + peers.append(value['pfxRcd']) + else: + peers.append(value['state']) + + peers.append(neigh_name) + bgp_summary.setdefault('peers', []).append(peers) diff --git a/utilities_common/constants.py b/utilities_common/constants.py index e3bb3ddb23..ee2a23c98d 100644 --- a/utilities_common/constants.py +++ b/utilities_common/constants.py @@ -6,4 +6,6 @@ BGP_NEIGH_OBJ = 'BGP_NEIGH' PORT_CHANNEL_OBJ = 'PORT_CHANNEL' PORT_OBJ = 'PORT' +IPV4 = 'v4' +IPV6 = 'v6' From 05a87fbb8f12e7c9c03aac7d244f61eb2111b488 Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Thu, 20 Aug 2020 19:36:00 -0700 Subject: [PATCH 2/3] more test and fixes Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- show/bgp_quagga_v4.py | 2 +- show/bgp_quagga_v6.py | 2 +- show/main.py | 2 +- tests/bgp_commands_test.py | 68 +++++++++--- tests/conftest.py | 46 +++++--- utilities_common/bgp_util.py | 207 ++++++++++++++++++++++++----------- 6 files changed, 230 insertions(+), 97 deletions(-) diff --git a/show/bgp_quagga_v4.py b/show/bgp_quagga_v4.py index 21444f3e2c..3eb3f4bc12 100644 --- a/show/bgp_quagga_v4.py +++ b/show/bgp_quagga_v4.py @@ -1,5 +1,5 @@ import click -from show.main import AliasedGroup, ip, run_command, +from show.main import AliasedGroup, ip, run_command from utilities_common.bgp_util import get_bgp_summary_extended diff --git a/show/bgp_quagga_v6.py b/show/bgp_quagga_v6.py index 73b9570d9d..9987588aa5 100644 --- a/show/bgp_quagga_v6.py +++ b/show/bgp_quagga_v6.py @@ -1,5 +1,5 @@ import click -from show.main import AliasedGroup, ipv6, run_command, +from show.main import AliasedGroup, ipv6, run_command from utilities_common.bgp_util import get_bgp_summary_extended diff --git a/show/main.py b/show/main.py index b94a522db7..bb6c517409 100755 --- a/show/main.py +++ b/show/main.py @@ -918,7 +918,7 @@ def protocol(verbose): ip.add_command(bgp) from .bgp_quagga_v6 import bgp ipv6.add_command(bgp) -else: +elif routing_stack == "frr": from .bgp_frr_v4 import bgp ip.add_command(bgp) from .bgp_frr_v6 import bgp diff --git a/tests/bgp_commands_test.py b/tests/bgp_commands_test.py index 64f25a2d70..b0ba0fcbd2 100644 --- a/tests/bgp_commands_test.py +++ b/tests/bgp_commands_test.py @@ -1,12 +1,14 @@ +import os + import pytest + from click.testing import CliRunner -import show.main as show -show_bgp_summary_v4="""\ +show_bgp_summary_v4 = """\ IPv4 Unicast Summary: BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0 -BGP table version 12811 +BGP table version 12811 RIB entries 12817, using 2358328 bytes of memory Peers 24, using 502080 KiB of memory Peer groups 4, using 256 bytes of memory @@ -40,11 +42,11 @@ 10.0.0.63 4 64016 0 0 0 0 0 never Active ARISTA16T0 """ -show_bgp_summary_v6="""\ +show_bgp_summary_v6 = """\ IPv6 Unicast Summary: BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0 -BGP table version 8972 +BGP table version 8972 RIB entries 12817, using 2358328 bytes of memory Peers 24, using 502080 KiB of memory Peer groups 4, using 256 bytes of memory @@ -77,23 +79,59 @@ fc00::76 4 64014 0 0 0 0 0 never Active ARISTA14T0 fc00::a 4 65200 6665 6671 0 0 0 2d09h38m 6402 ARISTA03T2 """ + +show_error_invalid_json = """\ +Usage: summary [OPTIONS] +Try 'summary --help' for help. + +Error: bgp summary from bgp container not in json format +""" + + class TestBgpCommands(object): @classmethod def setup_class(cls): print("SETUP") import mock_tables.dbconnector - @pytest.mark.parametrize('setup_single_bgp_instance', ['v4'], indirect=['setup_single_bgp_instance']) - def test_bgp_summary_v4(self, setup_single_bgp_instance): - #reload(show) + @pytest.mark.parametrize('setup_single_bgp_instance', + ['v4'], indirect=['setup_single_bgp_instance']) + def test_bgp_summary_v4( + self, + setup_bgp_commands, + setup_single_bgp_instance): + show = setup_bgp_commands runner = CliRunner() - result = runner.invoke(show.cli.commands["ip"].commands["bgp"].commands["summary"]) - print("Result : {}".format(result.output)) + result = runner.invoke( + show.cli.commands["ip"].commands["bgp"].commands["summary"], []) + print("{}".format(result.output)) + assert result.exit_code == 0 assert result.output == show_bgp_summary_v4 - @pytest.mark.parametrize('setup_single_bgp_instance', ['v6'], indirect=['setup_single_bgp_instance']) - def test_bgp_summary_v6(self, setup_single_bgp_instance): + @pytest.mark.parametrize('setup_single_bgp_instance', + ['v6'], indirect=['setup_single_bgp_instance']) + def test_bgp_summary_v6( + self, + setup_bgp_commands, + setup_single_bgp_instance): + show = setup_bgp_commands + runner = CliRunner() + result = runner.invoke( + show.cli.commands["ipv6"].commands["bgp"].commands["summary"], []) + print("{}".format(result.output)) + assert result.exit_code == 0 + assert result.output == show_bgp_summary_v6 + + @pytest.mark.parametrize('setup_single_bgp_instance', + [' '], indirect=['setup_single_bgp_instance']) + def test_bgp_summary_error( + self, + setup_bgp_commands, + setup_single_bgp_instance): + show = setup_bgp_commands runner = CliRunner() - result = runner.invoke(show.cli.commands["ipv6"].commands["bgp"].commands["summary"]) - print("Result : {}".format(result.output)) - assert result.output == show_bgp_summary_v6 \ No newline at end of file + result = runner.invoke( + show.cli.commands["ipv6"].commands["bgp"].commands["summary"], []) + print("{}".format(result.output)) + assert result.exit_code == 2 + assert result.output == show_error_invalid_json diff --git a/tests/conftest.py b/tests/conftest.py index a24fe68d55..4655ca208c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -49,6 +49,7 @@ 'snmp.timer', 'telemetry.timer'] + @pytest.fixture def get_cmd_module(): import config.main as config @@ -56,36 +57,51 @@ def get_cmd_module(): return (config, show) -@pytest.fixture -def get_show_module(): - import show.main as show - return show @pytest.fixture def setup_single_broacom_asic(): import config.main as config import show.main as show - device_info.get_num_npus = mock.MagicMock(return_value = 1) + device_info.get_num_npus = mock.MagicMock(return_value=1) config._get_sonic_generated_services = \ - mock.MagicMock(return_value = (generated_services_list, [])) + mock.MagicMock(return_value=(generated_services_list, [])) + + config.asic_type = mock.MagicMock(return_value="broadcom") + config._get_device_type = mock.MagicMock(return_value="ToRRouter") - config.asic_type = mock.MagicMock(return_value = "broadcom") - config._get_device_type = mock.MagicMock(return_value = "ToRRouter") @pytest.fixture -def setup_single_bgp_instance(monkeypatch, request): +def setup_single_bgp_instance(request): import utilities_common.bgp_util as bgp_util if request.param == 'v4': - bgp_summary_json = 'mock_tables/ipv4_bgp_summary.json' + bgp_summary_json = os.path.join( + test_path, 'mock_tables', 'ipv4_bgp_summary.json') + elif request.param == 'v6': + bgp_summary_json = os.path.join( + test_path, 'mock_tables', 'ipv6_bgp_summary.json') else: - bgp_summary_json = 'mock_tables/ipv6_bgp_summary.json' + bgp_summary_json = os.path.join( + test_path, 'mock_tables', 'dummy.json') def mock_run_bgp_command(vtysh_cmd, bgp_namespace): - with open(bgp_summary_json) as json_data: - mock_frr_data = json_data.read() - return mock_frr_data + if os.path.isfile(bgp_summary_json): + with open(bgp_summary_json) as json_data: + mock_frr_data = json_data.read() + return mock_frr_data + return "" - monkeypatch.setattr(bgp_util, "run_bgp_command", mock_run_bgp_command) + bgp_util.run_bgp_command = mock.MagicMock( + return_value=mock_run_bgp_command("", "")) + +@pytest.fixture +def setup_bgp_commands(): + import show.main as show + from show.bgp_frr_v4 import bgp as bgpv4 + from show.bgp_frr_v6 import bgp as bgpv6 + + show.ip.add_command(bgpv4) + show.ipv6.add_command(bgpv6) + return show diff --git a/utilities_common/bgp_util.py b/utilities_common/bgp_util.py index f0b71245c5..16e1627734 100644 --- a/utilities_common/bgp_util.py +++ b/utilities_common/bgp_util.py @@ -75,6 +75,7 @@ def get_bgp_neighbors_dict(namespace=multi_asic.DEFAULT_NAMESPACE): dynamic_neighbors = get_dynamic_neighbor_subnet(config_db) return static_neighbors, dynamic_neighbors + def get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors): """ return neighbor name for the ip provided @@ -87,15 +88,20 @@ def get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors): return static_neighbors[ip] elif is_ipv4_address(unicode(ip)): for subnet in dynamic_neighbors[constants.IPV4].keys(): - if ipaddress.IPv4Address(unicode(ip)) in ipaddress.IPv4Network(unicode(subnet)): + if ipaddress.IPv4Address( + unicode(ip)) in ipaddress.IPv4Network( + unicode(subnet)): return dynamic_neighbors[constants.IPV4][subnet] elif is_ipv6_address(unicode(ip)): for subnet in dynamic_neighbors[constants.IPV6].keys(): - if ipaddress.IPv6Address(unicode(ip)) in ipaddress.IPv6Network(unicode(subnet)): + if ipaddress.IPv6Address( + unicode(ip)) in ipaddress.IPv6Network( + unicode(subnet)): return dynamic_neighbors[constants.IPV6][subnet] else: return "NotAvailable" + def get_bgp_summary_extended(command_output): """ Adds Neighbor name to the show ip[v6] bgp summary command @@ -112,8 +118,11 @@ def get_bgp_summary_extended(command_output): modified_output.append(element) elif re.match(r"(\*?([0-9A-Fa-f]{1,4}:|\d+.\d+.\d+.\d+))", element.split()[0]): first_element = element.split()[0] - ip = first_element[1:] if first_element.startswith("*") else first_element - name = get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors) + ip = first_element[1:] if first_element.startswith( + "*") else first_element + name = get_bgp_neighbor_ip_to_name(ip, + static_neighbors, + dynamic_neighbors) if len(element.split()) == 1: modified_output.append(element) element = next(my_list) @@ -123,7 +132,8 @@ def get_bgp_summary_extended(command_output): modified_output.append(element) click.echo("\n".join(modified_output)) -def get_neighbor_dict_from_table(db,table_name): + +def get_neighbor_dict_from_table(db, table_name): """ returns a dict with bgp neighbor ip as key and neighbor name as value :param table_name: config db table name @@ -139,84 +149,153 @@ def get_neighbor_dict_from_table(db,table_name): except Exception: return neighbor_dict + def run_bgp_command(vtysh_cmd, bgp_namespace=multi_asic.DEFAULT_NAMESPACE): bgp_instance_id = ' ' - + output = None if bgp_namespace is not multi_asic.DEFAULT_NAMESPACE: bgp_instance_id = multi_asic.get_asic_id_from_name(bgp_namespace) - cmd = 'sudo docker exec bgp{} vtysh -c "{}"'.format(bgp_instance_id, vtysh_cmd) - output = clicommon.run_command(cmd, return_cmd=True) + cmd = 'sudo docker exec bgp{} vtysh -c "{}"'.format( + bgp_instance_id, vtysh_cmd) + try: + output = clicommon.run_command(cmd, return_cmd=True) + except Exception: + ctx = click.get_current_context() + ctx.fail("Unable to get summary from bgp".format(bgp_instance_id)) + return output -def get_bgp_summary_from_all_bgp_instances(af,namespace, display): + +def get_bgp_summary_from_all_bgp_instances(af, namespace, display): + device = multi_asic_util.MultiAsic(display, namespace) + ctx = click.get_current_context() if af is constants.IPV4: - vtysh_cmd = "show ip bgp summary json" - key = 'ipv4Unicast' + vtysh_cmd = "show ip bgp summary json" + key = 'ipv4Unicast' else: vtysh_cmd = "show bgp ipv6 summary json" key = 'ipv6Unicast' + bgp_summary = {} + cmd_output_json = {} for ns in device.get_ns_list_based_on_options(): - cmd_output = json.loads(run_bgp_command(vtysh_cmd, ns)) + cmd_output = run_bgp_command(vtysh_cmd, ns) + try: + cmd_output_json = json.loads(cmd_output) + except ValueError: + ctx.fail("bgp summary from bgp container not in json format") + + if key not in cmd_output_json: + ctx.fail("bgp summary from bgp container in invalid format") + device.current_namespace = ns - process_bgp_summary_json(bgp_summary, cmd_output[key], device) + + process_bgp_summary_json(bgp_summary, cmd_output_json[key], device) return bgp_summary def display_bgp_summary(bgp_summary, af): - headers = ["Neighbhor", "V", "AS", "MsgRcvd", "MsgSent", "TblVer", "InQ", "OutQ", "Up/Down", "State/PfxRcd", "NeighborName"] - click.echo("\nIP{} Unicast Summary:".format(af)) - for router_info in bgp_summary['router_info']: - for k in router_info.keys(): - v = router_info[k] - instance = "{}: ".format(k) if k is not "" else "" - click.echo("{}BGP router identifier {}, local AS number {} vrf-id {}"\ - .format(instance, v['router_id'], v['as'], v['vrf'] )) - click.echo("BGP table version {} ".format(v['tbl_ver'])) - click.echo("RIB entries {}, using {} bytes of memory".format(bgp_summary['ribCount'], bgp_summary['ribMemory'])) - click.echo("Peers {}, using {} KiB of memory".format(bgp_summary['peerCount'], bgp_summary['peerMemory']) ) - click.echo("Peer groups {}, using {} bytes of memory".format(bgp_summary['peerGroupCount'], bgp_summary['peerGroupMemory'])) - click.echo("\n") - click.echo(tabulate(natsorted(bgp_summary['peers']), headers = headers)) + ''' + Display the json output in the format display by FRR + + Args: + bgp_summary ([dict]): [Bgp summary from all bgp instances in ] + af: IPV4 or IPV6 + + ''' + headers = ["Neighbhor", "V", "AS", "MsgRcvd", "MsgSent", "TblVer", + "InQ", "OutQ", "Up/Down", "State/PfxRcd", "NeighborName"] + + try: + click.echo("\nIP{} Unicast Summary:".format(af)) + # display the bgp instance information + for router_info in bgp_summary['router_info']: + for k in router_info.keys(): + v = router_info[k] + instance = "{}: ".format(k) if k is not "" else "" + click.echo( + "{}BGP router identifier {}, local AS number {} vrf-id {}" .format( + instance, v['router_id'], v['as'], v['vrf'])) + click.echo("BGP table version {}".format(v['tbl_ver'])) + + click.echo("RIB entries {}, using {} bytes of memory" + .format(bgp_summary['ribCount'], bgp_summary['ribMemory'])) + click.echo( + "Peers {}, using {} KiB of memory" .format( + bgp_summary['peerCount'], + bgp_summary['peerMemory'])) + click.echo("Peer groups {}, using {} bytes of memory" .format( + bgp_summary['peerGroupCount'], bgp_summary['peerGroupMemory'])) + click.echo("\n") + + click.echo(tabulate(natsorted(bgp_summary['peers']), headers=headers)) + except KeyError as e: + ctx = click.get_current_context() + ctx.fail("{} missing in the bgp_summary".format(e.args[0])) + def process_bgp_summary_json(bgp_summary, cmd_output, device): - static_neighbors, dynamic_neighbors = get_bgp_neighbors_dict(device.current_namespace) - bgp_summary['peerCount'] = bgp_summary.get('peerCount', 0) + cmd_output['peerCount'] - bgp_summary['peerMemory'] = bgp_summary.get('peerMemory', 0) + cmd_output['peerMemory'] - bgp_summary['ribCount'] = bgp_summary.get('ribCount', 0) + cmd_output['ribCount'] - bgp_summary['ribMemory'] = bgp_summary.get('ribMemory', 0) + cmd_output['ribMemory'] - bgp_summary['peerGroupCount'] = bgp_summary.get('peerGroupCount', 0) + cmd_output['peerGroupCount'] - bgp_summary['peerGroupMemory'] = bgp_summary.get('peerGroupMemory', 0) + cmd_output['peerGroupMemory'] - - router_info = {} - router_info['router_id'] = cmd_output['routerId'] - router_info['vrf'] = cmd_output['vrfId'] - router_info['as'] = cmd_output['as'] - router_info['tbl_ver'] = cmd_output['tableVersion'] - bgp_summary.setdefault('router_info', []).append({device.current_namespace: router_info}) - - for peer_ip, value in cmd_output['peers'].iteritems(): - peers = [] - if device.skip_display(constants.BGP_NEIGH_OBJ, peer_ip): - continue - - peers.append(peer_ip) - neigh_name = get_bgp_neighbor_ip_to_name(peer_ip, static_neighbors, dynamic_neighbors) - peers.append( value['version']) - peers.append(value['remoteAs']) - peers.append(value['msgRcvd']) - peers.append(value['msgSent']) - peers.append(value['tableVersion']) - - peers.append(value['inq']) - peers.append(value['outq']) - peers.append(value['peerUptime']) - if value['state'] == 'Established': - peers.append(value['pfxRcd']) - else: - peers.append(value['state']) + ''' + This function process the frr output in json format from a bgp + instance and stores the need values in the a bgp_summary + + ''' + static_neighbors, dynamic_neighbors = get_bgp_neighbors_dict( + device.current_namespace) + try: + # add all the router level fields + bgp_summary['peerCount'] = bgp_summary.get( + 'peerCount', 0) + cmd_output['peerCount'] + bgp_summary['peerMemory'] = bgp_summary.get( + 'peerMemory', 0) + cmd_output['peerMemory'] + bgp_summary['ribCount'] = bgp_summary.get( + 'ribCount', 0) + cmd_output['ribCount'] + bgp_summary['ribMemory'] = bgp_summary.get( + 'ribMemory', 0) + cmd_output['ribMemory'] + bgp_summary['peerGroupCount'] = bgp_summary.get( + 'peerGroupCount', 0) + cmd_output['peerGroupCount'] + bgp_summary['peerGroupMemory'] = bgp_summary.get( + 'peerGroupMemory', 0) + cmd_output['peerGroupMemory'] + + #store instance level field is seperate dict + router_info = {} + router_info['router_id'] = cmd_output['routerId'] + router_info['vrf'] = cmd_output['vrfId'] + router_info['as'] = cmd_output['as'] + router_info['tbl_ver'] = cmd_output['tableVersion'] + bgp_summary.setdefault('router_info', []).append( + {device.current_namespace: router_info}) + + # store all the peers in the list + for peer_ip, value in cmd_output['peers'].iteritems(): + peers = [] + # if display option is 'frontend', internal bgp neighbors will not + # be displayed + if device.skip_display(constants.BGP_NEIGH_OBJ, peer_ip): + continue + + peers.append(peer_ip) + peers.append(value['version']) + peers.append(value['remoteAs']) + peers.append(value['msgRcvd']) + peers.append(value['msgSent']) + peers.append(value['tableVersion']) + peers.append(value['inq']) + peers.append(value['outq']) + peers.append(value['peerUptime']) + if value['state'] == 'Established': + peers.append(value['pfxRcd']) + else: + peers.append(value['state']) + + # Get the bgp neighbour name ans store it + neigh_name = get_bgp_neighbor_ip_to_name( + peer_ip, static_neighbors, dynamic_neighbors) + peers.append(neigh_name) - peers.append(neigh_name) - bgp_summary.setdefault('peers', []).append(peers) + bgp_summary.setdefault('peers', []).append(peers) + except KeyError as e: + ctx = click.get_current_context() + ctx.fail("{} missing in the bgp_summary".format(e.args[0])) From 2f4f9951bb1db7a3377fedfc1186bff9921723bb Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Mon, 24 Aug 2020 14:06:41 -0700 Subject: [PATCH 3/3] fix import Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- show/bgp_frr_v4.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/show/bgp_frr_v4.py b/show/bgp_frr_v4.py index e369056472..0b06727ce7 100644 --- a/show/bgp_frr_v4.py +++ b/show/bgp_frr_v4.py @@ -1,14 +1,12 @@ import json -from utilities_common import constants -from utilities_common import bgp_util -import click -import utilities_common.cli as clicommon +import click -from show.main import ip, run_command -import utilities_common.multi_asic as multi_asic_util import utilities_common.bgp_util as bgp_util +import utilities_common.cli as clicommon import utilities_common.constants as constants +import utilities_common.multi_asic as multi_asic_util +from show.main import ip, run_command ############################################################################### #