blob: 77e5df148ec49a8dae0ecab08cd90f46adc3c2b9 [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"
Ratan Gupta2b106532017-07-25 16:05:02 +05308#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05309
Ratan Gupta82549cc2017-04-21 08:45:23 +053010#include <arpa/inet.h>
William A. Kennington III26275a32021-07-13 20:32:42 -070011#include <fmt/format.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053012#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070013#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053015#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053016
Ratan Gupta82549cc2017-04-21 08:45:23 +053017#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053018#include <filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053019#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070020#include <phosphor-logging/elog-errors.hpp>
21#include <phosphor-logging/log.hpp>
William A. Kennington III26275a32021-07-13 20:32:42 -070022#include <sdbusplus/bus/match.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053023#include <sstream>
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080024#include <stdplus/fd/create.hpp>
William A. Kennington III12beaad2020-06-13 19:30:41 -070025#include <stdplus/raw.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053026#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070027#include <string_view>
William A. Kennington III26275a32021-07-13 20:32:42 -070028#include <unordered_map>
29#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070030#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053031
Ratan Gupta91a99cc2017-04-14 16:32:09 +053032namespace phosphor
33{
34namespace network
35{
36
37using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053038using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053039using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
40using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050041using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053042constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
43constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
44constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
45constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
46constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053047
Johnathan Mantey817012a2020-01-30 15:07:39 -080048std::map<EthernetInterface::DHCPConf, std::string> mapDHCPToSystemd = {
49 {EthernetInterface::DHCPConf::both, "true"},
50 {EthernetInterface::DHCPConf::v4, "ipv4"},
51 {EthernetInterface::DHCPConf::v6, "ipv6"},
52 {EthernetInterface::DHCPConf::none, "false"}};
53
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080054static stdplus::Fd& getIFSock()
55{
56 using namespace stdplus::fd;
57 static auto fd =
58 socket(SocketDomain::INet, SocketType::Datagram, SocketProto::IP);
59 return fd;
60}
61
Patrick Williamsc38b0712022-07-22 19:26:54 -050062EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus,
Ratan Gupta91a99cc2017-04-14 16:32:09 +053063 const std::string& objPath,
Johnathan Mantey817012a2020-01-30 15:07:39 -080064 DHCPConf dhcpEnabled, Manager& parent,
William A. Kennington III26275a32021-07-13 20:32:42 -070065 bool emitSignal,
66 std::optional<bool> enabled) :
Patrick Williams166b9592022-03-30 16:09:16 -050067 Ifaces(bus, objPath.c_str(),
68 emitSignal ? Ifaces::action::defer_emit
69 : Ifaces::action::emit_no_signals),
Gunnar Mills57d9c502018-09-14 14:42:34 -050070 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053071{
72 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053073 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053074 interfaceName(intfName);
Patrick Williams6aef7692021-05-01 06:39:41 -050075 EthernetInterfaceIntf::dhcpEnabled(dhcpEnabled);
76 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRAFromConf());
William A. Kennington III26275a32021-07-13 20:32:42 -070077 EthernetInterfaceIntf::nicEnabled(enabled ? *enabled : queryNicEnabled());
William A. Kennington IIIe0564842021-10-23 16:02:22 -070078 const auto& gatewayList = manager.getRouteTable().getDefaultGateway();
79 const auto& gateway6List = manager.getRouteTable().getDefaultGateway6();
Ravi Tejaa5a09442020-07-17 00:57:33 -050080 std::string defaultGateway;
81 std::string defaultGateway6;
82
William A. Kennington IIIe0564842021-10-23 16:02:22 -070083 for (const auto& gateway : gatewayList)
Ravi Tejaa5a09442020-07-17 00:57:33 -050084 {
85 if (gateway.first == intfName)
86 {
87 defaultGateway = gateway.second;
88 break;
89 }
90 }
91
William A. Kennington IIIe0564842021-10-23 16:02:22 -070092 for (const auto& gateway6 : gateway6List)
Ravi Tejaa5a09442020-07-17 00:57:33 -050093 {
94 if (gateway6.first == intfName)
95 {
96 defaultGateway6 = gateway6.second;
97 break;
98 }
99 }
100
101 EthernetInterfaceIntf::defaultGateway(defaultGateway);
102 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
Ratan Gupta99801ce2020-01-09 18:37:16 +0530103 // Don't get the mac address from the system as the mac address
104 // would be same as parent interface.
105 if (intfName.find(".") == std::string::npos)
106 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500107 MacAddressIntf::macAddress(getMACAddress(intfName));
Ratan Gupta99801ce2020-01-09 18:37:16 +0530108 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500109 EthernetInterfaceIntf::ntpServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +0530110
111 EthernetInterfaceIntf::linkUp(linkUp());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530112 EthernetInterfaceIntf::mtu(mtu());
Ratan Gupta613a0122020-04-24 15:18:53 +0530113
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700114#ifdef NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -0700115 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
116
117 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
118 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800119#endif
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530120
Ratan Gupta29b0e432017-05-25 12:51:40 +0530121 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530122 if (emitSignal)
123 {
124 this->emit_object_added();
125 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530126}
127
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800128static IP::Protocol convertFamily(int family)
129{
130 switch (family)
131 {
132 case AF_INET:
133 return IP::Protocol::IPv4;
134 case AF_INET6:
135 return IP::Protocol::IPv6;
136 }
137
138 throw std::invalid_argument("Bad address family");
139}
140
Johnathan Mantey817012a2020-01-30 15:07:39 -0800141void EthernetInterface::disableDHCP(IP::Protocol protocol)
142{
Patrick Williams6aef7692021-05-01 06:39:41 -0500143 DHCPConf dhcpState = EthernetInterfaceIntf::dhcpEnabled();
Johnathan Mantey817012a2020-01-30 15:07:39 -0800144 if (dhcpState == EthernetInterface::DHCPConf::both)
145 {
146 if (protocol == IP::Protocol::IPv4)
147 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500148 dhcpEnabled(EthernetInterface::DHCPConf::v6);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800149 }
150 else if (protocol == IP::Protocol::IPv6)
151 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500152 dhcpEnabled(EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800153 }
154 }
155 else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
156 (protocol == IP::Protocol::IPv4))
157 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500158 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800159 }
160 else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
161 (protocol == IP::Protocol::IPv6))
162 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500163 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800164 }
165}
166
William A. Kennington III24957b92021-12-03 13:59:19 -0800167bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800168{
William A. Kennington III24957b92021-12-03 13:59:19 -0800169 const auto cur = EthernetInterfaceIntf::dhcpEnabled();
170 return cur == EthernetInterface::DHCPConf::both ||
171 (family == IP::Protocol::IPv6 &&
172 cur == EthernetInterface::DHCPConf::v6) ||
173 (family == IP::Protocol::IPv4 &&
174 cur == EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800175}
176
Johnathan Mantey817012a2020-01-30 15:07:39 -0800177bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
178{
179 return (
180#ifdef LINK_LOCAL_AUTOCONFIGURATION
181 (origin == IP::AddressOrigin::Static)
182#else
183 (origin == IP::AddressOrigin::Static ||
184 origin == IP::AddressOrigin::LinkLocal)
185#endif
186
187 );
188}
189
Ratan Gupta87c13982017-06-15 09:27:27 +0530190void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530191{
Ratan Gupta87c13982017-06-15 09:27:27 +0530192 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530193
Ratan Gupta87c13982017-06-15 09:27:27 +0530194 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530195
Ratan Gupta6a387c12017-08-03 13:26:19 +0530196 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530197 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800198 IP::Protocol addressType = convertFamily(addr.addrType);
199 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800200 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530201 {
202 origin = IP::AddressOrigin::DHCP;
203 }
William A. Kennington III16893802019-01-30 16:01:01 -0800204 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530205 {
206 origin = IP::AddressOrigin::LinkLocal;
207 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700208 // Obsolete parameter
209 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530210
Gunnar Mills57d9c502018-09-14 14:42:34 -0500211 std::string ipAddressObjectPath = generateObjectPath(
Lei YU34027572021-08-11 15:23:52 +0800212 addressType, addr.ipaddress, addr.prefix, gateway, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530213
Lei YU7233c582021-04-08 14:39:43 +0800214 this->addrs.insert_or_assign(
215 addr.ipaddress,
216 std::make_shared<phosphor::network::IPAddress>(
217 bus, ipAddressObjectPath.c_str(), *this, addressType,
218 addr.ipaddress, origin, addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530219 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530220}
221
William A. Kennington III08505792019-01-30 16:00:04 -0800222void EthernetInterface::createStaticNeighborObjects()
223{
224 staticNeighbors.clear();
225
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700226 NeighborFilter filter;
227 filter.interface = ifIndex();
228 filter.state = NUD_PERMANENT;
229 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800230 for (const auto& neighbor : neighbors)
231 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700232 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800233 {
234 continue;
235 }
236 std::string ip = toString(neighbor.address);
237 std::string mac = mac_address::toString(*neighbor.mac);
238 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
239 staticNeighbors.emplace(ip,
240 std::make_shared<phosphor::network::Neighbor>(
241 bus, objectPath.c_str(), *this, ip, mac,
242 Neighbor::State::Permanent));
243 }
244}
245
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700246unsigned EthernetInterface::ifIndex() const
247{
248 unsigned idx = if_nametoindex(interfaceName().c_str());
249 if (idx == 0)
250 {
251 throw std::system_error(errno, std::generic_category(),
252 "if_nametoindex");
253 }
254 return idx;
255}
256
Patrick Williams6aef7692021-05-01 06:39:41 -0500257ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
raviteja-bce379562019-03-28 05:59:36 -0500258 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530259{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800260 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530261 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530262 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500263 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800264 disableDHCP(protType);
Ravi Teja07450442022-07-07 04:30:57 -0500265 // Delete the IP address object and that reloads the networkd
266 // to allow the same IP address to be set as Static IP
267 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500268 }
269
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500270 IP::AddressOrigin origin = IP::AddressOrigin::Static;
271
272 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
273
274 if (!isValidIP(addressFamily, ipaddress))
275 {
276 log<level::ERR>("Not a valid IP address"),
277 entry("ADDRESS=%s", ipaddress.c_str());
278 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
279 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
280 }
281
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700282 // Gateway is an obsolete parameter
283 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500284
285 if (!isValidPrefix(addressFamily, prefixLength))
286 {
287 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700288 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500289 elog<InvalidArgument>(
290 Argument::ARGUMENT_NAME("prefixLength"),
291 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530292 }
293
Gunnar Mills57d9c502018-09-14 14:42:34 -0500294 std::string objectPath =
Lei YU34027572021-08-11 15:23:52 +0800295 generateObjectPath(protType, ipaddress, prefixLength, gateway, origin);
Lei YU7233c582021-04-08 14:39:43 +0800296 this->addrs.insert_or_assign(ipaddress,
297 std::make_shared<phosphor::network::IPAddress>(
298 bus, objectPath.c_str(), *this, protType,
299 ipaddress, origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530300
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700301 writeConfigurationFile();
302 manager.reloadConfigs();
303
raviteja-bce379562019-03-28 05:59:36 -0500304 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530305}
306
Patrick Williams6aef7692021-05-01 06:39:41 -0500307ObjectPath EthernetInterface::neighbor(std::string ipAddress,
308 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800309{
Patrick Williams6aef7692021-05-01 06:39:41 -0500310 if (!isValidIP(AF_INET, ipAddress) && !isValidIP(AF_INET6, ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800311 {
312 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500313 entry("ADDRESS=%s", ipAddress.c_str()));
314 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
315 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800316 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500317 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800318 {
319 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500320 entry("MACADDRESS=%s", ipAddress.c_str()));
321 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
322 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800323 }
324
325 std::string objectPath =
Patrick Williams6aef7692021-05-01 06:39:41 -0500326 generateStaticNeighborObjectPath(ipAddress, macAddress);
327 staticNeighbors.emplace(ipAddress,
William A. Kennington III08505792019-01-30 16:00:04 -0800328 std::make_shared<phosphor::network::Neighbor>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500329 bus, objectPath.c_str(), *this, ipAddress,
330 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700331
332 writeConfigurationFile();
333 manager.reloadConfigs();
334
William A. Kennington III08505792019-01-30 16:00:04 -0800335 return objectPath;
336}
337
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700338#ifdef NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530339/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800340 Enable this code if your NIC driver supports the ETHTOOL features.
341 Do this by adding the following to your phosphor-network*.bbappend file.
342 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
343 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530344*/
345InterfaceInfo EthernetInterface::getInterfaceInfo() const
346{
William A. Kennington III05368f12021-05-13 18:40:47 -0700347 ifreq ifr = {};
348 ethtool_cmd edata = {};
349 LinkSpeed speed = {};
350 Autoneg autoneg = {};
351 DuplexMode duplex = {};
352 LinkUp linkState = {};
353 NICEnabled enabled = {};
Tejas Patil2c0fc562021-08-03 19:13:46 +0530354 MTU mtuSize = {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530355
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800356 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
357 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530358
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800359 edata.cmd = ETHTOOL_GSET;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800360 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800361 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800362 getIFSock().ioctl(SIOCETHTOOL, &ifr);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530363 speed = edata.speed;
364 duplex = edata.duplex;
365 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530366 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800367 catch (const std::exception& e)
368 {
369 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800370
William A. Kennington III96203312021-05-07 12:50:41 -0700371 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800372 linkState = linkUp();
Tejas Patil2c0fc562021-08-03 19:13:46 +0530373 mtuSize = mtu();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800374
Tejas Patil2c0fc562021-08-03 19:13:46 +0530375 return std::make_tuple(speed, duplex, autoneg, linkState, enabled, mtuSize);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530376}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800377#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530378
379/** @brief get the mac address of the interface.
380 * @return macaddress on success
381 */
382
Gunnar Mills57d9c502018-09-14 14:42:34 -0500383std::string
384 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530385{
Patrick Williams6aef7692021-05-01 06:39:41 -0500386 std::string activeMACAddr = MacAddressIntf::macAddress();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530387
William A. Kennington III05368f12021-05-13 18:40:47 -0700388 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800389 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800390 try
391 {
392 getIFSock().ioctl(SIOCGIFHWADDR, &ifr);
393 }
394 catch (const std::exception& e)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530395 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530396 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800397 entry("ERROR=%s", e.what()));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700398 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530399 }
400
William A. Kennington III1137a972019-04-20 20:49:58 -0700401 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
402 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
403 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700404 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530405}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530406
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530407std::string EthernetInterface::generateId(const std::string& ipaddress,
408 uint8_t prefixLength,
Lei YU34027572021-08-11 15:23:52 +0800409 const std::string& gateway,
410 const std::string& origin)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530411{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530412 std::stringstream hexId;
413 std::string hashString = ipaddress;
414 hashString += std::to_string(prefixLength);
415 hashString += gateway;
Lei YU34027572021-08-11 15:23:52 +0800416 hashString += origin;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530417
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530418 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500419 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530420 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530421}
422
Patrick Williams6aef7692021-05-01 06:39:41 -0500423std::string EthernetInterface::generateNeighborId(const std::string& ipAddress,
424 const std::string& macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800425{
426 std::stringstream hexId;
Patrick Williams6aef7692021-05-01 06:39:41 -0500427 std::string hashString = ipAddress + macAddress;
William A. Kennington III08505792019-01-30 16:00:04 -0800428
429 // Only want 8 hex digits.
430 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
431 return hexId.str();
432}
433
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530434void EthernetInterface::deleteObject(const std::string& ipaddress)
435{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530436 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530437 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530438 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530439 log<level::ERR>("DeleteObject:Unable to find the object.");
440 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530441 }
442 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700443
444 writeConfigurationFile();
445 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530446}
447
Patrick Williams6aef7692021-05-01 06:39:41 -0500448void EthernetInterface::deleteStaticNeighborObject(const std::string& ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800449{
Patrick Williams6aef7692021-05-01 06:39:41 -0500450 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800451 if (it == staticNeighbors.end())
452 {
453 log<level::ERR>(
454 "DeleteStaticNeighborObject:Unable to find the object.");
455 return;
456 }
457 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700458
459 writeConfigurationFile();
460 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800461}
462
Ratan Guptae9c9b812017-09-22 17:15:37 +0530463void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530464{
Ratan Guptabc886292017-07-25 18:29:57 +0530465 auto confDir = manager.getConfDir();
466 fs::path networkFile = confDir;
467 networkFile /= systemd::config::networkFilePrefix + interface +
468 systemd::config::networkFileSuffix;
469
470 fs::path deviceFile = confDir;
471 deviceFile /= interface + systemd::config::deviceFileSuffix;
472
473 // delete the vlan network file
474 if (fs::is_regular_file(networkFile))
475 {
476 fs::remove(networkFile);
477 }
478
479 // delete the vlan device file
480 if (fs::is_regular_file(deviceFile))
481 {
482 fs::remove(deviceFile);
483 }
Ratan Guptabc886292017-07-25 18:29:57 +0530484
485 // TODO systemd doesn't delete the virtual network interface
486 // even after deleting all the related configuartion.
487 // https://github.com/systemd/systemd/issues/6600
488 try
489 {
490 deleteInterface(interface);
491 }
Patrick Williams5758db32021-10-06 12:29:22 -0500492 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530493 {
494 commit<InternalFailure>();
495 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530496}
497
498void EthernetInterface::deleteVLANObject(const std::string& interface)
499{
500 auto it = vlanInterfaces.find(interface);
501 if (it == vlanInterfaces.end())
502 {
503 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500504 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530505 return;
506 }
507
508 deleteVLANFromSystem(interface);
509 // delete the interface
510 vlanInterfaces.erase(it);
511
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700512 writeConfigurationFile();
513 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530514}
515
Gunnar Mills57d9c502018-09-14 14:42:34 -0500516std::string EthernetInterface::generateObjectPath(
517 IP::Protocol addressType, const std::string& ipaddress,
Lei YU34027572021-08-11 15:23:52 +0800518 uint8_t prefixLength, const std::string& gateway,
519 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530520{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530521 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530522 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530523 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
524
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530525 std::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530526 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530527 objectPath /= type;
Lei YU34027572021-08-11 15:23:52 +0800528 objectPath /=
529 generateId(ipaddress, prefixLength, gateway, convertForMessage(origin));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530530 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530531}
532
William A. Kennington III08505792019-01-30 16:00:04 -0800533std::string EthernetInterface::generateStaticNeighborObjectPath(
Patrick Williams6aef7692021-05-01 06:39:41 -0500534 const std::string& ipAddress, const std::string& macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800535{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530536 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800537 objectPath /= objPath;
538 objectPath /= "static_neighbor";
Patrick Williams6aef7692021-05-01 06:39:41 -0500539 objectPath /= generateNeighborId(ipAddress, macAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800540 return objectPath.string();
541}
542
Patrick Williams6aef7692021-05-01 06:39:41 -0500543bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700544{
Patrick Williams6aef7692021-05-01 06:39:41 -0500545 if (value == EthernetInterfaceIntf::ipv6AcceptRA())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700546 {
547 return value;
548 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500549 EthernetInterfaceIntf::ipv6AcceptRA(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700550
551 writeConfigurationFile();
552 manager.reloadConfigs();
553
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700554 return value;
555}
556
Patrick Williams6aef7692021-05-01 06:39:41 -0500557EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530558{
Patrick Williams6aef7692021-05-01 06:39:41 -0500559 if (value == EthernetInterfaceIntf::dhcpEnabled())
Ratan Gupta5978dd12017-07-25 13:47:13 +0530560 {
561 return value;
562 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500563 EthernetInterfaceIntf::dhcpEnabled(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700564
565 writeConfigurationFile();
566 manager.reloadConfigs();
567
Ratan Gupta87c13982017-06-15 09:27:27 +0530568 return value;
569}
570
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800571bool EthernetInterface::linkUp() const
572{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800573 bool value = EthernetInterfaceIntf::linkUp();
574
William A. Kennington III05368f12021-05-13 18:40:47 -0700575 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800576 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800577 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800578 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800579 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800580 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
581 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800582 catch (const std::exception& e)
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800583 {
584 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800585 entry("ERROR=%s", e.what()));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800586 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700587 return value;
588}
589
Tejas Patil2c0fc562021-08-03 19:13:46 +0530590size_t EthernetInterface::mtu() const
591{
Tejas Patil2c0fc562021-08-03 19:13:46 +0530592 size_t value = EthernetInterfaceIntf::mtu();
593
Tejas Patil2c0fc562021-08-03 19:13:46 +0530594 ifreq ifr = {};
595 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800596 try
Tejas Patil2c0fc562021-08-03 19:13:46 +0530597 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800598 getIFSock().ioctl(SIOCGIFMTU, &ifr);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530599 value = ifr.ifr_mtu;
600 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800601 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530602 {
603 log<level::ERR>("ioctl failed for SIOCGIFMTU:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800604 entry("ERROR=%s", e.what()));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530605 }
606 return value;
607}
608
609size_t EthernetInterface::mtu(size_t value)
610{
611 if (value == EthernetInterfaceIntf::mtu())
612 {
613 return value;
614 }
615 else if (value == 0)
616 {
617 return EthernetInterfaceIntf::mtu();
618 }
619
Tejas Patil2c0fc562021-08-03 19:13:46 +0530620 ifreq ifr = {};
621 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
622 ifr.ifr_mtu = value;
623
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800624 try
625 {
626 getIFSock().ioctl(SIOCSIFMTU, &ifr);
627 }
628 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530629 {
630 log<level::ERR>("ioctl failed for SIOCSIFMTU:",
631 entry("ERROR=%s", strerror(errno)));
632 return EthernetInterfaceIntf::mtu();
633 }
Tejas Patil2c0fc562021-08-03 19:13:46 +0530634
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800635 EthernetInterfaceIntf::mtu(value);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530636 return value;
637}
638
William A. Kennington III26275a32021-07-13 20:32:42 -0700639bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700640{
William A. Kennington III26275a32021-07-13 20:32:42 -0700641 constexpr auto svc = "org.freedesktop.network1";
642 constexpr auto intf = "org.freedesktop.network1.Link";
643 constexpr auto prop = "AdministrativeState";
644 char* rpath;
645 sd_bus_path_encode("/org/freedesktop/network1/link",
646 std::to_string(ifIndex()).c_str(), &rpath);
647 std::string path(rpath);
648 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700649
William A. Kennington III26275a32021-07-13 20:32:42 -0700650 // Store / Parser for the AdministrativeState return value
651 std::optional<bool> ret;
652 auto cb = [&](const std::string& state) {
653 if (state != "initialized")
654 {
655 ret = state != "unmanaged";
656 }
657 };
658
659 // Build a matcher before making the property call to ensure we
660 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500661 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700662 bus,
663 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
664 "'PropertiesChanged',arg0='{}',",
665 svc, path, PROPERTY_INTERFACE, intf)
666 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500667 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700668 std::string intf;
669 std::unordered_map<std::string, std::variant<std::string>> values;
670 try
671 {
672 m.read(intf, values);
673 auto it = values.find(prop);
674 // Ignore properties that aren't AdministrativeState
675 if (it != values.end())
676 {
677 cb(std::get<std::string>(it->second));
678 }
679 }
680 catch (const std::exception& e)
681 {
682 log<level::ERR>(
683 fmt::format(
684 "AdministrativeState match parsing failed on {}: {}",
685 interfaceName(), e.what())
686 .c_str(),
687 entry("INTERFACE=%s", interfaceName().c_str()),
688 entry("ERROR=%s", e.what()));
689 }
690 });
691
692 // Actively call for the value in case the interface is already configured
693 auto method =
694 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
695 method.append(intf, prop);
696 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700697 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700698 auto reply = bus.call(method);
699 std::variant<std::string> state;
700 reply.read(state);
701 cb(std::get<std::string>(state));
702 }
703 catch (const std::exception& e)
704 {
705 log<level::ERR>(
706 fmt::format("Failed to get AdministrativeState on {}: {}",
707 interfaceName(), e.what())
708 .c_str(),
709 entry("INTERFACE=%s", interfaceName().c_str()),
710 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700711 }
712
William A. Kennington III26275a32021-07-13 20:32:42 -0700713 // The interface is not yet configured by systemd-networkd, wait until it
714 // signals us a valid state.
715 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700716 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700717 bus.wait();
718 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700719 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700720
721 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700722}
723
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800724static void setNICAdminState(const char* intf, bool up)
William A. Kennington III4209cee2021-10-23 18:14:21 -0700725{
726 ifreq ifr = {};
727 std::strncpy(ifr.ifr_name, intf, IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800728 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700729
730 ifr.ifr_flags &= ~IFF_UP;
731 ifr.ifr_flags |= up ? IFF_UP : 0;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800732 getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700733}
734
Patrick Williams6aef7692021-05-01 06:39:41 -0500735bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700736{
Patrick Williams6aef7692021-05-01 06:39:41 -0500737 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700738 {
739 return value;
740 }
741
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800742 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700743 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800744 if (!value)
745 {
746 // We only need to bring down the interface, networkd will always bring
747 // up managed interfaces
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800748 manager.addReloadPreHook([ifname = interfaceName()]() {
749 setNICAdminState(ifname.c_str(), false);
750 });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800751 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700752 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800753
754 return value;
755}
756
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530757ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530758{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530759 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
760 return EthernetInterfaceIntf::nameservers();
761}
762
763ServerList EthernetInterface::staticNameServers(ServerList value)
764{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530765 for (const auto& nameserverip : value)
766 {
767 if (!isValidIP(AF_INET, nameserverip) &&
768 !isValidIP(AF_INET6, nameserverip))
769 {
770 log<level::ERR>("Not a valid IP address"),
771 entry("ADDRESS=%s", nameserverip.c_str());
772 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530773 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530774 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
775 }
776 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530777 try
778 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530779 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700780
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530781 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700782 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530783 }
Patrick Williams5758db32021-10-06 12:29:22 -0500784 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530785 {
786 log<level::ERR>("Exception processing DNS entries");
787 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530788 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530789}
790
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530791void EthernetInterface::loadNameServers()
792{
793 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
794 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
795}
796
797ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530798{
799 fs::path confPath = manager.getConfDir();
800
801 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500802 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530803 confPath /= fileName;
804 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530805 config::Parser parser(confPath.string());
806 auto rc = config::ReturnCode::SUCCESS;
807
808 std::tie(rc, servers) = parser.getValues("Network", "DNS");
809 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530810 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530811 log<level::DEBUG>("Unable to get the value for network[DNS]",
812 entry("RC=%d", rc));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530813 }
814 return servers;
815}
816
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530817ServerList EthernetInterface::getNameServerFromResolvd()
818{
819 ServerList servers;
820 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
821
822 /*
823 The DNS property under org.freedesktop.resolve1.Link interface contains
824 an array containing all DNS servers currently used by resolved. It
825 contains similar information as the DNS server data written to
826 /run/systemd/resolve/resolv.conf.
827
828 Each structure in the array consists of a numeric network interface index,
829 an address family, and a byte array containing the DNS server address
830 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
831 The array contains DNS servers configured system-wide, including those
832 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
833 /etc/systemd/resolved.conf, as well as per-interface DNS server
834 information either retrieved from systemd-networkd or configured by
835 external software via SetLinkDNS().
836 */
837
838 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
839 std::variant<type> name; // Variable to capture the DNS property
840 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
841 PROPERTY_INTERFACE, METHOD_GET);
842
843 method.append(RESOLVED_INTERFACE, "DNS");
844 auto reply = bus.call(method);
845
846 try
847 {
848 reply.read(name);
849 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500850 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530851 {
852 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
853 }
854 auto tupleVector = std::get_if<type>(&name);
855 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
856 {
Alexander Filippov983da552021-02-08 15:26:54 +0300857 int addressFamily = std::get<0>(*i);
858 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
859
860 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530861 {
Alexander Filippov983da552021-02-08 15:26:54 +0300862 case AF_INET:
863 if (ipaddress.size() == sizeof(struct in_addr))
864 {
865 servers.push_back(toString(
866 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
867 }
868 else
869 {
870 log<level::ERR>(
871 "Invalid data recived from Systemd-Resolved");
872 }
873 break;
874
875 case AF_INET6:
876 if (ipaddress.size() == sizeof(struct in6_addr))
877 {
878 servers.push_back(toString(
879 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
880 }
881 else
882 {
883 log<level::ERR>(
884 "Invalid data recived from Systemd-Resolved");
885 }
886 break;
887
888 default:
889 log<level::ERR>(
890 "Unsupported address family in DNS from Systemd-Resolved");
891 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530892 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530893 }
894 return servers;
895}
896
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530897void EthernetInterface::loadVLAN(VlanId id)
898{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500899 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530900 std::string path = objPath;
901 path += "_" + std::to_string(id);
902
Johnathan Mantey817012a2020-01-30 15:07:39 -0800903 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500904 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530905 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500906 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nicEnabled(), id,
Johnathan Mantey817012a2020-01-30 15:07:39 -0800907 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530908
Gunnar Mills57d9c502018-09-14 14:42:34 -0500909 // Fetch the ip address from the system
910 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530911 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800912 vlanIntf->createStaticNeighborObjects();
Jiaqing Zhaocc5a6702021-12-31 14:58:55 +0800913 vlanIntf->loadNameServers();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530914
915 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
916 std::move(vlanIntf));
917}
918
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700919ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530920{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500921 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800922
923 if (this->vlanInterfaces.count(vlanInterfaceName))
924 {
925 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
926 elog<InvalidArgument>(
927 Argument::ARGUMENT_NAME("VLANId"),
928 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
929 }
930
Ratan Gupta5978dd12017-07-25 13:47:13 +0530931 std::string path = objPath;
932 path += "_" + std::to_string(id);
933
Patrick Williams6aef7692021-05-01 06:39:41 -0500934 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530935 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530936 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800937 bus, path.c_str(), EthernetInterface::DHCPConf::none,
Patrick Williams6aef7692021-05-01 06:39:41 -0500938 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530939
940 // write the device file for the vlan interface.
941 vlanIntf->writeDeviceFile();
942
Gunnar Mills57d9c502018-09-14 14:42:34 -0500943 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700944
945 writeConfigurationFile();
946 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700947
948 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530949}
Ratan Gupta2b106532017-07-25 16:05:02 +0530950
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700951bool EthernetInterface::getIPv6AcceptRAFromConf()
952{
953 fs::path confPath = manager.getConfDir();
954
955 std::string fileName = systemd::config::networkFilePrefix +
956 interfaceName() + systemd::config::networkFileSuffix;
957 confPath /= fileName;
958 config::ValueList values;
959 config::Parser parser(confPath.string());
960 auto rc = config::ReturnCode::SUCCESS;
961 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
962 if (rc != config::ReturnCode::SUCCESS)
963 {
964 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
965 entry("rc=%d", rc));
966 return false;
967 }
968 return (values[0] == "true");
969}
970
Ratan Gupta497c0c92017-08-22 19:15:59 +0530971ServerList EthernetInterface::getNTPServersFromConf()
972{
973 fs::path confPath = manager.getConfDir();
974
Gunnar Mills57d9c502018-09-14 14:42:34 -0500975 std::string fileName = systemd::config::networkFilePrefix +
976 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530977 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530978
Ratan Gupta497c0c92017-08-22 19:15:59 +0530979 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530980 config::Parser parser(confPath.string());
981 auto rc = config::ReturnCode::SUCCESS;
982
983 std::tie(rc, servers) = parser.getValues("Network", "NTP");
984 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530985 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530986 log<level::DEBUG>("Unable to get the value for Network[NTP]",
987 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530988 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530989
Ratan Gupta497c0c92017-08-22 19:15:59 +0530990 return servers;
991}
992
Patrick Williams6aef7692021-05-01 06:39:41 -0500993ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530994{
Patrick Williams6aef7692021-05-01 06:39:41 -0500995 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530996
997 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700998 manager.reloadConfigs();
999
Ratan Gupta497c0c92017-08-22 19:15:59 +05301000 return ntpServers;
1001}
Ratan Gupta2b106532017-07-25 16:05:02 +05301002// Need to merge the below function with the code which writes the
1003// config file during factory reset.
1004// TODO openbmc/openbmc#1751
1005
1006void EthernetInterface::writeConfigurationFile()
1007{
1008 // write all the static ip address in the systemd-network conf file
1009
1010 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +05301011 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +05301012
1013 // if there is vlan interafce then write the configuration file
1014 // for vlan also.
1015
Gunnar Mills57d9c502018-09-14 14:42:34 -05001016 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +05301017 {
1018 intf.second->writeConfigurationFile();
1019 }
1020
Ratan Gupta2b106532017-07-25 16:05:02 +05301021 fs::path confPath = manager.getConfDir();
1022
Gunnar Mills57d9c502018-09-14 14:42:34 -05001023 std::string fileName = systemd::config::networkFilePrefix +
1024 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +05301025 confPath /= fileName;
1026 std::fstream stream;
1027
1028 stream.open(confPath.c_str(), std::fstream::out);
1029 if (!stream.is_open())
1030 {
1031 log<level::ERR>("Unable to open the file",
1032 entry("FILE=%s", confPath.c_str()));
1033 elog<InternalFailure>();
1034 }
1035
1036 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001037 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301038 stream << "Name=" << interfaceName() << "\n";
1039
1040 auto addrs = getAddresses();
1041
William A. Kennington III15787212019-04-23 19:18:01 -07001042 // Write the link section
1043 stream << "[Link]\n";
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001044#ifdef PERSIST_MAC
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001045 auto mac = MacAddressIntf::macAddress();
William A. Kennington III15787212019-04-23 19:18:01 -07001046 if (!mac.empty())
1047 {
1048 stream << "MACAddress=" << mac << "\n";
1049 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001050#endif
William A. Kennington III15787212019-04-23 19:18:01 -07001051
Patrick Williams6aef7692021-05-01 06:39:41 -05001052 if (!EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -07001053 {
1054 stream << "Unmanaged=yes\n";
1055 }
1056
Ratan Gupta2b106532017-07-25 16:05:02 +05301057 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001058 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001059#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -05001060 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001061#else
1062 stream << "LinkLocalAddressing=no\n";
1063#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -07001064 stream << std::boolalpha
Patrick Williams6aef7692021-05-01 06:39:41 -05001065 << "IPv6AcceptRA=" << EthernetInterfaceIntf::ipv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301066
1067 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -05001068 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301069 {
1070 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -05001071 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301072 }
Ratan Gupta046b2a02019-09-20 15:49:51 +05301073 // Add the NTP server
Patrick Williams6aef7692021-05-01 06:39:41 -05001074 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301075 {
1076 stream << "NTP=" << ntp << "\n";
1077 }
1078
1079 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +05301080 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301081 {
1082 stream << "DNS=" << dns << "\n";
1083 }
1084
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001085 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -08001086 stream << "DHCP="s +
Patrick Williams6aef7692021-05-01 06:39:41 -05001087 mapDHCPToSystemd[EthernetInterfaceIntf::dhcpEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001088
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001089 stream << "[IPv6AcceptRA]\n";
1090 stream << "DHCPv6Client=";
1091 stream << (dhcpIsEnabled(IP::Protocol::IPv6) ? "true" : "false");
Johnathan Manteyb353ba02021-12-09 12:27:32 -08001092 stream << "\n";
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001093
Johnathan Mantey817012a2020-01-30 15:07:39 -08001094 // Static IP addresses
1095 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +05301096 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001097 if (originIsManuallyAssigned(addr.second->origin()) &&
1098 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001099 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001100 // Process all static addresses
1101 std::string address = addr.second->address() + "/" +
1102 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +05301103
Johnathan Mantey817012a2020-01-30 15:07:39 -08001104 // build the address entries. Do not use [Network] shortcuts to
1105 // insert address entries.
1106 stream << "[Address]\n";
1107 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001108 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001109 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001110
Lei YUcb2d4082021-08-12 15:26:49 +08001111 if (!dhcpIsEnabled(IP::Protocol::IPv4))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001112 {
Lei YUcb2d4082021-08-12 15:26:49 +08001113 auto gateway = EthernetInterfaceIntf::defaultGateway();
1114 if (!gateway.empty())
1115 {
1116 stream << "[Route]\n";
1117 stream << "Gateway=" << gateway << "\n";
1118 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001119 }
1120
Lei YUcb2d4082021-08-12 15:26:49 +08001121 if (!dhcpIsEnabled(IP::Protocol::IPv6))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001122 {
Lei YUcb2d4082021-08-12 15:26:49 +08001123 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1124 if (!gateway6.empty())
1125 {
1126 stream << "[Route]\n";
1127 stream << "Gateway=" << gateway6 << "\n";
1128 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001129 }
1130
William A. Kennington III08505792019-01-30 16:00:04 -08001131 // Write the neighbor sections
1132 for (const auto& neighbor : staticNeighbors)
1133 {
1134 stream << "[Neighbor]"
1135 << "\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001136 stream << "Address=" << neighbor.second->ipAddress() << "\n";
1137 stream << "MACAddress=" << neighbor.second->macAddress() << "\n";
William A. Kennington III08505792019-01-30 16:00:04 -08001138 }
1139
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001140 // Write the dhcp section irrespective of whether DHCP is enabled or not
1141 writeDHCPSection(stream);
1142
Ratan Gupta2b106532017-07-25 16:05:02 +05301143 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +05301144}
1145
1146void EthernetInterface::writeDHCPSection(std::fstream& stream)
1147{
1148 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301149 // write the dhcp section
1150 stream << "[DHCP]\n";
1151
1152 // Hardcoding the client identifier to mac, to address below issue
1153 // https://github.com/openbmc/openbmc/issues/1280
1154 stream << "ClientIdentifier=mac\n";
1155 if (manager.getDHCPConf())
1156 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001157 auto value = manager.getDHCPConf()->dnsEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301158 stream << "UseDNS="s + value + "\n";
sunharisdd1e5922022-03-31 01:49:21 -05001159 stream << "UseDomains="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301160
Patrick Williams6aef7692021-05-01 06:39:41 -05001161 value = manager.getDHCPConf()->ntpEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301162 stream << "UseNTP="s + value + "\n";
1163
1164 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1165 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001166
1167 value =
1168 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1169 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301170 }
1171}
1172
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001173std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301174{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001175#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001176 ether_addr newMAC;
1177 try
1178 {
1179 newMAC = mac_address::fromString(value);
1180 }
Patrick Williams5758db32021-10-06 12:29:22 -05001181 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001182 {
1183 log<level::ERR>("MACAddress is not valid.",
1184 entry("MAC=%s", value.c_str()));
1185 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1186 Argument::ARGUMENT_VALUE(value.c_str()));
1187 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001188 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301189 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001190 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001191 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001192 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1193 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301194 }
1195
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001196 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001197 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001198
William A. Kennington III1137a972019-04-20 20:49:58 -07001199 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001200 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001201 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301202 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001203 // Update everything that depends on the MAC value
1204 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301205 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001206 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301207 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001208 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301209
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001210 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001211 manager.addReloadPreHook([interface]() {
1212 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III5dad2aa2022-01-21 16:00:17 -08001213 setNICAdminState(interface.c_str(), false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001214 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001215 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301216 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001217
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001218#ifdef HAVE_UBOOT_ENV
1219 // Ensure that the valid address is stored in the u-boot-env
1220 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1221 if (envVar)
1222 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001223 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1224 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1225 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1226 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001227 }
1228#endif // HAVE_UBOOT_ENV
1229
William A. Kennington III1137a972019-04-20 20:49:58 -07001230 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001231#else
1232 elog<NotAllowed>(
1233 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1234#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301235}
1236
Ratan Guptae9c9b812017-09-22 17:15:37 +05301237void EthernetInterface::deleteAll()
1238{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301239 // clear all the ip on the interface
1240 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001241
1242 writeConfigurationFile();
1243 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301244}
1245
Ravi Tejaa5a09442020-07-17 00:57:33 -05001246std::string EthernetInterface::defaultGateway(std::string gateway)
1247{
1248 auto gw = EthernetInterfaceIntf::defaultGateway();
1249 if (gw == gateway)
1250 {
1251 return gw;
1252 }
1253
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001254 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001255 {
1256 log<level::ERR>("Not a valid v4 Gateway",
1257 entry("GATEWAY=%s", gateway.c_str()));
1258 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1259 Argument::ARGUMENT_VALUE(gateway.c_str()));
1260 }
1261 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001262
1263 writeConfigurationFile();
1264 manager.reloadConfigs();
1265
Ravi Tejaa5a09442020-07-17 00:57:33 -05001266 return gw;
1267}
1268
1269std::string EthernetInterface::defaultGateway6(std::string gateway)
1270{
1271 auto gw = EthernetInterfaceIntf::defaultGateway6();
1272 if (gw == gateway)
1273 {
1274 return gw;
1275 }
1276
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001277 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001278 {
1279 log<level::ERR>("Not a valid v6 Gateway",
1280 entry("GATEWAY=%s", gateway.c_str()));
1281 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1282 Argument::ARGUMENT_VALUE(gateway.c_str()));
1283 }
1284 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001285
1286 writeConfigurationFile();
1287 manager.reloadConfigs();
1288
Ravi Tejaa5a09442020-07-17 00:57:33 -05001289 return gw;
1290}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001291} // namespace network
1292} // namespace phosphor