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