Skip to content

Commit 19594b9

Browse files
authored
Fix show int transceiver EEPROM crash for for Backplane cartridge + enhance EEPROM CLI output (sonic-net#4020)
* Fix show int transceiver EEPROM crash for for Backplane cartridge + enhance EEPROM CLI output Signed-off-by: Mihir Patel <[email protected]> * Fixed SA warning * Added None check for sfp_firmware_info_dict * Added is_transceiver_c_cmis * Added new line before get_data_map_sort_key --------- Signed-off-by: Mihir Patel <[email protected]>
1 parent 0f8ac9b commit 19594b9

6 files changed

Lines changed: 119 additions & 36 deletions

File tree

scripts/sfpshow

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ from utilities_common.sfp_helper import (
2727
CMIS_VDM_TO_LEGACY_STATUS_MAP,
2828
CCMIS_STATUS_MAP,
2929
CCMIS_VDM_TO_LEGACY_STATUS_MAP,
30-
CCMIS_VDM_THRESHOLD_TO_LEGACY_DOM_THRESHOLD_MAP
30+
CCMIS_VDM_THRESHOLD_TO_LEGACY_DOM_THRESHOLD_MAP,
31+
get_data_map_sort_key,
32+
get_transceiver_data_map
3133
)
3234
from utilities_common.sfp_helper import is_transceiver_cmis
3335
from tabulate import tabulate
@@ -317,15 +319,18 @@ class SFPShow(object):
317319
is_sfp_cmis = is_transceiver_cmis(sfp_info_dict)
318320
is_sfp_c_cmis = 'supported_max_tx_power' in sfp_info_dict
319321

320-
if is_sfp_c_cmis:
321-
data_map = C_CMIS_DATA_MAP
322-
elif is_sfp_cmis:
323-
data_map = CMIS_DATA_MAP
324-
else:
325-
data_map = QSFP_DATA_MAP
322+
# Get the appropriate data map for this transceiver type
323+
data_map = get_transceiver_data_map(sfp_info_dict)
324+
325+
# Combine sfp_info_dict and sfp_firmware_info_dict for sorting
326+
combined_dict = sfp_info_dict.copy()
327+
if sfp_firmware_info_dict:
328+
combined_dict.update(sfp_firmware_info_dict)
329+
330+
# Use the utility function to get sorted keys from combined dictionary
331+
sorted_sfp_info_keys = sorted(combined_dict.keys(), key=get_data_map_sort_key(combined_dict, data_map))
326332

327-
sorted_data_map_keys = sorted(data_map, key=data_map.get)
328-
for key in sorted_data_map_keys:
333+
for key in sorted_sfp_info_keys:
329334
if key == 'cable_type':
330335
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
331336
elif key == 'cable_length':
@@ -352,7 +357,10 @@ class SFPShow(object):
352357
if key in sfp_firmware_info_dict:
353358
output += '{}{}: {}\n'.format(indent, data_map[key], sfp_firmware_info_dict[key])
354359
else:
355-
output += '{}{}: {}\n'.format(indent, data_map[key], sfp_info_dict[key])
360+
# For both known and unknown keys
361+
display_name = data_map.get(key, key) # Use data_map name if available, otherwise use key
362+
value = sfp_info_dict.get(key, sfp_firmware_info_dict.get(key, 'N/A') if sfp_firmware_info_dict else 'N/A')
363+
output += '{}{}: {}\n'.format(indent, display_name, value)
356364

357365
return output
358366

sfputil/main.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
)
2929
from utilities_common.sfp_helper import covert_application_advertisement_to_output_string
3030
from utilities_common.sfp_helper import QSFP_DATA_MAP
31-
from utilities_common.sfp_helper import is_transceiver_cmis
31+
from utilities_common.sfp_helper import is_transceiver_cmis, get_data_map_sort_key
3232
from tabulate import tabulate
3333
from utilities_common.general import load_db_config
3434

@@ -338,8 +338,10 @@ def convert_sfp_info_to_output_string(sfp_info_dict):
338338
output = ''
339339
is_sfp_cmis = is_transceiver_cmis(sfp_info_dict)
340340
if is_sfp_cmis:
341-
sorted_qsfp_data_map_keys = sorted(QSFP_DD_DATA_MAP, key=QSFP_DD_DATA_MAP.get)
342-
for key in sorted_qsfp_data_map_keys:
341+
# Use the utility function with the local QSFP_DD_DATA_MAP for CMIS transceivers
342+
get_sort_key = get_data_map_sort_key(sfp_info_dict, QSFP_DD_DATA_MAP)
343+
sorted_qsfp_dd_info_keys = sorted(sfp_info_dict.keys(), key=get_sort_key)
344+
for key in sorted_qsfp_dd_info_keys:
343345
if key == 'cable_type':
344346
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
345347
elif key == 'cable_length':
@@ -355,14 +357,15 @@ def convert_sfp_info_to_output_string(sfp_info_dict):
355357
elif key == 'application_advertisement':
356358
output += covert_application_advertisement_to_output_string(indent, sfp_info_dict)
357359
else:
358-
try:
359-
output += '{}{}: {}\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
360-
except (KeyError, ValueError) as e:
361-
output += '{}{}: N/A\n'.format(indent, QSFP_DD_DATA_MAP[key])
360+
# For both known and unknown keys, use the data map display name if available
361+
display_name = QSFP_DD_DATA_MAP.get(key, key) # Use data_map name if available, otherwise use key
362+
output += '{}{}: {}\n'.format(indent, display_name, sfp_info_dict.get(key, 'N/A'))
362363

363364
else:
364-
sorted_qsfp_data_map_keys = sorted(QSFP_DATA_MAP, key=QSFP_DATA_MAP.get)
365-
for key in sorted_qsfp_data_map_keys:
365+
# Use the utility function with QSFP_DATA_MAP for non-CMIS transceivers
366+
get_sort_key = get_data_map_sort_key(sfp_info_dict, QSFP_DATA_MAP)
367+
sorted_qsfp_info_keys = sorted(sfp_info_dict.keys(), key=get_sort_key)
368+
for key in sorted_qsfp_info_keys:
366369
if key == 'cable_type':
367370
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
368371
elif key == 'cable_length':
@@ -379,7 +382,9 @@ def convert_sfp_info_to_output_string(sfp_info_dict):
379382
except ValueError as e:
380383
output += '{}N/A\n'.format((indent * 2))
381384
else:
382-
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
385+
# For both known and unknown keys, use the data map display name if available
386+
display_name = QSFP_DATA_MAP.get(key, key) # Use data_map name if available, otherwise use key
387+
output += '{}{}: {}\n'.format(indent, display_name, sfp_info_dict.get(key, 'N/A'))
383388

384389
return output
385390

tests/mock_tables/state_db.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -718,11 +718,9 @@
718718
"active_apsel_hostlane4": "N/A",
719719
"is_replaceable": "True",
720720
"application_advertisement": "{1: {'host_electrical_interface_id': 'IB NDR', 'module_media_interface_id': 'Copper cable', 'media_lane_count': 4, 'host_lane_count': 4, 'host_lane_assignment_options': 17}, 2: {'host_electrical_interface_id': 'IB SDR (Arch.Spec.Vol.2)', 'module_media_interface_id': 'Copper cable', 'media_lane_count': 4, 'host_lane_count': 4, 'host_lane_assignment_options': 17}}",
721-
"host_electrical_interface": "N/A",
722721
"active_apsel_hostlane2": "N/A",
723722
"supported_min_tx_power": "N/A",
724723
"supported_max_tx_power": "N/A",
725-
"host_lane_assignment_option": "17",
726724
"specification_compliance": "passive_copper_media_interface",
727725
"ext_identifier": "Power Class 1 (0.25W Max)",
728726
"active_apsel_hostlane8": "N/A",
@@ -736,7 +734,6 @@
736734
"type": "OSFP 8X Pluggable Transceiver",
737735
"cable_length": "1.0",
738736
"active_apsel_hostlane5": "N/A",
739-
"media_lane_assignment_option": "N/A",
740737
"vendor_rev": "A3",
741738
"active_apsel_hostlane6": "N/A",
742739
"encoding": "N/A",
@@ -749,7 +746,6 @@
749746
"vendor_oui": "some-oui",
750747
"connector": "No separable connector",
751748
"supported_max_laser_freq": "N/A",
752-
"media_interface_code": "Copper cable",
753749
"active_apsel_hostlane3": "N/A",
754750
"ext_rateselect_compliance": "N/A",
755751
"model": "some-model ",

tests/sfp_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@
198198
Vendor PN: some-model
199199
Vendor Rev: A3
200200
Vendor SN: serial1
201+
dom_capability: N/A
202+
is_replaceable: True
201203
ChannelMonitorValues:
202204
RX1Power: 0.5dBm
203205
RX2Power: 0.3dBm

tests/sfputil_test.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@
3838
'cable_length': '3',
3939
'application_advertisement': 'N/A',
4040
'specification_compliance': "{'10/40G Ethernet Compliance Code': '40GBASE-CR4'}",
41-
'dom_capability': "{'Tx_power_support': 'no', 'Rx_power_support': 'no',\
42-
'Voltage_support': 'no', 'Temp_support': 'no'}",
41+
'dom_capability': "N/A",
4342
'nominal_bit_rate': '255'
4443
}
4544
FLAT_MEMORY_MODULE_EEPROM = """Ethernet16: SFP EEPROM detected
@@ -59,6 +58,8 @@
5958
Vendor PN: MCP1600-C003
6059
Vendor Rev: A2
6160
Vendor SN: MT1636VS10561
61+
dom_capability: N/A
62+
type_abbrv_name: QSFP28
6263
"""
6364
EMPTY_DOM_VALUES = """ ChannelMonitorValues:
6465
ChannelThresholdValues:
@@ -150,7 +151,7 @@ def test_format_dict_value_to_string(self):
150151
'cable_length': '3',
151152
'application_advertisement': 'N/A',
152153
'specification_compliance': "{'10/40G Ethernet Compliance Code': '40GBASE-CR4'}",
153-
'dom_capability': "{'Tx_power_support': 'no', 'Rx_power_support': 'no', 'Voltage_support': 'no', 'Temp_support': 'no'}",
154+
'dom_capability': "N/A",
154155
'nominal_bit_rate': '255'
155156
},
156157
# expected_output
@@ -170,6 +171,8 @@ def test_format_dict_value_to_string(self):
170171
" Vendor PN: MCP1600-C003\n"
171172
" Vendor Rev: A2\n"
172173
" Vendor SN: MT1636VS10561\n"
174+
" dom_capability: N/A\n"
175+
" type_abbrv_name: QSFP28\n"
173176
),
174177
# CMIS compliant module
175178
(
@@ -197,15 +200,11 @@ def test_format_dict_value_to_string(self):
197200
'media_lane_assignment_options': 2}, \
198201
2: {'host_electrical_interface_id': '200GBASE-CR4 (Clause 136)'}}",
199202
'specification_compliance': "sm_media_interface",
200-
'dom_capability': "{'Tx_power_support': 'no', 'Rx_power_support': 'no', 'Voltage_support': 'no', 'Temp_support': 'no'}",
203+
'dom_capability': "N/A",
201204
'nominal_bit_rate': '0',
202205
'hardware_rev': '0.0',
203-
'media_interface_code': '400ZR, DWDM, amplified',
204-
'host_electrical_interface': '400GAUI-8 C2M (Annex 120E)',
205206
'host_lane_count': 8,
206207
'media_lane_count': 1,
207-
'host_lane_assignment_option': 1,
208-
'media_lane_assignment_option': 1,
209208
'active_apsel_hostlane1': 1,
210209
'active_apsel_hostlane2': 1,
211210
'active_apsel_hostlane3': 1,
@@ -238,14 +237,10 @@ def test_format_dict_value_to_string(self):
238237
" Extended Identifier: Power Class 8 (18.0W Max)\n"
239238
" Extended RateSelect Compliance: N/A\n"
240239
" Hardware Revision: 0.0\n"
241-
" Host Electrical Interface: 400GAUI-8 C2M (Annex 120E)\n"
242-
" Host Lane Assignment Options: 1\n"
243240
" Host Lane Count: 8\n"
244241
" Identifier: QSFP-DD Double Density 8X Pluggable Transceiver\n"
245242
" Length Cable Assembly(m): 0\n"
246-
" Media Interface Code: 400ZR, DWDM, amplified\n"
247243
" Media Interface Technology: C-band tunable laser\n"
248-
" Media Lane Assignment Options: 1\n"
249244
" Media Lane Count: 1\n"
250245
" Nominal Bit Rate(100Mbs): 0\n"
251246
" Specification compliance: sm_media_interface\n"
@@ -259,6 +254,8 @@ def test_format_dict_value_to_string(self):
259254
" Vendor PN: def\n"
260255
" Vendor Rev: ghi\n"
261256
" Vendor SN: jkl\n"
257+
" dom_capability: N/A\n"
258+
" type_abbrv_name: QSFP-DD\n"
262259
),
263260
])
264261
def test_convert_sfp_info_to_output_string(self, sfp_info_dict, expected_output):

utilities_common/sfp_helper.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,78 @@ def is_transceiver_cmis(sfp_info_dict):
437437
if sfp_info_dict is None:
438438
return False
439439
return 'cmis_rev' in sfp_info_dict
440+
441+
442+
def is_transceiver_c_cmis(sfp_info_dict):
443+
"""
444+
Check if the transceiver is C-CMIS compliant.
445+
If the sfp_info_dict is None, return False.
446+
If 'supported_max_tx_power' is present in the dictionary, return True.
447+
Otherwise, return False.
448+
"""
449+
if sfp_info_dict is None:
450+
return False
451+
return 'supported_max_tx_power' in sfp_info_dict
452+
453+
454+
def get_data_map_sort_key(sfp_info_dict, data_map=None):
455+
"""
456+
Create a sorting key function for SFP info keys based on the transceiver type.
457+
458+
This function returns a key function that can be used with sorted() to order
459+
SFP info dictionary keys. Known keys (those present in the appropriate data map)
460+
are given priority 0 and sorted by their display name, while unknown keys are
461+
given priority 1 and sorted alphabetically by their original key name.
462+
463+
Args:
464+
sfp_info_dict (dict): The SFP info dictionary to determine transceiver type
465+
data_map (dict, optional): Custom data map to use. If not provided, will determine
466+
automatically based on transceiver type.
467+
468+
Returns:
469+
function: A key function that can be used with sorted()
470+
471+
Example:
472+
sorted_keys = sorted(sfp_info_dict.keys(), key=get_data_map_sort_key(sfp_info_dict))
473+
# Or with custom data map:
474+
sorted_keys = sorted(sfp_info_dict.keys(), key=get_data_map_sort_key(sfp_info_dict, CUSTOM_DATA_MAP))
475+
"""
476+
if data_map is None:
477+
data_map = get_transceiver_data_map(sfp_info_dict)
478+
479+
def get_sort_key(key):
480+
"""
481+
Sort key function that prioritizes known fields over unknown ones.
482+
Known fields are sorted by their display names, unknown fields by their key names.
483+
"""
484+
if key in data_map:
485+
return (0, data_map[key]) # Priority 0 for known keys, use data_map value
486+
else:
487+
return (1, key) # Priority 1 for unknown keys, use key name
488+
489+
return get_sort_key
490+
491+
492+
def get_transceiver_data_map(sfp_info_dict):
493+
"""
494+
Get the appropriate data map based on the transceiver type.
495+
496+
Args:
497+
sfp_info_dict (dict): The SFP info dictionary to determine transceiver type
498+
499+
Returns:
500+
dict: The appropriate data map (C_CMIS_DATA_MAP, CMIS_DATA_MAP, or QSFP_DATA_MAP)
501+
Returns QSFP_DATA_MAP as default if sfp_info_dict is None or invalid
502+
"""
503+
if sfp_info_dict is None or not isinstance(sfp_info_dict, dict):
504+
return QSFP_DATA_MAP # Default fallback
505+
506+
is_sfp_cmis = is_transceiver_cmis(sfp_info_dict)
507+
is_sfp_c_cmis = is_transceiver_c_cmis(sfp_info_dict)
508+
509+
if is_sfp_c_cmis:
510+
return C_CMIS_DATA_MAP
511+
elif is_sfp_cmis:
512+
return CMIS_DATA_MAP
513+
else:
514+
return QSFP_DATA_MAP

0 commit comments

Comments
 (0)