blob: c2ded8cef0f75f7b79e26a64723c8f24a188ba7b [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"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05306#include "network_manager.hpp"
William A. Kennington III95530ec2022-08-19 01:44:39 -07007#include "util.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05308
Ratan Gupta82549cc2017-04-21 08:45:23 +05309#include <arpa/inet.h>
William A. Kennington IIIa520a392022-08-08 12:17:34 -070010#include <fmt/compile.h>
William A. Kennington III26275a32021-07-13 20:32:42 -070011#include <fmt/format.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053012#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070013#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053015#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053016
Ratan Gupta82549cc2017-04-21 08:45:23 +053017#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053018#include <filesystem>
Patrick Venture189d44e2018-07-09 12:30:59 -070019#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/log.hpp>
William A. Kennington III26275a32021-07-13 20:32:42 -070021#include <sdbusplus/bus/match.hpp>
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080022#include <stdplus/fd/create.hpp>
William A. Kennington III12beaad2020-06-13 19:30:41 -070023#include <stdplus/raw.hpp>
William A. Kennington III69f45542022-09-24 23:28:14 -070024#include <stdplus/zstring.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053025#include <string>
William A. Kennington III26275a32021-07-13 20:32:42 -070026#include <unordered_map>
27#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070028#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053029
Ratan Gupta91a99cc2017-04-14 16:32:09 +053030namespace phosphor
31{
32namespace network
33{
34
35using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053036using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053037using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
38using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050039using Argument = xyz::openbmc_project::Common::InvalidArgument;
William A. Kennington III991a8e82022-10-11 15:02:47 -070040using std::literals::string_view_literals::operator""sv;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053041constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
42constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
43constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
44constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
45constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053046
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080047static stdplus::Fd& getIFSock()
48{
49 using namespace stdplus::fd;
50 static auto fd =
51 socket(SocketDomain::INet, SocketType::Datagram, SocketProto::IP);
52 return fd;
53}
54
Patrick Williamsc38b0712022-07-22 19:26:54 -050055EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus,
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -070056 stdplus::zstring_view objPath,
William A. Kennington IIIa520a392022-08-08 12:17:34 -070057 const config::Parser& config,
William A. Kennington III0caf2212022-08-18 18:15:51 -070058 Manager& parent, bool emitSignal,
William A. Kennington III26275a32021-07-13 20:32:42 -070059 std::optional<bool> enabled) :
Patrick Williams166b9592022-03-30 16:09:16 -050060 Ifaces(bus, objPath.c_str(),
61 emitSignal ? Ifaces::action::defer_emit
62 : Ifaces::action::emit_no_signals),
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -070063 bus(bus), manager(parent), objPath(objPath.c_str())
Ratan Gupta91a99cc2017-04-14 16:32:09 +053064{
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -070065 auto intfName = std::string(objPath.substr(objPath.rfind('/') + 1));
Ratan Gupta5978dd12017-07-25 13:47:13 +053066 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053067 interfaceName(intfName);
William A. Kennington III8060c0d2022-08-18 19:19:34 -070068 auto dhcpVal = getDHCPValue(config);
69 EthernetInterfaceIntf::dhcp4(dhcpVal.v4);
70 EthernetInterfaceIntf::dhcp6(dhcpVal.v6);
William A. Kennington IIIa520a392022-08-08 12:17:34 -070071 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRA(config));
William A. Kennington III26275a32021-07-13 20:32:42 -070072 EthernetInterfaceIntf::nicEnabled(enabled ? *enabled : queryNicEnabled());
William A. Kennington IIIe0564842021-10-23 16:02:22 -070073 const auto& gatewayList = manager.getRouteTable().getDefaultGateway();
74 const auto& gateway6List = manager.getRouteTable().getDefaultGateway6();
Ravi Tejaa5a09442020-07-17 00:57:33 -050075 std::string defaultGateway;
76 std::string defaultGateway6;
77
William A. Kennington IIIe0564842021-10-23 16:02:22 -070078 for (const auto& gateway : gatewayList)
Ravi Tejaa5a09442020-07-17 00:57:33 -050079 {
80 if (gateway.first == intfName)
81 {
82 defaultGateway = gateway.second;
83 break;
84 }
85 }
86
William A. Kennington IIIe0564842021-10-23 16:02:22 -070087 for (const auto& gateway6 : gateway6List)
Ravi Tejaa5a09442020-07-17 00:57:33 -050088 {
89 if (gateway6.first == intfName)
90 {
91 defaultGateway6 = gateway6.second;
92 break;
93 }
94 }
95
96 EthernetInterfaceIntf::defaultGateway(defaultGateway);
97 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
Ratan Gupta99801ce2020-01-09 18:37:16 +053098 // Don't get the mac address from the system as the mac address
99 // would be same as parent interface.
100 if (intfName.find(".") == std::string::npos)
101 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500102 MacAddressIntf::macAddress(getMACAddress(intfName));
Ratan Gupta99801ce2020-01-09 18:37:16 +0530103 }
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700104 EthernetInterfaceIntf::ntpServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700105 config.map.getValueStrings("Network", "NTP"));
Ratan Gupta613a0122020-04-24 15:18:53 +0530106
107 EthernetInterfaceIntf::linkUp(linkUp());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530108 EthernetInterfaceIntf::mtu(mtu());
Ratan Gupta613a0122020-04-24 15:18:53 +0530109
Johnathan Manteycb42fe22019-08-01 13:35:29 -0700110 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
Johnathan Manteycb42fe22019-08-01 13:35:29 -0700111 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
112 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530113
Ratan Gupta29b0e432017-05-25 12:51:40 +0530114 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530115 if (emitSignal)
116 {
117 this->emit_object_added();
118 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530119}
120
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700121static IP::Protocol getProtocol(const InAddrAny& addr)
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800122{
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700123 if (std::holds_alternative<in_addr>(addr))
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800124 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700125 return IP::Protocol::IPv4;
126 }
127 else if (std::holds_alternative<in6_addr>(addr))
128 {
129 return IP::Protocol::IPv6;
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800130 }
131
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700132 throw std::runtime_error("Invalid addr type");
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800133}
134
William A. Kennington III24957b92021-12-03 13:59:19 -0800135bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800136{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700137 switch (family)
138 {
139 case IP::Protocol::IPv6:
140 return dhcp6();
141 case IP::Protocol::IPv4:
142 return dhcp4();
143 }
144 throw std::logic_error("Unreachable");
Johnathan Mantey817012a2020-01-30 15:07:39 -0800145}
146
Johnathan Mantey817012a2020-01-30 15:07:39 -0800147bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
148{
149 return (
150#ifdef LINK_LOCAL_AUTOCONFIGURATION
151 (origin == IP::AddressOrigin::Static)
152#else
153 (origin == IP::AddressOrigin::Static ||
154 origin == IP::AddressOrigin::LinkLocal)
155#endif
156
157 );
158}
159
Ratan Gupta87c13982017-06-15 09:27:27 +0530160void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530161{
Ratan Gupta87c13982017-06-15 09:27:27 +0530162 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530163
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700164 AddressFilter filter;
165 filter.interface = ifIndex();
166 auto currentAddrs = getCurrentAddresses(filter);
167 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530168 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700169 if (addr.flags & IFA_F_DEPRECATED)
170 {
171 continue;
172 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700173 auto address = toString(addr.address);
174 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800175 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800176 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530177 {
178 origin = IP::AddressOrigin::DHCP;
179 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700180 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530181 {
182 origin = IP::AddressOrigin::LinkLocal;
183 }
Ratan Gupta82549cc2017-04-21 08:45:23 +0530184
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700185 auto ipAddressObjectPath =
186 generateObjectPath(addressType, address, addr.prefix, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530187
Lei YU7233c582021-04-08 14:39:43 +0800188 this->addrs.insert_or_assign(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700189 address, std::make_unique<IPAddress>(bus, ipAddressObjectPath,
190 *this, addressType, address,
191 origin, addr.prefix));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530192 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530193}
194
William A. Kennington III08505792019-01-30 16:00:04 -0800195void EthernetInterface::createStaticNeighborObjects()
196{
197 staticNeighbors.clear();
198
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700199 NeighborFilter filter;
200 filter.interface = ifIndex();
201 filter.state = NUD_PERMANENT;
202 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800203 for (const auto& neighbor : neighbors)
204 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700205 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800206 {
207 continue;
208 }
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700209 auto ip = toString(neighbor.address);
210 auto mac = mac_address::toString(*neighbor.mac);
211 auto objectPath = generateStaticNeighborObjectPath(ip, mac);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700212 staticNeighbors.emplace(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700213 ip, std::make_unique<Neighbor>(bus, objectPath, *this, ip, mac,
214 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800215 }
216}
217
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700218unsigned EthernetInterface::ifIndex() const
219{
220 unsigned idx = if_nametoindex(interfaceName().c_str());
221 if (idx == 0)
222 {
223 throw std::system_error(errno, std::generic_category(),
224 "if_nametoindex");
225 }
226 return idx;
227}
228
Patrick Williams6aef7692021-05-01 06:39:41 -0500229ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700230 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530231{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800232 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530233 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700234 log<level::INFO>("DHCP enabled on the interface, disabling"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500235 entry("INTERFACE=%s", interfaceName().c_str());
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700236 switch (protType)
237 {
238 case IP::Protocol::IPv4:
239 dhcp4(false);
240 break;
241 case IP::Protocol::IPv6:
242 dhcp6(false);
243 break;
244 }
Ravi Teja07450442022-07-07 04:30:57 -0500245 // Delete the IP address object and that reloads the networkd
246 // to allow the same IP address to be set as Static IP
247 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500248 }
249
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500250 IP::AddressOrigin origin = IP::AddressOrigin::Static;
251
252 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
253
254 if (!isValidIP(addressFamily, ipaddress))
255 {
256 log<level::ERR>("Not a valid IP address"),
257 entry("ADDRESS=%s", ipaddress.c_str());
258 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
259 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
260 }
261
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500262 if (!isValidPrefix(addressFamily, prefixLength))
263 {
264 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700265 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500266 elog<InvalidArgument>(
267 Argument::ARGUMENT_NAME("prefixLength"),
268 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530269 }
270
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700271 auto objectPath =
272 generateObjectPath(protType, ipaddress, prefixLength, origin);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700273 this->addrs.insert_or_assign(
274 ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700275 std::make_unique<IPAddress>(bus, objectPath, *this, protType, ipaddress,
276 origin, prefixLength));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530277
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700278 writeConfigurationFile();
279 manager.reloadConfigs();
280
raviteja-bce379562019-03-28 05:59:36 -0500281 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530282}
283
Patrick Williams6aef7692021-05-01 06:39:41 -0500284ObjectPath EthernetInterface::neighbor(std::string ipAddress,
285 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800286{
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700287 if (!isValidIP(ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800288 {
289 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500290 entry("ADDRESS=%s", ipAddress.c_str()));
291 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
292 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800293 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500294 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800295 {
296 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500297 entry("MACADDRESS=%s", ipAddress.c_str()));
298 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
299 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800300 }
301
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700302 auto objectPath = generateStaticNeighborObjectPath(ipAddress, macAddress);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700303 staticNeighbors.emplace(
304 ipAddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700305 std::make_unique<Neighbor>(bus, objectPath, *this, ipAddress,
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700306 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700307
308 writeConfigurationFile();
309 manager.reloadConfigs();
310
William A. Kennington III08505792019-01-30 16:00:04 -0800311 return objectPath;
312}
313
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530314InterfaceInfo EthernetInterface::getInterfaceInfo() const
315{
William A. Kennington III05368f12021-05-13 18:40:47 -0700316 ifreq ifr = {};
317 ethtool_cmd edata = {};
318 LinkSpeed speed = {};
319 Autoneg autoneg = {};
320 DuplexMode duplex = {};
321 LinkUp linkState = {};
322 NICEnabled enabled = {};
Tejas Patil2c0fc562021-08-03 19:13:46 +0530323 MTU mtuSize = {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530324
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800325 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
326 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530327
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800328 edata.cmd = ETHTOOL_GSET;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800329 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800330 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800331 getIFSock().ioctl(SIOCETHTOOL, &ifr);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530332 speed = edata.speed;
333 duplex = edata.duplex;
334 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530335 }
William A. Kennington III96221802022-10-11 16:15:55 -0700336 catch (const std::system_error& e)
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800337 {
William A. Kennington III96221802022-10-11 16:15:55 -0700338 if (e.code() == std::errc::operation_not_supported)
339 {
340 auto msg = fmt::format("ETHTOOL not supported on {}", ifr.ifr_name);
341 log<level::NOTICE>(msg.c_str(),
342 entry("INTERFACE=%s", ifr.ifr_name));
343 }
344 else
345 {
346 auto msg =
347 fmt::format("ETHTOOL failed on {}: {}", ifr.ifr_name, e.what());
348 log<level::ERR>(msg.c_str(), entry("INTERFACE=%s", ifr.ifr_name));
349 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800350 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800351
William A. Kennington III96203312021-05-07 12:50:41 -0700352 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800353 linkState = linkUp();
Tejas Patil2c0fc562021-08-03 19:13:46 +0530354 mtuSize = mtu();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800355
Tejas Patil2c0fc562021-08-03 19:13:46 +0530356 return std::make_tuple(speed, duplex, autoneg, linkState, enabled, mtuSize);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530357}
358
359/** @brief get the mac address of the interface.
360 * @return macaddress on success
361 */
362
Gunnar Mills57d9c502018-09-14 14:42:34 -0500363std::string
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700364 EthernetInterface::getMACAddress(stdplus::const_zstring interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530365{
Patrick Williams6aef7692021-05-01 06:39:41 -0500366 std::string activeMACAddr = MacAddressIntf::macAddress();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530367
William A. Kennington III05368f12021-05-13 18:40:47 -0700368 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800369 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800370 try
371 {
372 getIFSock().ioctl(SIOCGIFHWADDR, &ifr);
373 }
374 catch (const std::exception& e)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530375 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530376 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800377 entry("ERROR=%s", e.what()));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700378 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530379 }
William A. Kennington III7c4c9a92022-10-07 19:08:09 -0700380 return mac_address::toString(
381 stdplus::raw::refFrom<ether_addr>(ifr.ifr_hwaddr.sa_data));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530382}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530383
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700384void EthernetInterface::deleteObject(std::string_view ipaddress)
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530385{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530386 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530387 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530388 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530389 log<level::ERR>("DeleteObject:Unable to find the object.");
390 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530391 }
392 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700393
394 writeConfigurationFile();
395 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530396}
397
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700398void EthernetInterface::deleteStaticNeighborObject(std::string_view ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800399{
Patrick Williams6aef7692021-05-01 06:39:41 -0500400 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800401 if (it == staticNeighbors.end())
402 {
403 log<level::ERR>(
404 "DeleteStaticNeighborObject:Unable to find the object.");
405 return;
406 }
407 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700408
409 writeConfigurationFile();
410 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800411}
412
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700413void EthernetInterface::deleteVLANFromSystem(stdplus::zstring_view interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530414{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700415 const auto& confDir = manager.getConfDir();
416 auto networkFile = config::pathForIntfConf(confDir, interface);
417 auto deviceFile = config::pathForIntfDev(confDir, interface);
Ratan Guptabc886292017-07-25 18:29:57 +0530418
419 // delete the vlan network file
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700420 std::error_code ec;
William A. Kennington III95530ec2022-08-19 01:44:39 -0700421 std::filesystem::remove(networkFile, ec);
422 std::filesystem::remove(deviceFile, ec);
Ratan Guptabc886292017-07-25 18:29:57 +0530423
424 // TODO systemd doesn't delete the virtual network interface
425 // even after deleting all the related configuartion.
426 // https://github.com/systemd/systemd/issues/6600
427 try
428 {
429 deleteInterface(interface);
430 }
Patrick Williams5758db32021-10-06 12:29:22 -0500431 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530432 {
433 commit<InternalFailure>();
434 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530435}
436
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700437void EthernetInterface::deleteVLANObject(stdplus::zstring_view interface)
Ratan Guptae9c9b812017-09-22 17:15:37 +0530438{
439 auto it = vlanInterfaces.find(interface);
440 if (it == vlanInterfaces.end())
441 {
442 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500443 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530444 return;
445 }
446
447 deleteVLANFromSystem(interface);
448 // delete the interface
449 vlanInterfaces.erase(it);
450
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700451 writeConfigurationFile();
452 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530453}
454
Gunnar Mills57d9c502018-09-14 14:42:34 -0500455std::string EthernetInterface::generateObjectPath(
William A. Kennington III991a8e82022-10-11 15:02:47 -0700456 IP::Protocol addressType, std::string_view ipAddress, uint8_t prefixLength,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700457 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530458{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700459 std::string_view type;
460 switch (addressType)
461 {
462 case IP::Protocol::IPv4:
463 type = "ipv4"sv;
464 break;
465 case IP::Protocol::IPv6:
466 type = "ipv6"sv;
467 break;
468 }
469 return fmt::format(
470 FMT_COMPILE("{}/{}/{:08x}"), objPath, type,
471 static_cast<uint32_t>(hash_multi(
472 ipAddress, prefixLength,
473 static_cast<std::underlying_type_t<IP::AddressOrigin>>(origin))));
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530474}
475
William A. Kennington III08505792019-01-30 16:00:04 -0800476std::string EthernetInterface::generateStaticNeighborObjectPath(
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700477 std::string_view ipAddress, std::string_view macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800478{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700479 return fmt::format(
480 FMT_COMPILE("{}/static_neighbor/{:08x}"), objPath,
481 static_cast<uint32_t>(hash_multi(ipAddress, macAddress)));
William A. Kennington III08505792019-01-30 16:00:04 -0800482}
483
Patrick Williams6aef7692021-05-01 06:39:41 -0500484bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700485{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700486 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700487 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700488 writeConfigurationFile();
489 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700490 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700491 return value;
492}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700493
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700494bool EthernetInterface::dhcp4(bool value)
495{
496 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
497 {
498 writeConfigurationFile();
499 manager.reloadConfigs();
500 }
501 return value;
502}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700503
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700504bool EthernetInterface::dhcp6(bool value)
505{
506 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
507 {
508 writeConfigurationFile();
509 manager.reloadConfigs();
510 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700511 return value;
512}
513
Patrick Williams6aef7692021-05-01 06:39:41 -0500514EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530515{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700516 auto old4 = EthernetInterfaceIntf::dhcp4();
517 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
518 value == DHCPConf::v4v6stateless ||
519 value == DHCPConf::both);
520 auto old6 = EthernetInterfaceIntf::dhcp6();
521 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
522 value == DHCPConf::both);
523 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
524 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
525 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
526 value == DHCPConf::v6 || value == DHCPConf::both);
527
528 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530529 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700530 writeConfigurationFile();
531 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530532 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530533 return value;
534}
535
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700536EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
537{
538 if (dhcp6())
539 {
540 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
541 }
542 else if (dhcp4())
543 {
544 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
545 }
546 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
547}
548
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800549bool EthernetInterface::linkUp() const
550{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800551 bool value = EthernetInterfaceIntf::linkUp();
552
William A. Kennington III05368f12021-05-13 18:40:47 -0700553 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800554 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800555 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800556 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800557 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800558 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
559 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800560 catch (const std::exception& e)
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800561 {
562 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800563 entry("ERROR=%s", e.what()));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800564 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700565 return value;
566}
567
Tejas Patil2c0fc562021-08-03 19:13:46 +0530568size_t EthernetInterface::mtu() const
569{
Tejas Patil2c0fc562021-08-03 19:13:46 +0530570 size_t value = EthernetInterfaceIntf::mtu();
571
Tejas Patil2c0fc562021-08-03 19:13:46 +0530572 ifreq ifr = {};
573 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800574 try
Tejas Patil2c0fc562021-08-03 19:13:46 +0530575 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800576 getIFSock().ioctl(SIOCGIFMTU, &ifr);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530577 value = ifr.ifr_mtu;
578 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800579 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530580 {
581 log<level::ERR>("ioctl failed for SIOCGIFMTU:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800582 entry("ERROR=%s", e.what()));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530583 }
584 return value;
585}
586
587size_t EthernetInterface::mtu(size_t value)
588{
589 if (value == EthernetInterfaceIntf::mtu())
590 {
591 return value;
592 }
593 else if (value == 0)
594 {
595 return EthernetInterfaceIntf::mtu();
596 }
597
Tejas Patil2c0fc562021-08-03 19:13:46 +0530598 ifreq ifr = {};
599 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
600 ifr.ifr_mtu = value;
601
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800602 try
603 {
604 getIFSock().ioctl(SIOCSIFMTU, &ifr);
605 }
606 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530607 {
608 log<level::ERR>("ioctl failed for SIOCSIFMTU:",
609 entry("ERROR=%s", strerror(errno)));
610 return EthernetInterfaceIntf::mtu();
611 }
Tejas Patil2c0fc562021-08-03 19:13:46 +0530612
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800613 EthernetInterfaceIntf::mtu(value);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530614 return value;
615}
616
William A. Kennington III26275a32021-07-13 20:32:42 -0700617bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700618{
William A. Kennington III26275a32021-07-13 20:32:42 -0700619 constexpr auto svc = "org.freedesktop.network1";
620 constexpr auto intf = "org.freedesktop.network1.Link";
621 constexpr auto prop = "AdministrativeState";
622 char* rpath;
623 sd_bus_path_encode("/org/freedesktop/network1/link",
624 std::to_string(ifIndex()).c_str(), &rpath);
625 std::string path(rpath);
626 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700627
William A. Kennington III26275a32021-07-13 20:32:42 -0700628 // Store / Parser for the AdministrativeState return value
629 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700630 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700631 if (state != "initialized")
632 {
633 ret = state != "unmanaged";
634 }
635 };
636
637 // Build a matcher before making the property call to ensure we
638 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500639 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700640 bus,
641 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
642 "'PropertiesChanged',arg0='{}',",
643 svc, path, PROPERTY_INTERFACE, intf)
644 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500645 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700646 std::string intf;
647 std::unordered_map<std::string, std::variant<std::string>> values;
648 try
649 {
650 m.read(intf, values);
651 auto it = values.find(prop);
652 // Ignore properties that aren't AdministrativeState
653 if (it != values.end())
654 {
655 cb(std::get<std::string>(it->second));
656 }
657 }
658 catch (const std::exception& e)
659 {
660 log<level::ERR>(
661 fmt::format(
662 "AdministrativeState match parsing failed on {}: {}",
663 interfaceName(), e.what())
664 .c_str(),
665 entry("INTERFACE=%s", interfaceName().c_str()),
666 entry("ERROR=%s", e.what()));
667 }
668 });
669
670 // Actively call for the value in case the interface is already configured
671 auto method =
672 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
673 method.append(intf, prop);
674 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700675 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700676 auto reply = bus.call(method);
677 std::variant<std::string> state;
678 reply.read(state);
679 cb(std::get<std::string>(state));
680 }
681 catch (const std::exception& e)
682 {
683 log<level::ERR>(
684 fmt::format("Failed to get AdministrativeState on {}: {}",
685 interfaceName(), e.what())
686 .c_str(),
687 entry("INTERFACE=%s", interfaceName().c_str()),
688 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700689 }
690
William A. Kennington III26275a32021-07-13 20:32:42 -0700691 // The interface is not yet configured by systemd-networkd, wait until it
692 // signals us a valid state.
693 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700694 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700695 bus.wait();
696 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700697 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700698
699 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700700}
701
William A. Kennington III69f45542022-09-24 23:28:14 -0700702static void setNICAdminState(stdplus::const_zstring intf, bool up)
William A. Kennington III4209cee2021-10-23 18:14:21 -0700703{
704 ifreq ifr = {};
William A. Kennington III69f45542022-09-24 23:28:14 -0700705 std::strncpy(ifr.ifr_name, intf.data(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800706 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700707
708 ifr.ifr_flags &= ~IFF_UP;
709 ifr.ifr_flags |= up ? IFF_UP : 0;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800710 getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700711}
712
Patrick Williams6aef7692021-05-01 06:39:41 -0500713bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700714{
Patrick Williams6aef7692021-05-01 06:39:41 -0500715 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700716 {
717 return value;
718 }
719
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800720 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700721 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800722 if (!value)
723 {
724 // We only need to bring down the interface, networkd will always bring
725 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700726 manager.addReloadPreHook(
727 [ifname = interfaceName()]() { setNICAdminState(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800728 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700729 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800730
731 return value;
732}
733
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530734ServerList EthernetInterface::staticNameServers(ServerList value)
735{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530736 for (const auto& nameserverip : value)
737 {
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700738 if (!isValidIP(nameserverip))
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530739 {
740 log<level::ERR>("Not a valid IP address"),
741 entry("ADDRESS=%s", nameserverip.c_str());
742 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530743 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530744 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
745 }
746 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530747 try
748 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530749 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700750
Ratan Gupta6dec3902017-08-20 15:28:12 +0530751 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700752 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530753 }
Patrick Williams5758db32021-10-06 12:29:22 -0500754 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530755 {
756 log<level::ERR>("Exception processing DNS entries");
757 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530758 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530759}
760
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700761void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530762{
763 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700764 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700765 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530766}
767
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530768ServerList EthernetInterface::getNameServerFromResolvd()
769{
770 ServerList servers;
771 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
772
773 /*
774 The DNS property under org.freedesktop.resolve1.Link interface contains
775 an array containing all DNS servers currently used by resolved. It
776 contains similar information as the DNS server data written to
777 /run/systemd/resolve/resolv.conf.
778
779 Each structure in the array consists of a numeric network interface index,
780 an address family, and a byte array containing the DNS server address
781 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
782 The array contains DNS servers configured system-wide, including those
783 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
784 /etc/systemd/resolved.conf, as well as per-interface DNS server
785 information either retrieved from systemd-networkd or configured by
786 external software via SetLinkDNS().
787 */
788
789 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
790 std::variant<type> name; // Variable to capture the DNS property
791 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
792 PROPERTY_INTERFACE, METHOD_GET);
793
794 method.append(RESOLVED_INTERFACE, "DNS");
795 auto reply = bus.call(method);
796
797 try
798 {
799 reply.read(name);
800 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500801 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530802 {
803 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
804 }
805 auto tupleVector = std::get_if<type>(&name);
806 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
807 {
Alexander Filippov983da552021-02-08 15:26:54 +0300808 int addressFamily = std::get<0>(*i);
809 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
810
811 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530812 {
Alexander Filippov983da552021-02-08 15:26:54 +0300813 case AF_INET:
814 if (ipaddress.size() == sizeof(struct in_addr))
815 {
816 servers.push_back(toString(
817 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
818 }
819 else
820 {
821 log<level::ERR>(
822 "Invalid data recived from Systemd-Resolved");
823 }
824 break;
825
826 case AF_INET6:
827 if (ipaddress.size() == sizeof(struct in6_addr))
828 {
829 servers.push_back(toString(
830 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
831 }
832 else
833 {
834 log<level::ERR>(
835 "Invalid data recived from Systemd-Resolved");
836 }
837 break;
838
839 default:
840 log<level::ERR>(
841 "Unsupported address family in DNS from Systemd-Resolved");
842 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530843 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530844 }
845 return servers;
846}
847
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700848std::string EthernetInterface::vlanIntfName(VlanId id) const
849{
850 return fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
851}
852
853std::string EthernetInterface::vlanObjPath(VlanId id) const
854{
855 return fmt::format(FMT_COMPILE("{}_{}"), objPath, id);
856}
857
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530858void EthernetInterface::loadVLAN(VlanId id)
859{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700860 auto vlanInterfaceName = vlanIntfName(id);
861 auto path = vlanObjPath(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530862
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700863 config::Parser config(
864 config::pathForIntfConf(manager.getConfDir(), vlanInterfaceName));
865
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530866 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington III0caf2212022-08-18 18:15:51 -0700867 bus, path.c_str(), config, EthernetInterfaceIntf::nicEnabled(), id,
868 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530869
Gunnar Mills57d9c502018-09-14 14:42:34 -0500870 // Fetch the ip address from the system
871 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530872 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800873 vlanIntf->createStaticNeighborObjects();
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700874 vlanIntf->loadNameServers(config);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530875
876 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
877 std::move(vlanIntf));
878}
879
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700880ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530881{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700882 auto vlanInterfaceName = vlanIntfName(id);
883 if (this->vlanInterfaces.find(vlanInterfaceName) !=
884 this->vlanInterfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800885 {
886 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
887 elog<InvalidArgument>(
888 Argument::ARGUMENT_NAME("VLANId"),
889 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
890 }
891
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700892 auto path = vlanObjPath(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530893
Patrick Williams6aef7692021-05-01 06:39:41 -0500894 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530895 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530896 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington III0caf2212022-08-18 18:15:51 -0700897 bus, path.c_str(), config::Parser(),
Patrick Williams6aef7692021-05-01 06:39:41 -0500898 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530899
900 // write the device file for the vlan interface.
901 vlanIntf->writeDeviceFile();
902
Gunnar Mills57d9c502018-09-14 14:42:34 -0500903 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700904
905 writeConfigurationFile();
906 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700907
908 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530909}
Ratan Gupta2b106532017-07-25 16:05:02 +0530910
Patrick Williams6aef7692021-05-01 06:39:41 -0500911ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530912{
Patrick Williams6aef7692021-05-01 06:39:41 -0500913 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530914
915 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700916 manager.reloadConfigs();
917
Ratan Gupta497c0c92017-08-22 19:15:59 +0530918 return ntpServers;
919}
Ratan Gupta2b106532017-07-25 16:05:02 +0530920// Need to merge the below function with the code which writes the
921// config file during factory reset.
922// TODO openbmc/openbmc#1751
923
924void EthernetInterface::writeConfigurationFile()
925{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500926 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530927 {
928 intf.second->writeConfigurationFile();
929 }
930
William A. Kennington III95a49a22022-08-18 17:50:05 -0700931 config::Parser config;
932 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530933 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700934 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800935#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700936 auto mac = MacAddressIntf::macAddress();
937 if (!mac.empty())
938 {
939 link["MACAddress"].emplace_back(mac);
940 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800941#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700942 if (!EthernetInterfaceIntf::nicEnabled())
943 {
944 link["Unmanaged"].emplace_back("yes");
945 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700946 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700947 {
948 auto& network = config.map["Network"].emplace_back();
949 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400950#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700951 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400952#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700953 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400954#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700955 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
956 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
957 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600958 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700959 auto& vlans = network["VLAN"];
960 for (const auto& intf : vlanInterfaces)
961 {
962 vlans.emplace_back(
963 intf.second->EthernetInterface::interfaceName());
964 }
965 }
966 {
967 auto& ntps = network["NTP"];
968 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
969 {
970 ntps.emplace_back(ntp);
971 }
972 }
973 {
974 auto& dnss = network["DNS"];
975 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
976 {
977 dnss.emplace_back(dns);
978 }
979 }
980 {
981 auto& address = network["Address"];
982 for (const auto& addr : getAddresses())
983 {
984 if (originIsManuallyAssigned(addr.second->origin()) &&
985 !dhcpIsEnabled(addr.second->type()))
986 {
987 address.emplace_back(
988 fmt::format("{}/{}", addr.second->address(),
989 addr.second->prefixLength()));
990 }
991 }
992 }
993 {
994 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700995 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700996 {
997 auto gateway = EthernetInterfaceIntf::defaultGateway();
998 if (!gateway.empty())
999 {
1000 gateways.emplace_back(gateway);
1001 }
1002 }
Ratan Gupta2b106532017-07-25 16:05:02 +05301003
William A. Kennington III8060c0d2022-08-18 19:19:34 -07001004 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -07001005 {
1006 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1007 if (!gateway6.empty())
1008 {
1009 gateways.emplace_back(gateway6);
1010 }
1011 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001012 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001013 }
William A. Kennington III95a49a22022-08-18 17:50:05 -07001014 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -07001015 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -05001016 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001017 auto& neighbors = config.map["Neighbor"];
1018 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +08001019 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001020 auto& neighbor = neighbors.emplace_back();
1021 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
1022 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +08001023 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001024 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001025 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001026 auto& dhcp = config.map["DHCP"].emplace_back();
1027 dhcp["ClientIdentifier"].emplace_back("mac");
1028 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +08001029 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001030 const auto& conf = *manager.getDHCPConf();
1031 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
1032 dhcp["UseDNS"].emplace_back(dns_enabled);
1033 dhcp["UseDomains"].emplace_back(dns_enabled);
1034 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
1035 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
1036 : "false");
1037 dhcp["SendHostname"].emplace_back(
1038 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +08001039 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001040 }
William A. Kennington III95a49a22022-08-18 17:50:05 -07001041 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
1042 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -07001043 auto msg = fmt::format("Wrote networkd file: {}", path.native());
1044 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +05301045}
1046
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001047std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301048{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001049#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001050 ether_addr newMAC;
1051 try
1052 {
1053 newMAC = mac_address::fromString(value);
1054 }
Patrick Williams5758db32021-10-06 12:29:22 -05001055 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001056 {
1057 log<level::ERR>("MACAddress is not valid.",
1058 entry("MAC=%s", value.c_str()));
1059 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1060 Argument::ARGUMENT_VALUE(value.c_str()));
1061 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001062 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301063 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001064 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001065 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001066 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1067 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301068 }
1069
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001070 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001071 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001072
William A. Kennington III1137a972019-04-20 20:49:58 -07001073 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001074 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001075 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301076 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001077 // Update everything that depends on the MAC value
1078 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301079 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001080 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301081 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001082 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301083
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001084 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001085 manager.addReloadPreHook([interface]() {
1086 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III69f45542022-09-24 23:28:14 -07001087 setNICAdminState(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001088 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001089 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301090 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001091
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001092#ifdef HAVE_UBOOT_ENV
1093 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -07001094 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001095 if (envVar)
1096 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001097 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1098 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1099 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1100 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001101 }
1102#endif // HAVE_UBOOT_ENV
1103
William A. Kennington III1137a972019-04-20 20:49:58 -07001104 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001105#else
1106 elog<NotAllowed>(
1107 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1108#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301109}
1110
Ratan Guptae9c9b812017-09-22 17:15:37 +05301111void EthernetInterface::deleteAll()
1112{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301113 // clear all the ip on the interface
1114 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001115
1116 writeConfigurationFile();
1117 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301118}
1119
Ravi Tejaa5a09442020-07-17 00:57:33 -05001120std::string EthernetInterface::defaultGateway(std::string gateway)
1121{
1122 auto gw = EthernetInterfaceIntf::defaultGateway();
1123 if (gw == gateway)
1124 {
1125 return gw;
1126 }
1127
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001128 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001129 {
1130 log<level::ERR>("Not a valid v4 Gateway",
1131 entry("GATEWAY=%s", gateway.c_str()));
1132 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1133 Argument::ARGUMENT_VALUE(gateway.c_str()));
1134 }
1135 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001136
1137 writeConfigurationFile();
1138 manager.reloadConfigs();
1139
Ravi Tejaa5a09442020-07-17 00:57:33 -05001140 return gw;
1141}
1142
1143std::string EthernetInterface::defaultGateway6(std::string gateway)
1144{
1145 auto gw = EthernetInterfaceIntf::defaultGateway6();
1146 if (gw == gateway)
1147 {
1148 return gw;
1149 }
1150
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001151 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001152 {
1153 log<level::ERR>("Not a valid v6 Gateway",
1154 entry("GATEWAY=%s", gateway.c_str()));
1155 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1156 Argument::ARGUMENT_VALUE(gateway.c_str()));
1157 }
1158 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001159
1160 writeConfigurationFile();
1161 manager.reloadConfigs();
1162
Ravi Tejaa5a09442020-07-17 00:57:33 -05001163 return gw;
1164}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001165} // namespace network
1166} // namespace phosphor