diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | extensions/openpower-pels/manager.cpp | 90 | ||||
-rw-r--r-- | extensions/openpower-pels/manager.hpp | 65 | ||||
-rw-r--r-- | test/openpower-pels/Makefile.include | 8 | ||||
-rw-r--r-- | test/openpower-pels/pel_manager_test.cpp | 83 |
5 files changed, 239 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac index 657424d..ae9d6e8 100644 --- a/configure.ac +++ b/configure.ac @@ -169,7 +169,7 @@ AS_IF([test "x$enable_openpower_pel_extension" == "xyes"], [], [AC_MSG_ERROR([Could not find fifo_map.hpp])]) - AX_PKG_CHECK_MODULES([LIBPLDM], [libpldm])] + AX_PKG_CHECK_MODULES([LIBPLDM], [libpldm])] ) AC_ARG_ENABLE([dont-send-pels-to-host], diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp index b9c7d94..aec5053 100644 --- a/extensions/openpower-pels/manager.cpp +++ b/extensions/openpower-pels/manager.cpp @@ -20,6 +20,7 @@ #include <filesystem> #include <fstream> +#include <xyz/openbmc_project/Common/error.hpp> namespace openpower { @@ -29,6 +30,8 @@ namespace pels using namespace phosphor::logging; namespace fs = std::filesystem; +namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error; + namespace additional_data { constexpr auto rawPEL = "RAWPEL"; @@ -73,7 +76,7 @@ void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID) file.close(); - auto pel = std::make_unique<PEL>(data, obmcLogID); + auto pel = std::make_unique<openpower::pels::PEL>(data, obmcLogID); if (pel->valid()) { // PELs created by others still need these fields set by us. @@ -132,8 +135,8 @@ void Manager::createPEL(const std::string& message, uint32_t obmcLogID, { AdditionalData ad{additionalData}; - auto pel = std::make_unique<PEL>(*entry, obmcLogID, timestamp, severity, - ad, *_dataIface); + auto pel = std::make_unique<openpower::pels::PEL>( + *entry, obmcLogID, timestamp, severity, ad, *_dataIface); _repo.add(pel); @@ -160,5 +163,86 @@ void Manager::createPEL(const std::string& message, uint32_t obmcLogID, } } +sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID) +{ + Repository::LogID id{Repository::LogID::Pel(pelID)}; + std::optional<int> fd; + + try + { + fd = _repo.getPELFD(id); + } + catch (std::exception& e) + { + throw common_error::InternalFailure(); + } + + if (!fd) + { + throw common_error::InvalidArgument(); + } + + return *fd; +} + +std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID) +{ + Repository::LogID id{Repository::LogID::Obmc(obmcLogID)}; + std::optional<std::vector<uint8_t>> data; + + try + { + data = _repo.getPELData(id); + } + catch (std::exception& e) + { + throw common_error::InternalFailure(); + } + + if (!data) + { + throw common_error::InvalidArgument(); + } + + return *data; +} + +void Manager::hostAck(uint32_t pelID) +{ + Repository::LogID id{Repository::LogID::Pel(pelID)}; + + if (!_repo.hasPEL(id)) + { + throw common_error::InvalidArgument(); + } + + if (_hostNotifier) + { + _hostNotifier->ackPEL(pelID); + } +} + +void Manager::hostReject(uint32_t pelID, RejectionReason reason) +{ + Repository::LogID id{Repository::LogID::Pel(pelID)}; + + if (!_repo.hasPEL(id)) + { + throw common_error::InvalidArgument(); + } + + if (_hostNotifier) + { + if (reason == RejectionReason::BadPEL) + { + _hostNotifier->setBadPEL(pelID); + } + else if (reason == RejectionReason::HostFull) + { + _hostNotifier->setHostFull(pelID); + } + } +} + } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/manager.hpp b/extensions/openpower-pels/manager.hpp index 731dd16..7f1fcda 100644 --- a/extensions/openpower-pels/manager.hpp +++ b/extensions/openpower-pels/manager.hpp @@ -1,5 +1,7 @@ #pragma once +#include "config.h" + #include "data_interface.hpp" #include "host_notifier.hpp" #include "log_manager.hpp" @@ -7,15 +9,21 @@ #include "registry.hpp" #include "repository.hpp" +#include <org/open_power/Logging/PEL/server.hpp> +#include <sdbusplus/server.hpp> + namespace openpower { namespace pels { +using PELInterface = sdbusplus::server::object::object< + sdbusplus::org::open_power::Logging::server::PEL>; + /** * @brief PEL manager object */ -class Manager +class Manager : public PELInterface { public: Manager() = delete; @@ -33,8 +41,8 @@ class Manager */ Manager(phosphor::logging::internal::Manager& logManager, std::unique_ptr<DataInterfaceBase> dataIface) : - _logManager(logManager), - _repo(getPELRepoPath()), + PELInterface(logManager.getBus(), OBJ_LOGGING), + _logManager(logManager), _repo(getPELRepoPath()), _registry(getMessageRegistryPath() / message::registryFileName), _dataIface(std::move(dataIface)) { @@ -91,6 +99,57 @@ class Manager */ bool isDeleteProhibited(uint32_t obmcLogID); + /** + * @brief Return a file descriptor to the raw PEL data + * + * Throws InvalidArgument if the PEL ID isn't found, + * and InternalFailure if anything else fails. + * + * @param[in] pelID - The PEL ID to get the data for + * + * @return unix_fd - File descriptor to the file that contains the PEL + */ + sdbusplus::message::unix_fd getPEL(uint32_t pelID) override; + + /** + * @brief Returns data for the PEL corresponding to an OpenBMC + * event log. + * + * @param[in] obmcLogID - The OpenBMC event log ID + * + * @return vector<uint8_t> - The raw PEL data + */ + std::vector<uint8_t> getPELFromOBMCID(uint32_t obmcLogID) override; + + /** + * @brief The D-Bus method called when a host successfully processes + * a PEL. + * + * This D-Bus method is called from the PLDM daemon when they get an + * 'Ack PEL' PLDM message from the host, which indicates the host + * firmware successfully sent it to the OS and this code doesn't need + * to send it to the host again. + * + * @param[in] pelID - The PEL ID + */ + void hostAck(uint32_t pelID) override; + + /** + * @brief D-Bus method called when the host rejects a PEL. + * + * This D-Bus method is called from the PLDM daemon when they get an + * 'Ack PEL' PLDM message from the host with a payload that says + * something when wrong. + * + * The choices are either: + * * Host Full - The host's staging area is full - try again later + * * Malrformed PEL - The host received an invalid PEL + * + * @param[in] pelID - The PEL ID + * @param[in] reason - One of the above two reasons + */ + void hostReject(uint32_t pelID, RejectionReason reason) override; + private: /** * @brief Adds a received raw PEL to the PEL repository diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include index 1cb310f..6905dc3 100644 --- a/test/openpower-pels/Makefile.include +++ b/test/openpower-pels/Makefile.include @@ -141,7 +141,9 @@ repository_test_LDFLAGS = $(test_ldflags) pel_manager_test_SOURCES = \ %reldir%/pel_manager_test.cpp %reldir%/paths.cpp %reldir%/pel_utils.cpp pel_manager_test_CPPFLAGS = $(test_cppflags) -pel_manager_test_CXXFLAGS = $(test_cxxflags) $(SDEVENTPLUS_CFLAGS) +pel_manager_test_CXXFLAGS = \ + $(test_cxxflags) \ + $(SDEVENTPLUS_CFLAGS) pel_manager_test_LDADD = \ $(test_ldadd) \ $(pel_objects) \ @@ -149,7 +151,9 @@ pel_manager_test_LDADD = \ $(top_builddir)/extensions/openpower-pels/host_notifier.o \ $(top_builddir)/extensions/openpower-pels/manager.o \ $(top_builddir)/extensions/openpower-pels/repository.o -pel_manager_test_LDFLAGS = $(test_ldflags) $(SDEVENTPLUS_LIBS) +pel_manager_test_LDFLAGS = \ + $(test_ldflags) \ + $(SDEVENTPLUS_LIBS) registry_test_SOURCES = \ %reldir%/registry_test.cpp %reldir%/paths.cpp diff --git a/test/openpower-pels/pel_manager_test.cpp b/test/openpower-pels/pel_manager_test.cpp index a84ea7a..3036f30 100644 --- a/test/openpower-pels/pel_manager_test.cpp +++ b/test/openpower-pels/pel_manager_test.cpp @@ -19,6 +19,7 @@ #include <fstream> #include <regex> +#include <xyz/openbmc_project/Common/error.hpp> #include <gtest/gtest.h> @@ -166,3 +167,85 @@ TEST_F(ManagerTest, TestCreateWithMessageRegistry) pelFile = findAnyPELInRepo(); EXPECT_FALSE(pelFile); } + +TEST_F(ManagerTest, TestDBusMethods) +{ + auto bus = sdbusplus::bus::new_default(); + phosphor::logging::internal::Manager logManager(bus, "logging_path"); + std::unique_ptr<DataInterfaceBase> dataIface = + std::make_unique<DataInterface>(bus); + + Manager manager{logManager, std::move(dataIface)}; + + // Create a PEL, write it to a file, and pass that filename into + // the create function so there's one in the repo. + auto data = pelDataFactory(TestPELType::pelSimple); + + fs::path pelFilename = makeTempDir() / "rawpel"; + std::ofstream pelFile{pelFilename}; + pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); + pelFile.close(); + + std::string adItem = "RAWPEL=" + pelFilename.string(); + std::vector<std::string> additionalData{adItem}; + std::vector<std::string> associations; + + manager.create("error message", 42, 0, + phosphor::logging::Entry::Level::Error, additionalData, + associations); + + // getPELFromOBMCID + auto newData = manager.getPELFromOBMCID(42); + EXPECT_EQ(newData.size(), data.size()); + + // Read the PEL to get the ID for later + PEL pel{newData}; + auto id = pel.id(); + + EXPECT_THROW( + manager.getPELFromOBMCID(id + 1), + sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); + + // getPEL + auto unixfd = manager.getPEL(id); + + // Get the size + struct stat s; + int r = fstat(unixfd, &s); + ASSERT_EQ(r, 0); + auto size = s.st_size; + + // Open the FD and check the contents + FILE* fp = fdopen(unixfd, "r"); + ASSERT_NE(fp, nullptr); + + std::vector<uint8_t> fdData; + fdData.resize(size); + r = fread(fdData.data(), 1, size, fp); + EXPECT_EQ(r, size); + + EXPECT_EQ(newData, fdData); + + fclose(fp); + + EXPECT_THROW( + manager.getPEL(id + 1), + sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); + + // hostAck + manager.hostAck(id); + + EXPECT_THROW( + manager.hostAck(id + 1), + sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); + + // hostReject + manager.hostReject(id, Manager::RejectionReason::BadPEL); + manager.hostReject(id, Manager::RejectionReason::HostFull); + + EXPECT_THROW( + manager.hostReject(id + 1, Manager::RejectionReason::BadPEL), + sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); + + fs::remove_all(pelFilename.parent_path()); +} |