Skip to content

Commit

Permalink
Moving media_settings.json functionality to a separate file and updat…
Browse files Browse the repository at this point in the history
…ing xcvrd accordingly
  • Loading branch information
tshalvi committed Oct 16, 2023
1 parent 404e6ff commit 1a7bd24
Show file tree
Hide file tree
Showing 2 changed files with 334 additions and 304 deletions.
310 changes: 6 additions & 304 deletions sonic-xcvrd/xcvrd/xcvrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from .xcvrd_utilities import sfp_status_helper
from .xcvrd_utilities import port_mapping
from .xcvrd_utilities import media_settings_parser
from .xcvrd_utilities import optics_si_parser

from sonic_platform_base.sonic_xcvr.api.public.c_cmis import CmisApi
Expand Down Expand Up @@ -97,8 +98,6 @@
# Global chassis object based on new platform api
platform_chassis = None

LANE_SPEED_KEY_PREFIX = "speed:"

# Global logger instance for helper functions and classes
# TODO: Refactor so that we only need the logger inherited
# by DaemonXcvrd
Expand Down Expand Up @@ -639,292 +638,6 @@ def del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, int_tbl, dom_
sys.exit(NOT_IMPLEMENTED_ERROR)


def check_port_in_range(range_str, physical_port):
RANGE_SEPARATOR = '-'

range_list = range_str.split(RANGE_SEPARATOR)
start_num = int(range_list[0].strip())
end_num = int(range_list[1].strip())
if start_num <= physical_port <= end_num:
return True
return False

def is_si_per_speed_supported(media_dict):
return LANE_SPEED_KEY_PREFIX in list(media_dict.keys())[0]

def get_media_settings_value(physical_port, key):
GLOBAL_MEDIA_SETTINGS_KEY = 'GLOBAL_MEDIA_SETTINGS'
PORT_MEDIA_SETTINGS_KEY = 'PORT_MEDIA_SETTINGS'
DEFAULT_KEY = 'Default'
RANGE_SEPARATOR = '-'
COMMA_SEPARATOR = ','
media_dict = {}
default_dict = {}

# Keys under global media settings can be a list or range or list of ranges
# of physical port numbers. Below are some examples
# 1-32
# 1,2,3,4,5
# 1-4,9-12

if GLOBAL_MEDIA_SETTINGS_KEY in g_dict:
for keys in g_dict[GLOBAL_MEDIA_SETTINGS_KEY]:
if COMMA_SEPARATOR in keys:
port_list = keys.split(COMMA_SEPARATOR)
for port in port_list:
if RANGE_SEPARATOR in port:
if check_port_in_range(port, physical_port):
media_dict = g_dict[GLOBAL_MEDIA_SETTINGS_KEY][keys]
break
elif str(physical_port) == port:
media_dict = g_dict[GLOBAL_MEDIA_SETTINGS_KEY][keys]
break

elif RANGE_SEPARATOR in keys:
if check_port_in_range(keys, physical_port):
media_dict = g_dict[GLOBAL_MEDIA_SETTINGS_KEY][keys]

# If there is a match in the global profile for a media type,
# fetch those values
if key[0] in media_dict: # key[0] = vendor_key (e.g: 'AMPHENOL-1234')
if is_si_per_speed_supported(media_dict[key[0]]):
if key[2] is not None and key[2] in media_dict[key[0]]: # key[2] = lane_speed_key (e.g: 'speed:400GAUI-8')
return media_dict[key[0]][key[2]]
else:
return {}
else:
return media_dict[key[0]]
elif key[1] in media_dict: # key[1] = media_key (e.g: 'QSFP28-40GBASE-CR4-1M')
if is_si_per_speed_supported(media_dict[key[1]]):
if key[2] is not None and key[2] in media_dict[key[1]]:
return media_dict[key[1]][key[2]]
else:
return {}
else:
return media_dict[key[1]]
elif DEFAULT_KEY in media_dict:
default_dict = media_dict[DEFAULT_KEY]

media_dict = {}

if PORT_MEDIA_SETTINGS_KEY in g_dict:
for keys in g_dict[PORT_MEDIA_SETTINGS_KEY]:
if int(keys) == physical_port:
media_dict = g_dict[PORT_MEDIA_SETTINGS_KEY][keys]
break

if len(media_dict) == 0:
if len(default_dict) != 0:
return default_dict
else:
helper_logger.log_error("Error: No values for physical port '{}'".format(physical_port))
return {}

if key[0] in media_dict:
if is_si_per_speed_supported(media_dict[key[0]]):
if key[2] is not None and key[2] in media_dict[key[0]]:
return media_dict[key[0]][key[2]]
else:
return {}
else:
return media_dict[key[0]]
elif key[1] in media_dict:
if is_si_per_speed_supported(media_dict[key[1]]):
if key[2] is not None and key[2] in media_dict[key[1]]:
return media_dict[key[1]][key[2]]
else:
return {}
else:
return media_dict[key[1]]
elif DEFAULT_KEY in media_dict:
return media_dict[DEFAULT_KEY]
elif len(default_dict) != 0:
return default_dict
else:
if len(default_dict) != 0:
return default_dict

return {}


def get_speed_and_lane_count(port, cfg_port_tbl):
port_speed, lane_count = '0', 0
found, port_info = cfg_port_tbl.get(port)
port_info_dict = dict(port_info)
if found and 'speed' in port_info_dict and 'lanes' in port_info_dict:
port_speed = port_info_dict['speed']
lanes = port_info_dict['lanes']
lane_count = len(lanes.split(','))
return port_speed, lane_count


def get_lane_speed_key(physical_port, port_speed, lane_count):
sfp = platform_chassis.get_sfp(physical_port)
api = sfp.get_xcvr_api()

lane_speed_key = None
if is_cmis_api(api):
appl_adv_dict = api.get_application_advertisement()
app_id = get_cmis_application_desired(api, int(lane_count), int(port_speed))
if app_id and app_id in appl_adv_dict:
host_electrical_interface_id = appl_adv_dict[app_id].get('host_electrical_interface_id')
if host_electrical_interface_id:
lane_speed_key = LANE_SPEED_KEY_PREFIX + host_electrical_interface_id.split()[0]

return lane_speed_key


def get_media_settings_key(physical_port, transceiver_dict, port_speed, lane_count):
sup_compliance_str = '10/40G Ethernet Compliance Code'
sup_len_str = 'Length Cable Assembly(m)'
vendor_name_str = transceiver_dict[physical_port]['manufacturer']
vendor_pn_str = transceiver_dict[physical_port]['model']
vendor_key = vendor_name_str.upper() + '-' + vendor_pn_str

media_len = ''
if transceiver_dict[physical_port]['cable_type'] == sup_len_str:
media_len = transceiver_dict[physical_port]['cable_length']

media_compliance_dict_str = transceiver_dict[physical_port]['specification_compliance']
media_compliance_code = ''
media_type = ''
media_key = ''
media_compliance_dict = {}

try:
if _wrapper_get_sfp_type(physical_port) == 'QSFP_DD':
media_compliance_code = media_compliance_dict_str
else:
media_compliance_dict = ast.literal_eval(media_compliance_dict_str)
if sup_compliance_str in media_compliance_dict:
media_compliance_code = media_compliance_dict[sup_compliance_str]
except ValueError as e:
helper_logger.log_error("Invalid value for port {} 'specification_compliance': {}".format(physical_port, media_compliance_dict_str))

media_type = transceiver_dict[physical_port]['type_abbrv_name']

if len(media_type) != 0:
media_key += media_type
if len(media_compliance_code) != 0:
media_key += '-' + media_compliance_code
if _wrapper_get_sfp_type(physical_port) == 'QSFP_DD':
if media_compliance_code == "passive_copper_media_interface":
if media_len != 0:
media_key += '-' + str(media_len) + 'M'
else:
if media_len != 0:
media_key += '-' + str(media_len) + 'M'
else:
media_key += '-' + '*'

lane_speed_key = get_lane_speed_key(physical_port, port_speed, lane_count)
return (vendor_key, media_key, lane_speed_key)


def get_media_val_str_from_dict(media_dict):
LANE_STR = 'lane'
LANE_SEPARATOR = ','

media_str = ''
tmp_dict = {}

for keys in media_dict:
lane_num = int(keys.strip()[len(LANE_STR):])
tmp_dict[lane_num] = media_dict[keys]

for key in range(0, len(tmp_dict)):
media_str += tmp_dict[key]
if key != list(tmp_dict.keys())[-1]:
media_str += LANE_SEPARATOR
return media_str


def get_media_val_str(num_logical_ports, lane_dict, logical_idx):
LANE_STR = 'lane'

logical_media_dict = {}
num_lanes_on_port = len(lane_dict)

# The physical ports has more than one logical port meaning it is
# in breakout mode. So fetch the corresponding lanes from the file
media_val_str = ''
if (num_logical_ports > 1) and \
(num_lanes_on_port >= num_logical_ports):
num_lanes_per_logical_port = num_lanes_on_port//num_logical_ports
start_lane = logical_idx * num_lanes_per_logical_port

for lane_idx in range(start_lane, start_lane +
num_lanes_per_logical_port):
lane_idx_str = LANE_STR + str(lane_idx)
logical_lane_idx_str = LANE_STR + str(lane_idx - start_lane)
logical_media_dict[logical_lane_idx_str] = lane_dict[lane_idx_str]

media_val_str = get_media_val_str_from_dict(logical_media_dict)
else:
media_val_str = get_media_val_str_from_dict(lane_dict)
return media_val_str


def notify_media_setting(logical_port_name, transceiver_dict,
app_port_tbl, cfg_port_tbl, port_mapping):

if not g_dict:
return

port_speed, lane_count = get_speed_and_lane_count(logical_port_name, cfg_port_tbl)

ganged_port = False
ganged_member_num = 1

physical_port_list = port_mapping.logical_port_name_to_physical_port_list(logical_port_name)
if physical_port_list is None:
helper_logger.log_error("Error: No physical ports found for logical port '{}'".format(logical_port_name))
return PHYSICAL_PORT_NOT_EXIST

if len(physical_port_list) > 1:
ganged_port = True

for physical_port in physical_port_list:
logical_port_list = port_mapping.get_physical_to_logical(physical_port)
num_logical_ports = len(logical_port_list)
logical_idx = logical_port_list.index(logical_port_name)
if not _wrapper_get_presence(physical_port):
helper_logger.log_info("Media {} presence not detected during notify".format(physical_port))
continue
if physical_port not in transceiver_dict:
helper_logger.log_error("Media {} eeprom not populated in transceiver dict".format(physical_port))
continue

port_name = get_physical_port_name(logical_port_name,
ganged_member_num, ganged_port)

ganged_member_num += 1
key = get_media_settings_key(physical_port, transceiver_dict, port_speed, lane_count)
helper_logger.log_debug("Retrieving media settings for port {} using the following keys: {}".format(logical_port_name, key))
media_dict = get_media_settings_value(physical_port, key)

if len(media_dict) == 0:
helper_logger.log_error("Error in obtaining media setting for {}".format(logical_port_name))
return

fvs = swsscommon.FieldValuePairs(len(media_dict))

index = 0
helper_logger.log_debug("Storing in Application DB the following media settings for port {}:".format(logical_port_name))
for media_key in media_dict:
if type(media_dict[media_key]) is dict:
media_val_str = get_media_val_str(num_logical_ports,
media_dict[media_key],
logical_idx)
else:
media_val_str = media_dict[media_key]
helper_logger.log_debug("{}:({},{}) ".format(index, str(media_key), str(media_val_str)))
fvs[index] = (str(media_key), str(media_val_str))
index += 1

app_port_tbl.set(port_name, fvs)


def waiting_time_compensation_with_sleep(time_start, time_to_wait):
time_now = time.time()
time_diff = time_now - time_start
Expand Down Expand Up @@ -1996,7 +1709,7 @@ def _post_port_sfp_info_and_dom_thr_to_db_once(self, port_mapping, xcvr_table_he

# Do not notify media settings during warm reboot to avoid dataplane traffic impact
if is_warm_start == False:
notify_media_setting(logical_port_name, transceiver_dict, xcvr_table_helper.get_app_port_tbl(asic_index), xcvr_table_helper.get_cfg_port_tbl(asic_index), port_mapping)
media_settings_parser.notify_media_setting(logical_port_name, transceiver_dict, xcvr_table_helper.get_app_port_tbl(asic_index), xcvr_table_helper.get_cfg_port_tbl(asic_index), port_mapping)
transceiver_dict.clear()
else:
retry_eeprom_set.add(logical_port_name)
Expand Down Expand Up @@ -2218,7 +1931,7 @@ def task_worker(self, stopping_event, sfp_error_event):

if rc != SFP_EEPROM_NOT_READY:
post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_threshold_tbl(asic_index))
notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(asic_index), self.xcvr_table_helper.get_cfg_port_tbl(asic_index), self.port_mapping)
media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(asic_index), self.xcvr_table_helper.get_cfg_port_tbl(asic_index), self.port_mapping)
transceiver_dict.clear()
elif value == sfp_status_helper.SFP_STATUS_REMOVED:
helper_logger.log_notice("{}: Got SFP removed event".format(logical_port))
Expand Down Expand Up @@ -2417,7 +2130,7 @@ def on_add_logical_port(self, port_change_event):
self.retry_eeprom_set.add(port_change_event.port_name)
else:
post_port_dom_threshold_info_to_db(port_change_event.port_name, self.port_mapping, dom_threshold_tbl)
notify_media_setting(port_change_event.port_name, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_cfg_port_tbl(port_change_event.asic_id), self.port_mapping)
media_settings_parser.notify_media_setting(port_change_event.port_name, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_cfg_port_tbl(port_change_event.asic_id), self.port_mapping)
else:
status = sfp_status_helper.SFP_STATUS_REMOVED if not status else status
update_port_transceiver_status_table_sw(port_change_event.port_name, status_tbl, status, error_description)
Expand All @@ -2443,7 +2156,7 @@ def retry_eeprom_reading(self):
rc = post_port_sfp_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_intf_tbl(asic_index), transceiver_dict)
if rc != SFP_EEPROM_NOT_READY:
post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_threshold_tbl(asic_index))
notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(asic_index), self.xcvr_table_helper.get_cfg_port_tbl(asic_index), self.port_mapping)
media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(asic_index), self.xcvr_table_helper.get_cfg_port_tbl(asic_index), self.port_mapping)
transceiver_dict.clear()
retry_success_set.add(logical_port)
# Update retry EEPROM set
Expand Down Expand Up @@ -2499,17 +2212,6 @@ def wait_for_port_config_done(self, namespace):
if key in ["PortConfigDone", "PortInitDone"]:
break

def load_media_settings(self):
global g_dict
(platform_path, _) = device_info.get_paths_to_platform_and_hwsku_dirs()

media_settings_file_path = os.path.join(platform_path, "media_settings.json")
if not os.path.isfile(media_settings_file_path):
self.log_info("xcvrd: No media file exists")
return {}

with open(media_settings_file_path, "r") as media_file:
g_dict = json.load(media_file)

# Initialize daemon
def init(self):
Expand Down Expand Up @@ -2554,7 +2256,7 @@ def init(self):
if is_fast_reboot_enabled():
self.log_info("Skip loading media_settings.json and optics_si_settings.json in case of fast-reboot")
else:
self.load_media_settings()
media_settings_parser.load_media_settings()
optics_si_parser.load_optics_si_settings()

# Make sure this daemon started after all port configured
Expand Down
Loading

0 comments on commit 1a7bd24

Please sign in to comment.