blob: 2ca9c1822e89258502ccf338c56fc265be8c464c [file] [log] [blame]
Gunnar Mills57d9c502018-09-14 14:42:34 -05001#include "config.h"
2
Patrick Venture189d44e2018-07-09 12:30:59 -07003#include "ethernet_interface.hpp"
4
Ratan Gupta497c0c92017-08-22 19:15:59 +05305#include "config_parser.hpp"
William A. Kennington III08505792019-01-30 16:00:04 -08006#include "neighbor.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05307#include "network_manager.hpp"
Ravi Tejaa5a09442020-07-17 00:57:33 -05008#include "routing_table.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05309#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +053010
Ratan Gupta82549cc2017-04-21 08:45:23 +053011#include <arpa/inet.h>
William A. Kennington III26275a32021-07-13 20:32:42 -070012#include <fmt/format.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053013#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070014#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053015#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053016#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053017#include <netinet/in.h>
18#include <sys/ioctl.h>
19#include <sys/socket.h>
20#include <unistd.h>
21
Ratan Gupta82549cc2017-04-21 08:45:23 +053022#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053023#include <filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053024#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070025#include <phosphor-logging/elog-errors.hpp>
26#include <phosphor-logging/log.hpp>
William A. Kennington III26275a32021-07-13 20:32:42 -070027#include <sdbusplus/bus/match.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053028#include <sstream>
William A. Kennington III12beaad2020-06-13 19:30:41 -070029#include <stdplus/raw.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053030#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070031#include <string_view>
William A. Kennington III26275a32021-07-13 20:32:42 -070032#include <unordered_map>
33#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070034#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053035
Ratan Gupta91a99cc2017-04-14 16:32:09 +053036namespace phosphor
37{
38namespace network
39{
40
41using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053042using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053043using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
44using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050045using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053046constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
47constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
48constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
49constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
50constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053051
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080052struct EthernetIntfSocket
53{
54 EthernetIntfSocket(int domain, int type, int protocol)
55 {
56 if ((sock = socket(domain, type, protocol)) < 0)
57 {
58 log<level::ERR>("socket creation failed:",
59 entry("ERROR=%s", strerror(errno)));
60 }
61 }
62
63 ~EthernetIntfSocket()
64 {
65 if (sock >= 0)
66 {
67 close(sock);
68 }
69 }
70
71 int sock{-1};
72};
73
Johnathan Mantey817012a2020-01-30 15:07:39 -080074std::map<EthernetInterface::DHCPConf, std::string> mapDHCPToSystemd = {
75 {EthernetInterface::DHCPConf::both, "true"},
76 {EthernetInterface::DHCPConf::v4, "ipv4"},
77 {EthernetInterface::DHCPConf::v6, "ipv6"},
78 {EthernetInterface::DHCPConf::none, "false"}};
79
Ratan Gupta91a99cc2017-04-14 16:32:09 +053080EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
81 const std::string& objPath,
Johnathan Mantey817012a2020-01-30 15:07:39 -080082 DHCPConf dhcpEnabled, Manager& parent,
William A. Kennington III26275a32021-07-13 20:32:42 -070083 bool emitSignal,
84 std::optional<bool> enabled) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050085 Ifaces(bus, objPath.c_str(), true),
86 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053087{
88 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053089 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053090 interfaceName(intfName);
Patrick Williams6aef7692021-05-01 06:39:41 -050091 EthernetInterfaceIntf::dhcpEnabled(dhcpEnabled);
92 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRAFromConf());
William A. Kennington III26275a32021-07-13 20:32:42 -070093 EthernetInterfaceIntf::nicEnabled(enabled ? *enabled : queryNicEnabled());
Ravi Tejaa5a09442020-07-17 00:57:33 -050094 route::Table routingTable;
95 auto gatewayList = routingTable.getDefaultGateway();
96 auto gateway6List = routingTable.getDefaultGateway6();
97 std::string defaultGateway;
98 std::string defaultGateway6;
99
100 for (auto& gateway : gatewayList)
101 {
102 if (gateway.first == intfName)
103 {
104 defaultGateway = gateway.second;
105 break;
106 }
107 }
108
109 for (auto& gateway6 : gateway6List)
110 {
111 if (gateway6.first == intfName)
112 {
113 defaultGateway6 = gateway6.second;
114 break;
115 }
116 }
117
118 EthernetInterfaceIntf::defaultGateway(defaultGateway);
119 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
Ratan Gupta99801ce2020-01-09 18:37:16 +0530120 // Don't get the mac address from the system as the mac address
121 // would be same as parent interface.
122 if (intfName.find(".") == std::string::npos)
123 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500124 MacAddressIntf::macAddress(getMACAddress(intfName));
Ratan Gupta99801ce2020-01-09 18:37:16 +0530125 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500126 EthernetInterfaceIntf::ntpServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +0530127
128 EthernetInterfaceIntf::linkUp(linkUp());
Ratan Gupta613a0122020-04-24 15:18:53 +0530129
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700130#ifdef NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -0700131 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
132
133 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
134 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800135#endif
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530136
Ratan Gupta29b0e432017-05-25 12:51:40 +0530137 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530138 if (emitSignal)
139 {
140 this->emit_object_added();
141 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530142}
143
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800144static IP::Protocol convertFamily(int family)
145{
146 switch (family)
147 {
148 case AF_INET:
149 return IP::Protocol::IPv4;
150 case AF_INET6:
151 return IP::Protocol::IPv6;
152 }
153
154 throw std::invalid_argument("Bad address family");
155}
156
Johnathan Mantey817012a2020-01-30 15:07:39 -0800157void EthernetInterface::disableDHCP(IP::Protocol protocol)
158{
Patrick Williams6aef7692021-05-01 06:39:41 -0500159 DHCPConf dhcpState = EthernetInterfaceIntf::dhcpEnabled();
Johnathan Mantey817012a2020-01-30 15:07:39 -0800160 if (dhcpState == EthernetInterface::DHCPConf::both)
161 {
162 if (protocol == IP::Protocol::IPv4)
163 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500164 dhcpEnabled(EthernetInterface::DHCPConf::v6);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800165 }
166 else if (protocol == IP::Protocol::IPv6)
167 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500168 dhcpEnabled(EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800169 }
170 }
171 else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
172 (protocol == IP::Protocol::IPv4))
173 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500174 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800175 }
176 else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
177 (protocol == IP::Protocol::IPv6))
178 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500179 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800180 }
181}
182
183bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol)
184{
Patrick Williams6aef7692021-05-01 06:39:41 -0500185 return ((EthernetInterfaceIntf::dhcpEnabled() ==
Johnathan Mantey817012a2020-01-30 15:07:39 -0800186 EthernetInterface::DHCPConf::both) ||
Patrick Williams6aef7692021-05-01 06:39:41 -0500187 ((EthernetInterfaceIntf::dhcpEnabled() ==
Johnathan Mantey817012a2020-01-30 15:07:39 -0800188 EthernetInterface::DHCPConf::v6) &&
189 ((family == IP::Protocol::IPv6) || ignoreProtocol)) ||
Patrick Williams6aef7692021-05-01 06:39:41 -0500190 ((EthernetInterfaceIntf::dhcpEnabled() ==
Johnathan Mantey817012a2020-01-30 15:07:39 -0800191 EthernetInterface::DHCPConf::v4) &&
192 ((family == IP::Protocol::IPv4) || ignoreProtocol)));
193}
194
195bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family,
196 const std::string& nextDHCPState)
197{
198 return ((nextDHCPState == "true") ||
199 ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) ||
200 ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4)));
201}
202
203bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
204{
205 return (
206#ifdef LINK_LOCAL_AUTOCONFIGURATION
207 (origin == IP::AddressOrigin::Static)
208#else
209 (origin == IP::AddressOrigin::Static ||
210 origin == IP::AddressOrigin::LinkLocal)
211#endif
212
213 );
214}
215
Ratan Gupta87c13982017-06-15 09:27:27 +0530216void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530217{
Ratan Gupta87c13982017-06-15 09:27:27 +0530218 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530219
Ratan Gupta87c13982017-06-15 09:27:27 +0530220 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530221
Ratan Gupta6a387c12017-08-03 13:26:19 +0530222 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530223 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800224 IP::Protocol addressType = convertFamily(addr.addrType);
225 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800226 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530227 {
228 origin = IP::AddressOrigin::DHCP;
229 }
William A. Kennington III16893802019-01-30 16:01:01 -0800230 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530231 {
232 origin = IP::AddressOrigin::LinkLocal;
233 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700234 // Obsolete parameter
235 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530236
Gunnar Mills57d9c502018-09-14 14:42:34 -0500237 std::string ipAddressObjectPath = generateObjectPath(
Lei YU34027572021-08-11 15:23:52 +0800238 addressType, addr.ipaddress, addr.prefix, gateway, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530239
Lei YU7233c582021-04-08 14:39:43 +0800240 this->addrs.insert_or_assign(
241 addr.ipaddress,
242 std::make_shared<phosphor::network::IPAddress>(
243 bus, ipAddressObjectPath.c_str(), *this, addressType,
244 addr.ipaddress, origin, addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530245 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530246}
247
William A. Kennington III08505792019-01-30 16:00:04 -0800248void EthernetInterface::createStaticNeighborObjects()
249{
250 staticNeighbors.clear();
251
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700252 NeighborFilter filter;
253 filter.interface = ifIndex();
254 filter.state = NUD_PERMANENT;
255 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800256 for (const auto& neighbor : neighbors)
257 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700258 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800259 {
260 continue;
261 }
262 std::string ip = toString(neighbor.address);
263 std::string mac = mac_address::toString(*neighbor.mac);
264 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
265 staticNeighbors.emplace(ip,
266 std::make_shared<phosphor::network::Neighbor>(
267 bus, objectPath.c_str(), *this, ip, mac,
268 Neighbor::State::Permanent));
269 }
270}
271
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700272unsigned EthernetInterface::ifIndex() const
273{
274 unsigned idx = if_nametoindex(interfaceName().c_str());
275 if (idx == 0)
276 {
277 throw std::system_error(errno, std::generic_category(),
278 "if_nametoindex");
279 }
280 return idx;
281}
282
Patrick Williams6aef7692021-05-01 06:39:41 -0500283ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
raviteja-bce379562019-03-28 05:59:36 -0500284 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530285{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800286 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530287 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530288 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500289 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800290 disableDHCP(protType);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500291 }
292
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500293 IP::AddressOrigin origin = IP::AddressOrigin::Static;
294
295 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
296
297 if (!isValidIP(addressFamily, ipaddress))
298 {
299 log<level::ERR>("Not a valid IP address"),
300 entry("ADDRESS=%s", ipaddress.c_str());
301 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
302 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
303 }
304
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700305 // Gateway is an obsolete parameter
306 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500307
308 if (!isValidPrefix(addressFamily, prefixLength))
309 {
310 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700311 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500312 elog<InvalidArgument>(
313 Argument::ARGUMENT_NAME("prefixLength"),
314 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530315 }
316
Gunnar Mills57d9c502018-09-14 14:42:34 -0500317 std::string objectPath =
Lei YU34027572021-08-11 15:23:52 +0800318 generateObjectPath(protType, ipaddress, prefixLength, gateway, origin);
Lei YU7233c582021-04-08 14:39:43 +0800319 this->addrs.insert_or_assign(ipaddress,
320 std::make_shared<phosphor::network::IPAddress>(
321 bus, objectPath.c_str(), *this, protType,
322 ipaddress, origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530323
Ratan Guptae05083a2017-09-16 07:12:11 +0530324 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500325 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530326}
327
Patrick Williams6aef7692021-05-01 06:39:41 -0500328ObjectPath EthernetInterface::neighbor(std::string ipAddress,
329 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800330{
Patrick Williams6aef7692021-05-01 06:39:41 -0500331 if (!isValidIP(AF_INET, ipAddress) && !isValidIP(AF_INET6, ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800332 {
333 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500334 entry("ADDRESS=%s", ipAddress.c_str()));
335 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
336 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800337 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500338 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800339 {
340 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500341 entry("MACADDRESS=%s", ipAddress.c_str()));
342 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
343 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800344 }
345
346 std::string objectPath =
Patrick Williams6aef7692021-05-01 06:39:41 -0500347 generateStaticNeighborObjectPath(ipAddress, macAddress);
348 staticNeighbors.emplace(ipAddress,
William A. Kennington III08505792019-01-30 16:00:04 -0800349 std::make_shared<phosphor::network::Neighbor>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500350 bus, objectPath.c_str(), *this, ipAddress,
351 macAddress, Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800352 manager.writeToConfigurationFile();
353 return objectPath;
354}
355
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700356#ifdef NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530357/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800358 Enable this code if your NIC driver supports the ETHTOOL features.
359 Do this by adding the following to your phosphor-network*.bbappend file.
360 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
361 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530362*/
363InterfaceInfo EthernetInterface::getInterfaceInfo() const
364{
William A. Kennington III05368f12021-05-13 18:40:47 -0700365 ifreq ifr = {};
366 ethtool_cmd edata = {};
367 LinkSpeed speed = {};
368 Autoneg autoneg = {};
369 DuplexMode duplex = {};
370 LinkUp linkState = {};
371 NICEnabled enabled = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800372 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
373
374 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530375 {
William A. Kennington III96203312021-05-07 12:50:41 -0700376 return std::make_tuple(speed, duplex, autoneg, linkState, enabled);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800377 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530378
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800379 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
380 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530381
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800382 edata.cmd = ETHTOOL_GSET;
383 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
384 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530385 speed = edata.speed;
386 duplex = edata.duplex;
387 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530388 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800389
William A. Kennington III96203312021-05-07 12:50:41 -0700390 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800391 linkState = linkUp();
392
William A. Kennington III96203312021-05-07 12:50:41 -0700393 return std::make_tuple(speed, duplex, autoneg, linkState, enabled);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530394}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800395#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530396
397/** @brief get the mac address of the interface.
398 * @return macaddress on success
399 */
400
Gunnar Mills57d9c502018-09-14 14:42:34 -0500401std::string
402 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530403{
Patrick Williams6aef7692021-05-01 06:39:41 -0500404 std::string activeMACAddr = MacAddressIntf::macAddress();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800405 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
406
407 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530408 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800409 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530410 }
411
William A. Kennington III05368f12021-05-13 18:40:47 -0700412 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800413 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
414 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530415 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530416 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500417 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700418 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530419 }
420
William A. Kennington III1137a972019-04-20 20:49:58 -0700421 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
422 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
423 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700424 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530425}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530426
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530427std::string EthernetInterface::generateId(const std::string& ipaddress,
428 uint8_t prefixLength,
Lei YU34027572021-08-11 15:23:52 +0800429 const std::string& gateway,
430 const std::string& origin)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530431{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530432 std::stringstream hexId;
433 std::string hashString = ipaddress;
434 hashString += std::to_string(prefixLength);
435 hashString += gateway;
Lei YU34027572021-08-11 15:23:52 +0800436 hashString += origin;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530437
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530438 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500439 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530440 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530441}
442
Patrick Williams6aef7692021-05-01 06:39:41 -0500443std::string EthernetInterface::generateNeighborId(const std::string& ipAddress,
444 const std::string& macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800445{
446 std::stringstream hexId;
Patrick Williams6aef7692021-05-01 06:39:41 -0500447 std::string hashString = ipAddress + macAddress;
William A. Kennington III08505792019-01-30 16:00:04 -0800448
449 // Only want 8 hex digits.
450 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
451 return hexId.str();
452}
453
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530454void EthernetInterface::deleteObject(const std::string& ipaddress)
455{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530456 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530457 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530458 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530459 log<level::ERR>("DeleteObject:Unable to find the object.");
460 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530461 }
462 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530463 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530464}
465
Patrick Williams6aef7692021-05-01 06:39:41 -0500466void EthernetInterface::deleteStaticNeighborObject(const std::string& ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800467{
Patrick Williams6aef7692021-05-01 06:39:41 -0500468 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800469 if (it == staticNeighbors.end())
470 {
471 log<level::ERR>(
472 "DeleteStaticNeighborObject:Unable to find the object.");
473 return;
474 }
475 staticNeighbors.erase(it);
476 manager.writeToConfigurationFile();
477}
478
Ratan Guptae9c9b812017-09-22 17:15:37 +0530479void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530480{
Ratan Guptabc886292017-07-25 18:29:57 +0530481 auto confDir = manager.getConfDir();
482 fs::path networkFile = confDir;
483 networkFile /= systemd::config::networkFilePrefix + interface +
484 systemd::config::networkFileSuffix;
485
486 fs::path deviceFile = confDir;
487 deviceFile /= interface + systemd::config::deviceFileSuffix;
488
489 // delete the vlan network file
490 if (fs::is_regular_file(networkFile))
491 {
492 fs::remove(networkFile);
493 }
494
495 // delete the vlan device file
496 if (fs::is_regular_file(deviceFile))
497 {
498 fs::remove(deviceFile);
499 }
Ratan Guptabc886292017-07-25 18:29:57 +0530500
501 // TODO systemd doesn't delete the virtual network interface
502 // even after deleting all the related configuartion.
503 // https://github.com/systemd/systemd/issues/6600
504 try
505 {
506 deleteInterface(interface);
507 }
508 catch (InternalFailure& e)
509 {
510 commit<InternalFailure>();
511 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530512}
513
514void EthernetInterface::deleteVLANObject(const std::string& interface)
515{
516 auto it = vlanInterfaces.find(interface);
517 if (it == vlanInterfaces.end())
518 {
519 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500520 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530521 return;
522 }
523
524 deleteVLANFromSystem(interface);
525 // delete the interface
526 vlanInterfaces.erase(it);
527
Ratan Guptae05083a2017-09-16 07:12:11 +0530528 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530529}
530
Gunnar Mills57d9c502018-09-14 14:42:34 -0500531std::string EthernetInterface::generateObjectPath(
532 IP::Protocol addressType, const std::string& ipaddress,
Lei YU34027572021-08-11 15:23:52 +0800533 uint8_t prefixLength, const std::string& gateway,
534 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530535{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530536 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530537 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530538 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
539
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530540 std::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530541 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530542 objectPath /= type;
Lei YU34027572021-08-11 15:23:52 +0800543 objectPath /=
544 generateId(ipaddress, prefixLength, gateway, convertForMessage(origin));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530545 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530546}
547
William A. Kennington III08505792019-01-30 16:00:04 -0800548std::string EthernetInterface::generateStaticNeighborObjectPath(
Patrick Williams6aef7692021-05-01 06:39:41 -0500549 const std::string& ipAddress, const std::string& macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800550{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530551 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800552 objectPath /= objPath;
553 objectPath /= "static_neighbor";
Patrick Williams6aef7692021-05-01 06:39:41 -0500554 objectPath /= generateNeighborId(ipAddress, macAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800555 return objectPath.string();
556}
557
Patrick Williams6aef7692021-05-01 06:39:41 -0500558bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700559{
Patrick Williams6aef7692021-05-01 06:39:41 -0500560 if (value == EthernetInterfaceIntf::ipv6AcceptRA())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700561 {
562 return value;
563 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500564 EthernetInterfaceIntf::ipv6AcceptRA(value);
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700565 manager.writeToConfigurationFile();
566 return value;
567}
568
Patrick Williams6aef7692021-05-01 06:39:41 -0500569EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530570{
Patrick Williams6aef7692021-05-01 06:39:41 -0500571 if (value == EthernetInterfaceIntf::dhcpEnabled())
Ratan Gupta5978dd12017-07-25 13:47:13 +0530572 {
573 return value;
574 }
575
Patrick Williams6aef7692021-05-01 06:39:41 -0500576 EthernetInterfaceIntf::dhcpEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530577 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530578 return value;
579}
580
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800581bool EthernetInterface::linkUp() const
582{
583 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
584 bool value = EthernetInterfaceIntf::linkUp();
585
586 if (eifSocket.sock < 0)
587 {
588 return value;
589 }
590
William A. Kennington III05368f12021-05-13 18:40:47 -0700591 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800592 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
593 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
594 {
595 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
596 }
597 else
598 {
599 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
600 entry("ERROR=%s", strerror(errno)));
601 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700602 return value;
603}
604
William A. Kennington III26275a32021-07-13 20:32:42 -0700605bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700606{
William A. Kennington III26275a32021-07-13 20:32:42 -0700607 constexpr auto svc = "org.freedesktop.network1";
608 constexpr auto intf = "org.freedesktop.network1.Link";
609 constexpr auto prop = "AdministrativeState";
610 char* rpath;
611 sd_bus_path_encode("/org/freedesktop/network1/link",
612 std::to_string(ifIndex()).c_str(), &rpath);
613 std::string path(rpath);
614 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700615
William A. Kennington III26275a32021-07-13 20:32:42 -0700616 // Store / Parser for the AdministrativeState return value
617 std::optional<bool> ret;
618 auto cb = [&](const std::string& state) {
619 if (state != "initialized")
620 {
621 ret = state != "unmanaged";
622 }
623 };
624
625 // Build a matcher before making the property call to ensure we
626 // can eventually get the value.
627 sdbusplus::bus::match::match match(
628 bus,
629 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
630 "'PropertiesChanged',arg0='{}',",
631 svc, path, PROPERTY_INTERFACE, intf)
632 .c_str(),
633 [&](sdbusplus::message::message& m) {
634 std::string intf;
635 std::unordered_map<std::string, std::variant<std::string>> values;
636 try
637 {
638 m.read(intf, values);
639 auto it = values.find(prop);
640 // Ignore properties that aren't AdministrativeState
641 if (it != values.end())
642 {
643 cb(std::get<std::string>(it->second));
644 }
645 }
646 catch (const std::exception& e)
647 {
648 log<level::ERR>(
649 fmt::format(
650 "AdministrativeState match parsing failed on {}: {}",
651 interfaceName(), e.what())
652 .c_str(),
653 entry("INTERFACE=%s", interfaceName().c_str()),
654 entry("ERROR=%s", e.what()));
655 }
656 });
657
658 // Actively call for the value in case the interface is already configured
659 auto method =
660 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
661 method.append(intf, prop);
662 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700663 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700664 auto reply = bus.call(method);
665 std::variant<std::string> state;
666 reply.read(state);
667 cb(std::get<std::string>(state));
668 }
669 catch (const std::exception& e)
670 {
671 log<level::ERR>(
672 fmt::format("Failed to get AdministrativeState on {}: {}",
673 interfaceName(), e.what())
674 .c_str(),
675 entry("INTERFACE=%s", interfaceName().c_str()),
676 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700677 }
678
William A. Kennington III26275a32021-07-13 20:32:42 -0700679 // The interface is not yet configured by systemd-networkd, wait until it
680 // signals us a valid state.
681 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700682 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700683 bus.wait();
684 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700685 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700686
687 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700688}
689
Patrick Williams6aef7692021-05-01 06:39:41 -0500690bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700691{
Patrick Williams6aef7692021-05-01 06:39:41 -0500692 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700693 {
694 return value;
695 }
696
697 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
698 if (eifSocket.sock < 0)
699 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500700 return EthernetInterfaceIntf::nicEnabled();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700701 }
702
William A. Kennington III05368f12021-05-13 18:40:47 -0700703 ifreq ifr = {};
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700704 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
705 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) != 0)
706 {
707 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
708 entry("ERROR=%s", strerror(errno)));
Patrick Williams6aef7692021-05-01 06:39:41 -0500709 return EthernetInterfaceIntf::nicEnabled();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700710 }
711
712 ifr.ifr_flags &= ~IFF_UP;
713 ifr.ifr_flags |= value ? IFF_UP : 0;
714
715 if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
716 {
717 log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
718 entry("ERROR=%s", strerror(errno)));
Patrick Williams6aef7692021-05-01 06:39:41 -0500719 return EthernetInterfaceIntf::nicEnabled();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700720 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500721 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700722 writeConfigurationFile();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800723
724 return value;
725}
726
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530727ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530728{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530729 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
730 return EthernetInterfaceIntf::nameservers();
731}
732
733ServerList EthernetInterface::staticNameServers(ServerList value)
734{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530735 for (const auto& nameserverip : value)
736 {
737 if (!isValidIP(AF_INET, nameserverip) &&
738 !isValidIP(AF_INET6, nameserverip))
739 {
740 log<level::ERR>("Not a valid IP address"),
741 entry("ADDRESS=%s", nameserverip.c_str());
742 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530743 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530744 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
745 }
746 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530747 try
748 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530749 EthernetInterfaceIntf::staticNameServers(value);
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530750 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530751 // resolved reads the DNS server configuration from the
752 // network file.
753 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530754 }
755 catch (InternalFailure& e)
756 {
757 log<level::ERR>("Exception processing DNS entries");
758 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530759 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530760}
761
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530762void EthernetInterface::loadNameServers()
763{
764 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
765 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
766}
767
768ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530769{
770 fs::path confPath = manager.getConfDir();
771
772 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500773 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530774 confPath /= fileName;
775 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530776 config::Parser parser(confPath.string());
777 auto rc = config::ReturnCode::SUCCESS;
778
779 std::tie(rc, servers) = parser.getValues("Network", "DNS");
780 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530781 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530782 log<level::DEBUG>("Unable to get the value for network[DNS]",
783 entry("RC=%d", rc));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530784 }
785 return servers;
786}
787
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530788ServerList EthernetInterface::getNameServerFromResolvd()
789{
790 ServerList servers;
791 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
792
793 /*
794 The DNS property under org.freedesktop.resolve1.Link interface contains
795 an array containing all DNS servers currently used by resolved. It
796 contains similar information as the DNS server data written to
797 /run/systemd/resolve/resolv.conf.
798
799 Each structure in the array consists of a numeric network interface index,
800 an address family, and a byte array containing the DNS server address
801 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
802 The array contains DNS servers configured system-wide, including those
803 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
804 /etc/systemd/resolved.conf, as well as per-interface DNS server
805 information either retrieved from systemd-networkd or configured by
806 external software via SetLinkDNS().
807 */
808
809 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
810 std::variant<type> name; // Variable to capture the DNS property
811 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
812 PROPERTY_INTERFACE, METHOD_GET);
813
814 method.append(RESOLVED_INTERFACE, "DNS");
815 auto reply = bus.call(method);
816
817 try
818 {
819 reply.read(name);
820 }
821 catch (const sdbusplus::exception::SdBusError& e)
822 {
823 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
824 }
825 auto tupleVector = std::get_if<type>(&name);
826 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
827 {
Alexander Filippov983da552021-02-08 15:26:54 +0300828 int addressFamily = std::get<0>(*i);
829 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
830
831 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530832 {
Alexander Filippov983da552021-02-08 15:26:54 +0300833 case AF_INET:
834 if (ipaddress.size() == sizeof(struct in_addr))
835 {
836 servers.push_back(toString(
837 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
838 }
839 else
840 {
841 log<level::ERR>(
842 "Invalid data recived from Systemd-Resolved");
843 }
844 break;
845
846 case AF_INET6:
847 if (ipaddress.size() == sizeof(struct in6_addr))
848 {
849 servers.push_back(toString(
850 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
851 }
852 else
853 {
854 log<level::ERR>(
855 "Invalid data recived from Systemd-Resolved");
856 }
857 break;
858
859 default:
860 log<level::ERR>(
861 "Unsupported address family in DNS from Systemd-Resolved");
862 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530863 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530864 }
865 return servers;
866}
867
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530868void EthernetInterface::loadVLAN(VlanId id)
869{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500870 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530871 std::string path = objPath;
872 path += "_" + std::to_string(id);
873
Johnathan Mantey817012a2020-01-30 15:07:39 -0800874 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500875 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530876 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500877 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nicEnabled(), id,
Johnathan Mantey817012a2020-01-30 15:07:39 -0800878 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530879
Gunnar Mills57d9c502018-09-14 14:42:34 -0500880 // Fetch the ip address from the system
881 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530882 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800883 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530884
885 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
886 std::move(vlanIntf));
887}
888
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700889ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530890{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500891 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530892 std::string path = objPath;
893 path += "_" + std::to_string(id);
894
Patrick Williams6aef7692021-05-01 06:39:41 -0500895 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530896 // VLAN interface can inherit.
897
Ratan Gupta5978dd12017-07-25 13:47:13 +0530898 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800899 bus, path.c_str(), EthernetInterface::DHCPConf::none,
Patrick Williams6aef7692021-05-01 06:39:41 -0500900 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530901
902 // write the device file for the vlan interface.
903 vlanIntf->writeDeviceFile();
904
Gunnar Mills57d9c502018-09-14 14:42:34 -0500905 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530906 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530907 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700908
909 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530910}
Ratan Gupta2b106532017-07-25 16:05:02 +0530911
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700912bool EthernetInterface::getIPv6AcceptRAFromConf()
913{
914 fs::path confPath = manager.getConfDir();
915
916 std::string fileName = systemd::config::networkFilePrefix +
917 interfaceName() + systemd::config::networkFileSuffix;
918 confPath /= fileName;
919 config::ValueList values;
920 config::Parser parser(confPath.string());
921 auto rc = config::ReturnCode::SUCCESS;
922 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
923 if (rc != config::ReturnCode::SUCCESS)
924 {
925 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
926 entry("rc=%d", rc));
927 return false;
928 }
929 return (values[0] == "true");
930}
931
Ratan Gupta497c0c92017-08-22 19:15:59 +0530932ServerList EthernetInterface::getNTPServersFromConf()
933{
934 fs::path confPath = manager.getConfDir();
935
Gunnar Mills57d9c502018-09-14 14:42:34 -0500936 std::string fileName = systemd::config::networkFilePrefix +
937 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530938 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530939
Ratan Gupta497c0c92017-08-22 19:15:59 +0530940 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530941 config::Parser parser(confPath.string());
942 auto rc = config::ReturnCode::SUCCESS;
943
944 std::tie(rc, servers) = parser.getValues("Network", "NTP");
945 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530946 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530947 log<level::DEBUG>("Unable to get the value for Network[NTP]",
948 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530949 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530950
Ratan Gupta497c0c92017-08-22 19:15:59 +0530951 return servers;
952}
953
Patrick Williams6aef7692021-05-01 06:39:41 -0500954ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530955{
Patrick Williams6aef7692021-05-01 06:39:41 -0500956 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530957
958 writeConfigurationFile();
959 // timesynchd reads the NTP server configuration from the
960 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530961 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530962 return ntpServers;
963}
Ratan Gupta2b106532017-07-25 16:05:02 +0530964// Need to merge the below function with the code which writes the
965// config file during factory reset.
966// TODO openbmc/openbmc#1751
967
968void EthernetInterface::writeConfigurationFile()
969{
970 // write all the static ip address in the systemd-network conf file
971
972 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530973 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530974
975 // if there is vlan interafce then write the configuration file
976 // for vlan also.
977
Gunnar Mills57d9c502018-09-14 14:42:34 -0500978 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530979 {
980 intf.second->writeConfigurationFile();
981 }
982
Ratan Gupta2b106532017-07-25 16:05:02 +0530983 fs::path confPath = manager.getConfDir();
984
Gunnar Mills57d9c502018-09-14 14:42:34 -0500985 std::string fileName = systemd::config::networkFilePrefix +
986 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530987 confPath /= fileName;
988 std::fstream stream;
989
990 stream.open(confPath.c_str(), std::fstream::out);
991 if (!stream.is_open())
992 {
993 log<level::ERR>("Unable to open the file",
994 entry("FILE=%s", confPath.c_str()));
995 elog<InternalFailure>();
996 }
997
998 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400999 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301000 stream << "Name=" << interfaceName() << "\n";
1001
1002 auto addrs = getAddresses();
1003
William A. Kennington III15787212019-04-23 19:18:01 -07001004 // Write the link section
1005 stream << "[Link]\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001006 auto mac = MacAddressIntf::macAddress();
William A. Kennington III15787212019-04-23 19:18:01 -07001007 if (!mac.empty())
1008 {
1009 stream << "MACAddress=" << mac << "\n";
1010 }
1011
Patrick Williams6aef7692021-05-01 06:39:41 -05001012 if (!EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -07001013 {
1014 stream << "Unmanaged=yes\n";
1015 }
1016
Ratan Gupta2b106532017-07-25 16:05:02 +05301017 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001018 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001019#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -05001020 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001021#else
1022 stream << "LinkLocalAddressing=no\n";
1023#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -07001024 stream << std::boolalpha
Patrick Williams6aef7692021-05-01 06:39:41 -05001025 << "IPv6AcceptRA=" << EthernetInterfaceIntf::ipv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301026
1027 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -05001028 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301029 {
1030 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -05001031 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301032 }
Ratan Gupta046b2a02019-09-20 15:49:51 +05301033 // Add the NTP server
Patrick Williams6aef7692021-05-01 06:39:41 -05001034 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301035 {
1036 stream << "NTP=" << ntp << "\n";
1037 }
1038
1039 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +05301040 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301041 {
1042 stream << "DNS=" << dns << "\n";
1043 }
1044
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001045 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -08001046 stream << "DHCP="s +
Patrick Williams6aef7692021-05-01 06:39:41 -05001047 mapDHCPToSystemd[EthernetInterfaceIntf::dhcpEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001048
Johnathan Mantey817012a2020-01-30 15:07:39 -08001049 // Static IP addresses
1050 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +05301051 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001052 if (originIsManuallyAssigned(addr.second->origin()) &&
1053 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001054 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001055 // Process all static addresses
1056 std::string address = addr.second->address() + "/" +
1057 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +05301058
Johnathan Mantey817012a2020-01-30 15:07:39 -08001059 // build the address entries. Do not use [Network] shortcuts to
1060 // insert address entries.
1061 stream << "[Address]\n";
1062 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001063 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001064 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001065
Lei YUcb2d4082021-08-12 15:26:49 +08001066 if (!dhcpIsEnabled(IP::Protocol::IPv4))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001067 {
Lei YUcb2d4082021-08-12 15:26:49 +08001068 auto gateway = EthernetInterfaceIntf::defaultGateway();
1069 if (!gateway.empty())
1070 {
1071 stream << "[Route]\n";
1072 stream << "Gateway=" << gateway << "\n";
1073 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001074 }
1075
Lei YUcb2d4082021-08-12 15:26:49 +08001076 if (!dhcpIsEnabled(IP::Protocol::IPv6))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001077 {
Lei YUcb2d4082021-08-12 15:26:49 +08001078 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1079 if (!gateway6.empty())
1080 {
1081 stream << "[Route]\n";
1082 stream << "Gateway=" << gateway6 << "\n";
1083 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001084 }
1085
William A. Kennington III08505792019-01-30 16:00:04 -08001086 // Write the neighbor sections
1087 for (const auto& neighbor : staticNeighbors)
1088 {
1089 stream << "[Neighbor]"
1090 << "\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001091 stream << "Address=" << neighbor.second->ipAddress() << "\n";
1092 stream << "MACAddress=" << neighbor.second->macAddress() << "\n";
William A. Kennington III08505792019-01-30 16:00:04 -08001093 }
1094
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001095 // Write the dhcp section irrespective of whether DHCP is enabled or not
1096 writeDHCPSection(stream);
1097
Ratan Gupta2b106532017-07-25 16:05:02 +05301098 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +05301099}
1100
1101void EthernetInterface::writeDHCPSection(std::fstream& stream)
1102{
1103 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301104 // write the dhcp section
1105 stream << "[DHCP]\n";
1106
1107 // Hardcoding the client identifier to mac, to address below issue
1108 // https://github.com/openbmc/openbmc/issues/1280
1109 stream << "ClientIdentifier=mac\n";
1110 if (manager.getDHCPConf())
1111 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001112 auto value = manager.getDHCPConf()->dnsEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301113 stream << "UseDNS="s + value + "\n";
1114
Patrick Williams6aef7692021-05-01 06:39:41 -05001115 value = manager.getDHCPConf()->ntpEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301116 stream << "UseNTP="s + value + "\n";
1117
1118 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1119 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001120
1121 value =
1122 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1123 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301124 }
1125}
1126
Patrick Williams6aef7692021-05-01 06:39:41 -05001127std::string EthernetInterface::macAddress(std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301128{
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001129 ether_addr newMAC;
1130 try
1131 {
1132 newMAC = mac_address::fromString(value);
1133 }
1134 catch (std::invalid_argument&)
1135 {
1136 log<level::ERR>("MACAddress is not valid.",
1137 entry("MAC=%s", value.c_str()));
1138 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1139 Argument::ARGUMENT_VALUE(value.c_str()));
1140 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001141 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301142 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001143 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001144 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001145 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1146 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301147 }
1148
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001149 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001150 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001151
William A. Kennington III1137a972019-04-20 20:49:58 -07001152 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001153 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001154 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301155 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001156 // Update everything that depends on the MAC value
1157 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301158 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001159 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301160 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001161 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301162
William A. Kennington III15787212019-04-23 19:18:01 -07001163 // TODO: would remove the call below and
1164 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -07001165 // through https://github.com/systemd/systemd/issues/6696
1166 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
1167 "down");
William A. Kennington III15787212019-04-23 19:18:01 -07001168 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +05301169 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001170
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001171#ifdef HAVE_UBOOT_ENV
1172 // Ensure that the valid address is stored in the u-boot-env
1173 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1174 if (envVar)
1175 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001176 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1177 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1178 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1179 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001180 }
1181#endif // HAVE_UBOOT_ENV
1182
William A. Kennington III1137a972019-04-20 20:49:58 -07001183 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301184}
1185
Ratan Guptae9c9b812017-09-22 17:15:37 +05301186void EthernetInterface::deleteAll()
1187{
Johnathan Mantey817012a2020-01-30 15:07:39 -08001188 if (dhcpIsEnabled(IP::Protocol::IPv4, true))
Ratan Guptae9c9b812017-09-22 17:15:37 +05301189 {
1190 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001191 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301192 }
1193
1194 // clear all the ip on the interface
1195 addrs.clear();
1196 manager.writeToConfigurationFile();
1197}
1198
Ravi Tejaa5a09442020-07-17 00:57:33 -05001199std::string EthernetInterface::defaultGateway(std::string gateway)
1200{
1201 auto gw = EthernetInterfaceIntf::defaultGateway();
1202 if (gw == gateway)
1203 {
1204 return gw;
1205 }
1206
1207 if (!isValidIP(AF_INET, gateway))
1208 {
1209 log<level::ERR>("Not a valid v4 Gateway",
1210 entry("GATEWAY=%s", gateway.c_str()));
1211 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1212 Argument::ARGUMENT_VALUE(gateway.c_str()));
1213 }
1214 gw = EthernetInterfaceIntf::defaultGateway(gateway);
1215 manager.writeToConfigurationFile();
1216 return gw;
1217}
1218
1219std::string EthernetInterface::defaultGateway6(std::string gateway)
1220{
1221 auto gw = EthernetInterfaceIntf::defaultGateway6();
1222 if (gw == gateway)
1223 {
1224 return gw;
1225 }
1226
1227 if (!isValidIP(AF_INET6, gateway))
1228 {
1229 log<level::ERR>("Not a valid v6 Gateway",
1230 entry("GATEWAY=%s", gateway.c_str()));
1231 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1232 Argument::ARGUMENT_VALUE(gateway.c_str()));
1233 }
1234 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
1235 manager.writeToConfigurationFile();
1236 return gw;
1237}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001238} // namespace network
1239} // namespace phosphor