blob: c0f3a369cf22fad6d7e91010581987a009f93bc5 [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 III5dad2aa2022-01-21 16:00:17 -0800336 catch (const std::exception& e)
337 {
338 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800339
William A. Kennington III96203312021-05-07 12:50:41 -0700340 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800341 linkState = linkUp();
Tejas Patil2c0fc562021-08-03 19:13:46 +0530342 mtuSize = mtu();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800343
Tejas Patil2c0fc562021-08-03 19:13:46 +0530344 return std::make_tuple(speed, duplex, autoneg, linkState, enabled, mtuSize);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530345}
346
347/** @brief get the mac address of the interface.
348 * @return macaddress on success
349 */
350
Gunnar Mills57d9c502018-09-14 14:42:34 -0500351std::string
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700352 EthernetInterface::getMACAddress(stdplus::const_zstring interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530353{
Patrick Williams6aef7692021-05-01 06:39:41 -0500354 std::string activeMACAddr = MacAddressIntf::macAddress();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530355
William A. Kennington III05368f12021-05-13 18:40:47 -0700356 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800357 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800358 try
359 {
360 getIFSock().ioctl(SIOCGIFHWADDR, &ifr);
361 }
362 catch (const std::exception& e)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530363 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530364 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800365 entry("ERROR=%s", e.what()));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700366 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530367 }
William A. Kennington III7c4c9a92022-10-07 19:08:09 -0700368 return mac_address::toString(
369 stdplus::raw::refFrom<ether_addr>(ifr.ifr_hwaddr.sa_data));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530370}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530371
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700372void EthernetInterface::deleteObject(std::string_view ipaddress)
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530373{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530374 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530375 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530376 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530377 log<level::ERR>("DeleteObject:Unable to find the object.");
378 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530379 }
380 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700381
382 writeConfigurationFile();
383 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530384}
385
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700386void EthernetInterface::deleteStaticNeighborObject(std::string_view ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800387{
Patrick Williams6aef7692021-05-01 06:39:41 -0500388 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800389 if (it == staticNeighbors.end())
390 {
391 log<level::ERR>(
392 "DeleteStaticNeighborObject:Unable to find the object.");
393 return;
394 }
395 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700396
397 writeConfigurationFile();
398 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800399}
400
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700401void EthernetInterface::deleteVLANFromSystem(stdplus::zstring_view interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530402{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700403 const auto& confDir = manager.getConfDir();
404 auto networkFile = config::pathForIntfConf(confDir, interface);
405 auto deviceFile = config::pathForIntfDev(confDir, interface);
Ratan Guptabc886292017-07-25 18:29:57 +0530406
407 // delete the vlan network file
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700408 std::error_code ec;
William A. Kennington III95530ec2022-08-19 01:44:39 -0700409 std::filesystem::remove(networkFile, ec);
410 std::filesystem::remove(deviceFile, ec);
Ratan Guptabc886292017-07-25 18:29:57 +0530411
412 // TODO systemd doesn't delete the virtual network interface
413 // even after deleting all the related configuartion.
414 // https://github.com/systemd/systemd/issues/6600
415 try
416 {
417 deleteInterface(interface);
418 }
Patrick Williams5758db32021-10-06 12:29:22 -0500419 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530420 {
421 commit<InternalFailure>();
422 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530423}
424
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700425void EthernetInterface::deleteVLANObject(stdplus::zstring_view interface)
Ratan Guptae9c9b812017-09-22 17:15:37 +0530426{
427 auto it = vlanInterfaces.find(interface);
428 if (it == vlanInterfaces.end())
429 {
430 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500431 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530432 return;
433 }
434
435 deleteVLANFromSystem(interface);
436 // delete the interface
437 vlanInterfaces.erase(it);
438
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700439 writeConfigurationFile();
440 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530441}
442
Gunnar Mills57d9c502018-09-14 14:42:34 -0500443std::string EthernetInterface::generateObjectPath(
William A. Kennington III991a8e82022-10-11 15:02:47 -0700444 IP::Protocol addressType, std::string_view ipAddress, uint8_t prefixLength,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700445 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530446{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700447 std::string_view type;
448 switch (addressType)
449 {
450 case IP::Protocol::IPv4:
451 type = "ipv4"sv;
452 break;
453 case IP::Protocol::IPv6:
454 type = "ipv6"sv;
455 break;
456 }
457 return fmt::format(
458 FMT_COMPILE("{}/{}/{:08x}"), objPath, type,
459 static_cast<uint32_t>(hash_multi(
460 ipAddress, prefixLength,
461 static_cast<std::underlying_type_t<IP::AddressOrigin>>(origin))));
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530462}
463
William A. Kennington III08505792019-01-30 16:00:04 -0800464std::string EthernetInterface::generateStaticNeighborObjectPath(
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700465 std::string_view ipAddress, std::string_view macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800466{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700467 return fmt::format(
468 FMT_COMPILE("{}/static_neighbor/{:08x}"), objPath,
469 static_cast<uint32_t>(hash_multi(ipAddress, macAddress)));
William A. Kennington III08505792019-01-30 16:00:04 -0800470}
471
Patrick Williams6aef7692021-05-01 06:39:41 -0500472bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700473{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700474 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700475 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700476 writeConfigurationFile();
477 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700478 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700479 return value;
480}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700481
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700482bool EthernetInterface::dhcp4(bool value)
483{
484 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
485 {
486 writeConfigurationFile();
487 manager.reloadConfigs();
488 }
489 return value;
490}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700491
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700492bool EthernetInterface::dhcp6(bool value)
493{
494 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
495 {
496 writeConfigurationFile();
497 manager.reloadConfigs();
498 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700499 return value;
500}
501
Patrick Williams6aef7692021-05-01 06:39:41 -0500502EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530503{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700504 auto old4 = EthernetInterfaceIntf::dhcp4();
505 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
506 value == DHCPConf::v4v6stateless ||
507 value == DHCPConf::both);
508 auto old6 = EthernetInterfaceIntf::dhcp6();
509 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
510 value == DHCPConf::both);
511 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
512 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
513 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
514 value == DHCPConf::v6 || value == DHCPConf::both);
515
516 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530517 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700518 writeConfigurationFile();
519 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530520 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530521 return value;
522}
523
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700524EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
525{
526 if (dhcp6())
527 {
528 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
529 }
530 else if (dhcp4())
531 {
532 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
533 }
534 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
535}
536
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800537bool EthernetInterface::linkUp() const
538{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800539 bool value = EthernetInterfaceIntf::linkUp();
540
William A. Kennington III05368f12021-05-13 18:40:47 -0700541 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800542 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800543 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800544 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800545 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800546 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
547 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800548 catch (const std::exception& e)
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800549 {
550 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800551 entry("ERROR=%s", e.what()));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800552 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700553 return value;
554}
555
Tejas Patil2c0fc562021-08-03 19:13:46 +0530556size_t EthernetInterface::mtu() const
557{
Tejas Patil2c0fc562021-08-03 19:13:46 +0530558 size_t value = EthernetInterfaceIntf::mtu();
559
Tejas Patil2c0fc562021-08-03 19:13:46 +0530560 ifreq ifr = {};
561 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800562 try
Tejas Patil2c0fc562021-08-03 19:13:46 +0530563 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800564 getIFSock().ioctl(SIOCGIFMTU, &ifr);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530565 value = ifr.ifr_mtu;
566 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800567 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530568 {
569 log<level::ERR>("ioctl failed for SIOCGIFMTU:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800570 entry("ERROR=%s", e.what()));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530571 }
572 return value;
573}
574
575size_t EthernetInterface::mtu(size_t value)
576{
577 if (value == EthernetInterfaceIntf::mtu())
578 {
579 return value;
580 }
581 else if (value == 0)
582 {
583 return EthernetInterfaceIntf::mtu();
584 }
585
Tejas Patil2c0fc562021-08-03 19:13:46 +0530586 ifreq ifr = {};
587 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
588 ifr.ifr_mtu = value;
589
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800590 try
591 {
592 getIFSock().ioctl(SIOCSIFMTU, &ifr);
593 }
594 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530595 {
596 log<level::ERR>("ioctl failed for SIOCSIFMTU:",
597 entry("ERROR=%s", strerror(errno)));
598 return EthernetInterfaceIntf::mtu();
599 }
Tejas Patil2c0fc562021-08-03 19:13:46 +0530600
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800601 EthernetInterfaceIntf::mtu(value);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530602 return value;
603}
604
William A. Kennington III26275a32021-07-13 20:32:42 -0700605bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700606{
William A. Kennington III26275a32021-07-13 20:32:42 -0700607 constexpr auto svc = "org.freedesktop.network1";
608 constexpr auto intf = "org.freedesktop.network1.Link";
609 constexpr auto prop = "AdministrativeState";
610 char* rpath;
611 sd_bus_path_encode("/org/freedesktop/network1/link",
612 std::to_string(ifIndex()).c_str(), &rpath);
613 std::string path(rpath);
614 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700615
William A. Kennington III26275a32021-07-13 20:32:42 -0700616 // Store / Parser for the AdministrativeState return value
617 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700618 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700619 if (state != "initialized")
620 {
621 ret = state != "unmanaged";
622 }
623 };
624
625 // Build a matcher before making the property call to ensure we
626 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500627 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700628 bus,
629 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
630 "'PropertiesChanged',arg0='{}',",
631 svc, path, PROPERTY_INTERFACE, intf)
632 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500633 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700634 std::string intf;
635 std::unordered_map<std::string, std::variant<std::string>> values;
636 try
637 {
638 m.read(intf, values);
639 auto it = values.find(prop);
640 // Ignore properties that aren't AdministrativeState
641 if (it != values.end())
642 {
643 cb(std::get<std::string>(it->second));
644 }
645 }
646 catch (const std::exception& e)
647 {
648 log<level::ERR>(
649 fmt::format(
650 "AdministrativeState match parsing failed on {}: {}",
651 interfaceName(), e.what())
652 .c_str(),
653 entry("INTERFACE=%s", interfaceName().c_str()),
654 entry("ERROR=%s", e.what()));
655 }
656 });
657
658 // Actively call for the value in case the interface is already configured
659 auto method =
660 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
661 method.append(intf, prop);
662 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700663 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700664 auto reply = bus.call(method);
665 std::variant<std::string> state;
666 reply.read(state);
667 cb(std::get<std::string>(state));
668 }
669 catch (const std::exception& e)
670 {
671 log<level::ERR>(
672 fmt::format("Failed to get AdministrativeState on {}: {}",
673 interfaceName(), e.what())
674 .c_str(),
675 entry("INTERFACE=%s", interfaceName().c_str()),
676 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700677 }
678
William A. Kennington III26275a32021-07-13 20:32:42 -0700679 // The interface is not yet configured by systemd-networkd, wait until it
680 // signals us a valid state.
681 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700682 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700683 bus.wait();
684 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700685 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700686
687 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700688}
689
William A. Kennington III69f45542022-09-24 23:28:14 -0700690static void setNICAdminState(stdplus::const_zstring intf, bool up)
William A. Kennington III4209cee2021-10-23 18:14:21 -0700691{
692 ifreq ifr = {};
William A. Kennington III69f45542022-09-24 23:28:14 -0700693 std::strncpy(ifr.ifr_name, intf.data(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800694 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700695
696 ifr.ifr_flags &= ~IFF_UP;
697 ifr.ifr_flags |= up ? IFF_UP : 0;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800698 getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700699}
700
Patrick Williams6aef7692021-05-01 06:39:41 -0500701bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700702{
Patrick Williams6aef7692021-05-01 06:39:41 -0500703 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700704 {
705 return value;
706 }
707
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800708 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700709 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800710 if (!value)
711 {
712 // We only need to bring down the interface, networkd will always bring
713 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700714 manager.addReloadPreHook(
715 [ifname = interfaceName()]() { setNICAdminState(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800716 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700717 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800718
719 return value;
720}
721
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530722ServerList EthernetInterface::staticNameServers(ServerList value)
723{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530724 for (const auto& nameserverip : value)
725 {
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700726 if (!isValidIP(nameserverip))
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530727 {
728 log<level::ERR>("Not a valid IP address"),
729 entry("ADDRESS=%s", nameserverip.c_str());
730 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530731 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530732 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
733 }
734 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530735 try
736 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530737 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700738
Ratan Gupta6dec3902017-08-20 15:28:12 +0530739 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700740 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530741 }
Patrick Williams5758db32021-10-06 12:29:22 -0500742 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530743 {
744 log<level::ERR>("Exception processing DNS entries");
745 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530746 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530747}
748
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700749void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530750{
751 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700752 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700753 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530754}
755
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530756ServerList EthernetInterface::getNameServerFromResolvd()
757{
758 ServerList servers;
759 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
760
761 /*
762 The DNS property under org.freedesktop.resolve1.Link interface contains
763 an array containing all DNS servers currently used by resolved. It
764 contains similar information as the DNS server data written to
765 /run/systemd/resolve/resolv.conf.
766
767 Each structure in the array consists of a numeric network interface index,
768 an address family, and a byte array containing the DNS server address
769 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
770 The array contains DNS servers configured system-wide, including those
771 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
772 /etc/systemd/resolved.conf, as well as per-interface DNS server
773 information either retrieved from systemd-networkd or configured by
774 external software via SetLinkDNS().
775 */
776
777 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
778 std::variant<type> name; // Variable to capture the DNS property
779 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
780 PROPERTY_INTERFACE, METHOD_GET);
781
782 method.append(RESOLVED_INTERFACE, "DNS");
783 auto reply = bus.call(method);
784
785 try
786 {
787 reply.read(name);
788 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500789 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530790 {
791 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
792 }
793 auto tupleVector = std::get_if<type>(&name);
794 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
795 {
Alexander Filippov983da552021-02-08 15:26:54 +0300796 int addressFamily = std::get<0>(*i);
797 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
798
799 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530800 {
Alexander Filippov983da552021-02-08 15:26:54 +0300801 case AF_INET:
802 if (ipaddress.size() == sizeof(struct in_addr))
803 {
804 servers.push_back(toString(
805 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
806 }
807 else
808 {
809 log<level::ERR>(
810 "Invalid data recived from Systemd-Resolved");
811 }
812 break;
813
814 case AF_INET6:
815 if (ipaddress.size() == sizeof(struct in6_addr))
816 {
817 servers.push_back(toString(
818 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
819 }
820 else
821 {
822 log<level::ERR>(
823 "Invalid data recived from Systemd-Resolved");
824 }
825 break;
826
827 default:
828 log<level::ERR>(
829 "Unsupported address family in DNS from Systemd-Resolved");
830 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530831 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530832 }
833 return servers;
834}
835
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700836std::string EthernetInterface::vlanIntfName(VlanId id) const
837{
838 return fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
839}
840
841std::string EthernetInterface::vlanObjPath(VlanId id) const
842{
843 return fmt::format(FMT_COMPILE("{}_{}"), objPath, id);
844}
845
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530846void EthernetInterface::loadVLAN(VlanId id)
847{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700848 auto vlanInterfaceName = vlanIntfName(id);
849 auto path = vlanObjPath(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530850
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700851 config::Parser config(
852 config::pathForIntfConf(manager.getConfDir(), vlanInterfaceName));
853
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530854 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington III0caf2212022-08-18 18:15:51 -0700855 bus, path.c_str(), config, EthernetInterfaceIntf::nicEnabled(), id,
856 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530857
Gunnar Mills57d9c502018-09-14 14:42:34 -0500858 // Fetch the ip address from the system
859 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530860 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800861 vlanIntf->createStaticNeighborObjects();
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700862 vlanIntf->loadNameServers(config);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530863
864 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
865 std::move(vlanIntf));
866}
867
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700868ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530869{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700870 auto vlanInterfaceName = vlanIntfName(id);
871 if (this->vlanInterfaces.find(vlanInterfaceName) !=
872 this->vlanInterfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800873 {
874 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
875 elog<InvalidArgument>(
876 Argument::ARGUMENT_NAME("VLANId"),
877 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
878 }
879
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700880 auto path = vlanObjPath(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530881
Patrick Williams6aef7692021-05-01 06:39:41 -0500882 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530883 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530884 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington III0caf2212022-08-18 18:15:51 -0700885 bus, path.c_str(), config::Parser(),
Patrick Williams6aef7692021-05-01 06:39:41 -0500886 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530887
888 // write the device file for the vlan interface.
889 vlanIntf->writeDeviceFile();
890
Gunnar Mills57d9c502018-09-14 14:42:34 -0500891 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700892
893 writeConfigurationFile();
894 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700895
896 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530897}
Ratan Gupta2b106532017-07-25 16:05:02 +0530898
Patrick Williams6aef7692021-05-01 06:39:41 -0500899ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530900{
Patrick Williams6aef7692021-05-01 06:39:41 -0500901 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530902
903 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700904 manager.reloadConfigs();
905
Ratan Gupta497c0c92017-08-22 19:15:59 +0530906 return ntpServers;
907}
Ratan Gupta2b106532017-07-25 16:05:02 +0530908// Need to merge the below function with the code which writes the
909// config file during factory reset.
910// TODO openbmc/openbmc#1751
911
912void EthernetInterface::writeConfigurationFile()
913{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500914 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530915 {
916 intf.second->writeConfigurationFile();
917 }
918
William A. Kennington III95a49a22022-08-18 17:50:05 -0700919 config::Parser config;
920 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530921 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700922 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800923#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700924 auto mac = MacAddressIntf::macAddress();
925 if (!mac.empty())
926 {
927 link["MACAddress"].emplace_back(mac);
928 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800929#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700930 if (!EthernetInterfaceIntf::nicEnabled())
931 {
932 link["Unmanaged"].emplace_back("yes");
933 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700934 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700935 {
936 auto& network = config.map["Network"].emplace_back();
937 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400938#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700939 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400940#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700941 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400942#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700943 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
944 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
945 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600946 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700947 auto& vlans = network["VLAN"];
948 for (const auto& intf : vlanInterfaces)
949 {
950 vlans.emplace_back(
951 intf.second->EthernetInterface::interfaceName());
952 }
953 }
954 {
955 auto& ntps = network["NTP"];
956 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
957 {
958 ntps.emplace_back(ntp);
959 }
960 }
961 {
962 auto& dnss = network["DNS"];
963 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
964 {
965 dnss.emplace_back(dns);
966 }
967 }
968 {
969 auto& address = network["Address"];
970 for (const auto& addr : getAddresses())
971 {
972 if (originIsManuallyAssigned(addr.second->origin()) &&
973 !dhcpIsEnabled(addr.second->type()))
974 {
975 address.emplace_back(
976 fmt::format("{}/{}", addr.second->address(),
977 addr.second->prefixLength()));
978 }
979 }
980 }
981 {
982 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700983 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700984 {
985 auto gateway = EthernetInterfaceIntf::defaultGateway();
986 if (!gateway.empty())
987 {
988 gateways.emplace_back(gateway);
989 }
990 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530991
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700992 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700993 {
994 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
995 if (!gateway6.empty())
996 {
997 gateways.emplace_back(gateway6);
998 }
999 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001000 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001001 }
William A. Kennington III95a49a22022-08-18 17:50:05 -07001002 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -07001003 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -05001004 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001005 auto& neighbors = config.map["Neighbor"];
1006 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +08001007 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001008 auto& neighbor = neighbors.emplace_back();
1009 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
1010 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +08001011 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001012 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001013 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001014 auto& dhcp = config.map["DHCP"].emplace_back();
1015 dhcp["ClientIdentifier"].emplace_back("mac");
1016 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +08001017 {
William A. Kennington III95a49a22022-08-18 17:50:05 -07001018 const auto& conf = *manager.getDHCPConf();
1019 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
1020 dhcp["UseDNS"].emplace_back(dns_enabled);
1021 dhcp["UseDomains"].emplace_back(dns_enabled);
1022 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
1023 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
1024 : "false");
1025 dhcp["SendHostname"].emplace_back(
1026 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +08001027 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001028 }
William A. Kennington III95a49a22022-08-18 17:50:05 -07001029 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
1030 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -07001031 auto msg = fmt::format("Wrote networkd file: {}", path.native());
1032 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +05301033}
1034
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001035std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301036{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001037#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001038 ether_addr newMAC;
1039 try
1040 {
1041 newMAC = mac_address::fromString(value);
1042 }
Patrick Williams5758db32021-10-06 12:29:22 -05001043 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001044 {
1045 log<level::ERR>("MACAddress is not valid.",
1046 entry("MAC=%s", value.c_str()));
1047 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1048 Argument::ARGUMENT_VALUE(value.c_str()));
1049 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001050 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301051 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001052 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001053 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001054 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1055 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301056 }
1057
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001058 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001059 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001060
William A. Kennington III1137a972019-04-20 20:49:58 -07001061 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001062 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001063 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301064 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001065 // Update everything that depends on the MAC value
1066 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301067 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001068 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301069 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001070 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301071
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001072 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001073 manager.addReloadPreHook([interface]() {
1074 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III69f45542022-09-24 23:28:14 -07001075 setNICAdminState(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001076 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001077 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301078 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001079
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001080#ifdef HAVE_UBOOT_ENV
1081 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -07001082 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001083 if (envVar)
1084 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001085 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1086 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1087 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1088 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001089 }
1090#endif // HAVE_UBOOT_ENV
1091
William A. Kennington III1137a972019-04-20 20:49:58 -07001092 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001093#else
1094 elog<NotAllowed>(
1095 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1096#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301097}
1098
Ratan Guptae9c9b812017-09-22 17:15:37 +05301099void EthernetInterface::deleteAll()
1100{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301101 // clear all the ip on the interface
1102 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001103
1104 writeConfigurationFile();
1105 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301106}
1107
Ravi Tejaa5a09442020-07-17 00:57:33 -05001108std::string EthernetInterface::defaultGateway(std::string gateway)
1109{
1110 auto gw = EthernetInterfaceIntf::defaultGateway();
1111 if (gw == gateway)
1112 {
1113 return gw;
1114 }
1115
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001116 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001117 {
1118 log<level::ERR>("Not a valid v4 Gateway",
1119 entry("GATEWAY=%s", gateway.c_str()));
1120 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1121 Argument::ARGUMENT_VALUE(gateway.c_str()));
1122 }
1123 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001124
1125 writeConfigurationFile();
1126 manager.reloadConfigs();
1127
Ravi Tejaa5a09442020-07-17 00:57:33 -05001128 return gw;
1129}
1130
1131std::string EthernetInterface::defaultGateway6(std::string gateway)
1132{
1133 auto gw = EthernetInterfaceIntf::defaultGateway6();
1134 if (gw == gateway)
1135 {
1136 return gw;
1137 }
1138
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001139 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001140 {
1141 log<level::ERR>("Not a valid v6 Gateway",
1142 entry("GATEWAY=%s", gateway.c_str()));
1143 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1144 Argument::ARGUMENT_VALUE(gateway.c_str()));
1145 }
1146 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001147
1148 writeConfigurationFile();
1149 manager.reloadConfigs();
1150
Ravi Tejaa5a09442020-07-17 00:57:33 -05001151 return gw;
1152}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001153} // namespace network
1154} // namespace phosphor