1 #pragma once 2 3 #include "config.h" 4 5 #include "data_interface.hpp" 6 #include "event_logger.hpp" 7 #include "host_notifier.hpp" 8 #include "journal.hpp" 9 #include "log_manager.hpp" 10 #include "paths.hpp" 11 #include "pel.hpp" 12 #include "registry.hpp" 13 #include "repository.hpp" 14 15 #include <org/open_power/Logging/PEL/Entry/server.hpp> 16 #include <org/open_power/Logging/PEL/server.hpp> 17 #include <sdbusplus/server.hpp> 18 #include <sdeventplus/event.hpp> 19 #include <sdeventplus/source/event.hpp> 20 #include <xyz/openbmc_project/Logging/Create/server.hpp> 21 22 namespace openpower 23 { 24 namespace pels 25 { 26 27 using PELInterface = sdbusplus::server::object_t< 28 sdbusplus::org::open_power::Logging::server::PEL>; 29 30 /** 31 * @brief PEL manager object 32 */ 33 class Manager : public PELInterface 34 { 35 public: 36 Manager() = delete; 37 Manager(const Manager&) = default; 38 Manager& operator=(const Manager&) = default; 39 Manager(Manager&&) = default; 40 Manager& operator=(Manager&&) = default; 41 42 /** 43 * @brief constructor 44 * 45 * @param[in] logManager - internal::Manager object 46 * @param[in] dataIface - The data interface object 47 * @param[in] creatorFunc - The function that EventLogger will 48 * use for creating event logs 49 */ 50 Manager(phosphor::logging::internal::Manager& logManager, 51 std::unique_ptr<DataInterfaceBase> dataIface, 52 EventLogger::LogFunction creatorFunc, 53 std::unique_ptr<JournalBase> journal) : 54 PELInterface(logManager.getBus(), OBJ_LOGGING), 55 _logManager(logManager), _eventLogger(std::move(creatorFunc)), 56 _repo(getPELRepoPath()), 57 _registry(getPELReadOnlyDataPath() / message::registryFileName), 58 _event(sdeventplus::Event::get_default()), 59 _dataIface(std::move(dataIface)), _journal(std::move(journal)) 60 { 61 for (const auto& entry : _logManager.entries) 62 { 63 setEntryPath(entry.first); 64 setServiceProviderNotifyFlag(entry.first); 65 // Create PELEntry interface and setup properties with their values 66 createPELEntry(entry.first, true); 67 } 68 69 _repo.for_each( 70 std::bind(&Manager::updateResolution, this, std::placeholders::_1)); 71 72 setupPELDeleteWatch(); 73 74 _dataIface->subscribeToFruPresent( 75 "Manager", 76 std::bind(&Manager::hardwarePresent, this, std::placeholders::_1)); 77 } 78 79 /** 80 * @brief constructor that enables host notification 81 * 82 * @param[in] logManager - internal::Manager object 83 * @param[in] dataIface - The data interface object 84 * @param[in] creatorFunc - The function that EventLogger will 85 * use for creating event logs 86 * @param[in] hostIface - The hostInterface object 87 */ 88 Manager(phosphor::logging::internal::Manager& logManager, 89 std::unique_ptr<DataInterfaceBase> dataIface, 90 EventLogger::LogFunction creatorFunc, 91 std::unique_ptr<JournalBase> journal, 92 std::unique_ptr<HostInterface> hostIface) : 93 Manager(logManager, std::move(dataIface), std::move(creatorFunc), 94 std::move(journal)) 95 { 96 _hostNotifier = std::make_unique<HostNotifier>( 97 _repo, *(_dataIface.get()), std::move(hostIface)); 98 } 99 100 /** 101 * @brief Destructor 102 */ 103 ~Manager(); 104 105 /** 106 * @brief Creates a PEL based on the OpenBMC event log contents. If 107 * a PEL was passed in via the RAWPEL specifier in the 108 * additionalData parameter, use that instead. 109 * 110 * @param[in] message - the event log message property 111 * @param[in] obmcLogID - the corresponding OpenBMC event log id 112 * @param[in] timestamp - the Timestamp property 113 * @param[in] severity - the event log severity 114 * @param[in] additionalData - the AdditionalData property 115 * @param[in] associations - the Associations property 116 * @param[in] ffdc - A vector of FFDC file information 117 */ 118 void create(const std::string& message, uint32_t obmcLogID, 119 uint64_t timestamp, phosphor::logging::Entry::Level severity, 120 const std::vector<std::string>& additionalData, 121 const std::vector<std::string>& associations, 122 const phosphor::logging::FFDCEntries& ffdc = 123 phosphor::logging::FFDCEntries{}); 124 125 /** 126 * @brief Erase a PEL based on its OpenBMC event log ID 127 * 128 * @param[in] obmcLogID - the corresponding OpenBMC event log id 129 */ 130 void erase(uint32_t obmcLogID); 131 132 /** @brief Says if an OpenBMC event log may not be manually deleted at this 133 * time because its corresponding PEL cannot be. 134 * 135 * There are PEL retention policies that can prohibit the manual deletion 136 * of PELs (and therefore OpenBMC event logs). 137 * 138 * @param[in] obmcLogID - the OpenBMC event log ID 139 * @return bool - true if prohibited 140 */ 141 bool isDeleteProhibited(uint32_t obmcLogID); 142 143 /** 144 * @brief Return a file descriptor to the raw PEL data 145 * 146 * Throws InvalidArgument if the PEL ID isn't found, 147 * and InternalFailure if anything else fails. 148 * 149 * @param[in] pelID - The PEL ID to get the data for 150 * 151 * @return unix_fd - File descriptor to the file that contains the PEL 152 */ 153 sdbusplus::message::unix_fd getPEL(uint32_t pelID) override; 154 155 /** 156 * @brief Returns data for the PEL corresponding to an OpenBMC 157 * event log. 158 * 159 * @param[in] obmcLogID - The OpenBMC event log ID 160 * 161 * @return vector<uint8_t> - The raw PEL data 162 */ 163 std::vector<uint8_t> getPELFromOBMCID(uint32_t obmcLogID) override; 164 165 /** 166 * @brief The D-Bus method called when a host successfully processes 167 * a PEL. 168 * 169 * This D-Bus method is called from the PLDM daemon when they get an 170 * 'Ack PEL' PLDM message from the host, which indicates the host 171 * firmware successfully sent it to the OS and this code doesn't need 172 * to send it to the host again. 173 * 174 * @param[in] pelID - The PEL ID 175 */ 176 void hostAck(uint32_t pelID) override; 177 178 /** 179 * @brief D-Bus method called when the host rejects a PEL. 180 * 181 * This D-Bus method is called from the PLDM daemon when they get an 182 * 'Ack PEL' PLDM message from the host with a payload that says 183 * something when wrong. 184 * 185 * The choices are either: 186 * * Host Full - The host's staging area is full - try again later 187 * * Malrformed PEL - The host received an invalid PEL 188 * 189 * @param[in] pelID - The PEL ID 190 * @param[in] reason - One of the above two reasons 191 */ 192 void hostReject(uint32_t pelID, RejectionReason reason) override; 193 194 /** 195 * @brief D-Bus method to create a PEL/OpenBMC event log and 196 * return the created OpenBMC and PEL log IDs. 197 * 198 * The same as the CreateWithFFDCFiles method on the 199 * xyz.openbmc_project.Logging.Create interface, except for 200 * the return values. 201 * 202 * @param[in] message - The event log message property 203 * @param[in] severity - The event log severity 204 * @param[in] additionalData - The AdditionalData property 205 * @param[in] ffdc - A vector of FFDC file information 206 */ 207 std::tuple<uint32_t, uint32_t> createPELWithFFDCFiles( 208 std::string message, phosphor::logging::Entry::Level severity, 209 std::map<std::string, std::string> additionalData, 210 std::vector<std::tuple<sdbusplus::xyz::openbmc_project::Logging:: 211 server::Create::FFDCFormat, 212 uint8_t, uint8_t, sdbusplus::message::unix_fd>> 213 fFDC) override; 214 215 /** 216 * @brief D-Bus method to return the PEL in JSON format 217 * 218 * @param[in] obmcLogID - The OpenBMC entry log ID 219 * 220 * @return std::string - The fully parsed PEL in JSON 221 */ 222 std::string getPELJSON(uint32_t obmcLogID) override; 223 224 /** 225 * @brief Converts the ESEL field in an OpenBMC event log to a 226 * vector of uint8_ts that just contains the PEL data. 227 * 228 * That data string looks like: "50 48 00 ab ..." 229 * 230 * Throws an exception on any failures. 231 * 232 * @param[in] esel - The ESEL string 233 * 234 * @return std::vector<uint8_t> - The contained PEL data 235 */ 236 static std::vector<uint8_t> eselToRawData(const std::string& esel); 237 238 /** 239 * @brief Generate resolution string from the PEL 240 * 241 * @param[in] pel - The PEL to use 242 */ 243 std::string getResolution(const openpower::pels::PEL& pel) const; 244 245 /** 246 * @brief Generate event ID from the PEL 247 * 248 * @param[in] pel - The PEL to use 249 */ 250 std::string getEventId(const openpower::pels::PEL& pel) const; 251 252 /** @brief Implementation for GetPELIdFromBMCLogId 253 * 254 * Returns the PEL Id (aka Entry ID (EID)) based on the given 255 * BMC event log id. 256 * 257 * @param[in] bmcLogId - The BMC event log id of the PEL to retrieve 258 * the PEL id. 259 * 260 * @return uint32_t - The Id of the PEL. 261 * Throw "InvalidArgument" if not found. 262 */ 263 uint32_t getPELIdFromBMCLogId(uint32_t bmcLogId) override; 264 265 /** @brief Implementation for GetBMCLogIdFromPELId 266 * 267 * Returns the BMC event log id based on the given PEL id 268 * (aka Entry ID (EID)). 269 * 270 * @param[in] pelId - The PEL id to retrieve the BMC event log id. 271 * 272 * @return uint32_t - The BMC event log id of the PEL. 273 * Throw "InvalidArgument" if not found. 274 */ 275 uint32_t getBMCLogIdFromPELId(uint32_t pelId) override; 276 277 /** 278 * @brief Update boot progress SRC based on severity 0x51, critical error 279 * 280 * @param[in] pel - The PEL to use 281 */ 282 void updateProgressSRC(std::unique_ptr<openpower::pels::PEL>& pel) const; 283 284 /** 285 * @brief Converts unprintable characters from the passed 286 * in string to spaces so they won't crash D-Bus when 287 * used as a property value. 288 * 289 * @param[in] field - The field to fix 290 * 291 * @return std::string - The string without non printable characters. 292 */ 293 static std::string sanitizeFieldForDBus(std::string field); 294 295 private: 296 /** 297 * @brief Adds a received raw PEL to the PEL repository 298 * 299 * @param[in] rawPelPath - The path to the file that contains the 300 * raw PEL. 301 * @param[in] obmcLogID - the corresponding OpenBMC event log id 302 */ 303 void addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID); 304 305 /** 306 * @brief Creates a PEL based on the OpenBMC event log contents. 307 * 308 * @param[in] message - The event log message property 309 * @param[in] obmcLogID - the corresponding OpenBMC event log id 310 * @param[in] timestamp - The timestamp property 311 * @param[in] severity - The event log severity 312 * @param[in] additionalData - The AdditionalData property 313 * @param[in] associations - The associations property 314 * @param[in] ffdc - A vector of FFDC file information 315 */ 316 void createPEL(const std::string& message, uint32_t obmcLogID, 317 uint64_t timestamp, phosphor::logging::Entry::Level severity, 318 const std::vector<std::string>& additionalData, 319 const std::vector<std::string>& associations, 320 const phosphor::logging::FFDCEntries& ffdc); 321 322 /** 323 * @brief Schedules a close of the file descriptor to occur from 324 * the event loop. 325 * 326 * Uses sd_event_add_defer 327 * 328 * @param[in] fd - The file descriptor to close 329 */ 330 void scheduleFDClose(int fd); 331 332 /** 333 * @brief Closes the file descriptor passed in. 334 * 335 * This is called from the event loop to close FDs returned 336 * from getPEL(). 337 * 338 * @param[in] fd - The file descriptor to close 339 * @param[in] source - The event source object used 340 */ 341 void closeFD(int fd, sdeventplus::source::EventBase& source); 342 343 /** 344 * @brief Adds a PEL to the repository given its data 345 * 346 * @param[in] pelData - The PEL to add as a vector of uint8_ts 347 * @param[in] obmcLogID - the OpenBMC event log ID 348 */ 349 void addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID); 350 351 /** 352 * @brief Adds the PEL stored in the ESEL field of the AdditionalData 353 * property of an OpenBMC event log to the repository. 354 * 355 * @param[in] esel - The ESEL AdditionalData contents 356 * @param[in] obmcLogID - The OpenBMC event log ID 357 */ 358 void addESELPEL(const std::string& esel, uint32_t obmcLogID); 359 360 /** 361 * @brief Converts the D-Bus FFDC method argument into a data 362 * structure understood by the PEL code. 363 * 364 * @param[in] ffdc - A vector of FFDC file information 365 * 366 * @return PelFFDC - The PEL FFDC data structure 367 */ 368 PelFFDC convertToPelFFDC(const phosphor::logging::FFDCEntries& ffdc); 369 370 /** 371 * @brief Schedules a PEL repository prune to occur from 372 * the event loop. 373 * 374 * Uses sd_event_add_defer 375 */ 376 void scheduleRepoPrune(); 377 378 /** 379 * @brief Prunes old PELs out of the repository to save space. 380 * 381 * This is called from the event loop. 382 * 383 * @param[in] source - The event source object used 384 */ 385 void pruneRepo(sdeventplus::source::EventBase& source); 386 387 /** 388 * @brief Sets up an inotify watch to watch for deleted PEL 389 * files. Calls pelFileDeleted() when that occurs. 390 */ 391 void setupPELDeleteWatch(); 392 393 /** 394 * @brief Called when the inotify watch put on the repository directory 395 * detects a PEL file was deleted. 396 * 397 * Will tell the Repository class about the deleted PEL, and then tell 398 * the log manager class to delete the corresponding OpenBMC event log. 399 */ 400 void pelFileDeleted(sdeventplus::source::IO& io, int fd, uint32_t revents); 401 402 /** 403 * @brief Check if the input PEL should cause a quiesce of the system 404 * 405 * If QuiesceOnHwError is enabled within phosphor-settings and the PEL 406 * from the host has a severity which is not SeverityType::nonError or 407 * recovered then execute the quiesce and boot block logic. 408 * 409 * @param[in] pel - The PEL to check 410 */ 411 void checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel); 412 413 /** 414 * @brief Update eventId D-bus property for this error log 415 * 416 * Update the eventId property of D-bus with SRC and hexwords from the 417 * PEL created 418 * 419 * @param[in] pel - The PEL to use 420 */ 421 void updateEventId(std::unique_ptr<openpower::pels::PEL>& pel); 422 423 /** 424 * @brief Finds and serializes the log entry for the ID passed in. 425 * @param[in] obmcLogID - The OpenBMC event log ID 426 */ 427 void serializeLogEntry(uint32_t obmcLogID); 428 429 /** 430 * @brief Sets the FilePath of the specified error log entry to the PEL file 431 * path. 432 * 433 * @param[in] obmcLogID - The OpenBMC entry log ID 434 */ 435 void setEntryPath(uint32_t obmcLogID); 436 437 /** 438 * @brief Sets the serviceProviderNotify D-bus property of PEL. 439 * 440 * @param[in] obmcLogID - The OpenBMC entry log ID 441 */ 442 void setServiceProviderNotifyFlag(uint32_t obmcLogID); 443 444 /** 445 * @brief Update resolution D-bus property for this error log 446 * 447 * Update the resolution property of D-bus with callouts extracted from PEL 448 * 449 * @param[in] pel - The PEL to use 450 * 451 * @return bool - false for Repositor::for_each(). 452 */ 453 bool updateResolution(const openpower::pels::PEL& pel); 454 455 /** 456 * @brief Check if the D-Bus severity property for the event log 457 * needs to be updated based on the final PEL severity, 458 * and update the property accordingly. 459 * 460 * @param[in] pel - The PEL to operate on. 461 */ 462 void updateDBusSeverity(const openpower::pels::PEL& pel); 463 464 /** 465 * @brief Create PELEntry Interface with supported properties 466 * 467 * Create PELEntry Interface and update all the properties which are 468 * supported 469 * 470 * @param[in] obmcLogID - The OpenBMC entry log ID 471 * @param[in] skipIaSignal - If The InterfacesAdded signal should be 472 * skipped after creating the interfaces. 473 */ 474 void createPELEntry(uint32_t obmcLogID, bool skipIaSignal = false); 475 476 /** 477 * @brief Schedules the delete of the OpenBMC event log for when 478 * execution gets back to the event loop (uses sd_event_add_defer). 479 * 480 * @param[in] obmcLogID - The OpenBMC entry log ID 481 */ 482 void scheduleObmcLogDelete(uint32_t obmcLogID); 483 484 /** 485 * @brief SD event callback to delete an OpenBMC event log 486 * 487 * @param[in] obmcLogID - The OpenBMC entry log ID 488 */ 489 void deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID); 490 491 /** 492 * @brief Clears the deconfig flag in the PEL if necessary. 493 * 494 * If the passed in location code is in a callout and it's a PEL with 495 * the BMC power/thermal or fans component ID, clear the deconfig flag. 496 * 497 * @param[in] locationCode - The location code to look for 498 * @param[inout] pel - The PEL to check and modify. 499 * @return bool - true if the flag was cleared for this PEL 500 */ 501 static bool clearPowerThermalDeconfigFlag(const std::string& locationCode, 502 openpower::pels::PEL& pel); 503 504 /** 505 * @brief Called by DataInterface when the presence of hotpluggable 506 * hardware is detected. 507 * 508 * Clears the 'Deconfig' flag in any PEL that has the location code 509 * of the hardware in a callout. 510 * 511 * @param[in] locationCode - The location code of the hardware. 512 */ 513 void hardwarePresent(const std::string& locationCode); 514 515 /** 516 * @brief Reference to phosphor-logging's Manager class 517 */ 518 phosphor::logging::internal::Manager& _logManager; 519 520 /** 521 * @brief Handles creating event logs/PELs from within 522 * the PEL extension code 523 */ 524 EventLogger _eventLogger; 525 526 /** 527 * @brief The PEL repository object 528 */ 529 Repository _repo; 530 531 /** 532 * @brief The PEL message registry object 533 */ 534 message::Registry _registry; 535 536 /** 537 * @brief The Event object this class uses 538 */ 539 sdeventplus::Event _event; 540 541 /** 542 * @brief The API the PEL sections use to gather data 543 */ 544 std::unique_ptr<DataInterfaceBase> _dataIface; 545 546 /** 547 * @brief Object used to read from the journal 548 */ 549 std::unique_ptr<JournalBase> _journal; 550 551 /** 552 * @brief The map used to keep track of PEL entry pointer associated with 553 * event log. 554 */ 555 std::map<std::string, 556 std::unique_ptr< 557 sdbusplus::org::open_power::Logging::PEL::server::Entry>> 558 _pelEntries; 559 560 /** 561 * @brief The HostNotifier object used for telling the 562 * host about new PELs 563 */ 564 std::unique_ptr<HostNotifier> _hostNotifier; 565 566 /** 567 * @brief The event source for closing a PEL file descriptor after 568 * it has been returned from the getPEL D-Bus method. 569 */ 570 std::unique_ptr<sdeventplus::source::Defer> _fdCloserEventSource; 571 572 /** 573 * @brief The even source for removing old PELs when the repo is 574 * running out of space to make room for new ones. 575 */ 576 std::unique_ptr<sdeventplus::source::Defer> _repoPrunerEventSource; 577 578 /** 579 * @brief The event source for deleting an OpenBMC event log. 580 * Used when its corresponding PEL is invalid. 581 */ 582 std::unique_ptr<sdeventplus::source::Defer> _obmcLogDeleteEventSource; 583 584 /** 585 * @brief The even source for watching for deleted PEL files. 586 */ 587 std::unique_ptr<sdeventplus::source::IO> _pelFileDeleteEventSource; 588 589 /** 590 * @brief The file descriptor returned by inotify_init1() used 591 * for watching for deleted PEL files. 592 */ 593 int _pelFileDeleteFD = -1; 594 595 /** 596 * @brief The file descriptor returned by inotify_add_watch(). 597 */ 598 int _pelFileDeleteWatchFD = -1; 599 }; 600 601 } // namespace pels 602 } // namespace openpower 603