Skip to content

Commit

Permalink
show subinterfaces status (#642)
Browse files Browse the repository at this point in the history
* Add sub port interface to intfutil status

Signed-off-by: Wenda Ni <[email protected]>

* Format change

Signed-off-by: Wenda Ni <[email protected]>

* Hook 'intfutil status' with show subinterfaces status

Signed-off-by: Wenda Ni <[email protected]>

* Add 'intfutil status subport' to show only the status of sub port interfaces

Signed-off-by: Wenda Ni <[email protected]>

* Hook 'intfutil status subport' with 'show subinterfaces status'

Signed-off-by: Wenda Ni <[email protected]>

* Support intfutil status <sub_port_intf_name>

Signed-off-by: Wenda Ni <[email protected]>

* Add alias naming mode support

Signed-off-by: Wenda Ni <[email protected]>

* Address comments

Signed-off-by: Wenda Ni <[email protected]>

* Address comment: concatenate command line, and validate input

Signed-off-by: Wenda Ni <[email protected]>

* Address comment: keep show interface status intact

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for show interfaces status / intfutil status

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for 'show interfaces status --verbose'

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for 'show subinterfaces status' / 'intfutil status subport'

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for 'show subinterfaces status --verbose'

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for single sub interface status show

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for '--verbose' single sub interface status show

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for showing status of single sub interface in alias naming mode

Signed-off-by: Wenda Ni <[email protected]>

* Add unit test for '--verbose' status of single sub interface in alias naming mode

Signed-off-by: Wenda Ni <[email protected]>
  • Loading branch information
wendani authored and lguohan committed Nov 5, 2019
1 parent 8218b09 commit 1b0d542
Show file tree
Hide file tree
Showing 5 changed files with 325 additions and 35 deletions.
165 changes: 135 additions & 30 deletions scripts/intfutil
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,18 @@ from tabulate import tabulate
from natsort import natsorted
from swsssdk import ConfigDBConnector
from pprint import pprint

import os

# mock the redis for unit test purposes #
try:
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
modules_path = os.path.join(os.path.dirname(__file__), "..")
tests_path = os.path.join(modules_path, "sonic-utilities-tests")
sys.path.insert(0, modules_path)
sys.path.insert(0, tests_path)
import mock_tables.dbconnector
except KeyError:
pass

# ========================== Common interface-utils logic ==========================

Expand All @@ -25,6 +36,11 @@ PORT_DESCRIPTION = "description"
PORT_OPTICS_TYPE = "type"
PORT_PFC_ASYM_STATUS = "pfc_asym"

VLAN_SUB_INTERFACE_SEPARATOR = "."
VLAN_SUB_INTERFACE_TYPE = "802.1q-encapsulation"

SUB_PORT = "subport"

def db_connect_configdb():
"""
Connect to configdb
Expand All @@ -43,6 +59,15 @@ def get_frontpanel_port_list(config_db):
return front_panel_ports_list


def get_sub_port_intf_list(config_db):
sub_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE')
sub_intf_list = []
for sub_intf in sub_intf_dict.keys():
if isinstance(sub_intf, basestring):
sub_intf_list.append(sub_intf)
return sub_intf_list


def get_interface_vlan_dict(config_db):
"""
Get info from REDIS ConfigDB and create interface to vlan mapping
Expand Down Expand Up @@ -93,6 +118,24 @@ def appl_db_keys_get(appl_db, front_panel_ports_list, intf_name):
return appl_db_keys


def appl_db_sub_intf_keys_get(appl_db, sub_intf_list, sub_intf_name):
"""
Get APPL_DB sub port interface keys
"""
if sub_intf_name is None:
appl_db_sub_intf_keys = []
appl_db_intf_keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:*")
if appl_db_intf_keys is not None:
for appl_db_intf_key in appl_db_intf_keys:
if re.split(':', appl_db_intf_key, maxsplit=1)[-1].strip() in sub_intf_list:
appl_db_sub_intf_keys.append(appl_db_intf_key)
elif sub_intf_name in sub_intf_list:
appl_db_sub_intf_keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:%s" % sub_intf_name)
else:
return []
return appl_db_sub_intf_keys


def appl_db_port_status_get(appl_db, intf_name, status_type):
"""
Get the port status
Expand Down Expand Up @@ -267,13 +310,42 @@ def appl_db_portchannel_status_get(appl_db, config_db, po_name, status_type, por
return "N/A"
return status

def appl_db_sub_intf_status_get(appl_db, config_db, front_panel_ports_list, portchannel_speed_dict, sub_intf_name, status_type):
sub_intf_sep_idx = sub_intf_name.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx != -1:
parent_port_name = sub_intf_name[:sub_intf_sep_idx]
vlan_id = sub_intf_name[sub_intf_sep_idx + 1:]

full_intf_table_name = "INTF_TABLE" + ":" + sub_intf_name

if status_type == "vlan":
return vlan_id

if status_type == "admin_status":
status = appl_db.get(appl_db.APPL_DB, full_intf_table_name, status_type)
return status if status is not None else "N/A"

if status_type == "type":
return VLAN_SUB_INTERFACE_TYPE

if status_type == "mtu" or status_type == "speed":
if parent_port_name in front_panel_ports_list:
return appl_db_port_status_get(appl_db, parent_port_name, status_type)
elif parent_port_name in portchannel_speed_dict.keys():
return appl_db_portchannel_status_get(appl_db, config_db, parent_port_name, status_type, portchannel_speed_dict)
else:
return "N/A"

return "N/A"

# ========================== interface-status logic ==========================

header_stat = ['Interface', 'Lanes', 'Speed', 'MTU', 'Alias', 'Vlan', 'Oper', 'Admin', 'Type', 'Asym PFC']
header_stat_sub_intf = ['Sub port interface', 'Speed', 'MTU', 'Vlan', 'Admin', 'Type']

class IntfStatus(object):

def display_intf_status(self, appl_db_keys, front_panel_ports_list, portchannel_speed_dict):
def display_intf_status(self, appl_db_keys, front_panel_ports_list, portchannel_speed_dict, appl_db_sub_intf_keys, sub_intf_list, sub_intf_only):
"""
Generate interface-status output
"""
Expand All @@ -286,35 +358,47 @@ class IntfStatus(object):
# Iterate through all the keys and append port's associated state to
# the result table.
#
for i in appl_db_keys:
key = re.split(':', i, maxsplit=1)[-1].strip()
if key in front_panel_ports_list:
table.append((key,
appl_db_port_status_get(self.appl_db, key, PORT_LANES_STATUS),
appl_db_port_status_get(self.appl_db, key, PORT_SPEED),
appl_db_port_status_get(self.appl_db, key, PORT_MTU_STATUS),
appl_db_port_status_get(self.appl_db, key, PORT_ALIAS),
config_db_vlan_port_keys_get(self.combined_int_to_vlan_po_dict, self.front_panel_ports_list, key),
appl_db_port_status_get(self.appl_db, key, PORT_OPER_STATUS),
appl_db_port_status_get(self.appl_db, key, PORT_ADMIN_STATUS),
state_db_port_optics_get(self.state_db, key, PORT_OPTICS_TYPE),
appl_db_port_status_get(self.appl_db, key, PORT_PFC_ASYM_STATUS)))
# Sorting and tabulating the result table.
for po, value in portchannel_speed_dict.iteritems():
if po:
table.append((po,
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_LANES_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_SPEED, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_MTU_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ALIAS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, "vlan", self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPER_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ADMIN_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPTICS_TYPE, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_PFC_ASYM_STATUS, self.portchannel_speed_dict)))
if not sub_intf_only:
for i in appl_db_keys:
key = re.split(':', i, maxsplit=1)[-1].strip()
if key in front_panel_ports_list:
table.append((key,
appl_db_port_status_get(self.appl_db, key, PORT_LANES_STATUS),
appl_db_port_status_get(self.appl_db, key, PORT_SPEED),
appl_db_port_status_get(self.appl_db, key, PORT_MTU_STATUS),
appl_db_port_status_get(self.appl_db, key, PORT_ALIAS),
config_db_vlan_port_keys_get(self.combined_int_to_vlan_po_dict, self.front_panel_ports_list, key),
appl_db_port_status_get(self.appl_db, key, PORT_OPER_STATUS),
appl_db_port_status_get(self.appl_db, key, PORT_ADMIN_STATUS),
state_db_port_optics_get(self.state_db, key, PORT_OPTICS_TYPE),
appl_db_port_status_get(self.appl_db, key, PORT_PFC_ASYM_STATUS)))

for po, value in portchannel_speed_dict.iteritems():
if po:
table.append((po,
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_LANES_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_SPEED, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_MTU_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ALIAS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, "vlan", self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPER_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ADMIN_STATUS, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPTICS_TYPE, self.portchannel_speed_dict),
appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_PFC_ASYM_STATUS, self.portchannel_speed_dict)))
else:
for key in appl_db_sub_intf_keys:
sub_intf = re.split(':', key, maxsplit=1)[-1].strip()
if sub_intf in sub_intf_list:
table.append((sub_intf,
appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_SPEED),
appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_MTU_STATUS),
appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, "vlan"),
appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_ADMIN_STATUS),
appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_OPTICS_TYPE)))

# Sorting and tabulating the result table.
sorted_table = natsorted(table)
print tabulate(sorted_table, header_stat, tablefmt="simple", stralign='right')
print tabulate(sorted_table, header_stat if not sub_intf_only else header_stat_sub_intf, tablefmt="simple", stralign='right')


def __init__(self, intf_name):
Expand All @@ -333,6 +417,20 @@ class IntfStatus(object):
return
if self.config_db is None:
return

sub_intf_only = False
sub_intf_name = intf_name
if intf_name is not None:
if intf_name == SUB_PORT:
intf_name = None
sub_intf_name = None
sub_intf_only = True
else:
sub_intf_sep_idx = intf_name.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx != -1:
sub_intf_only = True
intf_name = intf_name[:sub_intf_sep_idx]

self.front_panel_ports_list = get_frontpanel_port_list(self.config_db)
appl_db_keys = appl_db_keys_get(self.appl_db, self.front_panel_ports_list, intf_name)
self.int_to_vlan_dict = get_interface_vlan_dict(self.config_db)
Expand All @@ -344,9 +442,12 @@ class IntfStatus(object):
self.combined_int_to_vlan_po_dict = merge_dicts(self.int_to_vlan_dict, self.int_po_dict)
self.portchannel_speed_dict = po_speed_dict(self.po_int_dict, self.appl_db)
self.portchannel_keys = self.portchannel_speed_dict.keys()

self.sub_intf_list = get_sub_port_intf_list(self.config_db)
appl_db_sub_intf_keys = appl_db_sub_intf_keys_get(self.appl_db, self.sub_intf_list, sub_intf_name)
if appl_db_keys is None:
return
self.display_intf_status(appl_db_keys, self.front_panel_ports_list, self.portchannel_speed_dict)
self.display_intf_status(appl_db_keys, self.front_panel_ports_list, self.portchannel_speed_dict, appl_db_sub_intf_keys, self.sub_intf_list, sub_intf_only)



Expand Down Expand Up @@ -392,6 +493,10 @@ class IntfDescription(object):
return
if self.config_db is None:
return

if intf_name is not None and intf_name == SUB_PORT:
intf_name = None

self.front_panel_ports_list = get_frontpanel_port_list(self.config_db)
appl_db_keys = appl_db_keys_get(self.appl_db, self.front_panel_ports_list, intf_name)
if appl_db_keys is None:
Expand Down
58 changes: 54 additions & 4 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'

VLAN_SUB_INTERFACE_SEPARATOR = '.'

try:
# noinspection PyPep8Naming
import ConfigParser as configparser
Expand Down Expand Up @@ -74,25 +76,42 @@ def name_to_alias(self, interface_name):
"""Return vendor interface alias if SONiC
interface name is given as argument
"""
vlan_id = ''
sub_intf_sep_idx = -1
if interface_name is not None:
sub_intf_sep_idx = interface_name.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx != -1:
vlan_id = interface_name[sub_intf_sep_idx + 1:]
# interface_name holds the parent port name
interface_name = interface_name[:sub_intf_sep_idx]

for port_name in self.port_dict.keys():
if interface_name == port_name:
return self.port_dict[port_name]['alias']
return self.port_dict[port_name]['alias'] if sub_intf_sep_idx == -1 \
else self.port_dict[port_name]['alias'] + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id

# interface_name not in port_dict. Just return interface_name
return interface_name
return interface_name if sub_intf_sep_idx == -1 else interface_name + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id

def alias_to_name(self, interface_alias):
"""Return SONiC interface name if vendor
port alias is given as argument
"""
vlan_id = ''
sub_intf_sep_idx = -1
if interface_alias is not None:
sub_intf_sep_idx = interface_alias.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx != -1:
vlan_id = interface_alias[sub_intf_sep_idx + 1:]
# interface_alias holds the parent port alias
interface_alias = interface_alias[:sub_intf_sep_idx]

for port_name in self.port_dict.keys():
if interface_alias == self.port_dict[port_name]['alias']:
return port_name
return port_name if sub_intf_sep_idx == -1 else port_name + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id

# interface_alias not in port_dict. Just return interface_alias
return interface_alias
return interface_alias if sub_intf_sep_idx == -1 else interface_alias + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id


# Global Config object
Expand Down Expand Up @@ -789,6 +808,37 @@ def portchannel(verbose):
cmd = "sudo teamshow"
run_command(cmd, display_cmd=verbose)

#
# 'subinterfaces' group ("show subinterfaces ...")
#

@cli.group(cls=AliasedGroup, default_if_no_args=False)
def subinterfaces():
"""Show details of the sub port interfaces"""
pass

# 'subinterfaces' subcommand ("show subinterfaces status")
@subinterfaces.command()
@click.argument('subinterfacename', type=str, required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def status(subinterfacename, verbose):
"""Show sub port interface status information"""
cmd = "intfutil status "

if subinterfacename is not None:
sub_intf_sep_idx = subinterfacename.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx == -1:
print("Invalid sub port interface name")
return

if get_interface_mode() == "alias":
subinterfacename = iface_alias_converter.alias_to_name(subinterfacename)

cmd += subinterfacename
else:
cmd += "subport"
run_command(cmd, display_cmd=verbose)

#
# 'pfc' group ("show pfc ...")
#
Expand Down
Loading

0 comments on commit 1b0d542

Please sign in to comment.