Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions sonic_platform_base/sonic_xcvr/api/public/cmis.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,20 @@ class CmisApi(XcvrApi):
LowPwrRequestSW = 4
LowPwrAllowRequestHW = 6

LPO_HOST_ELECTRICAL_INTERFACE_IDS = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@longhuan-cisco which SFF spec version are you using?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prgeor
The code here is based on today's sonic_platform_base/sonic_xcvr/codes/public/sff8024.py:

32: 'LEI-100G-PAM4-1',
33: 'LEI-200G-PAM4-2',
34: 'LEI-400G-PAM4-4',
35: 'LEI-800G-PAM4-8',

151: "100G-DR1-LPO",
152: "200G-DR2-LPO",
153: "400G-DR4-LPO",
154: "800G-DR8-LPO",

But according to latest rev4.13 July 11, 2025 version of SFF-8024, MEDIA_INTERFACE_IDS for LPO starting from 143:
Image
I think we need to update sonic_platform_base/sonic_xcvr/codes/public/sff8024.py, will raise a PR about this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already a PR #596 to update LPO media codes in sonic_platform_base/sonic_xcvr/codes/public/sff8024.py based on latest SFF-8024.
Will update lpo API accordingly.

Copy link
Contributor

@mihirpat1 mihirpat1 Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@longhuan-cisco @prgeor I corrected the LPO related IDs since this change was causing test failures for #596

Sff8024.HOST_ELECTRICAL_INTERFACE[32],
Sff8024.HOST_ELECTRICAL_INTERFACE[33],
Sff8024.HOST_ELECTRICAL_INTERFACE[34],
Sff8024.HOST_ELECTRICAL_INTERFACE[35]
]

LPO_SM_MEDIA_INTERFACE_IDS = [
Sff8024.SM_MEDIA_INTERFACE[151],
Sff8024.SM_MEDIA_INTERFACE[152],
Sff8024.SM_MEDIA_INTERFACE[153],
Sff8024.SM_MEDIA_INTERFACE[154]
]

# Default caching enabled; control via classmethod
cache_enabled = True

Expand Down Expand Up @@ -592,6 +606,25 @@ def is_copper(self):
media_intf = self.get_module_media_type()
return media_intf == "passive_copper_media_interface" if media_intf else None

def is_lpo(self):
'''
Returns True if the module is LPO, False otherwise
'''
appl_advt = self.get_application_advertisement()
if not appl_advt:
return False

for appl_dict in appl_advt.values():
host_intf = appl_dict.get('host_electrical_interface_id')
media_intf = appl_dict.get('module_media_interface_id')
if (
host_intf in self.LPO_HOST_ELECTRICAL_INTERFACE_IDS or
media_intf in self.LPO_SM_MEDIA_INTERFACE_IDS
):
return True

return False

@read_only_cached_api_return
def is_flat_memory(self):
return self.xcvr_eeprom.read(consts.FLAT_MEM_FIELD) is not False
Expand Down
9 changes: 9 additions & 0 deletions sonic_platform_base/sonic_xcvr/api/xcvr_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,3 +685,12 @@ def set_high_power_class(self, power_class, enable):
bool: True if the provision succeeds, False if it fails
"""
raise NotImplementedError

def is_lpo(self):
"""
Check if the module is Linear Pluggable Optics (LPO)

Returns:
A Boolean, True if the module is LPO, False otherwise
"""
raise NotImplementedError
105 changes: 105 additions & 0 deletions tests/sonic_xcvr/test_cmis.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,111 @@ def test_is_copper(self):
self.api.get_module_media_type.return_value = "sm_media_interface"
assert not self.api.is_copper()

@pytest.mark.parametrize("mock_response, expected", [
# Test case 1: No application advertisement
(None, False),
# Test case 2: Empty application advertisement
({}, False),
# Test case 3: Non-LPO host electrical interface
({
1: {
'host_electrical_interface_id': '400GAUI-8 C2M (Annex 120E)', # ID 17, not LPO
'module_media_interface_id': '400GBASE-DR4 (Cl 124)'
}
}, False),
# Test case 4: LPO host electrical interface LEI-100G-PAM4-1 (ID 32)
({
1: {
'host_electrical_interface_id': 'LEI-100G-PAM4-1', # LPO
'module_media_interface_id': '100GBASE-DR (Cl 140)'
}
}, True),
# Test case 5: LPO host electrical interface LEI-200G-PAM4-2 (ID 33)
({
1: {
'host_electrical_interface_id': 'LEI-200G-PAM4-2', # LPO
'module_media_interface_id': '200GBASE-DR2 (Clause 138)'
}
}, True),
# Test case 6: LPO host electrical interface LEI-400G-PAM4-4 (ID 34)
({
1: {
'host_electrical_interface_id': 'LEI-400G-PAM4-4', # LPO
'module_media_interface_id': '400GBASE-DR4 (Cl 124)'
}
}, True),
# Test case 7: LPO host electrical interface LEI-800G-PAM4-8 (ID 35)
({
1: {
'host_electrical_interface_id': 'LEI-800G-PAM4-8', # LPO
'module_media_interface_id': '800GBASE-DR8 (placeholder)'
}
}, True),
# Test case 8: LPO SM media interface 100G-DR1-LPO (ID 151)
({
1: {
'host_electrical_interface_id': '100GAUI-2 C2M (Annex 135G)',
'module_media_interface_id': '100G-DR1-LPO' # LPO
}
}, True),
# Test case 9: LPO SM media interface 200G-DR2-LPO (ID 152)
({
1: {
'host_electrical_interface_id': '200GAUI-4 C2M (Annex 120E)',
'module_media_interface_id': '200G-DR2-LPO' # LPO
}
}, True),
# Test case 10: LPO SM media interface 400G-DR4-LPO (ID 153)
({
1: {
'host_electrical_interface_id': '400GAUI-8 C2M (Annex 120E)',
'module_media_interface_id': '400G-DR4-LPO' # LPO
}
}, True),
# Test case 11: LPO SM media interface 800G-DR8-LPO (ID 154)
({
1: {
'host_electrical_interface_id': '800GAUI-16 C2M (Annex 120C)',
'module_media_interface_id': '800G-DR8-LPO' # LPO
}
}, True),
# Test case 12: Multiple applications, one with LPO
({
1: {
'host_electrical_interface_id': '400GAUI-8 C2M (Annex 120E)', # Non-LPO
'module_media_interface_id': '400GBASE-DR4 (Cl 124)'
},
2: {
'host_electrical_interface_id': 'LEI-200G-PAM4-2', # LPO
'module_media_interface_id': '200GBASE-DR2 (Clause 138)'
}
}, True),
# Test case 13: Both host and media interfaces match LPO
({
1: {
'host_electrical_interface_id': 'LEI-400G-PAM4-4', # LPO
'module_media_interface_id': '400G-DR4-LPO' # LPO
}
}, True),
# Test case 14: Application with missing keys
({
1: {
'host_electrical_interface_id': '100GAUI-2 C2M (Annex 135G)',
# Missing module_media_interface_id
},
2: {
# Missing host_electrical_interface_id
'module_media_interface_id': '100GBASE-DR (Cl 140)'
}
}, False),
])
def test_is_lpo(self, mock_response, expected):
"""Test is_lpo() method with various application advertisement scenarios"""
with patch.object(self.api, 'get_application_advertisement') as mock_get_app_adv:
mock_get_app_adv.return_value = mock_response
result = self.api.is_lpo()
assert result == expected

@pytest.mark.parametrize("mock_response, expected", [
(False, False)
])
Expand Down
Loading