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