1 #pragma once 2 #include "bcd_time.hpp" 3 #include "paths.hpp" 4 #include "pel.hpp" 5 6 #include <algorithm> 7 #include <bitset> 8 #include <filesystem> 9 #include <map> 10 11 namespace openpower 12 { 13 namespace pels 14 { 15 16 /** 17 * @class Repository 18 * 19 * The class handles saving and retrieving PELs on the BMC. 20 */ 21 class Repository 22 { 23 public: 24 /** 25 * @brief Structure of commonly used PEL attributes. 26 */ 27 struct PELAttributes 28 { 29 std::filesystem::path path; 30 size_t sizeOnDisk; 31 uint8_t creator; 32 uint8_t subsystem; 33 uint8_t severity; 34 std::bitset<16> actionFlags; 35 TransmissionState hostState; 36 TransmissionState hmcState; 37 uint32_t plid; 38 bool deconfig; 39 bool guard; 40 uint64_t creationTime; 41 42 PELAttributes() = delete; 43 PELAttributesopenpower::pels::Repository::PELAttributes44 PELAttributes(const std::filesystem::path& p, size_t size, 45 uint8_t creator, uint8_t subsystem, uint8_t sev, 46 uint16_t flags, TransmissionState hostState, 47 TransmissionState hmcState, uint32_t plid, bool deconfig, 48 bool guard, uint64_t creationTime) : 49 path(p), sizeOnDisk(size), creator(creator), subsystem(subsystem), 50 severity(sev), actionFlags(flags), hostState(hostState), 51 hmcState(hmcState), plid(plid), deconfig(deconfig), guard(guard), 52 creationTime(creationTime) 53 {} 54 }; 55 56 /** 57 * @brief A structure that holds both the PEL and corresponding 58 * OpenBMC IDs. 59 * Used for correlating the IDs with their data files for quick 60 * lookup. To find a PEL based on just one of the IDs, just use 61 * the constructor that takes that ID. 62 */ 63 struct LogID 64 { 65 struct Pel 66 { 67 uint32_t id; Pelopenpower::pels::Repository::LogID::Pel68 explicit Pel(uint32_t i) : id(i) {} 69 }; 70 struct Obmc 71 { 72 uint32_t id; Obmcopenpower::pels::Repository::LogID::Obmc73 explicit Obmc(uint32_t i) : id(i) {} 74 }; 75 76 Pel pelID; 77 78 Obmc obmcID; 79 LogIDopenpower::pels::Repository::LogID80 LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc) {} 81 LogIDopenpower::pels::Repository::LogID82 explicit LogID(Pel id) : pelID(id), obmcID(0) {} 83 LogIDopenpower::pels::Repository::LogID84 explicit LogID(Obmc id) : pelID(0), obmcID(id) {} 85 86 LogID() = delete; 87 88 /** 89 * @brief A == operator that will match on either ID 90 * being equal if the other is zero, so that 91 * one can look up a PEL with just one of the IDs. 92 */ operator ==openpower::pels::Repository::LogID93 bool operator==(const LogID& id) const 94 { 95 if (id.pelID.id != 0) 96 { 97 return id.pelID.id == pelID.id; 98 } 99 if (id.obmcID.id != 0) 100 { 101 return id.obmcID.id == obmcID.id; 102 } 103 return false; 104 } 105 operator <openpower::pels::Repository::LogID106 bool operator<(const LogID& id) const 107 { 108 return pelID.id < id.pelID.id; 109 } 110 }; 111 112 using AttributesReference = 113 std::reference_wrapper<const std::pair<const LogID, PELAttributes>>; 114 115 /** 116 * @brief A structure for keeping a breakdown of the sizes of PELs 117 * of different types in the repository. 118 */ 119 struct SizeStats 120 { 121 uint64_t total; 122 uint64_t bmc; 123 uint64_t nonBMC; 124 uint64_t bmcServiceable; 125 uint64_t bmcInfo; 126 uint64_t nonBMCServiceable; 127 uint64_t nonBMCInfo; 128 SizeStatsopenpower::pels::Repository::SizeStats129 SizeStats() : 130 total(0), bmc(0), nonBMC(0), bmcServiceable(0), bmcInfo(0), 131 nonBMCServiceable(0), nonBMCInfo(0) 132 {} 133 }; 134 135 Repository() = delete; 136 ~Repository() = default; 137 Repository(const Repository&) = default; 138 Repository& operator=(const Repository&) = default; 139 Repository(Repository&&) = default; 140 Repository& operator=(Repository&&) = default; 141 142 /** 143 * @brief Constructor 144 * 145 * @param[in] basePath - the base filesystem path for the repository 146 */ Repository(const std::filesystem::path & basePath)147 explicit Repository(const std::filesystem::path& basePath) : 148 Repository(basePath, getPELRepoSize(), getMaxNumPELs()) 149 {} 150 151 /** 152 * @brief Constructor that takes the repository size 153 * 154 * @param[in] basePath - the base filesystem path for the repository 155 * @param[in] repoSize - The maximum amount of space to use for PELs, 156 * in bytes 157 * @param[in] maxNumPELs - The maximum number of PELs to allow 158 */ 159 Repository(const std::filesystem::path& basePath, size_t repoSize, 160 size_t maxNumPELs); 161 162 /** 163 * @brief Adds a PEL to the repository 164 * 165 * Throws File.Error.Open or File.Error.Write exceptions on failure 166 * 167 * @param[in] pel - the PEL to add 168 */ 169 void add(std::unique_ptr<PEL>& pel); 170 171 /** 172 * @brief Removes a PEL from the repository 173 * 174 * Note that the returned LogID is the fully filled in LogID, i.e. 175 * it has both the PEL and OpenBMC IDs, unlike the passed in LogID 176 * which can just have one or the other. 177 * 178 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove 179 * 180 * @return std::optional<LogID> - The LogID of the removed PEL 181 */ 182 std::optional<LogID> remove(const LogID& id); 183 184 /** 185 * @brief Generates the filename to use for the PEL ID and BCDTime. 186 * 187 * @param[in] pelID - the PEL ID 188 * @param[in] time - the BCD time 189 * 190 * @return string - A filename string of <BCD_time>_<pelID> 191 */ 192 static std::string getPELFilename(uint32_t pelID, const BCDTime& time); 193 194 /** 195 * @brief Returns true if the PEL with the specified ID is in the repo. 196 * 197 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) 198 * @return bool - true if that PEL is present 199 */ hasPEL(const LogID & id)200 inline bool hasPEL(const LogID& id) 201 { 202 return findPEL(id) != _pelAttributes.end(); 203 } 204 205 /** 206 * @brief Returns the PEL data based on its ID. 207 * 208 * If the data can't be found for that ID, then the optional object 209 * will be empty. 210 * 211 * @param[in] id - the LogID to get the PEL for, which can be either a 212 * PEL ID or OpenBMC log ID. 213 * @return std::optional<std::vector<uint8_t>> - the PEL data 214 */ 215 std::optional<std::vector<uint8_t>> getPELData(const LogID& id); 216 217 /** 218 * @brief Get a file descriptor to the PEL data 219 * 220 * @param[in] id - The ID to get the FD for 221 * 222 * @return std::optional<sdbusplus::message::unix_fd> - 223 * The FD, or an empty optional object. 224 */ 225 std::optional<sdbusplus::message::unix_fd> getPELFD(const LogID& id); 226 227 using ForEachFunc = std::function<bool(const PEL&)>; 228 229 /** 230 * @brief Run a user defined function on every PEL in the repository. 231 * 232 * ForEachFunc takes a const PEL reference, and should return 233 * true to stop iterating and return out of for_each. 234 * 235 * For example, to save up to 100 IDs in the repo into a vector: 236 * 237 * std::vector<uint32_t> ids; 238 * ForEachFunc f = [&ids](const PEL& pel) { 239 * ids.push_back(pel.id()); 240 * return ids.size() == 100 ? true : false; 241 * }; 242 * 243 * @param[in] func - The function to run. 244 */ 245 void for_each(ForEachFunc func) const; 246 247 using AddCallback = std::function<void(const PEL&)>; 248 249 /** 250 * @brief Subscribe to PELs being added to the repository. 251 * 252 * Every time a PEL is added to the repository, the provided 253 * function will be called with the new PEL as the argument. 254 * 255 * The function must be of type void(const PEL&). 256 * 257 * @param[in] name - The subscription name 258 * @param[in] func - The callback function 259 */ subscribeToAdds(const std::string & name,AddCallback func)260 void subscribeToAdds(const std::string& name, AddCallback func) 261 { 262 _addSubscriptions.emplace(name, func); 263 } 264 265 /** 266 * @brief Unsubscribe from new PELs. 267 * 268 * @param[in] name - The subscription name 269 */ unsubscribeFromAdds(const std::string & name)270 void unsubscribeFromAdds(const std::string& name) 271 { 272 _addSubscriptions.erase(name); 273 } 274 275 using DeleteCallback = std::function<void(uint32_t)>; 276 277 /** 278 * @brief Subscribe to PELs being deleted from the repository. 279 * 280 * Every time a PEL is deleted from the repository, the provided 281 * function will be called with the PEL ID as the argument. 282 * 283 * The function must be of type void(const uint32_t). 284 * 285 * @param[in] name - The subscription name 286 * @param[in] func - The callback function 287 */ subscribeToDeletes(const std::string & name,DeleteCallback func)288 void subscribeToDeletes(const std::string& name, DeleteCallback func) 289 { 290 _deleteSubscriptions.emplace(name, func); 291 } 292 293 /** 294 * @brief Unsubscribe from deleted PELs. 295 * 296 * @param[in] name - The subscription name 297 */ unsubscribeFromDeletes(const std::string & name)298 void unsubscribeFromDeletes(const std::string& name) 299 { 300 _deleteSubscriptions.erase(name); 301 } 302 303 /** 304 * @brief Get the PEL attributes for a PEL 305 * 306 * @param[in] id - The ID to find the attributes for 307 * 308 * @return The attributes or an empty optional if not found 309 */ 310 std::optional<std::reference_wrapper<const PELAttributes>> 311 getPELAttributes(const LogID& id) const; 312 313 /** 314 * @brief Returns the attributes map so that others can traverse PELs. 315 * 316 * @return - A const reference to the attributes map. 317 */ getAttributesMap() const318 const std::map<LogID, PELAttributes>& getAttributesMap() const 319 { 320 return _pelAttributes; 321 } 322 323 /** 324 * @brief Sets the host transmission state on a PEL file 325 * 326 * Writes the host transmission state field in the User Header 327 * section in the PEL data specified by the ID. 328 * 329 * @param[in] pelID - The PEL ID 330 * @param[in] state - The state to write 331 */ 332 void setPELHostTransState(uint32_t pelID, TransmissionState state); 333 334 /** 335 * @brief Sets the HMC transmission state on a PEL file 336 * 337 * Writes the HMC transmission state field in the User Header 338 * section in the PEL data specified by the ID. 339 * 340 * @param[in] pelID - The PEL ID 341 * @param[in] state - The state to write 342 */ 343 void setPELHMCTransState(uint32_t pelID, TransmissionState state); 344 345 /** 346 * @brief Returns the size stats structure 347 * 348 * @return const SizeStats& - The stats structure 349 */ getSizeStats() const350 const SizeStats& getSizeStats() const 351 { 352 return _sizes; 353 } 354 355 /** 356 * @brief Says if the PEL is considered serviceable (not just 357 * informational) as determined by its severity. 358 * 359 * @param[in] pel - The PELAttributes entry for the PEL 360 * @return bool - If serviceable or not 361 */ 362 static bool isServiceableSev(const PELAttributes& pel); 363 364 /** 365 * @brief Returns true if the total amount of disk space occupied 366 * by the PELs in the repo is over 95% of the maximum 367 * size, or if there are over the maximum number of 368 * PELs allowed. 369 * 370 * @return bool - true if repo is > 95% full or too many PELs 371 */ 372 bool sizeWarning(); 373 374 /** 375 * @brief Deletes PELs to bring the repository size down 376 * to at most 90% full by placing PELs into 4 different 377 * catogories and then removing PELs until those catogories 378 * only take up certain percentages of the allowed space. 379 * 380 * This does not delete the corresponding OpenBMC event logs, which 381 * is why those IDs are returned, so they can be deleted later. 382 * 383 * The categories and their rules are: 384 * 1) Informational BMC PELs cannot take up more than 15% of 385 * the allocated space. 386 * 2) Non-informational BMC PELs cannot take up more than 30% 387 * of the allocated space. 388 * 3) Informational non-BMC PELs cannot take up more than 15% of 389 * the allocated space. 390 * 4) Non-informational non-BMC PELs cannot take up more than 30% 391 * of the allocated space. 392 * 393 * While removing PELs in a category, 4 passes will be made, with 394 * PELs being removed oldest first during each pass. 395 * 396 * Pass 1: only delete HMC acked PELs 397 * Pass 2: only delete OS acked PELs 398 * Pass 3: only delete PHYP sent PELs 399 * Pass 4: delete all PELs 400 * 401 * @param[in] ids - The OpenBMC event log Ids with hardware isolation entry. 402 * 403 * @return std::vector<uint32_t> - The OpenBMC event log IDs of 404 * the PELs that were deleted. 405 */ 406 std::vector<uint32_t> prune(const std::vector<uint32_t>& idsWithHwIsoEntry); 407 408 /** 409 * @brief Returns the path to the directory where the PEL 410 * files are stored. 411 * 412 * @return std::filesystem::path - The directory path 413 */ repoPath() const414 const std::filesystem::path& repoPath() const 415 { 416 return _logPath; 417 } 418 419 /** 420 * @brief Returns the ID of the most recently added PEL. 421 * 422 * @return uint32_t - The PEL ID 423 */ lastPelID() const424 uint32_t lastPelID() const 425 { 426 return _lastPelID; 427 } 428 429 /** 430 * @brief Get the LogID based on the given ObmcLogId or PelId. 431 * 432 * @param[in] id - The ID to find the LogID. 433 * 434 * @return The LogID or an empty optional if not found. 435 * 436 * @note The returned LogID is the fully filled in LogID, i.e. 437 * it has both the PEL and OpenBMC Log IDs, unlike the passed in LogID 438 * which can just have one or the other. 439 */ getLogID(const LogID & id) const440 std::optional<LogID> getLogID(const LogID& id) const 441 { 442 if (auto logID = findPEL(id); logID != _pelAttributes.end()) 443 { 444 return logID->first; 445 } 446 return std::nullopt; 447 } 448 449 /** 450 * @brief Save the PEL to archive folder 451 * 452 * @param[in] pel - The PEL data 453 */ 454 void archivePEL(const PEL& pel); 455 456 using PELUpdateFunc = std::function<bool(PEL&)>; 457 458 /** 459 * @brief Lets a function modify a PEL and saves the results 460 * 461 * Runs updateFunc (a bool(PEL&) function) on the PEL data 462 * on the file specified, and writes the results back to the file 463 * if the function returned true. 464 * 465 * @param[in] path - The file path to use 466 * @param[in] updateFunc - The function to run to update the PEL. 467 * 468 * @return bool - If the PEL was updated or not. 469 */ 470 bool updatePEL(const std::filesystem::path& path, PELUpdateFunc updateFunc); 471 472 private: 473 /** 474 * @brief Finds an entry in the _pelAttributes map. 475 * 476 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) 477 * 478 * @return an iterator to the entry 479 */ 480 std::map<LogID, PELAttributes>::const_iterator findPEL(const LogID & id) const481 findPEL(const LogID& id) const 482 { 483 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(), 484 [&id](const auto& a) { return a.first == id; }); 485 } 486 487 /** 488 * @brief Call any subscribed functions for new PELs 489 * 490 * @param[in] pel - The new PEL 491 */ 492 void processAddCallbacks(const PEL& pel) const; 493 494 /** 495 * @brief Call any subscribed functions for deleted PELs 496 * 497 * @param[in] id - The ID of the deleted PEL 498 */ 499 void processDeleteCallbacks(uint32_t id) const; 500 501 /** 502 * @brief Restores the _pelAttributes map on startup based on the existing 503 * PEL data files. 504 */ 505 void restore(); 506 507 /** 508 * @brief Stores a PEL object in the filesystem. 509 * 510 * @param[in] pel - The PEL to write 511 * @param[in] path - The file to write to 512 * 513 * Throws exceptions on failures. 514 */ 515 void write(const PEL& pel, const std::filesystem::path& path); 516 517 /** 518 * @brief Updates the repository statistics after a PEL is 519 * added or removed. 520 * 521 * @param[in] pel - The PELAttributes entry for the PEL 522 * @param[in] pelAdded - true if the PEL was added, false if removed 523 */ 524 void updateRepoStats(const PELAttributes& pel, bool pelAdded); 525 526 enum class SortOrder 527 { 528 ascending, 529 descending 530 }; 531 532 /** 533 * @brief Returns a vector of all the _pelAttributes entries sorted 534 * as specified 535 * 536 * @param[in] order - If the PELs should be returned in ascending 537 * (oldest first) or descending order. 538 * 539 * @return std::vector<AttributesReference> - The sorted vector of 540 * references to the pair<LogID, PELAttributes> entries of 541 * _pelAttributes. 542 */ 543 std::vector<AttributesReference> getAllPELAttributes(SortOrder order) const; 544 545 using IsOverLimitFunc = std::function<bool()>; 546 using IsPELTypeFunc = std::function<bool(const PELAttributes&)>; 547 548 /** 549 * @brief Makes 4 passes on the PELs that meet the IsPELTypeFunc 550 * criteria removing PELs until IsOverLimitFunc returns false. 551 * 552 * Pass 1: only delete HMC acked PELs 553 * Pass 2: only delete Os acked PELs 554 * Pass 3: only delete PHYP sent PELs 555 * Pass 4: delete all PELs 556 * 557 * @param[in] isOverLimit - The bool(void) function that should 558 * return true if PELs still need to be 559 * removed. 560 * @param[in] isPELType - The bool(const PELAttributes&) function 561 * used to select the PELs to operate on. 562 * @param[in] ids - The OpenBMC event log Ids with hardware isolation 563 * entry. 564 * 565 * @param[out] removedBMCLogIDs - The OpenBMC event log IDs of the 566 * removed PELs. 567 */ 568 void removePELs(const IsOverLimitFunc& isOverLimit, 569 const IsPELTypeFunc& isPELType, 570 const std::vector<uint32_t>& idsWithHwIsoEntry, 571 std::vector<uint32_t>& removedBMCLogIDs); 572 /** 573 * @brief The filesystem path to the PEL logs. 574 */ 575 const std::filesystem::path _logPath; 576 577 /** 578 * @brief A map of the PEL/OBMC IDs to PEL attributes. 579 */ 580 std::map<LogID, PELAttributes> _pelAttributes; 581 582 /** 583 * @brief Subcriptions for new PELs. 584 */ 585 std::map<std::string, AddCallback> _addSubscriptions; 586 587 /** 588 * @brief Subscriptions for deleted PELs. 589 */ 590 std::map<std::string, DeleteCallback> _deleteSubscriptions; 591 592 /** 593 * @brief The maximum amount of space that the PELs in the 594 * repository can occupy. 595 */ 596 const uint64_t _maxRepoSize; 597 598 /** 599 * @brief The maximum number of PELs to allow in the repo 600 * before pruning. 601 */ 602 const size_t _maxNumPELs; 603 604 /** 605 * @brief Statistics on the sizes of the stored PELs. 606 */ 607 SizeStats _sizes; 608 609 /** 610 * @brief The ID of the most recently added PEL. 611 */ 612 uint32_t _lastPelID = 0; 613 614 /** 615 * @brief The filesystem path to the archive PEL logs. 616 */ 617 const std::filesystem::path _archivePath; 618 619 /** 620 * @brief The size of archive folder. 621 */ 622 uint64_t _archiveSize = 0; 623 }; 624 625 } // namespace pels 626 } // namespace openpower 627