Fixed host count into 3(align with grpc-blob) Test result: https://paste.googleplex.com/6300373870182400?raw Google-Bug-Id: 433414984 Change-Id: I261e47cc00b1dc6b2031c4cdb98cb756aa6cccc1 Signed-off-by: Jack Huang <huangweichieh@google.com>
diff --git a/include/gen.hpp b/include/gen.hpp index 8a90959..ccb4d1d 100644 --- a/include/gen.hpp +++ b/include/gen.hpp
@@ -24,53 +24,17 @@ namespace btm = boot_time_monitor; /** - * @brief Generates the PSM (Platform State Manager) configuration for a - * specific node. + * @brief Generates the PSM D-Bus configuration for a specific host. * - * This function determines the correct D-Bus service names and object paths - * for monitoring host state and OS status based on whether the system is - * single-host or multi-host. For multi-host systems, it uses the node's - * index within the provided list to construct unique identifiers. + * This function constructs the necessary D-Bus service names and object paths + * for the phosphor-state-manager (PSM) based on a host's numerical index. + * This configuration is used to monitor host state and OS status changes. * - * @param nodeConfigs A vector containing the configurations of all nodes. - * @param nodeConfig The configuration of the specific node for which to - * generate the PSM config. - * @return psm::PSMConfig The generated PSM configuration containing D-Bus - * service names and object paths. Returns an empty - * config if the node is not found or the list is empty. + * @param idx The zero-based index of the host. + * @return psm::PSMConfig The generated PSM configuration. */ -inline psm::PSMConfig - GenPSMConfig(const std::vector<btm::NodeConfig>& nodeConfigs, - const btm::NodeConfig& nodeConfig) +inline psm::PSMConfig GenPSMConfig(int idx) { - if (nodeConfigs.empty()) - { - fmt::print("[{}] node list is empty!\n", __FUNCTION__); - return {}; - } - - // Singlehost rule - if (nodeConfigs.size() == 1) - { - return { - .hostStateDbusService = "xyz.openbmc_project.State.Host", - .hostStateDbusObjPath = "/xyz/openbmc_project/state/host0", - .osStateDbusService = "xyz.openbmc_project.State.OperatingSystem", - .osStateDbusObjPath = "/xyz/openbmc_project/state/os", - }; - } - - // Multihost platforms have a different PSM Dbus Service and Path rule. - // Create dBus path depends on its relative indices. - auto it = std::find(nodeConfigs.begin(), nodeConfigs.end(), nodeConfig); - if (it == nodeConfigs.end()) - { - fmt::print("[{}] node config not found!\n", __FUNCTION__); - return {}; - } - - int64_t idx = std::distance(nodeConfigs.begin(), it) + 1; - return { .hostStateDbusService = fmt::format("xyz.openbmc_project.State.Host{}", idx), @@ -92,7 +56,7 @@ * @return dbus::DbusConfig The generated D-Bus configuration containing the * object path. */ -inline dbus::DbusConfig GenDbusConfig(const NodeConfig& nodeConfig) +inline dbus::DbusConfig GenDbusConfig(const btm::NodeConfig& nodeConfig) { return {.dbusObjPath = fmt::format("/xyz/openbmc_project/time/boot/{}", nodeConfig.node_name)};
diff --git a/include/psm_handler.hpp b/include/psm_handler.hpp index d00d83b..aa4c2a0 100644 --- a/include/psm_handler.hpp +++ b/include/psm_handler.hpp
@@ -3,7 +3,9 @@ #include "boottime_api/boottime_api.h" #include "boottime_api/node_config.h" +#include <boost/asio/steady_timer.hpp> #include <boost/container/flat_map.hpp> +#include <sdbusplus/asio/connection.hpp> #include <sdbusplus/bus.hpp> #include <sdbusplus/bus/match.hpp> #include <sdbusplus/message.hpp> @@ -75,20 +77,24 @@ std::shared_ptr<btm::api::IBoottimeApi> api); private: - /** @brief D-Bus match rule watcher for Host State property changes. */ - std::unique_ptr<sdbusplus::bus::match::match> hostStateWatcher; - /** @brief D-Bus match rule watcher for OS Status property changes. */ - std::unique_ptr<sdbusplus::bus::match::match> osStatusWatcher; + /** @brief Callback for hostStateWatcher */ + void hostStateWatcherCallback(sdbusplus::message::message& message); + /** @brief Callback for oSStatusWatcher */ + void oSStatusWatcherCallback(sdbusplus::message::message& message); /** @brief Stores the previously observed Host State to detect changes. */ std::string mPreHostState; /** @brief Stores the previously observed OS State/Status to detect changes. */ - std::string mPreOSState; + std::string mPreOSStatus; /** @brief Configuration of the node associated with this handler. */ btm::NodeConfig mNodeConfig; /** @brief Shared pointer to the central boot time monitoring API. */ std::shared_ptr<btm::api::IBoottimeApi> mApi; + /** @brief D-Bus match rule watcher for Host State property changes. */ + std::unique_ptr<sdbusplus::bus::match::match> mHostStateWatcher; + /** @brief D-Bus match rule watcher for OS Status property changes. */ + std::unique_ptr<sdbusplus::bus::match::match> mOSStatusWatcher; }; } // namespace psm } // namespace boot_time_monitor
diff --git a/src/main.cpp b/src/main.cpp index 33920b1..acea6a6 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -46,22 +46,26 @@ * */ +constexpr int64_t kDefaultHostCount = 3; // Align with grpc-blobs default value +constexpr int64_t kDefaultBMCCount = 1; // Default BMC count + void print_usage(const char* prog_name) { fmt::print(stderr, "Usage: {} [options]\n", prog_name); fmt::print(stderr, "Options:\n"); fmt::print(stderr, " -h, --help Show this help message and exit\n"); - fmt::print(stderr, - " --host_count <num> Set number of hosts (default: 1)\n"); + fmt::print( + stderr, + " --host_count <num> Set number of hosts (optional, queries DBus if not set)\n"); fmt::print(stderr, " --bmc_count <num> Set number of BMCs (default: 1)\n"); } int main(int argc, char* argv[]) { - int64_t hostCount = 1; // Default host count - int64_t bmcCount = 1; // Default BMC count + int64_t hostCount = kDefaultHostCount; + int64_t bmcCount = kDefaultBMCCount; const struct option long_options[] = { {"help", no_argument, nullptr, 'h'}, @@ -71,8 +75,8 @@ int opt; int option_index = 0; - while ((opt = getopt_long(argc, argv, "h", long_options, &option_index)) != - -1) + while ((opt = getopt_long(argc, argv, "ho:b:", long_options, + &option_index)) != -1) { switch (opt) { @@ -80,28 +84,59 @@ print_usage(argv[0]); return 0; case 'o': - hostCount = std::strtol(optarg, nullptr, 10); + try + { + hostCount = std::stoi(optarg); + if (hostCount < 0) + { + fmt::print( + stderr, + "Warning: host_count should be non-negative. Using default {}.\n", + kDefaultHostCount); + hostCount = kDefaultHostCount; + } + } + catch (const std::exception& e) + { + fmt::print( + stderr, + "Error parsing host_count: {}. Using default {}.\n", + e.what(), kDefaultHostCount); + hostCount = kDefaultHostCount; + } break; case 'b': - bmcCount = std::strtol(optarg, nullptr, 10); + try + { + bmcCount = std::stoi(optarg); + if (bmcCount <= 0) + { + fmt::print( + stderr, + "Warning: bmc_count must be positive. Using default {}.\n", + kDefaultBMCCount); + bmcCount = kDefaultBMCCount; + } + fmt::print(stdout, "Using provided bmc count: {}\n", + bmcCount); + } + catch (const std::exception& e) + { + fmt::print( + stderr, + "Error parsing bmc_count: {}. Using default {}.\n", + e.what(), kDefaultBMCCount); + bmcCount = kDefaultBMCCount; + } break; default: /* '?' */ print_usage(argv[0]); return 1; } } - if (hostCount < 0) - { - fmt::print(stderr, "hostCount({}) must be greater than zero.\n", - hostCount); - return 1; - } - if (bmcCount < 0) - { - fmt::print(stderr, "bmcCount({}) must be greater than zero.\n", - bmcCount); - return 1; - } + + fmt::print(stdout, "Host count: {}\n", hostCount); + fmt::print(stdout, "BMC count: {}\n", bmcCount); boost::asio::io_service io; auto conn = std::make_shared<sdbusplus::asio::connection>(io); @@ -115,7 +150,7 @@ std::vector<std::unique_ptr<btm::dbus::Handler>> hostDbusHandlers; std::vector<std::unique_ptr<btm::dbus::Handler>> bmcDbusHandlers; - std::vector<btm::psm::Handler> psmHandlers; + std::vector<std::unique_ptr<btm::psm::Handler>> psmHandlers; std::shared_ptr<btm::api::BoottimeApi> api = std::make_shared<btm::api::BoottimeApi>(); @@ -134,18 +169,30 @@ std::string(btm::kBootTimeTagBMC)); } - for (auto& nodeConfig : hostNodeConfigs) + hostDbusHandlers.reserve(hostCount); + psmHandlers.reserve(hostCount + 1); // extra psm handler for single host + for (int i = 0; i < hostCount; i++) { + auto& nodeConfig = hostNodeConfigs[i]; absl::Status status = api->RegisterNode(nodeConfig); btm::log::LogIfError(status); hostDbusHandlers.emplace_back(std::make_unique<btm::dbus::Handler>( bus, nodeConfig, btm::gen::GenDbusConfig(nodeConfig), api)); - psmHandlers.emplace_back( - bus, nodeConfig, - btm::gen::GenPSMConfig(hostNodeConfigs, nodeConfig), api); + if (i == 0) + { + // Register an extra PSM handler for host 0, which is a common + // convention for a single-host system. In a multi-host + // configuration where this D-Bus service might not exist. + psmHandlers.emplace_back(std::make_unique<btm::psm::Handler>( + bus, hostNodeConfigs[0], btm::gen::GenPSMConfig(0), api)); + } + psmHandlers.emplace_back(std::make_unique<btm::psm::Handler>( + bus, nodeConfig, btm::gen::GenPSMConfig(i + 1), + api)); // PSMConfig using 1-based index. } + bmcDbusHandlers.reserve(bmcCount); for (auto& nodeConfig : bmcNodeConfigs) { absl::Status status = api->RegisterNode(nodeConfig);
diff --git a/src/psm_handler.cpp b/src/psm_handler.cpp index f19b258..1ecac5f 100644 --- a/src/psm_handler.cpp +++ b/src/psm_handler.cpp
@@ -29,25 +29,21 @@ return std::string("OSStatus:") + std::string(status.substr(found + 1)); } -Handler::Handler(sdbusplus::bus::bus& bus, const btm::NodeConfig& nodeConfig, - const btm::psm::PSMConfig& psmConfig, - std::shared_ptr<btm::api::IBoottimeApi> api) : - mNodeConfig(nodeConfig), mApi(std::move(api)) +std::string inline queryHostState(sdbusplus::bus::bus& bus, + const btm::psm::PSMConfig& psmConfig) { - // Initialize mPreHostState + std::string hostState; + BasicVariantType result; auto method = bus.new_method_call(psmConfig.hostStateDbusService.c_str(), // Service psmConfig.hostStateDbusObjPath.c_str(), // Path "org.freedesktop.DBus.Properties", // Iface "Get"); // Function method.append("xyz.openbmc_project.State.Host", "CurrentHostState"); - BasicVariantType result; try { bus.call(method).read(result); - mPreHostState = std::get<std::string>(result); - fmt::print("{} `CurrentHostState` is `{}`\n", mNodeConfig.node_name, - mPreHostState); + hostState = std::get<std::string>(result); } catch (const sdbusplus::exception::SdBusError& e) { @@ -59,37 +55,15 @@ psmConfig.hostStateDbusService, psmConfig.hostStateDbusObjPath, e.what()); } + return hostState; +} - hostStateWatcher = std::make_unique<sdbusplus::bus::match::match>( - bus, - sdbusplus::bus::match::rules::propertiesChanged( - psmConfig.hostStateDbusObjPath, "xyz.openbmc_project.State.Host"), - [this](sdbusplus::message::message& message) { - std::string objectName; - boost::container::flat_map< - std::string, - std::variant<std::string, bool, int64_t, uint64_t, double>> - values; - message.read(objectName, values); - - auto findState = values.find("CurrentHostState"); - if (findState != values.end()) - { - const std::string curHostState = - std::get<std::string>(findState->second); - fmt::print( - stderr, - "[hostStateWatcher] {} `CurrentHostState` has changed from {} to {}\n", - mNodeConfig.node_name, mPreHostState, curHostState); - absl::Status status = mApi->SetNodeCheckpoint( - mNodeConfig, translateHostStateName(curHostState), 0, 0); - btm::log::LogIfError(status); - mPreHostState = curHostState; - } - }); - - // Initialize mPreOSState - method = +std::string inline queryOSStatus(sdbusplus::bus::bus& bus, + const btm::psm::PSMConfig& psmConfig) +{ + std::string oSState; + BasicVariantType result; + auto method = bus.new_method_call(psmConfig.osStateDbusService.c_str(), // Service psmConfig.osStateDbusObjPath.c_str(), // Path "org.freedesktop.DBus.Properties", // Iface @@ -99,9 +73,7 @@ try { bus.call(method).read(result); - mPreOSState = std::get<std::string>(result); - fmt::print("{} `OperatingSystemState` is `{}`\n", mNodeConfig.node_name, - mPreOSState); + oSState = std::get<std::string>(result); } catch (const sdbusplus::exception::SdBusError& e) { @@ -113,36 +85,133 @@ psmConfig.hostStateDbusService, psmConfig.hostStateDbusObjPath, e.what()); } + return oSState; +} - osStatusWatcher = std::make_unique<sdbusplus::bus::match::match>( +std::string inline queryNameOwner(sdbusplus::bus::bus& bus, + const btm::psm::PSMConfig& psmConfig) +{ + std::string ownerUniqueName; + try + { + auto method = + bus.new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", + "org.freedesktop.DBus", "GetNameOwner"); + method.append(std::string(psmConfig.osStateDbusService)); + bus.call(method).read(ownerUniqueName); + } + catch (const sdbusplus::exception::SdBusError& e) + { + // This name isn't owned by anyone right now, so we can ignore this + // signal. + } + return ownerUniqueName; +} + +Handler::Handler(sdbusplus::bus::bus& bus, const btm::NodeConfig& nodeConfig, + const btm::psm::PSMConfig& psmConfig, + std::shared_ptr<btm::api::IBoottimeApi> api) : + mNodeConfig(nodeConfig), mApi(std::move(api)) +{ + mPreHostState = queryHostState(bus, psmConfig); + fmt::print("{} `CurrentHostState` is `{}`\n", mNodeConfig.node_name, + mPreHostState); + mHostStateWatcher = std::make_unique<sdbusplus::bus::match::match>( + bus, + sdbusplus::bus::match::rules::propertiesChanged( + psmConfig.hostStateDbusObjPath, "xyz.openbmc_project.State.Host"), + [this](sdbusplus::message::message& message) { + hostStateWatcherCallback(message); + }); + + mPreOSStatus = queryOSStatus(bus, psmConfig); + fmt::print("{} `OperatingSystemState` is `{}`\n", mNodeConfig.node_name, + mPreOSStatus); + mOSStatusWatcher = std::make_unique<sdbusplus::bus::match::match>( bus, sdbusplus::bus::match::rules::propertiesChanged( psmConfig.osStateDbusObjPath, "xyz.openbmc_project.State.OperatingSystem.Status"), - [this](sdbusplus::message::message& message) { - std::string objectName; - boost::container::flat_map< - std::string, - std::variant<std::string, bool, int64_t, uint64_t, double>> - values; - message.read(objectName, values); - - auto findState = values.find("OperatingSystemState"); - if (findState != values.end()) + [this, &bus, psmConfig](sdbusplus::message::message& message) { + const std::string& signalSenderUniqueName = message.get_sender(); + std::string ownerUniqueName = queryNameOwner(bus, psmConfig); + // Compare the signal's sender to the name's rightful owner. + if (signalSenderUniqueName != ownerUniqueName) { - const std::string curOSStatus = - std::get<std::string>(findState->second); - - fmt::print( - stderr, - "[osStatusWatcher] {} `OperatingSystemState` has changed from {} to {}\n", - mNodeConfig.node_name, mPreOSState, curOSStatus); - absl::Status status = mApi->SetNodeCheckpoint( - mNodeConfig, translateOSStatus(curOSStatus), 0, 0); - btm::log::LogIfError(status); - mPreOSState = curOSStatus; + return; // The signal came from a different process. Ignore it. } + oSStatusWatcherCallback(message); }); } + +void Handler::hostStateWatcherCallback(sdbusplus::message::message& message) +{ + fmt::print(stdout, "[mHostStateWatcher] Signal from {}\n", + mNodeConfig.node_name); + std::string objectName; + boost::container::flat_map< + std::string, std::variant<std::string, bool, int64_t, uint64_t, double>> + values; + message.read(objectName, values); + + auto findState = values.find("CurrentHostState"); + if (findState != values.end()) + { + const std::string curHostState = + std::get<std::string>(findState->second); + if (curHostState == mPreHostState) + { + return; + } + + fmt::print( + stdout, + "[mHostStateWatcher] {} `CurrentHostState` has changed from {} to {}\n", + mNodeConfig.node_name, mPreHostState, curHostState); + absl::Status status = mApi->SetNodeCheckpoint( + mNodeConfig, translateHostStateName(curHostState), 0, 0); + btm::log::LogIfError(status); + mPreHostState = curHostState; + fmt::print( + stdout, + "[mHostStateWatcher] {} `CurrentHostState` {} checkpoint has been recorded\n", + mNodeConfig.node_name, curHostState); + } +} + +void Handler::oSStatusWatcherCallback(sdbusplus::message::message& message) +{ + fmt::print(stdout, "[mOSStatusWatcher] Signal from {}.\n", + mNodeConfig.node_name); + std::string objectName; + boost::container::flat_map< + std::string, std::variant<std::string, bool, int64_t, uint64_t, double>> + values; + message.read(objectName, values); + + auto findState = values.find("OperatingSystemState"); + if (findState != values.end()) + { + const std::string curOSStatus = + std::get<std::string>(findState->second); + if (curOSStatus == mPreOSStatus) + { + return; + } + + fmt::print( + stdout, + "[mOSStatusWatcher] {} `OperatingSystemState` has changed from {} to {}\n", + mNodeConfig.node_name, mPreOSStatus, curOSStatus); + absl::Status status = mApi->SetNodeCheckpoint( + mNodeConfig, translateOSStatus(curOSStatus), 0, 0); + btm::log::LogIfError(status); + mPreOSStatus = curOSStatus; + fmt::print( + stdout, + "[mOSStatusWatcher] {} `OperatingSystemState` {} checkpoint has been recorded\n", + mNodeConfig.node_name, curOSStatus); + } +} } // namespace psm } // namespace boot_time_monitor
diff --git a/src/systemd_handler.cpp b/src/systemd_handler.cpp index ccf5f53..1893002 100644 --- a/src/systemd_handler.cpp +++ b/src/systemd_handler.cpp
@@ -235,6 +235,7 @@ SystemdDurations durationMap = CalculateSystemdDuration(times); #ifdef NPCM7XX_OR_NEWER + fmt::print(stderr, "NPCM7XX_OR_NEWER applied"); // NPCM7XX or newer Nuvoton BMC has a register that starts counting from // SoC power on. Also uptime starts counting when kernel is up. Thus we // can get (Firmware + Loader) time by `value[SEC_CNT_ADDR] - uptime`.