| #include "tlbmc/metrics/bmc_static_metrics.h" |
| |
| #include <sys/sysinfo.h> |
| #include <systemd/sd-id128.h> |
| |
| #include <array> |
| #include <cstdint> |
| #include <filesystem> // NOLINT |
| #include <fstream> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <system_error> // NOLINT |
| |
| #include "absl/memory/memory.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/str_cat.h" |
| #include "g3/macros.h" |
| #include "openssl/sha.h" |
| |
| namespace milotic_tlbmc { |
| |
| constexpr std::string_view kOsReleasePath = "/etc/os-release"; |
| constexpr std::string_view kBmcFirmwareVersionKey = "VERSION_ID="; |
| constexpr std::string_view kBmcRofsFlashIdPath = "/run/media"; |
| |
| absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcFirmwareVersion( |
| std::string_view root_path) { |
| std::error_code ec; |
| if (!std::filesystem::exists( |
| std::filesystem::path(absl::StrCat(root_path, kOsReleasePath)), ec)) { |
| return absl::InternalError("/etc/os-release does not exist"); |
| } |
| |
| std::ifstream os_release_stream(absl::StrCat(root_path, kOsReleasePath)); |
| if (!os_release_stream.good()) { |
| return absl::InternalError("Failed to open /etc/os-release."); |
| } |
| |
| while (os_release_stream.good()) { |
| std::string line; |
| std::getline(os_release_stream, line); |
| if (line.starts_with(kBmcFirmwareVersionKey)) { |
| return line.substr(kBmcFirmwareVersionKey.length()); |
| } |
| } |
| return absl::InternalError("Failed to find VERSION_ID in /etc/os-release."); |
| } |
| |
| absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcFirmwareFlashId( |
| std::string_view root_path) { |
| std::error_code bmc_rofs_flash_id_dir_exists_ec; |
| if (!std::filesystem::exists( |
| std::filesystem::path(absl::StrCat(root_path, kBmcRofsFlashIdPath)), |
| bmc_rofs_flash_id_dir_exists_ec)) { |
| return absl::InternalError("/run/media does not exist"); |
| } |
| |
| std::error_code bmc_rofs_flash_id_dir_iter_ec; |
| for (std::filesystem::directory_iterator dir_iter( |
| std::filesystem::path(absl::StrCat(root_path, kBmcRofsFlashIdPath)), |
| bmc_rofs_flash_id_dir_iter_ec); |
| dir_iter != std::filesystem::directory_iterator(); ++dir_iter) { |
| // Strip the rofs- prefix from the directory name to get the flash id. |
| if (dir_iter->is_directory() && |
| dir_iter->path().filename().string().starts_with("rofs-")) { |
| return dir_iter->path().filename().string().substr(5); |
| } |
| } |
| return absl::InternalError( |
| "Failed to find BMC rofs firmware flash id under /run/media"); |
| } |
| |
| absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcFirmwareVersionId( |
| std::string_view root_path, std::string_view bmc_firmware_version) { |
| ECCLESIA_ASSIGN_OR_RETURN(std::string bmc_firmware_flash_id, |
| FetchBmcFirmwareFlashId(root_path)); |
| |
| std::string version_to_hash = |
| absl::StrCat(bmc_firmware_version, bmc_firmware_flash_id); |
| |
| // This code is to generate the BMC firmware version ID. The format is |
| // The logic is extracted from |
| // https://github.com/openbmc/phosphor-bmc-code-mgmt/blob/de331ae49afd6fe27271c4081ffa239746bda8b5/bmc/version.cpp#L104 |
| |
| std::array<uint8_t, SHA512_DIGEST_LENGTH> digest; |
| SHA512(reinterpret_cast<const uint8_t*>(version_to_hash.data()), |
| version_to_hash.size(), digest.data()); |
| |
| // We are only using the first 8 characters. |
| std::string version_id = absl::StrCat(absl::Hex(digest[0], absl::kZeroPad2), |
| absl::Hex(digest[1], absl::kZeroPad2), |
| absl::Hex(digest[2], absl::kZeroPad2), |
| absl::Hex(digest[3], absl::kZeroPad2)); |
| return version_id; |
| } |
| |
| absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcUuid() { |
| std::string uuid; |
| // This ID needs to match the one in ipmid |
| sd_id128_t app_id{{0Xe0, 0Xe1, 0X73, 0X76, 0X64, 0X61, 0X47, 0Xda, 0Xa5, 0X0c, |
| 0Xd0, 0Xcc, 0X64, 0X12, 0X45, 0X78}}; |
| sd_id128_t machine_id{}; |
| if (sd_id128_get_machine_app_specific(app_id, &machine_id) == 0) { |
| std::array<char, SD_ID128_STRING_MAX> str{}; |
| uuid = sd_id128_to_string(machine_id, str.data()); |
| uuid.insert(8, 1, '-'); |
| uuid.insert(13, 1, '-'); |
| uuid.insert(18, 1, '-'); |
| uuid.insert(23, 1, '-'); |
| } |
| return uuid; |
| } |
| |
| absl::StatusOr<std::unique_ptr<BmcStaticMetrics>> BmcStaticMetrics::Create( |
| std::string_view root_path) { |
| ECCLESIA_ASSIGN_OR_RETURN(std::string bmc_firmware_version, |
| FetchBmcFirmwareVersion(root_path)); |
| ECCLESIA_ASSIGN_OR_RETURN( |
| std::string bmc_firmware_version_id, |
| FetchBmcFirmwareVersionId(root_path, bmc_firmware_version)); |
| |
| ECCLESIA_ASSIGN_OR_RETURN(std::string bmc_uuid, FetchBmcUuid()); |
| |
| return absl::WrapUnique(new BmcStaticMetrics( |
| bmc_firmware_version, bmc_firmware_version_id, bmc_uuid)); |
| } |
| |
| std::string BmcStaticMetrics::GetBmcFirmwareVersion() const { |
| return bmc_firmware_version_; |
| } |
| |
| std::string BmcStaticMetrics::GetBmcFirmwareVersionId() const { |
| return bmc_firmware_version_id_; |
| } |
| |
| std::string BmcStaticMetrics::GetBmcUuid() const { return bmc_uuid_; } |
| |
| } // namespace milotic_tlbmc |