summaryrefslogtreecommitdiffstats
path: root/extensions/openpower-pels/repository.hpp
blob: e55808f79afb4d96d33b4039ff124d81141d0e9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#pragma once
#include "bcd_time.hpp"
#include "pel.hpp"

#include <algorithm>
#include <bitset>
#include <filesystem>
#include <map>

namespace openpower
{
namespace pels
{

/**
 * @class Repository
 *
 * The class handles saving and retrieving PELs on the BMC.
 */
class Repository
{
  public:
    /**
     * @brief Structure of commonly used PEL attributes.
     */
    struct PELAttributes
    {
        std::filesystem::path path;
        std::bitset<16> actionFlags;
        TransmissionState hostState;
        TransmissionState hmcState;

        PELAttributes() = delete;

        PELAttributes(const std::filesystem::path& p, uint16_t flags,
                      TransmissionState hostState, TransmissionState hmcState) :
            path(p),
            actionFlags(flags), hostState(hostState), hmcState(hmcState)
        {
        }
    };

    /**
     * @brief A structure that holds both the PEL and corresponding
     *        OpenBMC IDs.
     * Used for correlating the IDs with their data files for quick
     * lookup.  To find a PEL based on just one of the IDs, just use
     * the constructor that takes that ID.
     */
    struct LogID
    {
        struct Pel
        {
            uint32_t id;
            explicit Pel(uint32_t i) : id(i)
            {
            }
        };
        struct Obmc
        {
            uint32_t id;
            explicit Obmc(uint32_t i) : id(i)
            {
            }
        };

        Pel pelID;

        Obmc obmcID;

        LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc)
        {
        }

        explicit LogID(Pel id) : pelID(id), obmcID(0)
        {
        }

        explicit LogID(Obmc id) : pelID(0), obmcID(id)
        {
        }

        LogID() = delete;

        /**
         * @brief A == operator that will match on either ID
         *        being equal if the other is zero, so that
         *        one can look up a PEL with just one of the IDs.
         */
        bool operator==(const LogID& id) const
        {
            if (id.pelID.id != 0)
            {
                return id.pelID.id == pelID.id;
            }
            if (id.obmcID.id != 0)
            {
                return id.obmcID.id == obmcID.id;
            }
            return false;
        }

        bool operator<(const LogID& id) const
        {
            return pelID.id < id.pelID.id;
        }
    };

    Repository() = delete;
    ~Repository() = default;
    Repository(const Repository&) = default;
    Repository& operator=(const Repository&) = default;
    Repository(Repository&&) = default;
    Repository& operator=(Repository&&) = default;

    /**
     * @brief Constructor
     *
     * @param[in] basePath - the base filesystem path for the repository
     */
    Repository(const std::filesystem::path& basePath);

    /**
     * @brief Adds a PEL to the repository
     *
     * Throws File.Error.Open or File.Error.Write exceptions on failure
     *
     * @param[in] pel - the PEL to add
     */
    void add(std::unique_ptr<PEL>& pel);

    /**
     * @brief Removes a PEL from the repository
     *
     * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
     */
    void remove(const LogID& id);

    /**
     * @brief Generates the filename to use for the PEL ID and BCDTime.
     *
     * @param[in] pelID - the PEL ID
     * @param[in] time - the BCD time
     *
     * @return string - A filename string of <BCD_time>_<pelID>
     */
    static std::string getPELFilename(uint32_t pelID, const BCDTime& time);

    /**
     * @brief Returns true if the PEL with the specified ID is in the repo.
     *
     * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
     * @return bool - true if that PEL is present
     */
    inline bool hasPEL(const LogID& id)
    {
        return findPEL(id) != _pelAttributes.end();
    }

    /**
     * @brief Returns the PEL data based on its ID.
     *
     * If the data can't be found for that ID, then the optional object
     * will be empty.
     *
     * @param[in] id - the LogID to get the PEL for, which can be either a
     *                 PEL ID or OpenBMC log ID.
     * @return std::optional<std::vector<uint8_t>> - the PEL data
     */
    std::optional<std::vector<uint8_t>> getPELData(const LogID& id);

    /**
     * @brief Get a file descriptor to the PEL data
     *
     * @param[in] id - The ID to get the FD for
     *
     * @return std::optional<sdbusplus::message::unix_fd> -
     *         The FD, or an empty optional object.
     */
    std::optional<sdbusplus::message::unix_fd> getPELFD(const LogID& id);

    using ForEachFunc = std::function<bool(const PEL&)>;

    /**
     * @brief Run a user defined function on every PEL in the repository.
     *
     * ForEachFunc takes a const PEL reference, and should return
     * true to stop iterating and return out of for_each.
     *
     * For example, to save up to 100 IDs in the repo into a vector:
     *
     *     std::vector<uint32_t> ids;
     *     ForEachFunc f = [&ids](const PEL& pel) {
     *         ids.push_back(pel.id());
     *         return ids.size() == 100 ? true : false;
     *     };
     *
     * @param[in] func - The function to run.
     */
    void for_each(ForEachFunc func) const;

    using AddCallback = std::function<void(const PEL&)>;

    /**
     * @brief Subscribe to PELs being added to the repository.
     *
     * Every time a PEL is added to the repository, the provided
     * function will be called with the new PEL as the argument.
     *
     * The function must be of type void(const PEL&).
     *
     * @param[in] name - The subscription name
     * @param[in] func - The callback function
     */
    void subscribeToAdds(const std::string& name, AddCallback func)
    {
        if (_addSubscriptions.find(name) == _addSubscriptions.end())
        {
            _addSubscriptions.emplace(name, func);
        }
    }

    /**
     * @brief Unsubscribe from new PELs.
     *
     * @param[in] name - The subscription name
     */
    void unsubscribeFromAdds(const std::string& name)
    {
        _addSubscriptions.erase(name);
    }

    using DeleteCallback = std::function<void(uint32_t)>;

    /**
     * @brief Subscribe to PELs being deleted from the repository.
     *
     * Every time a PEL is deleted from the repository, the provided
     * function will be called with the PEL ID as the argument.
     *
     * The function must be of type void(const uint32_t).
     *
     * @param[in] name - The subscription name
     * @param[in] func - The callback function
     */
    void subscribeToDeletes(const std::string& name, DeleteCallback func)
    {
        if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
        {
            _deleteSubscriptions.emplace(name, func);
        }
    }

    /**
     * @brief Unsubscribe from deleted PELs.
     *
     * @param[in] name - The subscription name
     */
    void unsubscribeFromDeletes(const std::string& name)
    {
        _deleteSubscriptions.erase(name);
    }

    /**
     * @brief Get the PEL attributes for a PEL
     *
     * @param[in] id - The ID to find the attributes for
     *
     * @return The attributes or an empty optional if not found
     */
    std::optional<std::reference_wrapper<const PELAttributes>>
        getPELAttributes(const LogID& id) const;

    /**
     * @brief Sets the host transmission state on a PEL file
     *
     * Writes the host transmission state field in the User Header
     * section in the PEL data specified by the ID.
     *
     * @param[in] pelID - The PEL ID
     * @param[in] state - The state to write
     */
    void setPELHostTransState(uint32_t pelID, TransmissionState state);

    /**
     * @brief Sets the HMC transmission state on a PEL file
     *
     * Writes the HMC transmission state field in the User Header
     * section in the PEL data specified by the ID.
     *
     * @param[in] pelID - The PEL ID
     * @param[in] state - The state to write
     */
    void setPELHMCTransState(uint32_t pelID, TransmissionState state);

  private:
    using PELUpdateFunc = std::function<void(PEL&)>;

    /**
     * @brief Lets a function modify a PEL and saves the results
     *
     * Runs updateFunc (a void(PEL&) function) on the PEL data
     * on the file specified, and writes the results back to the file.
     *
     * @param[in] path - The file path to use
     * @param[in] updateFunc - The function to run to update the PEL.
     */
    void updatePEL(const std::filesystem::path& path, PELUpdateFunc updateFunc);

    /**
     * @brief Finds an entry in the _pelAttributes map.
     *
     * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
     *
     * @return an iterator to the entry
     */
    std::map<LogID, PELAttributes>::const_iterator
        findPEL(const LogID& id) const
    {
        return std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
                            [&id](const auto& a) { return a.first == id; });
    }

    /**
     * @brief Call any subscribed functions for new PELs
     *
     * @param[in] pel - The new PEL
     */
    void processAddCallbacks(const PEL& pel) const;

    /**
     * @brief Call any subscribed functions for deleted PELs
     *
     * @param[in] id - The ID of the deleted PEL
     */
    void processDeleteCallbacks(uint32_t id) const;

    /**
     * @brief Restores the _pelAttributes map on startup based on the existing
     *        PEL data files.
     */
    void restore();

    /**
     * @brief Stores a PEL object in the filesystem.
     *
     * @param[in] pel - The PEL to write
     * @param[in] path - The file to write to
     *
     * Throws exceptions on failures.
     */
    void write(const PEL& pel, const std::filesystem::path& path);

    /**
     * @brief The filesystem path to the PEL logs.
     */
    const std::filesystem::path _logPath;

    /**
     * @brief A map of the PEL/OBMC IDs to PEL attributes.
     */
    std::map<LogID, PELAttributes> _pelAttributes;

    /**
     * @brief Subcriptions for new PELs.
     */
    std::map<std::string, AddCallback> _addSubscriptions;

    /**
     * @brief Subscriptions for deleted PELs.
     */
    std::map<std::string, DeleteCallback> _deleteSubscriptions;
};

} // namespace pels
} // namespace openpower
OpenPOWER on IntegriCloud