blob: a2137cd5548c2453a077b623401f9a41331b55fb [file] [log] [blame]
Patrick Venture690a2342020-05-17 11:51:31 -07001#pragma once
2
John Wang8a7236a2021-01-04 15:31:44 +08003#include "app/channel.hpp"
Peter Foley0893ca32023-10-19 16:19:55 -04004#include "transportconstants.hpp"
John Wang8a7236a2021-01-04 15:31:44 +08005#include "user_channel/cipher_mgmt.hpp"
6
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05007#include <ipmid/api-types.hpp>
8#include <ipmid/api.hpp>
9#include <ipmid/message.hpp>
10#include <ipmid/message/types.hpp>
11#include <ipmid/types.hpp>
12#include <ipmid/utils.hpp>
13#include <phosphor-logging/elog-errors.hpp>
14#include <phosphor-logging/elog.hpp>
15#include <phosphor-logging/log.hpp>
16#include <sdbusplus/bus.hpp>
17#include <sdbusplus/exception.hpp>
William A. Kennington III726f2bd2023-06-21 01:11:40 -070018#include <stdplus/net/addr/ether.hpp>
19#include <stdplus/net/addr/ip.hpp>
20#include <stdplus/str/conv.hpp>
William A. Kennington IIIc72f3602023-10-19 03:51:37 -070021#include <stdplus/zstring_view.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050022#include <user_channel/channel_layer.hpp>
23#include <xyz/openbmc_project/Common/error.hpp>
24#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
25#include <xyz/openbmc_project/Network/IP/server.hpp>
26#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
27
John Wang8a7236a2021-01-04 15:31:44 +080028#include <cinttypes>
John Wang8a7236a2021-01-04 15:31:44 +080029#include <functional>
John Wang8a7236a2021-01-04 15:31:44 +080030#include <optional>
John Wang8a7236a2021-01-04 15:31:44 +080031#include <string>
32#include <string_view>
John Wang8a7236a2021-01-04 15:31:44 +080033#include <unordered_map>
34#include <unordered_set>
John Wang8a7236a2021-01-04 15:31:44 +080035#include <utility>
Patrick Venture690a2342020-05-17 11:51:31 -070036
37namespace ipmi
38{
39namespace transport
40{
41
John Wang8a7236a2021-01-04 15:31:44 +080042/** @brief The dbus parameters for the interface corresponding to a channel
43 * This helps reduce the number of mapper lookups we need for each
44 * query and simplifies finding the VLAN interface if needed.
45 */
46struct ChannelParams
47{
48 /** @brief The channel ID */
49 int id;
50 /** @brief channel name for the interface */
51 std::string ifname;
52 /** @brief Name of the service on the bus */
53 std::string service;
54 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
55 std::string ifPath;
56 /** @brief Logical adapter path used for address assignment */
57 std::string logicalPath;
58};
59
John Wang8a7236a2021-01-04 15:31:44 +080060/** @brief Determines the ethernet interface name corresponding to a channel
61 * Tries to map a VLAN object first so that the address information
62 * is accurate. Otherwise it gets the standard ethernet interface.
63 *
64 * @param[in] bus - The bus object used for lookups
65 * @param[in] channel - The channel id corresponding to an ethernet interface
66 * @return Ethernet interface service and object path if it exists
67 */
Patrick Williams1318a5e2024-08-16 15:19:54 -040068std::optional<ChannelParams>
69 maybeGetChannelParams(sdbusplus::bus_t& bus, uint8_t channel);
John Wang8a7236a2021-01-04 15:31:44 +080070
71/** @brief A trivial helper around maybeGetChannelParams() that throws an
72 * exception when it is unable to acquire parameters for the channel.
73 *
74 * @param[in] bus - The bus object used for lookups
75 * @param[in] channel - The channel id corresponding to an ethernet interface
76 * @return Ethernet interface service and object path
77 */
Patrick Williams5d82f472022-07-22 19:26:53 -050078ChannelParams getChannelParams(sdbusplus::bus_t& bus, uint8_t channel);
John Wang8a7236a2021-01-04 15:31:44 +080079
80/** @brief Trivializes using parameter getter functions by providing a bus
81 * and channel parameters automatically.
82 *
83 * @param[in] channel - The channel id corresponding to an ethernet interface
84 * ...
85 */
86template <auto func, typename... Args>
87auto channelCall(uint8_t channel, Args&&... args)
88{
Patrick Williams5d82f472022-07-22 19:26:53 -050089 sdbusplus::bus_t bus(ipmid_get_sd_bus_connection());
John Wang8a7236a2021-01-04 15:31:44 +080090 auto params = getChannelParams(bus, channel);
91 return std::invoke(func, bus, params, std::forward<Args>(args)...);
92}
93
94/** @brief Generic paramters for different address families */
95template <int family>
96struct AddrFamily
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050097{};
John Wang8a7236a2021-01-04 15:31:44 +080098
99/** @brief Parameter specialization for IPv4 */
100template <>
101struct AddrFamily<AF_INET>
102{
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700103 using addr = stdplus::In4Addr;
John Wang8a7236a2021-01-04 15:31:44 +0800104 static constexpr auto protocol =
Willy Tu523e2d12023-09-05 11:36:48 -0700105 sdbusplus::server::xyz::openbmc_project::network::IP::Protocol::IPv4;
John Wang8a7236a2021-01-04 15:31:44 +0800106 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
107 static constexpr uint8_t defaultPrefix = 32;
108 static constexpr char propertyGateway[] = "DefaultGateway";
109};
110
111/** @brief Parameter specialization for IPv6 */
112template <>
113struct AddrFamily<AF_INET6>
114{
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700115 using addr = stdplus::In6Addr;
John Wang8a7236a2021-01-04 15:31:44 +0800116 static constexpr auto protocol =
Willy Tu523e2d12023-09-05 11:36:48 -0700117 sdbusplus::server::xyz::openbmc_project::network::IP::Protocol::IPv6;
John Wang8a7236a2021-01-04 15:31:44 +0800118 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
119 static constexpr uint8_t defaultPrefix = 128;
120 static constexpr char propertyGateway[] = "DefaultGateway6";
121};
122
123/** @brief Interface Neighbor configuration parameters */
124template <int family>
125struct IfNeigh
126{
127 std::string path;
128 typename AddrFamily<family>::addr ip;
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700129 stdplus::EtherAddr mac;
John Wang8a7236a2021-01-04 15:31:44 +0800130};
131
132/** @brief Interface IP Address configuration parameters */
133template <int family>
134struct IfAddr
135{
136 std::string path;
137 typename AddrFamily<family>::addr address;
Willy Tu523e2d12023-09-05 11:36:48 -0700138 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin origin;
John Wang8a7236a2021-01-04 15:31:44 +0800139 uint8_t prefix;
140};
141
142/** @brief Valid address origins for IPv6 */
143static inline const std::unordered_set<
Willy Tu523e2d12023-09-05 11:36:48 -0700144 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin>
145 originsV6Static = {sdbusplus::server::xyz::openbmc_project::network::IP::
John Wang8a7236a2021-01-04 15:31:44 +0800146 AddressOrigin::Static};
147static inline const std::unordered_set<
Willy Tu523e2d12023-09-05 11:36:48 -0700148 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin>
John Wang8a7236a2021-01-04 15:31:44 +0800149 originsV6Dynamic = {
Willy Tu523e2d12023-09-05 11:36:48 -0700150 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin::
John Wang8a7236a2021-01-04 15:31:44 +0800151 DHCP,
Willy Tu523e2d12023-09-05 11:36:48 -0700152 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin::
John Wang8a7236a2021-01-04 15:31:44 +0800153 SLAAC,
154};
155
156/** @brief A lazy lookup mechanism for iterating over object properties stored
157 * in DBus. This will only perform the object lookup when needed, and
158 * retains a cache of previous lookups to speed up future iterations.
159 */
160class ObjectLookupCache
161{
162 public:
163 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
164
165 /** @brief Creates a new ObjectLookupCache for the interface on the bus
166 * NOTE: The inputs to this object must outlive the object since
167 * they are only referenced by it.
168 *
169 * @param[in] bus - The bus object used for lookups
170 * @param[in] params - The parameters for the channel
171 * @param[in] intf - The interface we are looking up
172 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500173 ObjectLookupCache(sdbusplus::bus_t& bus, const ChannelParams& params,
John Wang8a7236a2021-01-04 15:31:44 +0800174 const char* intf) :
Patrick Williams1318a5e2024-08-16 15:19:54 -0400175 bus(bus), params(params), intf(intf),
John Wang8a7236a2021-01-04 15:31:44 +0800176 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500177 {}
John Wang8a7236a2021-01-04 15:31:44 +0800178
179 class iterator : public ObjectTree::const_iterator
180 {
181 public:
182 using value_type = PropertiesCache::value_type;
183
184 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
185 ObjectTree::const_iterator(it), container(container),
186 ret(container.cache.end())
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500187 {}
John Wang8a7236a2021-01-04 15:31:44 +0800188 value_type& operator*()
189 {
190 ret = container.get(ObjectTree::const_iterator::operator*().first);
191 return *ret;
192 }
193 value_type* operator->()
194 {
195 return &operator*();
196 }
197
198 private:
199 ObjectLookupCache& container;
200 PropertiesCache::iterator ret;
201 };
202
203 iterator begin() noexcept
204 {
205 return iterator(objs.begin(), *this);
206 }
207
208 iterator end() noexcept
209 {
210 return iterator(objs.end(), *this);
211 }
212
213 private:
Patrick Williams5d82f472022-07-22 19:26:53 -0500214 sdbusplus::bus_t& bus;
John Wang8a7236a2021-01-04 15:31:44 +0800215 const ChannelParams& params;
216 const char* const intf;
217 const ObjectTree objs;
218 PropertiesCache cache;
219
220 /** @brief Gets a cached copy of the object properties if possible
221 * Otherwise performs a query on DBus to look them up
222 *
223 * @param[in] path - The object path to lookup
224 * @return An iterator for the specified object path + properties
225 */
226 PropertiesCache::iterator get(const std::string& path)
227 {
228 auto it = cache.find(path);
229 if (it != cache.end())
230 {
231 return it;
232 }
233 auto properties = getAllDbusProperties(bus, params.service, path, intf);
234 return cache.insert({path, std::move(properties)}).first;
235 }
236};
237
John Wang8a7236a2021-01-04 15:31:44 +0800238/** @brief Searches the ip object lookup cache for an address matching
239 * the input parameters. NOTE: The index lacks stability across address
240 * changes since the network daemon has no notion of stable indicies.
241 *
242 * @param[in] bus - The bus object used for lookups
243 * @param[in] params - The parameters for the channel
244 * @param[in] idx - The index of the desired address on the interface
245 * @param[in] origins - The allowed origins for the address objects
246 * @param[in] ips - The object lookup cache holding all of the address info
247 * @return The address and prefix if it was found
248 */
249template <int family>
250std::optional<IfAddr<family>> findIfAddr(
Patrick Williams5d82f472022-07-22 19:26:53 -0500251 [[maybe_unused]] sdbusplus::bus_t& bus,
Willy Tu11d68892022-01-20 10:37:34 -0800252 [[maybe_unused]] const ChannelParams& params, uint8_t idx,
John Wang8a7236a2021-01-04 15:31:44 +0800253 const std::unordered_set<
Willy Tu523e2d12023-09-05 11:36:48 -0700254 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin>&
John Wang8a7236a2021-01-04 15:31:44 +0800255 origins,
256 ObjectLookupCache& ips)
257{
258 for (const auto& [path, properties] : ips)
259 {
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700260 std::optional<typename AddrFamily<family>::addr> addr;
261 try
262 {
263 addr.emplace(stdplus::fromStr<typename AddrFamily<family>::addr>(
264 std::get<std::string>(properties.at("Address"))));
265 }
266 catch (...)
John Wang8a7236a2021-01-04 15:31:44 +0800267 {
268 continue;
269 }
270
Willy Tu523e2d12023-09-05 11:36:48 -0700271 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin
272 origin = sdbusplus::server::xyz::openbmc_project::network::IP::
John Wang8a7236a2021-01-04 15:31:44 +0800273 convertAddressOriginFromString(
274 std::get<std::string>(properties.at("Origin")));
275 if (origins.find(origin) == origins.end())
276 {
277 continue;
278 }
279
280 if (idx > 0)
281 {
282 idx--;
283 continue;
284 }
285
286 IfAddr<family> ifaddr;
287 ifaddr.path = path;
288 ifaddr.address = *addr;
289 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
290 ifaddr.origin = origin;
Willy Tu11d68892022-01-20 10:37:34 -0800291 return ifaddr;
John Wang8a7236a2021-01-04 15:31:44 +0800292 }
293
294 return std::nullopt;
295}
296/** @brief Trivial helper around findIfAddr that simplifies calls
297 * for one off lookups. Don't use this if you intend to do multiple
298 * lookups at a time.
299 *
300 * @param[in] bus - The bus object used for lookups
301 * @param[in] params - The parameters for the channel
302 * @param[in] idx - The index of the desired address on the interface
303 * @param[in] origins - The allowed origins for the address objects
304 * @return The address and prefix if it was found
305 */
306template <int family>
307auto getIfAddr(
Patrick Williams5d82f472022-07-22 19:26:53 -0500308 sdbusplus::bus_t& bus, const ChannelParams& params, uint8_t idx,
John Wang8a7236a2021-01-04 15:31:44 +0800309 const std::unordered_set<
Willy Tu523e2d12023-09-05 11:36:48 -0700310 sdbusplus::server::xyz::openbmc_project::network::IP::AddressOrigin>&
John Wang8a7236a2021-01-04 15:31:44 +0800311 origins)
312{
313 ObjectLookupCache ips(bus, params, INTF_IP);
314 return findIfAddr<family>(bus, params, idx, origins, ips);
315}
316
John Wang8a7236a2021-01-04 15:31:44 +0800317/** @brief Reconfigures the IPv6 address info configured for the interface
318 *
319 * @param[in] bus - The bus object used for lookups
320 * @param[in] params - The parameters for the channel
321 * @param[in] idx - The address index to operate on
322 * @param[in] address - The new address
323 * @param[in] prefix - The new address prefix
324 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500325void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700326 uint8_t idx, stdplus::In6Addr address, uint8_t prefix);
John Wang8a7236a2021-01-04 15:31:44 +0800327
328/** @brief Retrieves the current gateway for the address family on the system
Lei YUd1bd8c42021-08-11 17:13:56 +0800329 * NOTE: The gateway is per channel instead of the system wide one.
John Wang8a7236a2021-01-04 15:31:44 +0800330 *
331 * @param[in] bus - The bus object used for lookups
332 * @param[in] params - The parameters for the channel
333 * @return An address representing the gateway address if it exists
334 */
335template <int family>
336std::optional<typename AddrFamily<family>::addr>
Patrick Williams5d82f472022-07-22 19:26:53 -0500337 getGatewayProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
John Wang8a7236a2021-01-04 15:31:44 +0800338{
Lei YUd1bd8c42021-08-11 17:13:56 +0800339 auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
340 auto gatewayStr = std::get<std::string>(
341 getDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
342 AddrFamily<family>::propertyGateway));
John Wang8a7236a2021-01-04 15:31:44 +0800343 if (gatewayStr.empty())
344 {
345 return std::nullopt;
346 }
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700347 return stdplus::fromStr<typename AddrFamily<family>::addr>(gatewayStr);
John Wang8a7236a2021-01-04 15:31:44 +0800348}
349
350template <int family>
Patrick Williams1318a5e2024-08-16 15:19:54 -0400351std::optional<IfNeigh<family>> findStaticNeighbor(
352 sdbusplus::bus_t&, const ChannelParams&,
353 typename AddrFamily<family>::addr ip, ObjectLookupCache& neighbors)
John Wang8a7236a2021-01-04 15:31:44 +0800354{
Willy Tu523e2d12023-09-05 11:36:48 -0700355 using sdbusplus::server::xyz::openbmc_project::network::Neighbor;
John Wang8a7236a2021-01-04 15:31:44 +0800356 const auto state =
Willy Tu523e2d12023-09-05 11:36:48 -0700357 sdbusplus::common::xyz::openbmc_project::network::convertForMessage(
John Wang8a7236a2021-01-04 15:31:44 +0800358 Neighbor::State::Permanent);
359 for (const auto& [path, neighbor] : neighbors)
360 {
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700361 std::optional<typename AddrFamily<family>::addr> neighIP;
362 try
363 {
364 neighIP.emplace(stdplus::fromStr<typename AddrFamily<family>::addr>(
365 std::get<std::string>(neighbor.at("IPAddress"))));
366 }
367 catch (...)
John Wang8a7236a2021-01-04 15:31:44 +0800368 {
369 continue;
370 }
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700371 if (*neighIP != ip)
John Wang8a7236a2021-01-04 15:31:44 +0800372 {
373 continue;
374 }
375 if (state != std::get<std::string>(neighbor.at("State")))
376 {
377 continue;
378 }
379
380 IfNeigh<family> ret;
381 ret.path = path;
382 ret.ip = ip;
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700383 ret.mac = stdplus::fromStr<stdplus::EtherAddr>(
384 std::get<std::string>(neighbor.at("MACAddress")));
Willy Tu11d68892022-01-20 10:37:34 -0800385 return ret;
John Wang8a7236a2021-01-04 15:31:44 +0800386 }
387
388 return std::nullopt;
389}
390
391template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500392void createNeighbor(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700393 typename AddrFamily<family>::addr address,
394 stdplus::EtherAddr mac)
John Wang8a7236a2021-01-04 15:31:44 +0800395{
Patrick Williams1318a5e2024-08-16 15:19:54 -0400396 auto newreq =
397 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
398 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700399 stdplus::ToStrHandle<stdplus::ToStr<stdplus::EtherAddr>> macToStr;
400 stdplus::ToStrHandle<stdplus::ToStr<typename AddrFamily<family>::addr>>
401 addrToStr;
402 newreq.append(addrToStr(address), macToStr(mac));
John Wang8a7236a2021-01-04 15:31:44 +0800403 bus.call_noreply(newreq);
404}
405
406/** @brief Deletes the dbus object. Ignores empty objects or objects that are
407 * missing from the bus.
408 *
409 * @param[in] bus - The bus object used for lookups
410 * @param[in] service - The name of the service
411 * @param[in] path - The path of the object to delete
412 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500413void deleteObjectIfExists(sdbusplus::bus_t& bus, const std::string& service,
John Wang8a7236a2021-01-04 15:31:44 +0800414 const std::string& path);
415
Lei YUd1bd8c42021-08-11 17:13:56 +0800416/** @brief Sets the value for the default gateway of the channel
John Wang8a7236a2021-01-04 15:31:44 +0800417 *
418 * @param[in] bus - The bus object used for lookups
419 * @param[in] params - The parameters for the channel
420 * @param[in] gateway - Gateway address to apply
421 */
422template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500423void setGatewayProperty(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700424 typename AddrFamily<family>::addr address)
John Wang8a7236a2021-01-04 15:31:44 +0800425{
426 // Save the old gateway MAC address if it exists so we can recreate it
427 auto gateway = getGatewayProperty<family>(bus, params);
428 std::optional<IfNeigh<family>> neighbor;
429 if (gateway)
430 {
431 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
432 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
433 }
434
Lei YUd1bd8c42021-08-11 17:13:56 +0800435 auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
436 setDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
John Wang8a7236a2021-01-04 15:31:44 +0800437 AddrFamily<family>::propertyGateway,
William A. Kennington III726f2bd2023-06-21 01:11:40 -0700438 stdplus::toStr(address));
John Wang8a7236a2021-01-04 15:31:44 +0800439
440 // Restore the gateway MAC if we had one
441 if (neighbor)
442 {
443 deleteObjectIfExists(bus, params.service, neighbor->path);
444 createNeighbor<family>(bus, params, address, neighbor->mac);
445 }
446}
447
Patrick Venture690a2342020-05-17 11:51:31 -0700448} // namespace transport
449} // namespace ipmi