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);