blob: b62de83afde5457cad0fab45bca18d1e648adcb7 [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"
4#include "user_channel/cipher_mgmt.hpp"
5
6#include <arpa/inet.h>
7#include <netinet/ether.h>
8
9#include <array>
10#include <bitset>
11#include <cinttypes>
Patrick Venture690a2342020-05-17 11:51:31 -070012#include <cstdint>
John Wang8a7236a2021-01-04 15:31:44 +080013#include <cstring>
14#include <fstream>
15#include <functional>
Patrick Venture690a2342020-05-17 11:51:31 -070016#include <ipmid/api-types.hpp>
John Wang8a7236a2021-01-04 15:31:44 +080017#include <ipmid/api.hpp>
18#include <ipmid/message.hpp>
19#include <ipmid/message/types.hpp>
20#include <ipmid/types.hpp>
21#include <ipmid/utils.hpp>
22#include <optional>
23#include <phosphor-logging/elog-errors.hpp>
24#include <phosphor-logging/elog.hpp>
25#include <phosphor-logging/log.hpp>
26#include <sdbusplus/bus.hpp>
27#include <sdbusplus/exception.hpp>
28#include <string>
29#include <string_view>
30#include <type_traits>
31#include <unordered_map>
32#include <unordered_set>
33#include <user_channel/channel_layer.hpp>
34#include <utility>
35#include <vector>
36#include <xyz/openbmc_project/Common/error.hpp>
37#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
38#include <xyz/openbmc_project/Network/IP/server.hpp>
39#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
Patrick Venture690a2342020-05-17 11:51:31 -070040
41namespace ipmi
42{
43namespace transport
44{
45
John Wang8a7236a2021-01-04 15:31:44 +080046// D-Bus Network Daemon definitions
47constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
John Wang8a7236a2021-01-04 15:31:44 +080048constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
49constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
50constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
51constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
52constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
53constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
54 "xyz.openbmc_project.Network.Neighbor.CreateStatic";
55constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
56constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
57
Patrick Venture690a2342020-05-17 11:51:31 -070058/** @brief IPMI LAN Parameters */
59enum class LanParam : uint8_t
60{
61 SetStatus = 0,
62 AuthSupport = 1,
63 AuthEnables = 2,
64 IP = 3,
65 IPSrc = 4,
66 MAC = 5,
67 SubnetMask = 6,
68 Gateway1 = 12,
69 Gateway1MAC = 13,
70 VLANId = 20,
71 CiphersuiteSupport = 22,
72 CiphersuiteEntries = 23,
73 cipherSuitePrivilegeLevels = 24,
74 IPFamilySupport = 50,
75 IPFamilyEnables = 51,
76 IPv6Status = 55,
77 IPv6StaticAddresses = 56,
78 IPv6DynamicAddresses = 59,
79 IPv6RouterControl = 64,
80 IPv6StaticRouter1IP = 65,
81 IPv6StaticRouter1MAC = 66,
82 IPv6StaticRouter1PrefixLength = 67,
83 IPv6StaticRouter1PrefixValue = 68,
84};
85
86/** @brief IPMI IP Origin Types */
87enum class IPSrc : uint8_t
88{
89 Unspecified = 0,
90 Static = 1,
91 DHCP = 2,
92 BIOS = 3,
93 BMC = 4,
94};
95
96/** @brief IPMI Set Status */
97enum class SetStatus : uint8_t
98{
99 Complete = 0,
100 InProgress = 1,
101 Commit = 2,
102};
103
104/** @brief IPMI Family Suport Bits */
105namespace IPFamilySupportFlag
106{
107constexpr uint8_t IPv6Only = 0;
108constexpr uint8_t DualStack = 1;
109constexpr uint8_t IPv6Alerts = 2;
110} // namespace IPFamilySupportFlag
111
112/** @brief IPMI IPFamily Enables Flag */
113enum class IPFamilyEnables : uint8_t
114{
115 IPv4Only = 0,
116 IPv6Only = 1,
117 DualStack = 2,
118};
119
120/** @brief IPMI IPv6 Dyanmic Status Bits */
121namespace IPv6StatusFlag
122{
123constexpr uint8_t DHCP = 0;
124constexpr uint8_t SLAAC = 1;
125}; // namespace IPv6StatusFlag
126
127/** @brief IPMI IPv6 Source */
128enum class IPv6Source : uint8_t
129{
130 Static = 0,
131 SLAAC = 1,
132 DHCP = 2,
133};
134
135/** @brief IPMI IPv6 Address Status */
136enum class IPv6AddressStatus : uint8_t
137{
138 Active = 0,
139 Disabled = 1,
140};
141
142namespace IPv6RouterControlFlag
143{
144constexpr uint8_t Static = 0;
145constexpr uint8_t Dynamic = 1;
146}; // namespace IPv6RouterControlFlag
147
148// LAN Handler specific response codes
149constexpr Cc ccParamNotSupported = 0x80;
150constexpr Cc ccParamSetLocked = 0x81;
151constexpr Cc ccParamReadOnly = 0x82;
152
153// VLANs are a 12-bit value
154constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
155constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
156
157// Arbitrary v6 Address Limits to prevent too much output in ipmitool
158constexpr uint8_t MAX_IPV6_STATIC_ADDRESSES = 15;
159constexpr uint8_t MAX_IPV6_DYNAMIC_ADDRESSES = 15;
160
John Wang8a7236a2021-01-04 15:31:44 +0800161/** @brief The dbus parameters for the interface corresponding to a channel
162 * This helps reduce the number of mapper lookups we need for each
163 * query and simplifies finding the VLAN interface if needed.
164 */
165struct ChannelParams
166{
167 /** @brief The channel ID */
168 int id;
169 /** @brief channel name for the interface */
170 std::string ifname;
171 /** @brief Name of the service on the bus */
172 std::string service;
173 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
174 std::string ifPath;
175 /** @brief Logical adapter path used for address assignment */
176 std::string logicalPath;
177};
178
179/** @brief A trivial helper used to determine if two PODs are equal
180 *
181 * @params[in] a - The first object to compare
182 * @params[in] b - The second object to compare
183 * @return True if the objects are the same bytewise
184 */
185template <typename T>
186bool equal(const T& a, const T& b)
187{
188 static_assert(std::is_trivially_copyable_v<T>);
189 return std::memcmp(&a, &b, sizeof(T)) == 0;
190}
191
192/** @brief Copies bytes from an array into a trivially copyable container
193 *
194 * @params[out] t - The container receiving the data
195 * @params[in] bytes - The data to copy
196 */
197template <size_t N, typename T>
198void copyInto(T& t, const std::array<uint8_t, N>& bytes)
199{
200 static_assert(std::is_trivially_copyable_v<T>);
201 static_assert(N == sizeof(T));
202 std::memcpy(&t, bytes.data(), bytes.size());
203}
204
205/** @brief Gets a generic view of the bytes in the input container
206 *
207 * @params[in] t - The data to reference
208 * @return A string_view referencing the bytes in the container
209 */
210template <typename T>
211std::string_view dataRef(const T& t)
212{
213 static_assert(std::is_trivially_copyable_v<T>);
214 return {reinterpret_cast<const char*>(&t), sizeof(T)};
215}
216
217/** @brief Determines the ethernet interface name corresponding to a channel
218 * Tries to map a VLAN object first so that the address information
219 * is accurate. Otherwise it gets the standard ethernet interface.
220 *
221 * @param[in] bus - The bus object used for lookups
222 * @param[in] channel - The channel id corresponding to an ethernet interface
223 * @return Ethernet interface service and object path if it exists
224 */
225std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
226 uint8_t channel);
227
228/** @brief A trivial helper around maybeGetChannelParams() that throws an
229 * exception when it is unable to acquire parameters for the channel.
230 *
231 * @param[in] bus - The bus object used for lookups
232 * @param[in] channel - The channel id corresponding to an ethernet interface
233 * @return Ethernet interface service and object path
234 */
235ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel);
236
237/** @brief Trivializes using parameter getter functions by providing a bus
238 * and channel parameters automatically.
239 *
240 * @param[in] channel - The channel id corresponding to an ethernet interface
241 * ...
242 */
243template <auto func, typename... Args>
244auto channelCall(uint8_t channel, Args&&... args)
245{
246 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
247 auto params = getChannelParams(bus, channel);
248 return std::invoke(func, bus, params, std::forward<Args>(args)...);
249}
250
251/** @brief Generic paramters for different address families */
252template <int family>
253struct AddrFamily
254{
255};
256
257/** @brief Parameter specialization for IPv4 */
258template <>
259struct AddrFamily<AF_INET>
260{
261 using addr = in_addr;
262 static constexpr auto protocol =
263 sdbusplus::xyz::openbmc_project::Network::server::IP::Protocol::IPv4;
264 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
265 static constexpr uint8_t defaultPrefix = 32;
266 static constexpr char propertyGateway[] = "DefaultGateway";
267};
268
269/** @brief Parameter specialization for IPv6 */
270template <>
271struct AddrFamily<AF_INET6>
272{
273 using addr = in6_addr;
274 static constexpr auto protocol =
275 sdbusplus::xyz::openbmc_project::Network::server::IP::Protocol::IPv6;
276 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
277 static constexpr uint8_t defaultPrefix = 128;
278 static constexpr char propertyGateway[] = "DefaultGateway6";
279};
280
281/** @brief Interface Neighbor configuration parameters */
282template <int family>
283struct IfNeigh
284{
285 std::string path;
286 typename AddrFamily<family>::addr ip;
287 ether_addr mac;
288};
289
290/** @brief Interface IP Address configuration parameters */
291template <int family>
292struct IfAddr
293{
294 std::string path;
295 typename AddrFamily<family>::addr address;
296 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin origin;
297 uint8_t prefix;
298};
299
300/** @brief Valid address origins for IPv6 */
301static inline const std::unordered_set<
302 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>
303 originsV6Static = {sdbusplus::xyz::openbmc_project::Network::server::IP::
304 AddressOrigin::Static};
305static inline const std::unordered_set<
306 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>
307 originsV6Dynamic = {
308 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin::
309 DHCP,
310 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin::
311 SLAAC,
312};
313
314/** @brief A lazy lookup mechanism for iterating over object properties stored
315 * in DBus. This will only perform the object lookup when needed, and
316 * retains a cache of previous lookups to speed up future iterations.
317 */
318class ObjectLookupCache
319{
320 public:
321 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
322
323 /** @brief Creates a new ObjectLookupCache for the interface on the bus
324 * NOTE: The inputs to this object must outlive the object since
325 * they are only referenced by it.
326 *
327 * @param[in] bus - The bus object used for lookups
328 * @param[in] params - The parameters for the channel
329 * @param[in] intf - The interface we are looking up
330 */
331 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
332 const char* intf) :
333 bus(bus),
334 params(params), intf(intf),
335 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
336 {
337 }
338
339 class iterator : public ObjectTree::const_iterator
340 {
341 public:
342 using value_type = PropertiesCache::value_type;
343
344 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
345 ObjectTree::const_iterator(it), container(container),
346 ret(container.cache.end())
347 {
348 }
349 value_type& operator*()
350 {
351 ret = container.get(ObjectTree::const_iterator::operator*().first);
352 return *ret;
353 }
354 value_type* operator->()
355 {
356 return &operator*();
357 }
358
359 private:
360 ObjectLookupCache& container;
361 PropertiesCache::iterator ret;
362 };
363
364 iterator begin() noexcept
365 {
366 return iterator(objs.begin(), *this);
367 }
368
369 iterator end() noexcept
370 {
371 return iterator(objs.end(), *this);
372 }
373
374 private:
375 sdbusplus::bus::bus& bus;
376 const ChannelParams& params;
377 const char* const intf;
378 const ObjectTree objs;
379 PropertiesCache cache;
380
381 /** @brief Gets a cached copy of the object properties if possible
382 * Otherwise performs a query on DBus to look them up
383 *
384 * @param[in] path - The object path to lookup
385 * @return An iterator for the specified object path + properties
386 */
387 PropertiesCache::iterator get(const std::string& path)
388 {
389 auto it = cache.find(path);
390 if (it != cache.end())
391 {
392 return it;
393 }
394 auto properties = getAllDbusProperties(bus, params.service, path, intf);
395 return cache.insert({path, std::move(properties)}).first;
396 }
397};
398
399/** @brief Turns an IP address string into the network byte order form
400 * NOTE: This version strictly validates family matches
401 *
402 * @param[in] address - The string form of the address
403 * @return A network byte order address or none if conversion failed
404 */
405template <int family>
406std::optional<typename AddrFamily<family>::addr>
407 maybeStringToAddr(const char* address)
408{
409 typename AddrFamily<family>::addr ret;
410 if (inet_pton(family, address, &ret) == 1)
411 {
412 return ret;
413 }
414 return std::nullopt;
415}
416
417/** @brief Turns an IP address string into the network byte order form
418 * NOTE: This version strictly validates family matches
419 *
420 * @param[in] address - The string form of the address
421 * @return A network byte order address
422 */
423template <int family>
424typename AddrFamily<family>::addr stringToAddr(const char* address)
425{
426 auto ret = maybeStringToAddr<family>(address);
427 if (!ret)
428 {
429 phosphor::logging::log<phosphor::logging::level::ERR>(
430 "Failed to convert IP Address",
431 phosphor::logging::entry("FAMILY=%d", family),
432 phosphor::logging::entry("ADDRESS=%s", address));
433 phosphor::logging::elog<
434 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
435 }
436 return *ret;
437}
438
439/** @brief Turns an IP address in network byte order into a string
440 *
441 * @param[in] address - The string form of the address
442 * @return A network byte order address
443 */
444template <int family>
445std::string addrToString(const typename AddrFamily<family>::addr& address)
446{
447 std::string ret(AddrFamily<family>::maxStrLen, '\0');
448 inet_ntop(family, &address, ret.data(), ret.size());
449 ret.resize(strlen(ret.c_str()));
450 return ret;
451}
452
453/** @brief Converts a human readable MAC string into MAC bytes
454 *
455 * @param[in] mac - The MAC string
456 * @return MAC in bytes
457 */
458ether_addr stringToMAC(const char* mac);
459/** @brief Searches the ip object lookup cache for an address matching
460 * the input parameters. NOTE: The index lacks stability across address
461 * changes since the network daemon has no notion of stable indicies.
462 *
463 * @param[in] bus - The bus object used for lookups
464 * @param[in] params - The parameters for the channel
465 * @param[in] idx - The index of the desired address on the interface
466 * @param[in] origins - The allowed origins for the address objects
467 * @param[in] ips - The object lookup cache holding all of the address info
468 * @return The address and prefix if it was found
469 */
470template <int family>
471std::optional<IfAddr<family>> findIfAddr(
472 sdbusplus::bus::bus& bus, const ChannelParams& params, uint8_t idx,
473 const std::unordered_set<
474 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>&
475 origins,
476 ObjectLookupCache& ips)
477{
478 for (const auto& [path, properties] : ips)
479 {
480 const auto& addrStr = std::get<std::string>(properties.at("Address"));
481 auto addr = maybeStringToAddr<family>(addrStr.c_str());
482 if (!addr)
483 {
484 continue;
485 }
486
487 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin
488 origin = sdbusplus::xyz::openbmc_project::Network::server::IP::
489 convertAddressOriginFromString(
490 std::get<std::string>(properties.at("Origin")));
491 if (origins.find(origin) == origins.end())
492 {
493 continue;
494 }
495
496 if (idx > 0)
497 {
498 idx--;
499 continue;
500 }
501
502 IfAddr<family> ifaddr;
503 ifaddr.path = path;
504 ifaddr.address = *addr;
505 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
506 ifaddr.origin = origin;
507 return std::move(ifaddr);
508 }
509
510 return std::nullopt;
511}
512/** @brief Trivial helper around findIfAddr that simplifies calls
513 * for one off lookups. Don't use this if you intend to do multiple
514 * lookups at a time.
515 *
516 * @param[in] bus - The bus object used for lookups
517 * @param[in] params - The parameters for the channel
518 * @param[in] idx - The index of the desired address on the interface
519 * @param[in] origins - The allowed origins for the address objects
520 * @return The address and prefix if it was found
521 */
522template <int family>
523auto getIfAddr(
524 sdbusplus::bus::bus& bus, const ChannelParams& params, uint8_t idx,
525 const std::unordered_set<
526 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>&
527 origins)
528{
529 ObjectLookupCache ips(bus, params, INTF_IP);
530 return findIfAddr<family>(bus, params, idx, origins, ips);
531}
532
533/** @brief Determines if the ethernet interface is using DHCP
534 *
535 * @param[in] bus - The bus object used for lookups
536 * @param[in] params - The parameters for the channel
537 * @return DHCPConf enumeration
538 */
539sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface::DHCPConf
540 getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params);
541
542/** @brief Sets the DHCP v6 state on the given interface
543 *
544 * @param[in] bus - The bus object used for lookups
545 * @param[in] params - The parameters for the channel
546 * @param[in] requestedDhcp - DHCP state to assign (none, v6, both)
547 * @param[in] defaultMode - True: Use algorithmic assignment
548 * False: requestedDhcp assigned unconditionally
549 */
550void setDHCPv6Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
551 const sdbusplus::xyz::openbmc_project::Network::server::
552 EthernetInterface::DHCPConf requestedDhcp,
553 const bool defaultMode);
554
555/** @brief Reconfigures the IPv6 address info configured for the interface
556 *
557 * @param[in] bus - The bus object used for lookups
558 * @param[in] params - The parameters for the channel
559 * @param[in] idx - The address index to operate on
560 * @param[in] address - The new address
561 * @param[in] prefix - The new address prefix
562 */
563void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
564 uint8_t idx, const in6_addr& address, uint8_t prefix);
565
566/** @brief Retrieves the current gateway for the address family on the system
Lei YUd1bd8c42021-08-11 17:13:56 +0800567 * NOTE: The gateway is per channel instead of the system wide one.
John Wang8a7236a2021-01-04 15:31:44 +0800568 *
569 * @param[in] bus - The bus object used for lookups
570 * @param[in] params - The parameters for the channel
571 * @return An address representing the gateway address if it exists
572 */
573template <int family>
574std::optional<typename AddrFamily<family>::addr>
575 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
576{
Lei YUd1bd8c42021-08-11 17:13:56 +0800577 auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
578 auto gatewayStr = std::get<std::string>(
579 getDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
580 AddrFamily<family>::propertyGateway));
John Wang8a7236a2021-01-04 15:31:44 +0800581 if (gatewayStr.empty())
582 {
583 return std::nullopt;
584 }
585 return stringToAddr<family>(gatewayStr.c_str());
586}
587
588template <int family>
589std::optional<IfNeigh<family>>
590 findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
591 const typename AddrFamily<family>::addr& ip,
592 ObjectLookupCache& neighbors)
593{
594 using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
595 const auto state =
596 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
597 Neighbor::State::Permanent);
598 for (const auto& [path, neighbor] : neighbors)
599 {
600 const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
601 auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
602 if (!neighIP)
603 {
604 continue;
605 }
606 if (!equal(*neighIP, ip))
607 {
608 continue;
609 }
610 if (state != std::get<std::string>(neighbor.at("State")))
611 {
612 continue;
613 }
614
615 IfNeigh<family> ret;
616 ret.path = path;
617 ret.ip = ip;
618 const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
619 ret.mac = stringToMAC(macStr.c_str());
620 return std::move(ret);
621 }
622
623 return std::nullopt;
624}
625
626template <int family>
627void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
628 const typename AddrFamily<family>::addr& address,
629 const ether_addr& mac)
630{
631 auto newreq =
632 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
633 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
634 std::string macStr = ether_ntoa(&mac);
635 newreq.append(addrToString<family>(address), macStr);
636 bus.call_noreply(newreq);
637}
638
639/** @brief Deletes the dbus object. Ignores empty objects or objects that are
640 * missing from the bus.
641 *
642 * @param[in] bus - The bus object used for lookups
643 * @param[in] service - The name of the service
644 * @param[in] path - The path of the object to delete
645 */
646void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
647 const std::string& path);
648
Lei YUd1bd8c42021-08-11 17:13:56 +0800649/** @brief Sets the value for the default gateway of the channel
John Wang8a7236a2021-01-04 15:31:44 +0800650 *
651 * @param[in] bus - The bus object used for lookups
652 * @param[in] params - The parameters for the channel
653 * @param[in] gateway - Gateway address to apply
654 */
655template <int family>
656void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
657 const typename AddrFamily<family>::addr& address)
658{
659 // Save the old gateway MAC address if it exists so we can recreate it
660 auto gateway = getGatewayProperty<family>(bus, params);
661 std::optional<IfNeigh<family>> neighbor;
662 if (gateway)
663 {
664 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
665 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
666 }
667
Lei YUd1bd8c42021-08-11 17:13:56 +0800668 auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
669 setDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
John Wang8a7236a2021-01-04 15:31:44 +0800670 AddrFamily<family>::propertyGateway,
671 addrToString<family>(address));
672
673 // Restore the gateway MAC if we had one
674 if (neighbor)
675 {
676 deleteObjectIfExists(bus, params.service, neighbor->path);
677 createNeighbor<family>(bus, params, address, neighbor->mac);
678 }
679}
680
Patrick Venture690a2342020-05-17 11:51:31 -0700681} // namespace transport
682} // namespace ipmi