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