summaryrefslogtreecommitdiff
path: root/redfish-core/include
diff options
context:
space:
mode:
authorChicago Duan <duanzhijia01@inspur.com>2020-11-26 09:12:12 +0300
committerGunnar Mills <gmills@us.ibm.com>2023-06-21 23:25:33 +0300
commit3d30708fb65e40cd28da601b3e91a527a8862e15 (patch)
tree702197e96fcd5f160e1eeed6c14a827f85135621 /redfish-core/include
parent100afe56dc38deff4d9bbefb9b88b467c2a9ff95 (diff)
downloadbmcweb-3d30708fb65e40cd28da601b3e91a527a8862e15.tar.xz
Redfish: Implement SNMP Trap
Implement SNMPTrap in EventDestination of Redfish. We can use this Redfish interface to add/get/delete the SNMPTrap port and destination address. When the error log is generated, phosphor-snmp will send SNMPTrap messages to our configured SNMPTrap destination. The MIB is here: [1] https://github.com/openbmc/phosphor-snmp/blob/master/mibs/NotificationMIB.txt Refer: [1] https://www.dmtf.org/sites/default/files/standards/documents/DSP0268_2019.3.pdf SNMPTrap test: Tested ok on the Witherspoon machine. Steps are as follows: 1. Use this Redfish interface to configure the port and destination address: curl -k -H "X-Auth-Token: $token" -X POST https://${bmc}/redfish/v1/EventService/Subscriptions -d '{"Destination": "snmp://192.168.31.89:162", "SubscriptionType": "SNMPTrap", "Protocol": "SNMPv2c"}' 2. Run the SNMPTrap receiver tool in the destination computer(192.168.31.89),I used iReasoning MIB Browser as the SNMPTrap receiving tool. 3. Trigger error logs such as power supply AC Lost. We will see the error log under /xyz/openbmc_project/logging. 4. The SNMPTrap receiver tool in the destination computer received the SNMPTrap sent by OpenBMC. Tested: Validator passes 1. Add snmp client: curl -k -H "X-Auth-Token: $token" -X POST https://${bmc}/redfish/v1/EventService/Subscriptions -d '{"Destination": "snmp://192.168.31.89:162", "SubscriptionType": "SNMPTrap", "Protocol": "SNMPv2c", "Context": "testContext"}' { "@Message.ExtendedInfo": [ { "@odata.type": "#Message.v1_0_0.Message", "Message": "The resource has been created successfully", "MessageArgs": [], "MessageId": "Base.1.8.1.Created", "MessageSeverity": "OK", "Resolution": "None" } ] } 2. Get snmp trap client configurations: curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/EventService/Subscriptions/snmp1 { "@odata.id": "/redfish/v1/EventService/Subscriptions/snmp1", "@odata.type": "#EventDestination.v1_7_0.EventDestination", "Context": "testContext", "Destination": "snmp://192.168.31.89:162", "EventFormatType": "Event", "Id": "snmp1", "Name": "Event Destination snmp1", "Protocol": "SNMPv2c", "SubscriptionType": "SNMPTrap" } Reboot the BMC, and get the snmp trap client again: curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/EventService/Subscriptions/snmp1 { "@odata.id": "/redfish/v1/EventService/Subscriptions/snmp1", "@odata.type": "#EventDestination.v1_7_0.EventDestination", "Context": "testContext", "Destination": "snmp://192.168.31.89:162", "EventFormatType": "Event", "Id": "snmp1", "Name": "Event Destination snmp1", "Protocol": "SNMPv2c", "SubscriptionType": "SNMPTrap" } 3. Delete snmp client: curl -k -H "X-Auth-Token: $token" -X DELETE https://${bmc}/redfish/v1/EventService/Subscriptions/snmp1 { "@Message.ExtendedInfo": [ { "@odata.type": "#Message.v1_1_1.Message", "Message": "Successfully Completed Request", "MessageArgs": [], "MessageId": "Base.1.8.1.Success", "MessageSeverity": "OK", "Resolution": "None" } ] } 4. After we have added some SNMP clients using Redfish, we can see them in Dbus: busctl tree xyz.openbmc_project.Network.SNMP `-/xyz `-/xyz/openbmc_project `-/xyz/openbmc_project/network `-/xyz/openbmc_project/network/snmp `-/xyz/openbmc_project/network/snmp/manager |-/xyz/openbmc_project/network/snmp/manager/1 busctl introspect xyz.openbmc_project.Network.SNMP /xyz/openbmc_project/network/snmp/manager/1 xyz.openbmc_project.Network.Client NAME TYPE SIGNATURE RESULT/VALUE FLAGS .Address property s "192.168.31.89" emits-change writable .Port property q 162 emits-change writable 5. Use "busctl call" add client busctl call xyz.openbmc_project.Network.SNMP /xyz/openbmc_project/network/snmp/manager xyz.openbmc_project.Network.Client.Create Client sq 192.168.31.90 162 s "/xyz/openbmc_project/network/snmp/manager/2" We will see it use the redfish url: curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/EventService/Subscriptions/snmp2 { "@odata.id": "/redfish/v1/EventService/Subscriptions/snmp2", "@odata.type": "#EventDestination.v1_7_0.EventDestination", "Context": "", "Destination": "snmp://192.168.31.90:162", "EventFormatType": "Event", "Id": "snmp2", "Name": "Event Destination snmp2", "Protocol": "SNMPv2c", "SubscriptionType": "SNMPTrap" } 6. Deleting snmp client using "busctl" First, we use redfish to add some SNMP clients: curl -k -H "X-Auth-Token: $token" -X POST https://${bmc}/redfish/v1/EventService/Subscriptions -d '{"Destination": "snmp://192.168.31.90:162", "SubscriptionType": "SNMPTrap", "Protocol": "SNMPv2c", "Context": "testContext0"}' curl -k -H "X-Auth-Token: $token" -X POST https://${bmc}/redfish/v1/EventService/Subscriptions -d '{"Destination": "snmp://192.168.31.91:162", "SubscriptionType": "SNMPTrap", "Protocol": "SNMPv2c", "Context": "testContext1"}' Then we can use redfish to get the subscriptions: curl -k -H "X-Auth-Token: $token" -XGET https://${bmc}/redfish/v1/EventService/Subscriptions { "@odata.id": "/redfish/v1/EventService/Subscriptions", "@odata.type":"#EventDestinationCollection.EventDestinationCollection", "Members": [ { "@odata.id": "/redfish/v1/EventService/Subscriptions/snmp1" }, { "@odata.id": "/redfish/v1/EventService/Subscriptions/snmp2" } ], "Members@odata.count": 2, "Name": "Event Destination Collections" } Now we use busctl to delete SNMP client 2: busctl call xyz.openbmc_project.Network.SNMP /xyz/openbmc_project/network/snmp/manager/2 xyz.openbmc_project.Object.Delete Delete Then we won't see snmp2 in the subscriptions of redfish: curl -k -H "X-Auth-Token: $token" -XGET https://${bmc}/redfish/v1/EventService/Subscriptions { "@odata.id": "/redfish/v1/EventService/Subscriptions", "@odata.type":"#EventDestinationCollection.EventDestinationCollection", "Members": [ { "@odata.id": "/redfish/v1/EventService/Subscriptions/snmp1" } ], "Members@odata.count": 1, "Name": "Event Destination Collections" } 7. Test the generic event subscription to make sure it didn't impacted Add Redfish subscription: curl -k -H "X-Auth-Token: $token" -X POST https://${bmc}/redfish/v1/EventService/Subscriptions -d '{"Destination": "https://192.168.31.189:443", "SubscriptionType": "RedfishEvent", "Protocol": "Redfish", "Context": "testContext"}' { "@Message.ExtendedInfo": [ { "@odata.type": "#Message.v1_1_1.Message", "Message": "The resource has been created successfully.", "MessageArgs": [], "MessageId": "Base.1.13.0.Created", "MessageSeverity": "OK", "Resolution": "None." } ] Get Redfish subscription: curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/EventService/Subscriptions/1358109191 { "@odata.id": "/redfish/v1/EventService/Subscriptions/1358109191", "@odata.type": "#EventDestination.v1_8_0.EventDestination", "Context": "testContext", "DeliveryRetryPolicy": "TerminateAfterRetries", "Destination": "https://192.168.31.189:443", "EventFormatType": "Event", "HttpHeaders": [], "Id": "1358109191", "MessageIds": [], "MetricReportDefinitions": [], "Name": "Event Destination 1358109191", "Protocol": "Redfish", "RegistryPrefixes": [], "ResourceTypes": [], "SubscriptionType": "RedfishEvent" } Signed-off-by: Chicago Duan <duanzhijia01@inspur.com> Signed-off-by: Ed Tanous <edtanous@google.com> Change-Id: Ie589b3934ee749c7e0add35e3ed1b0b7e817c557
Diffstat (limited to 'redfish-core/include')
-rw-r--r--redfish-core/include/snmp_trap_event_clients.hpp232
1 files changed, 232 insertions, 0 deletions
diff --git a/redfish-core/include/snmp_trap_event_clients.hpp b/redfish-core/include/snmp_trap_event_clients.hpp
new file mode 100644
index 0000000000..08ff81b439
--- /dev/null
+++ b/redfish-core/include/snmp_trap_event_clients.hpp
@@ -0,0 +1,232 @@
+#pragma once
+
+#include "async_resp.hpp"
+#include "dbus_singleton.hpp"
+#include "dbus_utility.hpp"
+#include "error_messages.hpp"
+#include "event_service_manager.hpp"
+#include "http_request.hpp"
+#include "http_response.hpp"
+#include "logging.hpp"
+#include "utils/dbus_utils.hpp"
+
+#include <boost/system/error_code.hpp>
+#include <boost/url/format.hpp>
+#include <sdbusplus/unpack_properties.hpp>
+
+#include <memory>
+#include <string>
+#include <string_view>
+
+namespace redfish
+{
+
+inline void afterGetSnmpTrapClientdata(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code& ec,
+ const dbus::utility::DBusPropertiesMap& propertiesList)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ std::string address;
+ uint16_t port = 0;
+
+ bool success = sdbusplus::unpackPropertiesNoThrow(
+ dbus_utils::UnpackErrorPrinter(), propertiesList, "Address", address,
+ "Port", port);
+
+ if (!success)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ asyncResp->res.jsonValue["Destination"] =
+ boost::urls::format("snmp://{}:{}", address, port);
+}
+
+inline void
+ getSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& id, const std::string& objectPath)
+{
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#EventDestination.v1_8_0.EventDestination";
+ asyncResp->res.jsonValue["Protocol"] = "SNMPv2c";
+ asyncResp->res.jsonValue["@odata.id"] =
+ boost::urls::format("/redfish/v1/EventService/Subscriptions/{}", id);
+
+ asyncResp->res.jsonValue["Id"] = id;
+ asyncResp->res.jsonValue["Name"] = "Event Destination";
+
+ asyncResp->res.jsonValue["SubscriptionType"] = "SNMPTrap";
+ asyncResp->res.jsonValue["EventFormatType"] = "Event";
+
+ std::shared_ptr<Subscription> subValue =
+ EventServiceManager::getInstance().getSubscription(id);
+ if (subValue != nullptr)
+ {
+ asyncResp->res.jsonValue["Context"] = subValue->customText;
+ }
+ else
+ {
+ asyncResp->res.jsonValue["Context"] = "";
+ }
+
+ sdbusplus::asio::getAllProperties(
+ *crow::connections::systemBus, "xyz.openbmc_project.Network.SNMP",
+ objectPath, "xyz.openbmc_project.Network.Client",
+ [asyncResp](const boost::system::error_code& ec,
+ const dbus::utility::DBusPropertiesMap& properties) {
+ afterGetSnmpTrapClientdata(asyncResp, ec, properties);
+ });
+}
+
+inline void
+ getSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& id)
+{
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, id](const boost::system::error_code& ec,
+ dbus::utility::ManagedObjectType& resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "D-Bus response error on GetManagedObjects "
+ << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ for (const auto& objpath : resp)
+ {
+ sdbusplus::message::object_path path(objpath.first);
+ const std::string snmpId = path.filename();
+ if (snmpId.empty())
+ {
+ BMCWEB_LOG_ERROR << "The SNMP client ID is wrong";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ const std::string subscriptionId = "snmp" + snmpId;
+ if (id != subscriptionId)
+ {
+ continue;
+ }
+
+ getSnmpTrapClientdata(asyncResp, id, objpath.first);
+ return;
+ }
+
+ messages::resourceNotFound(asyncResp->res, "Subscriptions", id);
+ EventServiceManager::getInstance().deleteSubscription(id);
+ },
+ "xyz.openbmc_project.Network.SNMP",
+ "/xyz/openbmc_project/network/snmp/manager",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+}
+
+inline void
+ afterSnmpClientCreate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code& ec,
+ const std::string& dbusSNMPid)
+{
+ if (ec)
+ {
+ if (ec.value() != EBADR)
+ {
+ // SNMP not installed
+ messages::propertyValueOutOfRange(asyncResp->res, "SNMPv2c",
+ "Protocol");
+ return;
+ }
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ sdbusplus::message::object_path path(dbusSNMPid);
+ const std::string snmpId = path.filename();
+ if (snmpId.empty())
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ std::string subscriptionId = "snmp" + snmpId;
+
+ boost::urls::url uri = boost::urls::format(
+ "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
+ asyncResp->res.addHeader("Location", uri.buffer());
+ messages::created(asyncResp->res);
+}
+
+inline void
+ addSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& host, uint16_t snmpTrapPort)
+{
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code& ec,
+ const std::string& dbusSNMPid) {
+ afterSnmpClientCreate(asyncResp, ec, dbusSNMPid);
+ },
+ "xyz.openbmc_project.Network.SNMP",
+ "/xyz/openbmc_project/network/snmp/manager",
+ "xyz.openbmc_project.Network.Client.Create", "Client", host,
+ snmpTrapPort);
+}
+
+inline void
+ getSnmpSubscriptionList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& snmpId,
+ nlohmann::json& memberArray)
+{
+ const std::string subscriptionId = "snmp" + snmpId;
+
+ nlohmann::json::object_t member;
+ member["@odata.id"] = boost::urls::format(
+ "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
+ memberArray.push_back(std::move(member));
+
+ asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
+}
+
+inline void
+ deleteSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& param)
+{
+ std::string_view snmpTrapId = param;
+
+ // Erase "snmp" in the request to find the corresponding
+ // dbus snmp client id. For example, the snmpid in the
+ // request is "snmp1", which will be "1" after being erased.
+ snmpTrapId.remove_prefix(4);
+
+ sdbusplus::message::object_path snmpPath =
+ sdbusplus::message::object_path(
+ "/xyz/openbmc_project/network/snmp/manager") /
+ std::string(snmpTrapId);
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, param](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ // The snmp trap id is incorrect
+ if (ec.value() == EBADR)
+ {
+ messages::resourceNotFound(asyncResp->res, "Subscription",
+ param);
+ return;
+ }
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ messages::success(asyncResp->res);
+ },
+ "xyz.openbmc_project.Network.SNMP", static_cast<std::string>(snmpPath),
+ "xyz.openbmc_project.Object.Delete", "Delete");
+}
+
+} // namespace redfish