Skip to content

Commit

Permalink
fix errors of "show ip bgp summary" and "show ip bgp neigh" under alias
Browse files Browse the repository at this point in the history
In alias mode, the output of "show ip/ipv6 bgp summary" and "show ip/ipv6
bgp neigh" return errors. This PR is used to fix these errors.
  • Loading branch information
JoshYangEC committed Jul 30, 2024
1 parent a813215 commit fe5791a
Show file tree
Hide file tree
Showing 7 changed files with 291 additions and 16 deletions.
90 changes: 90 additions & 0 deletions tests/bgp_commands_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,42 @@
Total number of neighbors 24
"""

show_bgp_summary_alias_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 2, using 502080 KiB of memory
Peer groups 1, using 256 bytes of memory
Neighbhor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName
----------- --- ----- --------- --------- -------- ----- ------ --------- -------------- --------------
etp1 4 65200 5919 2717 0 0 0 1d21h11m 6402 NotAvailable
etp2 4 65200 5916 2714 0 0 0 1d21h10m 6402 NotAvailable
Total number of neighbors 2
"""

show_bgp_summary_alias_v6 = """\
IPv6 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 2, using 502080 KiB of memory
Peer groups 1, using 256 bytes of memory
Neighbhor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd NeighborName
----------- --- ----- --------- --------- -------- ----- ------ --------- -------------- --------------
etp1 4 65200 5919 2717 0 0 0 1d21h11m 6402 NotAvailable
etp2 4 65200 5916 2714 0 0 0 1d21h10m 6402 NotAvailable
Total number of neighbors 2
"""

show_bgp_summary_v6 = """\
IPv6 Unicast Summary:
Expand Down Expand Up @@ -362,6 +398,60 @@ def test_bgp_summary_v4(
assert result.exit_code == 0
assert result.output == show_bgp_summary_v4

@pytest.mark.parametrize('setup_single_bgp_instance',
['alias_v4'], indirect=['setup_single_bgp_instance'])
def test_bgp_summary_alias_v4(
self,
setup_bgp_commands,
setup_single_bgp_instance):
show = setup_bgp_commands
runner = CliRunner()
os.environ['SONIC_CLI_IFACE_MODE'] = "alias"
result = runner.invoke(
show.cli.commands["ip"].commands["bgp"].commands["summary"], [])
os.environ['SONIC_CLI_IFACE_MODE'] = "default"
print("{}".format(result.output))
assert result.exit_code == 0
assert result.output == show_bgp_summary_alias_v4

@pytest.mark.parametrize('setup_single_bgp_instance',
['alias_v6'], indirect=['setup_single_bgp_instance'])
def test_bgp_summary_alias_v6(
self,
setup_bgp_commands,
setup_single_bgp_instance):
show = setup_bgp_commands
runner = CliRunner()
os.environ['SONIC_CLI_IFACE_MODE'] = "alias"
result = runner.invoke(
show.cli.commands["ipv6"].commands["bgp"].commands["summary"], [])
os.environ['SONIC_CLI_IFACE_MODE'] = "default"
print("{}".format(result.output))
assert result.exit_code == 0
assert result.output == show_bgp_summary_alias_v6

@pytest.mark.parametrize('setup_single_bgp_instance',
['alias_empty'], indirect=['setup_single_bgp_instance'])
def test_bgp_summary_alias_empty(
self,
setup_bgp_commands,
setup_single_bgp_instance):
show = setup_bgp_commands
runner = CliRunner()
os.environ['SONIC_CLI_IFACE_MODE'] = "alias"
result = runner.invoke(
show.cli.commands["ip"].commands["bgp"].commands["summary"], [])
os.environ['SONIC_CLI_IFACE_MODE'] = "default"
print("{}".format(result.output))
assert result.exit_code == 2

os.environ['SONIC_CLI_IFACE_MODE'] = "alias"
result = runner.invoke(
show.cli.commands["ipv6"].commands["bgp"].commands["summary"], [])
os.environ['SONIC_CLI_IFACE_MODE'] = "default"
print("{}".format(result.output))
assert result.exit_code == 2

@pytest.mark.parametrize('setup_single_bgp_instance',
['v6'], indirect=['setup_single_bgp_instance'])
def test_bgp_summary_v6(
Expand Down
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,15 @@ def setup_single_bgp_instance(request):
if request.param == 'v4':
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'ipv4_bgp_summary.json')
elif request.param == 'alias_v4':
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'ipv4_bgp_summary_alias.json')
elif request.param == 'alias_v6':
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'ipv6_bgp_summary_alias.json')
elif request.param == 'alias_empty':
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'ip_bgp_summary_alias_empty.json')
elif request.param == 'v6':
bgp_mocked_json = os.path.join(
test_path, 'mock_tables', 'ipv6_bgp_summary.json')
Expand Down
1 change: 1 addition & 0 deletions tests/mock_tables/ip_bgp_summary_alias_empty.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
61 changes: 61 additions & 0 deletions tests/mock_tables/ipv4_bgp_summary_alias.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"ipv4Unicast":{
"routerId":"10.1.0.32",
"as":65100,
"vrfId":0,
"vrfName":"default",
"tableVersion":12811,
"ribCount":12817,
"ribMemory":2358328,
"peerCount":2,
"peerMemory":502080,
"peerGroupCount":1,
"peerGroupMemory":256,
"peers":{
"Ethernet0":{
"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":"interface"
},
"Ethernet4":{
"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":"interface"
}
},
"failedPeers":0,
"totalPeers":2,
"dynamicPeers":0,
"bestPath":{
"multiPathRelax":"true"
}
}
}
61 changes: 61 additions & 0 deletions tests/mock_tables/ipv6_bgp_summary_alias.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"ipv6Unicast":{
"routerId":"10.1.0.32",
"as":65100,
"vrfId":0,
"vrfName":"default",
"tableVersion":12811,
"ribCount":12817,
"ribMemory":2358328,
"peerCount":2,
"peerMemory":502080,
"peerGroupCount":1,
"peerGroupMemory":256,
"peers":{
"Ethernet0":{
"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":"interface"
},
"Ethernet4":{
"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":"interface"
}
},
"failedPeers":0,
"totalPeers":2,
"dynamicPeers":0,
"bestPath":{
"multiPathRelax":"true"
}
}
}
81 changes: 67 additions & 14 deletions utilities_common/bgp_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,24 +217,77 @@ def run_bgp_command(vtysh_cmd, bgp_namespace=multi_asic.DEFAULT_NAMESPACE,
return output


def get_alias_route_converter(vtysh_output):
iface_alias_converter = clicommon.InterfaceAliasConverter()
route_info =json.loads(vtysh_output)
for route, info in route_info.items():
for i in range(0, len(info)):
if 'nexthops' in info[i]:
for j in range(0, len(info[i]['nexthops'])):
intf_name = ""
if 'interfaceName' in info[i]['nexthops'][j]:
intf_name = info[i]['nexthops'][j]['interfaceName']
alias = iface_alias_converter.name_to_alias(intf_name)
if alias is not None:
info[i]['nexthops'][j]['interfaceName'] = alias
output= json.dumps(route_info)
return output

def get_alias_bgp_summary_converter(key):
def converter(vtysh_output):
iface_alias_converter = clicommon.InterfaceAliasConverter()
cmd_json_output =json.loads(vtysh_output)

if cmd_json_output:
for iface_name in list(cmd_json_output[key]['peers'].keys()):
port_alias = iface_alias_converter.name_to_alias(iface_name)
if port_alias is not None:
cmd_json_output[key]['peers'][port_alias] = cmd_json_output[key]['peers'].pop(iface_name)
return json.dumps(cmd_json_output)
return converter

def get_alias_neighbor_converter(vtysh_output):
iface_alias_converter = clicommon.InterfaceAliasConverter()
output = ""
for vtysh_line in vtysh_output.split("\n"):
m = re.match(r'^BGP neighbor on (Ethernet[0-9]*):', vtysh_line)

if m:
iface_name = m[1]
port_alias = iface_alias_converter.name_to_alias(iface_name)
output += vtysh_line.replace(iface_name, port_alias) + "\n"
else:
output += vtysh_line + "\n"
return output

vtysh_alias_dict = {
"show (ip|ipv6) route": get_alias_route_converter,
"show ip bgp summary": lambda vtysh_output: get_alias_bgp_summary_converter('ipv4Unicast')(vtysh_output),
"show bgp ipv6 summary": lambda vtysh_output: get_alias_bgp_summary_converter('ipv6Unicast')(vtysh_output),
"show (ip bgp|bgp ipv6) neighbor": get_alias_neighbor_converter,
"show ip bgp json": None
}

def is_vtysh_cmd(vtysh_cmd):
return any(re.search(cmd_key, vtysh_cmd) for cmd_key in vtysh_alias_dict)

def get_vtysh_alias_converter(vtysh_output, vtysh_cmd):
for cmd_key, vtysh_alias_fun in vtysh_alias_dict.items():
if re.search(cmd_key, vtysh_cmd):
if vtysh_alias_fun is None:
return vtysh_output
return vtysh_alias_fun(vtysh_output)
return vtysh_output

def run_bgp_show_command(vtysh_cmd, bgp_namespace=multi_asic.DEFAULT_NAMESPACE, exit_on_fail=True):
output = run_bgp_command(vtysh_cmd, bgp_namespace, constants.RVTYSH_COMMAND, exit_on_fail)
# handle the the alias mode in the following code
if output == '':
return ''

if output is not None:
if clicommon.get_interface_naming_mode() == "alias" and re.search("show ip|ipv6 route", vtysh_cmd):
iface_alias_converter = clicommon.InterfaceAliasConverter()
route_info =json.loads(output)
for route, info in route_info.items():
for i in range(0, len(info)):
if 'nexthops' in info[i]:
for j in range(0, len(info[i]['nexthops'])):
intf_name = ""
if 'interfaceName' in info[i]['nexthops'][j]:
intf_name = info[i]['nexthops'][j]['interfaceName']
alias = iface_alias_converter.name_to_alias(intf_name)
if alias is not None:
info[i]['nexthops'][j]['interfaceName'] = alias
output= json.dumps(route_info)
if clicommon.get_interface_naming_mode() == "alias":
output = get_vtysh_alias_converter(output, vtysh_cmd)
return output


Expand Down
4 changes: 2 additions & 2 deletions utilities_common/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import json
import lazy_object_proxy
import netaddr
import utilities_common.bgp_util as bgp_util

from natsort import natsorted
from sonic_py_common import multi_asic
Expand Down Expand Up @@ -729,8 +730,7 @@ def run_command(command, display_cmd=False, ignore_error=False, return_cmd=False
# both SONiC interface name and alias name for all interfaces.
# IP route table cannot be handled in function run_command_in_alias_mode since it is in JSON format
# with a list for next hops
if (get_interface_naming_mode() == "alias" and not command_str.startswith("intfutil") and not re.search(
"show ip|ipv6 route", command_str)):
if (get_interface_naming_mode() == "alias" and not command_str.startswith("intfutil") and not bgp_util.is_vtysh_cmd(command_str)):
return run_command_in_alias_mode(command, shell=shell)

proc = subprocess.Popen(command, shell=shell, text=True, stdout=subprocess.PIPE)
Expand Down

0 comments on commit fe5791a

Please sign in to comment.