Skip to content

Commit

Permalink
Add transceiver-info items advertised for cmis-supported moddules (so…
Browse files Browse the repository at this point in the history
…nic-net#2135)

* include more transceiver-info items advertised for cmis-supported modules

* resolving test failure

* resolving test failure

* include a test case covering cmis-compliant module

* resolving test case failure

* add units for support laser freq and tx power

* add units on laser freq and tx power

* correct freq unit

* correct a syntax error on key categorization

Co-authored-by: Chuan Qin (QINCHUAN) <[email protected]>
  • Loading branch information
qinchuanares and qinchuanares authored May 10, 2022
1 parent 0811214 commit 083ebcc
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 64 deletions.
125 changes: 102 additions & 23 deletions sfputil/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,48 @@
'application_advertisement': 'Application Advertisement'
}

QSFP_DD_DATA_MAP = {
'model': 'Vendor PN',
'vendor_oui': 'Vendor OUI',
'vendor_date': 'Vendor Date Code(YYYY-MM-DD Lot)',
'manufacturer': 'Vendor Name',
'vendor_rev': 'Vendor Rev',
'serial': 'Vendor SN',
'type': 'Identifier',
'ext_identifier': 'Extended Identifier',
'ext_rateselect_compliance': 'Extended RateSelect Compliance',
'cable_length': 'cable_length',
'cable_type': 'Length',
'nominal_bit_rate': 'Nominal Bit Rate(100Mbs)',
'specification_compliance': 'Specification compliance',
'encoding': 'Encoding',
'connector': 'Connector',
'application_advertisement': 'Application Advertisement',
'active_firmware': 'Active Firmware Version',
'inactive_firmware': 'Inactive Firmware Version',
'hardware_rev': 'Hardware Revision',
'media_interface_code': 'Media Interface Code',
'host_electrical_interface': 'Host Electrical Interface',
'host_lane_count': 'Host Lane Count',
'media_lane_count': 'Media Lane Count',
'host_lane_assignment_option': 'Host Lane Assignment Options',
'media_lane_assignment_option': 'Media Lane Assignment Options',
'active_apsel_hostlane1': 'Active App Selection Host Lane 1',
'active_apsel_hostlane2': 'Active App Selection Host Lane 2',
'active_apsel_hostlane3': 'Active App Selection Host Lane 3',
'active_apsel_hostlane4': 'Active App Selection Host Lane 4',
'active_apsel_hostlane5': 'Active App Selection Host Lane 5',
'active_apsel_hostlane6': 'Active App Selection Host Lane 6',
'active_apsel_hostlane7': 'Active App Selection Host Lane 7',
'active_apsel_hostlane8': 'Active App Selection Host Lane 8',
'media_interface_technology': 'Media Interface Technology',
'cmis_rev': 'CMIS Revision',
'supported_max_tx_power': 'Supported Max TX Power',
'supported_min_tx_power': 'Supported Min TX Power',
'supported_max_laser_freq': 'Supported Max Laser Frequency',
'supported_min_laser_freq': 'Supported Min Laser Frequency'
}

SFP_DOM_CHANNEL_MONITOR_MAP = {
'rx1power': 'RXPower',
'tx1bias': 'TXBias',
Expand Down Expand Up @@ -273,31 +315,68 @@ def format_dict_value_to_string(sorted_key_table,
def convert_sfp_info_to_output_string(sfp_info_dict):
indent = ' ' * 8
output = ''

sorted_qsfp_data_map_keys = sorted(QSFP_DATA_MAP, key=QSFP_DATA_MAP.get)
for key in sorted_qsfp_data_map_keys:
if key == 'cable_type':
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
elif key == 'cable_length':
pass
elif key == 'specification_compliance':
if sfp_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver" or \
sfp_info_dict['type'] == "OSFP 8X Pluggable Transceiver" or \
sfp_info_dict['type'] == "QSFP+ or later with CMIS":
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
sfp_type = sfp_info_dict['type']
# CMIS supported module types include QSFP-DD and OSFP
if sfp_type.startswith('QSFP-DD') or sfp_type.startswith('OSFP'):
sorted_qsfp_data_map_keys = sorted(QSFP_DD_DATA_MAP, key=QSFP_DD_DATA_MAP.get)
for key in sorted_qsfp_data_map_keys:
if key == 'cable_type':
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
elif key == 'cable_length':
pass
elif key == 'specification_compliance':
if sfp_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver" or \
sfp_info_dict['type'] == "OSFP 8X Pluggable Transceiver" or \
sfp_info_dict['type'] == "QSFP+ or later with CMIS":
output += '{}{}: {}\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
else:
output += '{}{}:\n'.format(indent, QSFP_DD_DATA_MAP['specification_compliance'])

spec_compliance_dict = {}
try:
spec_compliance_dict = ast.literal_eval(sfp_info_dict['specification_compliance'])
sorted_compliance_key_table = natsorted(spec_compliance_dict)
for compliance_key in sorted_compliance_key_table:
output += '{}{}: {}\n'.format((indent * 2), compliance_key, spec_compliance_dict[compliance_key])
except ValueError as e:
output += '{}N/A\n'.format((indent * 2))
elif key == 'application_advertisement':
pass
elif key == 'supported_max_tx_power' or key == 'supported_min_tx_power':
output += '{}{}: {}dBm\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
elif key == 'supported_max_laser_freq' or key == 'supported_min_laser_freq':
output += '{}{}: {}GHz\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
else:
output += '{}{}:\n'.format(indent, QSFP_DATA_MAP['specification_compliance'])

spec_compliance_dict = {}
try:
spec_compliance_dict = ast.literal_eval(sfp_info_dict['specification_compliance'])
sorted_compliance_key_table = natsorted(spec_compliance_dict)
for compliance_key in sorted_compliance_key_table:
output += '{}{}: {}\n'.format((indent * 2), compliance_key, spec_compliance_dict[compliance_key])
except ValueError as e:
output += '{}N/A\n'.format((indent * 2))
else:
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
output += '{}{}: {}\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
except (KeyError, ValueError) as e:
output += '{}{}: N/A\n'.format(indent, QSFP_DD_DATA_MAP[key])

else:
sorted_qsfp_data_map_keys = sorted(QSFP_DATA_MAP, key=QSFP_DATA_MAP.get)
for key in sorted_qsfp_data_map_keys:
if key == 'cable_type':
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
elif key == 'cable_length':
pass
elif key == 'specification_compliance':
if sfp_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver" or \
sfp_info_dict['type'] == "OSFP 8X Pluggable Transceiver" or \
sfp_info_dict['type'] == "QSFP+ or later with CMIS":
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
else:
output += '{}{}:\n'.format(indent, QSFP_DATA_MAP['specification_compliance'])

spec_compliance_dict = {}
try:
spec_compliance_dict = ast.literal_eval(sfp_info_dict['specification_compliance'])
sorted_compliance_key_table = natsorted(spec_compliance_dict)
for compliance_key in sorted_compliance_key_table:
output += '{}{}: {}\n'.format((indent * 2), compliance_key, spec_compliance_dict[compliance_key])
except ValueError as e:
output += '{}N/A\n'.format((indent * 2))
else:
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])

return output

Expand Down
170 changes: 129 additions & 41 deletions tests/sfputil_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,47 +77,135 @@ def test_format_dict_value_to_string(self):
sfputil.QSFP_DOM_CHANNEL_MONITOR_MAP,
sfputil.DOM_VALUE_UNIT_MAP)
assert output == expected_output

def test_convert_sfp_info_to_output_string(self):
sfp_info_dict = {
'type': 'QSFP28 or later',
'type_abbrv_name': 'QSFP28',
'manufacturer': 'Mellanox',
'model': 'MCP1600-C003',
'vendor_rev': 'A2',
'serial': 'MT1636VS10561',
'vendor_oui': '00-02-c9',
'vendor_date': '2016-07-18',
'connector': 'No separable connector',
'encoding': '64B66B',
'ext_identifier': 'Power Class 1(1.5W max)',
'ext_rateselect_compliance': 'QSFP+ Rate Select Version 1',
'cable_type': 'Length Cable Assembly(m)',
'cable_length': '3',
'application_advertisement': 'N/A',
'specification_compliance': "{'10/40G Ethernet Compliance Code': '40GBASE-CR4'}",
'dom_capability': "{'Tx_power_support': 'no', 'Rx_power_support': 'no', 'Voltage_support': 'no', 'Temp_support': 'no'}",
'nominal_bit_rate': '255'
}

expected_output = '''\
Application Advertisement: N/A
Connector: No separable connector
Encoding: 64B66B
Extended Identifier: Power Class 1(1.5W max)
Extended RateSelect Compliance: QSFP+ Rate Select Version 1
Identifier: QSFP28 or later
Length Cable Assembly(m): 3
Nominal Bit Rate(100Mbs): 255
Specification compliance:
10/40G Ethernet Compliance Code: 40GBASE-CR4
Vendor Date Code(YYYY-MM-DD Lot): 2016-07-18
Vendor Name: Mellanox
Vendor OUI: 00-02-c9
Vendor PN: MCP1600-C003
Vendor Rev: A2
Vendor SN: MT1636VS10561
'''
@pytest.mark.parametrize("sfp_info_dict, expected_output",[
# Non-CMIS module
(
# sfp_info_dict
{
'type': 'QSFP28 or later',
'type_abbrv_name': 'QSFP28',
'manufacturer': 'Mellanox',
'model': 'MCP1600-C003',
'vendor_rev': 'A2',
'serial': 'MT1636VS10561',
'vendor_oui': '00-02-c9',
'vendor_date': '2016-07-18',
'connector': 'No separable connector',
'encoding': '64B66B',
'ext_identifier': 'Power Class 1(1.5W max)',
'ext_rateselect_compliance': 'QSFP+ Rate Select Version 1',
'cable_type': 'Length Cable Assembly(m)',
'cable_length': '3',
'application_advertisement': 'N/A',
'specification_compliance': "{'10/40G Ethernet Compliance Code': '40GBASE-CR4'}",
'dom_capability': "{'Tx_power_support': 'no', 'Rx_power_support': 'no', 'Voltage_support': 'no', 'Temp_support': 'no'}",
'nominal_bit_rate': '255'
},
# expected_output
" Application Advertisement: N/A\n"
" Connector: No separable connector\n"
" Encoding: 64B66B\n"
" Extended Identifier: Power Class 1(1.5W max)\n"
" Extended RateSelect Compliance: QSFP+ Rate Select Version 1\n"
" Identifier: QSFP28 or later\n"
" Length Cable Assembly(m): 3\n"
" Nominal Bit Rate(100Mbs): 255\n"
" Specification compliance:\n"
" 10/40G Ethernet Compliance Code: 40GBASE-CR4\n"
" Vendor Date Code(YYYY-MM-DD Lot): 2016-07-18\n"
" Vendor Name: Mellanox\n"
" Vendor OUI: 00-02-c9\n"
" Vendor PN: MCP1600-C003\n"
" Vendor Rev: A2\n"
" Vendor SN: MT1636VS10561\n"
),
# CMIS compliant module
(
# sfp_info_dict
{
'type': 'QSFP-DD Double Density 8X Pluggable Transceiver',
'type_abbrv_name': 'QSFP-DD',
'manufacturer': 'abc',
'model': 'def',
'vendor_rev': 'ghi',
'serial': 'jkl',
'vendor_oui': '00-00-00',
'vendor_date': '2000-01-01',
'connector': 'LC',
'encoding': 'N/A',
'ext_identifier': 'Power Class 8 (18.0W Max)',
'ext_rateselect_compliance': 'N/A',
'cable_type': 'Length Cable Assembly(m)',
'cable_length': '0',
'application_advertisement': 'N/A',
'specification_compliance': "sm_media_interface",
'dom_capability': "{'Tx_power_support': 'no', 'Rx_power_support': 'no', 'Voltage_support': 'no', 'Temp_support': 'no'}",
'nominal_bit_rate': '0',
'active_firmware': '0.1',
'inactive_firmware': '0.0',
'hardware_rev': '0.0',
'media_interface_code': '400ZR, DWDM, amplified',
'host_electrical_interface': '400GAUI-8 C2M (Annex 120E)',
'host_lane_count': 8,
'media_lane_count': 1,
'host_lane_assignment_option': 1,
'media_lane_assignment_option': 1,
'active_apsel_hostlane1': 1,
'active_apsel_hostlane2': 1,
'active_apsel_hostlane3': 1,
'active_apsel_hostlane4': 1,
'active_apsel_hostlane5': 1,
'active_apsel_hostlane6': 1,
'active_apsel_hostlane7': 1,
'active_apsel_hostlane8': 1,
'media_interface_technology': 'C-band tunable laser',
'cmis_rev': '5.0',
'supported_max_tx_power': 0,
'supported_min_tx_power': -20,
'supported_max_laser_freq': 196100,
'supported_min_laser_freq': 191300
},
# expected_output
" Active App Selection Host Lane 1: 1\n"
" Active App Selection Host Lane 2: 1\n"
" Active App Selection Host Lane 3: 1\n"
" Active App Selection Host Lane 4: 1\n"
" Active App Selection Host Lane 5: 1\n"
" Active App Selection Host Lane 6: 1\n"
" Active App Selection Host Lane 7: 1\n"
" Active App Selection Host Lane 8: 1\n"
" Active Firmware Version: 0.1\n"
" CMIS Revision: 5.0\n"
" Connector: LC\n"
" Encoding: N/A\n"
" Extended Identifier: Power Class 8 (18.0W Max)\n"
" Extended RateSelect Compliance: N/A\n"
" Hardware Revision: 0.0\n"
" Host Electrical Interface: 400GAUI-8 C2M (Annex 120E)\n"
" Host Lane Assignment Options: 1\n"
" Host Lane Count: 8\n"
" Identifier: QSFP-DD Double Density 8X Pluggable Transceiver\n"
" Inactive Firmware Version: 0.0\n"
" Length Cable Assembly(m): 0\n"
" Media Interface Code: 400ZR, DWDM, amplified\n"
" Media Interface Technology: C-band tunable laser\n"
" Media Lane Assignment Options: 1\n"
" Media Lane Count: 1\n"
" Nominal Bit Rate(100Mbs): 0\n"
" Specification compliance: sm_media_interface\n"
" Supported Max Laser Frequency: 196100GHz\n"
" Supported Max TX Power: 0dBm\n"
" Supported Min Laser Frequency: 191300GHz\n"
" Supported Min TX Power: -20dBm\n"
" Vendor Date Code(YYYY-MM-DD Lot): 2000-01-01\n"
" Vendor Name: abc\n"
" Vendor OUI: 00-00-00\n"
" Vendor PN: def\n"
" Vendor Rev: ghi\n"
" Vendor SN: jkl\n"
),
])
def test_convert_sfp_info_to_output_string(self, sfp_info_dict, expected_output):
output = sfputil.convert_sfp_info_to_output_string(sfp_info_dict)
assert output == expected_output

Expand Down

0 comments on commit 083ebcc

Please sign in to comment.