xref: /openbmc/phosphor-logging/extensions/openpower-pels/manager.hpp (revision 3387eac922ad16186eabbc126edd6719ef7cbb9b)
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 Finds and serializes the log entry for the ID passed in.
425      * @param[in] obmcLogID - The OpenBMC event log ID
426      */
427     void serializeLogEntry(uint32_t obmcLogID);
428 
429     /**
430      * @brief Sets the FilePath of the specified error log entry to the PEL file
431      *        path.
432      *
433      * @param[in] obmcLogID - The OpenBMC entry log ID
434      */
435     void setEntryPath(uint32_t obmcLogID);
436 
437     /**
438      * @brief Sets the serviceProviderNotify D-bus property of PEL.
439      *
440      * @param[in] obmcLogID - The OpenBMC entry log ID
441      */
442     void setServiceProviderNotifyFlag(uint32_t obmcLogID);
443 
444     /**
445      * @brief Update resolution D-bus property for this error log
446      *
447      * Update the resolution property of D-bus with callouts extracted from PEL
448      *
449      * @param[in] pel - The PEL to use
450      *
451      * @return bool - false for Repositor::for_each().
452      */
453     bool updateResolution(const openpower::pels::PEL& pel);
454 
455     /**
456      * @brief Check if the D-Bus severity property for the event log
457      *        needs to be updated based on the final PEL severity,
458      *        and update the property accordingly.
459      *
460      * @param[in] pel - The PEL to operate on.
461      */
462     void updateDBusSeverity(const openpower::pels::PEL& pel);
463 
464     /**
465      * @brief Create PELEntry Interface with supported properties
466      *
467      * Create PELEntry Interface and update all the properties which are
468      * supported
469      *
470      * @param[in] obmcLogID - The OpenBMC entry log ID
471      * @param[in] skipIaSignal - If The InterfacesAdded signal should be
472      *                           skipped after creating the interfaces.
473      */
474     void createPELEntry(uint32_t obmcLogID, bool skipIaSignal = false);
475 
476     /**
477      * @brief Schedules the delete of the OpenBMC event log for when
478      *        execution gets back to the event loop (uses sd_event_add_defer).
479      *
480      * @param[in] obmcLogID - The OpenBMC entry log ID
481      */
482     void scheduleObmcLogDelete(uint32_t obmcLogID);
483 
484     /**
485      * @brief SD event callback to delete an OpenBMC event log
486      *
487      * @param[in] obmcLogID - The OpenBMC entry log ID
488      */
489     void deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID);
490 
491     /**
492      * @brief Clears the deconfig flag in the PEL if necessary.
493      *
494      * If the passed in location code is in a callout and it's a PEL with
495      * the BMC power/thermal or fans component ID, clear the deconfig flag.
496      *
497      * @param[in] locationCode - The location code to look for
498      * @param[inout] pel - The PEL to check and modify.
499      * @return bool - true if the flag was cleared for this PEL
500      */
501     static bool clearPowerThermalDeconfigFlag(const std::string& locationCode,
502                                               openpower::pels::PEL& pel);
503 
504     /**
505      * @brief Called by DataInterface when the presence of hotpluggable
506      *        hardware is detected.
507      *
508      * Clears the 'Deconfig' flag in any PEL that has the location code
509      * of the hardware in a callout.
510      *
511      * @param[in] locationCode - The location code of the hardware.
512      */
513     void hardwarePresent(const std::string& locationCode);
514 
515     /**
516      * @brief Reference to phosphor-logging's Manager class
517      */
518     phosphor::logging::internal::Manager& _logManager;
519 
520     /**
521      * @brief Handles creating event logs/PELs from within
522      *        the PEL extension code
523      */
524     EventLogger _eventLogger;
525 
526     /**
527      * @brief The PEL repository object
528      */
529     Repository _repo;
530 
531     /**
532      * @brief The PEL message registry object
533      */
534     message::Registry _registry;
535 
536     /**
537      * @brief The Event object this class uses
538      */
539     sdeventplus::Event _event;
540 
541     /**
542      * @brief The API the PEL sections use to gather data
543      */
544     std::unique_ptr<DataInterfaceBase> _dataIface;
545 
546     /**
547      * @brief Object used to read from the journal
548      */
549     std::unique_ptr<JournalBase> _journal;
550 
551     /**
552      * @brief The map used to keep track of PEL entry pointer associated with
553      *        event log.
554      */
555     std::map<std::string,
556              std::unique_ptr<
557                  sdbusplus::org::open_power::Logging::PEL::server::Entry>>
558         _pelEntries;
559 
560     /**
561      * @brief The HostNotifier object used for telling the
562      *        host about new PELs
563      */
564     std::unique_ptr<HostNotifier> _hostNotifier;
565 
566     /**
567      * @brief The event source for closing a PEL file descriptor after
568      *        it has been returned from the getPEL D-Bus method.
569      */
570     std::unique_ptr<sdeventplus::source::Defer> _fdCloserEventSource;
571 
572     /**
573      * @brief The even source for removing old PELs when the repo is
574      *        running out of space to make room for new ones.
575      */
576     std::unique_ptr<sdeventplus::source::Defer> _repoPrunerEventSource;
577 
578     /**
579      * @brief The event source for deleting an OpenBMC event log.
580      *        Used when its corresponding PEL is invalid.
581      */
582     std::unique_ptr<sdeventplus::source::Defer> _obmcLogDeleteEventSource;
583 
584     /**
585      * @brief The even source for watching for deleted PEL files.
586      */
587     std::unique_ptr<sdeventplus::source::IO> _pelFileDeleteEventSource;
588 
589     /**
590      * @brief The file descriptor returned by inotify_init1() used
591      *        for watching for deleted PEL files.
592      */
593     int _pelFileDeleteFD = -1;
594 
595     /**
596      * @brief The file descriptor returned by inotify_add_watch().
597      */
598     int _pelFileDeleteWatchFD = -1;
599 };
600 
601 } // namespace pels
602 } // namespace openpower
603