diff options
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | extensions/openpower-pels/log_id.cpp | 97 | ||||
-rw-r--r-- | extensions/openpower-pels/log_id.hpp | 47 | ||||
-rw-r--r-- | extensions/openpower-pels/openpower-pels.mk | 2 | ||||
-rw-r--r-- | extensions/openpower-pels/paths.cpp | 23 | ||||
-rw-r--r-- | extensions/openpower-pels/paths.hpp | 15 | ||||
-rw-r--r-- | test/openpower-pels/Makefile.include | 10 | ||||
-rw-r--r-- | test/openpower-pels/log_id_test.cpp | 42 | ||||
-rw-r--r-- | test/openpower-pels/paths.cpp | 26 |
9 files changed, 269 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index 27175a5..ead0a07 100644 --- a/configure.ac +++ b/configure.ac @@ -150,6 +150,13 @@ AC_DEFINE(SYSTEMD_INTERFACE, "org.freedesktop.systemd1.Manager", [systemd interf AC_ARG_ENABLE([openpower-pel-extension], AS_HELP_STRING([--enable-openpower-pel-extension], [Create PELs]) ) + +AC_ARG_VAR(EXTENSION_PERSIST_DIR, [Base directory for extension persistent data]) +AS_IF([test "x$EXTENSION_PERSIST_DIR" == "x"], \ + [EXTENSION_PERSIST_DIR="/var/lib/phosphor-logging/extensions"]) +AC_DEFINE_UNQUOTED([EXTENSION_PERSIST_DIR], ["$EXTENSION_PERSIST_DIR"], \ + [Base directory for extension persistent data]) + AM_CONDITIONAL([ENABLE_PEL_EXTENSION], [test "x$enable_openpower_pel_extension" == "xyes"]) AC_CONFIG_HEADERS([config.h]) diff --git a/extensions/openpower-pels/log_id.cpp b/extensions/openpower-pels/log_id.cpp new file mode 100644 index 0000000..cbe1247 --- /dev/null +++ b/extensions/openpower-pels/log_id.cpp @@ -0,0 +1,97 @@ +#include "log_id.hpp" + +#include "paths.hpp" + +#include <chrono> +#include <filesystem> +#include <fstream> +#include <phosphor-logging/log.hpp> + +namespace openpower +{ +namespace pels +{ + +namespace fs = std::filesystem; +using namespace phosphor::logging; + +constexpr uint32_t startingLogID = 1; +constexpr uint32_t bmcLogIDPrefix = 0x50000000; + +namespace detail +{ + +uint32_t addLogIDPrefix(uint32_t id) +{ + // If redundant BMCs are ever a thing, may need a different prefix. + return (id & 0x00FFFFFF) | bmcLogIDPrefix; +} + +uint32_t getTimeBasedLogID() +{ + using namespace std::chrono; + + // Use 3 bytes of the nanosecond count since the epoch. + uint32_t id = + duration_cast<nanoseconds>(system_clock::now().time_since_epoch()) + .count(); + + return addLogIDPrefix(id); +} + +} // namespace detail + +uint32_t generatePELID() +{ + // Note: there isn't a need to be thread safe. + + static std::string idFilename; + if (idFilename.empty()) + { + idFilename = getPELIDFile(); + } + + uint32_t id = 0; + + if (!fs::exists(idFilename)) + { + auto path = fs::path(idFilename).parent_path(); + if (!fs::exists(path)) + { + fs::create_directories(path); + } + + id = startingLogID; + } + else + { + std::ifstream idFile{idFilename}; + idFile >> id; + if (idFile.fail()) + { + // Just make up an ID + log<level::ERR>("Unable to read PEL ID File!"); + return detail::getTimeBasedLogID(); + } + } + + // Wrapping shouldn't be a problem, but check anyway + if (id == 0x00FFFFFF) + { + id = startingLogID; + } + + std::ofstream idFile{idFilename}; + idFile << (id + 1); + if (idFile.fail()) + { + // Just make up an ID so we don't reuse one next time + log<level::ERR>("Unable to write PEL ID File!"); + return detail::getTimeBasedLogID(); + } + + return detail::addLogIDPrefix(id); +} + +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/log_id.hpp b/extensions/openpower-pels/log_id.hpp new file mode 100644 index 0000000..21f04eb --- /dev/null +++ b/extensions/openpower-pels/log_id.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include <cstdint> + +namespace openpower +{ +namespace pels +{ + +namespace detail +{ + +/** + * @brief Adds the 1 byte log creator prefix to the log ID + * + * @param[in] id - the ID to add it to + * + * @return - the full log ID + */ +uint32_t addLogIDPrefix(uint32_t id); + +/** + * @brief Generates a PEL ID based on the current time. + * + * Used for error scenarios where the normal method doesn't + * work in order to get a unique ID still. + * + * @return A unique log ID. + */ +uint32_t getTimeBasedLogID(); + +} // namespace detail + +/** + * @brief Generates a unique PEL log entry ID every time + * it is called. + * + * This ID is used at offset 0x2C in the Private Header + * section of a PEL. For single BMC systems, it must + * start with 0x50. + * + * @return uint32_t - The log ID + */ +uint32_t generatePELID(); + +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk index cc933f9..2cc2393 100644 --- a/extensions/openpower-pels/openpower-pels.mk +++ b/extensions/openpower-pels/openpower-pels.mk @@ -1,6 +1,8 @@ phosphor_log_manager_SOURCES += \ extensions/openpower-pels/bcd_time.cpp \ extensions/openpower-pels/entry_points.cpp \ + extensions/openpower-pels/log_id.cpp \ extensions/openpower-pels/manager.cpp \ + extensions/openpower-pels/paths.cpp \ extensions/openpower-pels/private_header.cpp \ extensions/openpower-pels/user_header.cpp diff --git a/extensions/openpower-pels/paths.cpp b/extensions/openpower-pels/paths.cpp new file mode 100644 index 0000000..dab73c9 --- /dev/null +++ b/extensions/openpower-pels/paths.cpp @@ -0,0 +1,23 @@ +#include "config.h" + +#include "paths.hpp" + +#include <filesystem> + +namespace openpower +{ +namespace pels +{ + +namespace fs = std::filesystem; + +fs::path getPELIDFile() +{ + fs::path logIDPath{EXTENSION_PERSIST_DIR}; + logIDPath /= fs::path{"pels"} / fs::path{"pelID"}; + return logIDPath; +} + +} // namespace pels + +} // namespace openpower diff --git a/extensions/openpower-pels/paths.hpp b/extensions/openpower-pels/paths.hpp new file mode 100644 index 0000000..334165c --- /dev/null +++ b/extensions/openpower-pels/paths.hpp @@ -0,0 +1,15 @@ +#pragma once +#include <filesystem> + +namespace openpower +{ +namespace pels +{ + +/** + * @brief Returns the path to the PEL ID file + */ +std::filesystem::path getPELIDFile(); + +} // namespace pels +} // namespace openpower diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include index f860db2..0e0257c 100644 --- a/test/openpower-pels/Makefile.include +++ b/test/openpower-pels/Makefile.include @@ -3,6 +3,7 @@ TESTS += $(check_PROGRAMS) check_PROGRAMS += \ additional_data_test \ bcd_time_test \ + log_id_test \ private_header_test \ section_header_test \ stream_test \ @@ -58,3 +59,12 @@ user_header_test_LDADD = \ $(test_ldadd) \ $(pel_objects) user_header_test_LDFLAGS = $(test_ldflags) + +log_id_test_SOURCES = \ + %reldir%/log_id_test.cpp %reldir%/paths.cpp +log_id_test_CPPFLAGS = $(test_cppflags) +log_id_test_CXXFLAGS = $(test_cxxflags) +log_id_test_LDADD = \ + $(test_ldadd) \ + $(top_builddir)/extensions/openpower-pels/log_id.o +log_id_test_LDFLAGS = $(test_ldflags) diff --git a/test/openpower-pels/log_id_test.cpp b/test/openpower-pels/log_id_test.cpp new file mode 100644 index 0000000..e5f2632 --- /dev/null +++ b/test/openpower-pels/log_id_test.cpp @@ -0,0 +1,42 @@ +#include "extensions/openpower-pels/log_id.hpp" +#include "extensions/openpower-pels/paths.hpp" + +#include <arpa/inet.h> + +#include <filesystem> + +#include <gtest/gtest.h> + +using namespace openpower::pels; +namespace fs = std::filesystem; + +TEST(LogIdTest, TimeBasedIDTest) +{ + uint32_t lastID = 0; + for (int i = 0; i < 10; i++) + { + auto id = detail::getTimeBasedLogID(); + + EXPECT_EQ(id & 0xFF000000, 0x50000000); + EXPECT_NE(id, lastID); + lastID = id; + } +} + +TEST(LogIdTest, IDTest) +{ + EXPECT_EQ(generatePELID(), 0x50000001); + EXPECT_EQ(generatePELID(), 0x50000002); + EXPECT_EQ(generatePELID(), 0x50000003); + EXPECT_EQ(generatePELID(), 0x50000004); + EXPECT_EQ(generatePELID(), 0x50000005); + EXPECT_EQ(generatePELID(), 0x50000006); + + auto backingFile = getPELIDFile(); + fs::remove(backingFile); + EXPECT_EQ(generatePELID(), 0x50000001); + EXPECT_EQ(generatePELID(), 0x50000002); + EXPECT_EQ(generatePELID(), 0x50000003); + + fs::remove_all(fs::path{backingFile}.parent_path()); +} diff --git a/test/openpower-pels/paths.cpp b/test/openpower-pels/paths.cpp new file mode 100644 index 0000000..464b92c --- /dev/null +++ b/test/openpower-pels/paths.cpp @@ -0,0 +1,26 @@ +#include "extensions/openpower-pels/paths.hpp" + +#include <filesystem> + +namespace openpower +{ +namespace pels +{ + +// Use paths that work in unit tests. + +std::filesystem::path getPELIDFile() +{ + static std::string idFile; + + if (idFile.empty()) + { + char templ[] = "/tmp/logidtestXXXXXX"; + std::filesystem::path dir = mkdtemp(templ); + idFile = dir / "logid"; + } + return idFile; +} + +} // namespace pels +} // namespace openpower |