1 #include "snmp_notification.hpp" 2 #include "snmp_util.hpp" 3 4 #include <phosphor-logging/elog-errors.hpp> 5 #include <phosphor-logging/log.hpp> 6 7 #include "xyz/openbmc_project/Common/error.hpp" 8 9 namespace phosphor 10 { 11 namespace network 12 { 13 namespace snmp 14 { 15 16 namespace variant_ns = sdbusplus::message::variant_ns; 17 using namespace phosphor::logging; 18 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 19 20 using snmpSessionPtr = 21 std::unique_ptr<netsnmp_session, decltype(&::snmp_close)>; 22 23 bool Notification::addPDUVar(netsnmp_pdu& pdu, const OID& objID, 24 size_t objIDLen, u_char type, Value val) 25 { 26 netsnmp_variable_list* varList = nullptr; 27 switch (type) 28 { 29 case ASN_INTEGER: 30 { 31 auto ltmp = variant_ns::get<int32_t>(val); 32 varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, 33 <mp, sizeof(ltmp)); 34 } 35 break; 36 case ASN_UNSIGNED: 37 { 38 auto ltmp = variant_ns::get<uint32_t>(val); 39 varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, 40 <mp, sizeof(ltmp)); 41 } 42 break; 43 case ASN_OPAQUE_U64: 44 { 45 auto ltmp = variant_ns::get<uint64_t>(val); 46 varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, 47 <mp, sizeof(ltmp)); 48 } 49 break; 50 case ASN_OCTET_STR: 51 { 52 const auto& value = variant_ns::get<std::string>(val); 53 varList = snmp_pdu_add_variable(&pdu, objID.data(), objIDLen, type, 54 value.c_str(), value.length()); 55 } 56 break; 57 } 58 return (varList == nullptr ? false : true); 59 } 60 61 void Notification::sendTrap() 62 { 63 constexpr auto comm = "public"; 64 netsnmp_session session{0}; 65 66 snmp_sess_init(&session); 67 68 init_snmp("snmpapp"); 69 70 // TODO: https://github.com/openbmc/openbmc/issues/3145 71 session.version = SNMP_VERSION_2c; 72 session.community = (u_char*)comm; 73 session.community_len = strlen(comm); 74 session.callback = nullptr; 75 session.callback_magic = nullptr; 76 77 auto mgrs = getManagers(); 78 79 for (auto& mgr : mgrs) 80 { 81 session.peername = const_cast<char*>(mgr.c_str()); 82 // create the session 83 auto ss = snmp_add( 84 &session, 85 netsnmp_transport_open_client("snmptrap", session.peername), 86 nullptr, nullptr); 87 if (!ss) 88 { 89 log<level::ERR>("Unable to get the snmp session.", 90 entry("SNMPMANAGER=%s", mgr.c_str())); 91 elog<InternalFailure>(); 92 } 93 94 // Wrap the raw pointer in RAII 95 snmpSessionPtr sessionPtr(ss, &::snmp_close); 96 97 ss = nullptr; 98 99 auto pdu = snmp_pdu_create(SNMP_MSG_TRAP2); 100 if (!pdu) 101 { 102 log<level::ERR>("Failed to create notification PDU"); 103 elog<InternalFailure>(); 104 } 105 106 pdu->trap_type = SNMP_TRAP_ENTERPRISESPECIFIC; 107 108 auto trapInfo = getTrapOID(); 109 110 if (!snmp_pdu_add_variable(pdu, SNMPTrapOID, 111 sizeof(SNMPTrapOID) / sizeof(oid), 112 ASN_OBJECT_ID, trapInfo.first.data(), 113 trapInfo.second * sizeof(oid))) 114 { 115 log<level::ERR>("Failed to add the SNMP var(trapID)"); 116 snmp_free_pdu(pdu); 117 elog<InternalFailure>(); 118 } 119 120 auto objectList = getFieldOIDList(); 121 122 for (const auto& object : objectList) 123 { 124 if (!addPDUVar(*pdu, std::get<0>(object), std::get<1>(object), 125 std::get<2>(object), std::get<3>(object))) 126 { 127 log<level::ERR>("Failed to add the SNMP var"); 128 snmp_free_pdu(pdu); 129 elog<InternalFailure>(); 130 } 131 } 132 // pdu is freed by snmp_send 133 if (!snmp_send(sessionPtr.get(), pdu)) 134 { 135 log<level::ERR>("Failed to send the snmp trap."); 136 elog<InternalFailure>(); 137 } 138 139 log<level::DEBUG>("Sent SNMP Trap", entry("MGR=%s", mgr.c_str())); 140 } 141 } 142 143 } // namespace snmp 144 } // namespace network 145 } // namespace phosphor 146