Convert a log entry into a SEL record

Check the DBUS logging entry for callout associations, if there
is a mapping between the inventory path and sensor number then
populate the SEL record. Otherwise log a SEL against the sytem
event sensor.

Resolves openbmc/openbmc#1516

Change-Id: I516bdac70cf39260af1744a9cdb118d763009bd5
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/configure.ac b/configure.ac
index 4e8476a..8b28ff0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,10 @@
 FRUGEN="$PYTHON $srcdir/scripts/fru_gen.py -i $FRU_YAML_GEN"
 AC_SUBST(FRUGEN)
 
+AC_DEFINE(CALLOUT_FWD_ASSOCIATION, "callout", [The name of the callout's forward association.])
+AC_DEFINE(BOARD_SENSOR, "/xyz/openbmc_project/inventory/system/chassis/motherboard", [The inventory path to the motherboard fault sensor.])
+AC_DEFINE(SYSTEM_SENSOR, "/xyz/openbmc_project/inventory/system", [The inventory path to the system event sensor.])
+
 # Soft Power off related.
 AS_IF([test "x$enable_softoff" != "xno"],
     # Dbus service name
diff --git a/selutility.cpp b/selutility.cpp
index 68226f1..0107515 100644
--- a/selutility.cpp
+++ b/selutility.cpp
@@ -3,6 +3,7 @@
 #include <phosphor-logging/elog-errors.hpp>
 #include "host-ipmid/ipmid-api.h"
 #include "xyz/openbmc_project/Common/error.hpp"
+#include "config.h"
 #include "selutility.hpp"
 #include "types.hpp"
 #include "utils.hpp"
@@ -112,6 +113,75 @@
 
 } // namespace internal
 
+GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
+{
+    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+    static constexpr auto assocIntf = "org.openbmc.Associations";
+    static constexpr auto assocProp = "associations";
+
+    auto service = ipmi::getService(bus, assocIntf, objPath);
+
+    // Read the Associations interface.
+    auto methodCall = bus.new_method_call(service.c_str(),
+                                          objPath.c_str(),
+                                          propIntf,
+                                          "Get");
+    methodCall.append(assocIntf);
+    methodCall.append(assocProp);
+
+    auto reply = bus.call(methodCall);
+    if (reply.is_method_error())
+    {
+        log<level::ERR>("Error in reading Associations interface");
+        elog<InternalFailure>();
+    }
+
+    using AssociationList = std::vector<std::tuple<
+                            std::string, std::string, std::string>>;
+
+    sdbusplus::message::variant<AssociationList> list;
+    reply.read(list);
+
+    auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>
+         (list);
+
+    /*
+     * Check if the log entry has any callout associations, if there is a
+     * callout association try to match the inventory path to the corresponding
+     * IPMI sensor.
+     */
+    for (const auto& item : assocs)
+    {
+        if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
+        {
+             auto iter = invSensors.find(std::get<2>(item));
+             if (iter == invSensors.end())
+             {
+                 iter = invSensors.find(BOARD_SENSOR);
+                 if (iter == invSensors.end())
+                 {
+                     log<level::ERR>("Motherboard sensor not found");
+                     elog<InternalFailure>();
+                 }
+             }
+
+             return internal::prepareSELEntry(objPath, iter);
+        }
+    }
+
+    // If there are no callout associations link the log entry to system event
+    // sensor
+    auto iter = invSensors.find(SYSTEM_SENSOR);
+    if (iter == invSensors.end())
+    {
+        log<level::ERR>("System event sensor not found");
+        elog<InternalFailure>();
+    }
+
+    return internal::prepareSELEntry(objPath, iter);
+}
+
 } // namespace sel
 
 } // namespace ipmi
diff --git a/selutility.hpp b/selutility.hpp
index 83ff0fd..573e89b 100644
--- a/selutility.hpp
+++ b/selutility.hpp
@@ -43,6 +43,15 @@
     uint8_t eventData3;             //!< Event Data 3.
 } __attribute__((packed));
 
+/** @brief Convert logging entry to SEL
+ *
+ *  @param[in] objPath - DBUS object path of the logging entry.
+ *
+ *  @return On success return the response of Get SEL entry command.
+ */
+GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath);
+
+
 namespace internal
 {