Skip to content

Commit

Permalink
Sfpshow presence (#19)
Browse files Browse the repository at this point in the history
* Update the presence state of RJ45 port

Present/Not present => Link Up/Link Down
Use the new platform API to test whether the port is an RJ45 port

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Use new platform API to check whether a port is RJ45 and represent present status accordingly

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Adjust sfputil and testcases

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Adjust sfpshow

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Exact is_rj45_port to a common module shared between sfpshow and intfutil

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Fall back to old way for checking RJ45 port

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Move RJ45 part to platform_sfputil_helper

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Remove fallback mechanism in is_rj45_port

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Remove get_child_ports which is not used

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Temporarily commit

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Update unit test

Signed-off-by: stephens <stephens@contoso.com>

* Adjust unit test

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Commit missed files

Signed-off-by: Stephen Sun <stephens@nvidia.com>

* Add missing files

Signed-off-by: stephens <stephens@contoso.com>

* Fix typo

Signed-off-by: Stephen Sun <stephens@nvidia.com>

Co-authored-by: Stephen Sun <stephens@nvidia.com>
Co-authored-by: stephens <stephens@contoso.com>
  • Loading branch information
3 people authored Jul 4, 2022
1 parent f64d280 commit a3e8f5e
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 97 deletions.
41 changes: 24 additions & 17 deletions scripts/intfutil
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ import os
import re
import sys

from natsort import natsorted
from tabulate import tabulate
from utilities_common import constants
from utilities_common import multi_asic as multi_asic_util
from utilities_common.intf_filter import parse_interface_in_filter
from sonic_py_common.interface import get_intf_longname

# mock the redis for unit test purposes #
try:
if os.environ["UTILITIES_UNIT_TESTING"] == "2":
Expand All @@ -20,13 +13,24 @@ try:
sys.path.insert(0, modules_path)
sys.path.insert(0, tests_path)
import mock_tables.dbconnector
from mock_platform_sfputil.mock_platform_sfputil import mock_platform_sfputil_helper
import utilities_common.platform_sfputil_helper as platform_sfputil_helper
mock_platform_sfputil_helper(platform_sfputil_helper)
if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic":
import mock_tables.mock_multi_asic
mock_tables.dbconnector.load_namespace_config()

except KeyError:
pass

from natsort import natsorted
from tabulate import tabulate
from utilities_common import constants
from utilities_common import multi_asic as multi_asic_util
from utilities_common.intf_filter import parse_interface_in_filter
from utilities_common.platform_sfputil_helper import is_rj45_port, RJ45_PORT_TYPE
from sonic_py_common.interface import get_intf_longname

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


Expand All @@ -49,7 +53,7 @@ PORT_RMT_ADV_SPEEDS = 'rmt_adv_speeds'
PORT_INTERFACE_TYPE = 'interface_type'
PORT_ADV_INTERFACE_TYPES = 'adv_interface_types'
PORT_TPID = "tpid"
OPTICS_TYPE_RJ45 = 'RJ45'
OPTICS_TYPE_RJ45 = RJ45_PORT_TYPE
PORT_LINK_TRAINING = 'link_training'
PORT_LINK_TRAINING_STATUS = 'link_training_status'

Expand Down Expand Up @@ -161,10 +165,10 @@ def appl_db_port_status_get(appl_db, intf_name, status_type):
if status is None:
return "N/A"
if status_type == PORT_SPEED and status != "N/A":
optics_type = state_db_port_optics_get(appl_db, intf_name, PORT_OPTICS_TYPE)
optics_type = port_optics_get(appl_db, intf_name, PORT_OPTICS_TYPE)
status = port_speed_parse(status, optics_type)
elif status_type == PORT_ADV_SPEEDS and status != "N/A" and status != "all":
optics_type = state_db_port_optics_get(appl_db, intf_name, PORT_OPTICS_TYPE)
optics_type = port_optics_get(appl_db, intf_name, PORT_OPTICS_TYPE)
speed_list = status.split(',')
new_speed_list = []
for s in natsorted(speed_list):
Expand All @@ -181,7 +185,7 @@ def state_db_port_status_get(db, intf_name, field):
if not status:
return "N/A"
if field in [PORT_RMT_ADV_SPEEDS] and status not in ["N/A", "all"]:
optics_type = state_db_port_optics_get(db, intf_name, PORT_OPTICS_TYPE)
optics_type = port_optics_get(db, intf_name, PORT_OPTICS_TYPE)
speed_list = status.split(',')
new_speed_list = []
for s in natsorted(speed_list):
Expand All @@ -198,7 +202,7 @@ def port_oper_speed_get(db, intf_name):
if oper_speed is None or oper_speed == "N/A" or oper_status != "up":
return appl_db_port_status_get(db, intf_name, PORT_SPEED)
else:
optics_type = state_db_port_optics_get(db, intf_name, PORT_OPTICS_TYPE)
optics_type = port_optics_get(db, intf_name, PORT_OPTICS_TYPE)
return port_speed_parse(oper_speed, optics_type)

def port_oper_speed_get_raw(db, intf_name):
Expand All @@ -211,14 +215,17 @@ def port_oper_speed_get_raw(db, intf_name):
speed = db.get(db.APPL_DB, PORT_STATUS_TABLE_PREFIX + intf_name, PORT_SPEED)
return speed

def state_db_port_optics_get(state_db, intf_name, type):
def port_optics_get(state_db, intf_name, type):
"""
Get optic type info for port
"""
full_table_id = PORT_TRANSCEIVER_TABLE_PREFIX + intf_name
optics_type = state_db.get(state_db.STATE_DB, full_table_id, type)
if optics_type is None:
return "N/A"
if is_rj45_port(intf_name):
return OPTICS_TYPE_RJ45
else:
return "N/A"
return optics_type

def merge_dicts(x,y):
Expand Down Expand Up @@ -325,13 +332,13 @@ def po_speed_dict(po_int_dict, appl_db):
# If no speed was returned, append None without format
po_list.append(None)
else:
optics_type = state_db_port_optics_get(appl_db, value[0], PORT_OPTICS_TYPE)
optics_type = port_optics_get(appl_db, value[0], PORT_OPTICS_TYPE)
interface_speed = port_speed_parse(interface_speed, optics_type)
po_list.append(interface_speed)
elif len(value) > 1:
for intf in value:
temp_speed = port_oper_speed_get_raw(appl_db, intf)
optics_type = state_db_port_optics_get(appl_db, intf, PORT_OPTICS_TYPE)
optics_type = port_optics_get(appl_db, intf, PORT_OPTICS_TYPE)
temp_speed = int(temp_speed) if temp_speed else 0
agg_speed_list.append(temp_speed)
interface_speed = sum(agg_speed_list)
Expand Down Expand Up @@ -477,7 +484,7 @@ class IntfStatus(object):
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.db, key, PORT_OPER_STATUS),
appl_db_port_status_get(self.db, key, PORT_ADMIN_STATUS),
state_db_port_optics_get(self.db, key, PORT_OPTICS_TYPE),
port_optics_get(self.db, key, PORT_OPTICS_TYPE),
appl_db_port_status_get(self.db, key, PORT_PFC_ASYM_STATUS)))

for po, value in self.portchannel_speed_dict.items():
Expand Down
83 changes: 46 additions & 37 deletions scripts/sfpshow
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ from natsort import natsorted
from sonic_py_common.interface import front_panel_prefix, backplane_prefix, inband_prefix, recirc_prefix
from sonic_py_common import multi_asic
from tabulate import tabulate
from utilities_common import multi_asic as multi_asic_util

# Mock the redis DB for unit test purposes
try:
Expand All @@ -27,12 +26,18 @@ try:
sys.path.insert(0, modules_path)
sys.path.insert(0, test_path)
import mock_tables.dbconnector
from mock_platform_sfputil.mock_platform_sfputil import mock_platform_sfputil_helper
import utilities_common.platform_sfputil_helper as platform_sfputil_helper
mock_platform_sfputil_helper(platform_sfputil_helper)
if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic":
import mock_tables.mock_multi_asic
mock_tables.dbconnector.load_namespace_config()
except KeyError:
pass

from utilities_common import multi_asic as multi_asic_util
from utilities_common.platform_sfputil_helper import is_rj45_port, RJ45_PORT_TYPE

# TODO: We should share these maps and the formatting functions between sfputil and sfpshow
QSFP_DATA_MAP = {
'model': 'Vendor PN',
Expand Down Expand Up @@ -215,8 +220,6 @@ QSFP_DD_DOM_VALUE_UNIT_MAP = {
'voltage': 'Volts'
}

RJ45_PORT_TYPE = 'RJ45'


def display_invalid_intf_eeprom(intf_name):
output = intf_name + ': SFP EEPROM Not detected\n'
Expand All @@ -231,7 +234,6 @@ def display_invalid_intf_presence(intf_name):


class SFPShow(object):

def __init__(self, intf_name, namespace_option, dump_dom=False):
super(SFPShow, self).__init__()
self.db = None
Expand Down Expand Up @@ -394,63 +396,70 @@ class SFPShow(object):
output = ''

sfp_info_dict = state_db.get_all(state_db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interface_name))
if sfp_info_dict['type'] == RJ45_PORT_TYPE:
output = 'SFP EEPROM is not applicable for RJ45 port\n'
if sfp_info_dict:
if sfp_info_dict['type'] == RJ45_PORT_TYPE:
output = 'SFP EEPROM is not applicable for RJ45 port\n'
else:
output = 'SFP EEPROM detected\n'
sfp_info_output = self.convert_sfp_info_to_output_string(sfp_info_dict)
output += sfp_info_output

if dump_dom:
sfp_type = sfp_info_dict['type']
dom_info_dict = state_db.get_all(state_db.STATE_DB, 'TRANSCEIVER_DOM_SENSOR|{}'.format(interface_name))
dom_output = self.convert_dom_to_output_string(sfp_type, dom_info_dict)
output += dom_output
else:
output = 'SFP EEPROM detected\n'
sfp_info_output = self.convert_sfp_info_to_output_string(sfp_info_dict)
output += sfp_info_output

if dump_dom:
sfp_type = sfp_info_dict['type']
dom_info_dict = state_db.get_all(state_db.STATE_DB, 'TRANSCEIVER_DOM_SENSOR|{}'.format(interface_name))
dom_output = self.convert_dom_to_output_string(sfp_type, dom_info_dict)
output += dom_output
if is_rj45_port(interface_name):
output = 'SFP EEPROM is not applicable for RJ45 port\n'
else:
output = "SFP EEPROM Not detected\n"

return output

@multi_asic_util.run_on_multi_asic
def get_eeprom(self):
if self.intf_name is not None:
presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(self.intf_name))
if presence:
self.intf_eeprom[self.intf_name] = self.convert_interface_sfp_info_to_cli_output_string(
self.db, self.intf_name, self.dump_dom)
else:
self.intf_eeprom[self.intf_name] = "SFP EEPROM Not detected\n"
self.intf_eeprom[self.intf_name] = self.convert_interface_sfp_info_to_cli_output_string(
self.db, self.intf_name, self.dump_dom)
else:
port_table_keys = self.db.keys(self.db.APPL_DB, "PORT_TABLE:*")
for i in port_table_keys:
interface = re.split(':', i, maxsplit=1)[-1].strip()
if interface and interface.startswith(front_panel_prefix()) and not interface.startswith((backplane_prefix(), inband_prefix(), recirc_prefix())):
presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interface))
if presence:
self.intf_eeprom[interface] = self.convert_interface_sfp_info_to_cli_output_string(
self.db, interface, self.dump_dom)
else:
self.intf_eeprom[interface] = "SFP EEPROM Not detected\n"
self.intf_eeprom[interface] = self.convert_interface_sfp_info_to_cli_output_string(
self.db, interface, self.dump_dom)

def convert_interface_sfp_presence_state_to_cli_output_string(self, state_db, interface_name):
sfp_info_dict = state_db.get_all(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interface_name))
if sfp_info_dict:
if sfp_info_dict['type'] == RJ45_PORT_TYPE:
output = 'Link Up'
else:
output = 'Present'
else:
# We have to check whether it is an RJ45 port via calling platform API in case it is absent
if is_rj45_port(interface_name):
output = 'Link Down'
else:
output = 'Not present'
return output


@multi_asic_util.run_on_multi_asic
def get_presence(self):
port_table = []

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((self.intf_name, 'Present'))
else:
port_table.append((self.intf_name, 'Not present'))
presence_string = self.convert_interface_sfp_presence_state_to_cli_output_string(self.db, self.intf_name)
port_table.append((self.intf_name, presence_string))
else:
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(front_panel_prefix()) and not key.startswith((backplane_prefix(), inband_prefix(), recirc_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'))
presence_string = self.convert_interface_sfp_presence_state_to_cli_output_string(self.db, key)
port_table.append((key, presence_string))

self.table += port_table

Expand Down
43 changes: 18 additions & 25 deletions sfputil/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import click
import sonic_platform
import sonic_platform_base.sonic_sfp.sfputilhelper
from sonic_platform_base.sfp_base import SfpBase
from swsscommon.swsscommon import SonicV2Connector
from natsort import natsorted
from sonic_py_common import device_info, logger, multi_asic
Expand Down Expand Up @@ -291,27 +292,16 @@ def is_sfp_present(port_name):
return bool(presence)


# Below defined two flavors of functions to determin whether a port is a RJ45 port.
# They serve different types of SFP utilities. One type of SFP utility consume the
# info stored in the STATE_DB, these utilities shall call 'is_rj45_port_from_db'
# to judge the port type. Another type of utilities will call the platform API
# directly to access SFP, for them shall use 'is_rj45_port_from_api'.
def is_rj45_port_from_db(port_name, db):
intf_type = db.get(db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(port_name), 'type')
return intf_type == RJ45_PORT_TYPE


def is_rj45_port_from_api(port_name):
physical_port = logical_port_to_physical_port_index(port_name)
sfp = platform_chassis.get_sfp(physical_port)

try:
port_type = sfp.get_transceiver_info()['type']
port_types = platform_chassis.get_port_or_cage_type(physical_port)
return SfpBase.SFP_PORT_TYPE_BIT_RJ45 == port_types
except NotImplementedError:
click.echo("Not able to judge the port type due to get_transceiver_info not implemented!", err=True)
sys.exit(ERROR_NOT_IMPLEMENTED)
port_types = None

return port_type == RJ45_PORT_TYPE
return False


def skip_if_port_is_rj45(port_name):
Expand Down Expand Up @@ -746,7 +736,10 @@ def presence(port):
click.echo("This functionality is currently not implemented for this platform")
sys.exit(ERROR_NOT_IMPLEMENTED)

status_string = "Present" if presence else "Not present"
if is_rj45_port_from_api(logical_port_name):
status_string = "Link Up" if presence else "Link Down"
else:
status_string = "Present" if presence else "Not present"
output_table.append([port_name, status_string])

i += 1
Expand Down Expand Up @@ -843,7 +836,7 @@ def fetch_error_status_from_state_db(port, state_db):
sorted_ports = natsort.natsorted(status)
output = []
for port in sorted_ports:
if is_rj45_port_from_db(port, state_db):
if is_rj45_port_from_api(port):
description = "N/A"
else:
statestring = status[port].get('status')
Expand Down Expand Up @@ -1226,12 +1219,12 @@ def download_firmware(port_name, filepath):
def run(port_name, mode):
"""Run the firmware with default mode=1"""

skip_if_port_is_rj45(port_name)

if not is_sfp_present(port_name):
click.echo("{}: SFP EEPROM not detected\n".format(port_name))
sys.exit(EXIT_FAIL)

skip_if_port_is_rj45(port_name)

status = run_firmware(port_name, int(mode))
if status != 1:
click.echo('Failed to run firmware in mode={}! CDB status: {}'.format(mode, status))
Expand All @@ -1245,12 +1238,12 @@ def run(port_name, mode):
def commit(port_name):
"""Commit the running firmware"""

skip_if_port_is_rj45(port_name)

if not is_sfp_present(port_name):
click.echo("{}: SFP EEPROM not detected\n".format(port_name))
sys.exit(EXIT_FAIL)

skip_if_port_is_rj45(port_name)

status = commit_firmware(port_name)
if status != 1:
click.echo('Failed to commit firmware! CDB status: {}'.format(status))
Expand All @@ -1267,12 +1260,12 @@ def upgrade(port_name, filepath):

physical_port = logical_port_to_physical_port_index(port_name)

skip_if_port_is_rj45(port_name)

if not is_sfp_present(port_name):
click.echo("{}: SFP EEPROM not detected\n".format(port_name))
sys.exit(EXIT_FAIL)

skip_if_port_is_rj45(port_name)

show_firmware_version(physical_port)

status = download_firmware(port_name, filepath)
Expand Down Expand Up @@ -1303,12 +1296,12 @@ def upgrade(port_name, filepath):
def download(port_name, filepath):
"""Download firmware on the transceiver"""

skip_if_port_is_rj45(port_name)

if not is_sfp_present(port_name):
click.echo("{}: SFP EEPROM not detected\n".format(port_name))
sys.exit(EXIT_FAIL)

skip_if_port_is_rj45(port_name)

start = time.time()
status = download_firmware(port_name, filepath)
if status == 1:
Expand Down
Loading

0 comments on commit a3e8f5e

Please sign in to comment.