blob: f33289c43d048fb6b9051776a25b37fbb91697ee [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 Spinlerb0a8df52020-07-07 14:41:06 -0500115 using AttributesReference =
116 std::reference_wrapper<const std::pair<const LogID, PELAttributes>>;
117
Matt Spinlerb188f782020-07-07 11:18:12 -0500118 /**
119 * @brief A structure for keeping a breakdown of the sizes of PELs
120 * of different types in the repository.
121 */
122 struct SizeStats
123 {
124 uint64_t total;
125 uint64_t bmc;
126 uint64_t nonBMC;
127 uint64_t bmcServiceable;
128 uint64_t bmcInfo;
129 uint64_t nonBMCServiceable;
130 uint64_t nonBMCInfo;
131
132 SizeStats() :
133 total(0), bmc(0), nonBMC(0), bmcServiceable(0), bmcInfo(0),
134 nonBMCServiceable(0), nonBMCInfo(0)
135 {
136 }
137 };
138
Matt Spinler89fa0822019-07-17 13:54:30 -0500139 Repository() = delete;
140 ~Repository() = default;
141 Repository(const Repository&) = default;
142 Repository& operator=(const Repository&) = default;
143 Repository(Repository&&) = default;
144 Repository& operator=(Repository&&) = default;
145
146 /**
147 * @brief Constructor
148 *
149 * @param[in] basePath - the base filesystem path for the repository
150 */
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500151 Repository(const std::filesystem::path& basePath) :
152 Repository(basePath, getPELRepoSize(), getMaxNumPELs())
153 {
154 }
155
156 /**
157 * @brief Constructor that takes the repository size
158 *
159 * @param[in] basePath - the base filesystem path for the repository
160 * @param[in] repoSize - The maximum amount of space to use for PELs,
161 * in bytes
162 * @param[in] maxNumPELs - The maximum number of PELs to allow
163 */
164 Repository(const std::filesystem::path& basePath, size_t repoSize,
165 size_t maxNumPELs);
Matt Spinler89fa0822019-07-17 13:54:30 -0500166
167 /**
168 * @brief Adds a PEL to the repository
169 *
170 * Throws File.Error.Open or File.Error.Write exceptions on failure
171 *
172 * @param[in] pel - the PEL to add
173 */
174 void add(std::unique_ptr<PEL>& pel);
175
176 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500177 * @brief Removes a PEL from the repository
178 *
179 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
180 */
181 void remove(const LogID& id);
182
183 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500184 * @brief Generates the filename to use for the PEL ID and BCDTime.
185 *
186 * @param[in] pelID - the PEL ID
187 * @param[in] time - the BCD time
188 *
189 * @return string - A filename string of <BCD_time>_<pelID>
190 */
191 static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
192
Matt Spinler475e5742019-07-18 16:09:49 -0500193 /**
194 * @brief Returns true if the PEL with the specified ID is in the repo.
195 *
196 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
197 * @return bool - true if that PEL is present
198 */
199 inline bool hasPEL(const LogID& id)
200 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600201 return findPEL(id) != _pelAttributes.end();
Matt Spinler475e5742019-07-18 16:09:49 -0500202 }
203
Matt Spinler2813f362019-07-19 12:45:28 -0500204 /**
205 * @brief Returns the PEL data based on its ID.
206 *
207 * If the data can't be found for that ID, then the optional object
208 * will be empty.
209 *
210 * @param[in] id - the LogID to get the PEL for, which can be either a
211 * PEL ID or OpenBMC log ID.
212 * @return std::optional<std::vector<uint8_t>> - the PEL data
213 */
214 std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
215
Matt Spinler6d512242019-12-09 13:44:17 -0600216 /**
217 * @brief Get a file descriptor to the PEL data
218 *
219 * @param[in] id - The ID to get the FD for
220 *
221 * @return std::optional<sdbusplus::message::unix_fd> -
222 * The FD, or an empty optional object.
223 */
224 std::optional<sdbusplus::message::unix_fd> getPELFD(const LogID& id);
225
Matt Spinler1ea78802019-11-01 13:04:59 -0500226 using ForEachFunc = std::function<bool(const PEL&)>;
227
228 /**
229 * @brief Run a user defined function on every PEL in the repository.
230 *
231 * ForEachFunc takes a const PEL reference, and should return
232 * true to stop iterating and return out of for_each.
233 *
234 * For example, to save up to 100 IDs in the repo into a vector:
235 *
236 * std::vector<uint32_t> ids;
237 * ForEachFunc f = [&ids](const PEL& pel) {
238 * ids.push_back(pel.id());
239 * return ids.size() == 100 ? true : false;
240 * };
241 *
242 * @param[in] func - The function to run.
243 */
244 void for_each(ForEachFunc func) const;
245
Matt Spinler421f6532019-11-06 15:40:45 -0600246 using AddCallback = std::function<void(const PEL&)>;
247
248 /**
249 * @brief Subscribe to PELs being added to the repository.
250 *
251 * Every time a PEL is added to the repository, the provided
252 * function will be called with the new PEL as the argument.
253 *
254 * The function must be of type void(const PEL&).
255 *
256 * @param[in] name - The subscription name
257 * @param[in] func - The callback function
258 */
259 void subscribeToAdds(const std::string& name, AddCallback func)
260 {
261 if (_addSubscriptions.find(name) == _addSubscriptions.end())
262 {
263 _addSubscriptions.emplace(name, func);
264 }
265 }
266
267 /**
268 * @brief Unsubscribe from new PELs.
269 *
270 * @param[in] name - The subscription name
271 */
272 void unsubscribeFromAdds(const std::string& name)
273 {
274 _addSubscriptions.erase(name);
275 }
276
277 using DeleteCallback = std::function<void(uint32_t)>;
278
279 /**
280 * @brief Subscribe to PELs being deleted from the repository.
281 *
282 * Every time a PEL is deleted from the repository, the provided
283 * function will be called with the PEL ID as the argument.
284 *
285 * The function must be of type void(const uint32_t).
286 *
287 * @param[in] name - The subscription name
288 * @param[in] func - The callback function
289 */
290 void subscribeToDeletes(const std::string& name, DeleteCallback func)
291 {
292 if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
293 {
294 _deleteSubscriptions.emplace(name, func);
295 }
296 }
297
298 /**
299 * @brief Unsubscribe from deleted PELs.
300 *
301 * @param[in] name - The subscription name
302 */
303 void unsubscribeFromDeletes(const std::string& name)
304 {
305 _deleteSubscriptions.erase(name);
306 }
307
Matt Spinler0ff00482019-11-06 16:19:46 -0600308 /**
309 * @brief Get the PEL attributes for a PEL
310 *
311 * @param[in] id - The ID to find the attributes for
312 *
313 * @return The attributes or an empty optional if not found
314 */
315 std::optional<std::reference_wrapper<const PELAttributes>>
316 getPELAttributes(const LogID& id) const;
317
Matt Spinler29d18c12019-11-21 13:31:27 -0600318 /**
319 * @brief Sets the host transmission state on a PEL file
320 *
321 * Writes the host transmission state field in the User Header
322 * section in the PEL data specified by the ID.
323 *
324 * @param[in] pelID - The PEL ID
325 * @param[in] state - The state to write
326 */
327 void setPELHostTransState(uint32_t pelID, TransmissionState state);
328
329 /**
330 * @brief Sets the HMC transmission state on a PEL file
331 *
332 * Writes the HMC transmission state field in the User Header
333 * section in the PEL data specified by the ID.
334 *
335 * @param[in] pelID - The PEL ID
336 * @param[in] state - The state to write
337 */
338 void setPELHMCTransState(uint32_t pelID, TransmissionState state);
339
Matt Spinlerb188f782020-07-07 11:18:12 -0500340 /**
341 * @brief Returns the size stats structure
342 *
343 * @return const SizeStats& - The stats structure
344 */
345 const SizeStats& getSizeStats() const
346 {
347 return _sizes;
348 }
349
350 /**
351 * @brief Says if the PEL is considered serviceable (not just
352 * informational) as determined by its severity.
353 *
354 * @param[in] pel - The PELAttributes entry for the PEL
355 * @return bool - If serviceable or not
356 */
357 static bool isServiceableSev(const PELAttributes& pel);
358
Matt Spinlerb0a8df52020-07-07 14:41:06 -0500359 /**
360 * @brief Deletes PELs to bring the repository size down
361 * to at most 90% full by placing PELs into 4 different
362 * catogories and then removing PELs until those catogories
363 * only take up certain percentages of the allowed space.
364 *
365 * This does not delete the corresponding OpenBMC event logs, which
366 * is why those IDs are returned, so they can be deleted later.
367 *
368 * The categories and their rules are:
369 * 1) Informational BMC PELs cannot take up more than 15% of
370 * the allocated space.
371 * 2) Non-informational BMC PELs cannot take up more than 30%
372 * of the allocated space.
373 * 3) Informational non-BMC PELs cannot take up more than 15% of
374 * the allocated space.
375 * 4) Non-informational non-BMC PELs cannot take up more than 30%
376 * of the allocated space.
377 *
378 * While removing PELs in a category, 4 passes will be made, with
379 * PELs being removed oldest first during each pass.
380 *
381 * Pass 1: only delete HMC acked PELs
382 * Pass 2: only delete OS acked PELs
383 * Pass 3: only delete PHYP sent PELs
384 * Pass 4: delete all PELs
385 *
386 * @return std::vector<uint32_t> - The OpenBMC event log IDs of
387 * the PELs that were deleted.
388 */
389 std::vector<uint32_t> prune();
390
Matt Spinler89fa0822019-07-17 13:54:30 -0500391 private:
Matt Spinler29d18c12019-11-21 13:31:27 -0600392 using PELUpdateFunc = std::function<void(PEL&)>;
393
394 /**
395 * @brief Lets a function modify a PEL and saves the results
396 *
397 * Runs updateFunc (a void(PEL&) function) on the PEL data
398 * on the file specified, and writes the results back to the file.
399 *
400 * @param[in] path - The file path to use
401 * @param[in] updateFunc - The function to run to update the PEL.
402 */
403 void updatePEL(const std::filesystem::path& path, PELUpdateFunc updateFunc);
404
Matt Spinler89fa0822019-07-17 13:54:30 -0500405 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600406 * @brief Finds an entry in the _pelAttributes map.
Matt Spinler475e5742019-07-18 16:09:49 -0500407 *
408 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
409 *
410 * @return an iterator to the entry
411 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600412 std::map<LogID, PELAttributes>::const_iterator
413 findPEL(const LogID& id) const
Matt Spinler475e5742019-07-18 16:09:49 -0500414 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600415 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
416 [&id](const auto& a) { return a.first == id; });
Matt Spinler475e5742019-07-18 16:09:49 -0500417 }
418
419 /**
Matt Spinler421f6532019-11-06 15:40:45 -0600420 * @brief Call any subscribed functions for new PELs
421 *
422 * @param[in] pel - The new PEL
423 */
424 void processAddCallbacks(const PEL& pel) const;
425
426 /**
427 * @brief Call any subscribed functions for deleted PELs
428 *
429 * @param[in] id - The ID of the deleted PEL
430 */
431 void processDeleteCallbacks(uint32_t id) const;
432
433 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600434 * @brief Restores the _pelAttributes map on startup based on the existing
Matt Spinler475e5742019-07-18 16:09:49 -0500435 * PEL data files.
436 */
437 void restore();
438
439 /**
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600440 * @brief Stores a PEL object in the filesystem.
441 *
442 * @param[in] pel - The PEL to write
443 * @param[in] path - The file to write to
444 *
445 * Throws exceptions on failures.
446 */
447 void write(const PEL& pel, const std::filesystem::path& path);
448
449 /**
Matt Spinlerb188f782020-07-07 11:18:12 -0500450 * @brief Updates the repository statistics after a PEL is
451 * added or removed.
452 *
453 * @param[in] pel - The PELAttributes entry for the PEL
454 * @param[in] pelAdded - true if the PEL was added, false if removed
455 */
456 void updateRepoStats(const PELAttributes& pel, bool pelAdded);
457
Matt Spinlerb0a8df52020-07-07 14:41:06 -0500458 enum class SortOrder
459 {
460 ascending,
461 descending
462 };
463
464 /**
465 * @brief Returns a vector of all the _pelAttributes entries sorted
466 * as specified
467 *
468 * @param[in] order - If the PELs should be returned in ascending
469 * (oldest first) or descending order.
470 *
471 * @return std::vector<AttributesReference> - The sorted vector of
472 * references to the pair<LogID, PELAttributes> entries of
473 * _pelAttributes.
474 */
475 std::vector<AttributesReference> getAllPELAttributes(SortOrder order) const;
476
477 using IsOverLimitFunc = std::function<bool()>;
478 using IsPELTypeFunc = std::function<bool(const PELAttributes&)>;
479
480 /**
481 * @brief Makes 4 passes on the PELs that meet the IsPELTypeFunc
482 * criteria removing PELs until IsOverLimitFunc returns false.
483 *
484 * Pass 1: only delete HMC acked PELs
485 * Pass 2: only delete Os acked PELs
486 * Pass 3: only delete PHYP sent PELs
487 * Pass 4: delete all PELs
488 *
489 * @param[in] isOverLimit - The bool(void) function that should
490 * return true if PELs still need to be
491 * removed.
492 * @param[in] isPELType - The bool(const PELAttributes&) function
493 * used to select the PELs to operate on.
494 *
495 * @param[out] removedBMCLogIDs - The OpenBMC event log IDs of the
496 * removed PELs.
497 */
498 void removePELs(IsOverLimitFunc& isOverLimit, IsPELTypeFunc& isPELType,
499 std::vector<uint32_t>& removedBMCLogIDs);
Matt Spinlerb188f782020-07-07 11:18:12 -0500500 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500501 * @brief The filesystem path to the PEL logs.
502 */
503 const std::filesystem::path _logPath;
Matt Spinler475e5742019-07-18 16:09:49 -0500504
505 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600506 * @brief A map of the PEL/OBMC IDs to PEL attributes.
Matt Spinler475e5742019-07-18 16:09:49 -0500507 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600508 std::map<LogID, PELAttributes> _pelAttributes;
Matt Spinler421f6532019-11-06 15:40:45 -0600509
510 /**
511 * @brief Subcriptions for new PELs.
512 */
513 std::map<std::string, AddCallback> _addSubscriptions;
514
515 /**
516 * @brief Subscriptions for deleted PELs.
517 */
518 std::map<std::string, DeleteCallback> _deleteSubscriptions;
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500519
520 /**
521 * @brief The maximum amount of space that the PELs in the
522 * repository can occupy.
523 */
524 const uint64_t _maxRepoSize;
525
526 /**
527 * @brief The maximum number of PELs to allow in the repo
528 * before pruning.
529 */
530 const size_t _maxNumPELs;
Matt Spinlerb188f782020-07-07 11:18:12 -0500531
532 /**
533 * @brief Statistics on the sizes of the stored PELs.
534 */
535 SizeStats _sizes;
Matt Spinler89fa0822019-07-17 13:54:30 -0500536};
537
538} // namespace pels
539} // namespace openpower