Skip to content

Commit

Permalink
[rfc2737]: Handle unicode error when parsing transceiver (#235)
Browse files Browse the repository at this point in the history
- What I did
If there is an issue in transceiver data and some junk characters are present in transceiver data, then SNMP does not parse this information and transceiver MIB cannot be queried.
Error seen in such scenario:

show interface transceiver eeprom
...
Ethernet5: SFP EEPROM detected
        Connector: Unknown
        Encoding: Unknown
        Extended Identifier: Unknown
        Extended RateSelect Compliance: Unknown
        Identifier: Unknown
        Length Cable Assembly(m): 255
        Length OM1(m): 255
        Length OM2(m): 255
        Length OM3(2m): 255
        Length(km): 255
        Nominal Bit Rate(100Mbs): 255
        Specification compliance:
                10/40G Ethernet Compliance Code: 10GBase-LR
                Fibre Channel Speed: 100 Mbytes/Sec
                Fibre Channel link length/Transmitter Technology: AAA
                Fibre Channel transmission media: AAA
                Gigabit Ethernet Compliant codes: 1000BASE-CX
                SAS/SATA compliance codes: AAA
                SONET Compliance codes: AAA
        Vendor Date Code(YYYY-MM-DD Lot): 20ÿÿ-ÿÿ-ÿÿ ÿÿ
        Vendor Name: ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
        Vendor OUI: AAA
        Vendor PN: ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
        Vendor Rev: ÿÿ
        Vendor SN: ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ

Error log in syslog:
INFO snmp#supervisord: snmp-subagent ERROR:ax_interface:MIBUpdater.start() caught an unexpected exception during update_data()
INFO snmp#supervisord: snmp-subagent Traceback (most recent call last):
INFO snmp#supervisord: snmp-subagent   File "/usr/local/lib/python3.6/dist-packages/ax_interface/mib.py", line 40, in start
INFO snmp#supervisord: snmp-subagent     self.reinit_data()
INFO snmp#supervisord: snmp-subagent   File "/usr/local/lib/python3.6/dist-packages/sonic_ax_impl/mibs/ietf/rfc2737.py", line 192, in reinit_data
INFO snmp#supervisord: snmp-subagent     self._update_transceiver_cache(interface)
INFO snmp#supervisord: snmp-subagent   File "/usr/local/lib/python3.6/dist-packages/sonic_ax_impl/mibs/ietf/rfc2737.py", line 276, in _update_transceiver_cache
INFO snmp#supervisord: snmp-subagent     self.physical_model_name_map[sub_id] = get_transceiver_data(transceiver_info)
INFO snmp#supervisord: snmp-subagent   File "/usr/local/lib/python3.6/dist-packages/sonic_ax_impl/mibs/ietf/rfc2737.py", line 76, in <genexpr>
INFO snmp#supervisord: snmp-subagent     for xcvr_field in XcvrInfoDB)

Because of this xcvr MIB does not provide expected output:
iso.3.6.1.2.1.47.1.1.1.1.13.5000 = No Such Instance currently exists at this OID
To avoid seeing this error message and to retrieve the transceiver information that is available in SNMP output, this fix is made.

- How I did it
Handle unicode error to handle parsing error seen in snmp_ax_impl.

- How to verify it
In the device where the above error was seen, fix was made and tested.

No error message in syslog.
Able to retrieve xcvr information using OID: iso.3.6.1.2.1.47.1.1.1.1
  • Loading branch information
SuvarnaMeenakshi authored Mar 1, 2022
1 parent ad07720 commit 214378c
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
11 changes: 7 additions & 4 deletions src/sonic_ax_impl/mibs/ietf/rfc2737.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@ def get_transceiver_data(xcvr_info):
:return: tuple (type, hw_version, mfg_name, model_name) of transceiver;
Empty string if field not in xcvr_info
"""

return (xcvr_info.get(xcvr_field.value, b"").decode()
for xcvr_field in XcvrInfoDB)

result = tuple()
for xcvr_field in XcvrInfoDB:
try:
result = result + (xcvr_info.get(xcvr_field.value, b"").decode(),)
except UnicodeError:
result = result + ("",)
return result

def get_transceiver_description(sfp_type, if_alias):
"""
Expand Down
5 changes: 5 additions & 0 deletions tests/mock_tables/dbconnector.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ def __init__(self, *args, **kwargs):

with open(fname) as f:
js = json.load(f)
# Add a corrupted string to test decoding of corrupted string.
# If this corrupted string is added in json file,
# json.load throws an exception.
if u'TRANSCEIVER_INFO|Ethernet4' in js and u'hardware_rev' in js[u'TRANSCEIVER_INFO|Ethernet4']:
js[u'TRANSCEIVER_INFO|Ethernet4'][u'hardware_rev'] = b'\xff\xff'
for h, table in js.items():
for k, v in table.items():
self.hset(h, k, v)
Expand Down
7 changes: 7 additions & 0 deletions tests/mock_tables/state_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
"manufacturer": "VENDOR_NAME",
"model": "MODEL_NAME"
},
"TRANSCEIVER_INFO|Ethernet4": {
"type": "QSFP+",
"hardware_rev": "\\xff\\xff",
"serial": "SERIAL_NUM_2",
"manufacturer": "VENDOR_NAME_2",
"model": "MODEL_NAME_2"
},
"TRANSCEIVER_DOM_SENSOR|Ethernet0": {
"temperature": 25.39,
"voltage": 3.37,
Expand Down
33 changes: 33 additions & 0 deletions tests/test_sn.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,39 @@ def test_getpdu_xcvr_info(self):
self.assertEqual(value.type_, expected_type)
self.assertEqual(str(value.data), str(expected_value))

def test_getpdu_xcvr_info_eth2(self):
sub_id = 1000 * 5 # sub id for Ethernet4

expected_mib = {
2: (ValueType.OCTET_STRING, "QSFP+ for etp2"),
5: (ValueType.INTEGER, PhysicalClass.PORT),
7: (ValueType.OCTET_STRING, ""), # skip
8: (ValueType.OCTET_STRING, ""), # Empty string as DB has junk string
9: (ValueType.OCTET_STRING, ""), # skip
10: (ValueType.OCTET_STRING, ""), # skip
11: (ValueType.OCTET_STRING, "SERIAL_NUM_2"),
12: (ValueType.OCTET_STRING, "VENDOR_NAME_2"),
13: (ValueType.OCTET_STRING, "MODEL_NAME_2")
}

oids = [ObjectIdentifier(12, 0, 1, 0, (1, 3, 6, 1, 2, 1, 47, 1, 1, 1, 1, field_sub_id, sub_id))
for field_sub_id in expected_mib]

get_pdu = GetNextPDU(
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0),
oids=oids
)

encoded = get_pdu.encode()
response = get_pdu.make_response(self.lut)

for mib_key, value in zip(expected_mib, response.values):
expected_oid = ObjectIdentifier(12, 0, 1, 0, (1, 3, 6, 1, 2, 1, 47, 1, 1, 1, 1, mib_key, sub_id))
expected_type, expected_value = expected_mib[mib_key]
self.assertEqual(str(value.name), str(expected_oid))
self.assertEqual(value.type_, expected_type)
self.assertEqual(str(value.data), str(expected_value))

def test_getpdu_xcvr_dom(self):
expected_mib = {
1000 * 1 + 1: "DOM Temperature Sensor for etp1",
Expand Down

0 comments on commit 214378c

Please sign in to comment.