blob: 90c987d7e08c70831dfa1c5e93eb5c62f60835d6 [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 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 Edaacd6dd52019-10-15 15:00:51 +0530765ServerList EthernetInterface::staticNameServers(ServerList value)
766{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530767 for (const auto& nameserverip : value)
768 {
769 if (!isValidIP(AF_INET, nameserverip) &&
770 !isValidIP(AF_INET6, nameserverip))
771 {
772 log<level::ERR>("Not a valid IP address"),
773 entry("ADDRESS=%s", nameserverip.c_str());
774 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530775 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530776 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
777 }
778 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530779 try
780 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530781 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700782
Ratan Gupta6dec3902017-08-20 15:28:12 +0530783 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700784 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530785 }
Patrick Williams5758db32021-10-06 12:29:22 -0500786 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530787 {
788 log<level::ERR>("Exception processing DNS entries");
789 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530790 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530791}
792
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530793void EthernetInterface::loadNameServers()
794{
795 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
796 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
797}
798
799ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec3902017-08-20 15:28:12 +0530800{
801 fs::path confPath = manager.getConfDir();
802
803 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500804 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530805 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530806 config::Parser parser(confPath.string());
William A. Kennington III25511a12022-08-04 16:32:28 -0700807 return parser.getValues("Network", "DNS");
Ratan Gupta6dec3902017-08-20 15:28:12 +0530808}
809
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530810ServerList EthernetInterface::getNameServerFromResolvd()
811{
812 ServerList servers;
813 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
814
815 /*
816 The DNS property under org.freedesktop.resolve1.Link interface contains
817 an array containing all DNS servers currently used by resolved. It
818 contains similar information as the DNS server data written to
819 /run/systemd/resolve/resolv.conf.
820
821 Each structure in the array consists of a numeric network interface index,
822 an address family, and a byte array containing the DNS server address
823 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
824 The array contains DNS servers configured system-wide, including those
825 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
826 /etc/systemd/resolved.conf, as well as per-interface DNS server
827 information either retrieved from systemd-networkd or configured by
828 external software via SetLinkDNS().
829 */
830
831 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
832 std::variant<type> name; // Variable to capture the DNS property
833 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
834 PROPERTY_INTERFACE, METHOD_GET);
835
836 method.append(RESOLVED_INTERFACE, "DNS");
837 auto reply = bus.call(method);
838
839 try
840 {
841 reply.read(name);
842 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500843 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530844 {
845 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
846 }
847 auto tupleVector = std::get_if<type>(&name);
848 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
849 {
Alexander Filippov983da552021-02-08 15:26:54 +0300850 int addressFamily = std::get<0>(*i);
851 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
852
853 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530854 {
Alexander Filippov983da552021-02-08 15:26:54 +0300855 case AF_INET:
856 if (ipaddress.size() == sizeof(struct in_addr))
857 {
858 servers.push_back(toString(
859 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
860 }
861 else
862 {
863 log<level::ERR>(
864 "Invalid data recived from Systemd-Resolved");
865 }
866 break;
867
868 case AF_INET6:
869 if (ipaddress.size() == sizeof(struct in6_addr))
870 {
871 servers.push_back(toString(
872 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
873 }
874 else
875 {
876 log<level::ERR>(
877 "Invalid data recived from Systemd-Resolved");
878 }
879 break;
880
881 default:
882 log<level::ERR>(
883 "Unsupported address family in DNS from Systemd-Resolved");
884 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530885 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530886 }
887 return servers;
888}
889
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530890void EthernetInterface::loadVLAN(VlanId id)
891{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500892 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530893 std::string path = objPath;
894 path += "_" + std::to_string(id);
895
Johnathan Mantey817012a2020-01-30 15:07:39 -0800896 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500897 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530898 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500899 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nicEnabled(), id,
Johnathan Mantey817012a2020-01-30 15:07:39 -0800900 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530901
Gunnar Mills57d9c502018-09-14 14:42:34 -0500902 // Fetch the ip address from the system
903 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530904 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800905 vlanIntf->createStaticNeighborObjects();
Jiaqing Zhaocc5a6702021-12-31 14:58:55 +0800906 vlanIntf->loadNameServers();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530907
908 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
909 std::move(vlanIntf));
910}
911
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700912ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530913{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500914 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800915
916 if (this->vlanInterfaces.count(vlanInterfaceName))
917 {
918 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
919 elog<InvalidArgument>(
920 Argument::ARGUMENT_NAME("VLANId"),
921 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
922 }
923
Ratan Gupta5978dd12017-07-25 13:47:13 +0530924 std::string path = objPath;
925 path += "_" + std::to_string(id);
926
Patrick Williams6aef7692021-05-01 06:39:41 -0500927 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530928 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530929 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800930 bus, path.c_str(), EthernetInterface::DHCPConf::none,
Patrick Williams6aef7692021-05-01 06:39:41 -0500931 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530932
933 // write the device file for the vlan interface.
934 vlanIntf->writeDeviceFile();
935
Gunnar Mills57d9c502018-09-14 14:42:34 -0500936 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700937
938 writeConfigurationFile();
939 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700940
941 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530942}
Ratan Gupta2b106532017-07-25 16:05:02 +0530943
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700944bool EthernetInterface::getIPv6AcceptRAFromConf()
945{
946 fs::path confPath = manager.getConfDir();
947
948 std::string fileName = systemd::config::networkFilePrefix +
949 interfaceName() + systemd::config::networkFileSuffix;
950 confPath /= fileName;
William A. Kennington III25511a12022-08-04 16:32:28 -0700951 config::Parser parser(confPath);
952 const auto& values = parser.getValues("Network", "IPv6AcceptRA");
953 if (values.empty())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700954 {
William A. Kennington III25511a12022-08-04 16:32:28 -0700955 log<level::NOTICE>("Unable to get the value for Network[IPv6AcceptRA]");
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700956 return false;
957 }
William A. Kennington III25511a12022-08-04 16:32:28 -0700958 return values.back() == "true";
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700959}
960
Ratan Gupta497c0c92017-08-22 19:15:59 +0530961ServerList EthernetInterface::getNTPServersFromConf()
962{
963 fs::path confPath = manager.getConfDir();
964
Gunnar Mills57d9c502018-09-14 14:42:34 -0500965 std::string fileName = systemd::config::networkFilePrefix +
966 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530967 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530968
Ratan Guptac27170a2017-11-22 15:44:42 +0530969 config::Parser parser(confPath.string());
William A. Kennington III25511a12022-08-04 16:32:28 -0700970 return parser.getValues("Network", "NTP");
Ratan Gupta497c0c92017-08-22 19:15:59 +0530971}
972
Patrick Williams6aef7692021-05-01 06:39:41 -0500973ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530974{
Patrick Williams6aef7692021-05-01 06:39:41 -0500975 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530976
977 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700978 manager.reloadConfigs();
979
Ratan Gupta497c0c92017-08-22 19:15:59 +0530980 return ntpServers;
981}
Ratan Gupta2b106532017-07-25 16:05:02 +0530982// Need to merge the below function with the code which writes the
983// config file during factory reset.
984// TODO openbmc/openbmc#1751
985
986void EthernetInterface::writeConfigurationFile()
987{
988 // write all the static ip address in the systemd-network conf file
989
990 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530991 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530992
993 // if there is vlan interafce then write the configuration file
994 // for vlan also.
995
Gunnar Mills57d9c502018-09-14 14:42:34 -0500996 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530997 {
998 intf.second->writeConfigurationFile();
999 }
1000
Ratan Gupta2b106532017-07-25 16:05:02 +05301001 fs::path confPath = manager.getConfDir();
1002
Gunnar Mills57d9c502018-09-14 14:42:34 -05001003 std::string fileName = systemd::config::networkFilePrefix +
1004 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +05301005 confPath /= fileName;
1006 std::fstream stream;
1007
1008 stream.open(confPath.c_str(), std::fstream::out);
1009 if (!stream.is_open())
1010 {
1011 log<level::ERR>("Unable to open the file",
1012 entry("FILE=%s", confPath.c_str()));
1013 elog<InternalFailure>();
1014 }
1015
1016 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001017 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301018 stream << "Name=" << interfaceName() << "\n";
1019
1020 auto addrs = getAddresses();
1021
William A. Kennington III15787212019-04-23 19:18:01 -07001022 // Write the link section
1023 stream << "[Link]\n";
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001024#ifdef PERSIST_MAC
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001025 auto mac = MacAddressIntf::macAddress();
William A. Kennington III15787212019-04-23 19:18:01 -07001026 if (!mac.empty())
1027 {
1028 stream << "MACAddress=" << mac << "\n";
1029 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001030#endif
William A. Kennington III15787212019-04-23 19:18:01 -07001031
Patrick Williams6aef7692021-05-01 06:39:41 -05001032 if (!EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -07001033 {
1034 stream << "Unmanaged=yes\n";
1035 }
1036
Ratan Gupta2b106532017-07-25 16:05:02 +05301037 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001038 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001039#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -05001040 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001041#else
1042 stream << "LinkLocalAddressing=no\n";
1043#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -07001044 stream << std::boolalpha
Patrick Williams6aef7692021-05-01 06:39:41 -05001045 << "IPv6AcceptRA=" << EthernetInterfaceIntf::ipv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301046
1047 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -05001048 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301049 {
1050 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -05001051 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301052 }
Ratan Gupta046b2a02019-09-20 15:49:51 +05301053 // Add the NTP server
Patrick Williams6aef7692021-05-01 06:39:41 -05001054 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301055 {
1056 stream << "NTP=" << ntp << "\n";
1057 }
1058
1059 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +05301060 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301061 {
1062 stream << "DNS=" << dns << "\n";
1063 }
1064
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001065 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -08001066 stream << "DHCP="s +
Patrick Williams6aef7692021-05-01 06:39:41 -05001067 mapDHCPToSystemd[EthernetInterfaceIntf::dhcpEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001068
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001069 stream << "[IPv6AcceptRA]\n";
1070 stream << "DHCPv6Client=";
1071 stream << (dhcpIsEnabled(IP::Protocol::IPv6) ? "true" : "false");
Johnathan Manteyb353ba02021-12-09 12:27:32 -08001072 stream << "\n";
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001073
Johnathan Mantey817012a2020-01-30 15:07:39 -08001074 // Static IP addresses
1075 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +05301076 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001077 if (originIsManuallyAssigned(addr.second->origin()) &&
1078 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001079 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001080 // Process all static addresses
1081 std::string address = addr.second->address() + "/" +
1082 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +05301083
Johnathan Mantey817012a2020-01-30 15:07:39 -08001084 // build the address entries. Do not use [Network] shortcuts to
1085 // insert address entries.
1086 stream << "[Address]\n";
1087 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001088 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001089 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001090
Lei YUcb2d4082021-08-12 15:26:49 +08001091 if (!dhcpIsEnabled(IP::Protocol::IPv4))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001092 {
Lei YUcb2d4082021-08-12 15:26:49 +08001093 auto gateway = EthernetInterfaceIntf::defaultGateway();
1094 if (!gateway.empty())
1095 {
1096 stream << "[Route]\n";
1097 stream << "Gateway=" << gateway << "\n";
1098 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001099 }
1100
Lei YUcb2d4082021-08-12 15:26:49 +08001101 if (!dhcpIsEnabled(IP::Protocol::IPv6))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001102 {
Lei YUcb2d4082021-08-12 15:26:49 +08001103 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1104 if (!gateway6.empty())
1105 {
1106 stream << "[Route]\n";
1107 stream << "Gateway=" << gateway6 << "\n";
1108 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001109 }
1110
William A. Kennington III08505792019-01-30 16:00:04 -08001111 // Write the neighbor sections
1112 for (const auto& neighbor : staticNeighbors)
1113 {
1114 stream << "[Neighbor]"
1115 << "\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001116 stream << "Address=" << neighbor.second->ipAddress() << "\n";
1117 stream << "MACAddress=" << neighbor.second->macAddress() << "\n";
William A. Kennington III08505792019-01-30 16:00:04 -08001118 }
1119
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001120 // Write the dhcp section irrespective of whether DHCP is enabled or not
1121 writeDHCPSection(stream);
1122
Ratan Gupta2b106532017-07-25 16:05:02 +05301123 stream.close();
William A. Kennington IIIf8b3fc32022-08-22 15:16:48 -07001124 auto msg = fmt::format("Wrote networkd file: {}", confPath.native());
1125 log<level::INFO>(msg.c_str(), entry("FILE=%s", confPath.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +05301126}
1127
1128void EthernetInterface::writeDHCPSection(std::fstream& stream)
1129{
1130 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301131 // write the dhcp section
1132 stream << "[DHCP]\n";
1133
1134 // Hardcoding the client identifier to mac, to address below issue
1135 // https://github.com/openbmc/openbmc/issues/1280
1136 stream << "ClientIdentifier=mac\n";
1137 if (manager.getDHCPConf())
1138 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001139 auto value = manager.getDHCPConf()->dnsEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301140 stream << "UseDNS="s + value + "\n";
sunharisdd1e5922022-03-31 01:49:21 -05001141 stream << "UseDomains="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301142
Patrick Williams6aef7692021-05-01 06:39:41 -05001143 value = manager.getDHCPConf()->ntpEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301144 stream << "UseNTP="s + value + "\n";
1145
1146 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1147 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001148
1149 value =
1150 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1151 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301152 }
1153}
1154
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001155std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301156{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001157#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001158 ether_addr newMAC;
1159 try
1160 {
1161 newMAC = mac_address::fromString(value);
1162 }
Patrick Williams5758db32021-10-06 12:29:22 -05001163 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001164 {
1165 log<level::ERR>("MACAddress is not valid.",
1166 entry("MAC=%s", value.c_str()));
1167 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1168 Argument::ARGUMENT_VALUE(value.c_str()));
1169 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001170 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301171 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001172 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001173 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001174 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1175 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301176 }
1177
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001178 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001179 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001180
William A. Kennington III1137a972019-04-20 20:49:58 -07001181 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001182 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001183 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301184 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001185 // Update everything that depends on the MAC value
1186 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301187 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001188 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301189 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001190 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301191
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001192 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001193 manager.addReloadPreHook([interface]() {
1194 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III5dad2aa2022-01-21 16:00:17 -08001195 setNICAdminState(interface.c_str(), false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001196 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001197 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301198 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001199
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001200#ifdef HAVE_UBOOT_ENV
1201 // Ensure that the valid address is stored in the u-boot-env
1202 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1203 if (envVar)
1204 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001205 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1206 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1207 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1208 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001209 }
1210#endif // HAVE_UBOOT_ENV
1211
William A. Kennington III1137a972019-04-20 20:49:58 -07001212 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001213#else
1214 elog<NotAllowed>(
1215 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1216#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301217}
1218
Ratan Guptae9c9b812017-09-22 17:15:37 +05301219void EthernetInterface::deleteAll()
1220{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301221 // clear all the ip on the interface
1222 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001223
1224 writeConfigurationFile();
1225 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301226}
1227
Ravi Tejaa5a09442020-07-17 00:57:33 -05001228std::string EthernetInterface::defaultGateway(std::string gateway)
1229{
1230 auto gw = EthernetInterfaceIntf::defaultGateway();
1231 if (gw == gateway)
1232 {
1233 return gw;
1234 }
1235
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001236 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001237 {
1238 log<level::ERR>("Not a valid v4 Gateway",
1239 entry("GATEWAY=%s", gateway.c_str()));
1240 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1241 Argument::ARGUMENT_VALUE(gateway.c_str()));
1242 }
1243 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001244
1245 writeConfigurationFile();
1246 manager.reloadConfigs();
1247
Ravi Tejaa5a09442020-07-17 00:57:33 -05001248 return gw;
1249}
1250
1251std::string EthernetInterface::defaultGateway6(std::string gateway)
1252{
1253 auto gw = EthernetInterfaceIntf::defaultGateway6();
1254 if (gw == gateway)
1255 {
1256 return gw;
1257 }
1258
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001259 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001260 {
1261 log<level::ERR>("Not a valid v6 Gateway",
1262 entry("GATEWAY=%s", gateway.c_str()));
1263 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1264 Argument::ARGUMENT_VALUE(gateway.c_str()));
1265 }
1266 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001267
1268 writeConfigurationFile();
1269 manager.reloadConfigs();
1270
Ravi Tejaa5a09442020-07-17 00:57:33 -05001271 return gw;
1272}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001273} // namespace network
1274} // namespace phosphor