blob: 537b7ad82b9891a8cc6f56b012e4b795ec2ea52c [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>
William A. Kennington IIIfd862be2022-10-09 18:40:55 -070015#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 III12beaad2020-06-13 19:30:41 -070022#include <stdplus/raw.hpp>
William A. Kennington III69f45542022-09-24 23:28:14 -070023#include <stdplus/zstring.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053024#include <string>
William A. Kennington III26275a32021-07-13 20:32:42 -070025#include <unordered_map>
26#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070027#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053028
Ratan Gupta91a99cc2017-04-14 16:32:09 +053029namespace phosphor
30{
31namespace network
32{
33
34using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053035using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053036using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
37using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050038using Argument = xyz::openbmc_project::Common::InvalidArgument;
William A. Kennington III991a8e82022-10-11 15:02:47 -070039using std::literals::string_view_literals::operator""sv;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053040constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
41constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
42constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
43constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -060044
45constexpr auto TIMESYNCD_SERVICE = "org.freedesktop.timesync1";
46constexpr auto TIMESYNCD_INTERFACE = "org.freedesktop.timesync1.Manager";
47constexpr auto TIMESYNCD_SERVICE_PATH = "/org/freedesktop/timesync1";
48
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053049constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053050
William A. Kennington III2e09d272022-10-14 17:15:00 -070051template <typename Func>
52inline decltype(std::declval<Func>()())
53 ignoreError(std::string_view msg, stdplus::zstring_view intf,
54 decltype(std::declval<Func>()()) fallback, Func&& func) noexcept
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080055{
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070056 try
57 {
William A. Kennington III2e09d272022-10-14 17:15:00 -070058 return func();
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070059 }
William A. Kennington III2e09d272022-10-14 17:15:00 -070060 catch (const std::exception& e)
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070061 {
William A. Kennington III2e09d272022-10-14 17:15:00 -070062 auto err = fmt::format("{} failed on {}: {}", msg, intf, e.what());
63 log<level::ERR>(err.c_str(), entry("INTERFACE=%s", intf.c_str()));
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070064 }
William A. Kennington III2e09d272022-10-14 17:15:00 -070065 return fallback;
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070066}
William A. Kennington IIId298f932022-10-17 14:31:38 -070067
William A. Kennington IIId298f932022-10-17 14:31:38 -070068static std::string makeObjPath(std::string_view root, std::string_view intf)
69{
70 auto ret = fmt::format(FMT_COMPILE("{}/{}"), root, intf);
71 std::replace(ret.begin() + ret.size() - intf.size(), ret.end(), '.', '_');
72 return ret;
73}
74
75EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus, Manager& manager,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -070076 const system::InterfaceInfo& info,
William A. Kennington IIId298f932022-10-17 14:31:38 -070077 std::string_view objRoot,
William A. Kennington IIIa520a392022-08-08 12:17:34 -070078 const config::Parser& config,
William A. Kennington IIId298f932022-10-17 14:31:38 -070079 bool emitSignal,
80 std::optional<bool> enabled) :
William A. Kennington IIIfd862be2022-10-09 18:40:55 -070081 EthernetInterface(bus, manager, info, makeObjPath(objRoot, *info.name),
William A. Kennington IIId298f932022-10-17 14:31:38 -070082 config, emitSignal, enabled)
83{
84}
85
86EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus, Manager& manager,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -070087 const system::InterfaceInfo& info,
William A. Kennington IIId298f932022-10-17 14:31:38 -070088 std::string&& objPath,
89 const config::Parser& config,
90 bool emitSignal,
William A. Kennington III26275a32021-07-13 20:32:42 -070091 std::optional<bool> enabled) :
Patrick Williams166b9592022-03-30 16:09:16 -050092 Ifaces(bus, objPath.c_str(),
93 emitSignal ? Ifaces::action::defer_emit
94 : Ifaces::action::emit_no_signals),
William A. Kennington IIIfd862be2022-10-09 18:40:55 -070095 bus(bus), manager(manager), objPath(std::move(objPath)), ifIdx(info.idx)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053096{
William A. Kennington IIIfd862be2022-10-09 18:40:55 -070097 interfaceName(*info.name);
William A. Kennington III8060c0d2022-08-18 19:19:34 -070098 auto dhcpVal = getDHCPValue(config);
99 EthernetInterfaceIntf::dhcp4(dhcpVal.v4);
100 EthernetInterfaceIntf::dhcp6(dhcpVal.v6);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700101 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRA(config));
William A. Kennington III26275a32021-07-13 20:32:42 -0700102 EthernetInterfaceIntf::nicEnabled(enabled ? *enabled : queryNicEnabled());
William A. Kennington IIIe0564842021-10-23 16:02:22 -0700103 const auto& gatewayList = manager.getRouteTable().getDefaultGateway();
104 const auto& gateway6List = manager.getRouteTable().getDefaultGateway6();
Ravi Tejaa5a09442020-07-17 00:57:33 -0500105 std::string defaultGateway;
106 std::string defaultGateway6;
107
William A. Kennington IIIe0564842021-10-23 16:02:22 -0700108 for (const auto& gateway : gatewayList)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500109 {
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700110 if (gateway.first == *info.name)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500111 {
112 defaultGateway = gateway.second;
113 break;
114 }
115 }
116
William A. Kennington IIIe0564842021-10-23 16:02:22 -0700117 for (const auto& gateway6 : gateway6List)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500118 {
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700119 if (gateway6.first == *info.name)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500120 {
121 defaultGateway6 = gateway6.second;
122 break;
123 }
124 }
125
126 EthernetInterfaceIntf::defaultGateway(defaultGateway);
127 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700128 EthernetInterfaceIntf::ntpServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700129 config.map.getValueStrings("Network", "NTP"));
Ratan Gupta613a0122020-04-24 15:18:53 +0530130
William A. Kennington III3e471c52022-10-27 19:46:07 -0700131 if (ifIdx > 0)
132 {
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700133 auto ethInfo = ignoreError("GetEthInfo", *info.name, {}, [&] {
134 return system::getEthInfo(*info.name);
William A. Kennington III3e471c52022-10-27 19:46:07 -0700135 });
136 EthernetInterfaceIntf::autoNeg(ethInfo.autoneg);
137 EthernetInterfaceIntf::speed(ethInfo.speed);
138 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530139
William A. Kennington IIId298f932022-10-17 14:31:38 -0700140 updateInfo(info);
141
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700142 if (info.vlan_id)
143 {
144 if (!info.parent_idx)
145 {
146 std::runtime_error("Missing parent link");
147 }
148 vlan.emplace(bus, this->objPath.c_str(), info, *this, emitSignal);
149 }
150
Ratan Gupta29b0e432017-05-25 12:51:40 +0530151 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530152 if (emitSignal)
153 {
154 this->emit_object_added();
155 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530156}
157
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700158void EthernetInterface::updateInfo(const system::InterfaceInfo& info)
William A. Kennington IIId298f932022-10-17 14:31:38 -0700159{
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700160 EthernetInterfaceIntf::linkUp(info.flags & IFF_RUNNING);
William A. Kennington IIId298f932022-10-17 14:31:38 -0700161 if (info.mac)
162 {
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700163 MacAddressIntf::macAddress(std::to_string(*info.mac));
William A. Kennington IIId298f932022-10-17 14:31:38 -0700164 }
165 if (info.mtu)
166 {
167 EthernetInterfaceIntf::mtu(*info.mtu);
168 }
169}
170
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700171static IP::Protocol getProtocol(const InAddrAny& addr)
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800172{
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700173 if (std::holds_alternative<in_addr>(addr))
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800174 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700175 return IP::Protocol::IPv4;
176 }
177 else if (std::holds_alternative<in6_addr>(addr))
178 {
179 return IP::Protocol::IPv6;
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800180 }
181
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700182 throw std::runtime_error("Invalid addr type");
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800183}
184
William A. Kennington III24957b92021-12-03 13:59:19 -0800185bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800186{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700187 switch (family)
188 {
189 case IP::Protocol::IPv6:
190 return dhcp6();
191 case IP::Protocol::IPv4:
192 return dhcp4();
193 }
194 throw std::logic_error("Unreachable");
Johnathan Mantey817012a2020-01-30 15:07:39 -0800195}
196
Johnathan Mantey817012a2020-01-30 15:07:39 -0800197bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
198{
199 return (
200#ifdef LINK_LOCAL_AUTOCONFIGURATION
201 (origin == IP::AddressOrigin::Static)
202#else
203 (origin == IP::AddressOrigin::Static ||
204 origin == IP::AddressOrigin::LinkLocal)
205#endif
206
207 );
208}
209
Ratan Gupta87c13982017-06-15 09:27:27 +0530210void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530211{
Ratan Gupta87c13982017-06-15 09:27:27 +0530212 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530213
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700214 AddressFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700215 filter.interface = ifIdx;
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700216 auto currentAddrs = getCurrentAddresses(filter);
217 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530218 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700219 if (addr.flags & IFA_F_DEPRECATED)
220 {
221 continue;
222 }
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700223 auto address = std::to_string(addr.address);
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700224 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800225 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800226 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530227 {
228 origin = IP::AddressOrigin::DHCP;
229 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400230#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700231 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530232 {
233 origin = IP::AddressOrigin::LinkLocal;
234 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400235#endif
Ratan Gupta82549cc2017-04-21 08:45:23 +0530236
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700237 auto ipAddressObjectPath =
238 generateObjectPath(addressType, address, addr.prefix, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530239
Lei YU7233c582021-04-08 14:39:43 +0800240 this->addrs.insert_or_assign(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700241 address, std::make_unique<IPAddress>(bus, ipAddressObjectPath,
242 *this, addressType, address,
243 origin, addr.prefix));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530244 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530245}
246
William A. Kennington III08505792019-01-30 16:00:04 -0800247void EthernetInterface::createStaticNeighborObjects()
248{
249 staticNeighbors.clear();
250
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700251 NeighborFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700252 filter.interface = ifIdx;
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700253 filter.state = NUD_PERMANENT;
254 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800255 for (const auto& neighbor : neighbors)
256 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700257 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800258 {
259 continue;
260 }
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700261 auto ip = std::to_string(neighbor.address);
262 auto mac = std::to_string(*neighbor.mac);
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700263 auto objectPath = generateStaticNeighborObjectPath(ip, mac);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700264 staticNeighbors.emplace(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700265 ip, std::make_unique<Neighbor>(bus, objectPath, *this, ip, mac,
266 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800267 }
268}
269
Patrick Williams6aef7692021-05-01 06:39:41 -0500270ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700271 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530272{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800273 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530274 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700275 log<level::INFO>("DHCP enabled on the interface, disabling"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500276 entry("INTERFACE=%s", interfaceName().c_str());
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700277 switch (protType)
278 {
279 case IP::Protocol::IPv4:
280 dhcp4(false);
281 break;
282 case IP::Protocol::IPv6:
283 dhcp6(false);
284 break;
285 }
Ravi Teja07450442022-07-07 04:30:57 -0500286 // Delete the IP address object and that reloads the networkd
287 // to allow the same IP address to be set as Static IP
288 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500289 }
290
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500291 IP::AddressOrigin origin = IP::AddressOrigin::Static;
292
293 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
294
295 if (!isValidIP(addressFamily, ipaddress))
296 {
297 log<level::ERR>("Not a valid IP address"),
298 entry("ADDRESS=%s", ipaddress.c_str());
299 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
300 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
301 }
302
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500303 if (!isValidPrefix(addressFamily, prefixLength))
304 {
305 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700306 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500307 elog<InvalidArgument>(
308 Argument::ARGUMENT_NAME("prefixLength"),
309 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530310 }
311
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700312 auto objectPath =
313 generateObjectPath(protType, ipaddress, prefixLength, origin);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700314 this->addrs.insert_or_assign(
315 ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700316 std::make_unique<IPAddress>(bus, objectPath, *this, protType, ipaddress,
317 origin, prefixLength));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530318
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700319 writeConfigurationFile();
320 manager.reloadConfigs();
321
raviteja-bce379562019-03-28 05:59:36 -0500322 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530323}
324
Patrick Williams6aef7692021-05-01 06:39:41 -0500325ObjectPath EthernetInterface::neighbor(std::string ipAddress,
326 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800327{
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700328 if (!isValidIP(ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800329 {
330 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500331 entry("ADDRESS=%s", ipAddress.c_str()));
332 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
333 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800334 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500335 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800336 {
337 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500338 entry("MACADDRESS=%s", ipAddress.c_str()));
339 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
340 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800341 }
342
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700343 auto objectPath = generateStaticNeighborObjectPath(ipAddress, macAddress);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700344 staticNeighbors.emplace(
345 ipAddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700346 std::make_unique<Neighbor>(bus, objectPath, *this, ipAddress,
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700347 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700348
349 writeConfigurationFile();
350 manager.reloadConfigs();
351
William A. Kennington III08505792019-01-30 16:00:04 -0800352 return objectPath;
353}
354
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700355void EthernetInterface::deleteObject(std::string_view ipaddress)
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530356{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530357 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530358 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530359 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530360 log<level::ERR>("DeleteObject:Unable to find the object.");
361 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530362 }
363 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700364
365 writeConfigurationFile();
366 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530367}
368
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700369void EthernetInterface::deleteStaticNeighborObject(std::string_view ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800370{
Patrick Williams6aef7692021-05-01 06:39:41 -0500371 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800372 if (it == staticNeighbors.end())
373 {
374 log<level::ERR>(
375 "DeleteStaticNeighborObject:Unable to find the object.");
376 return;
377 }
378 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700379
380 writeConfigurationFile();
381 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800382}
383
Gunnar Mills57d9c502018-09-14 14:42:34 -0500384std::string EthernetInterface::generateObjectPath(
William A. Kennington III991a8e82022-10-11 15:02:47 -0700385 IP::Protocol addressType, std::string_view ipAddress, uint8_t prefixLength,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700386 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530387{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700388 std::string_view type;
389 switch (addressType)
390 {
391 case IP::Protocol::IPv4:
392 type = "ipv4"sv;
393 break;
394 case IP::Protocol::IPv6:
395 type = "ipv6"sv;
396 break;
397 }
398 return fmt::format(
399 FMT_COMPILE("{}/{}/{:08x}"), objPath, type,
400 static_cast<uint32_t>(hash_multi(
401 ipAddress, prefixLength,
402 static_cast<std::underlying_type_t<IP::AddressOrigin>>(origin))));
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530403}
404
William A. Kennington III08505792019-01-30 16:00:04 -0800405std::string EthernetInterface::generateStaticNeighborObjectPath(
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700406 std::string_view ipAddress, std::string_view macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800407{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700408 return fmt::format(
409 FMT_COMPILE("{}/static_neighbor/{:08x}"), objPath,
410 static_cast<uint32_t>(hash_multi(ipAddress, macAddress)));
William A. Kennington III08505792019-01-30 16:00:04 -0800411}
412
Patrick Williams6aef7692021-05-01 06:39:41 -0500413bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700414{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700415 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700416 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700417 writeConfigurationFile();
418 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700419 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700420 return value;
421}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700422
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700423bool EthernetInterface::dhcp4(bool value)
424{
425 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
426 {
427 writeConfigurationFile();
428 manager.reloadConfigs();
429 }
430 return value;
431}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700432
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700433bool EthernetInterface::dhcp6(bool value)
434{
435 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
436 {
437 writeConfigurationFile();
438 manager.reloadConfigs();
439 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700440 return value;
441}
442
Patrick Williams6aef7692021-05-01 06:39:41 -0500443EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530444{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700445 auto old4 = EthernetInterfaceIntf::dhcp4();
446 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
447 value == DHCPConf::v4v6stateless ||
448 value == DHCPConf::both);
449 auto old6 = EthernetInterfaceIntf::dhcp6();
450 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
451 value == DHCPConf::both);
452 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
453 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
454 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
455 value == DHCPConf::v6 || value == DHCPConf::both);
456
457 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530458 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700459 writeConfigurationFile();
460 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530461 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530462 return value;
463}
464
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700465EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
466{
467 if (dhcp6())
468 {
469 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
470 }
471 else if (dhcp4())
472 {
473 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
474 }
475 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
476}
477
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800478bool EthernetInterface::linkUp() const
479{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700480 if (ifIdx == 0)
481 {
482 return EthernetInterfaceIntf::linkUp();
483 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700484 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700485}
486
Tejas Patil2c0fc562021-08-03 19:13:46 +0530487size_t EthernetInterface::mtu() const
488{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700489 if (ifIdx == 0)
490 {
491 return EthernetInterfaceIntf::mtu();
492 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700493 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700494 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700495 [&] { return system::getMTU(ifname); })
496 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530497}
498
499size_t EthernetInterface::mtu(size_t value)
500{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700501 const size_t old = EthernetInterfaceIntf::mtu();
502 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530503 {
504 return value;
505 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700506 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700507 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700508 system::setMTU(ifname, value);
509 return value;
510 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530511}
512
William A. Kennington III26275a32021-07-13 20:32:42 -0700513bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700514{
William A. Kennington III26275a32021-07-13 20:32:42 -0700515 constexpr auto svc = "org.freedesktop.network1";
516 constexpr auto intf = "org.freedesktop.network1.Link";
517 constexpr auto prop = "AdministrativeState";
518 char* rpath;
519 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700520 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700521 std::string path(rpath);
522 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700523
William A. Kennington III26275a32021-07-13 20:32:42 -0700524 // Store / Parser for the AdministrativeState return value
525 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700526 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700527 if (state != "initialized")
528 {
529 ret = state != "unmanaged";
530 }
531 };
532
533 // Build a matcher before making the property call to ensure we
534 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500535 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700536 bus,
537 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
538 "'PropertiesChanged',arg0='{}',",
539 svc, path, PROPERTY_INTERFACE, intf)
540 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500541 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700542 std::string intf;
543 std::unordered_map<std::string, std::variant<std::string>> values;
544 try
545 {
546 m.read(intf, values);
547 auto it = values.find(prop);
548 // Ignore properties that aren't AdministrativeState
549 if (it != values.end())
550 {
551 cb(std::get<std::string>(it->second));
552 }
553 }
554 catch (const std::exception& e)
555 {
556 log<level::ERR>(
557 fmt::format(
558 "AdministrativeState match parsing failed on {}: {}",
559 interfaceName(), e.what())
560 .c_str(),
561 entry("INTERFACE=%s", interfaceName().c_str()),
562 entry("ERROR=%s", e.what()));
563 }
564 });
565
566 // Actively call for the value in case the interface is already configured
567 auto method =
568 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
569 method.append(intf, prop);
570 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700571 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700572 auto reply = bus.call(method);
573 std::variant<std::string> state;
574 reply.read(state);
575 cb(std::get<std::string>(state));
576 }
577 catch (const std::exception& e)
578 {
579 log<level::ERR>(
580 fmt::format("Failed to get AdministrativeState on {}: {}",
581 interfaceName(), e.what())
582 .c_str(),
583 entry("INTERFACE=%s", interfaceName().c_str()),
584 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700585 }
586
William A. Kennington III26275a32021-07-13 20:32:42 -0700587 // The interface is not yet configured by systemd-networkd, wait until it
588 // signals us a valid state.
589 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700590 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700591 bus.wait();
592 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700593 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700594
595 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700596}
597
Patrick Williams6aef7692021-05-01 06:39:41 -0500598bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700599{
Patrick Williams6aef7692021-05-01 06:39:41 -0500600 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700601 {
602 return value;
603 }
604
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800605 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700606 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800607 if (!value)
608 {
609 // We only need to bring down the interface, networkd will always bring
610 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700611 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700612 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800613 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700614 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800615
616 return value;
617}
618
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530619ServerList EthernetInterface::staticNameServers(ServerList value)
620{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530621 for (const auto& nameserverip : value)
622 {
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700623 if (!isValidIP(nameserverip))
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530624 {
625 log<level::ERR>("Not a valid IP address"),
626 entry("ADDRESS=%s", nameserverip.c_str());
627 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530628 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530629 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
630 }
631 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530632 try
633 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530634 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700635
Ratan Gupta6dec3902017-08-20 15:28:12 +0530636 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700637 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530638 }
Patrick Williams5758db32021-10-06 12:29:22 -0500639 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530640 {
641 log<level::ERR>("Exception processing DNS entries");
642 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530643 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530644}
645
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600646void EthernetInterface::loadNTPServers(const config::Parser& config)
647{
648 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
649 EthernetInterfaceIntf::staticNTPServers(
650 config.map.getValueStrings("Network", "NTP"));
651}
652
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700653void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530654{
655 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700656 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700657 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530658}
659
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600660ServerList EthernetInterface::getNTPServerFromTimeSyncd()
661{
662 ServerList servers; // Variable to capture the NTP Server IPs
663 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
664 PROPERTY_INTERFACE, METHOD_GET);
665
666 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
667
668 try
669 {
670 auto reply = bus.call(method);
671 std::variant<ServerList> response;
672 reply.read(response);
673 servers = std::get<ServerList>(response);
674 }
675 catch (const sdbusplus::exception::SdBusError& e)
676 {
677 log<level::ERR>(
678 "Failed to get NTP server information from Systemd-Timesyncd");
679 }
680
681 return servers;
682}
683
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530684ServerList EthernetInterface::getNameServerFromResolvd()
685{
686 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700687 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530688
689 /*
690 The DNS property under org.freedesktop.resolve1.Link interface contains
691 an array containing all DNS servers currently used by resolved. It
692 contains similar information as the DNS server data written to
693 /run/systemd/resolve/resolv.conf.
694
695 Each structure in the array consists of a numeric network interface index,
696 an address family, and a byte array containing the DNS server address
697 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
698 The array contains DNS servers configured system-wide, including those
699 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
700 /etc/systemd/resolved.conf, as well as per-interface DNS server
701 information either retrieved from systemd-networkd or configured by
702 external software via SetLinkDNS().
703 */
704
705 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
706 std::variant<type> name; // Variable to capture the DNS property
707 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
708 PROPERTY_INTERFACE, METHOD_GET);
709
710 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530711
712 try
713 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500714 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530715 reply.read(name);
716 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500717 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530718 {
719 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
720 }
721 auto tupleVector = std::get_if<type>(&name);
722 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
723 {
Alexander Filippov983da552021-02-08 15:26:54 +0300724 int addressFamily = std::get<0>(*i);
725 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700726 servers.push_back(std::to_string(
727 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530728 }
729 return servers;
730}
731
William A. Kennington IIId298f932022-10-17 14:31:38 -0700732ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530733{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700734 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
735 auto idStr = std::to_string(id);
736 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800737 {
738 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700739 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
740 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800741 }
742
William A. Kennington IIId298f932022-10-17 14:31:38 -0700743 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700744 auto macStr = MacAddressIntf::macAddress();
745 std::optional<ether_addr> mac;
746 if (!macStr.empty())
747 {
748 mac.emplace(mac_address::fromString(macStr));
749 }
750 auto info = system::InterfaceInfo{
751 .idx = 0, // TODO: Query the correct value after creation
752 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700753 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700754 .mac = std::move(mac),
755 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700756 .parent_idx = ifIdx,
757 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700758 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530759
Patrick Williams6aef7692021-05-01 06:39:41 -0500760 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530761 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700762 auto vlanIntf = std::make_unique<EthernetInterface>(
763 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700764 nicEnabled());
765 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530766
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700767 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530768
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700769 // write the device file for the vlan interface.
770 config::Parser config;
771 auto& netdev = config.map["NetDev"].emplace_back();
772 netdev["Name"].emplace_back(intfName);
773 netdev["Kind"].emplace_back("vlan");
774 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
775 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700776
777 writeConfigurationFile();
778 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700779
William A. Kennington IIId298f932022-10-17 14:31:38 -0700780 return objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530781}
Ratan Gupta2b106532017-07-25 16:05:02 +0530782
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600783ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530784{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600785 try
786 {
787 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530788
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600789 writeConfigurationFile();
790 manager.reloadConfigs();
791 }
792 catch (InternalFailure& e)
793 {
794 log<level::ERR>("Exception processing NTP entries");
795 }
796 return EthernetInterfaceIntf::staticNTPServers();
797}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700798
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600799ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
800{
801 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530802}
Ratan Gupta2b106532017-07-25 16:05:02 +0530803// Need to merge the below function with the code which writes the
804// config file during factory reset.
805// TODO openbmc/openbmc#1751
806
807void EthernetInterface::writeConfigurationFile()
808{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700809 config::Parser config;
810 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530811 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700812 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800813#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700814 auto mac = MacAddressIntf::macAddress();
815 if (!mac.empty())
816 {
817 link["MACAddress"].emplace_back(mac);
818 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800819#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700820 if (!EthernetInterfaceIntf::nicEnabled())
821 {
822 link["Unmanaged"].emplace_back("yes");
823 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700824 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700825 {
826 auto& network = config.map["Network"].emplace_back();
827 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400828#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700829 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400830#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700831 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400832#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700833 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
834 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
835 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600836 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700837 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700838 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700839 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700840 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
841 {
842 vlans.emplace_back(intf->interfaceName());
843 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700844 }
845 }
846 {
847 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600848 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700849 {
850 ntps.emplace_back(ntp);
851 }
852 }
853 {
854 auto& dnss = network["DNS"];
855 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
856 {
857 dnss.emplace_back(dns);
858 }
859 }
860 {
861 auto& address = network["Address"];
862 for (const auto& addr : getAddresses())
863 {
864 if (originIsManuallyAssigned(addr.second->origin()) &&
865 !dhcpIsEnabled(addr.second->type()))
866 {
867 address.emplace_back(
868 fmt::format("{}/{}", addr.second->address(),
869 addr.second->prefixLength()));
870 }
871 }
872 }
873 {
874 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700875 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700876 {
877 auto gateway = EthernetInterfaceIntf::defaultGateway();
878 if (!gateway.empty())
879 {
880 gateways.emplace_back(gateway);
881 }
882 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530883
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700884 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700885 {
886 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
887 if (!gateway6.empty())
888 {
889 gateways.emplace_back(gateway6);
890 }
891 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600892 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800893 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700894 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700895 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500896 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700897 auto& neighbors = config.map["Neighbor"];
898 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800899 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700900 auto& neighbor = neighbors.emplace_back();
901 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
902 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800903 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500904 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500905 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700906 auto& dhcp = config.map["DHCP"].emplace_back();
907 dhcp["ClientIdentifier"].emplace_back("mac");
908 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800909 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700910 const auto& conf = *manager.getDHCPConf();
911 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
912 dhcp["UseDNS"].emplace_back(dns_enabled);
913 dhcp["UseDomains"].emplace_back(dns_enabled);
914 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
915 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
916 : "false");
917 dhcp["SendHostname"].emplace_back(
918 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800919 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500920 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700921 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
922 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700923 auto msg = fmt::format("Wrote networkd file: {}", path.native());
924 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530925}
926
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800927std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530928{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700929 if (vlan)
930 {
931 log<level::ERR>("Tried to set MAC address on VLAN");
932 elog<InternalFailure>();
933 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800934#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600935 ether_addr newMAC;
936 try
937 {
938 newMAC = mac_address::fromString(value);
939 }
Patrick Williams5758db32021-10-06 12:29:22 -0500940 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600941 {
942 log<level::ERR>("MACAddress is not valid.",
943 entry("MAC=%s", value.c_str()));
944 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
945 Argument::ARGUMENT_VALUE(value.c_str()));
946 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700947 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530948 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500949 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500950 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500951 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
952 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530953 }
954
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300955 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700956 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300957
William A. Kennington III1137a972019-04-20 20:49:58 -0700958 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -0500959 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700960 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530961 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700962 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700963 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530964 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700965 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
966 {
967 intf->MacAddressIntf::macAddress(validMAC);
968 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530969 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500970 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530971
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700972 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800973 manager.addReloadPreHook([interface]() {
974 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700975 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800976 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700977 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530978 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700979
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300980#ifdef HAVE_UBOOT_ENV
981 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700982 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300983 if (envVar)
984 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500985 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
986 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
987 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
988 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300989 }
990#endif // HAVE_UBOOT_ENV
991
William A. Kennington III1137a972019-04-20 20:49:58 -0700992 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800993#else
994 elog<NotAllowed>(
995 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
996#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530997}
998
Ratan Guptae9c9b812017-09-22 17:15:37 +0530999void EthernetInterface::deleteAll()
1000{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301001 // clear all the ip on the interface
1002 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001003
1004 writeConfigurationFile();
1005 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301006}
1007
Ravi Tejaa5a09442020-07-17 00:57:33 -05001008std::string EthernetInterface::defaultGateway(std::string gateway)
1009{
1010 auto gw = EthernetInterfaceIntf::defaultGateway();
1011 if (gw == gateway)
1012 {
1013 return gw;
1014 }
1015
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001016 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001017 {
1018 log<level::ERR>("Not a valid v4 Gateway",
1019 entry("GATEWAY=%s", gateway.c_str()));
1020 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1021 Argument::ARGUMENT_VALUE(gateway.c_str()));
1022 }
1023 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001024
1025 writeConfigurationFile();
1026 manager.reloadConfigs();
1027
Ravi Tejaa5a09442020-07-17 00:57:33 -05001028 return gw;
1029}
1030
1031std::string EthernetInterface::defaultGateway6(std::string gateway)
1032{
1033 auto gw = EthernetInterfaceIntf::defaultGateway6();
1034 if (gw == gateway)
1035 {
1036 return gw;
1037 }
1038
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001039 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001040 {
1041 log<level::ERR>("Not a valid v6 Gateway",
1042 entry("GATEWAY=%s", gateway.c_str()));
1043 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1044 Argument::ARGUMENT_VALUE(gateway.c_str()));
1045 }
1046 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001047
1048 writeConfigurationFile();
1049 manager.reloadConfigs();
1050
Ravi Tejaa5a09442020-07-17 00:57:33 -05001051 return gw;
1052}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001053
1054EthernetInterface::VlanProperties::VlanProperties(
1055 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
1056 const system::InterfaceInfo& info, EthernetInterface& eth,
1057 bool emitSignal) :
1058 VlanIfaces(bus, objPath.c_str(),
1059 emitSignal ? VlanIfaces::action::defer_emit
1060 : VlanIfaces::action::emit_no_signals),
1061 parentIdx(*info.parent_idx), eth(eth)
1062{
1063 VlanIntf::id(*info.vlan_id);
1064 if (emitSignal)
1065 {
1066 this->emit_object_added();
1067 }
1068}
1069
1070void EthernetInterface::VlanProperties::delete_()
1071{
1072 auto intf = eth.interfaceName();
1073
1074 // Remove all configs for the current interface
1075 const auto& confDir = eth.manager.getConfDir();
1076 std::error_code ec;
1077 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1078 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1079
1080 // Write an updated parent interface since it has a VLAN entry
1081 for (const auto& [_, intf] : eth.manager.interfaces)
1082 {
1083 if (intf->ifIdx == parentIdx)
1084 {
1085 intf->writeConfigurationFile();
1086 }
1087 }
1088
1089 // We need to forcibly delete the interface as systemd does not
1090 deleteInterface(intf);
1091
1092 eth.manager.interfaces.erase(intf);
1093}
1094
Gunnar Mills57d9c502018-09-14 14:42:34 -05001095} // namespace network
1096} // namespace phosphor