Skip to content

Commit 2c0ff92

Browse files
authored
support show interface commands for multi ASIC platforms (#1006)
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>
1 parent 17fb378 commit 2c0ff92

21 files changed

+1064
-224
lines changed

scripts/intfutil

+145-163
Large diffs are not rendered by default.

setup.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@
5959
],
6060
package_data={
6161
'show': ['aliases.ini'],
62-
'tests': ['acl_input/*', 'mock_tables/*.py', 'mock_tables/*.json', 'filter_fdb_input/*']
62+
'tests': ['acl_input/*',
63+
'mock_tables/*.py',
64+
'mock_tables/*.json',
65+
'mock_tables/asic0/*.json',
66+
'mock_tables/asic1/*.json',
67+
'filter_fdb_input/*']
6368
},
6469
scripts=[
6570
'scripts/aclshow',

show/interfaces/__init__.py

+39-24
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44
from natsort import natsorted
55
from tabulate import tabulate
66

7+
from sonic_py_common import multi_asic
78
import utilities_common.cli as clicommon
9+
import utilities_common.multi_asic as multi_asic_util
810
import portchannel
911

10-
def try_convert_interfacename_from_alias(ctx, db, interfacename):
12+
def try_convert_interfacename_from_alias(ctx, interfacename):
1113
"""try to convert interface name from alias"""
1214

1315
if clicommon.get_interface_naming_mode() == "alias":
1416
alias = interfacename
15-
interfacename = clicommon.InterfaceAliasConverter(db).alias_to_name(alias)
17+
interfacename = clicommon.InterfaceAliasConverter().alias_to_name(alias)
1618
# TODO: ideally alias_to_name should return None when it cannot find
1719
# the port name for the alias
1820
if interfacename == alias:
@@ -31,19 +33,19 @@ def interfaces():
3133
# 'alias' subcommand ("show interfaces alias")
3234
@interfaces.command()
3335
@click.argument('interfacename', required=False)
34-
@clicommon.pass_db
35-
def alias(db, interfacename):
36+
@multi_asic_util.multi_asic_click_options
37+
def alias(interfacename, namespace, display):
3638
"""Show Interface Name/Alias Mapping"""
3739

3840
ctx = click.get_current_context()
3941

40-
port_dict = db.cfgdb.get_table("PORT")
42+
port_dict = multi_asic.get_port_table(namespace=namespace)
4143

4244
header = ['Name', 'Alias']
4345
body = []
4446

4547
if interfacename is not None:
46-
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
48+
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)
4749

4850
# If we're given an interface name, output name and alias for that interface only
4951
if interfacename in port_dict.keys():
@@ -56,6 +58,10 @@ def alias(db, interfacename):
5658
else:
5759
# Output name and alias for all interfaces
5860
for port_name in natsorted(port_dict.keys()):
61+
if ((display == multi_asic_util.constants.DISPLAY_EXTERNAL) and
62+
('role' in port_dict[port_name]) and
63+
(port_dict[port_name]['role'] is multi_asic.INTERNAL_PORT)):
64+
continue
5965
if 'alias' in port_dict[port_name]:
6066
body.append([port_name, port_dict[port_name]['alias']])
6167
else:
@@ -65,19 +71,25 @@ def alias(db, interfacename):
6571

6672
@interfaces.command()
6773
@click.argument('interfacename', required=False)
74+
@multi_asic_util.multi_asic_click_options
6875
@click.option('--verbose', is_flag=True, help="Enable verbose output")
69-
@clicommon.pass_db
70-
def description(db, interfacename, verbose):
76+
def description(interfacename, namespace, display, verbose):
7177
"""Show interface status, protocol and description"""
7278

7379
ctx = click.get_current_context()
7480

75-
cmd = "intfutil description"
81+
cmd = "intfutil -c description"
7682

83+
#ignore the display option when interface name is passed
7784
if interfacename is not None:
78-
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
85+
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)
7986

80-
cmd += " {}".format(interfacename)
87+
cmd += " -i {}".format(interfacename)
88+
else:
89+
cmd += " -d {}".format(display)
90+
91+
if namespace is not None:
92+
cmd += " -n {}".format(namespace)
8193

8294
clicommon.run_command(cmd, display_cmd=verbose)
8395

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

92104
@interfaces.command()
93105
@click.argument('interfacename', required=False)
106+
@multi_asic_util.multi_asic_click_options
94107
@click.option('--verbose', is_flag=True, help="Enable verbose output")
95-
@clicommon.pass_db
96-
def status(db, interfacename, verbose):
108+
def status(interfacename, namespace, display, verbose):
97109
"""Show Interface status information"""
98110

99111
ctx = click.get_current_context()
100112

101-
cmd = "intfutil status"
113+
cmd = "intfutil -c status"
102114

103115
if interfacename is not None:
104-
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
116+
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)
105117

106-
cmd += " {}".format(interfacename)
118+
cmd += " -i {}".format(interfacename)
119+
else:
120+
cmd += " -d {}".format(display)
121+
122+
if namespace is not None:
123+
cmd += " -n {}".format(namespace)
107124

108125
clicommon.run_command(cmd, display_cmd=verbose)
109126

@@ -225,7 +242,7 @@ def expected(db, interfacename):
225242
for port in natsorted(neighbor_dict.keys()):
226243
temp_port = port
227244
if clicommon.get_interface_naming_mode() == "alias":
228-
port = clicommon.InterfaceAliasConverter(db).name_to_alias(port)
245+
port = clicommon.InterfaceAliasConverter().name_to_alias(port)
229246
neighbor_dict[port] = neighbor_dict.pop(temp_port)
230247
device2interface_dict[neighbor_dict[port]['name']] = {'localPort': port, 'neighborPort': neighbor_dict[port]['port']}
231248

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

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

282298
if interfacename is not None:
283-
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
299+
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)
284300

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

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

296311
ctx = click.get_current_context()
297312

298313
cmd = "sudo sfputil show lpmode"
299314

300315
if interfacename is not None:
301-
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
316+
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)
302317

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

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

318333
if interfacename is not None:
319-
interfacename = try_convert_interfacename_from_alias(ctx, db, interfacename)
334+
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)
320335

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

show/main.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ def subinterfaces():
468468
@click.option('--verbose', is_flag=True, help="Enable verbose output")
469469
def status(subinterfacename, verbose):
470470
"""Show sub port interface status information"""
471-
cmd = "intfutil status "
471+
cmd = "intfutil -c status"
472472

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

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

487487
#

tests/intfutil_test.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"""
5151

5252
show_interface_description_Ethernet0_verbose_output="""\
53-
Running command: intfutil description Ethernet0
53+
Running command: intfutil -c description -i Ethernet0
5454
Interface Oper Admin Alias Description
5555
----------- ------ ------- --------- --------------------
5656
Ethernet0 down up Ethernet0 ARISTA01T2:Ethernet1
@@ -83,7 +83,7 @@ def test_intf_status(self):
8383
assert result.output == show_interface_status_output
8484

8585
# Test 'intfutil status'
86-
output = subprocess.check_output('intfutil status', stderr=subprocess.STDOUT, shell=True)
86+
output = subprocess.check_output('intfutil -c status', stderr=subprocess.STDOUT, shell=True)
8787
print(output)
8888
assert result.output == show_interface_status_output
8989

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

9999
def test_intf_status_Ethernet32(self):
@@ -164,15 +164,15 @@ def test_subintf_status(self):
164164
self.assertEqual(result.output.strip(), expected_output)
165165

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

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

178178

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

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

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

203203

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

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

228228
os.environ["SONIC_CLI_IFACE_MODE"] = "default"

tests/mock_tables/asic0/__init__.py

Whitespace-only changes.

tests/mock_tables/asic0/appl_db.json

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"PORT_TABLE:Ethernet0": {
3+
"lanes": "33,34,35,36",
4+
"description": "ARISTA01T2:Ethernet3/1/1",
5+
"pfc_asym": "off",
6+
"mtu": "9100",
7+
"alias": "Ethernet1/1",
8+
"oper_status": "up",
9+
"admin_status": "up",
10+
"role": "Ext",
11+
"speed": "40000",
12+
"asic_port_name": "Eth0-ASIC0"
13+
},
14+
"PORT_TABLE:Ethernet4": {
15+
"oper_status": "up",
16+
"lanes": "29,30,31,32",
17+
"description": "ARISTA01T2:Ethernet3/2/1",
18+
"pfc_asym": "off",
19+
"mtu": "9100",
20+
"alias": "Ethernet1/2",
21+
"admin_status": "up",
22+
"role": "Ext",
23+
"speed": "40000",
24+
"asic_port_name": "Eth1-ASIC0"
25+
},
26+
"PORT_TABLE:Ethernet-BP0": {
27+
"oper_status": "up",
28+
"lanes": "93,94,95,96",
29+
"description": "ASIC1:Eth0-ASIC1",
30+
"pfc_asym": "off",
31+
"mtu": "9100",
32+
"alias": "Ethernet-BP0",
33+
"admin_status": "up",
34+
"role": "Int",
35+
"speed": "40000",
36+
"asic_port_name": "Eth16-ASIC0"
37+
},
38+
"PORT_TABLE:Ethernet-BP4": {
39+
"oper_status": "up",
40+
"lanes": "97,98,99,100",
41+
"description": "ASIC1:Eth1-ASIC1",
42+
"pfc_asym": "off",
43+
"mtu": "9100",
44+
"alias": "Ethernet-BP4",
45+
"admin_status": "up",
46+
"role": "Int",
47+
"speed": "40000",
48+
"asic_port_name": "Eth17-ASIC0"
49+
},
50+
"LAG_MEMBER_TABLE:PortChannel1002:Ethernet0": {
51+
"status": "disabled"
52+
},
53+
"LAG_MEMBER_TABLE:PortChannel1002:Ethernet4": {
54+
"status": "enabled"
55+
},
56+
"LAG_MEMBER_TABLE:PortChannel4001:Ethernet-BP0": {
57+
"status": "enabled"
58+
},
59+
"LAG_MEMBER_TABLE:PortChannel4001:Ethernet-BP4": {
60+
"status": "enabled"
61+
},
62+
"LAG_TABLE:PortChannel1002": {
63+
"admin_status": "up",
64+
"mtu": "9100",
65+
"oper_status": "up"
66+
},
67+
"LAG_TABLE:PortChannel4001": {
68+
"admin_status": "up",
69+
"mtu": "9100",
70+
"oper_status": "up"
71+
}
72+
}

tests/mock_tables/asic0/asic_db.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"ASIC_STATE:SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000": {
3+
"SAI_SWITCH_ATTR_INIT_SWITCH": "true",
4+
"SAI_SWITCH_ATTR_SRC_MAC_ADDRESS": "DE:AD:BE:EF:CA:FE"
5+
}
6+
}

0 commit comments

Comments
 (0)