blob: a1d9b83727567fe38afddcdd3d05878059f178ba [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 IIIc2e5e0e2019-04-22 01:26:06 -07006#include "ipaddress.hpp"
William A. Kennington III08505792019-01-30 16:00:04 -08007#include "neighbor.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05308#include "network_manager.hpp"
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -07009#include "types.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +053010#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +053011
Ratan Gupta82549cc2017-04-21 08:45:23 +053012#include <arpa/inet.h>
William A. Kennington III26275a32021-07-13 20:32:42 -070013#include <fmt/format.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070015#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053016#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053017#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053018
Ratan Gupta82549cc2017-04-21 08:45:23 +053019#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053020#include <filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053021#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070022#include <phosphor-logging/elog-errors.hpp>
23#include <phosphor-logging/log.hpp>
William A. Kennington III26275a32021-07-13 20:32:42 -070024#include <sdbusplus/bus/match.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053025#include <sstream>
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080026#include <stdplus/fd/create.hpp>
William A. Kennington III12beaad2020-06-13 19:30:41 -070027#include <stdplus/raw.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053028#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070029#include <string_view>
William A. Kennington III26275a32021-07-13 20:32:42 -070030#include <unordered_map>
31#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070032#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053033
Ratan Gupta91a99cc2017-04-14 16:32:09 +053034namespace phosphor
35{
36namespace network
37{
38
39using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053040using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053041using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
42using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050043using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053044constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
45constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
46constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
47constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
48constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053049
Johnathan Mantey817012a2020-01-30 15:07:39 -080050std::map<EthernetInterface::DHCPConf, std::string> mapDHCPToSystemd = {
51 {EthernetInterface::DHCPConf::both, "true"},
52 {EthernetInterface::DHCPConf::v4, "ipv4"},
53 {EthernetInterface::DHCPConf::v6, "ipv6"},
54 {EthernetInterface::DHCPConf::none, "false"}};
55
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080056static stdplus::Fd& getIFSock()
57{
58 using namespace stdplus::fd;
59 static auto fd =
60 socket(SocketDomain::INet, SocketType::Datagram, SocketProto::IP);
61 return fd;
62}
63
Patrick Williamsc38b0712022-07-22 19:26:54 -050064EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus,
Ratan Gupta91a99cc2017-04-14 16:32:09 +053065 const std::string& objPath,
Johnathan Mantey817012a2020-01-30 15:07:39 -080066 DHCPConf dhcpEnabled, Manager& parent,
William A. Kennington III26275a32021-07-13 20:32:42 -070067 bool emitSignal,
68 std::optional<bool> enabled) :
Patrick Williams166b9592022-03-30 16:09:16 -050069 Ifaces(bus, objPath.c_str(),
70 emitSignal ? Ifaces::action::defer_emit
71 : Ifaces::action::emit_no_signals),
Gunnar Mills57d9c502018-09-14 14:42:34 -050072 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053073{
74 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053075 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053076 interfaceName(intfName);
Patrick Williams6aef7692021-05-01 06:39:41 -050077 EthernetInterfaceIntf::dhcpEnabled(dhcpEnabled);
78 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRAFromConf());
William A. Kennington III26275a32021-07-13 20:32:42 -070079 EthernetInterfaceIntf::nicEnabled(enabled ? *enabled : queryNicEnabled());
William A. Kennington IIIe0564842021-10-23 16:02:22 -070080 const auto& gatewayList = manager.getRouteTable().getDefaultGateway();
81 const auto& gateway6List = manager.getRouteTable().getDefaultGateway6();
Ravi Tejaa5a09442020-07-17 00:57:33 -050082 std::string defaultGateway;
83 std::string defaultGateway6;
84
William A. Kennington IIIe0564842021-10-23 16:02:22 -070085 for (const auto& gateway : gatewayList)
Ravi Tejaa5a09442020-07-17 00:57:33 -050086 {
87 if (gateway.first == intfName)
88 {
89 defaultGateway = gateway.second;
90 break;
91 }
92 }
93
William A. Kennington IIIe0564842021-10-23 16:02:22 -070094 for (const auto& gateway6 : gateway6List)
Ravi Tejaa5a09442020-07-17 00:57:33 -050095 {
96 if (gateway6.first == intfName)
97 {
98 defaultGateway6 = gateway6.second;
99 break;
100 }
101 }
102
103 EthernetInterfaceIntf::defaultGateway(defaultGateway);
104 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
Ratan Gupta99801ce2020-01-09 18:37:16 +0530105 // Don't get the mac address from the system as the mac address
106 // would be same as parent interface.
107 if (intfName.find(".") == std::string::npos)
108 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500109 MacAddressIntf::macAddress(getMACAddress(intfName));
Ratan Gupta99801ce2020-01-09 18:37:16 +0530110 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500111 EthernetInterfaceIntf::ntpServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +0530112
113 EthernetInterfaceIntf::linkUp(linkUp());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530114 EthernetInterfaceIntf::mtu(mtu());
Ratan Gupta613a0122020-04-24 15:18:53 +0530115
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700116#ifdef NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -0700117 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
118
119 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
120 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800121#endif
Ratan Gupta6dec3902017-08-20 15:28:12 +0530122
Ratan Gupta29b0e432017-05-25 12:51:40 +0530123 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530124 if (emitSignal)
125 {
126 this->emit_object_added();
127 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530128}
129
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700130static IP::Protocol getProtocol(const InAddrAny& addr)
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800131{
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700132 if (std::holds_alternative<in_addr>(addr))
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800133 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700134 return IP::Protocol::IPv4;
135 }
136 else if (std::holds_alternative<in6_addr>(addr))
137 {
138 return IP::Protocol::IPv6;
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800139 }
140
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700141 throw std::runtime_error("Invalid addr type");
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800142}
143
Johnathan Mantey817012a2020-01-30 15:07:39 -0800144void EthernetInterface::disableDHCP(IP::Protocol protocol)
145{
Patrick Williams6aef7692021-05-01 06:39:41 -0500146 DHCPConf dhcpState = EthernetInterfaceIntf::dhcpEnabled();
Johnathan Mantey817012a2020-01-30 15:07:39 -0800147 if (dhcpState == EthernetInterface::DHCPConf::both)
148 {
149 if (protocol == IP::Protocol::IPv4)
150 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500151 dhcpEnabled(EthernetInterface::DHCPConf::v6);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800152 }
153 else if (protocol == IP::Protocol::IPv6)
154 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500155 dhcpEnabled(EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800156 }
157 }
158 else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
159 (protocol == IP::Protocol::IPv4))
160 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500161 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800162 }
163 else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
164 (protocol == IP::Protocol::IPv6))
165 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500166 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800167 }
168}
169
William A. Kennington III24957b92021-12-03 13:59:19 -0800170bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800171{
William A. Kennington III24957b92021-12-03 13:59:19 -0800172 const auto cur = EthernetInterfaceIntf::dhcpEnabled();
173 return cur == EthernetInterface::DHCPConf::both ||
174 (family == IP::Protocol::IPv6 &&
175 cur == EthernetInterface::DHCPConf::v6) ||
176 (family == IP::Protocol::IPv4 &&
177 cur == EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800178}
179
Johnathan Mantey817012a2020-01-30 15:07:39 -0800180bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
181{
182 return (
183#ifdef LINK_LOCAL_AUTOCONFIGURATION
184 (origin == IP::AddressOrigin::Static)
185#else
186 (origin == IP::AddressOrigin::Static ||
187 origin == IP::AddressOrigin::LinkLocal)
188#endif
189
190 );
191}
192
Ratan Gupta87c13982017-06-15 09:27:27 +0530193void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530194{
Ratan Gupta87c13982017-06-15 09:27:27 +0530195 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530196
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700197 AddressFilter filter;
198 filter.interface = ifIndex();
199 auto currentAddrs = getCurrentAddresses(filter);
200 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530201 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700202 auto address = toString(addr.address);
203 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800204 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800205 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530206 {
207 origin = IP::AddressOrigin::DHCP;
208 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700209 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530210 {
211 origin = IP::AddressOrigin::LinkLocal;
212 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700213 // Obsolete parameter
214 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530215
Gunnar Mills57d9c502018-09-14 14:42:34 -0500216 std::string ipAddressObjectPath = generateObjectPath(
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700217 addressType, address, addr.prefix, gateway, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530218
Lei YU7233c582021-04-08 14:39:43 +0800219 this->addrs.insert_or_assign(
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700220 address, std::make_shared<phosphor::network::IPAddress>(
221 bus, ipAddressObjectPath.c_str(), *this, addressType,
222 address, origin, addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530223 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530224}
225
William A. Kennington III08505792019-01-30 16:00:04 -0800226void EthernetInterface::createStaticNeighborObjects()
227{
228 staticNeighbors.clear();
229
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700230 NeighborFilter filter;
231 filter.interface = ifIndex();
232 filter.state = NUD_PERMANENT;
233 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800234 for (const auto& neighbor : neighbors)
235 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700236 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800237 {
238 continue;
239 }
240 std::string ip = toString(neighbor.address);
241 std::string mac = mac_address::toString(*neighbor.mac);
242 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
243 staticNeighbors.emplace(ip,
244 std::make_shared<phosphor::network::Neighbor>(
245 bus, objectPath.c_str(), *this, ip, mac,
246 Neighbor::State::Permanent));
247 }
248}
249
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700250unsigned EthernetInterface::ifIndex() const
251{
252 unsigned idx = if_nametoindex(interfaceName().c_str());
253 if (idx == 0)
254 {
255 throw std::system_error(errno, std::generic_category(),
256 "if_nametoindex");
257 }
258 return idx;
259}
260
Patrick Williams6aef7692021-05-01 06:39:41 -0500261ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
raviteja-bce379562019-03-28 05:59:36 -0500262 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530263{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800264 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530265 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530266 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500267 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800268 disableDHCP(protType);
Ravi Teja07450442022-07-07 04:30:57 -0500269 // Delete the IP address object and that reloads the networkd
270 // to allow the same IP address to be set as Static IP
271 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500272 }
273
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500274 IP::AddressOrigin origin = IP::AddressOrigin::Static;
275
276 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
277
278 if (!isValidIP(addressFamily, ipaddress))
279 {
280 log<level::ERR>("Not a valid IP address"),
281 entry("ADDRESS=%s", ipaddress.c_str());
282 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
283 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
284 }
285
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700286 // Gateway is an obsolete parameter
287 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500288
289 if (!isValidPrefix(addressFamily, prefixLength))
290 {
291 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700292 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500293 elog<InvalidArgument>(
294 Argument::ARGUMENT_NAME("prefixLength"),
295 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530296 }
297
Gunnar Mills57d9c502018-09-14 14:42:34 -0500298 std::string objectPath =
Lei YU34027572021-08-11 15:23:52 +0800299 generateObjectPath(protType, ipaddress, prefixLength, gateway, origin);
Lei YU7233c582021-04-08 14:39:43 +0800300 this->addrs.insert_or_assign(ipaddress,
301 std::make_shared<phosphor::network::IPAddress>(
302 bus, objectPath.c_str(), *this, protType,
303 ipaddress, origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530304
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700305 writeConfigurationFile();
306 manager.reloadConfigs();
307
raviteja-bce379562019-03-28 05:59:36 -0500308 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530309}
310
Patrick Williams6aef7692021-05-01 06:39:41 -0500311ObjectPath EthernetInterface::neighbor(std::string ipAddress,
312 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800313{
Patrick Williams6aef7692021-05-01 06:39:41 -0500314 if (!isValidIP(AF_INET, ipAddress) && !isValidIP(AF_INET6, ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800315 {
316 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500317 entry("ADDRESS=%s", ipAddress.c_str()));
318 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
319 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800320 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500321 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800322 {
323 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500324 entry("MACADDRESS=%s", ipAddress.c_str()));
325 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
326 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800327 }
328
329 std::string objectPath =
Patrick Williams6aef7692021-05-01 06:39:41 -0500330 generateStaticNeighborObjectPath(ipAddress, macAddress);
331 staticNeighbors.emplace(ipAddress,
William A. Kennington III08505792019-01-30 16:00:04 -0800332 std::make_shared<phosphor::network::Neighbor>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500333 bus, objectPath.c_str(), *this, ipAddress,
334 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700335
336 writeConfigurationFile();
337 manager.reloadConfigs();
338
William A. Kennington III08505792019-01-30 16:00:04 -0800339 return objectPath;
340}
341
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700342#ifdef NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530343/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800344 Enable this code if your NIC driver supports the ETHTOOL features.
345 Do this by adding the following to your phosphor-network*.bbappend file.
346 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
347 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530348*/
349InterfaceInfo EthernetInterface::getInterfaceInfo() const
350{
William A. Kennington III05368f12021-05-13 18:40:47 -0700351 ifreq ifr = {};
352 ethtool_cmd edata = {};
353 LinkSpeed speed = {};
354 Autoneg autoneg = {};
355 DuplexMode duplex = {};
356 LinkUp linkState = {};
357 NICEnabled enabled = {};
Tejas Patil2c0fc562021-08-03 19:13:46 +0530358 MTU mtuSize = {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530359
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800360 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
361 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530362
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800363 edata.cmd = ETHTOOL_GSET;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800364 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800365 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800366 getIFSock().ioctl(SIOCETHTOOL, &ifr);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530367 speed = edata.speed;
368 duplex = edata.duplex;
369 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530370 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800371 catch (const std::exception& e)
372 {
373 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800374
William A. Kennington III96203312021-05-07 12:50:41 -0700375 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800376 linkState = linkUp();
Tejas Patil2c0fc562021-08-03 19:13:46 +0530377 mtuSize = mtu();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800378
Tejas Patil2c0fc562021-08-03 19:13:46 +0530379 return std::make_tuple(speed, duplex, autoneg, linkState, enabled, mtuSize);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530380}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800381#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530382
383/** @brief get the mac address of the interface.
384 * @return macaddress on success
385 */
386
Gunnar Mills57d9c502018-09-14 14:42:34 -0500387std::string
388 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530389{
Patrick Williams6aef7692021-05-01 06:39:41 -0500390 std::string activeMACAddr = MacAddressIntf::macAddress();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530391
William A. Kennington III05368f12021-05-13 18:40:47 -0700392 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800393 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800394 try
395 {
396 getIFSock().ioctl(SIOCGIFHWADDR, &ifr);
397 }
398 catch (const std::exception& e)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530399 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530400 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800401 entry("ERROR=%s", e.what()));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700402 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530403 }
404
William A. Kennington III1137a972019-04-20 20:49:58 -0700405 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
406 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
407 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700408 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530409}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530410
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530411std::string EthernetInterface::generateId(const std::string& ipaddress,
412 uint8_t prefixLength,
Lei YU34027572021-08-11 15:23:52 +0800413 const std::string& gateway,
414 const std::string& origin)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530415{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530416 std::stringstream hexId;
417 std::string hashString = ipaddress;
418 hashString += std::to_string(prefixLength);
419 hashString += gateway;
Lei YU34027572021-08-11 15:23:52 +0800420 hashString += origin;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530421
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530422 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500423 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530424 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530425}
426
Patrick Williams6aef7692021-05-01 06:39:41 -0500427std::string EthernetInterface::generateNeighborId(const std::string& ipAddress,
428 const std::string& macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800429{
430 std::stringstream hexId;
Patrick Williams6aef7692021-05-01 06:39:41 -0500431 std::string hashString = ipAddress + macAddress;
William A. Kennington III08505792019-01-30 16:00:04 -0800432
433 // Only want 8 hex digits.
434 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
435 return hexId.str();
436}
437
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530438void EthernetInterface::deleteObject(const std::string& ipaddress)
439{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530440 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530441 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530442 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530443 log<level::ERR>("DeleteObject:Unable to find the object.");
444 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530445 }
446 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700447
448 writeConfigurationFile();
449 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530450}
451
Patrick Williams6aef7692021-05-01 06:39:41 -0500452void EthernetInterface::deleteStaticNeighborObject(const std::string& ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800453{
Patrick Williams6aef7692021-05-01 06:39:41 -0500454 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800455 if (it == staticNeighbors.end())
456 {
457 log<level::ERR>(
458 "DeleteStaticNeighborObject:Unable to find the object.");
459 return;
460 }
461 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700462
463 writeConfigurationFile();
464 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800465}
466
Ratan Guptae9c9b812017-09-22 17:15:37 +0530467void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530468{
Ratan Guptabc886292017-07-25 18:29:57 +0530469 auto confDir = manager.getConfDir();
470 fs::path networkFile = confDir;
471 networkFile /= systemd::config::networkFilePrefix + interface +
472 systemd::config::networkFileSuffix;
473
474 fs::path deviceFile = confDir;
475 deviceFile /= interface + systemd::config::deviceFileSuffix;
476
477 // delete the vlan network file
478 if (fs::is_regular_file(networkFile))
479 {
480 fs::remove(networkFile);
481 }
482
483 // delete the vlan device file
484 if (fs::is_regular_file(deviceFile))
485 {
486 fs::remove(deviceFile);
487 }
Ratan Guptabc886292017-07-25 18:29:57 +0530488
489 // TODO systemd doesn't delete the virtual network interface
490 // even after deleting all the related configuartion.
491 // https://github.com/systemd/systemd/issues/6600
492 try
493 {
494 deleteInterface(interface);
495 }
Patrick Williams5758db32021-10-06 12:29:22 -0500496 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530497 {
498 commit<InternalFailure>();
499 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530500}
501
502void EthernetInterface::deleteVLANObject(const std::string& interface)
503{
504 auto it = vlanInterfaces.find(interface);
505 if (it == vlanInterfaces.end())
506 {
507 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500508 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530509 return;
510 }
511
512 deleteVLANFromSystem(interface);
513 // delete the interface
514 vlanInterfaces.erase(it);
515
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700516 writeConfigurationFile();
517 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530518}
519
Gunnar Mills57d9c502018-09-14 14:42:34 -0500520std::string EthernetInterface::generateObjectPath(
521 IP::Protocol addressType, const std::string& ipaddress,
Lei YU34027572021-08-11 15:23:52 +0800522 uint8_t prefixLength, const std::string& gateway,
523 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530524{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530525 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530526 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530527 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
528
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530529 std::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530530 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530531 objectPath /= type;
Lei YU34027572021-08-11 15:23:52 +0800532 objectPath /=
533 generateId(ipaddress, prefixLength, gateway, convertForMessage(origin));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530534 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530535}
536
William A. Kennington III08505792019-01-30 16:00:04 -0800537std::string EthernetInterface::generateStaticNeighborObjectPath(
Patrick Williams6aef7692021-05-01 06:39:41 -0500538 const std::string& ipAddress, const std::string& macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800539{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530540 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800541 objectPath /= objPath;
542 objectPath /= "static_neighbor";
Patrick Williams6aef7692021-05-01 06:39:41 -0500543 objectPath /= generateNeighborId(ipAddress, macAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800544 return objectPath.string();
545}
546
Patrick Williams6aef7692021-05-01 06:39:41 -0500547bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700548{
Patrick Williams6aef7692021-05-01 06:39:41 -0500549 if (value == EthernetInterfaceIntf::ipv6AcceptRA())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700550 {
551 return value;
552 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500553 EthernetInterfaceIntf::ipv6AcceptRA(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700554
555 writeConfigurationFile();
556 manager.reloadConfigs();
557
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700558 return value;
559}
560
Patrick Williams6aef7692021-05-01 06:39:41 -0500561EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530562{
Patrick Williams6aef7692021-05-01 06:39:41 -0500563 if (value == EthernetInterfaceIntf::dhcpEnabled())
Ratan Gupta5978dd12017-07-25 13:47:13 +0530564 {
565 return value;
566 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500567 EthernetInterfaceIntf::dhcpEnabled(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700568
569 writeConfigurationFile();
570 manager.reloadConfigs();
571
Ratan Gupta87c13982017-06-15 09:27:27 +0530572 return value;
573}
574
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800575bool EthernetInterface::linkUp() const
576{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800577 bool value = EthernetInterfaceIntf::linkUp();
578
William A. Kennington III05368f12021-05-13 18:40:47 -0700579 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800580 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800581 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800582 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800583 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800584 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
585 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800586 catch (const std::exception& e)
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800587 {
588 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800589 entry("ERROR=%s", e.what()));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800590 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700591 return value;
592}
593
Tejas Patil2c0fc562021-08-03 19:13:46 +0530594size_t EthernetInterface::mtu() const
595{
Tejas Patil2c0fc562021-08-03 19:13:46 +0530596 size_t value = EthernetInterfaceIntf::mtu();
597
Tejas Patil2c0fc562021-08-03 19:13:46 +0530598 ifreq ifr = {};
599 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800600 try
Tejas Patil2c0fc562021-08-03 19:13:46 +0530601 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800602 getIFSock().ioctl(SIOCGIFMTU, &ifr);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530603 value = ifr.ifr_mtu;
604 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800605 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530606 {
607 log<level::ERR>("ioctl failed for SIOCGIFMTU:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800608 entry("ERROR=%s", e.what()));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530609 }
610 return value;
611}
612
613size_t EthernetInterface::mtu(size_t value)
614{
615 if (value == EthernetInterfaceIntf::mtu())
616 {
617 return value;
618 }
619 else if (value == 0)
620 {
621 return EthernetInterfaceIntf::mtu();
622 }
623
Tejas Patil2c0fc562021-08-03 19:13:46 +0530624 ifreq ifr = {};
625 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
626 ifr.ifr_mtu = value;
627
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800628 try
629 {
630 getIFSock().ioctl(SIOCSIFMTU, &ifr);
631 }
632 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530633 {
634 log<level::ERR>("ioctl failed for SIOCSIFMTU:",
635 entry("ERROR=%s", strerror(errno)));
636 return EthernetInterfaceIntf::mtu();
637 }
Tejas Patil2c0fc562021-08-03 19:13:46 +0530638
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800639 EthernetInterfaceIntf::mtu(value);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530640 return value;
641}
642
William A. Kennington III26275a32021-07-13 20:32:42 -0700643bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700644{
William A. Kennington III26275a32021-07-13 20:32:42 -0700645 constexpr auto svc = "org.freedesktop.network1";
646 constexpr auto intf = "org.freedesktop.network1.Link";
647 constexpr auto prop = "AdministrativeState";
648 char* rpath;
649 sd_bus_path_encode("/org/freedesktop/network1/link",
650 std::to_string(ifIndex()).c_str(), &rpath);
651 std::string path(rpath);
652 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700653
William A. Kennington III26275a32021-07-13 20:32:42 -0700654 // Store / Parser for the AdministrativeState return value
655 std::optional<bool> ret;
656 auto cb = [&](const std::string& state) {
657 if (state != "initialized")
658 {
659 ret = state != "unmanaged";
660 }
661 };
662
663 // Build a matcher before making the property call to ensure we
664 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500665 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700666 bus,
667 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
668 "'PropertiesChanged',arg0='{}',",
669 svc, path, PROPERTY_INTERFACE, intf)
670 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500671 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700672 std::string intf;
673 std::unordered_map<std::string, std::variant<std::string>> values;
674 try
675 {
676 m.read(intf, values);
677 auto it = values.find(prop);
678 // Ignore properties that aren't AdministrativeState
679 if (it != values.end())
680 {
681 cb(std::get<std::string>(it->second));
682 }
683 }
684 catch (const std::exception& e)
685 {
686 log<level::ERR>(
687 fmt::format(
688 "AdministrativeState match parsing failed on {}: {}",
689 interfaceName(), e.what())
690 .c_str(),
691 entry("INTERFACE=%s", interfaceName().c_str()),
692 entry("ERROR=%s", e.what()));
693 }
694 });
695
696 // Actively call for the value in case the interface is already configured
697 auto method =
698 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
699 method.append(intf, prop);
700 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700701 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700702 auto reply = bus.call(method);
703 std::variant<std::string> state;
704 reply.read(state);
705 cb(std::get<std::string>(state));
706 }
707 catch (const std::exception& e)
708 {
709 log<level::ERR>(
710 fmt::format("Failed to get AdministrativeState on {}: {}",
711 interfaceName(), e.what())
712 .c_str(),
713 entry("INTERFACE=%s", interfaceName().c_str()),
714 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700715 }
716
William A. Kennington III26275a32021-07-13 20:32:42 -0700717 // The interface is not yet configured by systemd-networkd, wait until it
718 // signals us a valid state.
719 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700720 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700721 bus.wait();
722 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700723 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700724
725 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700726}
727
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800728static void setNICAdminState(const char* intf, bool up)
William A. Kennington III4209cee2021-10-23 18:14:21 -0700729{
730 ifreq ifr = {};
731 std::strncpy(ifr.ifr_name, intf, IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800732 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700733
734 ifr.ifr_flags &= ~IFF_UP;
735 ifr.ifr_flags |= up ? IFF_UP : 0;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800736 getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700737}
738
Patrick Williams6aef7692021-05-01 06:39:41 -0500739bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700740{
Patrick Williams6aef7692021-05-01 06:39:41 -0500741 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700742 {
743 return value;
744 }
745
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800746 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700747 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800748 if (!value)
749 {
750 // We only need to bring down the interface, networkd will always bring
751 // up managed interfaces
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800752 manager.addReloadPreHook([ifname = interfaceName()]() {
753 setNICAdminState(ifname.c_str(), false);
754 });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800755 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700756 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800757
758 return value;
759}
760
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530761ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530762{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530763 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
764 return EthernetInterfaceIntf::nameservers();
765}
766
767ServerList EthernetInterface::staticNameServers(ServerList value)
768{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530769 for (const auto& nameserverip : value)
770 {
771 if (!isValidIP(AF_INET, nameserverip) &&
772 !isValidIP(AF_INET6, nameserverip))
773 {
774 log<level::ERR>("Not a valid IP address"),
775 entry("ADDRESS=%s", nameserverip.c_str());
776 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530777 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530778 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
779 }
780 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530781 try
782 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530783 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700784
Ratan Gupta6dec3902017-08-20 15:28:12 +0530785 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700786 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530787 }
Patrick Williams5758db32021-10-06 12:29:22 -0500788 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530789 {
790 log<level::ERR>("Exception processing DNS entries");
791 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530792 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530793}
794
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530795void EthernetInterface::loadNameServers()
796{
797 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
798 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
799}
800
801ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec3902017-08-20 15:28:12 +0530802{
803 fs::path confPath = manager.getConfDir();
804
805 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500806 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530807 confPath /= fileName;
808 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530809 config::Parser parser(confPath.string());
810 auto rc = config::ReturnCode::SUCCESS;
811
812 std::tie(rc, servers) = parser.getValues("Network", "DNS");
813 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530814 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530815 log<level::DEBUG>("Unable to get the value for network[DNS]",
816 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530817 }
818 return servers;
819}
820
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530821ServerList EthernetInterface::getNameServerFromResolvd()
822{
823 ServerList servers;
824 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
825
826 /*
827 The DNS property under org.freedesktop.resolve1.Link interface contains
828 an array containing all DNS servers currently used by resolved. It
829 contains similar information as the DNS server data written to
830 /run/systemd/resolve/resolv.conf.
831
832 Each structure in the array consists of a numeric network interface index,
833 an address family, and a byte array containing the DNS server address
834 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
835 The array contains DNS servers configured system-wide, including those
836 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
837 /etc/systemd/resolved.conf, as well as per-interface DNS server
838 information either retrieved from systemd-networkd or configured by
839 external software via SetLinkDNS().
840 */
841
842 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
843 std::variant<type> name; // Variable to capture the DNS property
844 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
845 PROPERTY_INTERFACE, METHOD_GET);
846
847 method.append(RESOLVED_INTERFACE, "DNS");
848 auto reply = bus.call(method);
849
850 try
851 {
852 reply.read(name);
853 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500854 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530855 {
856 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
857 }
858 auto tupleVector = std::get_if<type>(&name);
859 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
860 {
Alexander Filippov983da552021-02-08 15:26:54 +0300861 int addressFamily = std::get<0>(*i);
862 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
863
864 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530865 {
Alexander Filippov983da552021-02-08 15:26:54 +0300866 case AF_INET:
867 if (ipaddress.size() == sizeof(struct in_addr))
868 {
869 servers.push_back(toString(
870 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
871 }
872 else
873 {
874 log<level::ERR>(
875 "Invalid data recived from Systemd-Resolved");
876 }
877 break;
878
879 case AF_INET6:
880 if (ipaddress.size() == sizeof(struct in6_addr))
881 {
882 servers.push_back(toString(
883 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
884 }
885 else
886 {
887 log<level::ERR>(
888 "Invalid data recived from Systemd-Resolved");
889 }
890 break;
891
892 default:
893 log<level::ERR>(
894 "Unsupported address family in DNS from Systemd-Resolved");
895 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530896 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530897 }
898 return servers;
899}
900
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530901void EthernetInterface::loadVLAN(VlanId id)
902{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500903 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530904 std::string path = objPath;
905 path += "_" + std::to_string(id);
906
Johnathan Mantey817012a2020-01-30 15:07:39 -0800907 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500908 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530909 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500910 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nicEnabled(), id,
Johnathan Mantey817012a2020-01-30 15:07:39 -0800911 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530912
Gunnar Mills57d9c502018-09-14 14:42:34 -0500913 // Fetch the ip address from the system
914 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530915 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800916 vlanIntf->createStaticNeighborObjects();
Jiaqing Zhaocc5a6702021-12-31 14:58:55 +0800917 vlanIntf->loadNameServers();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530918
919 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
920 std::move(vlanIntf));
921}
922
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700923ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530924{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500925 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800926
927 if (this->vlanInterfaces.count(vlanInterfaceName))
928 {
929 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
930 elog<InvalidArgument>(
931 Argument::ARGUMENT_NAME("VLANId"),
932 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
933 }
934
Ratan Gupta5978dd12017-07-25 13:47:13 +0530935 std::string path = objPath;
936 path += "_" + std::to_string(id);
937
Patrick Williams6aef7692021-05-01 06:39:41 -0500938 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530939 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530940 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800941 bus, path.c_str(), EthernetInterface::DHCPConf::none,
Patrick Williams6aef7692021-05-01 06:39:41 -0500942 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530943
944 // write the device file for the vlan interface.
945 vlanIntf->writeDeviceFile();
946
Gunnar Mills57d9c502018-09-14 14:42:34 -0500947 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700948
949 writeConfigurationFile();
950 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700951
952 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530953}
Ratan Gupta2b106532017-07-25 16:05:02 +0530954
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700955bool EthernetInterface::getIPv6AcceptRAFromConf()
956{
957 fs::path confPath = manager.getConfDir();
958
959 std::string fileName = systemd::config::networkFilePrefix +
960 interfaceName() + systemd::config::networkFileSuffix;
961 confPath /= fileName;
962 config::ValueList values;
963 config::Parser parser(confPath.string());
964 auto rc = config::ReturnCode::SUCCESS;
965 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
966 if (rc != config::ReturnCode::SUCCESS)
967 {
968 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
969 entry("rc=%d", rc));
970 return false;
971 }
972 return (values[0] == "true");
973}
974
Ratan Gupta497c0c92017-08-22 19:15:59 +0530975ServerList EthernetInterface::getNTPServersFromConf()
976{
977 fs::path confPath = manager.getConfDir();
978
Gunnar Mills57d9c502018-09-14 14:42:34 -0500979 std::string fileName = systemd::config::networkFilePrefix +
980 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530981 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530982
Ratan Gupta497c0c92017-08-22 19:15:59 +0530983 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530984 config::Parser parser(confPath.string());
985 auto rc = config::ReturnCode::SUCCESS;
986
987 std::tie(rc, servers) = parser.getValues("Network", "NTP");
988 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530989 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530990 log<level::DEBUG>("Unable to get the value for Network[NTP]",
991 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530992 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530993
Ratan Gupta497c0c92017-08-22 19:15:59 +0530994 return servers;
995}
996
Patrick Williams6aef7692021-05-01 06:39:41 -0500997ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530998{
Patrick Williams6aef7692021-05-01 06:39:41 -0500999 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +05301000
1001 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001002 manager.reloadConfigs();
1003
Ratan Gupta497c0c92017-08-22 19:15:59 +05301004 return ntpServers;
1005}
Ratan Gupta2b106532017-07-25 16:05:02 +05301006// Need to merge the below function with the code which writes the
1007// config file during factory reset.
1008// TODO openbmc/openbmc#1751
1009
1010void EthernetInterface::writeConfigurationFile()
1011{
1012 // write all the static ip address in the systemd-network conf file
1013
1014 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +05301015 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +05301016
1017 // if there is vlan interafce then write the configuration file
1018 // for vlan also.
1019
Gunnar Mills57d9c502018-09-14 14:42:34 -05001020 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +05301021 {
1022 intf.second->writeConfigurationFile();
1023 }
1024
Ratan Gupta2b106532017-07-25 16:05:02 +05301025 fs::path confPath = manager.getConfDir();
1026
Gunnar Mills57d9c502018-09-14 14:42:34 -05001027 std::string fileName = systemd::config::networkFilePrefix +
1028 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +05301029 confPath /= fileName;
1030 std::fstream stream;
1031
1032 stream.open(confPath.c_str(), std::fstream::out);
1033 if (!stream.is_open())
1034 {
1035 log<level::ERR>("Unable to open the file",
1036 entry("FILE=%s", confPath.c_str()));
1037 elog<InternalFailure>();
1038 }
1039
1040 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001041 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301042 stream << "Name=" << interfaceName() << "\n";
1043
1044 auto addrs = getAddresses();
1045
William A. Kennington III15787212019-04-23 19:18:01 -07001046 // Write the link section
1047 stream << "[Link]\n";
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001048#ifdef PERSIST_MAC
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001049 auto mac = MacAddressIntf::macAddress();
William A. Kennington III15787212019-04-23 19:18:01 -07001050 if (!mac.empty())
1051 {
1052 stream << "MACAddress=" << mac << "\n";
1053 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001054#endif
William A. Kennington III15787212019-04-23 19:18:01 -07001055
Patrick Williams6aef7692021-05-01 06:39:41 -05001056 if (!EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -07001057 {
1058 stream << "Unmanaged=yes\n";
1059 }
1060
Ratan Gupta2b106532017-07-25 16:05:02 +05301061 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001062 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001063#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -05001064 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001065#else
1066 stream << "LinkLocalAddressing=no\n";
1067#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -07001068 stream << std::boolalpha
Patrick Williams6aef7692021-05-01 06:39:41 -05001069 << "IPv6AcceptRA=" << EthernetInterfaceIntf::ipv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301070
1071 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -05001072 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301073 {
1074 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -05001075 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301076 }
Ratan Gupta046b2a02019-09-20 15:49:51 +05301077 // Add the NTP server
Patrick Williams6aef7692021-05-01 06:39:41 -05001078 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301079 {
1080 stream << "NTP=" << ntp << "\n";
1081 }
1082
1083 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +05301084 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301085 {
1086 stream << "DNS=" << dns << "\n";
1087 }
1088
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001089 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -08001090 stream << "DHCP="s +
Patrick Williams6aef7692021-05-01 06:39:41 -05001091 mapDHCPToSystemd[EthernetInterfaceIntf::dhcpEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001092
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001093 stream << "[IPv6AcceptRA]\n";
1094 stream << "DHCPv6Client=";
1095 stream << (dhcpIsEnabled(IP::Protocol::IPv6) ? "true" : "false");
Johnathan Manteyb353ba02021-12-09 12:27:32 -08001096 stream << "\n";
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001097
Johnathan Mantey817012a2020-01-30 15:07:39 -08001098 // Static IP addresses
1099 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +05301100 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001101 if (originIsManuallyAssigned(addr.second->origin()) &&
1102 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001103 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001104 // Process all static addresses
1105 std::string address = addr.second->address() + "/" +
1106 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +05301107
Johnathan Mantey817012a2020-01-30 15:07:39 -08001108 // build the address entries. Do not use [Network] shortcuts to
1109 // insert address entries.
1110 stream << "[Address]\n";
1111 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001112 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001113 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001114
Lei YUcb2d4082021-08-12 15:26:49 +08001115 if (!dhcpIsEnabled(IP::Protocol::IPv4))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001116 {
Lei YUcb2d4082021-08-12 15:26:49 +08001117 auto gateway = EthernetInterfaceIntf::defaultGateway();
1118 if (!gateway.empty())
1119 {
1120 stream << "[Route]\n";
1121 stream << "Gateway=" << gateway << "\n";
1122 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001123 }
1124
Lei YUcb2d4082021-08-12 15:26:49 +08001125 if (!dhcpIsEnabled(IP::Protocol::IPv6))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001126 {
Lei YUcb2d4082021-08-12 15:26:49 +08001127 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1128 if (!gateway6.empty())
1129 {
1130 stream << "[Route]\n";
1131 stream << "Gateway=" << gateway6 << "\n";
1132 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001133 }
1134
William A. Kennington III08505792019-01-30 16:00:04 -08001135 // Write the neighbor sections
1136 for (const auto& neighbor : staticNeighbors)
1137 {
1138 stream << "[Neighbor]"
1139 << "\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001140 stream << "Address=" << neighbor.second->ipAddress() << "\n";
1141 stream << "MACAddress=" << neighbor.second->macAddress() << "\n";
William A. Kennington III08505792019-01-30 16:00:04 -08001142 }
1143
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001144 // Write the dhcp section irrespective of whether DHCP is enabled or not
1145 writeDHCPSection(stream);
1146
Ratan Gupta2b106532017-07-25 16:05:02 +05301147 stream.close();
William A. Kennington IIIf8b3fc32022-08-22 15:16:48 -07001148 auto msg = fmt::format("Wrote networkd file: {}", confPath.native());
1149 log<level::INFO>(msg.c_str(), entry("FILE=%s", confPath.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +05301150}
1151
1152void EthernetInterface::writeDHCPSection(std::fstream& stream)
1153{
1154 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301155 // write the dhcp section
1156 stream << "[DHCP]\n";
1157
1158 // Hardcoding the client identifier to mac, to address below issue
1159 // https://github.com/openbmc/openbmc/issues/1280
1160 stream << "ClientIdentifier=mac\n";
1161 if (manager.getDHCPConf())
1162 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001163 auto value = manager.getDHCPConf()->dnsEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301164 stream << "UseDNS="s + value + "\n";
sunharisdd1e5922022-03-31 01:49:21 -05001165 stream << "UseDomains="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301166
Patrick Williams6aef7692021-05-01 06:39:41 -05001167 value = manager.getDHCPConf()->ntpEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301168 stream << "UseNTP="s + value + "\n";
1169
1170 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1171 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001172
1173 value =
1174 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1175 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301176 }
1177}
1178
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001179std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301180{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001181#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001182 ether_addr newMAC;
1183 try
1184 {
1185 newMAC = mac_address::fromString(value);
1186 }
Patrick Williams5758db32021-10-06 12:29:22 -05001187 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001188 {
1189 log<level::ERR>("MACAddress is not valid.",
1190 entry("MAC=%s", value.c_str()));
1191 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1192 Argument::ARGUMENT_VALUE(value.c_str()));
1193 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001194 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301195 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001196 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001197 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001198 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1199 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301200 }
1201
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001202 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001203 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001204
William A. Kennington III1137a972019-04-20 20:49:58 -07001205 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001206 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001207 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301208 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001209 // Update everything that depends on the MAC value
1210 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301211 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001212 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301213 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001214 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301215
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001216 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001217 manager.addReloadPreHook([interface]() {
1218 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III5dad2aa2022-01-21 16:00:17 -08001219 setNICAdminState(interface.c_str(), false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001220 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001221 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301222 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001223
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001224#ifdef HAVE_UBOOT_ENV
1225 // Ensure that the valid address is stored in the u-boot-env
1226 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1227 if (envVar)
1228 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001229 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1230 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1231 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1232 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001233 }
1234#endif // HAVE_UBOOT_ENV
1235
William A. Kennington III1137a972019-04-20 20:49:58 -07001236 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001237#else
1238 elog<NotAllowed>(
1239 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1240#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301241}
1242
Ratan Guptae9c9b812017-09-22 17:15:37 +05301243void EthernetInterface::deleteAll()
1244{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301245 // clear all the ip on the interface
1246 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001247
1248 writeConfigurationFile();
1249 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301250}
1251
Ravi Tejaa5a09442020-07-17 00:57:33 -05001252std::string EthernetInterface::defaultGateway(std::string gateway)
1253{
1254 auto gw = EthernetInterfaceIntf::defaultGateway();
1255 if (gw == gateway)
1256 {
1257 return gw;
1258 }
1259
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001260 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001261 {
1262 log<level::ERR>("Not a valid v4 Gateway",
1263 entry("GATEWAY=%s", gateway.c_str()));
1264 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1265 Argument::ARGUMENT_VALUE(gateway.c_str()));
1266 }
1267 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001268
1269 writeConfigurationFile();
1270 manager.reloadConfigs();
1271
Ravi Tejaa5a09442020-07-17 00:57:33 -05001272 return gw;
1273}
1274
1275std::string EthernetInterface::defaultGateway6(std::string gateway)
1276{
1277 auto gw = EthernetInterfaceIntf::defaultGateway6();
1278 if (gw == gateway)
1279 {
1280 return gw;
1281 }
1282
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001283 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001284 {
1285 log<level::ERR>("Not a valid v6 Gateway",
1286 entry("GATEWAY=%s", gateway.c_str()));
1287 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1288 Argument::ARGUMENT_VALUE(gateway.c_str()));
1289 }
1290 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001291
1292 writeConfigurationFile();
1293 manager.reloadConfigs();
1294
Ravi Tejaa5a09442020-07-17 00:57:33 -05001295 return gw;
1296}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001297} // namespace network
1298} // namespace phosphor