blob: 021c126a3f9c144fa831b73b6d215b5da983d460 [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
Ratan Gupta29b0e432017-05-25 12:51:40 +0530142 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530143 if (emitSignal)
144 {
145 this->emit_object_added();
146 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530147}
148
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700149void EthernetInterface::updateInfo(const system::InterfaceInfo& info)
William A. Kennington IIId298f932022-10-17 14:31:38 -0700150{
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700151 EthernetInterfaceIntf::linkUp(info.flags & IFF_RUNNING);
William A. Kennington IIId298f932022-10-17 14:31:38 -0700152 if (info.mac)
153 {
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700154 MacAddressIntf::macAddress(std::to_string(*info.mac));
William A. Kennington IIId298f932022-10-17 14:31:38 -0700155 }
156 if (info.mtu)
157 {
158 EthernetInterfaceIntf::mtu(*info.mtu);
159 }
160}
161
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700162static IP::Protocol getProtocol(const InAddrAny& addr)
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800163{
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700164 if (std::holds_alternative<in_addr>(addr))
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800165 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700166 return IP::Protocol::IPv4;
167 }
168 else if (std::holds_alternative<in6_addr>(addr))
169 {
170 return IP::Protocol::IPv6;
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800171 }
172
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700173 throw std::runtime_error("Invalid addr type");
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800174}
175
William A. Kennington III24957b92021-12-03 13:59:19 -0800176bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800177{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700178 switch (family)
179 {
180 case IP::Protocol::IPv6:
181 return dhcp6();
182 case IP::Protocol::IPv4:
183 return dhcp4();
184 }
185 throw std::logic_error("Unreachable");
Johnathan Mantey817012a2020-01-30 15:07:39 -0800186}
187
Johnathan Mantey817012a2020-01-30 15:07:39 -0800188bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
189{
190 return (
191#ifdef LINK_LOCAL_AUTOCONFIGURATION
192 (origin == IP::AddressOrigin::Static)
193#else
194 (origin == IP::AddressOrigin::Static ||
195 origin == IP::AddressOrigin::LinkLocal)
196#endif
197
198 );
199}
200
Ratan Gupta87c13982017-06-15 09:27:27 +0530201void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530202{
Ratan Gupta87c13982017-06-15 09:27:27 +0530203 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530204
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700205 AddressFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700206 filter.interface = ifIdx;
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700207 auto currentAddrs = getCurrentAddresses(filter);
208 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530209 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700210 if (addr.flags & IFA_F_DEPRECATED)
211 {
212 continue;
213 }
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700214 auto address = std::to_string(addr.address);
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700215 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800216 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800217 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530218 {
219 origin = IP::AddressOrigin::DHCP;
220 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400221#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700222 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530223 {
224 origin = IP::AddressOrigin::LinkLocal;
225 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400226#endif
Ratan Gupta82549cc2017-04-21 08:45:23 +0530227
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700228 auto ipAddressObjectPath =
229 generateObjectPath(addressType, address, addr.prefix, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530230
Lei YU7233c582021-04-08 14:39:43 +0800231 this->addrs.insert_or_assign(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700232 address, std::make_unique<IPAddress>(bus, ipAddressObjectPath,
233 *this, addressType, address,
234 origin, addr.prefix));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530235 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530236}
237
William A. Kennington III08505792019-01-30 16:00:04 -0800238void EthernetInterface::createStaticNeighborObjects()
239{
240 staticNeighbors.clear();
241
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700242 NeighborFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700243 filter.interface = ifIdx;
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700244 filter.state = NUD_PERMANENT;
245 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800246 for (const auto& neighbor : neighbors)
247 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700248 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800249 {
250 continue;
251 }
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700252 auto ip = std::to_string(neighbor.address);
253 auto mac = std::to_string(*neighbor.mac);
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700254 auto objectPath = generateStaticNeighborObjectPath(ip, mac);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700255 staticNeighbors.emplace(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700256 ip, std::make_unique<Neighbor>(bus, objectPath, *this, ip, mac,
257 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800258 }
259}
260
Patrick Williams6aef7692021-05-01 06:39:41 -0500261ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700262 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530263{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800264 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530265 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700266 log<level::INFO>("DHCP enabled on the interface, disabling"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500267 entry("INTERFACE=%s", interfaceName().c_str());
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700268 switch (protType)
269 {
270 case IP::Protocol::IPv4:
271 dhcp4(false);
272 break;
273 case IP::Protocol::IPv6:
274 dhcp6(false);
275 break;
276 }
Ravi Teja07450442022-07-07 04:30:57 -0500277 // Delete the IP address object and that reloads the networkd
278 // to allow the same IP address to be set as Static IP
279 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500280 }
281
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500282 IP::AddressOrigin origin = IP::AddressOrigin::Static;
283
284 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
285
286 if (!isValidIP(addressFamily, ipaddress))
287 {
288 log<level::ERR>("Not a valid IP address"),
289 entry("ADDRESS=%s", ipaddress.c_str());
290 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
291 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
292 }
293
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500294 if (!isValidPrefix(addressFamily, prefixLength))
295 {
296 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700297 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500298 elog<InvalidArgument>(
299 Argument::ARGUMENT_NAME("prefixLength"),
300 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530301 }
302
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700303 auto objectPath =
304 generateObjectPath(protType, ipaddress, prefixLength, origin);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700305 this->addrs.insert_or_assign(
306 ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700307 std::make_unique<IPAddress>(bus, objectPath, *this, protType, ipaddress,
308 origin, prefixLength));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530309
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700310 writeConfigurationFile();
311 manager.reloadConfigs();
312
raviteja-bce379562019-03-28 05:59:36 -0500313 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530314}
315
Patrick Williams6aef7692021-05-01 06:39:41 -0500316ObjectPath EthernetInterface::neighbor(std::string ipAddress,
317 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800318{
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700319 if (!isValidIP(ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800320 {
321 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500322 entry("ADDRESS=%s", ipAddress.c_str()));
323 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
324 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800325 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500326 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800327 {
328 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500329 entry("MACADDRESS=%s", ipAddress.c_str()));
330 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
331 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800332 }
333
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700334 auto objectPath = generateStaticNeighborObjectPath(ipAddress, macAddress);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700335 staticNeighbors.emplace(
336 ipAddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700337 std::make_unique<Neighbor>(bus, objectPath, *this, ipAddress,
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700338 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700339
340 writeConfigurationFile();
341 manager.reloadConfigs();
342
William A. Kennington III08505792019-01-30 16:00:04 -0800343 return objectPath;
344}
345
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700346void EthernetInterface::deleteObject(std::string_view ipaddress)
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530347{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530348 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530349 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530350 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530351 log<level::ERR>("DeleteObject:Unable to find the object.");
352 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530353 }
354 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700355
356 writeConfigurationFile();
357 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530358}
359
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700360void EthernetInterface::deleteStaticNeighborObject(std::string_view ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800361{
Patrick Williams6aef7692021-05-01 06:39:41 -0500362 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800363 if (it == staticNeighbors.end())
364 {
365 log<level::ERR>(
366 "DeleteStaticNeighborObject:Unable to find the object.");
367 return;
368 }
369 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700370
371 writeConfigurationFile();
372 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800373}
374
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700375void EthernetInterface::deleteVLANFromSystem(stdplus::zstring_view interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530376{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700377 const auto& confDir = manager.getConfDir();
378 auto networkFile = config::pathForIntfConf(confDir, interface);
379 auto deviceFile = config::pathForIntfDev(confDir, interface);
Ratan Guptabc886292017-07-25 18:29:57 +0530380
381 // delete the vlan network file
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700382 std::error_code ec;
William A. Kennington III95530ec2022-08-19 01:44:39 -0700383 std::filesystem::remove(networkFile, ec);
384 std::filesystem::remove(deviceFile, ec);
Ratan Guptabc886292017-07-25 18:29:57 +0530385
386 // TODO systemd doesn't delete the virtual network interface
387 // even after deleting all the related configuartion.
388 // https://github.com/systemd/systemd/issues/6600
389 try
390 {
391 deleteInterface(interface);
392 }
Patrick Williams5758db32021-10-06 12:29:22 -0500393 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530394 {
395 commit<InternalFailure>();
396 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530397}
398
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700399void EthernetInterface::deleteVLANObject(stdplus::zstring_view interface)
Ratan Guptae9c9b812017-09-22 17:15:37 +0530400{
401 auto it = vlanInterfaces.find(interface);
402 if (it == vlanInterfaces.end())
403 {
404 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500405 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530406 return;
407 }
408
409 deleteVLANFromSystem(interface);
410 // delete the interface
411 vlanInterfaces.erase(it);
412
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700413 writeConfigurationFile();
414 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530415}
416
Gunnar Mills57d9c502018-09-14 14:42:34 -0500417std::string EthernetInterface::generateObjectPath(
William A. Kennington III991a8e82022-10-11 15:02:47 -0700418 IP::Protocol addressType, std::string_view ipAddress, uint8_t prefixLength,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700419 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530420{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700421 std::string_view type;
422 switch (addressType)
423 {
424 case IP::Protocol::IPv4:
425 type = "ipv4"sv;
426 break;
427 case IP::Protocol::IPv6:
428 type = "ipv6"sv;
429 break;
430 }
431 return fmt::format(
432 FMT_COMPILE("{}/{}/{:08x}"), objPath, type,
433 static_cast<uint32_t>(hash_multi(
434 ipAddress, prefixLength,
435 static_cast<std::underlying_type_t<IP::AddressOrigin>>(origin))));
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530436}
437
William A. Kennington III08505792019-01-30 16:00:04 -0800438std::string EthernetInterface::generateStaticNeighborObjectPath(
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700439 std::string_view ipAddress, std::string_view macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800440{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700441 return fmt::format(
442 FMT_COMPILE("{}/static_neighbor/{:08x}"), objPath,
443 static_cast<uint32_t>(hash_multi(ipAddress, macAddress)));
William A. Kennington III08505792019-01-30 16:00:04 -0800444}
445
Patrick Williams6aef7692021-05-01 06:39:41 -0500446bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700447{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700448 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700449 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700450 writeConfigurationFile();
451 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700452 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700453 return value;
454}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700455
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700456bool EthernetInterface::dhcp4(bool value)
457{
458 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
459 {
460 writeConfigurationFile();
461 manager.reloadConfigs();
462 }
463 return value;
464}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700465
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700466bool EthernetInterface::dhcp6(bool value)
467{
468 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
469 {
470 writeConfigurationFile();
471 manager.reloadConfigs();
472 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700473 return value;
474}
475
Patrick Williams6aef7692021-05-01 06:39:41 -0500476EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530477{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700478 auto old4 = EthernetInterfaceIntf::dhcp4();
479 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
480 value == DHCPConf::v4v6stateless ||
481 value == DHCPConf::both);
482 auto old6 = EthernetInterfaceIntf::dhcp6();
483 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
484 value == DHCPConf::both);
485 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
486 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
487 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
488 value == DHCPConf::v6 || value == DHCPConf::both);
489
490 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530491 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700492 writeConfigurationFile();
493 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530494 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530495 return value;
496}
497
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700498EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
499{
500 if (dhcp6())
501 {
502 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
503 }
504 else if (dhcp4())
505 {
506 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
507 }
508 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
509}
510
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800511bool EthernetInterface::linkUp() const
512{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700513 if (ifIdx == 0)
514 {
515 return EthernetInterfaceIntf::linkUp();
516 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700517 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700518}
519
Tejas Patil2c0fc562021-08-03 19:13:46 +0530520size_t EthernetInterface::mtu() const
521{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700522 if (ifIdx == 0)
523 {
524 return EthernetInterfaceIntf::mtu();
525 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700526 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700527 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700528 [&] { return system::getMTU(ifname); })
529 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530530}
531
532size_t EthernetInterface::mtu(size_t value)
533{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700534 const size_t old = EthernetInterfaceIntf::mtu();
535 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530536 {
537 return value;
538 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700539 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700540 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700541 system::setMTU(ifname, value);
542 return value;
543 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530544}
545
William A. Kennington III26275a32021-07-13 20:32:42 -0700546bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700547{
William A. Kennington III26275a32021-07-13 20:32:42 -0700548 constexpr auto svc = "org.freedesktop.network1";
549 constexpr auto intf = "org.freedesktop.network1.Link";
550 constexpr auto prop = "AdministrativeState";
551 char* rpath;
552 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700553 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700554 std::string path(rpath);
555 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700556
William A. Kennington III26275a32021-07-13 20:32:42 -0700557 // Store / Parser for the AdministrativeState return value
558 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700559 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700560 if (state != "initialized")
561 {
562 ret = state != "unmanaged";
563 }
564 };
565
566 // Build a matcher before making the property call to ensure we
567 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500568 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700569 bus,
570 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
571 "'PropertiesChanged',arg0='{}',",
572 svc, path, PROPERTY_INTERFACE, intf)
573 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500574 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700575 std::string intf;
576 std::unordered_map<std::string, std::variant<std::string>> values;
577 try
578 {
579 m.read(intf, values);
580 auto it = values.find(prop);
581 // Ignore properties that aren't AdministrativeState
582 if (it != values.end())
583 {
584 cb(std::get<std::string>(it->second));
585 }
586 }
587 catch (const std::exception& e)
588 {
589 log<level::ERR>(
590 fmt::format(
591 "AdministrativeState match parsing failed on {}: {}",
592 interfaceName(), e.what())
593 .c_str(),
594 entry("INTERFACE=%s", interfaceName().c_str()),
595 entry("ERROR=%s", e.what()));
596 }
597 });
598
599 // Actively call for the value in case the interface is already configured
600 auto method =
601 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
602 method.append(intf, prop);
603 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700604 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700605 auto reply = bus.call(method);
606 std::variant<std::string> state;
607 reply.read(state);
608 cb(std::get<std::string>(state));
609 }
610 catch (const std::exception& e)
611 {
612 log<level::ERR>(
613 fmt::format("Failed to get AdministrativeState on {}: {}",
614 interfaceName(), e.what())
615 .c_str(),
616 entry("INTERFACE=%s", interfaceName().c_str()),
617 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700618 }
619
William A. Kennington III26275a32021-07-13 20:32:42 -0700620 // The interface is not yet configured by systemd-networkd, wait until it
621 // signals us a valid state.
622 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700623 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700624 bus.wait();
625 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700626 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700627
628 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700629}
630
Patrick Williams6aef7692021-05-01 06:39:41 -0500631bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700632{
Patrick Williams6aef7692021-05-01 06:39:41 -0500633 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700634 {
635 return value;
636 }
637
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800638 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700639 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800640 if (!value)
641 {
642 // We only need to bring down the interface, networkd will always bring
643 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700644 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700645 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800646 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700647 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800648
649 return value;
650}
651
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530652ServerList EthernetInterface::staticNameServers(ServerList value)
653{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530654 for (const auto& nameserverip : value)
655 {
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700656 if (!isValidIP(nameserverip))
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530657 {
658 log<level::ERR>("Not a valid IP address"),
659 entry("ADDRESS=%s", nameserverip.c_str());
660 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530661 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530662 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
663 }
664 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530665 try
666 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530667 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700668
Ratan Gupta6dec3902017-08-20 15:28:12 +0530669 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700670 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530671 }
Patrick Williams5758db32021-10-06 12:29:22 -0500672 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530673 {
674 log<level::ERR>("Exception processing DNS entries");
675 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530676 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530677}
678
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600679void EthernetInterface::loadNTPServers(const config::Parser& config)
680{
681 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
682 EthernetInterfaceIntf::staticNTPServers(
683 config.map.getValueStrings("Network", "NTP"));
684}
685
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700686void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530687{
688 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700689 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700690 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530691}
692
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600693ServerList EthernetInterface::getNTPServerFromTimeSyncd()
694{
695 ServerList servers; // Variable to capture the NTP Server IPs
696 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
697 PROPERTY_INTERFACE, METHOD_GET);
698
699 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
700
701 try
702 {
703 auto reply = bus.call(method);
704 std::variant<ServerList> response;
705 reply.read(response);
706 servers = std::get<ServerList>(response);
707 }
708 catch (const sdbusplus::exception::SdBusError& e)
709 {
710 log<level::ERR>(
711 "Failed to get NTP server information from Systemd-Timesyncd");
712 }
713
714 return servers;
715}
716
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530717ServerList EthernetInterface::getNameServerFromResolvd()
718{
719 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700720 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530721
722 /*
723 The DNS property under org.freedesktop.resolve1.Link interface contains
724 an array containing all DNS servers currently used by resolved. It
725 contains similar information as the DNS server data written to
726 /run/systemd/resolve/resolv.conf.
727
728 Each structure in the array consists of a numeric network interface index,
729 an address family, and a byte array containing the DNS server address
730 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
731 The array contains DNS servers configured system-wide, including those
732 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
733 /etc/systemd/resolved.conf, as well as per-interface DNS server
734 information either retrieved from systemd-networkd or configured by
735 external software via SetLinkDNS().
736 */
737
738 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
739 std::variant<type> name; // Variable to capture the DNS property
740 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
741 PROPERTY_INTERFACE, METHOD_GET);
742
743 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530744
745 try
746 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500747 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530748 reply.read(name);
749 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500750 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530751 {
752 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
753 }
754 auto tupleVector = std::get_if<type>(&name);
755 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
756 {
Alexander Filippov983da552021-02-08 15:26:54 +0300757 int addressFamily = std::get<0>(*i);
758 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700759 servers.push_back(std::to_string(
760 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530761 }
762 return servers;
763}
764
William A. Kennington IIId298f932022-10-17 14:31:38 -0700765std::string EthernetInterface::vlanIntfName(uint16_t id) const
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700766{
767 return fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
768}
769
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700770void EthernetInterface::loadVLAN(std::string_view objRoot, uint16_t id,
771 system::InterfaceInfo&& info)
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530772{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700773 config::Parser config(
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700774 config::pathForIntfConf(manager.getConfDir(), *info.name));
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530775 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700776 bus, manager, info, objRoot, config, id, *this);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530777
Gunnar Mills57d9c502018-09-14 14:42:34 -0500778 // Fetch the ip address from the system
779 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530780 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800781 vlanIntf->createStaticNeighborObjects();
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700782 vlanIntf->loadNameServers(config);
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600783 vlanIntf->loadNTPServers(config);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530784
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700785 this->vlanInterfaces.emplace(std::move(*info.name), std::move(vlanIntf));
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530786}
787
William A. Kennington IIId298f932022-10-17 14:31:38 -0700788ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530789{
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700790 auto vlanInterfaceName = vlanIntfName(id);
791 if (this->vlanInterfaces.find(vlanInterfaceName) !=
792 this->vlanInterfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800793 {
794 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
795 elog<InvalidArgument>(
796 Argument::ARGUMENT_NAME("VLANId"),
797 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
798 }
799
William A. Kennington IIId298f932022-10-17 14:31:38 -0700800 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700801 auto macStr = MacAddressIntf::macAddress();
802 std::optional<ether_addr> mac;
803 if (!macStr.empty())
804 {
805 mac.emplace(mac_address::fromString(macStr));
806 }
807 auto info = system::InterfaceInfo{
808 .idx = 0, // TODO: Query the correct value after creation
809 .flags = 0,
810 .name = vlanInterfaceName,
811 .mac = std::move(mac),
812 .mtu = mtu(),
813 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530814
Patrick Williams6aef7692021-05-01 06:39:41 -0500815 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530816 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530817 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
William A. Kennington IIId298f932022-10-17 14:31:38 -0700818 bus, manager, info, objRoot, config::Parser(), id, *this, /*emit=*/true,
819 nicEnabled());
820 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530821
822 // write the device file for the vlan interface.
823 vlanIntf->writeDeviceFile();
824
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700825 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
826 std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700827
828 writeConfigurationFile();
829 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700830
William A. Kennington IIId298f932022-10-17 14:31:38 -0700831 return objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530832}
Ratan Gupta2b106532017-07-25 16:05:02 +0530833
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600834ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530835{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600836 try
837 {
838 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530839
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600840 writeConfigurationFile();
841 manager.reloadConfigs();
842 }
843 catch (InternalFailure& e)
844 {
845 log<level::ERR>("Exception processing NTP entries");
846 }
847 return EthernetInterfaceIntf::staticNTPServers();
848}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700849
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600850ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
851{
852 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530853}
Ratan Gupta2b106532017-07-25 16:05:02 +0530854// Need to merge the below function with the code which writes the
855// config file during factory reset.
856// TODO openbmc/openbmc#1751
857
858void EthernetInterface::writeConfigurationFile()
859{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500860 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530861 {
862 intf.second->writeConfigurationFile();
863 }
864
William A. Kennington III95a49a22022-08-18 17:50:05 -0700865 config::Parser config;
866 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530867 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700868 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800869#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700870 auto mac = MacAddressIntf::macAddress();
871 if (!mac.empty())
872 {
873 link["MACAddress"].emplace_back(mac);
874 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800875#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700876 if (!EthernetInterfaceIntf::nicEnabled())
877 {
878 link["Unmanaged"].emplace_back("yes");
879 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700880 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700881 {
882 auto& network = config.map["Network"].emplace_back();
883 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400884#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700885 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400886#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700887 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400888#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700889 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
890 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
891 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600892 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700893 auto& vlans = network["VLAN"];
894 for (const auto& intf : vlanInterfaces)
895 {
896 vlans.emplace_back(
897 intf.second->EthernetInterface::interfaceName());
898 }
899 }
900 {
901 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600902 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700903 {
904 ntps.emplace_back(ntp);
905 }
906 }
907 {
908 auto& dnss = network["DNS"];
909 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
910 {
911 dnss.emplace_back(dns);
912 }
913 }
914 {
915 auto& address = network["Address"];
916 for (const auto& addr : getAddresses())
917 {
918 if (originIsManuallyAssigned(addr.second->origin()) &&
919 !dhcpIsEnabled(addr.second->type()))
920 {
921 address.emplace_back(
922 fmt::format("{}/{}", addr.second->address(),
923 addr.second->prefixLength()));
924 }
925 }
926 }
927 {
928 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700929 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700930 {
931 auto gateway = EthernetInterfaceIntf::defaultGateway();
932 if (!gateway.empty())
933 {
934 gateways.emplace_back(gateway);
935 }
936 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530937
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700938 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700939 {
940 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
941 if (!gateway6.empty())
942 {
943 gateways.emplace_back(gateway6);
944 }
945 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600946 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800947 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700948 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700949 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500950 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700951 auto& neighbors = config.map["Neighbor"];
952 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800953 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700954 auto& neighbor = neighbors.emplace_back();
955 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
956 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800957 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500958 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500959 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700960 auto& dhcp = config.map["DHCP"].emplace_back();
961 dhcp["ClientIdentifier"].emplace_back("mac");
962 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800963 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700964 const auto& conf = *manager.getDHCPConf();
965 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
966 dhcp["UseDNS"].emplace_back(dns_enabled);
967 dhcp["UseDomains"].emplace_back(dns_enabled);
968 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
969 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
970 : "false");
971 dhcp["SendHostname"].emplace_back(
972 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800973 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500974 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700975 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
976 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700977 auto msg = fmt::format("Wrote networkd file: {}", path.native());
978 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530979}
980
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800981std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530982{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800983#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600984 ether_addr newMAC;
985 try
986 {
987 newMAC = mac_address::fromString(value);
988 }
Patrick Williams5758db32021-10-06 12:29:22 -0500989 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600990 {
991 log<level::ERR>("MACAddress is not valid.",
992 entry("MAC=%s", value.c_str()));
993 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
994 Argument::ARGUMENT_VALUE(value.c_str()));
995 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700996 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530997 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500998 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500999 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001000 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1001 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301002 }
1003
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001004 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -07001005 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001006
William A. Kennington III1137a972019-04-20 20:49:58 -07001007 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001008 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -07001009 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +05301010 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001011 // Update everything that depends on the MAC value
1012 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301013 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001014 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301015 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001016 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301017
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001018 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001019 manager.addReloadPreHook([interface]() {
1020 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -07001021 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001022 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001023 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301024 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001025
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001026#ifdef HAVE_UBOOT_ENV
1027 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -07001028 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001029 if (envVar)
1030 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001031 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1032 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1033 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1034 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001035 }
1036#endif // HAVE_UBOOT_ENV
1037
William A. Kennington III1137a972019-04-20 20:49:58 -07001038 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001039#else
1040 elog<NotAllowed>(
1041 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1042#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301043}
1044
Ratan Guptae9c9b812017-09-22 17:15:37 +05301045void EthernetInterface::deleteAll()
1046{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301047 // clear all the ip on the interface
1048 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001049
1050 writeConfigurationFile();
1051 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301052}
1053
Ravi Tejaa5a09442020-07-17 00:57:33 -05001054std::string EthernetInterface::defaultGateway(std::string gateway)
1055{
1056 auto gw = EthernetInterfaceIntf::defaultGateway();
1057 if (gw == gateway)
1058 {
1059 return gw;
1060 }
1061
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001062 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001063 {
1064 log<level::ERR>("Not a valid v4 Gateway",
1065 entry("GATEWAY=%s", gateway.c_str()));
1066 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1067 Argument::ARGUMENT_VALUE(gateway.c_str()));
1068 }
1069 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001070
1071 writeConfigurationFile();
1072 manager.reloadConfigs();
1073
Ravi Tejaa5a09442020-07-17 00:57:33 -05001074 return gw;
1075}
1076
1077std::string EthernetInterface::defaultGateway6(std::string gateway)
1078{
1079 auto gw = EthernetInterfaceIntf::defaultGateway6();
1080 if (gw == gateway)
1081 {
1082 return gw;
1083 }
1084
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001085 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001086 {
1087 log<level::ERR>("Not a valid v6 Gateway",
1088 entry("GATEWAY=%s", gateway.c_str()));
1089 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1090 Argument::ARGUMENT_VALUE(gateway.c_str()));
1091 }
1092 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001093
1094 writeConfigurationFile();
1095 manager.reloadConfigs();
1096
Ravi Tejaa5a09442020-07-17 00:57:33 -05001097 return gw;
1098}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001099} // namespace network
1100} // namespace phosphor