blob: 2e2f6233e00475d3a682f6be70bb604c85518a11 [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;
30 std::bitset<16> actionFlags;
Matt Spinler346f99a2019-11-21 13:06:35 -060031 TransmissionState hostState;
32 TransmissionState hmcState;
Matt Spinler0ff00482019-11-06 16:19:46 -060033
34 PELAttributes() = delete;
35
Matt Spinler346f99a2019-11-21 13:06:35 -060036 PELAttributes(const std::filesystem::path& p, uint16_t flags,
37 TransmissionState hostState, TransmissionState hmcState) :
38 path(p),
39 actionFlags(flags), hostState(hostState), hmcState(hmcState)
Matt Spinler0ff00482019-11-06 16:19:46 -060040 {
41 }
42 };
43
44 /**
Matt Spinler475e5742019-07-18 16:09:49 -050045 * @brief A structure that holds both the PEL and corresponding
46 * OpenBMC IDs.
47 * Used for correlating the IDs with their data files for quick
48 * lookup. To find a PEL based on just one of the IDs, just use
49 * the constructor that takes that ID.
50 */
51 struct LogID
52 {
53 struct Pel
54 {
55 uint32_t id;
56 explicit Pel(uint32_t i) : id(i)
57 {
58 }
59 };
60 struct Obmc
61 {
62 uint32_t id;
63 explicit Obmc(uint32_t i) : id(i)
64 {
65 }
66 };
67
68 Pel pelID;
69
70 Obmc obmcID;
71
72 LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc)
73 {
74 }
75
76 explicit LogID(Pel id) : pelID(id), obmcID(0)
77 {
78 }
79
80 explicit LogID(Obmc id) : pelID(0), obmcID(id)
81 {
82 }
83
84 LogID() = delete;
85
86 /**
87 * @brief A == operator that will match on either ID
88 * being equal if the other is zero, so that
89 * one can look up a PEL with just one of the IDs.
90 */
91 bool operator==(const LogID& id) const
92 {
93 if (id.pelID.id != 0)
94 {
95 return id.pelID.id == pelID.id;
96 }
97 if (id.obmcID.id != 0)
98 {
99 return id.obmcID.id == obmcID.id;
100 }
101 return false;
102 }
103
104 bool operator<(const LogID& id) const
105 {
106 return pelID.id < id.pelID.id;
107 }
108 };
109
Matt Spinler89fa0822019-07-17 13:54:30 -0500110 Repository() = delete;
111 ~Repository() = default;
112 Repository(const Repository&) = default;
113 Repository& operator=(const Repository&) = default;
114 Repository(Repository&&) = default;
115 Repository& operator=(Repository&&) = default;
116
117 /**
118 * @brief Constructor
119 *
120 * @param[in] basePath - the base filesystem path for the repository
121 */
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500122 Repository(const std::filesystem::path& basePath) :
123 Repository(basePath, getPELRepoSize(), getMaxNumPELs())
124 {
125 }
126
127 /**
128 * @brief Constructor that takes the repository size
129 *
130 * @param[in] basePath - the base filesystem path for the repository
131 * @param[in] repoSize - The maximum amount of space to use for PELs,
132 * in bytes
133 * @param[in] maxNumPELs - The maximum number of PELs to allow
134 */
135 Repository(const std::filesystem::path& basePath, size_t repoSize,
136 size_t maxNumPELs);
Matt Spinler89fa0822019-07-17 13:54:30 -0500137
138 /**
139 * @brief Adds a PEL to the repository
140 *
141 * Throws File.Error.Open or File.Error.Write exceptions on failure
142 *
143 * @param[in] pel - the PEL to add
144 */
145 void add(std::unique_ptr<PEL>& pel);
146
147 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500148 * @brief Removes a PEL from the repository
149 *
150 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
151 */
152 void remove(const LogID& id);
153
154 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500155 * @brief Generates the filename to use for the PEL ID and BCDTime.
156 *
157 * @param[in] pelID - the PEL ID
158 * @param[in] time - the BCD time
159 *
160 * @return string - A filename string of <BCD_time>_<pelID>
161 */
162 static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
163
Matt Spinler475e5742019-07-18 16:09:49 -0500164 /**
165 * @brief Returns true if the PEL with the specified ID is in the repo.
166 *
167 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
168 * @return bool - true if that PEL is present
169 */
170 inline bool hasPEL(const LogID& id)
171 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600172 return findPEL(id) != _pelAttributes.end();
Matt Spinler475e5742019-07-18 16:09:49 -0500173 }
174
Matt Spinler2813f362019-07-19 12:45:28 -0500175 /**
176 * @brief Returns the PEL data based on its ID.
177 *
178 * If the data can't be found for that ID, then the optional object
179 * will be empty.
180 *
181 * @param[in] id - the LogID to get the PEL for, which can be either a
182 * PEL ID or OpenBMC log ID.
183 * @return std::optional<std::vector<uint8_t>> - the PEL data
184 */
185 std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
186
Matt Spinler6d512242019-12-09 13:44:17 -0600187 /**
188 * @brief Get a file descriptor to the PEL data
189 *
190 * @param[in] id - The ID to get the FD for
191 *
192 * @return std::optional<sdbusplus::message::unix_fd> -
193 * The FD, or an empty optional object.
194 */
195 std::optional<sdbusplus::message::unix_fd> getPELFD(const LogID& id);
196
Matt Spinler1ea78802019-11-01 13:04:59 -0500197 using ForEachFunc = std::function<bool(const PEL&)>;
198
199 /**
200 * @brief Run a user defined function on every PEL in the repository.
201 *
202 * ForEachFunc takes a const PEL reference, and should return
203 * true to stop iterating and return out of for_each.
204 *
205 * For example, to save up to 100 IDs in the repo into a vector:
206 *
207 * std::vector<uint32_t> ids;
208 * ForEachFunc f = [&ids](const PEL& pel) {
209 * ids.push_back(pel.id());
210 * return ids.size() == 100 ? true : false;
211 * };
212 *
213 * @param[in] func - The function to run.
214 */
215 void for_each(ForEachFunc func) const;
216
Matt Spinler421f6532019-11-06 15:40:45 -0600217 using AddCallback = std::function<void(const PEL&)>;
218
219 /**
220 * @brief Subscribe to PELs being added to the repository.
221 *
222 * Every time a PEL is added to the repository, the provided
223 * function will be called with the new PEL as the argument.
224 *
225 * The function must be of type void(const PEL&).
226 *
227 * @param[in] name - The subscription name
228 * @param[in] func - The callback function
229 */
230 void subscribeToAdds(const std::string& name, AddCallback func)
231 {
232 if (_addSubscriptions.find(name) == _addSubscriptions.end())
233 {
234 _addSubscriptions.emplace(name, func);
235 }
236 }
237
238 /**
239 * @brief Unsubscribe from new PELs.
240 *
241 * @param[in] name - The subscription name
242 */
243 void unsubscribeFromAdds(const std::string& name)
244 {
245 _addSubscriptions.erase(name);
246 }
247
248 using DeleteCallback = std::function<void(uint32_t)>;
249
250 /**
251 * @brief Subscribe to PELs being deleted from the repository.
252 *
253 * Every time a PEL is deleted from the repository, the provided
254 * function will be called with the PEL ID as the argument.
255 *
256 * The function must be of type void(const uint32_t).
257 *
258 * @param[in] name - The subscription name
259 * @param[in] func - The callback function
260 */
261 void subscribeToDeletes(const std::string& name, DeleteCallback func)
262 {
263 if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
264 {
265 _deleteSubscriptions.emplace(name, func);
266 }
267 }
268
269 /**
270 * @brief Unsubscribe from deleted PELs.
271 *
272 * @param[in] name - The subscription name
273 */
274 void unsubscribeFromDeletes(const std::string& name)
275 {
276 _deleteSubscriptions.erase(name);
277 }
278
Matt Spinler0ff00482019-11-06 16:19:46 -0600279 /**
280 * @brief Get the PEL attributes for a PEL
281 *
282 * @param[in] id - The ID to find the attributes for
283 *
284 * @return The attributes or an empty optional if not found
285 */
286 std::optional<std::reference_wrapper<const PELAttributes>>
287 getPELAttributes(const LogID& id) const;
288
Matt Spinler29d18c12019-11-21 13:31:27 -0600289 /**
290 * @brief Sets the host transmission state on a PEL file
291 *
292 * Writes the host transmission state field in the User Header
293 * section in the PEL data specified by the ID.
294 *
295 * @param[in] pelID - The PEL ID
296 * @param[in] state - The state to write
297 */
298 void setPELHostTransState(uint32_t pelID, TransmissionState state);
299
300 /**
301 * @brief Sets the HMC transmission state on a PEL file
302 *
303 * Writes the HMC transmission state field in the User Header
304 * section in the PEL data specified by the ID.
305 *
306 * @param[in] pelID - The PEL ID
307 * @param[in] state - The state to write
308 */
309 void setPELHMCTransState(uint32_t pelID, TransmissionState state);
310
Matt Spinler89fa0822019-07-17 13:54:30 -0500311 private:
Matt Spinler29d18c12019-11-21 13:31:27 -0600312 using PELUpdateFunc = std::function<void(PEL&)>;
313
314 /**
315 * @brief Lets a function modify a PEL and saves the results
316 *
317 * Runs updateFunc (a void(PEL&) function) on the PEL data
318 * on the file specified, and writes the results back to the file.
319 *
320 * @param[in] path - The file path to use
321 * @param[in] updateFunc - The function to run to update the PEL.
322 */
323 void updatePEL(const std::filesystem::path& path, PELUpdateFunc updateFunc);
324
Matt Spinler89fa0822019-07-17 13:54:30 -0500325 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600326 * @brief Finds an entry in the _pelAttributes map.
Matt Spinler475e5742019-07-18 16:09:49 -0500327 *
328 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
329 *
330 * @return an iterator to the entry
331 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600332 std::map<LogID, PELAttributes>::const_iterator
333 findPEL(const LogID& id) const
Matt Spinler475e5742019-07-18 16:09:49 -0500334 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600335 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
336 [&id](const auto& a) { return a.first == id; });
Matt Spinler475e5742019-07-18 16:09:49 -0500337 }
338
339 /**
Matt Spinler421f6532019-11-06 15:40:45 -0600340 * @brief Call any subscribed functions for new PELs
341 *
342 * @param[in] pel - The new PEL
343 */
344 void processAddCallbacks(const PEL& pel) const;
345
346 /**
347 * @brief Call any subscribed functions for deleted PELs
348 *
349 * @param[in] id - The ID of the deleted PEL
350 */
351 void processDeleteCallbacks(uint32_t id) const;
352
353 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600354 * @brief Restores the _pelAttributes map on startup based on the existing
Matt Spinler475e5742019-07-18 16:09:49 -0500355 * PEL data files.
356 */
357 void restore();
358
359 /**
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600360 * @brief Stores a PEL object in the filesystem.
361 *
362 * @param[in] pel - The PEL to write
363 * @param[in] path - The file to write to
364 *
365 * Throws exceptions on failures.
366 */
367 void write(const PEL& pel, const std::filesystem::path& path);
368
369 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500370 * @brief The filesystem path to the PEL logs.
371 */
372 const std::filesystem::path _logPath;
Matt Spinler475e5742019-07-18 16:09:49 -0500373
374 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600375 * @brief A map of the PEL/OBMC IDs to PEL attributes.
Matt Spinler475e5742019-07-18 16:09:49 -0500376 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600377 std::map<LogID, PELAttributes> _pelAttributes;
Matt Spinler421f6532019-11-06 15:40:45 -0600378
379 /**
380 * @brief Subcriptions for new PELs.
381 */
382 std::map<std::string, AddCallback> _addSubscriptions;
383
384 /**
385 * @brief Subscriptions for deleted PELs.
386 */
387 std::map<std::string, DeleteCallback> _deleteSubscriptions;
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500388
389 /**
390 * @brief The maximum amount of space that the PELs in the
391 * repository can occupy.
392 */
393 const uint64_t _maxRepoSize;
394
395 /**
396 * @brief The maximum number of PELs to allow in the repo
397 * before pruning.
398 */
399 const size_t _maxNumPELs;
Matt Spinler89fa0822019-07-17 13:54:30 -0500400};
401
402} // namespace pels
403} // namespace openpower