blob: ecfcf7e945c191481042a70a665f2ccaa52229ce [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 Spinler89fa0822019-07-17 13:54:30 -0500115 Repository() = delete;
116 ~Repository() = default;
117 Repository(const Repository&) = default;
118 Repository& operator=(const Repository&) = default;
119 Repository(Repository&&) = default;
120 Repository& operator=(Repository&&) = default;
121
122 /**
123 * @brief Constructor
124 *
125 * @param[in] basePath - the base filesystem path for the repository
126 */
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500127 Repository(const std::filesystem::path& basePath) :
128 Repository(basePath, getPELRepoSize(), getMaxNumPELs())
129 {
130 }
131
132 /**
133 * @brief Constructor that takes the repository size
134 *
135 * @param[in] basePath - the base filesystem path for the repository
136 * @param[in] repoSize - The maximum amount of space to use for PELs,
137 * in bytes
138 * @param[in] maxNumPELs - The maximum number of PELs to allow
139 */
140 Repository(const std::filesystem::path& basePath, size_t repoSize,
141 size_t maxNumPELs);
Matt Spinler89fa0822019-07-17 13:54:30 -0500142
143 /**
144 * @brief Adds a PEL to the repository
145 *
146 * Throws File.Error.Open or File.Error.Write exceptions on failure
147 *
148 * @param[in] pel - the PEL to add
149 */
150 void add(std::unique_ptr<PEL>& pel);
151
152 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500153 * @brief Removes a PEL from the repository
154 *
155 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
156 */
157 void remove(const LogID& id);
158
159 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500160 * @brief Generates the filename to use for the PEL ID and BCDTime.
161 *
162 * @param[in] pelID - the PEL ID
163 * @param[in] time - the BCD time
164 *
165 * @return string - A filename string of <BCD_time>_<pelID>
166 */
167 static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
168
Matt Spinler475e5742019-07-18 16:09:49 -0500169 /**
170 * @brief Returns true if the PEL with the specified ID is in the repo.
171 *
172 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
173 * @return bool - true if that PEL is present
174 */
175 inline bool hasPEL(const LogID& id)
176 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600177 return findPEL(id) != _pelAttributes.end();
Matt Spinler475e5742019-07-18 16:09:49 -0500178 }
179
Matt Spinler2813f362019-07-19 12:45:28 -0500180 /**
181 * @brief Returns the PEL data based on its ID.
182 *
183 * If the data can't be found for that ID, then the optional object
184 * will be empty.
185 *
186 * @param[in] id - the LogID to get the PEL for, which can be either a
187 * PEL ID or OpenBMC log ID.
188 * @return std::optional<std::vector<uint8_t>> - the PEL data
189 */
190 std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
191
Matt Spinler6d512242019-12-09 13:44:17 -0600192 /**
193 * @brief Get a file descriptor to the PEL data
194 *
195 * @param[in] id - The ID to get the FD for
196 *
197 * @return std::optional<sdbusplus::message::unix_fd> -
198 * The FD, or an empty optional object.
199 */
200 std::optional<sdbusplus::message::unix_fd> getPELFD(const LogID& id);
201
Matt Spinler1ea78802019-11-01 13:04:59 -0500202 using ForEachFunc = std::function<bool(const PEL&)>;
203
204 /**
205 * @brief Run a user defined function on every PEL in the repository.
206 *
207 * ForEachFunc takes a const PEL reference, and should return
208 * true to stop iterating and return out of for_each.
209 *
210 * For example, to save up to 100 IDs in the repo into a vector:
211 *
212 * std::vector<uint32_t> ids;
213 * ForEachFunc f = [&ids](const PEL& pel) {
214 * ids.push_back(pel.id());
215 * return ids.size() == 100 ? true : false;
216 * };
217 *
218 * @param[in] func - The function to run.
219 */
220 void for_each(ForEachFunc func) const;
221
Matt Spinler421f6532019-11-06 15:40:45 -0600222 using AddCallback = std::function<void(const PEL&)>;
223
224 /**
225 * @brief Subscribe to PELs being added to the repository.
226 *
227 * Every time a PEL is added to the repository, the provided
228 * function will be called with the new PEL as the argument.
229 *
230 * The function must be of type void(const PEL&).
231 *
232 * @param[in] name - The subscription name
233 * @param[in] func - The callback function
234 */
235 void subscribeToAdds(const std::string& name, AddCallback func)
236 {
237 if (_addSubscriptions.find(name) == _addSubscriptions.end())
238 {
239 _addSubscriptions.emplace(name, func);
240 }
241 }
242
243 /**
244 * @brief Unsubscribe from new PELs.
245 *
246 * @param[in] name - The subscription name
247 */
248 void unsubscribeFromAdds(const std::string& name)
249 {
250 _addSubscriptions.erase(name);
251 }
252
253 using DeleteCallback = std::function<void(uint32_t)>;
254
255 /**
256 * @brief Subscribe to PELs being deleted from the repository.
257 *
258 * Every time a PEL is deleted from the repository, the provided
259 * function will be called with the PEL ID as the argument.
260 *
261 * The function must be of type void(const uint32_t).
262 *
263 * @param[in] name - The subscription name
264 * @param[in] func - The callback function
265 */
266 void subscribeToDeletes(const std::string& name, DeleteCallback func)
267 {
268 if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
269 {
270 _deleteSubscriptions.emplace(name, func);
271 }
272 }
273
274 /**
275 * @brief Unsubscribe from deleted PELs.
276 *
277 * @param[in] name - The subscription name
278 */
279 void unsubscribeFromDeletes(const std::string& name)
280 {
281 _deleteSubscriptions.erase(name);
282 }
283
Matt Spinler0ff00482019-11-06 16:19:46 -0600284 /**
285 * @brief Get the PEL attributes for a PEL
286 *
287 * @param[in] id - The ID to find the attributes for
288 *
289 * @return The attributes or an empty optional if not found
290 */
291 std::optional<std::reference_wrapper<const PELAttributes>>
292 getPELAttributes(const LogID& id) const;
293
Matt Spinler29d18c12019-11-21 13:31:27 -0600294 /**
295 * @brief Sets the host transmission state on a PEL file
296 *
297 * Writes the host transmission state field in the User Header
298 * section in the PEL data specified by the ID.
299 *
300 * @param[in] pelID - The PEL ID
301 * @param[in] state - The state to write
302 */
303 void setPELHostTransState(uint32_t pelID, TransmissionState state);
304
305 /**
306 * @brief Sets the HMC transmission state on a PEL file
307 *
308 * Writes the HMC transmission state field in the User Header
309 * section in the PEL data specified by the ID.
310 *
311 * @param[in] pelID - The PEL ID
312 * @param[in] state - The state to write
313 */
314 void setPELHMCTransState(uint32_t pelID, TransmissionState state);
315
Matt Spinler89fa0822019-07-17 13:54:30 -0500316 private:
Matt Spinler29d18c12019-11-21 13:31:27 -0600317 using PELUpdateFunc = std::function<void(PEL&)>;
318
319 /**
320 * @brief Lets a function modify a PEL and saves the results
321 *
322 * Runs updateFunc (a void(PEL&) function) on the PEL data
323 * on the file specified, and writes the results back to the file.
324 *
325 * @param[in] path - The file path to use
326 * @param[in] updateFunc - The function to run to update the PEL.
327 */
328 void updatePEL(const std::filesystem::path& path, PELUpdateFunc updateFunc);
329
Matt Spinler89fa0822019-07-17 13:54:30 -0500330 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600331 * @brief Finds an entry in the _pelAttributes map.
Matt Spinler475e5742019-07-18 16:09:49 -0500332 *
333 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
334 *
335 * @return an iterator to the entry
336 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600337 std::map<LogID, PELAttributes>::const_iterator
338 findPEL(const LogID& id) const
Matt Spinler475e5742019-07-18 16:09:49 -0500339 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600340 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
341 [&id](const auto& a) { return a.first == id; });
Matt Spinler475e5742019-07-18 16:09:49 -0500342 }
343
344 /**
Matt Spinler421f6532019-11-06 15:40:45 -0600345 * @brief Call any subscribed functions for new PELs
346 *
347 * @param[in] pel - The new PEL
348 */
349 void processAddCallbacks(const PEL& pel) const;
350
351 /**
352 * @brief Call any subscribed functions for deleted PELs
353 *
354 * @param[in] id - The ID of the deleted PEL
355 */
356 void processDeleteCallbacks(uint32_t id) const;
357
358 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600359 * @brief Restores the _pelAttributes map on startup based on the existing
Matt Spinler475e5742019-07-18 16:09:49 -0500360 * PEL data files.
361 */
362 void restore();
363
364 /**
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600365 * @brief Stores a PEL object in the filesystem.
366 *
367 * @param[in] pel - The PEL to write
368 * @param[in] path - The file to write to
369 *
370 * Throws exceptions on failures.
371 */
372 void write(const PEL& pel, const std::filesystem::path& path);
373
374 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500375 * @brief The filesystem path to the PEL logs.
376 */
377 const std::filesystem::path _logPath;
Matt Spinler475e5742019-07-18 16:09:49 -0500378
379 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600380 * @brief A map of the PEL/OBMC IDs to PEL attributes.
Matt Spinler475e5742019-07-18 16:09:49 -0500381 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600382 std::map<LogID, PELAttributes> _pelAttributes;
Matt Spinler421f6532019-11-06 15:40:45 -0600383
384 /**
385 * @brief Subcriptions for new PELs.
386 */
387 std::map<std::string, AddCallback> _addSubscriptions;
388
389 /**
390 * @brief Subscriptions for deleted PELs.
391 */
392 std::map<std::string, DeleteCallback> _deleteSubscriptions;
Matt Spinler8d5f3a22020-07-07 10:30:33 -0500393
394 /**
395 * @brief The maximum amount of space that the PELs in the
396 * repository can occupy.
397 */
398 const uint64_t _maxRepoSize;
399
400 /**
401 * @brief The maximum number of PELs to allow in the repo
402 * before pruning.
403 */
404 const size_t _maxNumPELs;
Matt Spinler89fa0822019-07-17 13:54:30 -0500405};
406
407} // namespace pels
408} // namespace openpower