sel: Support OEM record 0xCD~0xDF
The SEL OEM record is retrieved from logging/entry, and converted to SEL
format.
Tested: When the BMC has a logging entry like below:
{
"data": {
"AdditionalData": [
"EVENT_DIR=0",
"GENERATOR_ID=0",
"RECORD_TYPE=205",
"SENSOR_DATA=1112141500DDB3BACD000000",
"SENSOR_PATH=",
"_PID=200"
],
"Associations": [],
"Id": 1,
"Message": "xyz.openbmc_project.Logging.SEL.Error.Created",
"Purpose": "xyz.openbmc_project.Software.Version.VersionPurpose.BMC",
"Resolved": false,
"Severity": "xyz.openbmc_project.Logging.Entry.Level.Informational",
"Timestamp": 320246,
"UpdateTimestamp": 320246,
"Version": "2.9.0-dev-1308-g01b7feb91-dirty"
},
"message": "200 OK",
"status": "ok"
}
Verify the SEL entry is expected:
SEL Record ID : 0002
Record Type : cd (OEM timestamped)
Timestamp : 01/01/1970 01:22:47
Manufactacturer ID : b3dd00
OEM Defined : bacd00010000 [......]
Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: Ia9ee86d8cb98ddd8d64f82170e1b57a45af7bed1
diff --git a/selutility.cpp b/selutility.cpp
index 83a8bd2..528cffd 100644
--- a/selutility.cpp
+++ b/selutility.cpp
@@ -2,6 +2,7 @@
#include "selutility.hpp"
+#include <charconv>
#include <chrono>
#include <filesystem>
#include <ipmid/api.hpp>
@@ -16,6 +17,13 @@
using InternalFailure =
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+namespace
+{
+
+constexpr auto systemEventRecord = 0x02;
+
+} // namespace
+
namespace ipmi
{
@@ -25,6 +33,54 @@
namespace internal
{
+inline bool isRecordOEM(uint8_t recordType)
+{
+ return recordType != systemEventRecord;
+}
+
+/** Parse the entry with format like key=val */
+std::pair<std::string, std::string> parseEntry(const std::string& entry)
+{
+ constexpr auto equalSign = "=";
+ auto pos = entry.find(equalSign);
+ assert(pos != std::string::npos);
+ auto key = entry.substr(0, pos);
+ auto val = entry.substr(pos + 1);
+ return {key, val};
+}
+
+std::map<std::string, std::string>
+ parseAdditionalData(const AdditionalData& data)
+{
+ std::map<std::string, std::string> ret;
+
+ for (const auto& d : data)
+ {
+ ret.insert(parseEntry(d));
+ }
+ return ret;
+}
+
+uint8_t convert(const std::string_view& str, int base = 10)
+{
+ int ret;
+ std::from_chars(str.data(), str.data() + str.size(), ret, base);
+ return static_cast<uint8_t>(ret);
+}
+
+// Convert the string to a vector of uint8_t, where the str is formatted as hex
+std::vector<uint8_t> convertVec(const std::string_view& str)
+{
+ std::vector<uint8_t> ret;
+ auto len = str.size() / 2;
+ ret.reserve(len);
+ for (size_t i = 0; i < len; ++i)
+ {
+ ret.emplace_back(convert(str.substr(i * 2, 2), 16));
+ }
+ return ret;
+}
+
GetSELEntryResponse
prepareSELEntry(const std::string& objPath,
ipmi::sensor::InvObjectIDMap::const_iterator iter)
@@ -72,7 +128,49 @@
if (iter == invSensors.end())
{
// It is expected to be a custom SEL entry
- // TODO
+ record.event.oemCD.recordID =
+ static_cast<uint16_t>(std::get<uint32_t>(iterId->second));
+ static constexpr auto propAdditionalData = "AdditionalData";
+ // static constexpr auto strEventDir = "EVENT_DIR";
+ // static constexpr auto strGenerateId = "GENERATOR_ID";
+ static constexpr auto strRecordType = "RECORD_TYPE";
+ static constexpr auto strSensorData = "SENSOR_DATA";
+ // static constexpr auto strSensorPath = "SENSOR_PATH";
+ iterId = entryData.find(propAdditionalData);
+ if (iterId == entryData.end())
+ {
+ log<level::ERR>("Error finding AdditionalData");
+ elog<InternalFailure>();
+ }
+ const auto& addData = std::get<AdditionalData>(iterId->second);
+ auto m = parseAdditionalData(addData);
+ auto recordType = convert(m[strRecordType]);
+ auto isOEM = isRecordOEM(recordType);
+ if (isOEM)
+ {
+ if (recordType >= 0xC0 && recordType < 0xE0)
+ {
+ record.event.oemCD.timeStamp = static_cast<uint32_t>(
+ std::chrono::duration_cast<std::chrono::seconds>(
+ chronoTimeStamp)
+ .count());
+ record.event.oemCD.recordType = recordType;
+ // The ManufactureID and OEM Defined are packed in the sensor
+ // data
+ auto sensorData = convertVec(m[strSensorData]);
+ // Fill the 9 bytes of Manufacture ID and oemDefined
+ memcpy(&record.event.oemCD.manufacturerID, sensorData.data(),
+ std::min(sensorData.size(), static_cast<size_t>(9)));
+ }
+ else if (recordType >= 0xE0)
+ {
+ // TODO
+ }
+ }
+ else
+ {
+ // TODO
+ }
}
else
{
@@ -83,7 +181,6 @@
std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
.count());
- static constexpr auto systemEventRecord = 0x02;
static constexpr auto generatorID = 0x2000;
static constexpr auto eventMsgRevision = 0x04;