Skip to content

Commit ba9b628

Browse files
[sfp] Fix issue: Application Advertisement is not well formatted (sonic-net#2491)
#### What I did Currently, the value of "Application Advertisement" is a python dict to string which is not well formatted. This PR re-format the output of "Application Advertisement" to a human readable string #### How I did it Set the output to similar to 202012 #### How to verify it Unit test Manual test #### Previous command output (if the output of a command-line utility has changed) ``` Ethernet200: SFP EEPROM detected Application Advertisement: {1: {'host_electrical_interface_id': '400GAUI-8 C2M (Annex 120E)', 'module_media_interface_id': '400GBASE-DR4 (Cl 124)', 'media_lane_count': 4, 'host_lane_count': 8, 'host_lane_assignment_options': 1}, 2: {'host_electrical_interface_id': '100GAUI-2 C2M (Annex 135G)', 'module_media_interface_id': '100GBASE-DR (Cl 140)', 'media_lane_count': 1, 'host_lane_count': 2, 'host_lane_assignment_options': 85}} ... ``` #### New command output (if the output of a command-line utility has changed) ``` Ethernet200: SFP EEPROM detected Application Advertisement: 400GAUI-8 C2M (Annex 120E) - 400GBASE-DR4 (Cl 124) - 0x1 100GAUI-2 C2M (Annex 135G) - 100GBASE-DR (Cl 140) - 0x55 ... ```
1 parent 94a092d commit ba9b628

File tree

6 files changed

+149
-68
lines changed

6 files changed

+149
-68
lines changed

scripts/sfpshow

+4-19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import click
1616
from natsort import natsorted
1717
from sonic_py_common.interface import front_panel_prefix, backplane_prefix, inband_prefix, recirc_prefix
1818
from sonic_py_common import multi_asic
19+
from utilities_common.sfp_helper import covert_application_advertisement_to_output_string
20+
from utilities_common.sfp_helper import QSFP_DATA_MAP
1921
from tabulate import tabulate
2022

2123
# Mock the redis DB for unit test purposes
@@ -38,25 +40,6 @@ from utilities_common import multi_asic as multi_asic_util
3840
from utilities_common.platform_sfputil_helper import is_rj45_port, RJ45_PORT_TYPE
3941

4042
# TODO: We should share these maps and the formatting functions between sfputil and sfpshow
41-
QSFP_DATA_MAP = {
42-
'model': 'Vendor PN',
43-
'vendor_oui': 'Vendor OUI',
44-
'vendor_date': 'Vendor Date Code(YYYY-MM-DD Lot)',
45-
'manufacturer': 'Vendor Name',
46-
'vendor_rev': 'Vendor Rev',
47-
'serial': 'Vendor SN',
48-
'type': 'Identifier',
49-
'ext_identifier': 'Extended Identifier',
50-
'ext_rateselect_compliance': 'Extended RateSelect Compliance',
51-
'cable_length': 'cable_length',
52-
'cable_type': 'Length',
53-
'nominal_bit_rate': 'Nominal Bit Rate(100Mbs)',
54-
'specification_compliance': 'Specification compliance',
55-
'encoding': 'Encoding',
56-
'connector': 'Connector',
57-
'application_advertisement': 'Application Advertisement'
58-
}
59-
6043
SFP_DOM_CHANNEL_MONITOR_MAP = {
6144
'rx1power': 'RXPower',
6245
'tx1bias': 'TXBias',
@@ -287,6 +270,8 @@ class SFPShow(object):
287270
output += '{}{}: {}\n'.format((indent * 2), compliance_key, spec_compliance_dict[compliance_key])
288271
except ValueError as e:
289272
output += '{}N/A\n'.format((indent * 2))
273+
elif key == 'application_advertisement':
274+
output += covert_application_advertisement_to_output_string(indent, sfp_info_dict)
290275
else:
291276
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
292277

sfputil/main.py

+14-29
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from swsscommon.swsscommon import SonicV2Connector
2121
from natsort import natsorted
2222
from sonic_py_common import device_info, logger, multi_asic
23+
from utilities_common.sfp_helper import covert_application_advertisement_to_output_string
24+
from utilities_common.sfp_helper import QSFP_DATA_MAP
2325
from tabulate import tabulate
2426

2527
VERSION = '3.0'
@@ -50,25 +52,6 @@
5052
SFF8472_A0_SIZE = 256
5153

5254
# TODO: We should share these maps and the formatting functions between sfputil and sfpshow
53-
QSFP_DATA_MAP = {
54-
'model': 'Vendor PN',
55-
'vendor_oui': 'Vendor OUI',
56-
'vendor_date': 'Vendor Date Code(YYYY-MM-DD Lot)',
57-
'manufacturer': 'Vendor Name',
58-
'vendor_rev': 'Vendor Rev',
59-
'serial': 'Vendor SN',
60-
'type': 'Identifier',
61-
'ext_identifier': 'Extended Identifier',
62-
'ext_rateselect_compliance': 'Extended RateSelect Compliance',
63-
'cable_length': 'cable_length',
64-
'cable_type': 'Length',
65-
'nominal_bit_rate': 'Nominal Bit Rate(100Mbs)',
66-
'specification_compliance': 'Specification compliance',
67-
'encoding': 'Encoding',
68-
'connector': 'Connector',
69-
'application_advertisement': 'Application Advertisement'
70-
}
71-
7255
QSFP_DD_DATA_MAP = {
7356
'model': 'Vendor PN',
7457
'vendor_oui': 'Vendor OUI',
@@ -350,6 +333,8 @@ def convert_sfp_info_to_output_string(sfp_info_dict):
350333
elif key == 'supported_max_laser_freq' or key == 'supported_min_laser_freq':
351334
if key in sfp_info_dict: # C-CMIS compliant / coherent modules
352335
output += '{}{}: {}GHz\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
336+
elif key == 'application_advertisement':
337+
output += covert_application_advertisement_to_output_string(indent, sfp_info_dict)
353338
else:
354339
try:
355340
output += '{}{}: {}\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
@@ -1358,8 +1343,8 @@ def download_firmware(port_name, filepath):
13581343
def run(port_name, mode):
13591344
"""Run the firmware with default mode=1"""
13601345

1361-
if is_port_type_rj45(port_name):
1362-
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
1346+
if is_port_type_rj45(port_name):
1347+
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
13631348
sys.exit(EXIT_FAIL)
13641349

13651350
if not is_sfp_present(port_name):
@@ -1379,8 +1364,8 @@ def run(port_name, mode):
13791364
def commit(port_name):
13801365
"""Commit the running firmware"""
13811366

1382-
if is_port_type_rj45(port_name):
1383-
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
1367+
if is_port_type_rj45(port_name):
1368+
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
13841369
sys.exit(EXIT_FAIL)
13851370

13861371
if not is_sfp_present(port_name):
@@ -1403,8 +1388,8 @@ def upgrade(port_name, filepath):
14031388

14041389
physical_port = logical_port_to_physical_port_index(port_name)
14051390

1406-
if is_port_type_rj45(port_name):
1407-
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
1391+
if is_port_type_rj45(port_name):
1392+
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
14081393
sys.exit(EXIT_FAIL)
14091394

14101395
if not is_sfp_present(port_name):
@@ -1441,8 +1426,8 @@ def upgrade(port_name, filepath):
14411426
def download(port_name, filepath):
14421427
"""Download firmware on the transceiver"""
14431428

1444-
if is_port_type_rj45(port_name):
1445-
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
1429+
if is_port_type_rj45(port_name):
1430+
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
14461431
sys.exit(EXIT_FAIL)
14471432

14481433
if not is_sfp_present(port_name):
@@ -1469,8 +1454,8 @@ def unlock(port_name, password):
14691454
physical_port = logical_port_to_physical_port_index(port_name)
14701455
sfp = platform_chassis.get_sfp(physical_port)
14711456

1472-
if is_port_type_rj45(port_name):
1473-
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
1457+
if is_port_type_rj45(port_name):
1458+
click.echo("This functionality is not applicable for RJ45 port {}.".format(port_name))
14741459
sys.exit(EXIT_FAIL)
14751460

14761461
if not is_sfp_present(port_name):

tests/mock_tables/state_db.json

+24-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"manufacturer": "INNOLIGHT",
7575
"model": "C-DQ8FNM010-N00",
7676
"vendor_oui": "44-7c-7f",
77-
"vendor_date": "2020-05-22 ",
77+
"vendor_date": "2020-05-22",
7878
"connector": "No separable connector",
7979
"encoding": "Not supported for CMIS cables",
8080
"ext_identifier": "Power Class 1(10.0W Max)",
@@ -83,7 +83,7 @@
8383
"cable_length": "10",
8484
"specification_compliance": "Not supported for CMIS cables",
8585
"nominal_bit_rate": "Not supported for CMIS cables",
86-
"application_advertisement": "400GAUI-8 C2M (Annex 120E) - Active Cable assembly with BER < 2.6x10^-4\n\t\t\t\t IB EDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 5x10^-5\n\t\t\t\t IB QDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 10^-12\n\t\t\t\t "
86+
"application_advertisement": "400GAUI-8 C2M (Annex 120E) - Active Cable assembly with BER < 2.6x10^-4\n\t\t\t\t IB EDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 5x10^-5\n\t\t\t\t IB QDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 10^-12"
8787
},
8888
"TRANSCEIVER_DOM_SENSOR|Ethernet8": {
8989
"temperature": "44.9883",
@@ -205,6 +205,24 @@
205205
"nominal_bit_rate": "N/A",
206206
"application_advertisement": "N/A"
207207
},
208+
"TRANSCEIVER_INFO|Ethernet40": {
209+
"type": "QSFP-DD Double Density 8X Pluggable Transceiver",
210+
"vendor_rev": "2A",
211+
"serial": "INKAO2900002A",
212+
"manufacturer": "INNOLIGHT",
213+
"model": "C-DQ8FNM010-N00",
214+
"vendor_oui": "44-7c-7f",
215+
"vendor_date": "2020-05-22",
216+
"connector": "No separable connector",
217+
"encoding": "Not supported for CMIS cables",
218+
"ext_identifier": "Power Class 1(10.0W Max)",
219+
"ext_rateselect_compliance": "Not supported for CMIS cables",
220+
"cable_type": "Length Cable Assembly(m)",
221+
"cable_length": "10",
222+
"specification_compliance": "Not supported for CMIS cables",
223+
"nominal_bit_rate": "Not supported for CMIS cables",
224+
"application_advertisement": "{1: {'host_electrical_interface_id': '400G CR8', 'module_media_interface_id': 'Copper cable', 'media_lane_count': 8, 'host_lane_count': 8, 'host_lane_assignment_options': 1, 'media_lane_assignment_options': 2}, 2: {'host_electrical_interface_id': '200GBASE-CR4 (Clause 136)'}}"
225+
},
208226
"TRANSCEIVER_STATUS|Ethernet0": {
209227
"status": "67",
210228
"error": "Blocking Error|High temperature"
@@ -233,6 +251,10 @@
233251
"status": "255",
234252
"error": "Unknown"
235253
},
254+
"TRANSCEIVER_STATUS|Ethernet40": {
255+
"status": "0",
256+
"error": "N/A"
257+
},
236258
"CHASSIS_INFO|chassis 1": {
237259
"psu_num": "2"
238260
},

tests/sfp_test.py

+39-14
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
Application Advertisement: 400GAUI-8 C2M (Annex 120E) - Active Cable assembly with BER < 2.6x10^-4
6767
IB EDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 5x10^-5
6868
IB QDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 10^-12
69-
7069
Connector: No separable connector
7170
Encoding: Not supported for CMIS cables
7271
Extended Identifier: Power Class 1(10.0W Max)
@@ -75,13 +74,13 @@
7574
Length Cable Assembly(m): 10
7675
Nominal Bit Rate(100Mbs): Not supported for CMIS cables
7776
Specification compliance: Not supported for CMIS cables
78-
Vendor Date Code(YYYY-MM-DD Lot): 2020-05-22
77+
Vendor Date Code(YYYY-MM-DD Lot): 2020-05-22
7978
Vendor Name: INNOLIGHT
8079
Vendor OUI: 44-7c-7f
8180
Vendor PN: C-DQ8FNM010-N00
8281
Vendor Rev: 2A
8382
Vendor SN: INKAO2900002A
84-
ChannelMonitorValues:
83+
ChannelMonitorValues:
8584
RX1Power: -3.8595dBm
8685
RX2Power: 8.1478dBm
8786
RX3Power: -22.9243dBm
@@ -98,15 +97,15 @@
9897
TX3Power: 1.175dBm
9998
TX4Bias: 0.0000mA
10099
TX4Power: 1.175dBm
101-
TX5Bias: 0.0000mAmA
100+
TX5Bias: 0.0000mA
102101
TX5Power: 1.175dBm
103-
TX6Bias: 8.2240mAmA
102+
TX6Bias: 8.2240mA
104103
TX6Power: 1.175dBm
105-
TX7Bias: 8.2240mAmA
104+
TX7Bias: 8.2240mA
106105
TX7Power: 1.175dBm
107-
TX8Bias: 8.2240mAmA
106+
TX8Bias: 8.2240mA
108107
TX8Power: 1.175dBm
109-
ChannelThresholdValues:
108+
ChannelThresholdValues:
110109
RxPowerHighAlarm : 6.9999dBm
111110
RxPowerHighWarning: 4.9999dBm
112111
RxPowerLowAlarm : -11.9044dBm
@@ -119,10 +118,10 @@
119118
TxPowerHighWarning: 4.9999dBm
120119
TxPowerLowAlarm : -10.5012dBm
121120
TxPowerLowWarning : -7.5007dBm
122-
ModuleMonitorValues:
121+
ModuleMonitorValues:
123122
Temperature: 44.9883C
124123
Vcc: 3.2999Volts
125-
ModuleThresholdValues:
124+
ModuleThresholdValues:
126125
TempHighAlarm : 80.0000C
127126
TempHighWarning: 75.0000C
128127
TempLowAlarm : -10.0000C
@@ -158,7 +157,6 @@
158157
Application Advertisement: 400GAUI-8 C2M (Annex 120E) - Active Cable assembly with BER < 2.6x10^-4
159158
IB EDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 5x10^-5
160159
IB QDR (Arch.Spec.Vol.2) - Active Cable assembly with BER < 10^-12
161-
162160
Connector: No separable connector
163161
Encoding: Not supported for CMIS cables
164162
Extended Identifier: Power Class 1(10.0W Max)
@@ -167,7 +165,27 @@
167165
Length Cable Assembly(m): 10
168166
Nominal Bit Rate(100Mbs): Not supported for CMIS cables
169167
Specification compliance: Not supported for CMIS cables
170-
Vendor Date Code(YYYY-MM-DD Lot): 2020-05-22
168+
Vendor Date Code(YYYY-MM-DD Lot): 2020-05-22
169+
Vendor Name: INNOLIGHT
170+
Vendor OUI: 44-7c-7f
171+
Vendor PN: C-DQ8FNM010-N00
172+
Vendor Rev: 2A
173+
Vendor SN: INKAO2900002A
174+
"""
175+
176+
test_qsfp_dd_eeprom_adv_app_output = """\
177+
Ethernet40: SFP EEPROM detected
178+
Application Advertisement: 400G CR8 - Host Assign (0x1) - Copper cable - Media Assign (0x2)
179+
200GBASE-CR4 (Clause 136) - Host Assign (Unknown) - Unknown - Media Assign (Unknown)
180+
Connector: No separable connector
181+
Encoding: Not supported for CMIS cables
182+
Extended Identifier: Power Class 1(10.0W Max)
183+
Extended RateSelect Compliance: Not supported for CMIS cables
184+
Identifier: QSFP-DD Double Density 8X Pluggable Transceiver
185+
Length Cable Assembly(m): 10
186+
Nominal Bit Rate(100Mbs): Not supported for CMIS cables
187+
Specification compliance: Not supported for CMIS cables
188+
Vendor Date Code(YYYY-MM-DD Lot): 2020-05-22
171189
Vendor Name: INNOLIGHT
172190
Vendor OUI: 44-7c-7f
173191
Vendor PN: C-DQ8FNM010-N00
@@ -390,7 +408,7 @@ def test_qsfp_dd_eeprom_with_dom(self):
390408
runner = CliRunner()
391409
result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet8 -d"])
392410
assert result.exit_code == 0
393-
assert "result.output == test_qsfp_dd_eeprom_with_dom_output"
411+
assert result.output == test_qsfp_dd_eeprom_with_dom_output
394412

395413
def test_sfp_eeprom(self):
396414
runner = CliRunner()
@@ -407,7 +425,14 @@ def test_qsfp_dd_eeprom(self):
407425
runner = CliRunner()
408426
result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet8"])
409427
assert result.exit_code == 0
410-
assert "result.output == test_qsfp_dd_eeprom_output"
428+
assert result.output == test_qsfp_dd_eeprom_output
429+
430+
def test_qsfp_dd_eeprom_adv_app(self):
431+
runner = CliRunner()
432+
result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet40"])
433+
assert result.exit_code == 0
434+
print(result.output)
435+
assert result.output == test_qsfp_dd_eeprom_adv_app_output
411436

412437
def test_rj45_eeprom(self):
413438
runner = CliRunner()

tests/sfputil_test.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ def test_format_dict_value_to_string(self):
8080
sfputil.QSFP_DOM_CHANNEL_MONITOR_MAP,
8181
sfputil.DOM_VALUE_UNIT_MAP)
8282
assert output == expected_output
83+
8384
@pytest.mark.parametrize("sfp_info_dict, expected_output",[
8485
# Non-CMIS module
8586
(
@@ -140,7 +141,13 @@ def test_format_dict_value_to_string(self):
140141
'ext_rateselect_compliance': 'N/A',
141142
'cable_type': 'Length Cable Assembly(m)',
142143
'cable_length': '0',
143-
'application_advertisement': 'N/A',
144+
'application_advertisement': "{1: {'host_electrical_interface_id': '400G CR8', \
145+
'module_media_interface_id': 'Copper cable', \
146+
'media_lane_count': 8, \
147+
'host_lane_count': 8, \
148+
'host_lane_assignment_options': 1, \
149+
'media_lane_assignment_options': 2}, \
150+
2: {'host_electrical_interface_id': '200GBASE-CR4 (Clause 136)'}}",
144151
'specification_compliance': "sm_media_interface",
145152
'dom_capability': "{'Tx_power_support': 'no', 'Rx_power_support': 'no', 'Voltage_support': 'no', 'Temp_support': 'no'}",
146153
'nominal_bit_rate': '0',
@@ -178,7 +185,8 @@ def test_format_dict_value_to_string(self):
178185
" Active App Selection Host Lane 7: 1\n"
179186
" Active App Selection Host Lane 8: 1\n"
180187
" Active Firmware Version: 0.1\n"
181-
" Application Advertisement: N/A\n"
188+
" Application Advertisement: 400G CR8 - Host Assign (0x1) - Copper cable - Media Assign (0x2)\n"
189+
" 200GBASE-CR4 (Clause 136) - Host Assign (Unknown) - Unknown - Media Assign (Unknown)\n"
182190
" CMIS Revision: 5.0\n"
183191
" Connector: LC\n"
184192
" Encoding: N/A\n"
@@ -279,7 +287,8 @@ def test_error_status_from_db(self):
279287
['Ethernet12', 'Unknown state: 255'],
280288
['Ethernet16', 'Unplugged'],
281289
['Ethernet28', 'Unplugged'],
282-
['Ethernet36', 'Unknown']]
290+
['Ethernet36', 'Unknown'],
291+
['Ethernet40', 'Unplugged']]
283292
output = sfputil.fetch_error_status_from_state_db(None, db.db)
284293
assert output == expected_output
285294

@@ -296,7 +305,8 @@ def test_error_status_from_db_RJ45(self):
296305
['Ethernet12', 'N/A'],
297306
['Ethernet16', 'N/A'],
298307
['Ethernet28', 'N/A'],
299-
['Ethernet36', 'N/A']]
308+
['Ethernet36', 'N/A'],
309+
['Ethernet40', 'N/A']]
300310
output = sfputil.fetch_error_status_from_state_db(None, db.db)
301311
assert output == expected_output
302312

@@ -382,6 +392,7 @@ def test_show_error_status(self):
382392
Ethernet16 Unplugged
383393
Ethernet28 Unplugged
384394
Ethernet36 Unknown
395+
Ethernet40 Unplugged
385396
"""
386397
assert result.output == expected_output
387398

0 commit comments

Comments
 (0)