#include "snmp_notification.hpp" #include "snmp_util.hpp" #include "xyz/openbmc_project/Common/error.hpp" #include #include namespace phosphor { namespace network { namespace snmp { using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Common::Error; using snmpSessionPtr = std::unique_ptr; 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 = std::get(val); varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, <mp, sizeof(ltmp)); } break; case ASN_UNSIGNED: { auto ltmp = std::get(val); varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, <mp, sizeof(ltmp)); } break; case ASN_OPAQUE_U64: { auto ltmp = std::get(val); varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, <mp, sizeof(ltmp)); } break; case ASN_OCTET_STR: { const auto& value = std::get(val); varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, value.c_str(), value.length()); } break; } return (varList == nullptr ? false : true); } void Notification::sendTrap() { constexpr auto comm = "public"; netsnmp_session session{}; 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; auto mgrs = getManagers(); for (auto& mgr : mgrs) { session.peername = const_cast(mgr.c_str()); // create the session auto ss = snmp_add( &session, netsnmp_transport_open_client("snmptrap", session.peername), nullptr, nullptr); if (!ss) { lg2::error("Unable to get the snmp session: {SNMPMANAGER}", "SNMPMANAGER", mgr); elog(); } // Wrap the raw pointer in RAII snmpSessionPtr sessionPtr(ss, &::snmp_close); ss = nullptr; auto pdu = snmp_pdu_create(SNMP_MSG_TRAP2); if (!pdu) { lg2::error("Failed to create notification PDU"); elog(); } // https://tools.ietf.org/search/rfc3416#page-22 // add the sysUpTime.0 [RFC3418] auto sysuptime = get_uptime(); std::string sysuptimeStr = std::to_string(sysuptime); if (snmp_add_var(pdu, sysuptimeOID, sizeof(sysuptimeOID) / sizeof(oid), 't', sysuptimeStr.c_str())) { lg2::error("Failed to add the SNMP var(systime)"); snmp_free_pdu(pdu); elog(); } pdu->trap_type = SNMP_TRAP_ENTERPRISESPECIFIC; auto trapInfo = getTrapOID(); // add the snmpTrapOID.0 [RFC3418] if (!snmp_pdu_add_variable(pdu, SNMPTrapOID, sizeof(SNMPTrapOID) / sizeof(oid), ASN_OBJECT_ID, trapInfo.first.data(), trapInfo.second * sizeof(oid))) { lg2::error("Failed to add the SNMP var(trapID)"); snmp_free_pdu(pdu); elog(); } auto objectList = getFieldOIDList(); for (const auto& object : objectList) { if (!addPDUVar(*pdu, object.oid, object.oid_len, object.type, object.value)) { lg2::error("Failed to add the SNMP var"); snmp_free_pdu(pdu); elog(); } } // pdu is freed by snmp_send if (!snmp_send(sessionPtr.get(), pdu)) { lg2::error("Failed to send the snmp trap."); elog(); } lg2::debug("Sent SNMP Trap: {MGR}", "MGR", mgr); } } } // namespace snmp } // namespace network } // namespace phosphor