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