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