Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[show] enhance 'show ip[v6] bgp summary' command #754

Merged
merged 6 commits into from
Jan 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,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
Expand Down Expand Up @@ -1512,11 +1532,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
rvisnu marked this conversation as resolved.
Show resolved Hide resolved
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
```
Expand Down
6 changes: 5 additions & 1 deletion show/bgp_frr_v6.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
6 changes: 5 additions & 1 deletion show/bgp_quagga_v4.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
6 changes: 5 additions & 1 deletion show/bgp_quagga_v6.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
pavel-shirshov marked this conversation as resolved.
Show resolved Hide resolved
run_command('sudo vtysh -c "show ipv6 bgp summary"')


# 'neighbors' subcommand ("show ipv6 bgp neighbors")
Expand Down
146 changes: 145 additions & 1 deletion show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import re
import subprocess
import sys
import ipaddr

import click
from click_default_group import DefaultGroup
Expand Down Expand Up @@ -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'))

Expand All @@ -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
Expand Down Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel safe with next() here. I'm not sure it's a good practice.

Copy link
Contributor Author

@rvisnu rvisnu Nov 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

element = next(my_list)
The show ipv6 bgp summary command output have ipv6 address in one line and the other datas in second line.

acb0::10:182:1:10e
                4 64802     548     546        0    0    0 08:59:22        7

as the motive of this PR is to add the Neighbor Name at the end of default data, we have to move to the line and append at the end. That is the reason I chose the next method.

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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you open that connection only once?
Otherwise you'll open a connection for every neighbor

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed in next iteration

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', '-?'])

#
Expand Down