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

Enable show ip bgp on sup and -n all for show ip bgp network (#3417) #85

Merged
merged 1 commit into from
Jul 26, 2024
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,20 @@ A convenient alternative is to let the SONiC build system configure a build envi
```
python3 setup.py bdist_wheel
```
Note: This command by default will not update the wheel package in target/. To specify the destination location of wheel package, use "-d" option.

#### To run unit tests

```
python3 setup.py test
```

#### To install the package on a SONiC machine
```
sudo pip uninstall sonic-utilities
sudo pip install YOUR_WHEEL_PACKAGE
```
Note: Don't use "--force-reinstall".

### sonic-utilities-data

Expand Down
14 changes: 12 additions & 2 deletions rcli/linecard.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import termios
import tty

from .utils import get_linecard_ip
from .utils import get_linecard_ip, get_linecard_hostname_from_module_name, get_linecard_module_name_from_hostname
from paramiko.py3compat import u
from paramiko import Channel

Expand All @@ -31,7 +31,17 @@ def __init__(self, linecard_name, username, password):
if not self.ip:
sys.exit(1)

self.linecard_name = linecard_name
# if the user passes linecard hostname, then try to get the module name for that linecard
module_name = get_linecard_module_name_from_hostname(linecard_name)
if module_name is None:
# if the module name cannot be found from host, assume the user has passed module name
self.module_name = linecard_name
self.hostname = get_linecard_hostname_from_module_name(linecard_name)
else:
# the user has passed linecard hostname
self.hostname = linecard_name
self.module_name = module_name

self.username = username
self.password = password

Expand Down
12 changes: 7 additions & 5 deletions rcli/rexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,22 @@ def cli(linecard_names, command, username):

if list(linecard_names) == ["all"]:
# Get all linecard names using autocompletion helper
linecard_names = rcli_utils.get_all_linecards(None, None, "")
module_names = sorted(rcli_utils.get_all_linecards(None, None, ""))
else:
module_names = linecard_names

linecards = []
# Iterate through each linecard, check if the login was successful
for linecard_name in linecard_names:
linecard = Linecard(linecard_name, username, password)
for module_name in module_names:
linecard = Linecard(module_name, username, password)
if not linecard.connection:
click.echo(f"Failed to connect to {linecard_name} with username {username}")
click.echo(f"Failed to connect to {module_name} with username {username}")
sys.exit(1)
linecards.append(linecard)

for linecard in linecards:
if linecard.connection:
click.echo(f"======== {linecard.linecard_name} output: ========")
click.echo(f"======== {linecard.module_name}|{linecard.hostname} output: ========")
click.echo(linecard.execute_cmd(command))


Expand Down
4 changes: 2 additions & 2 deletions rcli/rshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ def cli(linecard_name, username):
try:
linecard = Linecard(linecard_name, username, password)
if linecard.connection:
click.echo(f"Connecting to {linecard.linecard_name}")
click.echo(f"Connecting to {linecard.module_name}")
# If connection was created, connection exists.
# Otherwise, user will see an error message.
linecard.start_shell()
click.echo("Connection Closed")
except paramiko.ssh_exception.AuthenticationException:
click.echo(
f"Login failed on '{linecard.linecard_name}' with username '{linecard.username}'")
f"Login failed on '{linecard.module_name}' with username '{linecard.username}'")


if __name__=="__main__":
Expand Down
15 changes: 15 additions & 0 deletions rcli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ def get_linecard_module_name_from_hostname(linecard_name: str):

return None


def get_linecard_hostname_from_module_name(linecard_name: str):

chassis_state_db = connect_to_chassis_state_db()
keys = chassis_state_db.keys(chassis_state_db.CHASSIS_STATE_DB, '{}|{}'.format(CHASSIS_MODULE_HOSTNAME_TABLE, '*'))
for key in keys:
module_name = key.split('|')[1]
if module_name.replace('-', '').lower() == linecard_name.replace('-', '').lower():
hostname = chassis_state_db.get(chassis_state_db.CHASSIS_STATE_DB, key, CHASSIS_MODULE_HOSTNAME)
return hostname

return None


def get_linecard_ip(linecard_name: str):
"""
Given a linecard name, lookup its IP address in the midplane table
Expand All @@ -69,6 +83,7 @@ def get_linecard_ip(linecard_name: str):
return None
return module_ip


def get_module_ip_and_access_from_state_db(module_name):
state_db = connect_state_db()
data_dict = state_db.get_all(
Expand Down
38 changes: 31 additions & 7 deletions show/bgp_frr_v4.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import click
import sys
import subprocess

from sonic_py_common import multi_asic
from sonic_py_common import multi_asic, device_info
from show.main import ip
import utilities_common.bgp_util as bgp_util
import utilities_common.cli as clicommon
Expand All @@ -17,6 +19,12 @@
@ip.group(cls=clicommon.AliasedGroup)
def bgp():
"""Show IPv4 BGP (Border Gateway Protocol) information"""
if device_info.is_supervisor():
# if the device is a chassis, the command need to be executed by rexec
click.echo("Since the current device is a chassis supervisor, " +
"this command will be executed remotely on all linecards")
proc = subprocess.run(["rexec", "all"] + ["-c", " ".join(sys.argv)])
sys.exit(proc.returncode)
pass


Expand Down Expand Up @@ -102,10 +110,16 @@ def neighbors(ipaddress, info_type, namespace):
def network(ipaddress, info_type, namespace):
"""Show IP (IPv4) BGP network"""

if multi_asic.is_multi_asic() and namespace not in multi_asic.get_namespace_list():
ctx = click.get_current_context()
ctx.fail('-n/--namespace option required. provide namespace from list {}'\
.format(multi_asic.get_namespace_list()))
namespace = namespace.strip()
if multi_asic.is_multi_asic():
if namespace == multi_asic.DEFAULT_NAMESPACE:
ctx = click.get_current_context()
ctx.fail('-n/--namespace option required. provide namespace from list {}'
.format(multi_asic.get_namespace_list()))
if namespace != "all" and namespace not in multi_asic.get_namespace_list():
ctx = click.get_current_context()
ctx.fail('invalid namespace {}. provide namespace from list {}'
.format(namespace, multi_asic.get_namespace_list()))

command = 'show ip bgp'
if ipaddress is not None:
Expand All @@ -125,5 +139,15 @@ def network(ipaddress, info_type, namespace):
if info_type is not None:
command += ' {}'.format(info_type)

output = bgp_util.run_bgp_show_command(command, namespace)
click.echo(output.rstrip('\n'))
if namespace == "all":
if multi_asic.is_multi_asic():
for ns in multi_asic.get_namespace_list():
click.echo("\n======== namespace {} ========".format(ns))
output = bgp_util.run_bgp_show_command(command, ns)
click.echo(output.rstrip('\n'))
else:
output = bgp_util.run_bgp_show_command(command, "")
click.echo(output.rstrip('\n'))
else:
output = bgp_util.run_bgp_show_command(command, namespace)
click.echo(output.rstrip('\n'))
6 changes: 5 additions & 1 deletion show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,11 @@ def protocol(verbose):
ip.add_command(bgp)
from .bgp_frr_v6 import bgp
ipv6.add_command(bgp)

elif device_info.is_supervisor():
from .bgp_frr_v4 import bgp
ip.add_command(bgp)
from .bgp_frr_v6 import bgp
ipv6.add_command(bgp)
#
# 'link-local-mode' subcommand ("show ipv6 link-local-mode")
#
Expand Down
128 changes: 127 additions & 1 deletion tests/bgp_commands_input/bgp_network_test_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@
multi_asic_bgp_network_err = \
"""Error: -n/--namespace option required. provide namespace from list ['asic0', 'asic1']"""

multi_asic_bgp_network_asic_unknown_err = \
"""Error: invalid namespace asic_unknown. provide namespace from list ['asic0', 'asic1']"""

bgp_v4_network_asic0 = \
"""
BGP table version is 11256, local router ID is 10.1.0.32, vrf id 0
Expand Down Expand Up @@ -276,7 +279,7 @@
*=i10.0.0.42/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.44/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
"""

bgp_v4_network_ip_address_asic0 = \
Expand Down Expand Up @@ -311,6 +314,111 @@
Last update: Thu Apr 22 02:13:30 2021
"""

bgp_v4_network_all_asic = \
"""
======== namespace asic0 ========

BGP table version is 11256, local router ID is 10.1.0.32, vrf id 0
Default local pref 100, local AS 65100
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete

Network Next Hop Metric LocPrf Weight Path
* i0.0.0.0/0 10.1.0.2 100 0 65200 6666 6667 i
* i 10.1.0.0 100 0 65200 6666 6667 i
*= 10.0.0.5 0 65200 6666 6667 i
*> 10.0.0.1 0 65200 6666 6667 i
* i8.0.0.0/32 10.1.0.2 0 100 0 i
* i 10.1.0.0 0 100 0 i
* 0.0.0.0 0 32768 ?
*> 0.0.0.0 0 32768 i
*=i8.0.0.1/32 10.1.0.2 0 100 0 i
*>i 10.1.0.0 0 100 0 i
*=i8.0.0.2/32 10.1.0.2 0 100 0 i
*>i 10.1.0.0 0 100 0 i
*=i8.0.0.3/32 10.1.0.2 0 100 0 i
*>i 10.1.0.0 0 100 0 i
*>i8.0.0.4/32 10.1.0.0 0 100 0 i
*>i8.0.0.5/32 10.1.0.2 0 100 0 i
* i10.0.0.0/31 10.1.0.2 0 100 0 ?
* i 10.1.0.0 0 100 0 ?
*> 0.0.0.0 0 32768 ?
* i10.0.0.4/31 10.1.0.2 0 100 0 ?
* i 10.1.0.0 0 100 0 ?
*> 0.0.0.0 0 32768 ?
*=i10.0.0.8/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.12/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.32/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.34/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.36/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.38/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.40/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.42/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.44/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?

======== namespace asic1 ========

BGP table version is 11256, local router ID is 10.1.0.32, vrf id 0
Default local pref 100, local AS 65100
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete

Network Next Hop Metric LocPrf Weight Path
* i0.0.0.0/0 10.1.0.2 100 0 65200 6666 6667 i
* i 10.1.0.0 100 0 65200 6666 6667 i
*= 10.0.0.5 0 65200 6666 6667 i
*> 10.0.0.1 0 65200 6666 6667 i
* i8.0.0.0/32 10.1.0.2 0 100 0 i
* i 10.1.0.0 0 100 0 i
* 0.0.0.0 0 32768 ?
*> 0.0.0.0 0 32768 i
*=i8.0.0.1/32 10.1.0.2 0 100 0 i
*>i 10.1.0.0 0 100 0 i
*=i8.0.0.2/32 10.1.0.2 0 100 0 i
*>i 10.1.0.0 0 100 0 i
*=i8.0.0.3/32 10.1.0.2 0 100 0 i
*>i 10.1.0.0 0 100 0 i
*>i8.0.0.4/32 10.1.0.0 0 100 0 i
*>i8.0.0.5/32 10.1.0.2 0 100 0 i
* i10.0.0.0/31 10.1.0.2 0 100 0 ?
* i 10.1.0.0 0 100 0 ?
*> 0.0.0.0 0 32768 ?
* i10.0.0.4/31 10.1.0.2 0 100 0 ?
* i 10.1.0.0 0 100 0 ?
*> 0.0.0.0 0 32768 ?
*=i10.0.0.8/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.12/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.32/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.34/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.36/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.38/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.40/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.42/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
*=i10.0.0.44/31 10.1.0.2 0 100 0 ?
*>i 10.1.0.0 0 100 0 ?
"""

bgp_v6_network_asic0 = \
"""
BGP table version is 12849, local router ID is 10.1.0.32, vrf id 0
Expand Down Expand Up @@ -429,6 +537,9 @@ def mock_show_bgp_network_multi_asic(param):
return bgp_v6_network_ip_address_asic0
elif param == 'bgp_v6_network_bestpath_asic0':
return bgp_v6_network_ip_address_asic0_bestpath
elif param == "bgp_v4_network_all_asic":
# this is mocking the output of a single LC
return bgp_v4_network_asic0
else:
return ''

Expand All @@ -454,6 +565,11 @@ def mock_show_bgp_network_multi_asic(param):
'rc': 1,
'rc_output': bgp_v4_network_longer_prefixes_error
},
'bgp_v4_network_all_asic_on_single_asic': {
'args': ['-nall'],
'rc': 0,
'rc_output': bgp_v4_network
},
'bgp_v6_network': {
'args': [],
'rc': 0,
Expand Down Expand Up @@ -499,6 +615,16 @@ def mock_show_bgp_network_multi_asic(param):
'rc': 0,
'rc_output': bgp_v4_network_bestpath_asic0
},
'bgp_v4_network_all_asic': {
'args': ['-nall'],
'rc': 0,
'rc_output': bgp_v4_network_all_asic
},
'bgp_v4_network_asic_unknown': {
'args': ['-nasic_unknown'],
'rc': 2,
'rc_err_msg': multi_asic_bgp_network_asic_unknown_err
},
'bgp_v6_network_multi_asic': {
'args': [],
'rc': 2,
Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,13 @@ def mock_run_show_summ_bgp_command_no_ext_neigh_on_asic1(
else:
return ""

def mock_multi_asic_list():
return ["asic0", "asic1"]

# mock multi-asic list
if request.param == "bgp_v4_network_all_asic":
multi_asic.get_namespace_list = mock_multi_asic_list

_old_run_bgp_command = bgp_util.run_bgp_command
if request.param == 'ip_route_for_int_ip':
bgp_util.run_bgp_command = mock_run_bgp_command_for_static
Expand Down
3 changes: 3 additions & 0 deletions tests/mock_tables/chassis_state_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
},
"CHASSIS_MODULE_HOSTNAME_TABLE|LINE-CARD1": {
"module_hostname": "sonic-lc2"
},
"CHASSIS_MODULE_HOSTNAME_TABLE|LINE-CARD2": {
"module_hostname": "sonic-lc3"
}

}
Loading
Loading