metrics-ipmi-blobs: Support ECC Error Counts

Export the ECC Error Cournter from
http://github.com/openbmc/phosphor-ecc to ipmi blob.

Tested:
The blob output is updated if MemoryECC dbus object exists compared to
the blob output if MemoryECC doesn't exists.

Change-Id: I2c63dbcd0970afc587f5c2ee01f8c261909f0b08
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/subprojects/metrics-ipmi-blobs/metric.cpp b/subprojects/metrics-ipmi-blobs/metric.cpp
index 4b21347..59954c4 100644
--- a/subprojects/metrics-ipmi-blobs/metric.cpp
+++ b/subprojects/metrics-ipmi-blobs/metric.cpp
@@ -314,6 +314,20 @@
     };
 }
 
+static bmcmetrics_metricproto_BmcECCMetric getECCMetric(bool& use) noexcept
+{
+    EccCounts eccCounts;
+    use = getECCErrorCounts(eccCounts);
+    if (!use)
+    {
+        return {};
+    }
+    return bmcmetrics_metricproto_BmcECCMetric{
+        .correctable_error_count = eccCounts.correctableErrCount,
+        .uncorrectable_error_count = eccCounts.uncorrectableErrCount,
+    };
+}
+
 static bmcmetrics_metricproto_BmcMemoryMetric getMemMetric() noexcept
 {
     bmcmetrics_metricproto_BmcMemoryMetric ret = {};
@@ -460,6 +474,8 @@
         .has_fdstat_metric = false,
         .fdstat_metric = getFdStatMetric(*this, ticksPerSec, fds,
                                          snapshot.has_fdstat_metric),
+        .has_ecc_metric = false,
+        .ecc_metric = getECCMetric(snapshot.has_ecc_metric),
     };
     pb_ostream_t nost = {};
     if (!pb_encode(&nost, bmcmetrics_metricproto_BmcMetricSnapshot_fields,
diff --git a/subprojects/metrics-ipmi-blobs/metricblob.proto b/subprojects/metrics-ipmi-blobs/metricblob.proto
index 9842692..4d3038f 100644
--- a/subprojects/metrics-ipmi-blobs/metricblob.proto
+++ b/subprojects/metrics-ipmi-blobs/metricblob.proto
@@ -61,6 +61,11 @@
   repeated StringEntry entries = 10;
 }
 
+message BmcECCMetric {
+  int32 correctable_error_count = 1;
+  int32 uncorrectable_error_count = 2;
+}
+
 message BmcMetricSnapshot {
   BmcStringTable string_table = 1;
   BmcMemoryMetric memory_metric = 2;
@@ -68,4 +73,7 @@
   BmcDiskSpaceMetric storage_space_metric = 4;
   BmcProcStatMetric procstat_metric = 5;
   BmcFdStatMetric fdstat_metric = 6;
+  reserved 7;
+  reserved 8;
+  BmcECCMetric ecc_metric = 9;
 }
diff --git a/subprojects/metrics-ipmi-blobs/util.cpp b/subprojects/metrics-ipmi-blobs/util.cpp
index 5bfc9c8..0e14698 100644
--- a/subprojects/metrics-ipmi-blobs/util.cpp
+++ b/subprojects/metrics-ipmi-blobs/util.cpp
@@ -348,4 +348,52 @@
     return true;
 }
 
+bool getECCErrorCounts(EccCounts& eccCounts)
+{
+    std::vector<
+        std::pair<std::string, std::variant<uint64_t, uint8_t, std::string>>>
+        values;
+    try
+    {
+        auto bus = sdbusplus::bus::new_default_system();
+        auto m =
+            bus.new_method_call("xyz.openbmc_project.memory.ECC",
+                                "/xyz/openbmc_project/metrics/memory/BmcECC",
+                                "org.freedesktop.DBus.Properties", "GetAll");
+        m.append("xyz.openbmc_project.Memory.MemoryECC");
+        auto reply = bus.call(m);
+        reply.read(values);
+    }
+    catch (const sdbusplus::exception::SdBusError& ex)
+    {
+        return false;
+    }
+    bool hasCorrectable = false;
+    bool hasUncorrectable = false;
+    for (const auto& [key, value] : values)
+    {
+        if (key == "ceCount")
+        {
+            eccCounts.correctableErrCount =
+                static_cast<int32_t>(std::get<uint64_t>(value));
+            hasCorrectable = true;
+            if (hasUncorrectable)
+            {
+                return true;
+            }
+        }
+        if (key == "ueCount")
+        {
+            eccCounts.uncorrectableErrCount =
+                static_cast<int32_t>(std::get<uint64_t>(value));
+            hasUncorrectable = true;
+            if (hasCorrectable)
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 } // namespace metric_blob
diff --git a/subprojects/metrics-ipmi-blobs/util.hpp b/subprojects/metrics-ipmi-blobs/util.hpp
index 642e0f2..f3ad222 100644
--- a/subprojects/metrics-ipmi-blobs/util.hpp
+++ b/subprojects/metrics-ipmi-blobs/util.hpp
@@ -55,4 +55,12 @@
 char controlCharsToSpace(char c);
 std::string trimStringRight(std::string_view s);
 
+struct EccCounts
+{
+    int32_t correctableErrCount;
+    int32_t uncorrectableErrCount;
+};
+
+bool getECCErrorCounts(EccCounts& eccCounts);
+
 } // namespace metric_blob