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`.