blob: e55808f79afb4d96d33b4039ff124d81141d0e9c [file] [log] [blame]
Matt Spinler89fa0822019-07-17 13:54:30 -05001#pragma once
2#include "bcd_time.hpp"
3#include "pel.hpp"
4
5#include <algorithm>
Matt Spinler0ff00482019-11-06 16:19:46 -06006#include <bitset>
Matt Spinler89fa0822019-07-17 13:54:30 -05007#include <filesystem>
Matt Spinler475e5742019-07-18 16:09:49 -05008#include <map>
Matt Spinler89fa0822019-07-17 13:54:30 -05009
10namespace openpower
11{
12namespace pels
13{
14
15/**
16 * @class Repository
17 *
18 * The class handles saving and retrieving PELs on the BMC.
19 */
20class Repository
21{
22 public:
Matt Spinler475e5742019-07-18 16:09:49 -050023 /**
Matt Spinler0ff00482019-11-06 16:19:46 -060024 * @brief Structure of commonly used PEL attributes.
25 */
26 struct PELAttributes
27 {
28 std::filesystem::path path;
29 std::bitset<16> actionFlags;
Matt Spinler346f99a2019-11-21 13:06:35 -060030 TransmissionState hostState;
31 TransmissionState hmcState;
Matt Spinler0ff00482019-11-06 16:19:46 -060032
33 PELAttributes() = delete;
34
Matt Spinler346f99a2019-11-21 13:06:35 -060035 PELAttributes(const std::filesystem::path& p, uint16_t flags,
36 TransmissionState hostState, TransmissionState hmcState) :
37 path(p),
38 actionFlags(flags), hostState(hostState), hmcState(hmcState)
Matt Spinler0ff00482019-11-06 16:19:46 -060039 {
40 }
41 };
42
43 /**
Matt Spinler475e5742019-07-18 16:09:49 -050044 * @brief A structure that holds both the PEL and corresponding
45 * OpenBMC IDs.
46 * Used for correlating the IDs with their data files for quick
47 * lookup. To find a PEL based on just one of the IDs, just use
48 * the constructor that takes that ID.
49 */
50 struct LogID
51 {
52 struct Pel
53 {
54 uint32_t id;
55 explicit Pel(uint32_t i) : id(i)
56 {
57 }
58 };
59 struct Obmc
60 {
61 uint32_t id;
62 explicit Obmc(uint32_t i) : id(i)
63 {
64 }
65 };
66
67 Pel pelID;
68
69 Obmc obmcID;
70
71 LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc)
72 {
73 }
74
75 explicit LogID(Pel id) : pelID(id), obmcID(0)
76 {
77 }
78
79 explicit LogID(Obmc id) : pelID(0), obmcID(id)
80 {
81 }
82
83 LogID() = delete;
84
85 /**
86 * @brief A == operator that will match on either ID
87 * being equal if the other is zero, so that
88 * one can look up a PEL with just one of the IDs.
89 */
90 bool operator==(const LogID& id) const
91 {
92 if (id.pelID.id != 0)
93 {
94 return id.pelID.id == pelID.id;
95 }
96 if (id.obmcID.id != 0)
97 {
98 return id.obmcID.id == obmcID.id;
99 }
100 return false;
101 }
102
103 bool operator<(const LogID& id) const
104 {
105 return pelID.id < id.pelID.id;
106 }
107 };
108
Matt Spinler89fa0822019-07-17 13:54:30 -0500109 Repository() = delete;
110 ~Repository() = default;
111 Repository(const Repository&) = default;
112 Repository& operator=(const Repository&) = default;
113 Repository(Repository&&) = default;
114 Repository& operator=(Repository&&) = default;
115
116 /**
117 * @brief Constructor
118 *
119 * @param[in] basePath - the base filesystem path for the repository
120 */
121 Repository(const std::filesystem::path& basePath);
122
123 /**
124 * @brief Adds a PEL to the repository
125 *
126 * Throws File.Error.Open or File.Error.Write exceptions on failure
127 *
128 * @param[in] pel - the PEL to add
129 */
130 void add(std::unique_ptr<PEL>& pel);
131
132 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500133 * @brief Removes a PEL from the repository
134 *
135 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
136 */
137 void remove(const LogID& id);
138
139 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500140 * @brief Generates the filename to use for the PEL ID and BCDTime.
141 *
142 * @param[in] pelID - the PEL ID
143 * @param[in] time - the BCD time
144 *
145 * @return string - A filename string of <BCD_time>_<pelID>
146 */
147 static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
148
Matt Spinler475e5742019-07-18 16:09:49 -0500149 /**
150 * @brief Returns true if the PEL with the specified ID is in the repo.
151 *
152 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
153 * @return bool - true if that PEL is present
154 */
155 inline bool hasPEL(const LogID& id)
156 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600157 return findPEL(id) != _pelAttributes.end();
Matt Spinler475e5742019-07-18 16:09:49 -0500158 }
159
Matt Spinler2813f362019-07-19 12:45:28 -0500160 /**
161 * @brief Returns the PEL data based on its ID.
162 *
163 * If the data can't be found for that ID, then the optional object
164 * will be empty.
165 *
166 * @param[in] id - the LogID to get the PEL for, which can be either a
167 * PEL ID or OpenBMC log ID.
168 * @return std::optional<std::vector<uint8_t>> - the PEL data
169 */
170 std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
171
Matt Spinler6d512242019-12-09 13:44:17 -0600172 /**
173 * @brief Get a file descriptor to the PEL data
174 *
175 * @param[in] id - The ID to get the FD for
176 *
177 * @return std::optional<sdbusplus::message::unix_fd> -
178 * The FD, or an empty optional object.
179 */
180 std::optional<sdbusplus::message::unix_fd> getPELFD(const LogID& id);
181
Matt Spinler1ea78802019-11-01 13:04:59 -0500182 using ForEachFunc = std::function<bool(const PEL&)>;
183
184 /**
185 * @brief Run a user defined function on every PEL in the repository.
186 *
187 * ForEachFunc takes a const PEL reference, and should return
188 * true to stop iterating and return out of for_each.
189 *
190 * For example, to save up to 100 IDs in the repo into a vector:
191 *
192 * std::vector<uint32_t> ids;
193 * ForEachFunc f = [&ids](const PEL& pel) {
194 * ids.push_back(pel.id());
195 * return ids.size() == 100 ? true : false;
196 * };
197 *
198 * @param[in] func - The function to run.
199 */
200 void for_each(ForEachFunc func) const;
201
Matt Spinler421f6532019-11-06 15:40:45 -0600202 using AddCallback = std::function<void(const PEL&)>;
203
204 /**
205 * @brief Subscribe to PELs being added to the repository.
206 *
207 * Every time a PEL is added to the repository, the provided
208 * function will be called with the new PEL as the argument.
209 *
210 * The function must be of type void(const PEL&).
211 *
212 * @param[in] name - The subscription name
213 * @param[in] func - The callback function
214 */
215 void subscribeToAdds(const std::string& name, AddCallback func)
216 {
217 if (_addSubscriptions.find(name) == _addSubscriptions.end())
218 {
219 _addSubscriptions.emplace(name, func);
220 }
221 }
222
223 /**
224 * @brief Unsubscribe from new PELs.
225 *
226 * @param[in] name - The subscription name
227 */
228 void unsubscribeFromAdds(const std::string& name)
229 {
230 _addSubscriptions.erase(name);
231 }
232
233 using DeleteCallback = std::function<void(uint32_t)>;
234
235 /**
236 * @brief Subscribe to PELs being deleted from the repository.
237 *
238 * Every time a PEL is deleted from the repository, the provided
239 * function will be called with the PEL ID as the argument.
240 *
241 * The function must be of type void(const uint32_t).
242 *
243 * @param[in] name - The subscription name
244 * @param[in] func - The callback function
245 */
246 void subscribeToDeletes(const std::string& name, DeleteCallback func)
247 {
248 if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
249 {
250 _deleteSubscriptions.emplace(name, func);
251 }
252 }
253
254 /**
255 * @brief Unsubscribe from deleted PELs.
256 *
257 * @param[in] name - The subscription name
258 */
259 void unsubscribeFromDeletes(const std::string& name)
260 {
261 _deleteSubscriptions.erase(name);
262 }
263
Matt Spinler0ff00482019-11-06 16:19:46 -0600264 /**
265 * @brief Get the PEL attributes for a PEL
266 *
267 * @param[in] id - The ID to find the attributes for
268 *
269 * @return The attributes or an empty optional if not found
270 */
271 std::optional<std::reference_wrapper<const PELAttributes>>
272 getPELAttributes(const LogID& id) const;
273
Matt Spinler29d18c12019-11-21 13:31:27 -0600274 /**
275 * @brief Sets the host transmission state on a PEL file
276 *
277 * Writes the host transmission state field in the User Header
278 * section in the PEL data specified by the ID.
279 *
280 * @param[in] pelID - The PEL ID
281 * @param[in] state - The state to write
282 */
283 void setPELHostTransState(uint32_t pelID, TransmissionState state);
284
285 /**
286 * @brief Sets the HMC transmission state on a PEL file
287 *
288 * Writes the HMC transmission state field in the User Header
289 * section in the PEL data specified by the ID.
290 *
291 * @param[in] pelID - The PEL ID
292 * @param[in] state - The state to write
293 */
294 void setPELHMCTransState(uint32_t pelID, TransmissionState state);
295
Matt Spinler89fa0822019-07-17 13:54:30 -0500296 private:
Matt Spinler29d18c12019-11-21 13:31:27 -0600297 using PELUpdateFunc = std::function<void(PEL&)>;
298
299 /**
300 * @brief Lets a function modify a PEL and saves the results
301 *
302 * Runs updateFunc (a void(PEL&) function) on the PEL data
303 * on the file specified, and writes the results back to the file.
304 *
305 * @param[in] path - The file path to use
306 * @param[in] updateFunc - The function to run to update the PEL.
307 */
308 void updatePEL(const std::filesystem::path& path, PELUpdateFunc updateFunc);
309
Matt Spinler89fa0822019-07-17 13:54:30 -0500310 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600311 * @brief Finds an entry in the _pelAttributes map.
Matt Spinler475e5742019-07-18 16:09:49 -0500312 *
313 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
314 *
315 * @return an iterator to the entry
316 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600317 std::map<LogID, PELAttributes>::const_iterator
318 findPEL(const LogID& id) const
Matt Spinler475e5742019-07-18 16:09:49 -0500319 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600320 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
321 [&id](const auto& a) { return a.first == id; });
Matt Spinler475e5742019-07-18 16:09:49 -0500322 }
323
324 /**
Matt Spinler421f6532019-11-06 15:40:45 -0600325 * @brief Call any subscribed functions for new PELs
326 *
327 * @param[in] pel - The new PEL
328 */
329 void processAddCallbacks(const PEL& pel) const;
330
331 /**
332 * @brief Call any subscribed functions for deleted PELs
333 *
334 * @param[in] id - The ID of the deleted PEL
335 */
336 void processDeleteCallbacks(uint32_t id) const;
337
338 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600339 * @brief Restores the _pelAttributes map on startup based on the existing
Matt Spinler475e5742019-07-18 16:09:49 -0500340 * PEL data files.
341 */
342 void restore();
343
344 /**
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600345 * @brief Stores a PEL object in the filesystem.
346 *
347 * @param[in] pel - The PEL to write
348 * @param[in] path - The file to write to
349 *
350 * Throws exceptions on failures.
351 */
352 void write(const PEL& pel, const std::filesystem::path& path);
353
354 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500355 * @brief The filesystem path to the PEL logs.
356 */
357 const std::filesystem::path _logPath;
Matt Spinler475e5742019-07-18 16:09:49 -0500358
359 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600360 * @brief A map of the PEL/OBMC IDs to PEL attributes.
Matt Spinler475e5742019-07-18 16:09:49 -0500361 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600362 std::map<LogID, PELAttributes> _pelAttributes;
Matt Spinler421f6532019-11-06 15:40:45 -0600363
364 /**
365 * @brief Subcriptions for new PELs.
366 */
367 std::map<std::string, AddCallback> _addSubscriptions;
368
369 /**
370 * @brief Subscriptions for deleted PELs.
371 */
372 std::map<std::string, DeleteCallback> _deleteSubscriptions;
Matt Spinler89fa0822019-07-17 13:54:30 -0500373};
374
375} // namespace pels
376} // namespace openpower