Ignore uninteresting IA/IR signals
Currently, entity-manager will parse every JSON file and do its full
D-Bus scan and probe on any interfacesAdded or interfacesRemoved signal,
without regard for which interface was added or removed.
Since the interfaces that are involved in the probes are known to
entity-manager via the Probe statements in the JSON files, it is
possible to only actually look for new or removed entities when the
signals received contain one of those interfaces.
This implements something I saw suggested in an abandoned commit[1]: to
extract the probe interfaces from the JSON files for use with the
matches. Since the argX matches can only be done when the arg is a
string, it can't build the interfaces into the match string, but it can
check for a probe interface in the message payload before doing any real
processing.
Note that the NameOwnerChanged signal doesn't contain interfaces, only
well known bus names, so no interface checking can be done against it.
I imagine some further simplification could be done, such as not also
parsing all the JSON files as part of propertiesChangedCallback(), or at
least sharing more code, if desired.
[1] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/56723
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Iaa8d30099459d8043a49879761241cf3590c3407
diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp
index f0e1c96..c28e50f 100644
--- a/src/entity_manager.cpp
+++ b/src/entity_manager.cpp
@@ -1098,6 +1098,105 @@
});
}
+// Extract the D-Bus interfaces to probe from the JSON config files.
+static std::set<std::string> getProbeInterfaces()
+{
+ std::set<std::string> interfaces;
+ std::list<nlohmann::json> configurations;
+ if (!loadConfigurations(configurations))
+ {
+ return interfaces;
+ }
+
+ for (auto it = configurations.begin(); it != configurations.end();)
+ {
+ auto findProbe = it->find("Probe");
+ if (findProbe == it->end())
+ {
+ std::cerr << "configuration file missing probe:\n " << *it << "\n";
+ it++;
+ continue;
+ }
+
+ nlohmann::json probeCommand;
+ if ((*findProbe).type() != nlohmann::json::value_t::array)
+ {
+ probeCommand = nlohmann::json::array();
+ probeCommand.push_back(*findProbe);
+ }
+ else
+ {
+ probeCommand = *findProbe;
+ }
+
+ for (const nlohmann::json& probeJson : probeCommand)
+ {
+ const std::string* probe = probeJson.get_ptr<const std::string*>();
+ if (probe == nullptr)
+ {
+ std::cerr << "Probe statement wasn't a string, can't parse";
+ continue;
+ }
+ // Skip it if the probe cmd doesn't contain an interface.
+ if (findProbeType(*probe))
+ {
+ continue;
+ }
+
+ // syntax requires probe before first open brace
+ auto findStart = probe->find('(');
+ if (findStart != std::string::npos)
+ {
+ std::string interface = probe->substr(0, findStart);
+ interfaces.emplace(interface);
+ }
+ }
+ it++;
+ }
+
+ return interfaces;
+}
+
+// Check if InterfacesAdded payload contains an iface that needs probing.
+static bool
+ iaContainsProbeInterface(sdbusplus::message_t& msg,
+ const std::set<std::string>& probeInterfaces)
+{
+ sdbusplus::message::object_path path;
+ DBusObject interfaces;
+ std::set<std::string> interfaceSet;
+ std::set<std::string> intersect;
+
+ msg.read(path, interfaces);
+
+ std::for_each(interfaces.begin(), interfaces.end(),
+ [&interfaceSet](const auto& iface) {
+ interfaceSet.insert(iface.first);
+ });
+
+ std::set_intersection(interfaceSet.begin(), interfaceSet.end(),
+ probeInterfaces.begin(), probeInterfaces.end(),
+ std::inserter(intersect, intersect.end()));
+ return !intersect.empty();
+}
+
+// Check if InterfacesRemoved payload contains an iface that needs probing.
+static bool
+ irContainsProbeInterface(sdbusplus::message_t& msg,
+ const std::set<std::string>& probeInterfaces)
+{
+ sdbusplus::message::object_path path;
+ std::set<std::string> interfaces;
+ std::set<std::string> intersect;
+
+ msg.read(path, interfaces);
+
+ std::set_intersection(interfaces.begin(), interfaces.end(),
+ probeInterfaces.begin(), probeInterfaces.end(),
+ std::inserter(intersect, intersect.end()));
+ return !intersect.empty();
+}
+
int main()
{
// setup connection to dbus
@@ -1123,6 +1222,8 @@
nlohmann::json systemConfiguration = nlohmann::json::object();
+ std::set<std::string> probeInterfaces = getProbeInterfaces();
+
// We need a poke from DBus for static providers that create all their
// objects prior to claiming a well-known name, and thus don't emit any
// org.freedesktop.DBus.Properties signals. Similarly if a process exits
@@ -1148,14 +1249,20 @@
sdbusplus::bus::match_t interfacesAddedMatch(
static_cast<sdbusplus::bus_t&>(*systemBus),
sdbusplus::bus::match::rules::interfacesAdded(),
- [&](sdbusplus::message_t&) {
- propertiesChangedCallback(systemConfiguration, objServer);
+ [&](sdbusplus::message_t& msg) {
+ if (iaContainsProbeInterface(msg, probeInterfaces))
+ {
+ propertiesChangedCallback(systemConfiguration, objServer);
+ }
});
sdbusplus::bus::match_t interfacesRemovedMatch(
static_cast<sdbusplus::bus_t&>(*systemBus),
sdbusplus::bus::match::rules::interfacesRemoved(),
- [&](sdbusplus::message_t&) {
- propertiesChangedCallback(systemConfiguration, objServer);
+ [&](sdbusplus::message_t& msg) {
+ if (irContainsProbeInterface(msg, probeInterfaces))
+ {
+ propertiesChangedCallback(systemConfiguration, objServer);
+ }
});
boost::asio::post(io, [&]() {