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