blob: 825ce62d2df55a4dae7286bbb0219791accfdd40 [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 Gupta6dec390f2017-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 III13d17082021-11-04 21:36:54 -0700202 if (addr.flags & IFA_F_DEPRECATED)
203 {
204 continue;
205 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700206 auto address = toString(addr.address);
207 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800208 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800209 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530210 {
211 origin = IP::AddressOrigin::DHCP;
212 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700213 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530214 {
215 origin = IP::AddressOrigin::LinkLocal;
216 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700217 // Obsolete parameter
218 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530219
Gunnar Mills57d9c502018-09-14 14:42:34 -0500220 std::string ipAddressObjectPath = generateObjectPath(
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700221 addressType, address, addr.prefix, gateway, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530222
Lei YU7233c582021-04-08 14:39:43 +0800223 this->addrs.insert_or_assign(
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700224 address, std::make_shared<phosphor::network::IPAddress>(
225 bus, ipAddressObjectPath.c_str(), *this, addressType,
226 address, origin, addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530227 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530228}
229
William A. Kennington III08505792019-01-30 16:00:04 -0800230void EthernetInterface::createStaticNeighborObjects()
231{
232 staticNeighbors.clear();
233
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700234 NeighborFilter filter;
235 filter.interface = ifIndex();
236 filter.state = NUD_PERMANENT;
237 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800238 for (const auto& neighbor : neighbors)
239 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700240 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800241 {
242 continue;
243 }
244 std::string ip = toString(neighbor.address);
245 std::string mac = mac_address::toString(*neighbor.mac);
246 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
247 staticNeighbors.emplace(ip,
248 std::make_shared<phosphor::network::Neighbor>(
249 bus, objectPath.c_str(), *this, ip, mac,
250 Neighbor::State::Permanent));
251 }
252}
253
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700254unsigned EthernetInterface::ifIndex() const
255{
256 unsigned idx = if_nametoindex(interfaceName().c_str());
257 if (idx == 0)
258 {
259 throw std::system_error(errno, std::generic_category(),
260 "if_nametoindex");
261 }
262 return idx;
263}
264
Patrick Williams6aef7692021-05-01 06:39:41 -0500265ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
raviteja-bce379562019-03-28 05:59:36 -0500266 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530267{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800268 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530269 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530270 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500271 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800272 disableDHCP(protType);
Ravi Teja07450442022-07-07 04:30:57 -0500273 // Delete the IP address object and that reloads the networkd
274 // to allow the same IP address to be set as Static IP
275 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500276 }
277
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500278 IP::AddressOrigin origin = IP::AddressOrigin::Static;
279
280 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
281
282 if (!isValidIP(addressFamily, ipaddress))
283 {
284 log<level::ERR>("Not a valid IP address"),
285 entry("ADDRESS=%s", ipaddress.c_str());
286 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
287 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
288 }
289
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700290 // Gateway is an obsolete parameter
291 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500292
293 if (!isValidPrefix(addressFamily, prefixLength))
294 {
295 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700296 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500297 elog<InvalidArgument>(
298 Argument::ARGUMENT_NAME("prefixLength"),
299 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530300 }
301
Gunnar Mills57d9c502018-09-14 14:42:34 -0500302 std::string objectPath =
Lei YU34027572021-08-11 15:23:52 +0800303 generateObjectPath(protType, ipaddress, prefixLength, gateway, origin);
Lei YU7233c582021-04-08 14:39:43 +0800304 this->addrs.insert_or_assign(ipaddress,
305 std::make_shared<phosphor::network::IPAddress>(
306 bus, objectPath.c_str(), *this, protType,
307 ipaddress, origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530308
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700309 writeConfigurationFile();
310 manager.reloadConfigs();
311
raviteja-bce379562019-03-28 05:59:36 -0500312 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530313}
314
Patrick Williams6aef7692021-05-01 06:39:41 -0500315ObjectPath EthernetInterface::neighbor(std::string ipAddress,
316 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800317{
Patrick Williams6aef7692021-05-01 06:39:41 -0500318 if (!isValidIP(AF_INET, ipAddress) && !isValidIP(AF_INET6, ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800319 {
320 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500321 entry("ADDRESS=%s", ipAddress.c_str()));
322 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
323 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800324 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500325 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800326 {
327 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500328 entry("MACADDRESS=%s", ipAddress.c_str()));
329 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
330 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800331 }
332
333 std::string objectPath =
Patrick Williams6aef7692021-05-01 06:39:41 -0500334 generateStaticNeighborObjectPath(ipAddress, macAddress);
335 staticNeighbors.emplace(ipAddress,
William A. Kennington III08505792019-01-30 16:00:04 -0800336 std::make_shared<phosphor::network::Neighbor>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500337 bus, objectPath.c_str(), *this, ipAddress,
338 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700339
340 writeConfigurationFile();
341 manager.reloadConfigs();
342
William A. Kennington III08505792019-01-30 16:00:04 -0800343 return objectPath;
344}
345
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700346#ifdef NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530347/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800348 Enable this code if your NIC driver supports the ETHTOOL features.
349 Do this by adding the following to your phosphor-network*.bbappend file.
350 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
351 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530352*/
353InterfaceInfo EthernetInterface::getInterfaceInfo() const
354{
William A. Kennington III05368f12021-05-13 18:40:47 -0700355 ifreq ifr = {};
356 ethtool_cmd edata = {};
357 LinkSpeed speed = {};
358 Autoneg autoneg = {};
359 DuplexMode duplex = {};
360 LinkUp linkState = {};
361 NICEnabled enabled = {};
Tejas Patil2c0fc562021-08-03 19:13:46 +0530362 MTU mtuSize = {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530363
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800364 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
365 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530366
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800367 edata.cmd = ETHTOOL_GSET;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800368 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800369 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800370 getIFSock().ioctl(SIOCETHTOOL, &ifr);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530371 speed = edata.speed;
372 duplex = edata.duplex;
373 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530374 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800375 catch (const std::exception& e)
376 {
377 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800378
William A. Kennington III96203312021-05-07 12:50:41 -0700379 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800380 linkState = linkUp();
Tejas Patil2c0fc562021-08-03 19:13:46 +0530381 mtuSize = mtu();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800382
Tejas Patil2c0fc562021-08-03 19:13:46 +0530383 return std::make_tuple(speed, duplex, autoneg, linkState, enabled, mtuSize);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530384}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800385#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530386
387/** @brief get the mac address of the interface.
388 * @return macaddress on success
389 */
390
Gunnar Mills57d9c502018-09-14 14:42:34 -0500391std::string
392 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530393{
Patrick Williams6aef7692021-05-01 06:39:41 -0500394 std::string activeMACAddr = MacAddressIntf::macAddress();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530395
William A. Kennington III05368f12021-05-13 18:40:47 -0700396 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800397 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800398 try
399 {
400 getIFSock().ioctl(SIOCGIFHWADDR, &ifr);
401 }
402 catch (const std::exception& e)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530403 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530404 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800405 entry("ERROR=%s", e.what()));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700406 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530407 }
408
William A. Kennington III1137a972019-04-20 20:49:58 -0700409 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
410 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
411 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700412 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530413}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530414
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530415std::string EthernetInterface::generateId(const std::string& ipaddress,
416 uint8_t prefixLength,
Lei YU34027572021-08-11 15:23:52 +0800417 const std::string& gateway,
418 const std::string& origin)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530419{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530420 std::stringstream hexId;
421 std::string hashString = ipaddress;
422 hashString += std::to_string(prefixLength);
423 hashString += gateway;
Lei YU34027572021-08-11 15:23:52 +0800424 hashString += origin;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530425
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530426 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530428 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530429}
430
Patrick Williams6aef7692021-05-01 06:39:41 -0500431std::string EthernetInterface::generateNeighborId(const std::string& ipAddress,
432 const std::string& macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800433{
434 std::stringstream hexId;
Patrick Williams6aef7692021-05-01 06:39:41 -0500435 std::string hashString = ipAddress + macAddress;
William A. Kennington III08505792019-01-30 16:00:04 -0800436
437 // Only want 8 hex digits.
438 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
439 return hexId.str();
440}
441
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530442void EthernetInterface::deleteObject(const std::string& ipaddress)
443{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530444 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530445 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530446 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530447 log<level::ERR>("DeleteObject:Unable to find the object.");
448 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530449 }
450 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700451
452 writeConfigurationFile();
453 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530454}
455
Patrick Williams6aef7692021-05-01 06:39:41 -0500456void EthernetInterface::deleteStaticNeighborObject(const std::string& ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800457{
Patrick Williams6aef7692021-05-01 06:39:41 -0500458 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800459 if (it == staticNeighbors.end())
460 {
461 log<level::ERR>(
462 "DeleteStaticNeighborObject:Unable to find the object.");
463 return;
464 }
465 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700466
467 writeConfigurationFile();
468 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800469}
470
Ratan Guptae9c9b812017-09-22 17:15:37 +0530471void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530472{
Ratan Guptabc886292017-07-25 18:29:57 +0530473 auto confDir = manager.getConfDir();
474 fs::path networkFile = confDir;
475 networkFile /= systemd::config::networkFilePrefix + interface +
476 systemd::config::networkFileSuffix;
477
478 fs::path deviceFile = confDir;
479 deviceFile /= interface + systemd::config::deviceFileSuffix;
480
481 // delete the vlan network file
482 if (fs::is_regular_file(networkFile))
483 {
484 fs::remove(networkFile);
485 }
486
487 // delete the vlan device file
488 if (fs::is_regular_file(deviceFile))
489 {
490 fs::remove(deviceFile);
491 }
Ratan Guptabc886292017-07-25 18:29:57 +0530492
493 // TODO systemd doesn't delete the virtual network interface
494 // even after deleting all the related configuartion.
495 // https://github.com/systemd/systemd/issues/6600
496 try
497 {
498 deleteInterface(interface);
499 }
Patrick Williams5758db32021-10-06 12:29:22 -0500500 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530501 {
502 commit<InternalFailure>();
503 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530504}
505
506void EthernetInterface::deleteVLANObject(const std::string& interface)
507{
508 auto it = vlanInterfaces.find(interface);
509 if (it == vlanInterfaces.end())
510 {
511 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500512 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530513 return;
514 }
515
516 deleteVLANFromSystem(interface);
517 // delete the interface
518 vlanInterfaces.erase(it);
519
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700520 writeConfigurationFile();
521 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530522}
523
Gunnar Mills57d9c502018-09-14 14:42:34 -0500524std::string EthernetInterface::generateObjectPath(
525 IP::Protocol addressType, const std::string& ipaddress,
Lei YU34027572021-08-11 15:23:52 +0800526 uint8_t prefixLength, const std::string& gateway,
527 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530528{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530529 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530530 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530531 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
532
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530533 std::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530534 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530535 objectPath /= type;
Lei YU34027572021-08-11 15:23:52 +0800536 objectPath /=
537 generateId(ipaddress, prefixLength, gateway, convertForMessage(origin));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530538 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530539}
540
William A. Kennington III08505792019-01-30 16:00:04 -0800541std::string EthernetInterface::generateStaticNeighborObjectPath(
Patrick Williams6aef7692021-05-01 06:39:41 -0500542 const std::string& ipAddress, const std::string& macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800543{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530544 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800545 objectPath /= objPath;
546 objectPath /= "static_neighbor";
Patrick Williams6aef7692021-05-01 06:39:41 -0500547 objectPath /= generateNeighborId(ipAddress, macAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800548 return objectPath.string();
549}
550
Patrick Williams6aef7692021-05-01 06:39:41 -0500551bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700552{
Patrick Williams6aef7692021-05-01 06:39:41 -0500553 if (value == EthernetInterfaceIntf::ipv6AcceptRA())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700554 {
555 return value;
556 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500557 EthernetInterfaceIntf::ipv6AcceptRA(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700558
559 writeConfigurationFile();
560 manager.reloadConfigs();
561
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700562 return value;
563}
564
Patrick Williams6aef7692021-05-01 06:39:41 -0500565EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530566{
Patrick Williams6aef7692021-05-01 06:39:41 -0500567 if (value == EthernetInterfaceIntf::dhcpEnabled())
Ratan Gupta5978dd12017-07-25 13:47:13 +0530568 {
569 return value;
570 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500571 EthernetInterfaceIntf::dhcpEnabled(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700572
573 writeConfigurationFile();
574 manager.reloadConfigs();
575
Ratan Gupta87c13982017-06-15 09:27:27 +0530576 return value;
577}
578
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800579bool EthernetInterface::linkUp() const
580{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800581 bool value = EthernetInterfaceIntf::linkUp();
582
William A. Kennington III05368f12021-05-13 18:40:47 -0700583 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800584 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800585 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800586 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800587 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800588 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
589 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800590 catch (const std::exception& e)
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800591 {
592 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800593 entry("ERROR=%s", e.what()));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800594 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700595 return value;
596}
597
Tejas Patil2c0fc562021-08-03 19:13:46 +0530598size_t EthernetInterface::mtu() const
599{
Tejas Patil2c0fc562021-08-03 19:13:46 +0530600 size_t value = EthernetInterfaceIntf::mtu();
601
Tejas Patil2c0fc562021-08-03 19:13:46 +0530602 ifreq ifr = {};
603 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800604 try
Tejas Patil2c0fc562021-08-03 19:13:46 +0530605 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800606 getIFSock().ioctl(SIOCGIFMTU, &ifr);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530607 value = ifr.ifr_mtu;
608 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800609 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530610 {
611 log<level::ERR>("ioctl failed for SIOCGIFMTU:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800612 entry("ERROR=%s", e.what()));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530613 }
614 return value;
615}
616
617size_t EthernetInterface::mtu(size_t value)
618{
619 if (value == EthernetInterfaceIntf::mtu())
620 {
621 return value;
622 }
623 else if (value == 0)
624 {
625 return EthernetInterfaceIntf::mtu();
626 }
627
Tejas Patil2c0fc562021-08-03 19:13:46 +0530628 ifreq ifr = {};
629 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
630 ifr.ifr_mtu = value;
631
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800632 try
633 {
634 getIFSock().ioctl(SIOCSIFMTU, &ifr);
635 }
636 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530637 {
638 log<level::ERR>("ioctl failed for SIOCSIFMTU:",
639 entry("ERROR=%s", strerror(errno)));
640 return EthernetInterfaceIntf::mtu();
641 }
Tejas Patil2c0fc562021-08-03 19:13:46 +0530642
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800643 EthernetInterfaceIntf::mtu(value);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530644 return value;
645}
646
William A. Kennington III26275a32021-07-13 20:32:42 -0700647bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700648{
William A. Kennington III26275a32021-07-13 20:32:42 -0700649 constexpr auto svc = "org.freedesktop.network1";
650 constexpr auto intf = "org.freedesktop.network1.Link";
651 constexpr auto prop = "AdministrativeState";
652 char* rpath;
653 sd_bus_path_encode("/org/freedesktop/network1/link",
654 std::to_string(ifIndex()).c_str(), &rpath);
655 std::string path(rpath);
656 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700657
William A. Kennington III26275a32021-07-13 20:32:42 -0700658 // Store / Parser for the AdministrativeState return value
659 std::optional<bool> ret;
660 auto cb = [&](const std::string& state) {
661 if (state != "initialized")
662 {
663 ret = state != "unmanaged";
664 }
665 };
666
667 // Build a matcher before making the property call to ensure we
668 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500669 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700670 bus,
671 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
672 "'PropertiesChanged',arg0='{}',",
673 svc, path, PROPERTY_INTERFACE, intf)
674 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500675 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700676 std::string intf;
677 std::unordered_map<std::string, std::variant<std::string>> values;
678 try
679 {
680 m.read(intf, values);
681 auto it = values.find(prop);
682 // Ignore properties that aren't AdministrativeState
683 if (it != values.end())
684 {
685 cb(std::get<std::string>(it->second));
686 }
687 }
688 catch (const std::exception& e)
689 {
690 log<level::ERR>(
691 fmt::format(
692 "AdministrativeState match parsing failed on {}: {}",
693 interfaceName(), e.what())
694 .c_str(),
695 entry("INTERFACE=%s", interfaceName().c_str()),
696 entry("ERROR=%s", e.what()));
697 }
698 });
699
700 // Actively call for the value in case the interface is already configured
701 auto method =
702 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
703 method.append(intf, prop);
704 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700705 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700706 auto reply = bus.call(method);
707 std::variant<std::string> state;
708 reply.read(state);
709 cb(std::get<std::string>(state));
710 }
711 catch (const std::exception& e)
712 {
713 log<level::ERR>(
714 fmt::format("Failed to get AdministrativeState on {}: {}",
715 interfaceName(), e.what())
716 .c_str(),
717 entry("INTERFACE=%s", interfaceName().c_str()),
718 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700719 }
720
William A. Kennington III26275a32021-07-13 20:32:42 -0700721 // The interface is not yet configured by systemd-networkd, wait until it
722 // signals us a valid state.
723 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700724 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700725 bus.wait();
726 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700727 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700728
729 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700730}
731
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800732static void setNICAdminState(const char* intf, bool up)
William A. Kennington III4209cee2021-10-23 18:14:21 -0700733{
734 ifreq ifr = {};
735 std::strncpy(ifr.ifr_name, intf, IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800736 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700737
738 ifr.ifr_flags &= ~IFF_UP;
739 ifr.ifr_flags |= up ? IFF_UP : 0;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800740 getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700741}
742
Patrick Williams6aef7692021-05-01 06:39:41 -0500743bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700744{
Patrick Williams6aef7692021-05-01 06:39:41 -0500745 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700746 {
747 return value;
748 }
749
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800750 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700751 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800752 if (!value)
753 {
754 // We only need to bring down the interface, networkd will always bring
755 // up managed interfaces
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800756 manager.addReloadPreHook([ifname = interfaceName()]() {
757 setNICAdminState(ifname.c_str(), false);
758 });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800759 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700760 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800761
762 return value;
763}
764
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530765ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530766{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530767 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
768 return EthernetInterfaceIntf::nameservers();
769}
770
771ServerList EthernetInterface::staticNameServers(ServerList value)
772{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530773 for (const auto& nameserverip : value)
774 {
775 if (!isValidIP(AF_INET, nameserverip) &&
776 !isValidIP(AF_INET6, nameserverip))
777 {
778 log<level::ERR>("Not a valid IP address"),
779 entry("ADDRESS=%s", nameserverip.c_str());
780 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530781 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530782 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
783 }
784 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530785 try
786 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530787 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700788
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530789 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700790 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530791 }
Patrick Williams5758db32021-10-06 12:29:22 -0500792 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530793 {
794 log<level::ERR>("Exception processing DNS entries");
795 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530796 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530797}
798
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530799void EthernetInterface::loadNameServers()
800{
801 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
802 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
803}
804
805ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530806{
807 fs::path confPath = manager.getConfDir();
808
809 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500810 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530811 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530812 config::Parser parser(confPath.string());
William A. Kennington III25511a12022-08-04 16:32:28 -0700813 return parser.getValues("Network", "DNS");
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530814}
815
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530816ServerList EthernetInterface::getNameServerFromResolvd()
817{
818 ServerList servers;
819 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
820
821 /*
822 The DNS property under org.freedesktop.resolve1.Link interface contains
823 an array containing all DNS servers currently used by resolved. It
824 contains similar information as the DNS server data written to
825 /run/systemd/resolve/resolv.conf.
826
827 Each structure in the array consists of a numeric network interface index,
828 an address family, and a byte array containing the DNS server address
829 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
830 The array contains DNS servers configured system-wide, including those
831 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
832 /etc/systemd/resolved.conf, as well as per-interface DNS server
833 information either retrieved from systemd-networkd or configured by
834 external software via SetLinkDNS().
835 */
836
837 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
838 std::variant<type> name; // Variable to capture the DNS property
839 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
840 PROPERTY_INTERFACE, METHOD_GET);
841
842 method.append(RESOLVED_INTERFACE, "DNS");
843 auto reply = bus.call(method);
844
845 try
846 {
847 reply.read(name);
848 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500849 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530850 {
851 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
852 }
853 auto tupleVector = std::get_if<type>(&name);
854 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
855 {
Alexander Filippov983da552021-02-08 15:26:54 +0300856 int addressFamily = std::get<0>(*i);
857 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
858
859 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530860 {
Alexander Filippov983da552021-02-08 15:26:54 +0300861 case AF_INET:
862 if (ipaddress.size() == sizeof(struct in_addr))
863 {
864 servers.push_back(toString(
865 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
866 }
867 else
868 {
869 log<level::ERR>(
870 "Invalid data recived from Systemd-Resolved");
871 }
872 break;
873
874 case AF_INET6:
875 if (ipaddress.size() == sizeof(struct in6_addr))
876 {
877 servers.push_back(toString(
878 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
879 }
880 else
881 {
882 log<level::ERR>(
883 "Invalid data recived from Systemd-Resolved");
884 }
885 break;
886
887 default:
888 log<level::ERR>(
889 "Unsupported address family in DNS from Systemd-Resolved");
890 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530891 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530892 }
893 return servers;
894}
895
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530896void EthernetInterface::loadVLAN(VlanId id)
897{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500898 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530899 std::string path = objPath;
900 path += "_" + std::to_string(id);
901
Johnathan Mantey817012a2020-01-30 15:07:39 -0800902 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500903 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530904 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500905 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nicEnabled(), id,
Johnathan Mantey817012a2020-01-30 15:07:39 -0800906 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530907
Gunnar Mills57d9c502018-09-14 14:42:34 -0500908 // Fetch the ip address from the system
909 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530910 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800911 vlanIntf->createStaticNeighborObjects();
Jiaqing Zhaocc5a6702021-12-31 14:58:55 +0800912 vlanIntf->loadNameServers();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530913
914 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
915 std::move(vlanIntf));
916}
917
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700918ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530919{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500920 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800921
922 if (this->vlanInterfaces.count(vlanInterfaceName))
923 {
924 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
925 elog<InvalidArgument>(
926 Argument::ARGUMENT_NAME("VLANId"),
927 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
928 }
929
Ratan Gupta5978dd12017-07-25 13:47:13 +0530930 std::string path = objPath;
931 path += "_" + std::to_string(id);
932
Patrick Williams6aef7692021-05-01 06:39:41 -0500933 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530934 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530935 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800936 bus, path.c_str(), EthernetInterface::DHCPConf::none,
Patrick Williams6aef7692021-05-01 06:39:41 -0500937 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530938
939 // write the device file for the vlan interface.
940 vlanIntf->writeDeviceFile();
941
Gunnar Mills57d9c502018-09-14 14:42:34 -0500942 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700943
944 writeConfigurationFile();
945 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700946
947 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530948}
Ratan Gupta2b106532017-07-25 16:05:02 +0530949
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700950bool EthernetInterface::getIPv6AcceptRAFromConf()
951{
952 fs::path confPath = manager.getConfDir();
953
954 std::string fileName = systemd::config::networkFilePrefix +
955 interfaceName() + systemd::config::networkFileSuffix;
956 confPath /= fileName;
William A. Kennington III25511a12022-08-04 16:32:28 -0700957 config::Parser parser(confPath);
958 const auto& values = parser.getValues("Network", "IPv6AcceptRA");
959 if (values.empty())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700960 {
William A. Kennington III25511a12022-08-04 16:32:28 -0700961 log<level::NOTICE>("Unable to get the value for Network[IPv6AcceptRA]");
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700962 return false;
963 }
William A. Kennington III25511a12022-08-04 16:32:28 -0700964 return values.back() == "true";
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700965}
966
Ratan Gupta497c0c92017-08-22 19:15:59 +0530967ServerList EthernetInterface::getNTPServersFromConf()
968{
969 fs::path confPath = manager.getConfDir();
970
Gunnar Mills57d9c502018-09-14 14:42:34 -0500971 std::string fileName = systemd::config::networkFilePrefix +
972 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530973 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530974
Ratan Guptac27170a2017-11-22 15:44:42 +0530975 config::Parser parser(confPath.string());
William A. Kennington III25511a12022-08-04 16:32:28 -0700976 return parser.getValues("Network", "NTP");
Ratan Gupta497c0c92017-08-22 19:15:59 +0530977}
978
Patrick Williams6aef7692021-05-01 06:39:41 -0500979ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530980{
Patrick Williams6aef7692021-05-01 06:39:41 -0500981 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530982
983 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700984 manager.reloadConfigs();
985
Ratan Gupta497c0c92017-08-22 19:15:59 +0530986 return ntpServers;
987}
Ratan Gupta2b106532017-07-25 16:05:02 +0530988// Need to merge the below function with the code which writes the
989// config file during factory reset.
990// TODO openbmc/openbmc#1751
991
992void EthernetInterface::writeConfigurationFile()
993{
994 // write all the static ip address in the systemd-network conf file
995
996 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530997 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530998
999 // if there is vlan interafce then write the configuration file
1000 // for vlan also.
1001
Gunnar Mills57d9c502018-09-14 14:42:34 -05001002 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +05301003 {
1004 intf.second->writeConfigurationFile();
1005 }
1006
Ratan Gupta2b106532017-07-25 16:05:02 +05301007 fs::path confPath = manager.getConfDir();
1008
Gunnar Mills57d9c502018-09-14 14:42:34 -05001009 std::string fileName = systemd::config::networkFilePrefix +
1010 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +05301011 confPath /= fileName;
1012 std::fstream stream;
1013
1014 stream.open(confPath.c_str(), std::fstream::out);
1015 if (!stream.is_open())
1016 {
1017 log<level::ERR>("Unable to open the file",
1018 entry("FILE=%s", confPath.c_str()));
1019 elog<InternalFailure>();
1020 }
1021
1022 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001023 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301024 stream << "Name=" << interfaceName() << "\n";
1025
1026 auto addrs = getAddresses();
1027
William A. Kennington III15787212019-04-23 19:18:01 -07001028 // Write the link section
1029 stream << "[Link]\n";
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001030#ifdef PERSIST_MAC
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001031 auto mac = MacAddressIntf::macAddress();
William A. Kennington III15787212019-04-23 19:18:01 -07001032 if (!mac.empty())
1033 {
1034 stream << "MACAddress=" << mac << "\n";
1035 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001036#endif
William A. Kennington III15787212019-04-23 19:18:01 -07001037
Patrick Williams6aef7692021-05-01 06:39:41 -05001038 if (!EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -07001039 {
1040 stream << "Unmanaged=yes\n";
1041 }
1042
Ratan Gupta2b106532017-07-25 16:05:02 +05301043 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001044 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001045#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -05001046 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001047#else
1048 stream << "LinkLocalAddressing=no\n";
1049#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -07001050 stream << std::boolalpha
Patrick Williams6aef7692021-05-01 06:39:41 -05001051 << "IPv6AcceptRA=" << EthernetInterfaceIntf::ipv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301052
1053 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -05001054 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301055 {
1056 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -05001057 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301058 }
Ratan Gupta046b2a02019-09-20 15:49:51 +05301059 // Add the NTP server
Patrick Williams6aef7692021-05-01 06:39:41 -05001060 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301061 {
1062 stream << "NTP=" << ntp << "\n";
1063 }
1064
1065 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +05301066 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301067 {
1068 stream << "DNS=" << dns << "\n";
1069 }
1070
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001071 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -08001072 stream << "DHCP="s +
Patrick Williams6aef7692021-05-01 06:39:41 -05001073 mapDHCPToSystemd[EthernetInterfaceIntf::dhcpEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001074
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001075 stream << "[IPv6AcceptRA]\n";
1076 stream << "DHCPv6Client=";
1077 stream << (dhcpIsEnabled(IP::Protocol::IPv6) ? "true" : "false");
Johnathan Manteyb353ba02021-12-09 12:27:32 -08001078 stream << "\n";
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001079
Johnathan Mantey817012a2020-01-30 15:07:39 -08001080 // Static IP addresses
1081 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +05301082 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001083 if (originIsManuallyAssigned(addr.second->origin()) &&
1084 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001085 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001086 // Process all static addresses
1087 std::string address = addr.second->address() + "/" +
1088 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +05301089
Johnathan Mantey817012a2020-01-30 15:07:39 -08001090 // build the address entries. Do not use [Network] shortcuts to
1091 // insert address entries.
1092 stream << "[Address]\n";
1093 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001094 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001095 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001096
Lei YUcb2d4082021-08-12 15:26:49 +08001097 if (!dhcpIsEnabled(IP::Protocol::IPv4))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001098 {
Lei YUcb2d4082021-08-12 15:26:49 +08001099 auto gateway = EthernetInterfaceIntf::defaultGateway();
1100 if (!gateway.empty())
1101 {
1102 stream << "[Route]\n";
1103 stream << "Gateway=" << gateway << "\n";
1104 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001105 }
1106
Lei YUcb2d4082021-08-12 15:26:49 +08001107 if (!dhcpIsEnabled(IP::Protocol::IPv6))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001108 {
Lei YUcb2d4082021-08-12 15:26:49 +08001109 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1110 if (!gateway6.empty())
1111 {
1112 stream << "[Route]\n";
1113 stream << "Gateway=" << gateway6 << "\n";
1114 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001115 }
1116
William A. Kennington III08505792019-01-30 16:00:04 -08001117 // Write the neighbor sections
1118 for (const auto& neighbor : staticNeighbors)
1119 {
1120 stream << "[Neighbor]"
1121 << "\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001122 stream << "Address=" << neighbor.second->ipAddress() << "\n";
1123 stream << "MACAddress=" << neighbor.second->macAddress() << "\n";
William A. Kennington III08505792019-01-30 16:00:04 -08001124 }
1125
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001126 // Write the dhcp section irrespective of whether DHCP is enabled or not
1127 writeDHCPSection(stream);
1128
Ratan Gupta2b106532017-07-25 16:05:02 +05301129 stream.close();
William A. Kennington IIIf8b3fc32022-08-22 15:16:48 -07001130 auto msg = fmt::format("Wrote networkd file: {}", confPath.native());
1131 log<level::INFO>(msg.c_str(), entry("FILE=%s", confPath.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +05301132}
1133
1134void EthernetInterface::writeDHCPSection(std::fstream& stream)
1135{
1136 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301137 // write the dhcp section
1138 stream << "[DHCP]\n";
1139
1140 // Hardcoding the client identifier to mac, to address below issue
1141 // https://github.com/openbmc/openbmc/issues/1280
1142 stream << "ClientIdentifier=mac\n";
1143 if (manager.getDHCPConf())
1144 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001145 auto value = manager.getDHCPConf()->dnsEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301146 stream << "UseDNS="s + value + "\n";
sunharisdd1e5922022-03-31 01:49:21 -05001147 stream << "UseDomains="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301148
Patrick Williams6aef7692021-05-01 06:39:41 -05001149 value = manager.getDHCPConf()->ntpEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301150 stream << "UseNTP="s + value + "\n";
1151
1152 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1153 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001154
1155 value =
1156 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1157 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301158 }
1159}
1160
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001161std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301162{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001163#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001164 ether_addr newMAC;
1165 try
1166 {
1167 newMAC = mac_address::fromString(value);
1168 }
Patrick Williams5758db32021-10-06 12:29:22 -05001169 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001170 {
1171 log<level::ERR>("MACAddress is not valid.",
1172 entry("MAC=%s", value.c_str()));
1173 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1174 Argument::ARGUMENT_VALUE(value.c_str()));
1175 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001176 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301177 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001178 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001179 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001180 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1181 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301182 }
1183
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001184 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001185 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001186
William A. Kennington III1137a972019-04-20 20:49:58 -07001187 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001188 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001189 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301190 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001191 // Update everything that depends on the MAC value
1192 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301193 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001194 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301195 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001196 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301197
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001198 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001199 manager.addReloadPreHook([interface]() {
1200 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III5dad2aa2022-01-21 16:00:17 -08001201 setNICAdminState(interface.c_str(), false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001202 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001203 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301204 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001205
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001206#ifdef HAVE_UBOOT_ENV
1207 // Ensure that the valid address is stored in the u-boot-env
1208 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1209 if (envVar)
1210 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001211 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1212 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1213 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1214 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001215 }
1216#endif // HAVE_UBOOT_ENV
1217
William A. Kennington III1137a972019-04-20 20:49:58 -07001218 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001219#else
1220 elog<NotAllowed>(
1221 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1222#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301223}
1224
Ratan Guptae9c9b812017-09-22 17:15:37 +05301225void EthernetInterface::deleteAll()
1226{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301227 // clear all the ip on the interface
1228 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001229
1230 writeConfigurationFile();
1231 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301232}
1233
Ravi Tejaa5a09442020-07-17 00:57:33 -05001234std::string EthernetInterface::defaultGateway(std::string gateway)
1235{
1236 auto gw = EthernetInterfaceIntf::defaultGateway();
1237 if (gw == gateway)
1238 {
1239 return gw;
1240 }
1241
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001242 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001243 {
1244 log<level::ERR>("Not a valid v4 Gateway",
1245 entry("GATEWAY=%s", gateway.c_str()));
1246 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1247 Argument::ARGUMENT_VALUE(gateway.c_str()));
1248 }
1249 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001250
1251 writeConfigurationFile();
1252 manager.reloadConfigs();
1253
Ravi Tejaa5a09442020-07-17 00:57:33 -05001254 return gw;
1255}
1256
1257std::string EthernetInterface::defaultGateway6(std::string gateway)
1258{
1259 auto gw = EthernetInterfaceIntf::defaultGateway6();
1260 if (gw == gateway)
1261 {
1262 return gw;
1263 }
1264
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001265 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001266 {
1267 log<level::ERR>("Not a valid v6 Gateway",
1268 entry("GATEWAY=%s", gateway.c_str()));
1269 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1270 Argument::ARGUMENT_VALUE(gateway.c_str()));
1271 }
1272 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001273
1274 writeConfigurationFile();
1275 manager.reloadConfigs();
1276
Ravi Tejaa5a09442020-07-17 00:57:33 -05001277 return gw;
1278}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001279} // namespace network
1280} // namespace phosphor