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