blob: a29bcedc67aa3175c10f6868aea466dc37d761ee [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 III2e09d272022-10-14 17:15:00 -07007#include "system_queries.hpp"
William A. Kennington III95530ec2022-08-19 01:44:39 -07008#include "util.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05309
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>
William A. Kennington III2e09d272022-10-14 17:15:00 -070012#include <linux/if_addr.h>
13#include <linux/neighbour.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070014#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053015
Ratan Gupta82549cc2017-04-21 08:45:23 +053016#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053017#include <filesystem>
Patrick Venture189d44e2018-07-09 12:30:59 -070018#include <phosphor-logging/elog-errors.hpp>
19#include <phosphor-logging/log.hpp>
William A. Kennington III26275a32021-07-13 20:32:42 -070020#include <sdbusplus/bus/match.hpp>
William A. Kennington III12beaad2020-06-13 19:30:41 -070021#include <stdplus/raw.hpp>
William A. Kennington III69f45542022-09-24 23:28:14 -070022#include <stdplus/zstring.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053023#include <string>
William A. Kennington III26275a32021-07-13 20:32:42 -070024#include <unordered_map>
25#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070026#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053027
Ratan Gupta91a99cc2017-04-14 16:32:09 +053028namespace phosphor
29{
30namespace network
31{
32
33using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053034using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053035using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
36using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050037using Argument = xyz::openbmc_project::Common::InvalidArgument;
William A. Kennington III991a8e82022-10-11 15:02:47 -070038using std::literals::string_view_literals::operator""sv;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053039constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
40constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
41constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
42constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -060043
44constexpr auto TIMESYNCD_SERVICE = "org.freedesktop.timesync1";
45constexpr auto TIMESYNCD_INTERFACE = "org.freedesktop.timesync1.Manager";
46constexpr auto TIMESYNCD_SERVICE_PATH = "/org/freedesktop/timesync1";
47
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053048constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053049
William A. Kennington III2e09d272022-10-14 17:15:00 -070050template <typename Func>
51inline decltype(std::declval<Func>()())
52 ignoreError(std::string_view msg, stdplus::zstring_view intf,
53 decltype(std::declval<Func>()()) fallback, Func&& func) noexcept
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080054{
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070055 try
56 {
William A. Kennington III2e09d272022-10-14 17:15:00 -070057 return func();
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070058 }
William A. Kennington III2e09d272022-10-14 17:15:00 -070059 catch (const std::exception& e)
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070060 {
William A. Kennington III2e09d272022-10-14 17:15:00 -070061 auto err = fmt::format("{} failed on {}: {}", msg, intf, e.what());
62 log<level::ERR>(err.c_str(), entry("INTERFACE=%s", intf.c_str()));
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070063 }
William A. Kennington III2e09d272022-10-14 17:15:00 -070064 return fallback;
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070065}
Patrick Williamsc38b0712022-07-22 19:26:54 -050066EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus,
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -070067 stdplus::zstring_view objPath,
William A. Kennington IIIa520a392022-08-08 12:17:34 -070068 const config::Parser& config,
William A. Kennington III0caf2212022-08-18 18:15:51 -070069 Manager& parent, bool emitSignal,
William A. Kennington III26275a32021-07-13 20:32:42 -070070 std::optional<bool> enabled) :
Patrick Williams166b9592022-03-30 16:09:16 -050071 Ifaces(bus, objPath.c_str(),
72 emitSignal ? Ifaces::action::defer_emit
73 : Ifaces::action::emit_no_signals),
William A. Kennington III2e09d272022-10-14 17:15:00 -070074 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053075{
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -070076 auto intfName = std::string(objPath.substr(objPath.rfind('/') + 1));
Ratan Gupta5978dd12017-07-25 13:47:13 +053077 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053078 interfaceName(intfName);
William A. Kennington III2e09d272022-10-14 17:15:00 -070079 ifIdx = system::intfIndex(intfName);
William A. Kennington III8060c0d2022-08-18 19:19:34 -070080 auto dhcpVal = getDHCPValue(config);
81 EthernetInterfaceIntf::dhcp4(dhcpVal.v4);
82 EthernetInterfaceIntf::dhcp6(dhcpVal.v6);
William A. Kennington IIIa520a392022-08-08 12:17:34 -070083 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRA(config));
William A. Kennington III26275a32021-07-13 20:32:42 -070084 EthernetInterfaceIntf::nicEnabled(enabled ? *enabled : queryNicEnabled());
William A. Kennington IIIe0564842021-10-23 16:02:22 -070085 const auto& gatewayList = manager.getRouteTable().getDefaultGateway();
86 const auto& gateway6List = manager.getRouteTable().getDefaultGateway6();
Ravi Tejaa5a09442020-07-17 00:57:33 -050087 std::string defaultGateway;
88 std::string defaultGateway6;
89
William A. Kennington IIIe0564842021-10-23 16:02:22 -070090 for (const auto& gateway : gatewayList)
Ravi Tejaa5a09442020-07-17 00:57:33 -050091 {
92 if (gateway.first == intfName)
93 {
94 defaultGateway = gateway.second;
95 break;
96 }
97 }
98
William A. Kennington IIIe0564842021-10-23 16:02:22 -070099 for (const auto& gateway6 : gateway6List)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500100 {
101 if (gateway6.first == intfName)
102 {
103 defaultGateway6 = gateway6.second;
104 break;
105 }
106 }
107
108 EthernetInterfaceIntf::defaultGateway(defaultGateway);
109 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
Ratan Gupta99801ce2020-01-09 18:37:16 +0530110 // Don't get the mac address from the system as the mac address
111 // would be same as parent interface.
112 if (intfName.find(".") == std::string::npos)
113 {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700114 auto mac = ignoreError("getMAC", intfName, std::nullopt,
115 [&] { return system::getMAC(intfName); });
116 if (mac)
William A. Kennington III9ecb90e2022-10-14 03:12:43 -0700117 {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700118 MacAddressIntf::macAddress(mac_address::toString(*mac));
William A. Kennington III9ecb90e2022-10-14 03:12:43 -0700119 }
Ratan Gupta99801ce2020-01-09 18:37:16 +0530120 }
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700121 EthernetInterfaceIntf::ntpServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700122 config.map.getValueStrings("Network", "NTP"));
Ratan Gupta613a0122020-04-24 15:18:53 +0530123
124 EthernetInterfaceIntf::linkUp(linkUp());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530125 EthernetInterfaceIntf::mtu(mtu());
Ratan Gupta613a0122020-04-24 15:18:53 +0530126
William A. Kennington III2e09d272022-10-14 17:15:00 -0700127 auto ethInfo = ignoreError("GetEthInfo", intfName, {},
128 [&] { return system::getEthInfo(intfName); });
129 EthernetInterfaceIntf::autoNeg(ethInfo.autoneg);
130 EthernetInterfaceIntf::speed(ethInfo.speed);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530131
Ratan Gupta29b0e432017-05-25 12:51:40 +0530132 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530133 if (emitSignal)
134 {
135 this->emit_object_added();
136 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530137}
138
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700139static IP::Protocol getProtocol(const InAddrAny& addr)
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800140{
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700141 if (std::holds_alternative<in_addr>(addr))
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800142 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700143 return IP::Protocol::IPv4;
144 }
145 else if (std::holds_alternative<in6_addr>(addr))
146 {
147 return IP::Protocol::IPv6;
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800148 }
149
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700150 throw std::runtime_error("Invalid addr type");
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800151}
152
William A. Kennington III24957b92021-12-03 13:59:19 -0800153bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800154{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700155 switch (family)
156 {
157 case IP::Protocol::IPv6:
158 return dhcp6();
159 case IP::Protocol::IPv4:
160 return dhcp4();
161 }
162 throw std::logic_error("Unreachable");
Johnathan Mantey817012a2020-01-30 15:07:39 -0800163}
164
Johnathan Mantey817012a2020-01-30 15:07:39 -0800165bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
166{
167 return (
168#ifdef LINK_LOCAL_AUTOCONFIGURATION
169 (origin == IP::AddressOrigin::Static)
170#else
171 (origin == IP::AddressOrigin::Static ||
172 origin == IP::AddressOrigin::LinkLocal)
173#endif
174
175 );
176}
177
Ratan Gupta87c13982017-06-15 09:27:27 +0530178void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530179{
Ratan Gupta87c13982017-06-15 09:27:27 +0530180 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530181
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700182 AddressFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700183 filter.interface = ifIdx;
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700184 auto currentAddrs = getCurrentAddresses(filter);
185 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530186 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700187 if (addr.flags & IFA_F_DEPRECATED)
188 {
189 continue;
190 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700191 auto address = toString(addr.address);
192 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800193 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800194 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530195 {
196 origin = IP::AddressOrigin::DHCP;
197 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400198#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700199 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530200 {
201 origin = IP::AddressOrigin::LinkLocal;
202 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400203#endif
Ratan Gupta82549cc2017-04-21 08:45:23 +0530204
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700205 auto ipAddressObjectPath =
206 generateObjectPath(addressType, address, addr.prefix, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530207
Lei YU7233c582021-04-08 14:39:43 +0800208 this->addrs.insert_or_assign(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700209 address, std::make_unique<IPAddress>(bus, ipAddressObjectPath,
210 *this, addressType, address,
211 origin, addr.prefix));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530212 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530213}
214
William A. Kennington III08505792019-01-30 16:00:04 -0800215void EthernetInterface::createStaticNeighborObjects()
216{
217 staticNeighbors.clear();
218
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700219 NeighborFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700220 filter.interface = ifIdx;
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700221 filter.state = NUD_PERMANENT;
222 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800223 for (const auto& neighbor : neighbors)
224 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700225 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800226 {
227 continue;
228 }
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700229 auto ip = toString(neighbor.address);
230 auto mac = mac_address::toString(*neighbor.mac);
231 auto objectPath = generateStaticNeighborObjectPath(ip, mac);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700232 staticNeighbors.emplace(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700233 ip, std::make_unique<Neighbor>(bus, objectPath, *this, ip, mac,
234 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800235 }
236}
237
Patrick Williams6aef7692021-05-01 06:39:41 -0500238ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700239 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530240{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800241 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530242 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700243 log<level::INFO>("DHCP enabled on the interface, disabling"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500244 entry("INTERFACE=%s", interfaceName().c_str());
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700245 switch (protType)
246 {
247 case IP::Protocol::IPv4:
248 dhcp4(false);
249 break;
250 case IP::Protocol::IPv6:
251 dhcp6(false);
252 break;
253 }
Ravi Teja07450442022-07-07 04:30:57 -0500254 // Delete the IP address object and that reloads the networkd
255 // to allow the same IP address to be set as Static IP
256 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500257 }
258
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500259 IP::AddressOrigin origin = IP::AddressOrigin::Static;
260
261 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
262
263 if (!isValidIP(addressFamily, ipaddress))
264 {
265 log<level::ERR>("Not a valid IP address"),
266 entry("ADDRESS=%s", ipaddress.c_str());
267 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
268 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
269 }
270
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500271 if (!isValidPrefix(addressFamily, prefixLength))
272 {
273 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700274 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500275 elog<InvalidArgument>(
276 Argument::ARGUMENT_NAME("prefixLength"),
277 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530278 }
279
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700280 auto objectPath =
281 generateObjectPath(protType, ipaddress, prefixLength, origin);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700282 this->addrs.insert_or_assign(
283 ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700284 std::make_unique<IPAddress>(bus, objectPath, *this, protType, ipaddress,
285 origin, prefixLength));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530286
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700287 writeConfigurationFile();
288 manager.reloadConfigs();
289
raviteja-bce379562019-03-28 05:59:36 -0500290 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530291}
292
Patrick Williams6aef7692021-05-01 06:39:41 -0500293ObjectPath EthernetInterface::neighbor(std::string ipAddress,
294 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800295{
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700296 if (!isValidIP(ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800297 {
298 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500299 entry("ADDRESS=%s", ipAddress.c_str()));
300 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
301 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800302 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500303 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800304 {
305 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500306 entry("MACADDRESS=%s", ipAddress.c_str()));
307 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
308 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800309 }
310
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700311 auto objectPath = generateStaticNeighborObjectPath(ipAddress, macAddress);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700312 staticNeighbors.emplace(
313 ipAddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700314 std::make_unique<Neighbor>(bus, objectPath, *this, ipAddress,
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700315 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700316
317 writeConfigurationFile();
318 manager.reloadConfigs();
319
William A. Kennington III08505792019-01-30 16:00:04 -0800320 return objectPath;
321}
322
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700323void EthernetInterface::deleteObject(std::string_view ipaddress)
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530324{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530325 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530326 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530327 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530328 log<level::ERR>("DeleteObject:Unable to find the object.");
329 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530330 }
331 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700332
333 writeConfigurationFile();
334 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530335}
336
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700337void EthernetInterface::deleteStaticNeighborObject(std::string_view ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800338{
Patrick Williams6aef7692021-05-01 06:39:41 -0500339 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800340 if (it == staticNeighbors.end())
341 {
342 log<level::ERR>(
343 "DeleteStaticNeighborObject:Unable to find the object.");
344 return;
345 }
346 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700347
348 writeConfigurationFile();
349 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800350}
351
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700352void EthernetInterface::deleteVLANFromSystem(stdplus::zstring_view interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530353{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700354 const auto& confDir = manager.getConfDir();
355 auto networkFile = config::pathForIntfConf(confDir, interface);
356 auto deviceFile = config::pathForIntfDev(confDir, interface);
Ratan Guptabc886292017-07-25 18:29:57 +0530357
358 // delete the vlan network file
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700359 std::error_code ec;
William A. Kennington III95530ec2022-08-19 01:44:39 -0700360 std::filesystem::remove(networkFile, ec);
361 std::filesystem::remove(deviceFile, ec);
Ratan Guptabc886292017-07-25 18:29:57 +0530362
363 // TODO systemd doesn't delete the virtual network interface
364 // even after deleting all the related configuartion.
365 // https://github.com/systemd/systemd/issues/6600
366 try
367 {
368 deleteInterface(interface);
369 }
Patrick Williams5758db32021-10-06 12:29:22 -0500370 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530371 {
372 commit<InternalFailure>();
373 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530374}
375
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700376void EthernetInterface::deleteVLANObject(stdplus::zstring_view interface)
Ratan Guptae9c9b812017-09-22 17:15:37 +0530377{
378 auto it = vlanInterfaces.find(interface);
379 if (it == vlanInterfaces.end())
380 {
381 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500382 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530383 return;
384 }
385
386 deleteVLANFromSystem(interface);
387 // delete the interface
388 vlanInterfaces.erase(it);
389
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700390 writeConfigurationFile();
391 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530392}
393
Gunnar Mills57d9c502018-09-14 14:42:34 -0500394std::string EthernetInterface::generateObjectPath(
William A. Kennington III991a8e82022-10-11 15:02:47 -0700395 IP::Protocol addressType, std::string_view ipAddress, uint8_t prefixLength,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700396 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530397{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700398 std::string_view type;
399 switch (addressType)
400 {
401 case IP::Protocol::IPv4:
402 type = "ipv4"sv;
403 break;
404 case IP::Protocol::IPv6:
405 type = "ipv6"sv;
406 break;
407 }
408 return fmt::format(
409 FMT_COMPILE("{}/{}/{:08x}"), objPath, type,
410 static_cast<uint32_t>(hash_multi(
411 ipAddress, prefixLength,
412 static_cast<std::underlying_type_t<IP::AddressOrigin>>(origin))));
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530413}
414
William A. Kennington III08505792019-01-30 16:00:04 -0800415std::string EthernetInterface::generateStaticNeighborObjectPath(
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700416 std::string_view ipAddress, std::string_view macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800417{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700418 return fmt::format(
419 FMT_COMPILE("{}/static_neighbor/{:08x}"), objPath,
420 static_cast<uint32_t>(hash_multi(ipAddress, macAddress)));
William A. Kennington III08505792019-01-30 16:00:04 -0800421}
422
Patrick Williams6aef7692021-05-01 06:39:41 -0500423bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700424{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700425 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700426 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700427 writeConfigurationFile();
428 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700429 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700430 return value;
431}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700432
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700433bool EthernetInterface::dhcp4(bool value)
434{
435 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
436 {
437 writeConfigurationFile();
438 manager.reloadConfigs();
439 }
440 return value;
441}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700442
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700443bool EthernetInterface::dhcp6(bool value)
444{
445 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
446 {
447 writeConfigurationFile();
448 manager.reloadConfigs();
449 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700450 return value;
451}
452
Patrick Williams6aef7692021-05-01 06:39:41 -0500453EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530454{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700455 auto old4 = EthernetInterfaceIntf::dhcp4();
456 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
457 value == DHCPConf::v4v6stateless ||
458 value == DHCPConf::both);
459 auto old6 = EthernetInterfaceIntf::dhcp6();
460 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
461 value == DHCPConf::both);
462 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
463 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
464 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
465 value == DHCPConf::v6 || value == DHCPConf::both);
466
467 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530468 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700469 writeConfigurationFile();
470 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530471 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530472 return value;
473}
474
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700475EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
476{
477 if (dhcp6())
478 {
479 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
480 }
481 else if (dhcp4())
482 {
483 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
484 }
485 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
486}
487
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800488bool EthernetInterface::linkUp() const
489{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700490 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700491}
492
Tejas Patil2c0fc562021-08-03 19:13:46 +0530493size_t EthernetInterface::mtu() const
494{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700495 const auto ifname = interfaceName();
496 return ignoreError("getMTU", ifname, std::nullopt,
497 [&] { return system::getMTU(ifname); })
498 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530499}
500
501size_t EthernetInterface::mtu(size_t value)
502{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700503 const size_t old = EthernetInterfaceIntf::mtu();
504 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530505 {
506 return value;
507 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700508 const auto ifname = interfaceName();
509 return EthernetInterfaceIntf::mtu(ignoreError("setMTU", ifname, old, [&] {
510 system::setMTU(ifname, value);
511 return value;
512 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530513}
514
William A. Kennington III26275a32021-07-13 20:32:42 -0700515bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700516{
William A. Kennington III26275a32021-07-13 20:32:42 -0700517 constexpr auto svc = "org.freedesktop.network1";
518 constexpr auto intf = "org.freedesktop.network1.Link";
519 constexpr auto prop = "AdministrativeState";
520 char* rpath;
521 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700522 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700523 std::string path(rpath);
524 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700525
William A. Kennington III26275a32021-07-13 20:32:42 -0700526 // Store / Parser for the AdministrativeState return value
527 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700528 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700529 if (state != "initialized")
530 {
531 ret = state != "unmanaged";
532 }
533 };
534
535 // Build a matcher before making the property call to ensure we
536 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500537 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700538 bus,
539 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
540 "'PropertiesChanged',arg0='{}',",
541 svc, path, PROPERTY_INTERFACE, intf)
542 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500543 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700544 std::string intf;
545 std::unordered_map<std::string, std::variant<std::string>> values;
546 try
547 {
548 m.read(intf, values);
549 auto it = values.find(prop);
550 // Ignore properties that aren't AdministrativeState
551 if (it != values.end())
552 {
553 cb(std::get<std::string>(it->second));
554 }
555 }
556 catch (const std::exception& e)
557 {
558 log<level::ERR>(
559 fmt::format(
560 "AdministrativeState match parsing failed on {}: {}",
561 interfaceName(), e.what())
562 .c_str(),
563 entry("INTERFACE=%s", interfaceName().c_str()),
564 entry("ERROR=%s", e.what()));
565 }
566 });
567
568 // Actively call for the value in case the interface is already configured
569 auto method =
570 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
571 method.append(intf, prop);
572 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700573 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700574 auto reply = bus.call(method);
575 std::variant<std::string> state;
576 reply.read(state);
577 cb(std::get<std::string>(state));
578 }
579 catch (const std::exception& e)
580 {
581 log<level::ERR>(
582 fmt::format("Failed to get AdministrativeState on {}: {}",
583 interfaceName(), e.what())
584 .c_str(),
585 entry("INTERFACE=%s", interfaceName().c_str()),
586 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700587 }
588
William A. Kennington III26275a32021-07-13 20:32:42 -0700589 // The interface is not yet configured by systemd-networkd, wait until it
590 // signals us a valid state.
591 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700592 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700593 bus.wait();
594 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700595 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700596
597 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700598}
599
Patrick Williams6aef7692021-05-01 06:39:41 -0500600bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700601{
Patrick Williams6aef7692021-05-01 06:39:41 -0500602 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700603 {
604 return value;
605 }
606
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800607 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700608 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800609 if (!value)
610 {
611 // We only need to bring down the interface, networkd will always bring
612 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700613 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700614 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800615 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700616 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800617
618 return value;
619}
620
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530621ServerList EthernetInterface::staticNameServers(ServerList value)
622{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530623 for (const auto& nameserverip : value)
624 {
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700625 if (!isValidIP(nameserverip))
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530626 {
627 log<level::ERR>("Not a valid IP address"),
628 entry("ADDRESS=%s", nameserverip.c_str());
629 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530630 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530631 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
632 }
633 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530634 try
635 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530636 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700637
Ratan Gupta6dec3902017-08-20 15:28:12 +0530638 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700639 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530640 }
Patrick Williams5758db32021-10-06 12:29:22 -0500641 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530642 {
643 log<level::ERR>("Exception processing DNS entries");
644 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530645 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530646}
647
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600648void EthernetInterface::loadNTPServers(const config::Parser& config)
649{
650 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
651 EthernetInterfaceIntf::staticNTPServers(
652 config.map.getValueStrings("Network", "NTP"));
653}
654
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700655void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530656{
657 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700658 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700659 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530660}
661
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600662ServerList EthernetInterface::getNTPServerFromTimeSyncd()
663{
664 ServerList servers; // Variable to capture the NTP Server IPs
665 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
666 PROPERTY_INTERFACE, METHOD_GET);
667
668 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
669
670 try
671 {
672 auto reply = bus.call(method);
673 std::variant<ServerList> response;
674 reply.read(response);
675 servers = std::get<ServerList>(response);
676 }
677 catch (const sdbusplus::exception::SdBusError& e)
678 {
679 log<level::ERR>(
680 "Failed to get NTP server information from Systemd-Timesyncd");
681 }
682
683 return servers;
684}
685
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530686ServerList EthernetInterface::getNameServerFromResolvd()
687{
688 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700689 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530690
691 /*
692 The DNS property under org.freedesktop.resolve1.Link interface contains
693 an array containing all DNS servers currently used by resolved. It
694 contains similar information as the DNS server data written to
695 /run/systemd/resolve/resolv.conf.
696
697 Each structure in the array consists of a numeric network interface index,
698 an address family, and a byte array containing the DNS server address
699 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
700 The array contains DNS servers configured system-wide, including those
701 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
702 /etc/systemd/resolved.conf, as well as per-interface DNS server
703 information either retrieved from systemd-networkd or configured by
704 external software via SetLinkDNS().
705 */
706
707 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
708 std::variant<type> name; // Variable to capture the DNS property
709 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
710 PROPERTY_INTERFACE, METHOD_GET);
711
712 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530713
714 try
715 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500716 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530717 reply.read(name);
718 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500719 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530720 {
721 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
722 }
723 auto tupleVector = std::get_if<type>(&name);
724 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
725 {
Alexander Filippov983da552021-02-08 15:26:54 +0300726 int addressFamily = std::get<0>(*i);
727 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
728
729 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530730 {
Alexander Filippov983da552021-02-08 15:26:54 +0300731 case AF_INET:
732 if (ipaddress.size() == sizeof(struct in_addr))
733 {
734 servers.push_back(toString(
735 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
736 }
737 else
738 {
739 log<level::ERR>(
740 "Invalid data recived from Systemd-Resolved");
741 }
742 break;
743
744 case AF_INET6:
745 if (ipaddress.size() == sizeof(struct in6_addr))
746 {
747 servers.push_back(toString(
748 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
749 }
750 else
751 {
752 log<level::ERR>(
753 "Invalid data recived from Systemd-Resolved");
754 }
755 break;
756
757 default:
758 log<level::ERR>(
759 "Unsupported address family in DNS from Systemd-Resolved");
760 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530761 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530762 }
763 return servers;
764}
765
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700766std::string EthernetInterface::vlanIntfName(VlanId id) const
767{
768 return fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
769}
770
771std::string EthernetInterface::vlanObjPath(VlanId id) const
772{
773 return fmt::format(FMT_COMPILE("{}_{}"), objPath, id);
774}
775
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530776void EthernetInterface::loadVLAN(VlanId id)
777{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700778 auto vlanInterfaceName = vlanIntfName(id);
779 auto path = vlanObjPath(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530780
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700781 config::Parser config(
782 config::pathForIntfConf(manager.getConfDir(), vlanInterfaceName));
783
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530784 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington III0caf2212022-08-18 18:15:51 -0700785 bus, path.c_str(), config, EthernetInterfaceIntf::nicEnabled(), id,
786 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530787
Gunnar Mills57d9c502018-09-14 14:42:34 -0500788 // Fetch the ip address from the system
789 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530790 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800791 vlanIntf->createStaticNeighborObjects();
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700792 vlanIntf->loadNameServers(config);
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600793 vlanIntf->loadNTPServers(config);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530794
795 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
796 std::move(vlanIntf));
797}
798
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700799ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530800{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700801 auto vlanInterfaceName = vlanIntfName(id);
802 if (this->vlanInterfaces.find(vlanInterfaceName) !=
803 this->vlanInterfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800804 {
805 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
806 elog<InvalidArgument>(
807 Argument::ARGUMENT_NAME("VLANId"),
808 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
809 }
810
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700811 auto path = vlanObjPath(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530812
Patrick Williams6aef7692021-05-01 06:39:41 -0500813 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530814 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530815 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington III0caf2212022-08-18 18:15:51 -0700816 bus, path.c_str(), config::Parser(),
Patrick Williams6aef7692021-05-01 06:39:41 -0500817 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530818
819 // write the device file for the vlan interface.
820 vlanIntf->writeDeviceFile();
821
Gunnar Mills57d9c502018-09-14 14:42:34 -0500822 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700823
824 writeConfigurationFile();
825 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700826
827 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530828}
Ratan Gupta2b106532017-07-25 16:05:02 +0530829
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600830ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530831{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600832 try
833 {
834 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530835
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600836 writeConfigurationFile();
837 manager.reloadConfigs();
838 }
839 catch (InternalFailure& e)
840 {
841 log<level::ERR>("Exception processing NTP entries");
842 }
843 return EthernetInterfaceIntf::staticNTPServers();
844}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700845
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600846ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
847{
848 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530849}
Ratan Gupta2b106532017-07-25 16:05:02 +0530850// Need to merge the below function with the code which writes the
851// config file during factory reset.
852// TODO openbmc/openbmc#1751
853
854void EthernetInterface::writeConfigurationFile()
855{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500856 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530857 {
858 intf.second->writeConfigurationFile();
859 }
860
William A. Kennington III95a49a22022-08-18 17:50:05 -0700861 config::Parser config;
862 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530863 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700864 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800865#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700866 auto mac = MacAddressIntf::macAddress();
867 if (!mac.empty())
868 {
869 link["MACAddress"].emplace_back(mac);
870 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800871#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700872 if (!EthernetInterfaceIntf::nicEnabled())
873 {
874 link["Unmanaged"].emplace_back("yes");
875 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700876 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700877 {
878 auto& network = config.map["Network"].emplace_back();
879 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400880#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700881 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400882#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700883 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400884#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700885 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
886 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
887 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600888 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700889 auto& vlans = network["VLAN"];
890 for (const auto& intf : vlanInterfaces)
891 {
892 vlans.emplace_back(
893 intf.second->EthernetInterface::interfaceName());
894 }
895 }
896 {
897 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600898 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700899 {
900 ntps.emplace_back(ntp);
901 }
902 }
903 {
904 auto& dnss = network["DNS"];
905 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
906 {
907 dnss.emplace_back(dns);
908 }
909 }
910 {
911 auto& address = network["Address"];
912 for (const auto& addr : getAddresses())
913 {
914 if (originIsManuallyAssigned(addr.second->origin()) &&
915 !dhcpIsEnabled(addr.second->type()))
916 {
917 address.emplace_back(
918 fmt::format("{}/{}", addr.second->address(),
919 addr.second->prefixLength()));
920 }
921 }
922 }
923 {
924 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700925 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700926 {
927 auto gateway = EthernetInterfaceIntf::defaultGateway();
928 if (!gateway.empty())
929 {
930 gateways.emplace_back(gateway);
931 }
932 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530933
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700934 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700935 {
936 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
937 if (!gateway6.empty())
938 {
939 gateways.emplace_back(gateway6);
940 }
941 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600942 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800943 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700944 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700945 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500946 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700947 auto& neighbors = config.map["Neighbor"];
948 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800949 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700950 auto& neighbor = neighbors.emplace_back();
951 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
952 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800953 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500954 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500955 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700956 auto& dhcp = config.map["DHCP"].emplace_back();
957 dhcp["ClientIdentifier"].emplace_back("mac");
958 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800959 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700960 const auto& conf = *manager.getDHCPConf();
961 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
962 dhcp["UseDNS"].emplace_back(dns_enabled);
963 dhcp["UseDomains"].emplace_back(dns_enabled);
964 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
965 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
966 : "false");
967 dhcp["SendHostname"].emplace_back(
968 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800969 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500970 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700971 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
972 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700973 auto msg = fmt::format("Wrote networkd file: {}", path.native());
974 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530975}
976
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800977std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530978{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800979#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600980 ether_addr newMAC;
981 try
982 {
983 newMAC = mac_address::fromString(value);
984 }
Patrick Williams5758db32021-10-06 12:29:22 -0500985 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600986 {
987 log<level::ERR>("MACAddress is not valid.",
988 entry("MAC=%s", value.c_str()));
989 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
990 Argument::ARGUMENT_VALUE(value.c_str()));
991 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700992 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530993 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500994 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500995 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500996 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
997 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530998 }
999
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001000 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001001 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001002
William A. Kennington III1137a972019-04-20 20:49:58 -07001003 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001004 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001005 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301006 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001007 // Update everything that depends on the MAC value
1008 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301009 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001010 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301011 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001012 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301013
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001014 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001015 manager.addReloadPreHook([interface]() {
1016 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -07001017 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001018 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001019 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301020 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001021
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001022#ifdef HAVE_UBOOT_ENV
1023 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -07001024 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001025 if (envVar)
1026 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001027 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1028 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1029 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1030 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001031 }
1032#endif // HAVE_UBOOT_ENV
1033
William A. Kennington III1137a972019-04-20 20:49:58 -07001034 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001035#else
1036 elog<NotAllowed>(
1037 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1038#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301039}
1040
Ratan Guptae9c9b812017-09-22 17:15:37 +05301041void EthernetInterface::deleteAll()
1042{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301043 // clear all the ip on the interface
1044 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001045
1046 writeConfigurationFile();
1047 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301048}
1049
Ravi Tejaa5a09442020-07-17 00:57:33 -05001050std::string EthernetInterface::defaultGateway(std::string gateway)
1051{
1052 auto gw = EthernetInterfaceIntf::defaultGateway();
1053 if (gw == gateway)
1054 {
1055 return gw;
1056 }
1057
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001058 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001059 {
1060 log<level::ERR>("Not a valid v4 Gateway",
1061 entry("GATEWAY=%s", gateway.c_str()));
1062 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1063 Argument::ARGUMENT_VALUE(gateway.c_str()));
1064 }
1065 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001066
1067 writeConfigurationFile();
1068 manager.reloadConfigs();
1069
Ravi Tejaa5a09442020-07-17 00:57:33 -05001070 return gw;
1071}
1072
1073std::string EthernetInterface::defaultGateway6(std::string gateway)
1074{
1075 auto gw = EthernetInterfaceIntf::defaultGateway6();
1076 if (gw == gateway)
1077 {
1078 return gw;
1079 }
1080
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001081 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001082 {
1083 log<level::ERR>("Not a valid v6 Gateway",
1084 entry("GATEWAY=%s", gateway.c_str()));
1085 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1086 Argument::ARGUMENT_VALUE(gateway.c_str()));
1087 }
1088 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001089
1090 writeConfigurationFile();
1091 manager.reloadConfigs();
1092
Ravi Tejaa5a09442020-07-17 00:57:33 -05001093 return gw;
1094}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001095} // namespace network
1096} // namespace phosphor