Skip to content

Commit

Permalink
[multi-asic] show_transceiver changes (sonic-net#1081)
Browse files Browse the repository at this point in the history
* show_interface transceiver changes for multi-asic, takes care of sub commands
       eeprom    Show interface transceiver EEPROM information
       lpmode    Show interface transceiver low-power mode...
       presence  Show interface transceiver presence  
* Rearranging of common functions in config/main.py to py-common
* Updates to show command and testcases
  • Loading branch information
judyjoseph committed Sep 4, 2020
1 parent aeaada0 commit 96cb359
Show file tree
Hide file tree
Showing 10 changed files with 788 additions and 121 deletions.
53 changes: 1 addition & 52 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from minigraph import parse_device_desc_xml
from portconfig import get_child_ports
from sonic_py_common import device_info, multi_asic
from sonic_py_common.interface import front_panel_prefix, portchannel_prefix, vlan_prefix, loopback_prefix
from sonic_py_common.interface import get_interface_table_name, get_port_table_name
from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig
from utilities_common.db import Db
from utilities_common.intf_filter import parse_interface_in_filter
Expand Down Expand Up @@ -265,18 +265,6 @@ def _get_device_type():

return device_type

# TODO move to sonic-py-common package
# Validate whether a given namespace name is valid in the device.
def validate_namespace(namespace):
if not multi_asic.is_multi_asic():
return True

namespaces = multi_asic.get_all_namespaces()
if namespace in namespaces['front_ns'] + namespaces['back_ns']:
return True
else:
return False

def interface_alias_to_name(config_db, interface_alias):
"""Return default interface name if alias name is given as argument
"""
Expand Down Expand Up @@ -372,25 +360,6 @@ def interface_name_to_alias(config_db, interface_name):

return None

# TODO move to sonic-py-common package
def get_interface_table_name(interface_name):
"""Get table name by interface_name prefix
"""
if interface_name.startswith(front_panel_prefix()):
if VLAN_SUB_INTERFACE_SEPARATOR in interface_name:
return "VLAN_SUB_INTERFACE"
return "INTERFACE"
elif interface_name.startswith(portchannel_prefix()):
if VLAN_SUB_INTERFACE_SEPARATOR in interface_name:
return "VLAN_SUB_INTERFACE"
return "PORTCHANNEL_INTERFACE"
elif interface_name.startswith(vlan_prefix()):
return "VLAN_INTERFACE"
elif interface_name.startswith(loopback_prefix()):
return "LOOPBACK_INTERFACE"
else:
return ""

def interface_ipaddr_dependent_on_interface(config_db, interface_name):
"""Get table keys including ipaddress
"""
Expand All @@ -415,26 +384,6 @@ def is_interface_bind_to_vrf(config_db, interface_name):
return True
return False

# TODO move to sonic-py-common package
# Get the table name based on the interface type
def get_port_table_name(interface_name):
"""Get table name by port_name prefix
"""
if interface_name.startswith(front_panel_prefix()):
if VLAN_SUB_INTERFACE_SEPARATOR in interface_name:
return "VLAN_SUB_INTERFACE"
return "PORT"
elif interface_name.startswith(portchannel_prefix()):
if VLAN_SUB_INTERFACE_SEPARATOR in interface_name:
return "VLAN_SUB_INTERFACE"
return "PORTCHANNEL"
elif interface_name.startswith(vlan_prefix()):
return "VLAN_INTERFACE"
elif interface_name.startswith(loopback_prefix()):
return "LOOPBACK_INTERFACE"
else:
return ""

# Return the namespace where an interface belongs
# The port name input could be in default mode or in alias mode.
def get_port_namespace(port):
Expand Down
113 changes: 78 additions & 35 deletions scripts/sfpshow
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import operator
import os

from natsort import natsorted
from swsssdk import SonicV2Connector
from tabulate import tabulate

from utilities_common import multi_asic as multi_asic_util
from sonic_py_common.interface import front_panel_prefix, backplane_prefix
from sonic_py_common import multi_asic

# Mock the redis for unit test purposes #
try:
if os.environ["UTILITIES_UNIT_TESTING"] == "2":
Expand All @@ -21,6 +24,9 @@ try:
sys.path.insert(0, modules_path)
sys.path.insert(0, test_path)
import mock_tables.dbconnector
if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic":
import mock_tables.mock_multi_asic
mock_tables.dbconnector.load_namespace_config()
except KeyError:
pass

Expand Down Expand Up @@ -126,18 +132,27 @@ dom_value_unit_map = {'rx1power': 'dBm', 'rx2power': 'dBm',
'tx3power': 'dBm', 'tx4power': 'dBm',
'temperature': 'C', 'voltage': 'Volts'}

def display_invalid_intf_eeprom(intf_name):
output = intf_name + ': ' + 'SFP EEPROM Not detected' + '\n'
click.echo(output)

def display_invalid_intf_presence(intf_name):
header = ['Port', 'Presence']
port_table = []
port_table.append((intf_name, 'Not present'))
click.echo(tabulate(port_table, header))

class SFPShow(object):

def __init__(self):
def __init__(self, intf_name, namespace_option, dump_dom=False):
super(SFPShow,self).__init__()
self.adb = SonicV2Connector(host="127.0.0.1")
self.adb.connect(self.adb.APPL_DB)

self.sdb = SonicV2Connector(host="127.0.0.1")
self.sdb.connect(self.sdb.STATE_DB)
return
self.db = None
self.config_db = None
self.intf_name = intf_name
self.dump_dom = dump_dom
self.table = []
self.output = ''
self.multi_asic = multi_asic_util.MultiAsic(namespace_option=namespace_option)

# Convert dict values to cli output string
def format_dict_value_to_string(self, sorted_key_table,
Expand Down Expand Up @@ -291,53 +306,61 @@ class SFPShow(object):

return out_put

def display_eeprom(self, interfacename, dump_dom):
@multi_asic_util.run_on_multi_asic
def get_eeprom(self):
out_put = ''

if interfacename is not None:
presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interfacename))
if self.intf_name is not None:
presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(self.intf_name))
if presence:
out_put = self.convert_interface_sfp_info_to_cli_output_string(self.sdb, interfacename, dump_dom)
out_put = self.convert_interface_sfp_info_to_cli_output_string(self.db, self.intf_name, self.dump_dom)
else:
out_put = out_put + interfacename + ': ' + 'SFP EEPROM Not detected' + '\n'
out_put = out_put + self.intf_name + ': ' + 'SFP EEPROM Not detected' + '\n'
else:
port_table_keys = self.adb.keys(self.adb.APPL_DB, "PORT_TABLE:*")
port_table_keys = self.db.keys(self.db.APPL_DB, "PORT_TABLE:*")
sorted_table_keys = natsorted(port_table_keys)
for i in sorted_table_keys:
interface = re.split(':', i, maxsplit=1)[-1].strip()
if interface and interface.startswith('Ethernet'):
presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interface))
if interface and interface.startswith(front_panel_prefix()) and not interface.startswith(backplane_prefix()):
presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interface))
if presence:
out_put = out_put + self.convert_interface_sfp_info_to_cli_output_string(self.sdb, interface, dump_dom)
out_put = out_put + self.convert_interface_sfp_info_to_cli_output_string(self.db, interface, self.dump_dom)
else:
out_put = out_put + interface + ': ' + 'SFP EEPROM Not detected' + '\n'

out_put = out_put + '\n'
out_put = out_put + '\n'

click.echo(out_put)
self.output += out_put

def display_presence(self, interfacename):
@multi_asic_util.run_on_multi_asic
def get_presence(self):
port_table = []
header = ['Port', 'Presence']

if interfacename is not None:
presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interfacename))
if self.intf_name is not None:
presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(self.intf_name))
if presence:
port_table.append((interfacename, 'Present'))
port_table.append((self.intf_name, 'Present'))
else:
port_table.append((interfacename, 'Not present'))
port_table.append((self.intf_name, 'Not present'))
else:
port_table_keys = self.adb.keys(self.adb.APPL_DB, "PORT_TABLE:*")
port_table_keys = self.db.keys(self.db.APPL_DB, "PORT_TABLE:*")
for i in port_table_keys:
key = re.split(':', i, maxsplit=1)[-1].strip()
if key and key.startswith('Ethernet'):
presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(key))
if key and key.startswith(front_panel_prefix()) and not key.startswith(backplane_prefix()):
presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(key))
if presence:
port_table.append((key,'Present'))
else:
port_table.append((key,'Not present'))

sorted_port_table = natsorted(port_table)
self.table += port_table

def display_eeprom(self):
click.echo(self.output)

def display_presence(self):
header = ['Port', 'Presence']
sorted_port_table = natsorted(self.table)
click.echo(tabulate(sorted_port_table, header))

# This is our main entrypoint - the main 'sfpshow' command
Expand All @@ -350,16 +373,36 @@ def cli():
@cli.command()
@click.option('-p', '--port', metavar='<port_name>', help="Display SFP EEPROM data for port <port_name> only")
@click.option('-d', '--dom', 'dump_dom', is_flag=True, help="Also display Digital Optical Monitoring (DOM) data")
def eeprom(port, dump_dom):
sfp = SFPShow()
sfp.display_eeprom(port, dump_dom)
@click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace")
def eeprom(port, dump_dom, namespace):
if port and multi_asic.is_multi_asic() and namespace is None:
try:
ns = multi_asic.get_namespace_for_port(port)
namespace=ns
except Exception:
display_invalid_intf_eeprom(port)
sys.exit(1)

sfp = SFPShow(port, namespace, dump_dom)
sfp.get_eeprom()
sfp.display_eeprom()

# 'presence' subcommand
@cli.command()
@click.option('-p', '--port', metavar='<port_name>', help="Display SFP presence for port <port_name> only")
def presence(port):
sfp = SFPShow()
sfp.display_presence(port)
@click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace")
def presence(port, namespace):
if port and multi_asic.is_multi_asic() and namespace is None:
try:
ns = multi_asic.get_namespace_for_port(port)
namespace=ns
except Exception:
display_invalid_intf_presence(port)
sys.exit(1)

sfp = SFPShow(port, namespace)
sfp.get_presence()
sfp.display_presence()

if __name__ == "__main__":
cli()
14 changes: 12 additions & 2 deletions show/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,10 @@ def transceiver():
@transceiver.command()
@click.argument('interfacename', required=False)
@click.option('-d', '--dom', 'dump_dom', is_flag=True, help="Also display Digital Optical Monitoring (DOM) data")
@click.option('--namespace', '-n', 'namespace', default=None, show_default=True,
type=click.Choice(multi_asic_util.multi_asic_ns_choices()), help='Namespace name or all')
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def eeprom(interfacename, dump_dom, verbose):
def eeprom(interfacename, dump_dom, namespace, verbose):
"""Show interface transceiver EEPROM information"""

ctx = click.get_current_context()
Expand All @@ -300,6 +302,9 @@ def eeprom(interfacename, dump_dom, verbose):

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

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

clicommon.run_command(cmd, display_cmd=verbose)

@transceiver.command()
Expand All @@ -321,9 +326,11 @@ def lpmode(interfacename, verbose):

@transceiver.command()
@click.argument('interfacename', required=False)
@click.option('--namespace', '-n', 'namespace', default=None, show_default=True,
type=click.Choice(multi_asic_util.multi_asic_ns_choices()), help='Namespace name or all')
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@clicommon.pass_db
def presence(db, interfacename, verbose):
def presence(db, interfacename, namespace, verbose):
"""Show interface transceiver presence"""

ctx = click.get_current_context()
Expand All @@ -335,6 +342,9 @@ def presence(db, interfacename, verbose):

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

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

clicommon.run_command(cmd, display_cmd=verbose)


Expand Down
Loading

0 comments on commit 96cb359

Please sign in to comment.