From be7a3c753a3b390878dbb55c1d2186750309be01 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Fri, 10 Jul 2026 03:21:13 +0200 Subject: [PATCH 1/4] Fix crash if sel entry is not OEM --- confluent_server/aiohmi/ipmi/oem/generic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/confluent_server/aiohmi/ipmi/oem/generic.py b/confluent_server/aiohmi/ipmi/oem/generic.py index 34ca2b79..5775b241 100644 --- a/confluent_server/aiohmi/ipmi/oem/generic.py +++ b/confluent_server/aiohmi/ipmi/oem/generic.py @@ -143,7 +143,9 @@ class OEMHandler(object): to apply some transform to some field to suit their conventions. """ event['oem_handler'] = None - evdata = event['event_data_bytes'] + evdata = event.get('event_data_bytes') + if evdata is None: + return if evdata[0] & 0b11000000 == 0b10000000: event['oem_byte2'] = evdata[1] if evdata[0] & 0b110000 == 0b100000: From 9f35965b1b877887bd2fb0e34a7de4c6e34793a4 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Fri, 10 Jul 2026 15:47:37 +0200 Subject: [PATCH 2/4] Decode reserved SEL record types as standard events Some BMCs (e.g. AMI) log events using spec-reserved record types like 0x04 with a standard system event record layout. Previously only type 0x02 was decoded, leaving such entries with no usable data and tripping the generic OEM handler. Follow ipmitool and treat all types below 0xc0 as standard format. If the body of a reserved type turns out not to follow the standard layout, fall back to passing it through raw instead of aborting the whole log retrieval. --- confluent_server/aiohmi/ipmi/events.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/confluent_server/aiohmi/ipmi/events.py b/confluent_server/aiohmi/ipmi/events.py index c2c4b1ca..2314128c 100644 --- a/confluent_server/aiohmi/ipmi/events.py +++ b/confluent_server/aiohmi/ipmi/events.py @@ -519,12 +519,25 @@ class EventHandler(object): selentry = bytearray(origselentry) event = {} event['record_id'] = struct.unpack_from('= 7: # Either standard, or at least the timestamp is standard event['timecode'] = struct.unpack_from(' Date: Fri, 10 Jul 2026 15:48:05 +0200 Subject: [PATCH 3/4] Decode Linux kernel panic SEL records The Linux kernel ipmi panic logger stores panic strings in SEL records of type 0xf0, with a chunk sequence number in byte 4 and up to 11 characters of the message in bytes 5-15. ipmitool and freeipmi both recognize this convention; do the same rather than presenting such records as opaque non-timestamped OEM data. --- confluent_server/aiohmi/ipmi/events.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/confluent_server/aiohmi/ipmi/events.py b/confluent_server/aiohmi/ipmi/events.py index 2314128c..27e05a1b 100644 --- a/confluent_server/aiohmi/ipmi/events.py +++ b/confluent_server/aiohmi/ipmi/events.py @@ -541,6 +541,18 @@ class EventHandler(object): elif 0xc0 <= selentry[2] <= 0xdf: event['oemid'] = selentry[7:10] event['oemdata'] = selentry[10:] + elif selentry[2] == 0xf0: + # De facto standard from the Linux kernel ipmi panic logger, + # also recognized by ipmitool and freeipmi: byte 4 is a chunk + # sequence number and bytes 5-15 carry a piece of the panic + # string + event['event'] = 'Linux kernel panic: {0}'.format( + selentry[5:16].partition(b'\x00')[0].decode( + 'utf-8', 'replace')) + event['severity'] = pygconst.Health.Critical + # this layout is defined by the kernel convention rather than + # the BMC vendor, so bypass the OEM handler + return event elif selentry[2] >= 0xe0: # In this class of OEM message, all bytes are OEM, interpretation # is wholly left up to the OEM layer, using the OEM ID of the BMC From 3af93c2a395299f8b439c24e0c6493f07324a9b5 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Fri, 10 Jul 2026 16:16:28 +0200 Subject: [PATCH 4/4] Tolerate standard SEL records with malformed bodies A type 0x02 record whose body cannot be decoded (e.g. a bogus EvM revision) would raise and abort retrieval of the entire event log. ipmitool and freeipmi print such entries with whatever fields they can extract rather than failing; degrade to the same raw passthrough used for undecodable reserved types instead of raising. --- confluent_server/aiohmi/ipmi/events.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/confluent_server/aiohmi/ipmi/events.py b/confluent_server/aiohmi/ipmi/events.py index 27e05a1b..3d8aa179 100644 --- a/confluent_server/aiohmi/ipmi/events.py +++ b/confluent_server/aiohmi/ipmi/events.py @@ -529,9 +529,7 @@ class EventHandler(object): try: self._decode_standard_event(selentry[7:], event) except Exception: - if selentry[2] == 2: - raise - # a reserved type that does not actually follow the standard + # a record body that does not actually follow the standard # layout; discard any partially decoded fields and pass it # through raw rather than aborting the fetch for key in list(event):