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