xref: /openbmc/phosphor-logging/extensions/openpower-pels/manager.hpp (revision 6ef6b25e44e07e1af74f2578d30331922c7879ac)
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 /**
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);
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   private:
277     /**
278      * @brief Adds a received raw PEL to the PEL repository
279      *
280      * @param[in] rawPelPath - The path to the file that contains the
281      *                         raw PEL.
282      * @param[in] obmcLogID - the corresponding OpenBMC event log id
283      */
284     void addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID);
285 
286     /**
287      * @brief Creates a PEL based on the OpenBMC event log contents.
288      *
289      * @param[in] message - The event log message property
290      * @param[in] obmcLogID - the corresponding OpenBMC event log id
291      * @param[in] timestamp - The timestamp property
292      * @param[in] severity - The event log severity
293      * @param[in] additionalData - The AdditionalData property
294      * @param[in] associations - The associations property
295      * @param[in] ffdc - A vector of FFDC file information
296      */
297     void createPEL(const std::string& message, uint32_t obmcLogID,
298                    uint64_t timestamp, phosphor::logging::Entry::Level severity,
299                    const std::vector<std::string>& additionalData,
300                    const std::vector<std::string>& associations,
301                    const phosphor::logging::FFDCEntries& ffdc);
302 
303     /**
304      * @brief Schedules a close of the file descriptor to occur from
305      *        the event loop.
306      *
307      * Uses sd_event_add_defer
308      *
309      * @param[in] fd - The file descriptor to close
310      */
311     void scheduleFDClose(int fd);
312 
313     /**
314      * @brief Closes the file descriptor passed in.
315      *
316      * This is called from the event loop to close FDs returned
317      * from getPEL().
318      *
319      * @param[in] fd - The file descriptor to close
320      * @param[in] source - The event source object used
321      */
322     void closeFD(int fd, sdeventplus::source::EventBase& source);
323 
324     /**
325      * @brief Adds a PEL to the repository given its data
326      *
327      * @param[in] pelData - The PEL to add as a vector of uint8_ts
328      * @param[in] obmcLogID - the OpenBMC event log ID
329      */
330     void addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID);
331 
332     /**
333      * @brief Adds the PEL stored in the ESEL field of the AdditionalData
334      *        property of an OpenBMC event log to the repository.
335      *
336      * @param[in] esel - The ESEL AdditionalData contents
337      * @param[in] obmcLogID - The OpenBMC event log ID
338      */
339     void addESELPEL(const std::string& esel, uint32_t obmcLogID);
340 
341     /**
342      * @brief Converts the D-Bus FFDC method argument into a data
343      *        structure understood by the PEL code.
344      *
345      * @param[in] ffdc - A vector of FFDC file information
346      *
347      * @return PelFFDC - The PEL FFDC data structure
348      */
349     PelFFDC convertToPelFFDC(const phosphor::logging::FFDCEntries& ffdc);
350 
351     /**
352      * @brief Schedules a PEL repository prune to occur from
353      *        the event loop.
354      *
355      * Uses sd_event_add_defer
356      */
357     void scheduleRepoPrune();
358 
359     /**
360      * @brief Prunes old PELs out of the repository to save space.
361      *
362      * This is called from the event loop.
363      *
364      * @param[in] source - The event source object used
365      */
366     void pruneRepo(sdeventplus::source::EventBase& source);
367 
368     /**
369      * @brief Sets up an inotify watch to watch for deleted PEL
370      *        files.  Calls pelFileDeleted() when that occurs.
371      */
372     void setupPELDeleteWatch();
373 
374     /**
375      * @brief Called when the inotify watch put on the repository directory
376      *        detects a PEL file was deleted.
377      *
378      * Will tell the Repository class about the deleted PEL, and then tell
379      * the log manager class to delete the corresponding OpenBMC event log.
380      */
381     void pelFileDeleted(sdeventplus::source::IO& io, int fd, uint32_t revents);
382 
383     /**
384      * @brief Check if the input PEL should cause a quiesce of the system
385      *
386      * If QuiesceOnHwError is enabled within phosphor-settings and the PEL
387      * from the host has a severity which is not SeverityType::nonError or
388      * recovered then execute the quiesce and boot block logic.
389      *
390      * @param[in] pel - The PEL to check
391      */
392     void checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel);
393 
394     /**
395      * @brief Update eventId D-bus property for this error log
396      *
397      * Update the eventId property of D-bus with SRC and hexwords from the
398      * PEL created
399      *
400      * @param[in] pel - The PEL to use
401      */
402     void updateEventId(std::unique_ptr<openpower::pels::PEL>& pel);
403 
404     /**
405      * @brief Sets the FilePath of the specified error log entry to the PEL file
406      *        path.
407      *
408      * @param[in] obmcLogID - The OpenBMC entry log ID
409      */
410     void setEntryPath(uint32_t obmcLogID);
411 
412     /**
413      * @brief Sets the serviceProviderNotify D-bus property of PEL.
414      *
415      * @param[in] obmcLogID - The OpenBMC entry log ID
416      */
417     void setServiceProviderNotifyFlag(uint32_t obmcLogID);
418 
419     /**
420      * @brief Update resolution D-bus property for this error log
421      *
422      * Update the resolution property of D-bus with callouts extracted from PEL
423      *
424      * @param[in] pel - The PEL to use
425      *
426      * @return bool - false for Repositor::for_each().
427      */
428     bool updateResolution(const openpower::pels::PEL& pel);
429 
430     /**
431      * @brief Create PELEntry Interface with supported properties
432      *
433      * Create PELEntry Interface and update all the properties which are
434      * supported
435      *
436      * @param[in] obmcLogID - The OpenBMC entry log ID
437      * @param[in] skipIaSignal - If The InterfacesAdded signal should be
438      *                           skipped after creating the interfaces.
439      */
440     void createPELEntry(uint32_t obmcLogID, bool skipIaSignal = false);
441 
442     /**
443      * @brief Schedules the delete of the OpenBMC event log for when
444      *        execution gets back to the event loop (uses sd_event_add_defer).
445      *
446      * @param[in] obmcLogID - The OpenBMC entry log ID
447      */
448     void scheduleObmcLogDelete(uint32_t obmcLogID);
449 
450     /**
451      * @brief SD event callback to delete an OpenBMC event log
452      *
453      * @param[in] obmcLogID - The OpenBMC entry log ID
454      */
455     void deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID);
456 
457     /**
458      * @brief Reference to phosphor-logging's Manager class
459      */
460     phosphor::logging::internal::Manager& _logManager;
461 
462     /**
463      * @brief Handles creating event logs/PELs from within
464      *        the PEL extension code
465      */
466     EventLogger _eventLogger;
467 
468     /**
469      * @brief The PEL repository object
470      */
471     Repository _repo;
472 
473     /**
474      * @brief The PEL message registry object
475      */
476     message::Registry _registry;
477 
478     /**
479      * @brief The Event object this class uses
480      */
481     sdeventplus::Event _event;
482 
483     /**
484      * @brief The API the PEL sections use to gather data
485      */
486     std::unique_ptr<DataInterfaceBase> _dataIface;
487 
488     /**
489      * @brief The map used to keep track of PEL entry pointer associated with
490      *        event log.
491      */
492     std::map<std::string,
493              std::unique_ptr<
494                  sdbusplus::org::open_power::Logging::PEL::server::Entry>>
495         _pelEntries;
496 
497     /**
498      * @brief The HostNotifier object used for telling the
499      *        host about new PELs
500      */
501     std::unique_ptr<HostNotifier> _hostNotifier;
502 
503     /**
504      * @brief The event source for closing a PEL file descriptor after
505      *        it has been returned from the getPEL D-Bus method.
506      */
507     std::unique_ptr<sdeventplus::source::Defer> _fdCloserEventSource;
508 
509     /**
510      * @brief The even source for removing old PELs when the repo is
511      *        running out of space to make room for new ones.
512      */
513     std::unique_ptr<sdeventplus::source::Defer> _repoPrunerEventSource;
514 
515     /**
516      * @brief The event source for deleting an OpenBMC event log.
517      *        Used when its corresponding PEL is invalid.
518      */
519     std::unique_ptr<sdeventplus::source::Defer> _obmcLogDeleteEventSource;
520 
521     /**
522      * @brief The even source for watching for deleted PEL files.
523      */
524     std::unique_ptr<sdeventplus::source::IO> _pelFileDeleteEventSource;
525 
526     /**
527      * @brief The file descriptor returned by inotify_init1() used
528      *        for watching for deleted PEL files.
529      */
530     int _pelFileDeleteFD = -1;
531 
532     /**
533      * @brief The file descriptor returned by inotify_add_watch().
534      */
535     int _pelFileDeleteWatchFD = -1;
536 };
537 
538 } // namespace pels
539 } // namespace openpower
540