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