Skip to content

Commit e18640e

Browse files
authored
Switchport mode update for 'show interfaces status' (sonic-net#3788)
What I did Fixed "show interfaces status" output for interfaces with switchport mode configuration. How I did it Configured "switchport mode" is fetched from DB for all front panel ports and PortChannel interfaces. "Vlan" column in "show interface status" is displayed based on below considerations: If interface is part of PortChannel - display PortChannel interface name [present behavior] If "switchport mode" is configured on interface [Ethernet/PortChannel] - display configured mode [new behavior] If "switchport mode" is NOT configured on interface but part of a VLAN [Ethernet/PortChannel] - display as "trunk" [present behavior] If "switchport mode" is NOT configured on interface and NOT part of a VLAN [Ethernet/PortChannel] - display as "routed" [present behavior] How to verify it Configure "switchport mode" for an interface/portchannel and verify the output in below show commands show interfaces switchport status show interfaces status Previous command output (if the output of a command-line utility has changed) Previously it was always displaying as trunk even if interface is configured as access root@sonic:~# config switchport mode access Ethernet0 Ethernet0 switched to access mode root@sonic:~# show interfaces switchport status | grep Ethernet0 Ethernet0 access root@sonic:~# root@sonic:~# show interfaces status | grep Ethernet0 Ethernet0 2304,2305,2306,2307 100G 9100 N/A etp0 trunk up up QSFP28 or later N/A New command output (if the output of a command-line utility has changed) root@sonic:~# config switchport mode access Ethernet0 Ethernet0 switched to access mode root@sonic:~# show interfaces switchport status | grep Ethernet0 Ethernet0 access root@sonic:~# root@sonic:~# show interfaces status | grep Ethernet0 Ethernet0 2304,2305,2306,2307 100G 9100 N/A etp0 access up up QSFP28 or later N/A closes sonic-net#3787
1 parent 809646a commit e18640e

File tree

2 files changed

+116
-28
lines changed

2 files changed

+116
-28
lines changed

scripts/intfutil

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,33 +80,40 @@ def get_sub_port_intf_list(config_db):
8080
return sub_intf_list
8181

8282

83-
def get_interface_vlan_dict(config_db):
83+
def get_interface_sw_mode_dict(config_db, front_panel_ports_list):
8484
"""
85-
Get info from REDIS ConfigDB and create interface to vlan mapping
85+
Get info from REDIS ConfigDB and create interface to swithport mode mapping
8686
"""
87-
get_int_vlan_configdb_info = config_db.get_table('VLAN_MEMBER')
88-
int_list = []
89-
vlan_list = []
90-
for line in get_int_vlan_configdb_info:
91-
vlan_number = line[0]
92-
interface = line[1]
93-
int_list.append(interface)
94-
vlan_list.append(vlan_number)
95-
int_to_vlan_dict = dict(zip(int_list, vlan_list))
96-
return int_to_vlan_dict
87+
vlan_member_table = config_db.get_table('VLAN_MEMBER')
9788

89+
vlan_member_keys = []
90+
for _, key in vlan_member_table:
91+
vlan_member_keys.append(key)
9892

99-
def config_db_vlan_port_keys_get(int_to_vlan_dict, front_panel_ports_list, intf_name):
93+
intf_to_sw_mode_dict = {}
94+
for intf_name in front_panel_ports_list:
95+
port = config_db.get_entry('PORT', intf_name)
96+
if "mode" in port:
97+
mode = port['mode']
98+
elif intf_name in vlan_member_keys:
99+
mode = 'trunk'
100+
else:
101+
mode = 'routed'
102+
intf_to_sw_mode_dict[intf_name] = mode
103+
104+
return intf_to_sw_mode_dict
105+
106+
107+
def config_db_vlan_port_keys_get(intf_to_sw_mode_dict, intf_to_po_dict, intf_name):
100108
"""
101109
Get interface vlan value and return it.
102110
"""
103-
vlan = "routed"
104-
if intf_name in front_panel_ports_list:
105-
if intf_name in int_to_vlan_dict.keys():
106-
vlan = int_to_vlan_dict[intf_name]
107-
if "Vlan" in vlan:
108-
vlan = "trunk"
109-
return vlan
111+
mode = "routed"
112+
if intf_name in intf_to_po_dict.keys():
113+
mode = intf_to_po_dict[intf_name]
114+
elif intf_name in intf_to_sw_mode_dict.keys():
115+
mode = intf_to_sw_mode_dict[intf_name]
116+
return mode
110117

111118

112119
def appl_db_keys_get(appl_db, front_panel_ports_list, intf_name):
@@ -307,6 +314,31 @@ def create_po_int_dict(po_int_tuple_list):
307314
po_int_dict = tuple_to_dict(po_int_tuple_list, temp_dict)
308315
return po_int_dict
309316

317+
def create_po_to_sw_mode_dict(config_db, po_int_tuple_list):
318+
"""
319+
This function takes the portchannel to interface tuple
320+
and converts that into an interface to portchannel dictionary
321+
with the portchannels as the key and the mode as the values.
322+
"""
323+
vlan_member_table = config_db.get_table('VLAN_MEMBER')
324+
325+
vlan_member_keys = []
326+
for _, key in vlan_member_table:
327+
vlan_member_keys.append(key)
328+
329+
po_to_sw_mode_dict = {}
330+
for po, intf in po_int_tuple_list:
331+
portchannel = config_db.get_entry('PORTCHANNEL', po)
332+
if "mode" in portchannel:
333+
mode = portchannel['mode']
334+
elif po in vlan_member_keys:
335+
mode = 'trunk'
336+
else:
337+
mode = 'routed'
338+
339+
po_to_sw_mode_dict[po] = mode
340+
return po_to_sw_mode_dict
341+
310342
def create_int_to_portchannel_dict(po_int_tuple_list):
311343
"""
312344
This function takes the portchannel to interface tuple
@@ -354,7 +386,7 @@ def po_speed_dict(po_int_dict, appl_db):
354386
po_speed_dict = {}
355387
return po_speed_dict
356388

357-
def appl_db_portchannel_status_get(appl_db, config_db, po_name, status_type, portchannel_speed_dict, combined_int_to_vlan_po_dict=None):
389+
def appl_db_portchannel_status_get(appl_db, config_db, po_name, status_type, portchannel_speed_dict, po_to_sw_mode_dict=None):
358390
"""
359391
Get the port status
360392
"""
@@ -367,8 +399,8 @@ def appl_db_portchannel_status_get(appl_db, config_db, po_name, status_type, por
367399
return "N/A"
368400
return status
369401
if status_type == "vlan":
370-
if combined_int_to_vlan_po_dict and po_name in combined_int_to_vlan_po_dict.keys():
371-
status = "trunk"
402+
if po_to_sw_mode_dict and po_name in po_to_sw_mode_dict.keys():
403+
status = po_to_sw_mode_dict[po_name]
372404
else:
373405
status = "routed"
374406
return status
@@ -484,7 +516,7 @@ class IntfStatus(object):
484516
appl_db_port_status_get(self.db, key, PORT_MTU_STATUS),
485517
appl_db_port_status_get(self.db, key, PORT_FEC),
486518
appl_db_port_status_get(self.db, key, PORT_ALIAS),
487-
config_db_vlan_port_keys_get(self.combined_int_to_vlan_po_dict, self.front_panel_ports_list, key),
519+
config_db_vlan_port_keys_get(self.intf_to_sw_mode_dict, self.int_po_dict, key),
488520
appl_db_port_status_get(self.db, key, PORT_OPER_STATUS),
489521
appl_db_port_status_get(self.db, key, PORT_ADMIN_STATUS),
490522
port_optics_get(self.db, key, PORT_OPTICS_TYPE),
@@ -501,7 +533,7 @@ class IntfStatus(object):
501533
appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_MTU_STATUS, self.portchannel_speed_dict),
502534
appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_FEC, self.portchannel_speed_dict),
503535
appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_ALIAS, self.portchannel_speed_dict),
504-
appl_db_portchannel_status_get(self.db, self.config_db, po, "vlan", self.portchannel_speed_dict, self.combined_int_to_vlan_po_dict),
536+
appl_db_portchannel_status_get(self.db, self.config_db, po, "vlan", self.portchannel_speed_dict, self.po_to_sw_mode_dict),
505537
appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_OPER_STATUS, self.portchannel_speed_dict),
506538
appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_ADMIN_STATUS, self.portchannel_speed_dict),
507539
appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_OPTICS_TYPE, self.portchannel_speed_dict),
@@ -523,13 +555,13 @@ class IntfStatus(object):
523555
def get_intf_status(self):
524556
self.front_panel_ports_list = get_frontpanel_port_list(self.config_db)
525557
self.appl_db_keys = appl_db_keys_get(self.db, self.front_panel_ports_list, None)
526-
self.int_to_vlan_dict = get_interface_vlan_dict(self.config_db)
558+
self.intf_to_sw_mode_dict = get_interface_sw_mode_dict(self.config_db, self.front_panel_ports_list)
527559
self.get_raw_po_int_configdb_info = get_raw_portchannel_info(self.config_db)
528560
self.portchannel_list = get_portchannel_list(self.get_raw_po_int_configdb_info)
529561
self.po_int_tuple_list = create_po_int_tuple_list(self.get_raw_po_int_configdb_info)
530562
self.po_int_dict = create_po_int_dict(self.po_int_tuple_list)
531563
self.int_po_dict = create_int_to_portchannel_dict(self.po_int_tuple_list)
532-
self.combined_int_to_vlan_po_dict = merge_dicts(self.int_to_vlan_dict, self.int_po_dict)
564+
self.po_to_sw_mode_dict = create_po_to_sw_mode_dict(self.config_db, self.po_int_tuple_list)
533565
self.portchannel_speed_dict = po_speed_dict(self.po_int_dict, self.db)
534566
self.portchannel_keys = self.portchannel_speed_dict.keys()
535567

tests/vlan_test.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
from importlib import reload
1414
import utilities_common.bgp_util as bgp_util
1515

16+
root_path = os.path.dirname(os.path.abspath(__file__))
17+
modules_path = os.path.dirname(root_path)
18+
scripts_path = os.path.join(modules_path, "scripts")
19+
1620
IP_VERSION_PARAMS_MAP = {
1721
"ipv4": {
1822
"table": "VLAN"
@@ -296,12 +300,24 @@
296300
"""
297301

298302

303+
def get_intf_switchport_status(self, output: str, interface: str) -> str:
304+
for line in output.splitlines():
305+
line = line.strip()
306+
if not line or line.startswith("Interface") or line.startswith("----"):
307+
continue
308+
parts = line.split()
309+
if parts[0] == interface and len(parts) >= 2:
310+
return parts[1]
311+
return "interface not found"
312+
313+
299314
class TestVlan(object):
300315
_old_run_bgp_command = None
301316

302317
@classmethod
303318
def setup_class(cls):
304-
os.environ['UTILITIES_UNIT_TESTING'] = "1"
319+
os.environ["PATH"] += os.pathsep + scripts_path
320+
os.environ['UTILITIES_UNIT_TESTING'] = "2"
305321
# ensure that we are working with single asic config
306322
cls._old_run_bgp_command = bgp_util.run_bgp_command
307323
bgp_util.run_bgp_command = mock.MagicMock(
@@ -718,6 +734,9 @@ def test_config_vlan_add_portchannel_member_with_switchport_modes(self):
718734
print(result.exit_code)
719735
print(result.output)
720736
assert result.exit_code == 0
737+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
738+
switchport_status = get_intf_switchport_status(self, result.output, "PortChannel0001")
739+
assert "routed" in switchport_status
721740

722741
# Configure PortChannel0001 to routed mode again; should give error as it is already in routed mode
723742
result = runner.invoke(config.config.commands["switchport"].commands["mode"],
@@ -748,20 +767,30 @@ def test_config_vlan_add_portchannel_member_with_switchport_modes(self):
748767
print(result.exit_code)
749768
print(result.output)
750769
assert result.exit_code == 0
770+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
771+
print(result.output)
772+
switchport_status = get_intf_switchport_status(self, result.output, "PortChannel1001")
773+
assert "access" in switchport_status
751774

752775
# Configure PortChannel1001 back to routed mode
753776
result = runner.invoke(config.config.commands["switchport"].commands["mode"],
754777
["routed", "PortChannel1001"], obj=db)
755778
print(result.exit_code)
756779
print(result.output)
757780
assert result.exit_code == 0
781+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
782+
switchport_status = get_intf_switchport_status(self, result.output, "PortChannel1001")
783+
assert "routed" in switchport_status
758784

759785
# Configure PortChannel1001 to trunk mode
760786
result = runner.invoke(config.config.commands["switchport"].commands["mode"],
761787
["trunk", "PortChannel1001"], obj=db)
762788
print(result.exit_code)
763789
print(result.output)
764790
assert result.exit_code == 0
791+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
792+
switchport_status = get_intf_switchport_status(self, result.output, "PortChannel1001")
793+
assert "trunk" in switchport_status
765794

766795
# Add back PortChannel1001 tagged member to Vlan4000
767796
result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["add"],
@@ -1176,6 +1205,10 @@ def test_config_add_del_vlan_and_vlan_member_with_switchport_modes(self, mock_re
11761205
print(result.output)
11771206
assert result.exit_code == 0
11781207
assert "Ethernet20 switched to access mode" in result.output
1208+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
1209+
print(result.output)
1210+
switchport_status = get_intf_switchport_status(self, result.output, "Ethernet20")
1211+
assert "access" in switchport_status
11791212

11801213
# configure Ethernet20 to access mode again; should give error as it is already in access mode
11811214
result = runner.invoke(config.config.commands["switchport"].commands["mode"], ["access", "Ethernet20"], obj=db)
@@ -1215,6 +1248,10 @@ def test_config_add_del_vlan_and_vlan_member_with_switchport_modes(self, mock_re
12151248
print(result.output)
12161249
traceback.print_tb(result.exc_info[2])
12171250
assert result.exit_code == 0
1251+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
1252+
print(result.output)
1253+
switchport_status = get_intf_switchport_status(self, result.output, "Ethernet20")
1254+
assert "trunk" in switchport_status
12181255

12191256
# show output
12201257
result = runner.invoke(show.cli.commands["vlan"].commands["brief"], [], obj=db)
@@ -1256,6 +1293,11 @@ def test_config_add_del_vlan_and_vlan_member_with_switchport_modes(self, mock_re
12561293
assert result.exit_code == 0
12571294
assert "Ethernet20 switched to routed mode" in result.output
12581295

1296+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
1297+
print(result.output)
1298+
switchport_status = get_intf_switchport_status(self, result.output, "Ethernet20")
1299+
assert "routed" in switchport_status
1300+
12591301
# del 1001
12601302
result = runner.invoke(config.config.commands["vlan"].commands["del"], ["1001"], obj=db)
12611303
print(result.exit_code)
@@ -1287,6 +1329,11 @@ def test_config_add_del_with_switchport_modes_changes_output(
12871329
assert result.exit_code == 0
12881330
assert "Ethernet20 switched to trunk mode" in result.output
12891331

1332+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
1333+
print(result.output)
1334+
switchport_status = get_intf_switchport_status(self, result.output, "Ethernet20")
1335+
assert "trunk" in switchport_status
1336+
12901337
# add Ethernet64 to vlan 1001 but Ethernet64 is in routed mode will give error
12911338
result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["add"],
12921339
["1001", "Ethernet64"], obj=db)
@@ -1302,6 +1349,10 @@ def test_config_add_del_with_switchport_modes_changes_output(
13021349
print(result.output)
13031350
assert result.exit_code == 0
13041351
assert "Ethernet64 switched to trunk mode" in result.output
1352+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
1353+
print(result.output)
1354+
switchport_status = get_intf_switchport_status(self, result.output, "Ethernet20")
1355+
assert "trunk" in switchport_status
13051356

13061357
# add Ethernet64 to vlan 1001
13071358
result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["add"],
@@ -1332,6 +1383,11 @@ def test_config_add_del_with_switchport_modes_changes_output(
13321383
assert result.exit_code == 0
13331384
assert "Ethernet64 switched to access mode" in result.output
13341385

1386+
result = runner.invoke(show.cli.commands["interfaces"].commands["switchport"].commands["status"], obj=db)
1387+
print(result.output)
1388+
switchport_status = get_intf_switchport_status(self, result.output, "Ethernet64")
1389+
assert "access" in switchport_status
1390+
13351391
# show output
13361392
result = runner.invoke(show.cli.commands["vlan"].commands["brief"], [], obj=db)
13371393
print(result.exit_code)

0 commit comments

Comments
 (0)