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