1 #pragma once 2 #include "bcd_time.hpp" 3 #include "pel.hpp" 4 5 #include <algorithm> 6 #include <bitset> 7 #include <filesystem> 8 #include <map> 9 10 namespace openpower 11 { 12 namespace pels 13 { 14 15 /** 16 * @class Repository 17 * 18 * The class handles saving and retrieving PELs on the BMC. 19 */ 20 class Repository 21 { 22 public: 23 /** 24 * @brief Structure of commonly used PEL attributes. 25 */ 26 struct PELAttributes 27 { 28 std::filesystem::path path; 29 std::bitset<16> actionFlags; 30 TransmissionState hostState; 31 TransmissionState hmcState; 32 33 PELAttributes() = delete; 34 35 PELAttributes(const std::filesystem::path& p, uint16_t flags, 36 TransmissionState hostState, TransmissionState hmcState) : 37 path(p), 38 actionFlags(flags), hostState(hostState), hmcState(hmcState) 39 { 40 } 41 }; 42 43 /** 44 * @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 109 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 /** 133 * @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 /** 140 * @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 149 /** 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 { 157 return findPEL(id) != _pelAttributes.end(); 158 } 159 160 /** 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 172 /** 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 182 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 202 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 264 /** 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 274 /** 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 296 private: 297 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 310 /** 311 * @brief Finds an entry in the _pelAttributes map. 312 * 313 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) 314 * 315 * @return an iterator to the entry 316 */ 317 std::map<LogID, PELAttributes>::const_iterator 318 findPEL(const LogID& id) const 319 { 320 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(), 321 [&id](const auto& a) { return a.first == id; }); 322 } 323 324 /** 325 * @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 /** 339 * @brief Restores the _pelAttributes map on startup based on the existing 340 * PEL data files. 341 */ 342 void restore(); 343 344 /** 345 * @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 /** 355 * @brief The filesystem path to the PEL logs. 356 */ 357 const std::filesystem::path _logPath; 358 359 /** 360 * @brief A map of the PEL/OBMC IDs to PEL attributes. 361 */ 362 std::map<LogID, PELAttributes> _pelAttributes; 363 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; 373 }; 374 375 } // namespace pels 376 } // namespace openpower 377