Skip to content

Commit

Permalink
support show interface commands for multi ASIC platforms (sonic-net#1006
Browse files Browse the repository at this point in the history
)

Changes to support the show interface status/description for multi ASIC
- Add argparse intfutil script
- Change the IntfDescription and IntfStatus classes to get the information from all namespaces.
- Add changes to filter out the internal ports from display
- Add support for -n and -d click options
- Add unit test to test mulit asic commands

Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan <arlakshm@microsoft.com>
  • Loading branch information
arlakshm authored Aug 21, 2020
1 parent 17fb378 commit 2c0ff92
Show file tree
Hide file tree
Showing 21 changed files with 1,064 additions and 224 deletions.
308 changes: 145 additions & 163 deletions scripts/intfutil

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@
],
package_data={
'show': ['aliases.ini'],
'tests': ['acl_input/*', 'mock_tables/*.py', 'mock_tables/*.json', 'filter_fdb_input/*']
'tests': ['acl_input/*',
'mock_tables/*.py',
'mock_tables/*.json',
'mock_tables/asic0/*.json',
'mock_tables/asic1/*.json',
'filter_fdb_input/*']
},
scripts=[
'scripts/aclshow',
Expand Down
63 changes: 39 additions & 24 deletions show/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
from natsort import natsorted
from tabulate import tabulate

from sonic_py_common import multi_asic
import utilities_common.cli as clicommon
import utilities_common.multi_asic as multi_asic_util
import portchannel

def try_convert_interfacename_from_alias(ctx, db, interfacename):
def try_convert_interfacename_from_alias(ctx, interfacename):
"""try to convert interface name from alias"""

if clicommon.get_interface_naming_mode() == "alias":
alias = interfacename
interfacename = clicommon.InterfaceAliasConverter(db).alias_to_name(alias)
interfacename = clicommon.InterfaceAliasConverter().alias_to_name(alias)
# TODO: ideally alias_to_name should return None when it cannot find
# the port name for the alias
if interfacename == alias:
Expand All @@ -31,19 +33,19 @@ def interfaces():
# 'alias' subcommand ("show interfaces alias")
@interfaces.command()
@click.argument('interfacename', required=False)
@clicommon.pass_db
def alias(db, interfacename):
@multi_asic_util.multi_asic_click_options
def alias(interfacename, namespace, display):
"""Show Interface Name/Alias Mapping"""

ctx = click.get_current_context()

port_dict = db.cfgdb.get_table("PORT")
port_dict = multi_asic.get_port_table(namespace=namespace)

header = ['Name', 'Alias']
body = []

if interfacename is not None:
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)

# If we're given an interface name, output name and alias for that interface only
if interfacename in port_dict.keys():
Expand All @@ -56,6 +58,10 @@ def alias(db, interfacename):
else:
# Output name and alias for all interfaces
for port_name in natsorted(port_dict.keys()):
if ((display == multi_asic_util.constants.DISPLAY_EXTERNAL) and
('role' in port_dict[port_name]) and
(port_dict[port_name]['role'] is multi_asic.INTERNAL_PORT)):
continue
if 'alias' in port_dict[port_name]:
body.append([port_name, port_dict[port_name]['alias']])
else:
Expand All @@ -65,19 +71,25 @@ def alias(db, interfacename):

@interfaces.command()
@click.argument('interfacename', required=False)
@multi_asic_util.multi_asic_click_options
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@clicommon.pass_db
def description(db, interfacename, verbose):
def description(interfacename, namespace, display, verbose):
"""Show interface status, protocol and description"""

ctx = click.get_current_context()

cmd = "intfutil description"
cmd = "intfutil -c description"

#ignore the display option when interface name is passed
if interfacename is not None:
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)

cmd += " {}".format(interfacename)
cmd += " -i {}".format(interfacename)
else:
cmd += " -d {}".format(display)

if namespace is not None:
cmd += " -n {}".format(namespace)

clicommon.run_command(cmd, display_cmd=verbose)

Expand All @@ -91,19 +103,24 @@ def naming_mode(verbose):

@interfaces.command()
@click.argument('interfacename', required=False)
@multi_asic_util.multi_asic_click_options
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@clicommon.pass_db
def status(db, interfacename, verbose):
def status(interfacename, namespace, display, verbose):
"""Show Interface status information"""

ctx = click.get_current_context()

cmd = "intfutil status"
cmd = "intfutil -c status"

if interfacename is not None:
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)

cmd += " {}".format(interfacename)
cmd += " -i {}".format(interfacename)
else:
cmd += " -d {}".format(display)

if namespace is not None:
cmd += " -n {}".format(namespace)

clicommon.run_command(cmd, display_cmd=verbose)

Expand Down Expand Up @@ -225,7 +242,7 @@ def expected(db, interfacename):
for port in natsorted(neighbor_dict.keys()):
temp_port = port
if clicommon.get_interface_naming_mode() == "alias":
port = clicommon.InterfaceAliasConverter(db).name_to_alias(port)
port = clicommon.InterfaceAliasConverter().name_to_alias(port)
neighbor_dict[port] = neighbor_dict.pop(temp_port)
device2interface_dict[neighbor_dict[port]['name']] = {'localPort': port, 'neighborPort': neighbor_dict[port]['port']}

Expand Down Expand Up @@ -268,8 +285,7 @@ def transceiver():
@click.argument('interfacename', required=False)
@click.option('-d', '--dom', 'dump_dom', is_flag=True, help="Also display Digital Optical Monitoring (DOM) data")
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@clicommon.pass_db
def eeprom(db, interfacename, dump_dom, verbose):
def eeprom(interfacename, dump_dom, verbose):
"""Show interface transceiver EEPROM information"""

ctx = click.get_current_context()
Expand All @@ -280,7 +296,7 @@ def eeprom(db, interfacename, dump_dom, verbose):
cmd += " --dom"

if interfacename is not None:
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)

cmd += " -p {}".format(interfacename)

Expand All @@ -289,16 +305,15 @@ def eeprom(db, interfacename, dump_dom, verbose):
@transceiver.command()
@click.argument('interfacename', required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@clicommon.pass_db
def lpmode(db, interfacename, verbose):
def lpmode(interfacename, verbose):
"""Show interface transceiver low-power mode status"""

ctx = click.get_current_context()

cmd = "sudo sfputil show lpmode"

if interfacename is not None:
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)

cmd += " -p {}".format(interfacename)

Expand All @@ -316,7 +331,7 @@ def presence(db, interfacename, verbose):
cmd = "sfpshow presence"

if interfacename is not None:
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)

cmd += " -p {}".format(interfacename)

Expand Down
6 changes: 3 additions & 3 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ def subinterfaces():
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def status(subinterfacename, verbose):
"""Show sub port interface status information"""
cmd = "intfutil status "
cmd = "intfutil -c status"

if subinterfacename is not None:
sub_intf_sep_idx = subinterfacename.find(VLAN_SUB_INTERFACE_SEPARATOR)
Expand All @@ -479,9 +479,9 @@ def status(subinterfacename, verbose):
if clicommon.get_interface_naming_mode() == "alias":
subinterfacename = iface_alias_converter.alias_to_name(subinterfacename)

cmd += subinterfacename
cmd += " -i {}".format(subinterfacename)
else:
cmd += "subport"
cmd += " -i subport"
run_command(cmd, display_cmd=verbose)

#
Expand Down
16 changes: 8 additions & 8 deletions tests/intfutil_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"""

show_interface_description_Ethernet0_verbose_output="""\
Running command: intfutil description Ethernet0
Running command: intfutil -c description -i Ethernet0
Interface Oper Admin Alias Description
----------- ------ ------- --------- --------------------
Ethernet0 down up Ethernet0 ARISTA01T2:Ethernet1
Expand Down Expand Up @@ -83,7 +83,7 @@ def test_intf_status(self):
assert result.output == show_interface_status_output

# Test 'intfutil status'
output = subprocess.check_output('intfutil status', stderr=subprocess.STDOUT, shell=True)
output = subprocess.check_output('intfutil -c status', stderr=subprocess.STDOUT, shell=True)
print(output)
assert result.output == show_interface_status_output

Expand All @@ -93,7 +93,7 @@ def test_intf_status_verbose(self):
assert result.exit_code == 0
print(result.exit_code)
print(result.output)
expected_output = "Running command: intfutil status"
expected_output = "Running command: intfutil -c status -d all"
assert result.output.split('\n')[0] == expected_output

def test_intf_status_Ethernet32(self):
Expand Down Expand Up @@ -164,15 +164,15 @@ def test_subintf_status(self):
self.assertEqual(result.output.strip(), expected_output)

# Test 'intfutil status subport'
output = subprocess.check_output('intfutil status subport', stderr=subprocess.STDOUT, shell=True)
output = subprocess.check_output('intfutil -c status -i subport', stderr=subprocess.STDOUT, shell=True)
print >> sys.stderr, output
self.assertEqual(output.strip(), expected_output)

# Test 'show subinterfaces status --verbose'
def test_subintf_status_verbose(self):
result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["--verbose"])
print >> sys.stderr, result.output
expected_output = "Command: intfutil status subport"
expected_output = "Command: intfutil -c status -i subport"
self.assertEqual(result.output.split('\n')[0], expected_output)


Expand All @@ -189,15 +189,15 @@ def test_single_subintf_status(self):
self.assertEqual(result.output.strip(), expected_output)

# Test 'intfutil status Ethernet0.10'
output = subprocess.check_output('intfutil status Ethernet0.10', stderr=subprocess.STDOUT, shell=True)
output = subprocess.check_output('intfutil -c status -i Ethernet0.10', stderr=subprocess.STDOUT, shell=True)
print >> sys.stderr, output
self.assertEqual(output.strip(), expected_output)

# Test '--verbose' status of single sub interface
def test_single_subintf_status_verbose(self):
result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["Ethernet0.10", "--verbose"])
print >> sys.stderr, result.output
expected_output = "Command: intfutil status Ethernet0.10"
expected_output = "Command: intfutil -c status -i Ethernet0.10"
self.assertEqual(result.output.split('\n')[0], expected_output)


Expand All @@ -222,7 +222,7 @@ def test_single_subintf_status_alias_mode_verbose(self):

result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["etp1.10", "--verbose"])
print >> sys.stderr, result.output
expected_output = "Command: intfutil status Ethernet0.10"
expected_output = "Command: intfutil -c status -i Ethernet0.10"
self.assertEqual(result.output.split('\n')[0], expected_output)

os.environ["SONIC_CLI_IFACE_MODE"] = "default"
Expand Down
Empty file.
72 changes: 72 additions & 0 deletions tests/mock_tables/asic0/appl_db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"PORT_TABLE:Ethernet0": {
"lanes": "33,34,35,36",
"description": "ARISTA01T2:Ethernet3/1/1",
"pfc_asym": "off",
"mtu": "9100",
"alias": "Ethernet1/1",
"oper_status": "up",
"admin_status": "up",
"role": "Ext",
"speed": "40000",
"asic_port_name": "Eth0-ASIC0"
},
"PORT_TABLE:Ethernet4": {
"oper_status": "up",
"lanes": "29,30,31,32",
"description": "ARISTA01T2:Ethernet3/2/1",
"pfc_asym": "off",
"mtu": "9100",
"alias": "Ethernet1/2",
"admin_status": "up",
"role": "Ext",
"speed": "40000",
"asic_port_name": "Eth1-ASIC0"
},
"PORT_TABLE:Ethernet-BP0": {
"oper_status": "up",
"lanes": "93,94,95,96",
"description": "ASIC1:Eth0-ASIC1",
"pfc_asym": "off",
"mtu": "9100",
"alias": "Ethernet-BP0",
"admin_status": "up",
"role": "Int",
"speed": "40000",
"asic_port_name": "Eth16-ASIC0"
},
"PORT_TABLE:Ethernet-BP4": {
"oper_status": "up",
"lanes": "97,98,99,100",
"description": "ASIC1:Eth1-ASIC1",
"pfc_asym": "off",
"mtu": "9100",
"alias": "Ethernet-BP4",
"admin_status": "up",
"role": "Int",
"speed": "40000",
"asic_port_name": "Eth17-ASIC0"
},
"LAG_MEMBER_TABLE:PortChannel1002:Ethernet0": {
"status": "disabled"
},
"LAG_MEMBER_TABLE:PortChannel1002:Ethernet4": {
"status": "enabled"
},
"LAG_MEMBER_TABLE:PortChannel4001:Ethernet-BP0": {
"status": "enabled"
},
"LAG_MEMBER_TABLE:PortChannel4001:Ethernet-BP4": {
"status": "enabled"
},
"LAG_TABLE:PortChannel1002": {
"admin_status": "up",
"mtu": "9100",
"oper_status": "up"
},
"LAG_TABLE:PortChannel4001": {
"admin_status": "up",
"mtu": "9100",
"oper_status": "up"
}
}
6 changes: 6 additions & 0 deletions tests/mock_tables/asic0/asic_db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"ASIC_STATE:SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000": {
"SAI_SWITCH_ATTR_INIT_SWITCH": "true",
"SAI_SWITCH_ATTR_SRC_MAC_ADDRESS": "DE:AD:BE:EF:CA:FE"
}
}
Loading

0 comments on commit 2c0ff92

Please sign in to comment.