#pragma once #include "config.h" #include "data_interface.hpp" #include "event_logger.hpp" #include "host_notifier.hpp" #include "journal.hpp" #include "log_manager.hpp" #include "paths.hpp" #include "pel.hpp" #include "registry.hpp" #include "repository.hpp" #include #include #include #include #include #include namespace openpower { namespace pels { using PELInterface = sdbusplus::server::object_t< sdbusplus::org::open_power::Logging::server::PEL>; /** * @brief PEL manager object */ class Manager : public PELInterface { public: Manager() = delete; Manager(const Manager&) = default; Manager& operator=(const Manager&) = default; Manager(Manager&&) = default; Manager& operator=(Manager&&) = default; /** * @brief constructor * * @param[in] logManager - internal::Manager object * @param[in] dataIface - The data interface object * @param[in] creatorFunc - The function that EventLogger will * use for creating event logs */ Manager(phosphor::logging::internal::Manager& logManager, std::unique_ptr dataIface, EventLogger::LogFunction creatorFunc, std::unique_ptr journal) : PELInterface(logManager.getBus(), OBJ_LOGGING), _logManager(logManager), _eventLogger(std::move(creatorFunc)), _repo(getPELRepoPath()), _registry(getPELReadOnlyDataPath() / message::registryFileName), _event(sdeventplus::Event::get_default()), _dataIface(std::move(dataIface)), _journal(std::move(journal)) { for (const auto& entry : _logManager.entries) { setEntryPath(entry.first); setServiceProviderNotifyFlag(entry.first); // Create PELEntry interface and setup properties with their values createPELEntry(entry.first, true); } setupPELDeleteWatch(); _dataIface->subscribeToFruPresent( "Manager", std::bind(&Manager::hardwarePresent, this, std::placeholders::_1)); } /** * @brief constructor that enables host notification * * @param[in] logManager - internal::Manager object * @param[in] dataIface - The data interface object * @param[in] creatorFunc - The function that EventLogger will * use for creating event logs * @param[in] hostIface - The hostInterface object */ Manager(phosphor::logging::internal::Manager& logManager, std::unique_ptr dataIface, EventLogger::LogFunction creatorFunc, std::unique_ptr journal, std::unique_ptr hostIface) : Manager(logManager, std::move(dataIface), std::move(creatorFunc), std::move(journal)) { _hostNotifier = std::make_unique( _repo, *(_dataIface.get()), std::move(hostIface)); } /** * @brief Destructor */ ~Manager(); /** * @brief Creates a PEL based on the OpenBMC event log contents. If * a PEL was passed in via the RAWPEL specifier in the * additionalData parameter, use that instead. * * @param[in] message - the event log message property * @param[in] obmcLogID - the corresponding OpenBMC event log id * @param[in] timestamp - the Timestamp property * @param[in] severity - the event log severity * @param[in] additionalData - the AdditionalData property * @param[in] associations - the Associations property * @param[in] ffdc - A vector of FFDC file information */ void create(const std::string& message, uint32_t obmcLogID, uint64_t timestamp, phosphor::logging::Entry::Level severity, const std::vector& additionalData, const std::vector& associations, const phosphor::logging::FFDCEntries& ffdc = phosphor::logging::FFDCEntries{}); /** * @brief Erase a PEL based on its OpenBMC event log ID * * @param[in] obmcLogID - the corresponding OpenBMC event log id */ void erase(uint32_t obmcLogID); /** @brief Says if an OpenBMC event log may not be manually deleted at this * time because its corresponding PEL cannot be. * * There are PEL retention policies that can prohibit the manual deletion * of PELs (and therefore OpenBMC event logs). * * @param[in] obmcLogID - the OpenBMC event log ID * @return bool - true if prohibited */ 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 - The raw PEL data */ std::vector 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; /** * @brief D-Bus method to create a PEL/OpenBMC event log and * return the created OpenBMC and PEL log IDs. * * The same as the CreateWithFFDCFiles method on the * xyz.openbmc_project.Logging.Create interface, except for * the return values. * * @param[in] message - The event log message property * @param[in] severity - The event log severity * @param[in] additionalData - The AdditionalData property * @param[in] ffdc - A vector of FFDC file information */ std::tuple createPELWithFFDCFiles( std::string message, phosphor::logging::Entry::Level severity, std::map additionalData, std::vector> fFDC) override; /** * @brief D-Bus method to return the PEL in JSON format * * @param[in] obmcLogID - The OpenBMC entry log ID * * @return std::string - The fully parsed PEL in JSON */ std::string getPELJSON(uint32_t obmcLogID) override; /** * @brief Converts the ESEL field in an OpenBMC event log to a * vector of uint8_ts that just contains the PEL data. * * That data string looks like: "50 48 00 ab ..." * * Throws an exception on any failures. * * @param[in] esel - The ESEL string * * @return std::vector - The contained PEL data */ static std::vector eselToRawData(const std::string& esel); /** * @brief Generate resolution string from the PEL * * @param[in] pel - The PEL to use */ std::string getResolution(const openpower::pels::PEL& pel) const; /** * @brief Generate event ID from the PEL * * @param[in] pel - The PEL to use */ std::string getEventId(const openpower::pels::PEL& pel) const; /** @brief Implementation for GetPELIdFromBMCLogId * * Returns the PEL Id (aka Entry ID (EID)) based on the given * BMC event log id. * * @param[in] bmcLogId - The BMC event log id of the PEL to retrieve * the PEL id. * * @return uint32_t - The Id of the PEL. * Throw "InvalidArgument" if not found. */ uint32_t getPELIdFromBMCLogId(uint32_t bmcLogId) override; /** @brief Implementation for GetBMCLogIdFromPELId * * Returns the BMC event log id based on the given PEL id * (aka Entry ID (EID)). * * @param[in] pelId - The PEL id to retrieve the BMC event log id. * * @return uint32_t - The BMC event log id of the PEL. * Throw "InvalidArgument" if not found. */ uint32_t getBMCLogIdFromPELId(uint32_t pelId) override; /** * @brief Update boot progress SRC based on severity 0x51, critical error * * @param[in] pel - The PEL to use */ void updateProgressSRC(std::unique_ptr& pel) const; /** * @brief Converts unprintable characters from the passed * in string to spaces so they won't crash D-Bus when * used as a property value. * * @param[in] field - The field to fix * * @return std::string - The string without non printable characters. */ static std::string sanitizeFieldForDBus(std::string field); private: /** * @brief Adds a received raw PEL to the PEL repository * * @param[in] rawPelPath - The path to the file that contains the * raw PEL. * @param[in] obmcLogID - the corresponding OpenBMC event log id */ void addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID); /** * @brief Creates a PEL based on the OpenBMC event log contents. * * @param[in] message - The event log message property * @param[in] obmcLogID - the corresponding OpenBMC event log id * @param[in] timestamp - The timestamp property * @param[in] severity - The event log severity * @param[in] additionalData - The AdditionalData property * @param[in] associations - The associations property * @param[in] ffdc - A vector of FFDC file information */ void createPEL(const std::string& message, uint32_t obmcLogID, uint64_t timestamp, phosphor::logging::Entry::Level severity, const std::vector& additionalData, const std::vector& associations, const phosphor::logging::FFDCEntries& ffdc); /** * @brief Schedules a close of the file descriptor to occur from * the event loop. * * Uses sd_event_add_defer * * @param[in] fd - The file descriptor to close */ void scheduleFDClose(int fd); /** * @brief Closes the file descriptor passed in. * * This is called from the event loop to close FDs returned * from getPEL(). * * @param[in] fd - The file descriptor to close * @param[in] source - The event source object used */ void closeFD(int fd, sdeventplus::source::EventBase& source); /** * @brief Adds a PEL to the repository given its data * * @param[in] pelData - The PEL to add as a vector of uint8_ts * @param[in] obmcLogID - the OpenBMC event log ID */ void addPEL(std::vector& pelData, uint32_t obmcLogID); /** * @brief Adds the PEL stored in the ESEL field of the AdditionalData * property of an OpenBMC event log to the repository. * * @param[in] esel - The ESEL AdditionalData contents * @param[in] obmcLogID - The OpenBMC event log ID */ void addESELPEL(const std::string& esel, uint32_t obmcLogID); /** * @brief Converts the D-Bus FFDC method argument into a data * structure understood by the PEL code. * * @param[in] ffdc - A vector of FFDC file information * * @return PelFFDC - The PEL FFDC data structure */ PelFFDC convertToPelFFDC(const phosphor::logging::FFDCEntries& ffdc); /** * @brief Schedules a PEL repository prune to occur from * the event loop. * * Uses sd_event_add_defer */ void scheduleRepoPrune(); /** * @brief Prunes old PELs out of the repository to save space. * * This is called from the event loop. * * @param[in] source - The event source object used */ void pruneRepo(sdeventplus::source::EventBase& source); /** * @brief Sets up an inotify watch to watch for deleted PEL * files. Calls pelFileDeleted() when that occurs. */ void setupPELDeleteWatch(); /** * @brief Called when the inotify watch put on the repository directory * detects a PEL file was deleted. * * Will tell the Repository class about the deleted PEL, and then tell * the log manager class to delete the corresponding OpenBMC event log. */ void pelFileDeleted(sdeventplus::source::IO& io, int fd, uint32_t revents); /** * @brief Check if the input PEL should cause a quiesce of the system * * If QuiesceOnHwError is enabled within phosphor-settings and the PEL * from the host has a severity which is not SeverityType::nonError or * recovered then execute the quiesce and boot block logic. * * @param[in] pel - The PEL to check */ void checkPelAndQuiesce(std::unique_ptr& pel); /** * @brief Update eventId D-bus property for this error log * * Update the eventId property of D-bus with SRC and hexwords from the * PEL created * * @param[in] pel - The PEL to use */ void updateEventId(std::unique_ptr& pel); /** * @brief Finds and serializes the log entry for the ID passed in. * @param[in] obmcLogID - The OpenBMC event log ID */ void serializeLogEntry(uint32_t obmcLogID); /** * @brief Sets the FilePath of the specified error log entry to the PEL file * path. * * @param[in] obmcLogID - The OpenBMC entry log ID */ void setEntryPath(uint32_t obmcLogID); /** * @brief Sets the serviceProviderNotify D-bus property of PEL. * * @param[in] obmcLogID - The OpenBMC entry log ID */ void setServiceProviderNotifyFlag(uint32_t obmcLogID); /** * @brief Update resolution D-bus property for this error log * * Update the resolution property of D-bus with callouts extracted from PEL * * @param[in] pel - The PEL to use * * @return bool - false for Repositor::for_each(). */ bool updateResolution(const openpower::pels::PEL& pel); /** * @brief Check if the D-Bus severity property for the event log * needs to be updated based on the final PEL severity, * and update the property accordingly. * * @param[in] pel - The PEL to operate on. */ void updateDBusSeverity(const openpower::pels::PEL& pel); /** * @brief Create PELEntry Interface with supported properties * * Create PELEntry Interface and update all the properties which are * supported * * @param[in] obmcLogID - The OpenBMC entry log ID * @param[in] skipIaSignal - If The InterfacesAdded signal should be * skipped after creating the interfaces. */ void createPELEntry(uint32_t obmcLogID, bool skipIaSignal = false); /** * @brief Schedules the delete of the OpenBMC event log for when * execution gets back to the event loop (uses sd_event_add_defer). * * @param[in] obmcLogID - The OpenBMC entry log ID */ void scheduleObmcLogDelete(uint32_t obmcLogID); /** * @brief SD event callback to delete an OpenBMC event log * * @param[in] obmcLogID - The OpenBMC entry log ID */ void deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID); /** * @brief Clears the deconfig flag in the PEL if necessary. * * If the passed in location code is in a callout and it's a PEL with * the BMC power/thermal or fans component ID, clear the deconfig flag. * * @param[in] locationCode - The location code to look for * @param[inout] pel - The PEL to check and modify. * @return bool - true if the flag was cleared for this PEL */ static bool clearPowerThermalDeconfigFlag(const std::string& locationCode, openpower::pels::PEL& pel); /** * @brief Called by DataInterface when the presence of hotpluggable * hardware is detected. * * Clears the 'Deconfig' flag in any PEL that has the location code * of the hardware in a callout. * * @param[in] locationCode - The location code of the hardware. */ void hardwarePresent(const std::string& locationCode); /** * @brief Reference to phosphor-logging's Manager class */ phosphor::logging::internal::Manager& _logManager; /** * @brief Handles creating event logs/PELs from within * the PEL extension code */ EventLogger _eventLogger; /** * @brief The PEL repository object */ Repository _repo; /** * @brief The PEL message registry object */ message::Registry _registry; /** * @brief The Event object this class uses */ sdeventplus::Event _event; /** * @brief The API the PEL sections use to gather data */ std::unique_ptr _dataIface; /** * @brief Object used to read from the journal */ std::unique_ptr _journal; /** * @brief The map used to keep track of PEL entry pointer associated with * event log. */ std::map> _pelEntries; /** * @brief The HostNotifier object used for telling the * host about new PELs */ std::unique_ptr _hostNotifier; /** * @brief The event source for closing a PEL file descriptor after * it has been returned from the getPEL D-Bus method. */ std::unique_ptr _fdCloserEventSource; /** * @brief The even source for removing old PELs when the repo is * running out of space to make room for new ones. */ std::unique_ptr _repoPrunerEventSource; /** * @brief The event source for deleting an OpenBMC event log. * Used when its corresponding PEL is invalid. */ std::unique_ptr _obmcLogDeleteEventSource; /** * @brief The even source for watching for deleted PEL files. */ std::unique_ptr _pelFileDeleteEventSource; /** * @brief The file descriptor returned by inotify_init1() used * for watching for deleted PEL files. */ int _pelFileDeleteFD = -1; /** * @brief The file descriptor returned by inotify_add_watch(). */ int _pelFileDeleteWatchFD = -1; }; } // namespace pels } // namespace openpower