summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--http/utility.hpp8
-rw-r--r--redfish-core/include/snmp_trap_event_clients.hpp232
-rw-r--r--redfish-core/lib/event_service.hpp126
3 files changed, 363 insertions, 3 deletions
diff --git a/http/utility.hpp b/http/utility.hpp
index aa64043132..3fbdd0c32f 100644
--- a/http/utility.hpp
+++ b/http/utility.hpp
@@ -551,6 +551,10 @@ inline std::string setProtocolDefaults(boost::urls::url_view urlView)
}
return "";
}
+ if (urlView.scheme() == "snmp")
+ {
+ return "snmp";
+ }
return "";
}
@@ -573,6 +577,10 @@ inline uint16_t setPortDefaults(boost::urls::url_view url)
{
return 443;
}
+ if (url.scheme() == "snmp")
+ {
+ return 162;
+ }
return 0;
}
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
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index 28a7ac6b6d..aef4d47278 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -20,10 +20,17 @@
#include "logging.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
+#include "snmp_trap_event_clients.hpp"
#include <boost/beast/http/fields.hpp>
+#include <boost/system/error_code.hpp>
+#include <sdbusplus/unpack_properties.hpp>
+#include <utils/dbus_utils.hpp>
+#include <charconv>
+#include <memory>
#include <span>
+#include <string>
namespace redfish
{
@@ -183,6 +190,39 @@ inline void requestRoutesSubmitTestEvent(App& app)
});
}
+inline void doSubscriptionCollection(
+ const boost::system::error_code ec,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const dbus::utility::ManagedObjectType& resp)
+{
+ if (ec)
+ {
+ if (ec.value() == EBADR)
+ {
+ // This is an optional process so just return if it isn't there
+ return;
+ }
+
+ BMCWEB_LOG_ERROR << "D-Bus response error on GetManagedObjects " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
+ 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;
+ }
+
+ getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
+ }
+}
+
inline void requestRoutesEventDestinationCollection(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
@@ -210,11 +250,20 @@ inline void requestRoutesEventDestinationCollection(App& app)
for (const std::string& id : subscripIds)
{
nlohmann::json::object_t member;
- member["@odata.id"] = "/redfish/v1/EventService/Subscriptions/" +
- id;
+ member["@odata.id"] = boost::urls::format(
+ "/redfish/v1/EventService/Subscriptions/{}" + id);
memberArray.emplace_back(std::move(member));
}
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec,
+ const dbus::utility::ManagedObjectType& resp) {
+ doSubscriptionCollection(ec, asyncResp, resp);
+ },
+ "xyz.openbmc_project.Network.SNMP",
+ "/xyz/openbmc_project/network/snmp/manager",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
});
+
BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
.privileges(redfish::privileges::postEventDestinationCollection)
.methods(boost::beast::http::verb::post)(
@@ -287,10 +336,66 @@ inline void requestRoutesEventDestinationCollection(App& app)
return;
}
+ if (protocol == "SNMPv2c")
+ {
+ if (context)
+ {
+ messages::propertyValueConflict(asyncResp->res, "Context",
+ "Protocol");
+ return;
+ }
+ if (eventFormatType2)
+ {
+ messages::propertyValueConflict(asyncResp->res,
+ "EventFormatType", "Protocol");
+ return;
+ }
+ if (retryPolicy)
+ {
+ messages::propertyValueConflict(asyncResp->res, "RetryPolicy",
+ "Protocol");
+ return;
+ }
+ if (msgIds)
+ {
+ messages::propertyValueConflict(asyncResp->res, "MessageIds",
+ "Protocol");
+ return;
+ }
+ if (regPrefixes)
+ {
+ messages::propertyValueConflict(asyncResp->res,
+ "RegistryPrefixes", "Protocol");
+ return;
+ }
+ if (resTypes)
+ {
+ messages::propertyValueConflict(asyncResp->res, "ResourceTypes",
+ "Protocol");
+ return;
+ }
+ if (headers)
+ {
+ messages::propertyValueConflict(asyncResp->res, "HttpHeaders",
+ "Protocol");
+ return;
+ }
+ if (mrdJsonArray)
+ {
+ messages::propertyValueConflict(
+ asyncResp->res, "MetricReportDefinitions", "Protocol");
+ return;
+ }
+
+ addSnmpTrapClient(asyncResp, host, port);
+ return;
+ }
+
if (path.empty())
{
path = "/";
}
+
std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>(
host, port, path, urlProto, app.ioContext());
@@ -526,6 +631,13 @@ inline void requestRoutesEventDestination(App& app)
{
return;
}
+
+ if (param.starts_with("snmp"))
+ {
+ getSnmpTrapClient(asyncResp, param);
+ return;
+ }
+
std::shared_ptr<Subscription> subValue =
EventServiceManager::getInstance().getSubscription(param);
if (subValue == nullptr)
@@ -536,7 +648,7 @@ inline void requestRoutesEventDestination(App& app)
const std::string& id = param;
asyncResp->res.jsonValue["@odata.type"] =
- "#EventDestination.v1_7_0.EventDestination";
+ "#EventDestination.v1_8_0.EventDestination";
asyncResp->res.jsonValue["Protocol"] = "Redfish";
asyncResp->res.jsonValue["@odata.id"] =
"/redfish/v1/EventService/Subscriptions/" + id;
@@ -653,6 +765,14 @@ inline void requestRoutesEventDestination(App& app)
{
return;
}
+
+ if (param.starts_with("snmp"))
+ {
+ deleteSnmpTrapClient(asyncResp, param);
+ EventServiceManager::getInstance().deleteSubscription(param);
+ return;
+ }
+
if (!EventServiceManager::getInstance().isSubscriptionExist(param))
{
asyncResp->res.result(boost::beast::http::status::not_found);