Implement sendTrap function

This function gets all the objects from the specific
notification class and send the snmp trap using the
netsnmp lib functions.

This commt adds the configure, makefile, bootstrap.sh,
clangformat file.

Add the unit test cases for ErrorNotification unit.

Change-Id: I2e982f18eb2745f2c0c8de0702cc85d12e80f6e3
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/snmp_notification.cpp b/snmp_notification.cpp
new file mode 100644
index 0000000..e27408a
--- /dev/null
+++ b/snmp_notification.cpp
@@ -0,0 +1,142 @@
+#include "snmp_notification.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+
+#include "xyz/openbmc_project/Common/error.hpp"
+
+namespace phosphor
+{
+namespace network
+{
+namespace snmp
+{
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+using snmpSessionPtr =
+    std::unique_ptr<netsnmp_session, decltype(&::snmp_close)>;
+
+bool Notification::addPDUVar(netsnmp_pdu& pdu, const OID& objID,
+                             size_t objIDLen, u_char type, Value val)
+{
+    netsnmp_variable_list* varList = nullptr;
+    switch (type)
+    {
+        case ASN_INTEGER:
+        {
+            auto ltmp = val.get<int32_t>();
+            varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type,
+                                            &ltmp, sizeof(ltmp));
+        }
+        break;
+        case ASN_UNSIGNED:
+        {
+            auto ltmp = val.get<uint32_t>();
+            varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type,
+                                            &ltmp, sizeof(ltmp));
+        }
+        break;
+        case ASN_OPAQUE_U64:
+        {
+            auto ltmp = val.get<uint64_t>();
+            varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type,
+                                            &ltmp, sizeof(ltmp));
+        }
+        break;
+        case ASN_OCTET_STR:
+        {
+            auto value = val.get<std::string>();
+            varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type,
+                                            value.c_str(), value.length());
+        }
+        break;
+    }
+    return (varList == nullptr ? false : true);
+}
+
+void Notification::sendTrap()
+{
+    log<level::DEBUG>("Sending SNMP Trap");
+
+    constexpr auto comm = "public";
+    constexpr auto localHost = "127.0.0.1";
+    netsnmp_session session{0};
+
+    snmp_sess_init(&session);
+
+    init_snmp("snmpapp");
+
+    // TODO: https://github.com/openbmc/openbmc/issues/3145
+    session.version = SNMP_VERSION_2c;
+    session.community = (u_char*)comm;
+    session.community_len = strlen(comm);
+    session.callback = nullptr;
+    session.callback_magic = nullptr;
+
+    // TODO:- get it from settings D-bus object.
+    session.peername = const_cast<char*>(localHost);
+
+    // create the session
+    auto ss = snmp_add(
+        &session, netsnmp_transport_open_client("snmptrap", session.peername),
+        nullptr, nullptr);
+    if (!ss)
+    {
+        log<level::ERR>("Unable to get the snmp session.",
+                        entry("SNMPMANAGER=%s", session.peername));
+        elog<InternalFailure>();
+    }
+
+    // Wrap the raw pointer in RAII
+    snmpSessionPtr sessionPtr(ss, &::snmp_close);
+
+    ss = nullptr;
+
+    auto pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
+    if (!pdu)
+    {
+        log<level::ERR>("Failed to create notification PDU");
+        elog<InternalFailure>();
+    }
+
+    pdu->trap_type = SNMP_TRAP_ENTERPRISESPECIFIC;
+
+    auto trapInfo = getTrapOID();
+
+    if (!snmp_pdu_add_variable(
+            pdu, SNMPTrapOID, sizeof(SNMPTrapOID) / sizeof(oid), ASN_OBJECT_ID,
+            trapInfo.first.data(), trapInfo.second * sizeof(oid)))
+    {
+        log<level::ERR>("Failed to add the SNMP var(trapID)");
+        snmp_free_pdu(pdu);
+        elog<InternalFailure>();
+    }
+
+    auto objectList = getFieldOIDList();
+
+    for (const auto& object : objectList)
+    {
+        if (!addPDUVar(*pdu, std::get<0>(object), std::get<1>(object),
+                       std::get<2>(object), std::get<3>(object)))
+        {
+            log<level::ERR>("Failed to add the SNMP var");
+            snmp_free_pdu(pdu);
+            elog<InternalFailure>();
+        }
+    }
+
+    // pdu is freed by snmp_send
+    if (!snmp_send(sessionPtr.get(), pdu))
+    {
+        log<level::ERR>("Failed to send the snmp trap.");
+        elog<InternalFailure>();
+    }
+
+    log<level::DEBUG>("Sent SNMP Trap");
+}
+
+} // namespace snmp
+} // namespace network
+} // namespace phosphor