diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index 8938e3577da6..50b691365c62 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -1354,6 +1354,26 @@ This command displays the summary of all IPv4 & IPv6 bgp neighbors that are conf show ip bgp summary ``` +- Example: + ``` + admin@sonic-z9264f-9251:~# show ip bgp summary + + IPv4 Unicast Summary: + BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0 + BGP table version 6465 + RIB entries 12807, using 2001 KiB of memory + Peers 4, using 83 KiB of memory + Peer groups 2, using 128 bytes of memory + + Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName + 10.0.0.57 4 64600 3995 4001 0 0 0 00:39:32 6400 Lab-T1-01 + 10.0.0.59 4 64600 3995 3998 0 0 0 00:39:32 6400 Lab-T1-02 + 10.0.0.61 4 64600 3995 4001 0 0 0 00:39:32 6400 Lab-T1-03 + 10.0.0.63 4 64600 3995 3998 0 0 0 00:39:32 6400 NotAvailable + + Total number of neighbors 4 + ``` + - Example: ``` admin@sonic-z9264f-9251:~# show bgp summary @@ -1515,11 +1535,11 @@ This command displays the summary of all IPv6 bgp neighbors that are configured Peers 4, using 83 KiB of memory Peer groups 2, using 128 bytes of memory - Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd - fc00::72 4 64600 3995 5208 0 0 0 00:39:30 6400 - fc00::76 4 64600 3994 5208 0 0 0 00:39:30 6400 - fc00::7a 4 64600 3993 5208 0 0 0 00:39:30 6400 - fc00::7e 4 64600 3993 5208 0 0 0 00:39:30 6400 + Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName + fc00::72 4 64600 3995 5208 0 0 0 00:39:30 6400 Lab-T1-01 + fc00::76 4 64600 3994 5208 0 0 0 00:39:30 6400 Lab-T1-02 + fc00::7a 4 64600 3993 5208 0 0 0 00:39:30 6400 Lab-T1-03 + fc00::7e 4 64600 3993 5208 0 0 0 00:39:30 6400 Lab-T1-04 Total number of neighbors 4 ``` diff --git a/show/bgp_frr_v6.py b/show/bgp_frr_v6.py index 47c66aaed0f0..9ff2ded3b645 100644 --- a/show/bgp_frr_v6.py +++ b/show/bgp_frr_v6.py @@ -19,7 +19,11 @@ def bgp(): @bgp.command() def summary(): """Show summarized information of IPv6 BGP state""" - run_command('sudo vtysh -c "show bgp ipv6 summary"') + try: + device_output = run_command('sudo vtysh -c "show bgp ipv6 summary"', return_cmd=True) + get_bgp_summary_extended(device_output) + except: + run_command('sudo vtysh -c "show bgp ipv6 summary"') # 'neighbors' subcommand ("show ipv6 bgp neighbors") diff --git a/show/bgp_quagga_v4.py b/show/bgp_quagga_v4.py index d543b6a1b95b..4883880682e1 100644 --- a/show/bgp_quagga_v4.py +++ b/show/bgp_quagga_v4.py @@ -19,7 +19,11 @@ def bgp(): @bgp.command() def summary(): """Show summarized information of IPv4 BGP state""" - run_command('sudo vtysh -c "show ip bgp summary"') + try: + device_output = run_command('sudo vtysh -c "show ip bgp summary"', return_cmd=True) + get_bgp_summary_extended(device_output) + except: + run_command('sudo vtysh -c "show ip bgp summary"') # 'neighbors' subcommand ("show ip bgp neighbors") diff --git a/show/bgp_quagga_v6.py b/show/bgp_quagga_v6.py index 06ef6a4df817..e2afe0f13e64 100644 --- a/show/bgp_quagga_v6.py +++ b/show/bgp_quagga_v6.py @@ -19,7 +19,11 @@ def bgp(): @bgp.command() def summary(): """Show summarized information of IPv6 BGP state""" - run_command('sudo vtysh -c "show ipv6 bgp summary"') + try: + device_output = run_command('sudo vtysh -c "show ipv6 bgp summary"', return_cmd=True) + get_bgp_summary_extended(device_output) + except: + run_command('sudo vtysh -c "show ipv6 bgp summary"') # 'neighbors' subcommand ("show ipv6 bgp neighbors") diff --git a/show/main.py b/show/main.py index d452bc1d842e..e7314698e2d3 100755 --- a/show/main.py +++ b/show/main.py @@ -8,6 +8,7 @@ import re import subprocess import sys +import ipaddr import click from click_default_group import DefaultGroup @@ -188,7 +189,7 @@ def get_routing_stack(): routing_stack = get_routing_stack() -def run_command(command, display_cmd=False): +def run_command(command, display_cmd=False, return_cmd=False): if display_cmd: click.echo(click.style("Command: ", fg='cyan') + click.style(command, fg='green')) @@ -201,6 +202,9 @@ def run_command(command, display_cmd=False): proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) while True: + if return_cmd: + output = proc.communicate()[0].decode("utf-8") + return output output = proc.stdout.readline() if output == "" and proc.poll() is not None: break @@ -393,6 +397,146 @@ def run_command_in_alias_mode(command): sys.exit(rc) +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(): + """ + Connects to config_db + """ + config_db = ConfigDBConnector() + config_db.connect() + 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: + 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: + 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', '-?']) #