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