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