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 "journal.hpp"
9 #include "log_manager.hpp"
10 #include "paths.hpp"
11 #include "pel.hpp"
12 #include "registry.hpp"
13 #include "repository.hpp"
14 
15 #include <org/open_power/Logging/PEL/Entry/server.hpp>
16 #include <org/open_power/Logging/PEL/server.hpp>
17 #include <sdbusplus/server.hpp>
18 #include <sdeventplus/event.hpp>
19 #include <sdeventplus/source/event.hpp>
20 #include <xyz/openbmc_project/Logging/Create/server.hpp>
21 
22 namespace openpower
23 {
24 namespace pels
25 {
26 
27 using PELInterface = sdbusplus::server::object_t<
28     sdbusplus::org::open_power::Logging::server::PEL>;
29 
30 /**
31  * @brief PEL manager object
32  */
33 class Manager : public PELInterface
34 {
35   public:
36     Manager() = delete;
37     Manager(const Manager&) = default;
38     Manager& operator=(const Manager&) = default;
39     Manager(Manager&&) = default;
40     Manager& operator=(Manager&&) = default;
41 
42     /**
43      * @brief constructor
44      *
45      * @param[in] logManager - internal::Manager object
46      * @param[in] dataIface - The data interface object
47      * @param[in] creatorFunc - The function that EventLogger will
48      *                          use for creating event logs
49      */
Manager(phosphor::logging::internal::Manager & logManager,std::unique_ptr<DataInterfaceBase> dataIface,EventLogger::LogFunction creatorFunc,std::unique_ptr<JournalBase> journal)50     Manager(phosphor::logging::internal::Manager& logManager,
51             std::unique_ptr<DataInterfaceBase> dataIface,
52             EventLogger::LogFunction creatorFunc,
53             std::unique_ptr<JournalBase> journal) :
54         PELInterface(logManager.getBus(), OBJ_LOGGING), _logManager(logManager),
55         _eventLogger(std::move(creatorFunc)), _repo(getPELRepoPath()),
56         _registry(getPELReadOnlyDataPath() / message::registryFileName),
57         _event(sdeventplus::Event::get_default()),
58         _dataIface(std::move(dataIface)), _journal(std::move(journal))
59     {
60         for (const auto& entry : _logManager.entries)
61         {
62             setEntryPath(entry.first);
63             setServiceProviderNotifyFlag(entry.first);
64             // Create PELEntry interface and setup properties with their values
65             createPELEntry(entry.first, true);
66         }
67 
68         setupPELDeleteWatch();
69 
70         _dataIface->subscribeToFruPresent(
71             "Manager",
72             std::bind(&Manager::hardwarePresent, this, std::placeholders::_1));
73     }
74 
75     /**
76      * @brief constructor that enables host notification
77      *
78      * @param[in] logManager - internal::Manager object
79      * @param[in] dataIface - The data interface object
80      * @param[in] creatorFunc - The function that EventLogger will
81      *                          use for creating event logs
82      * @param[in] hostIface - The hostInterface object
83      */
Manager(phosphor::logging::internal::Manager & logManager,std::unique_ptr<DataInterfaceBase> dataIface,EventLogger::LogFunction creatorFunc,std::unique_ptr<JournalBase> journal,std::unique_ptr<HostInterface> hostIface)84     Manager(phosphor::logging::internal::Manager& logManager,
85             std::unique_ptr<DataInterfaceBase> dataIface,
86             EventLogger::LogFunction creatorFunc,
87             std::unique_ptr<JournalBase> journal,
88             std::unique_ptr<HostInterface> hostIface) :
89         Manager(logManager, std::move(dataIface), std::move(creatorFunc),
90                 std::move(journal))
91     {
92         _hostNotifier = std::make_unique<HostNotifier>(
93             _repo, *(_dataIface.get()), std::move(hostIface));
94     }
95 
96     /**
97      * @brief Destructor
98      */
99     ~Manager();
100 
101     /**
102      * @brief Creates a PEL based on the OpenBMC event log contents.  If
103      *        a PEL was passed in via the RAWPEL specifier in the
104      *        additionalData parameter, use that instead.
105      *
106      * @param[in] message - the event log message property
107      * @param[in] obmcLogID - the corresponding OpenBMC event log id
108      * @param[in] timestamp - the Timestamp property
109      * @param[in] severity - the event log severity
110      * @param[in] additionalData - the AdditionalData property
111      * @param[in] associations - the Associations property
112      * @param[in] ffdc - A vector of FFDC file information
113      */
114     void create(const std::string& message, uint32_t obmcLogID,
115                 uint64_t timestamp, phosphor::logging::Entry::Level severity,
116                 const std::vector<std::string>& additionalData,
117                 const std::vector<std::string>& associations,
118                 const phosphor::logging::FFDCEntries& ffdc =
119                     phosphor::logging::FFDCEntries{});
120 
121     /**
122      * @brief Erase a PEL based on its OpenBMC event log ID
123      *
124      * @param[in] obmcLogID - the corresponding OpenBMC event log id
125      */
126     void erase(uint32_t obmcLogID);
127 
128     /**
129      * @brief Get the list of event log ids that have an associated
130      *        hardware isolation entry.
131      *
132      * @param[in] idsWithHwIsoEntry - List to store the list of log ids
133      */
134     void getLogIDWithHwIsolation(std::vector<uint32_t>& idsWithHwIsoEntry);
135 
136     /** @brief Says if an OpenBMC event log may not be manually deleted at this
137      *         time because its corresponding PEL cannot be.
138      *
139      * There are PEL retention policies that can prohibit the manual deletion
140      * of PELs (and therefore OpenBMC event logs).
141      *
142      * @param[in] obmcLogID - the OpenBMC event log ID
143      * @return bool - true if prohibited
144      */
145     bool isDeleteProhibited(uint32_t obmcLogID);
146 
147     /**
148      * @brief Return a file descriptor to the raw PEL data
149      *
150      * Throws InvalidArgument if the PEL ID isn't found,
151      * and InternalFailure if anything else fails.
152      *
153      * @param[in] pelID - The PEL ID to get the data for
154      *
155      * @return unix_fd - File descriptor to the file that contains the PEL
156      */
157     sdbusplus::message::unix_fd getPEL(uint32_t pelID) override;
158 
159     /**
160      * @brief Returns data for the PEL corresponding to an OpenBMC
161      *        event log.
162      *
163      * @param[in] obmcLogID - The OpenBMC event log ID
164      *
165      * @return vector<uint8_t> - The raw PEL data
166      */
167     std::vector<uint8_t> getPELFromOBMCID(uint32_t obmcLogID) override;
168 
169     /**
170      * @brief The D-Bus method called when a host successfully processes
171      *        a PEL.
172      *
173      * This D-Bus method is called from the PLDM daemon when they get an
174      * 'Ack PEL' PLDM message from the host, which indicates the host
175      * firmware successfully sent it to the OS and this code doesn't need
176      * to send it to the host again.
177      *
178      * @param[in] pelID - The PEL ID
179      */
180     void hostAck(uint32_t pelID) override;
181 
182     /**
183      * @brief D-Bus method called when the host rejects a PEL.
184      *
185      * This D-Bus method is called from the PLDM daemon when they get an
186      * 'Ack PEL' PLDM message from the host with a payload that says
187      * something when wrong.
188      *
189      * The choices are either:
190      *  * Host Full - The host's staging area is full - try again later
191      *  * Malrformed PEL - The host received an invalid PEL
192      *
193      * @param[in] pelID - The PEL ID
194      * @param[in] reason - One of the above two reasons
195      */
196     void hostReject(uint32_t pelID, RejectionReason reason) override;
197 
198     /**
199      * @brief D-Bus method to create a PEL/OpenBMC event log and
200      *        return the created OpenBMC and PEL log IDs.
201      *
202      * The same as the CreateWithFFDCFiles method on the
203      * xyz.openbmc_project.Logging.Create interface, except for
204      * the return values.
205      *
206      * @param[in] message - The event log message property
207      * @param[in] severity - The event log severity
208      * @param[in] additionalData - The AdditionalData property
209      * @param[in] ffdc - A vector of FFDC file information
210      */
211     std::tuple<uint32_t, uint32_t> createPELWithFFDCFiles(
212         std::string message, phosphor::logging::Entry::Level severity,
213         std::map<std::string, std::string> additionalData,
214         std::vector<std::tuple<sdbusplus::xyz::openbmc_project::Logging::
215                                    server::Create::FFDCFormat,
216                                uint8_t, uint8_t, sdbusplus::message::unix_fd>>
217             fFDC) override;
218 
219     /**
220      * @brief D-Bus method to return the PEL in JSON format
221      *
222      * @param[in] obmcLogID - The OpenBMC entry log ID
223      *
224      * @return std::string - The fully parsed PEL in JSON
225      */
226     std::string getPELJSON(uint32_t obmcLogID) override;
227 
228     /**
229      * @brief Converts the ESEL field in an OpenBMC event log to a
230      *        vector of uint8_ts that just contains the PEL data.
231      *
232      * That data string looks like: "50 48 00 ab ..."
233      *
234      * Throws an exception on any failures.
235      *
236      * @param[in] esel - The ESEL string
237      *
238      * @return std::vector<uint8_t> - The contained PEL data
239      */
240     static std::vector<uint8_t> eselToRawData(const std::string& esel);
241 
242     /**
243      * @brief Generate resolution string from the PEL
244      *
245      * @param[in] pel - The PEL to use
246      */
247     std::string getResolution(const openpower::pels::PEL& pel) const;
248 
249     /**
250      * @brief Generate event ID from the PEL
251      *
252      * @param[in] pel - The PEL to use
253      */
254     std::string getEventId(const openpower::pels::PEL& pel) const;
255 
256     /** @brief Implementation for GetPELIdFromBMCLogId
257      *
258      *  Returns the PEL Id (aka Entry ID (EID)) based on the given
259      *  BMC event log id.
260      *
261      *  @param[in] bmcLogId - The BMC event log id of the PEL to retrieve
262      *                        the PEL id.
263      *
264      *  @return uint32_t - The Id of the PEL.
265      *                     Throw "InvalidArgument" if not found.
266      */
267     uint32_t getPELIdFromBMCLogId(uint32_t bmcLogId) override;
268 
269     /** @brief Implementation for GetBMCLogIdFromPELId
270      *
271      *  Returns the BMC event log id based on the given PEL id
272      *  (aka Entry ID (EID)).
273      *
274      *  @param[in] pelId - The PEL id to retrieve the BMC event log id.
275      *
276      *  @return uint32_t - The BMC event log id of the PEL.
277      *                     Throw "InvalidArgument" if not found.
278      */
279     uint32_t getBMCLogIdFromPELId(uint32_t pelId) override;
280 
281     /**
282      * @brief Update boot progress SRC based on severity 0x51, critical error
283      *
284      * @param[in] pel - The PEL to use
285      */
286     void updateProgressSRC(std::unique_ptr<openpower::pels::PEL>& pel) const;
287 
288     /**
289      * @brief Converts unprintable characters from the passed
290      *        in string to spaces so they won't crash D-Bus when
291      *        used as a property value.
292      *
293      * @param[in] field - The field to fix
294      *
295      * @return std::string - The string without non printable characters.
296      */
297     static std::string sanitizeFieldForDBus(std::string field);
298 
299   private:
300     /**
301      * @brief Adds a received raw PEL to the PEL repository
302      *
303      * @param[in] rawPelPath - The path to the file that contains the
304      *                         raw PEL.
305      * @param[in] obmcLogID - the corresponding OpenBMC event log id
306      */
307     void addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID);
308 
309     /**
310      * @brief Creates a PEL based on the OpenBMC event log contents.
311      *
312      * @param[in] message - The event log message property
313      * @param[in] obmcLogID - the corresponding OpenBMC event log id
314      * @param[in] timestamp - The timestamp property
315      * @param[in] severity - The event log severity
316      * @param[in] additionalData - The AdditionalData property
317      * @param[in] associations - The associations property
318      * @param[in] ffdc - A vector of FFDC file information
319      */
320     void createPEL(const std::string& message, uint32_t obmcLogID,
321                    uint64_t timestamp, phosphor::logging::Entry::Level severity,
322                    const std::vector<std::string>& additionalData,
323                    const std::vector<std::string>& associations,
324                    const phosphor::logging::FFDCEntries& ffdc);
325 
326     /**
327      * @brief Schedules a close of the file descriptor to occur from
328      *        the event loop.
329      *
330      * Uses sd_event_add_defer
331      *
332      * @param[in] fd - The file descriptor to close
333      */
334     void scheduleFDClose(int fd);
335 
336     /**
337      * @brief Closes the file descriptor passed in.
338      *
339      * This is called from the event loop to close FDs returned
340      * from getPEL().
341      *
342      * @param[in] fd - The file descriptor to close
343      * @param[in] source - The event source object used
344      */
345     void closeFD(int fd, sdeventplus::source::EventBase& source);
346 
347     /**
348      * @brief Adds a PEL to the repository given its data
349      *
350      * @param[in] pelData - The PEL to add as a vector of uint8_ts
351      * @param[in] obmcLogID - the OpenBMC event log ID
352      */
353     void addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID);
354 
355     /**
356      * @brief Adds the PEL stored in the ESEL field of the AdditionalData
357      *        property of an OpenBMC event log to the repository.
358      *
359      * @param[in] esel - The ESEL AdditionalData contents
360      * @param[in] obmcLogID - The OpenBMC event log ID
361      */
362     void addESELPEL(const std::string& esel, uint32_t obmcLogID);
363 
364     /**
365      * @brief Converts the D-Bus FFDC method argument into a data
366      *        structure understood by the PEL code.
367      *
368      * @param[in] ffdc - A vector of FFDC file information
369      *
370      * @return PelFFDC - The PEL FFDC data structure
371      */
372     PelFFDC convertToPelFFDC(const phosphor::logging::FFDCEntries& ffdc);
373 
374     /**
375      * @brief Schedules a PEL repository prune to occur from
376      *        the event loop.
377      *
378      * Uses sd_event_add_defer
379      */
380     void scheduleRepoPrune();
381 
382     /**
383      * @brief Prunes old PELs out of the repository to save space.
384      *
385      * This is called from the event loop.
386      *
387      * @param[in] source - The event source object used
388      */
389     void pruneRepo(sdeventplus::source::EventBase& source);
390 
391     /**
392      * @brief Sets up an inotify watch to watch for deleted PEL
393      *        files.  Calls pelFileDeleted() when that occurs.
394      */
395     void setupPELDeleteWatch();
396 
397     /**
398      * @brief Called when the inotify watch put on the repository directory
399      *        detects a PEL file was deleted.
400      *
401      * Will tell the Repository class about the deleted PEL, and then tell
402      * the log manager class to delete the corresponding OpenBMC event log.
403      */
404     void pelFileDeleted(sdeventplus::source::IO& io, int fd, uint32_t revents);
405 
406     /**
407      * @brief Check if the input PEL should cause a quiesce of the system
408      *
409      * If QuiesceOnHwError is enabled within phosphor-settings and the PEL
410      * from the host has a severity which is not SeverityType::nonError or
411      * recovered then execute the quiesce and boot block logic.
412      *
413      * @param[in] pel - The PEL to check
414      */
415     void checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel);
416 
417     /**
418      * @brief Update eventId D-bus property for this error log
419      *
420      * Update the eventId property of D-bus with SRC and hexwords from the
421      * PEL created
422      *
423      * @param[in] pel - The PEL to use
424      */
425     void updateEventId(std::unique_ptr<openpower::pels::PEL>& pel);
426 
427     /**
428      * @brief Finds and serializes the log entry for the ID passed in.
429      * @param[in] obmcLogID - The OpenBMC event log ID
430      */
431     void serializeLogEntry(uint32_t obmcLogID);
432 
433     /**
434      * @brief Sets the FilePath of the specified error log entry to the PEL file
435      *        path.
436      *
437      * @param[in] obmcLogID - The OpenBMC entry log ID
438      */
439     void setEntryPath(uint32_t obmcLogID);
440 
441     /**
442      * @brief Sets the serviceProviderNotify D-bus property of PEL.
443      *
444      * @param[in] obmcLogID - The OpenBMC entry log ID
445      */
446     void setServiceProviderNotifyFlag(uint32_t obmcLogID);
447 
448     /**
449      * @brief Update resolution D-bus property for this error log
450      *
451      * Update the resolution property of D-bus with callouts extracted from PEL
452      *
453      * @param[in] pel - The PEL to use
454      *
455      * @return bool - false for Repositor::for_each().
456      */
457     bool updateResolution(const openpower::pels::PEL& pel);
458 
459     /**
460      * @brief Check if the D-Bus severity property for the event log
461      *        needs to be updated based on the final PEL severity,
462      *        and update the property accordingly.
463      *
464      * @param[in] pel - The PEL to operate on.
465      */
466     void updateDBusSeverity(const openpower::pels::PEL& pel);
467 
468     /**
469      * @brief Create PELEntry Interface with supported properties
470      *
471      * Create PELEntry Interface and update all the properties which are
472      * supported
473      *
474      * @param[in] obmcLogID - The OpenBMC entry log ID
475      * @param[in] skipIaSignal - If The InterfacesAdded signal should be
476      *                           skipped after creating the interfaces.
477      */
478     void createPELEntry(uint32_t obmcLogID, bool skipIaSignal = false);
479 
480     /**
481      * @brief Schedules the delete of the OpenBMC event log for when
482      *        execution gets back to the event loop (uses sd_event_add_defer).
483      *
484      * @param[in] obmcLogID - The OpenBMC entry log ID
485      */
486     void scheduleObmcLogDelete(uint32_t obmcLogID);
487 
488     /**
489      * @brief SD event callback to delete an OpenBMC event log
490      *
491      * @param[in] obmcLogID - The OpenBMC entry log ID
492      */
493     void deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID);
494 
495     /**
496      * @brief Clears the deconfig flag in the PEL if necessary.
497      *
498      * If the passed in location code is in a callout and it's a PEL with
499      * the BMC power/thermal or fans component ID, clear the deconfig flag.
500      *
501      * @param[in] locationCode - The location code to look for
502      * @param[inout] pel - The PEL to check and modify.
503      * @return bool - true if the flag was cleared for this PEL
504      */
505     static bool clearPowerThermalDeconfigFlag(const std::string& locationCode,
506                                               openpower::pels::PEL& pel);
507 
508     /**
509      * @brief Called by DataInterface when the presence of hotpluggable
510      *        hardware is detected.
511      *
512      * Clears the 'Deconfig' flag in any PEL that has the location code
513      * of the hardware in a callout.
514      *
515      * @param[in] locationCode - The location code of the hardware.
516      */
517     void hardwarePresent(const std::string& locationCode);
518 
519     /**
520      * @brief Reference to phosphor-logging's Manager class
521      */
522     phosphor::logging::internal::Manager& _logManager;
523 
524     /**
525      * @brief Handles creating event logs/PELs from within
526      *        the PEL extension code
527      */
528     EventLogger _eventLogger;
529 
530     /**
531      * @brief The PEL repository object
532      */
533     Repository _repo;
534 
535     /**
536      * @brief The PEL message registry object
537      */
538     message::Registry _registry;
539 
540     /**
541      * @brief The Event object this class uses
542      */
543     sdeventplus::Event _event;
544 
545     /**
546      * @brief The API the PEL sections use to gather data
547      */
548     std::unique_ptr<DataInterfaceBase> _dataIface;
549 
550     /**
551      * @brief Object used to read from the journal
552      */
553     std::unique_ptr<JournalBase> _journal;
554 
555     /**
556      * @brief The map used to keep track of PEL entry pointer associated with
557      *        event log.
558      */
559     std::map<std::string,
560              std::unique_ptr<
561                  sdbusplus::server::org::open_power::logging::pel::Entry>>
562         _pelEntries;
563 
564     /**
565      * @brief The HostNotifier object used for telling the
566      *        host about new PELs
567      */
568     std::unique_ptr<HostNotifier> _hostNotifier;
569 
570     /**
571      * @brief The event source for closing a PEL file descriptor after
572      *        it has been returned from the getPEL D-Bus method.
573      */
574     std::unique_ptr<sdeventplus::source::Defer> _fdCloserEventSource;
575 
576     /**
577      * @brief The even source for removing old PELs when the repo is
578      *        running out of space to make room for new ones.
579      */
580     std::unique_ptr<sdeventplus::source::Defer> _repoPrunerEventSource;
581 
582     /**
583      * @brief The event source for deleting an OpenBMC event log.
584      *        Used when its corresponding PEL is invalid.
585      */
586     std::unique_ptr<sdeventplus::source::Defer> _obmcLogDeleteEventSource;
587 
588     /**
589      * @brief The even source for watching for deleted PEL files.
590      */
591     std::unique_ptr<sdeventplus::source::IO> _pelFileDeleteEventSource;
592 
593     /**
594      * @brief The file descriptor returned by inotify_init1() used
595      *        for watching for deleted PEL files.
596      */
597     int _pelFileDeleteFD = -1;
598 
599     /**
600      * @brief The file descriptor returned by inotify_add_watch().
601      */
602     int _pelFileDeleteWatchFD = -1;
603 };
604 
605 } // namespace pels
606 } // namespace openpower
607