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/lg2.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{}; 64 snmp_sess_init(&session); 65 66 init_snmp("snmpapp"); 67 68 // TODO: https://github.com/openbmc/openbmc/issues/3145 69 session.version = SNMP_VERSION_2c; 70 session.community = (u_char*)comm; 71 session.community_len = strlen(comm); 72 session.callback = nullptr; 73 session.callback_magic = nullptr; 74 75 auto mgrs = getManagers(); 76 77 for (auto& mgr : mgrs) 78 { 79 session.peername = const_cast<char*>(mgr.c_str()); 80 // create the session 81 auto ss = snmp_add( 82 &session, 83 netsnmp_transport_open_client("snmptrap", session.peername), 84 nullptr, nullptr); 85 if (!ss) 86 { 87 lg2::error("Unable to get the snmp session: {SNMPMANAGER}", 88 "SNMPMANAGER", mgr); 89 elog<InternalFailure>(); 90 } 91 92 // Wrap the raw pointer in RAII 93 snmpSessionPtr sessionPtr(ss, &::snmp_close); 94 95 ss = nullptr; 96 97 auto pdu = snmp_pdu_create(SNMP_MSG_TRAP2); 98 if (!pdu) 99 { 100 lg2::error("Failed to create notification PDU"); 101 elog<InternalFailure>(); 102 } 103 104 // https://tools.ietf.org/search/rfc3416#page-22 105 // add the sysUpTime.0 [RFC3418] 106 auto sysuptime = get_uptime(); 107 std::string sysuptimeStr = std::to_string(sysuptime); 108 109 if (snmp_add_var(pdu, sysuptimeOID, sizeof(sysuptimeOID) / sizeof(oid), 110 't', sysuptimeStr.c_str())) 111 112 { 113 lg2::error("Failed to add the SNMP var(systime)"); 114 snmp_free_pdu(pdu); 115 elog<InternalFailure>(); 116 } 117 118 pdu->trap_type = SNMP_TRAP_ENTERPRISESPECIFIC; 119 120 auto trapInfo = getTrapOID(); 121 122 // add the snmpTrapOID.0 [RFC3418] 123 if (!snmp_pdu_add_variable(pdu, SNMPTrapOID, 124 sizeof(SNMPTrapOID) / sizeof(oid), 125 ASN_OBJECT_ID, trapInfo.first.data(), 126 trapInfo.second * sizeof(oid))) 127 { 128 lg2::error("Failed to add the SNMP var(trapID)"); 129 snmp_free_pdu(pdu); 130 elog<InternalFailure>(); 131 } 132 133 auto objectList = getFieldOIDList(); 134 135 for (const auto& object : objectList) 136 { 137 if (!addPDUVar(*pdu, std::get<0>(object), std::get<1>(object), 138 std::get<2>(object), std::get<3>(object))) 139 { 140 lg2::error("Failed to add the SNMP var"); 141 snmp_free_pdu(pdu); 142 elog<InternalFailure>(); 143 } 144 } 145 // pdu is freed by snmp_send 146 if (!snmp_send(sessionPtr.get(), pdu)) 147 { 148 lg2::error("Failed to send the snmp trap."); 149 elog<InternalFailure>(); 150 } 151 152 lg2::debug("Sent SNMP Trap: {MGR}", "MGR", mgr); 153 } 154 } 155 156 } // namespace snmp 157 } // namespace network 158 } // namespace phosphor 159