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][BGP] Show BGP Change for no neighbor scenario #2885

Merged
Merged
Show file tree
Hide file tree
Changes from 7 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
36 changes: 30 additions & 6 deletions tests/bgp_commands_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,35 @@
"""

show_error_no_v6_neighbor = """\
No IPv6 neighbor is configured

IPv6 Unicast Summary:
BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0
BGP table version 8972
RIB entries 0, using 0 bytes of memory
Peers 0, using 0 KiB of memory
Peer groups 0, using 0 bytes of memory


Neighbhor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName
----------- --- ---- --------- --------- -------- ----- ------ --------- -------------- --------------

Total number of neighbors 0
"""

show_error_no_v4_neighbor = """\
No IPv4 neighbor is configured

developfast marked this conversation as resolved.
Show resolved Hide resolved
IPv4 Unicast Summary:
BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0
BGP table version 8972
RIB entries 0, using 0 bytes of memory
Peers 0, using 0 KiB of memory
Peer groups 0, using 0 bytes of memory


Neighbhor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName
----------- --- ---- --------- --------- -------- ----- ------ --------- -------------- --------------

Total number of neighbors 0
"""

show_bgp_summary_v4_chassis = """\
Expand Down Expand Up @@ -337,10 +361,10 @@ def test_bgp_summary_no_v4_neigh(
show = setup_bgp_commands
runner = CliRunner()
result = runner.invoke(
show.cli.commands["ipv6"].commands["bgp"].commands["summary"], [])
show.cli.commands["ip"].commands["bgp"].commands["summary"], [])
print("{}".format(result.output))
assert result.exit_code == 0
assert result.output == show_error_no_v6_neighbor
assert result.output == show_error_no_v4_neighbor

@pytest.mark.parametrize('setup_single_bgp_instance',
['show_bgp_summary_no_neigh'], indirect=['setup_single_bgp_instance'])
Expand All @@ -351,7 +375,7 @@ def test_bgp_summary_no_v6_neigh(
show = setup_bgp_commands
runner = CliRunner()
result = runner.invoke(
show.cli.commands["ip"].commands["bgp"].commands["summary"], [])
show.cli.commands["ipv6"].commands["bgp"].commands["summary"], [])
print("{}".format(result.output))
assert result.exit_code == 0
assert result.output == show_error_no_v4_neighbor
assert result.output == show_error_no_v6_neighbor
35 changes: 19 additions & 16 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ def setup_single_bgp_instance(request):
elif request.param == 'v6':
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'ipv6_bgp_summary.json')
elif request.param == 'show_bgp_summary_no_neigh':
bgp_neigh_mocked_json = os.path.join(
test_path, 'mock_tables', 'no_bgp_neigh.json')
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'device_bgp_info.json')
elif request.param == 'show_run_bgp':
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'show_run_bgp.txt')
Expand All @@ -187,12 +192,9 @@ def setup_single_bgp_instance(request):
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'dummy.json')

def mock_show_bgp_summary_no_neigh(vtysh_cmd, bgp_namespace, vtysh_shell_cmd=constants.RVTYSH_COMMAND):
return "{}"

def mock_show_bgp_summary(vtysh_cmd, bgp_namespace, vtysh_shell_cmd=constants.RVTYSH_COMMAND):
if os.path.isfile(bgp_mocked_json):
with open(bgp_mocked_json) as json_data:
def mock_run_bgp_command(mock_bgp_file):
if os.path.isfile(mock_bgp_file):
with open(mock_bgp_file) as json_data:
mock_frr_data = json_data.read()
return mock_frr_data
return ""
Expand All @@ -218,7 +220,7 @@ def mock_run_show_ip_route_commands(request):
else:
return ""

def mock_run_bgp_command(vtysh_cmd, bgp_namespace, vtysh_shell_cmd=constants.RVTYSH_COMMAND):
def mock_run_bgp_route_command(vtysh_cmd, bgp_namespace, vtysh_shell_cmd=constants.RVTYSH_COMMAND):
bgp_mocked_json_file = os.path.join(
test_path, 'mock_tables', bgp_mocked_json)
if os.path.isfile(bgp_mocked_json_file):
Expand All @@ -229,11 +231,11 @@ def mock_run_bgp_command(vtysh_cmd, bgp_namespace, vtysh_shell_cmd=constants.RVT
return ""

_old_run_bgp_command = bgp_util.run_bgp_command
if any ([request.param == 'ip_route',\
request.param == 'ip_specific_route', request.param == 'ip_special_route',\
request.param == 'ipv6_route', request.param == 'ipv6_specific_route']):
if any([request.param == 'ip_route',
request.param == 'ip_specific_route', request.param == 'ip_special_route',
request.param == 'ipv6_route', request.param == 'ipv6_specific_route']):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_run_bgp_command("",""))
return_value=mock_run_bgp_route_command("", ""))
elif request.param.startswith('ipv6_route_err'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_run_show_ip_route_commands(request))
Expand All @@ -242,20 +244,21 @@ def mock_run_bgp_command(vtysh_cmd, bgp_namespace, vtysh_shell_cmd=constants.RVT
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_bgp_neighbor_single_asic(request))
elif request.param.startswith('bgp_v4_network') or \
request.param.startswith('bgp_v6_network'):
request.param.startswith('bgp_v6_network'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_bgp_network_single_asic(request))
elif request.param == 'ip_route_for_int_ip':
bgp_util.run_bgp_command = mock_run_bgp_command_for_static
elif request.param == "show_bgp_summary_no_neigh":
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_bgp_summary_no_neigh("", ""))
elif request.param.startswith('show_run_bgp'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_run_bgp(request))
elif request.param == 'show_bgp_summary_no_neigh':
functions_to_call = [mock_run_bgp_command(bgp_neigh_mocked_json), mock_run_bgp_command(bgp_mocked_json)]
bgp_util.run_bgp_command = mock.MagicMock(
side_effect=functions_to_call)
else:
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_bgp_summary("", ""))
return_value=mock_run_bgp_command(bgp_mocked_json))

yield

Expand Down
30 changes: 30 additions & 0 deletions tests/mock_tables/device_bgp_info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"vrfId": 0,
"vrfName": "default",
"tableVersion": 8972,
"routerId": "10.1.0.32",
"defaultLocPrf": 100,
"localAS": 65100,
"routes": { "10.1.0.32/32": [
{
"valid":true,
"bestpath":true,
"pathFrom":"external",
"prefix":"10.1.0.32",
"prefixLen":32,
"network":"10.1.0.32\/32",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"0.0.0.0",
"hostname":"STR-8102-C19-U24",
"afi":"ipv4",
"used":true
}
]
}
] } }
1 change: 1 addition & 0 deletions tests/mock_tables/no_bgp_neigh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
125 changes: 75 additions & 50 deletions utilities_common/bgp_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def run_bgp_command(vtysh_cmd, bgp_namespace=multi_asic.DEFAULT_NAMESPACE, vtysh

return output


def run_bgp_show_command(vtysh_cmd, bgp_namespace=multi_asic.DEFAULT_NAMESPACE):
output = run_bgp_command(vtysh_cmd, bgp_namespace, constants.RVTYSH_COMMAND)
# handle the the alias mode in the following code
Expand All @@ -214,6 +215,7 @@ def run_bgp_show_command(vtysh_cmd, bgp_namespace=multi_asic.DEFAULT_NAMESPACE):
output= json.dumps(route_info)
return output


def get_bgp_summary_from_all_bgp_instances(af, namespace, display):

device = multi_asic_util.MultiAsic(display, namespace)
Expand All @@ -227,21 +229,30 @@ def get_bgp_summary_from_all_bgp_instances(af, namespace, display):

bgp_summary = {}
cmd_output_json = {}

for ns in device.get_ns_list_based_on_options():
has_bgp_neighbors = False
cmd_output = run_bgp_show_command(vtysh_cmd, ns)
device.current_namespace = ns
try:
cmd_output_json = json.loads(cmd_output)
if cmd_output_json:
has_bgp_neighbors = True
except ValueError:
ctx.fail("bgp summary from bgp container not in json format")

# exit cli command without printing the error message
if key not in cmd_output_json:
click.echo("No IP{} neighbor is configured".format(af))
exit()
# no bgp neighbors found so print basic device bgp info
if key not in cmd_output_json or not has_bgp_neighbors:
vtysh_cmd = "show ip bgp json"
developfast marked this conversation as resolved.
Show resolved Hide resolved
no_neigh_cmd_output = run_bgp_show_command(vtysh_cmd, ns)
try:
no_neigh_cmd_output_json = json.loads(no_neigh_cmd_output)
except ValueError:
ctx.fail("bgp summary from bgp container not in json format")

device.current_namespace = ns
out_cmd = cmd_output_json[key] if has_bgp_neighbors else no_neigh_cmd_output_json
process_bgp_summary_json(bgp_summary, out_cmd, device, has_bgp_neighbors=has_bgp_neighbors)

process_bgp_summary_json(bgp_summary, cmd_output_json[key], device)
return bgp_summary


Expand All @@ -263,7 +274,7 @@ def display_bgp_summary(bgp_summary, af):
for router_info in bgp_summary['router_info']:
for k in router_info:
v = router_info[k]
instance = "{}: ".format(k) if k is not "" else ""
instance = "{}: ".format(k) if k != "" else ""
click.echo(
"{}BGP router identifier {}, local AS number {} vrf-id {}" .format(
instance, v['router_id'], v['as'], v['vrf']))
Expand All @@ -287,66 +298,80 @@ def display_bgp_summary(bgp_summary, af):
ctx.fail("{} missing in the bgp_summary".format(e.args[0]))


def process_bgp_summary_json(bgp_summary, cmd_output, device):
def process_bgp_summary_json(bgp_summary, cmd_output, device, has_bgp_neighbors=True):
'''
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)
if has_bgp_neighbors:
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']
if has_bgp_neighbors:
# when there are bgp neighbors, fill information from the dict
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']
else:
# when there are no bgp neighbors, all values are zero
bgp_summary['peerCount'] = 0
bgp_summary['peerMemory'] = 0
bgp_summary['ribCount'] = 0
bgp_summary['ribMemory'] = 0
bgp_summary['peerGroupCount'] = 0
bgp_summary['peerGroupMemory'] = 0

# 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['as'] = cmd_output['as'] if has_bgp_neighbors else cmd_output['localAS']
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'].items():
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)

bgp_summary.setdefault('peers', []).append(peers)
if has_bgp_neighbors:
for peer_ip, value in cmd_output['peers'].items():
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)

bgp_summary.setdefault('peers', []).append(peers)
else:
bgp_summary['peers'] = []
except KeyError as e:
ctx = click.get_current_context()
ctx.fail("{} missing in the bgp_summary".format(e.args[0]))