1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #pragma once
4
5 #include "async_resp.hpp"
6 #include "dbus_utility.hpp"
7 #include "error_messages.hpp"
8 #include "event_service_manager.hpp"
9 #include "generated/enums/event_destination.hpp"
10 #include "http_response.hpp"
11 #include "logging.hpp"
12 #include "utils/dbus_utils.hpp"
13
14 #include <asm-generic/errno.h>
15 #include <systemd/sd-bus.h>
16
17 #include <boost/system/error_code.hpp>
18 #include <boost/url/format.hpp>
19 #include <boost/url/url.hpp>
20 #include <sdbusplus/message.hpp>
21 #include <sdbusplus/message/native_types.hpp>
22 #include <sdbusplus/unpack_properties.hpp>
23
24 #include <cstdint>
25 #include <memory>
26 #include <string>
27 #include <string_view>
28 #include <utility>
29
30 namespace redfish
31 {
32
afterGetSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & propertiesList)33 inline void afterGetSnmpTrapClientdata(
34 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
35 const boost::system::error_code& ec,
36 const dbus::utility::DBusPropertiesMap& propertiesList)
37 {
38 if (ec)
39 {
40 BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
41 messages::internalError(asyncResp->res);
42 return;
43 }
44
45 std::string address;
46 uint16_t port = 0;
47
48 bool success = sdbusplus::unpackPropertiesNoThrow(
49 dbus_utils::UnpackErrorPrinter(), propertiesList, "Address", address,
50 "Port", port);
51
52 if (!success)
53 {
54 messages::internalError(asyncResp->res);
55 return;
56 }
57
58 asyncResp->res.jsonValue["Destination"] =
59 boost::urls::format("snmp://{}:{}", address, port);
60 }
61
getSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & id,const std::string & objectPath)62 inline void getSnmpTrapClientdata(
63 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id,
64 const std::string& objectPath)
65 {
66 asyncResp->res.jsonValue["@odata.type"] =
67 "#EventDestination.v1_8_0.EventDestination";
68 asyncResp->res.jsonValue["Protocol"] =
69 event_destination::EventDestinationProtocol::SNMPv2c;
70 asyncResp->res.jsonValue["@odata.id"] =
71 boost::urls::format("/redfish/v1/EventService/Subscriptions/{}", id);
72
73 asyncResp->res.jsonValue["Id"] = id;
74 asyncResp->res.jsonValue["Name"] = "Event Destination";
75
76 asyncResp->res.jsonValue["SubscriptionType"] =
77 event_destination::SubscriptionType::SNMPTrap;
78 asyncResp->res.jsonValue["EventFormatType"] =
79 event_destination::EventFormatType::Event;
80
81 /* Context is required Redfish field,
82 * but SNMP backend doesn't support a context string.
83 */
84 asyncResp->res.jsonValue["Context"] = "";
85
86 dbus::utility::getAllProperties(
87 "xyz.openbmc_project.Network.SNMP", objectPath,
88 "xyz.openbmc_project.Network.Client",
89 [asyncResp](const boost::system::error_code& ec,
90 const dbus::utility::DBusPropertiesMap& properties) {
91 afterGetSnmpTrapClientdata(asyncResp, ec, properties);
92 });
93 }
94
getSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & id)95 inline void getSnmpTrapClient(
96 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
97 {
98 dbus::utility::async_method_call(
99 asyncResp,
100 [asyncResp, id](const boost::system::error_code& ec,
101 dbus::utility::ManagedObjectType& resp) {
102 if (ec)
103 {
104 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}",
105 ec);
106 messages::internalError(asyncResp->res);
107 return;
108 }
109
110 for (const auto& objpath : resp)
111 {
112 sdbusplus::message::object_path path(objpath.first);
113 const std::string snmpId = path.filename();
114 if (snmpId.empty())
115 {
116 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
117 messages::internalError(asyncResp->res);
118 return;
119 }
120 const std::string subscriptionId = "snmp" + snmpId;
121 if (id != subscriptionId)
122 {
123 continue;
124 }
125
126 getSnmpTrapClientdata(asyncResp, id, objpath.first);
127 return;
128 }
129
130 messages::resourceNotFound(asyncResp->res, "Subscriptions", id);
131 EventServiceManager::getInstance().deleteSubscription(id);
132 },
133 "xyz.openbmc_project.Network.SNMP",
134 "/xyz/openbmc_project/network/snmp/manager",
135 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
136 }
137
afterSnmpClientCreate(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const sdbusplus::message_t & msg,const std::string & host,const std::string & dbusSNMPid)138 inline void afterSnmpClientCreate(
139 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
140 const boost::system::error_code& ec, const sdbusplus::message_t& msg,
141 const std::string& host, const std::string& dbusSNMPid)
142 {
143 if (ec)
144 {
145 const sd_bus_error* dbusError = msg.get_error();
146 if (dbusError != nullptr)
147 {
148 if (std::string_view(
149 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
150 dbusError->name)
151 {
152 messages::propertyValueIncorrect(asyncResp->res, "Destination",
153 host);
154 return;
155 }
156 if (ec.value() != EBADR)
157 {
158 // SNMP not installed
159 messages::propertyValueOutOfRange(asyncResp->res, "SNMPv2c",
160 "Protocol");
161 return;
162 }
163 }
164 messages::internalError(asyncResp->res);
165 return;
166 }
167 sdbusplus::message::object_path path(dbusSNMPid);
168 const std::string snmpId = path.filename();
169 if (snmpId.empty())
170 {
171 messages::internalError(asyncResp->res);
172 return;
173 }
174
175 std::string subscriptionId = "snmp" + snmpId;
176
177 boost::urls::url uri = boost::urls::format(
178 "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
179 asyncResp->res.addHeader("Location", uri.buffer());
180 messages::created(asyncResp->res);
181 }
182
addSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & host,uint16_t snmpTrapPort)183 inline void addSnmpTrapClient(
184 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
185 const std::string& host, uint16_t snmpTrapPort)
186 {
187 dbus::utility::async_method_call(
188 asyncResp,
189 [asyncResp,
190 host](const boost::system::error_code& ec,
191 const sdbusplus::message_t& msg, const std::string& dbusSNMPid) {
192 afterSnmpClientCreate(asyncResp, ec, msg, host, dbusSNMPid);
193 },
194 "xyz.openbmc_project.Network.SNMP",
195 "/xyz/openbmc_project/network/snmp/manager",
196 "xyz.openbmc_project.Network.Client.Create", "Client", host,
197 snmpTrapPort);
198 }
199
getSnmpSubscriptionList(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & snmpId,nlohmann::json & memberArray)200 inline void getSnmpSubscriptionList(
201 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
202 const std::string& snmpId, nlohmann::json& memberArray)
203 {
204 const std::string subscriptionId = "snmp" + snmpId;
205
206 nlohmann::json::object_t member;
207 member["@odata.id"] = boost::urls::format(
208 "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
209 memberArray.push_back(std::move(member));
210
211 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
212 }
213
deleteSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & param)214 inline void deleteSnmpTrapClient(
215 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
216 const std::string& param)
217 {
218 std::string_view snmpTrapId = param;
219
220 // Erase "snmp" in the request to find the corresponding
221 // dbus snmp client id. For example, the snmpid in the
222 // request is "snmp1", which will be "1" after being erased.
223 snmpTrapId.remove_prefix(4);
224
225 sdbusplus::message::object_path snmpPath =
226 sdbusplus::message::object_path(
227 "/xyz/openbmc_project/network/snmp/manager") /
228 std::string(snmpTrapId);
229
230 dbus::utility::async_method_call(
231 asyncResp,
232 [asyncResp, param](const boost::system::error_code& ec) {
233 if (ec)
234 {
235 // The snmp trap id is incorrect
236 if (ec.value() == EBADR)
237 {
238 messages::resourceNotFound(asyncResp->res, "Subscription",
239 param);
240 return;
241 }
242 messages::internalError(asyncResp->res);
243 return;
244 }
245 messages::success(asyncResp->res);
246 },
247 "xyz.openbmc_project.Network.SNMP", static_cast<std::string>(snmpPath),
248 "xyz.openbmc_project.Object.Delete", "Delete");
249 }
250
251 } // namespace redfish
252