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