Enable reducing the number of sensors managed by IPMI

IPMI is only able to support a finite amount of SDR records. Modern
servers are capable of exceeding the number of sensors the IPMI
specification can support.

The change made in this commit filters sensors from a service based
upon contents in a JSON configuration file.

Tested:
Confirmed the default compile resulted in too many sensors being
created.
Added the 'sensor_filter.json' file and confirmed the number of
sensors was reduced, and 'ipmitool sdr list' no longer exhibited error
messages.

Change-Id: I3643e06abbb8708d3f4000f35c79be8901e34057
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
diff --git a/dbus-sdr/sdrutils.cpp b/dbus-sdr/sdrutils.cpp
index d148d9a..65f651b 100644
--- a/dbus-sdr/sdrutils.cpp
+++ b/dbus-sdr/sdrutils.cpp
@@ -16,6 +16,9 @@
 
 #include "dbus-sdr/sdrutils.hpp"
 
+#include <nlohmann/json.hpp>
+
+#include <fstream>
 #include <optional>
 #include <unordered_set>
 
@@ -34,6 +37,43 @@
 
 namespace details
 {
+
+// IPMI supports a smaller number of sensors than are available via Redfish.
+// Trim the list of sensors, via a configuration file.
+// Read the IPMI Sensor Filtering section in docs/configuration.md for
+// a more detailed description.
+static void filterSensors(SensorSubTree& subtree)
+{
+    constexpr const char* filterFilename =
+        "/usr/share/ipmi-providers/sensor_filter.json";
+    std::ifstream filterFile(filterFilename);
+    if (!filterFile.good())
+    {
+        return;
+    }
+    nlohmann::json sensorFilterJSON = nlohmann::json::parse(filterFile, nullptr,
+                                                            false);
+    nlohmann::json::iterator svcFilterit =
+        sensorFilterJSON.find("ServiceFilter");
+    if (svcFilterit == sensorFilterJSON.end())
+    {
+        return;
+    }
+
+    subtree.erase(std::remove_if(subtree.begin(), subtree.end(),
+                                 [svcFilterit](SensorSubTree::value_type& kv) {
+        auto& [_, serviceToIfaces] = kv;
+
+        for (auto service = svcFilterit->begin(); service != svcFilterit->end();
+             ++service)
+        {
+            serviceToIfaces.erase(*service);
+        }
+        return serviceToIfaces.empty();
+    }),
+                  subtree.end());
+}
+
 uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
 {
     static std::shared_ptr<SensorSubTree> sensorTreePtr;
@@ -136,6 +176,7 @@
         return sensorUpdatedIndex;
     }
 
+    filterSensors(*sensorTreePtr);
     // Add VR control as optional search path.
     (void)lbdUpdateSensorTree("/xyz/openbmc_project/vr", vrInterfaces);
 
diff --git a/docs/configuration.md b/docs/configuration.md
index b1656f7..061e3d5 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -21,3 +21,38 @@
 get_device_id. The data is then cached for future use. If you change the data at
 runtime, simply restart the service to see the new data fetched by a call to
 get_device_id.
+
+# IPMI D-Bus Sensor Filtering
+
+Phosphor-ipmi-host provides a compile time option to control how IPMI sensors
+are populated. The default model is for the sensors to be culled from a set of
+JSON files. There is another model that collects the sensors to display from
+D-Bus. The D-Bus method is the default mode used by Redfish. Redfish does not
+have a fixed limit on the number of sensors that can be reported.
+
+IPMI supports a smaller number of sensors than are available via Redfish. The
+limit being the number of Sensor Data Records (SDR) supported in the IPMI
+specification. Enabling IPMI to use D-Bus may cause the number of sensors
+retrieved to exceed the number SDRs IPMI can support. Even if the number of
+sensors retrieved is within the SDR limit IPMI can support, it may be desirable
+to filter entries that are uninteresting.
+
+Meson uses the _dyanmic-sensors_ configuration option to enable retrieving the
+sensors via D-Bus. When dynamic sensors are active all of the sensors placed on
+D-Bus by a service are added to the IPMI sensor list. In the event that too many
+sensors are exposed on D-Bus, the list can be filtered by adding a list of
+services to filter to _/usr/share/ipmi-providers/sensor_filter.json_.
+
+Example filtering:
+
+```json
+{
+  "ServiceFilter": [
+    "xyz.openbmc_project.RedfishSensors1",
+    "xyz.openbmc_project.RedfishSensors2"
+  ]
+}
+```
+
+Any sensors published by the example services are blocked from being added to
+the IPMI SDR table.