blob: e9b6a27e9e5a79cc226aa6e58f8f4162d9f02fa3 [file] [log] [blame]
Matt Spinler89fa0822019-07-17 13:54:30 -05001#pragma once
2#include "bcd_time.hpp"
Matt Spinler8d5f3a22020-07-07 10:30:33 -05003#include "paths.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -05004#include "pel.hpp"
5
6#include <algorithm>
Matt Spinler0ff00482019-11-06 16:19:46 -06007#include <bitset>
Matt Spinler89fa0822019-07-17 13:54:30 -05008#include <filesystem>
Matt Spinler475e5742019-07-18 16:09:49 -05009#include <map>
Matt Spinler89fa0822019-07-17 13:54:30 -050010
11namespace openpower
12{
13namespace pels
14{
15
16/**
17 * @class Repository
18 *
19 * The class handles saving and retrieving PELs on the BMC.
20 */
21class Repository
22{
23 public:
Matt Spinler475e5742019-07-18 16:09:49 -050024 /**
Matt Spinler0ff00482019-11-06 16:19:46 -060025 * @brief Structure of commonly used PEL attributes.
26 */
27 struct PELAttributes
28 {
29 std::filesystem::path path;
Matt Spinlerdd325c32020-07-07 11:01:54 -050030 size_t sizeOnDisk;
31 uint8_t creator;
32 uint8_t severity;
Matt Spinler0ff00482019-11-06 16:19:46 -060033 std::bitset<16> actionFlags;
Matt Spinler346f99a2019-11-21 13:06:35 -060034 TransmissionState hostState;
35 TransmissionState hmcState;
Matt Spinler0ff00482019-11-06 16:19:46 -060036
37 PELAttributes() = delete;
38
Matt Spinlerdd325c32020-07-07 11:01:54 -050039 PELAttributes(const std::filesystem::path& p, size_t size,
40 uint8_t creator, uint8_t sev, uint16_t flags,
Matt Spinler346f99a2019-11-21 13:06:35 -060041 TransmissionState hostState, TransmissionState hmcState) :
42 path(p),
Matt Spinlerdd325c32020-07-07 11:01:54 -050043 sizeOnDisk(size), creator(creator), severity(sev),
Matt Spinler346f99a2019-11-21 13:06:35 -060044 actionFlags(flags), hostState(hostState), hmcState(hmcState)
Matt Spinler0ff00482019-11-06 16:19:46 -060045 {
46 }
47 };
48
49 /**
Matt Spinler475e5742019-07-18 16:09:49 -050050 * @brief A structure that holds both the PEL and corresponding
51 * OpenBMC IDs.
52 * Used for correlating the IDs with their data files for quick
53 * lookup. To find a PEL based on just one of the IDs, just use
54 * the constructor that takes that ID.
55 */
56 struct LogID
57 {
58 struct Pel
59 {
60 uint32_t id;
61 explicit Pel(uint32_t i) : id(i)
62 {
63 }
64 };
65 struct Obmc
66 {
67 uint32_t id;
68 explicit Obmc(uint32_t i) : id(i)
69 {
70 }
71 };
72
73 Pel pelID;
74
75 Obmc obmcID;
76
77 LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc)
78 {
79 }
80
81 explicit LogID(Pel id) : pelID(id), obmcID(0)
82 {
83 }
84
85 explicit LogID(Obmc id) : pelID(0), obmcID(id)
86 {
87 }
88
89 LogID() = delete;
90
91 /**
92 * @brief A == operator that will match on either ID
93 * being equal if the other is zero, so that
94 * one can look up a PEL with just one of the IDs.
95 */
96 bool operator==(const LogID& id) const
97 {
98 if (id.pelID.id != 0)
99 {
100 return id.pelID.id == pelID.id;
101 }
102 if (id.obmcID.id != 0)
103 {
104 return id.obmcID.id == obmcID.id;
105 }
106 return false;
107 }
108
109 bool operator<(const LogID& id) const
110 {
111 return pelID.id < id.pelID.id;
112 }
113 };
114
Matt Spinlerb188f782020-07-07 11:18:12 -0500115 /**
116 * @brief A structure for keeping a breakdown of the sizes of PELs
117 * of different types in the repository.
118 */
119 struct SizeStats
120 {
121 uint64_t total;
122 uint64_t bmc;
123 uint64_t nonBMC;
124 uint64_t bmcServiceable;
125 uint64_t bmcInfo;
126 uint64_t nonBMCServiceable;
127 uint64_t nonBMCInfo;
128
129 SizeStats() :
130 total(0), bmc(0), nonBMC(0), bmcServiceable(0), bmcInfo(0),
131 nonBMCServiceable(0), nonBMCInfo(0)
132 {
133 }
134 };
135
Matt Spinler89fa0822019-07-17 13:54:30 -0500136 Repository() = delete;
137 ~Repository() = default;
138 Repository(const Repository&) = default;
139 Repository& operator=(const Repository&) = default;
140 Repository(Repository&&) = default;
141 Repository& operator=(Repository&&) = default;
142
143 /**
144 * @brief Constructor
145 *
146 * @param[in] basePath - the base filesystem path for the repository
147 */
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500148 Repository(const std::filesystem::path& basePath) :
149 Repository(basePath, getPELRepoSize(), getMaxNumPELs())
150 {
151 }
152
153 /**
154 * @brief Constructor that takes the repository size
155 *
156 * @param[in] basePath - the base filesystem path for the repository
157 * @param[in] repoSize - The maximum amount of space to use for PELs,
158 * in bytes
159 * @param[in] maxNumPELs - The maximum number of PELs to allow
160 */
161 Repository(const std::filesystem::path& basePath, size_t repoSize,
162 size_t maxNumPELs);
Matt Spinler89fa0822019-07-17 13:54:30 -0500163
164 /**
165 * @brief Adds a PEL to the repository
166 *
167 * Throws File.Error.Open or File.Error.Write exceptions on failure
168 *
169 * @param[in] pel - the PEL to add
170 */
171 void add(std::unique_ptr<PEL>& pel);
172
173 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500174 * @brief Removes a PEL from the repository
175 *
176 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
177 */
178 void remove(const LogID& id);
179
180 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500181 * @brief Generates the filename to use for the PEL ID and BCDTime.
182 *
183 * @param[in] pelID - the PEL ID
184 * @param[in] time - the BCD time
185 *
186 * @return string - A filename string of <BCD_time>_<pelID>
187 */
188 static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
189
Matt Spinler475e5742019-07-18 16:09:49 -0500190 /**
191 * @brief Returns true if the PEL with the specified ID is in the repo.
192 *
193 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
194 * @return bool - true if that PEL is present
195 */
196 inline bool hasPEL(const LogID& id)
197 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600198 return findPEL(id) != _pelAttributes.end();
Matt Spinler475e5742019-07-18 16:09:49 -0500199 }
200
Matt Spinler2813f362019-07-19 12:45:28 -0500201 /**
202 * @brief Returns the PEL data based on its ID.
203 *
204 * If the data can't be found for that ID, then the optional object
205 * will be empty.
206 *
207 * @param[in] id - the LogID to get the PEL for, which can be either a
208 * PEL ID or OpenBMC log ID.
209 * @return std::optional<std::vector<uint8_t>> - the PEL data
210 */
211 std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
212
Matt Spinler6d512242019-12-09 13:44:17 -0600213 /**
214 * @brief Get a file descriptor to the PEL data
215 *
216 * @param[in] id - The ID to get the FD for
217 *
218 * @return std::optional<sdbusplus::message::unix_fd> -
219 * The FD, or an empty optional object.
220 */
221 std::optional<sdbusplus::message::unix_fd> getPELFD(const LogID& id);
222
Matt Spinler1ea78802019-11-01 13:04:59 -0500223 using ForEachFunc = std::function<bool(const PEL&)>;
224
225 /**
226 * @brief Run a user defined function on every PEL in the repository.
227 *
228 * ForEachFunc takes a const PEL reference, and should return
229 * true to stop iterating and return out of for_each.
230 *
231 * For example, to save up to 100 IDs in the repo into a vector:
232 *
233 * std::vector<uint32_t> ids;
234 * ForEachFunc f = [&ids](const PEL& pel) {
235 * ids.push_back(pel.id());
236 * return ids.size() == 100 ? true : false;
237 * };
238 *
239 * @param[in] func - The function to run.
240 */
241 void for_each(ForEachFunc func) const;
242
Matt Spinler421f6532019-11-06 15:40:45 -0600243 using AddCallback = std::function<void(const PEL&)>;
244
245 /**
246 * @brief Subscribe to PELs being added to the repository.
247 *
248 * Every time a PEL is added to the repository, the provided
249 * function will be called with the new PEL as the argument.
250 *
251 * The function must be of type void(const PEL&).
252 *
253 * @param[in] name - The subscription name
254 * @param[in] func - The callback function
255 */
256 void subscribeToAdds(const std::string& name, AddCallback func)
257 {
258 if (_addSubscriptions.find(name) == _addSubscriptions.end())
259 {
260 _addSubscriptions.emplace(name, func);
261 }
262 }
263
264 /**
265 * @brief Unsubscribe from new PELs.
266 *
267 * @param[in] name - The subscription name
268 */
269 void unsubscribeFromAdds(const std::string& name)
270 {
271 _addSubscriptions.erase(name);
272 }
273
274 using DeleteCallback = std::function<void(uint32_t)>;
275
276 /**
277 * @brief Subscribe to PELs being deleted from the repository.
278 *
279 * Every time a PEL is deleted from the repository, the provided
280 * function will be called with the PEL ID as the argument.
281 *
282 * The function must be of type void(const uint32_t).
283 *
284 * @param[in] name - The subscription name
285 * @param[in] func - The callback function
286 */
287 void subscribeToDeletes(const std::string& name, DeleteCallback func)
288 {
289 if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
290 {
291 _deleteSubscriptions.emplace(name, func);
292 }
293 }
294
295 /**
296 * @brief Unsubscribe from deleted PELs.
297 *
298 * @param[in] name - The subscription name
299 */
300 void unsubscribeFromDeletes(const std::string& name)
301 {
302 _deleteSubscriptions.erase(name);
303 }
304
Matt Spinler0ff00482019-11-06 16:19:46 -0600305 /**
306 * @brief Get the PEL attributes for a PEL
307 *
308 * @param[in] id - The ID to find the attributes for
309 *
310 * @return The attributes or an empty optional if not found
311 */
312 std::optional<std::reference_wrapper<const PELAttributes>>
313 getPELAttributes(const LogID& id) const;
314
Matt Spinler29d18c12019-11-21 13:31:27 -0600315 /**
316 * @brief Sets the host transmission state on a PEL file
317 *
318 * Writes the host transmission state field in the User Header
319 * section in the PEL data specified by the ID.
320 *
321 * @param[in] pelID - The PEL ID
322 * @param[in] state - The state to write
323 */
324 void setPELHostTransState(uint32_t pelID, TransmissionState state);
325
326 /**
327 * @brief Sets the HMC transmission state on a PEL file
328 *
329 * Writes the HMC transmission state field in the User Header
330 * section in the PEL data specified by the ID.
331 *
332 * @param[in] pelID - The PEL ID
333 * @param[in] state - The state to write
334 */
335 void setPELHMCTransState(uint32_t pelID, TransmissionState state);
336
Matt Spinlerb188f782020-07-07 11:18:12 -0500337 /**
338 * @brief Returns the size stats structure
339 *
340 * @return const SizeStats& - The stats structure
341 */
342 const SizeStats& getSizeStats() const
343 {
344 return _sizes;
345 }
346
347 /**
348 * @brief Says if the PEL is considered serviceable (not just
349 * informational) as determined by its severity.
350 *
351 * @param[in] pel - The PELAttributes entry for the PEL
352 * @return bool - If serviceable or not
353 */
354 static bool isServiceableSev(const PELAttributes& pel);
355
Matt Spinler89fa0822019-07-17 13:54:30 -0500356 private:
Matt Spinler29d18c12019-11-21 13:31:27 -0600357 using PELUpdateFunc = std::function<void(PEL&)>;
358
359 /**
360 * @brief Lets a function modify a PEL and saves the results
361 *
362 * Runs updateFunc (a void(PEL&) function) on the PEL data
363 * on the file specified, and writes the results back to the file.
364 *
365 * @param[in] path - The file path to use
366 * @param[in] updateFunc - The function to run to update the PEL.
367 */
368 void updatePEL(const std::filesystem::path& path, PELUpdateFunc updateFunc);
369
Matt Spinler89fa0822019-07-17 13:54:30 -0500370 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600371 * @brief Finds an entry in the _pelAttributes map.
Matt Spinler475e5742019-07-18 16:09:49 -0500372 *
373 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
374 *
375 * @return an iterator to the entry
376 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600377 std::map<LogID, PELAttributes>::const_iterator
378 findPEL(const LogID& id) const
Matt Spinler475e5742019-07-18 16:09:49 -0500379 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600380 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
381 [&id](const auto& a) { return a.first == id; });
Matt Spinler475e5742019-07-18 16:09:49 -0500382 }
383
384 /**
Matt Spinler421f6532019-11-06 15:40:45 -0600385 * @brief Call any subscribed functions for new PELs
386 *
387 * @param[in] pel - The new PEL
388 */
389 void processAddCallbacks(const PEL& pel) const;
390
391 /**
392 * @brief Call any subscribed functions for deleted PELs
393 *
394 * @param[in] id - The ID of the deleted PEL
395 */
396 void processDeleteCallbacks(uint32_t id) const;
397
398 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600399 * @brief Restores the _pelAttributes map on startup based on the existing
Matt Spinler475e5742019-07-18 16:09:49 -0500400 * PEL data files.
401 */
402 void restore();
403
404 /**
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600405 * @brief Stores a PEL object in the filesystem.
406 *
407 * @param[in] pel - The PEL to write
408 * @param[in] path - The file to write to
409 *
410 * Throws exceptions on failures.
411 */
412 void write(const PEL& pel, const std::filesystem::path& path);
413
414 /**
Matt Spinlerb188f782020-07-07 11:18:12 -0500415 * @brief Updates the repository statistics after a PEL is
416 * added or removed.
417 *
418 * @param[in] pel - The PELAttributes entry for the PEL
419 * @param[in] pelAdded - true if the PEL was added, false if removed
420 */
421 void updateRepoStats(const PELAttributes& pel, bool pelAdded);
422
423 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500424 * @brief The filesystem path to the PEL logs.
425 */
426 const std::filesystem::path _logPath;
Matt Spinler475e5742019-07-18 16:09:49 -0500427
428 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600429 * @brief A map of the PEL/OBMC IDs to PEL attributes.
Matt Spinler475e5742019-07-18 16:09:49 -0500430 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600431 std::map<LogID, PELAttributes> _pelAttributes;
Matt Spinler421f6532019-11-06 15:40:45 -0600432
433 /**
434 * @brief Subcriptions for new PELs.
435 */
436 std::map<std::string, AddCallback> _addSubscriptions;
437
438 /**
439 * @brief Subscriptions for deleted PELs.
440 */
441 std::map<std::string, DeleteCallback> _deleteSubscriptions;
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500442
443 /**
444 * @brief The maximum amount of space that the PELs in the
445 * repository can occupy.
446 */
447 const uint64_t _maxRepoSize;
448
449 /**
450 * @brief The maximum number of PELs to allow in the repo
451 * before pruning.
452 */
453 const size_t _maxNumPELs;
Matt Spinlerb188f782020-07-07 11:18:12 -0500454
455 /**
456 * @brief Statistics on the sizes of the stored PELs.
457 */
458 SizeStats _sizes;
Matt Spinler89fa0822019-07-17 13:54:30 -0500459};
460
461} // namespace pels
462} // namespace openpower