blob: b1ada82a9ebd2acb6497914873a3b7c369c4ef97 [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());
Ravi Tejaa5a09442020-07-17 00:57:33 -0500103 {
William A. Kennington III2bd35d62022-10-26 19:20:29 -0700104 const auto& gws = manager.getRouteTable().getDefaultGateway();
105 auto it = gws.find(ifIdx);
106 if (it != gws.end())
Ravi Tejaa5a09442020-07-17 00:57:33 -0500107 {
William A. Kennington III2bd35d62022-10-26 19:20:29 -0700108 EthernetInterfaceIntf::defaultGateway(std::to_string(it->second));
109 }
110 }
111 {
112 const auto& gws = manager.getRouteTable().getDefaultGateway6();
113 auto it = gws.find(ifIdx);
114 if (it != gws.end())
115 {
116 EthernetInterfaceIntf::defaultGateway6(std::to_string(it->second));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500117 }
118 }
119
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700120 EthernetInterfaceIntf::ntpServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700121 config.map.getValueStrings("Network", "NTP"));
Ratan Gupta613a0122020-04-24 15:18:53 +0530122
William A. Kennington III3e471c52022-10-27 19:46:07 -0700123 if (ifIdx > 0)
124 {
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700125 auto ethInfo = ignoreError("GetEthInfo", *info.name, {}, [&] {
126 return system::getEthInfo(*info.name);
William A. Kennington III3e471c52022-10-27 19:46:07 -0700127 });
128 EthernetInterfaceIntf::autoNeg(ethInfo.autoneg);
129 EthernetInterfaceIntf::speed(ethInfo.speed);
130 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530131
William A. Kennington IIId298f932022-10-17 14:31:38 -0700132 updateInfo(info);
133
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700134 if (info.vlan_id)
135 {
136 if (!info.parent_idx)
137 {
138 std::runtime_error("Missing parent link");
139 }
140 vlan.emplace(bus, this->objPath.c_str(), info, *this, emitSignal);
141 }
142
Ratan Gupta29b0e432017-05-25 12:51:40 +0530143 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530144 if (emitSignal)
145 {
146 this->emit_object_added();
147 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530148}
149
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700150void EthernetInterface::updateInfo(const system::InterfaceInfo& info)
William A. Kennington IIId298f932022-10-17 14:31:38 -0700151{
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700152 EthernetInterfaceIntf::linkUp(info.flags & IFF_RUNNING);
William A. Kennington IIId298f932022-10-17 14:31:38 -0700153 if (info.mac)
154 {
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700155 MacAddressIntf::macAddress(std::to_string(*info.mac));
William A. Kennington IIId298f932022-10-17 14:31:38 -0700156 }
157 if (info.mtu)
158 {
159 EthernetInterfaceIntf::mtu(*info.mtu);
160 }
161}
162
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700163static IP::Protocol getProtocol(const InAddrAny& addr)
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800164{
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700165 if (std::holds_alternative<in_addr>(addr))
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800166 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700167 return IP::Protocol::IPv4;
168 }
169 else if (std::holds_alternative<in6_addr>(addr))
170 {
171 return IP::Protocol::IPv6;
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800172 }
173
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700174 throw std::runtime_error("Invalid addr type");
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800175}
176
William A. Kennington III24957b92021-12-03 13:59:19 -0800177bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800178{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700179 switch (family)
180 {
181 case IP::Protocol::IPv6:
182 return dhcp6();
183 case IP::Protocol::IPv4:
184 return dhcp4();
185 }
186 throw std::logic_error("Unreachable");
Johnathan Mantey817012a2020-01-30 15:07:39 -0800187}
188
Johnathan Mantey817012a2020-01-30 15:07:39 -0800189bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
190{
191 return (
192#ifdef LINK_LOCAL_AUTOCONFIGURATION
193 (origin == IP::AddressOrigin::Static)
194#else
195 (origin == IP::AddressOrigin::Static ||
196 origin == IP::AddressOrigin::LinkLocal)
197#endif
198
199 );
200}
201
Ratan Gupta87c13982017-06-15 09:27:27 +0530202void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530203{
Ratan Gupta87c13982017-06-15 09:27:27 +0530204 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530205
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700206 AddressFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700207 filter.interface = ifIdx;
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700208 auto currentAddrs = getCurrentAddresses(filter);
209 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530210 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700211 if (addr.flags & IFA_F_DEPRECATED)
212 {
213 continue;
214 }
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700215 auto address = std::to_string(addr.address);
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700216 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800217 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800218 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530219 {
220 origin = IP::AddressOrigin::DHCP;
221 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400222#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700223 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530224 {
225 origin = IP::AddressOrigin::LinkLocal;
226 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400227#endif
Ratan Gupta82549cc2017-04-21 08:45:23 +0530228
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700229 auto ipAddressObjectPath =
230 generateObjectPath(addressType, address, addr.prefix, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530231
Lei YU7233c582021-04-08 14:39:43 +0800232 this->addrs.insert_or_assign(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700233 address, std::make_unique<IPAddress>(bus, ipAddressObjectPath,
234 *this, addressType, address,
235 origin, addr.prefix));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530236 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530237}
238
William A. Kennington III08505792019-01-30 16:00:04 -0800239void EthernetInterface::createStaticNeighborObjects()
240{
241 staticNeighbors.clear();
242
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700243 NeighborFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700244 filter.interface = ifIdx;
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700245 filter.state = NUD_PERMANENT;
246 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800247 for (const auto& neighbor : neighbors)
248 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700249 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800250 {
251 continue;
252 }
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700253 auto ip = std::to_string(neighbor.address);
254 auto mac = std::to_string(*neighbor.mac);
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700255 auto objectPath = generateStaticNeighborObjectPath(ip, mac);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700256 staticNeighbors.emplace(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700257 ip, std::make_unique<Neighbor>(bus, objectPath, *this, ip, mac,
258 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800259 }
260}
261
Patrick Williams6aef7692021-05-01 06:39:41 -0500262ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700263 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530264{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800265 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530266 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700267 log<level::INFO>("DHCP enabled on the interface, disabling"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500268 entry("INTERFACE=%s", interfaceName().c_str());
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700269 switch (protType)
270 {
271 case IP::Protocol::IPv4:
272 dhcp4(false);
273 break;
274 case IP::Protocol::IPv6:
275 dhcp6(false);
276 break;
277 }
Ravi Teja07450442022-07-07 04:30:57 -0500278 // Delete the IP address object and that reloads the networkd
279 // to allow the same IP address to be set as Static IP
280 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500281 }
282
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500283 IP::AddressOrigin origin = IP::AddressOrigin::Static;
284
285 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
286
287 if (!isValidIP(addressFamily, ipaddress))
288 {
289 log<level::ERR>("Not a valid IP address"),
290 entry("ADDRESS=%s", ipaddress.c_str());
291 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
292 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
293 }
294
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500295 if (!isValidPrefix(addressFamily, prefixLength))
296 {
297 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700298 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500299 elog<InvalidArgument>(
300 Argument::ARGUMENT_NAME("prefixLength"),
301 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530302 }
303
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700304 auto objectPath =
305 generateObjectPath(protType, ipaddress, prefixLength, origin);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700306 this->addrs.insert_or_assign(
307 ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700308 std::make_unique<IPAddress>(bus, objectPath, *this, protType, ipaddress,
309 origin, prefixLength));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530310
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700311 writeConfigurationFile();
312 manager.reloadConfigs();
313
raviteja-bce379562019-03-28 05:59:36 -0500314 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530315}
316
Patrick Williams6aef7692021-05-01 06:39:41 -0500317ObjectPath EthernetInterface::neighbor(std::string ipAddress,
318 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800319{
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700320 if (!isValidIP(ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800321 {
322 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500323 entry("ADDRESS=%s", ipAddress.c_str()));
324 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
325 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800326 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500327 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800328 {
329 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500330 entry("MACADDRESS=%s", ipAddress.c_str()));
331 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
332 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800333 }
334
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700335 auto objectPath = generateStaticNeighborObjectPath(ipAddress, macAddress);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700336 staticNeighbors.emplace(
337 ipAddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700338 std::make_unique<Neighbor>(bus, objectPath, *this, ipAddress,
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700339 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700340
341 writeConfigurationFile();
342 manager.reloadConfigs();
343
William A. Kennington III08505792019-01-30 16:00:04 -0800344 return objectPath;
345}
346
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700347void EthernetInterface::deleteObject(std::string_view ipaddress)
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530348{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530349 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530350 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530351 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530352 log<level::ERR>("DeleteObject:Unable to find the object.");
353 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530354 }
355 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700356
357 writeConfigurationFile();
358 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530359}
360
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700361void EthernetInterface::deleteStaticNeighborObject(std::string_view ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800362{
Patrick Williams6aef7692021-05-01 06:39:41 -0500363 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800364 if (it == staticNeighbors.end())
365 {
366 log<level::ERR>(
367 "DeleteStaticNeighborObject:Unable to find the object.");
368 return;
369 }
370 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700371
372 writeConfigurationFile();
373 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800374}
375
Gunnar Mills57d9c502018-09-14 14:42:34 -0500376std::string EthernetInterface::generateObjectPath(
William A. Kennington III991a8e82022-10-11 15:02:47 -0700377 IP::Protocol addressType, std::string_view ipAddress, uint8_t prefixLength,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700378 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530379{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700380 std::string_view type;
381 switch (addressType)
382 {
383 case IP::Protocol::IPv4:
384 type = "ipv4"sv;
385 break;
386 case IP::Protocol::IPv6:
387 type = "ipv6"sv;
388 break;
389 }
390 return fmt::format(
391 FMT_COMPILE("{}/{}/{:08x}"), objPath, type,
392 static_cast<uint32_t>(hash_multi(
393 ipAddress, prefixLength,
394 static_cast<std::underlying_type_t<IP::AddressOrigin>>(origin))));
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530395}
396
William A. Kennington III08505792019-01-30 16:00:04 -0800397std::string EthernetInterface::generateStaticNeighborObjectPath(
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700398 std::string_view ipAddress, std::string_view macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800399{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700400 return fmt::format(
401 FMT_COMPILE("{}/static_neighbor/{:08x}"), objPath,
402 static_cast<uint32_t>(hash_multi(ipAddress, macAddress)));
William A. Kennington III08505792019-01-30 16:00:04 -0800403}
404
Patrick Williams6aef7692021-05-01 06:39:41 -0500405bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700406{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700407 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700408 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700409 writeConfigurationFile();
410 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700411 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700412 return value;
413}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700414
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700415bool EthernetInterface::dhcp4(bool value)
416{
417 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
418 {
419 writeConfigurationFile();
420 manager.reloadConfigs();
421 }
422 return value;
423}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700424
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700425bool EthernetInterface::dhcp6(bool value)
426{
427 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
428 {
429 writeConfigurationFile();
430 manager.reloadConfigs();
431 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700432 return value;
433}
434
Patrick Williams6aef7692021-05-01 06:39:41 -0500435EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530436{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700437 auto old4 = EthernetInterfaceIntf::dhcp4();
438 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
439 value == DHCPConf::v4v6stateless ||
440 value == DHCPConf::both);
441 auto old6 = EthernetInterfaceIntf::dhcp6();
442 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
443 value == DHCPConf::both);
444 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
445 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
446 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
447 value == DHCPConf::v6 || value == DHCPConf::both);
448
449 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530450 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700451 writeConfigurationFile();
452 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530453 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530454 return value;
455}
456
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700457EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
458{
459 if (dhcp6())
460 {
461 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
462 }
463 else if (dhcp4())
464 {
465 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
466 }
467 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
468}
469
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800470bool EthernetInterface::linkUp() const
471{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700472 if (ifIdx == 0)
473 {
474 return EthernetInterfaceIntf::linkUp();
475 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700476 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700477}
478
Tejas Patil2c0fc562021-08-03 19:13:46 +0530479size_t EthernetInterface::mtu() const
480{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700481 if (ifIdx == 0)
482 {
483 return EthernetInterfaceIntf::mtu();
484 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700485 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700486 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700487 [&] { return system::getMTU(ifname); })
488 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530489}
490
491size_t EthernetInterface::mtu(size_t value)
492{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700493 const size_t old = EthernetInterfaceIntf::mtu();
494 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530495 {
496 return value;
497 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700498 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700499 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700500 system::setMTU(ifname, value);
501 return value;
502 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530503}
504
William A. Kennington III26275a32021-07-13 20:32:42 -0700505bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700506{
William A. Kennington III26275a32021-07-13 20:32:42 -0700507 constexpr auto svc = "org.freedesktop.network1";
508 constexpr auto intf = "org.freedesktop.network1.Link";
509 constexpr auto prop = "AdministrativeState";
510 char* rpath;
511 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700512 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700513 std::string path(rpath);
514 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700515
William A. Kennington III26275a32021-07-13 20:32:42 -0700516 // Store / Parser for the AdministrativeState return value
517 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700518 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700519 if (state != "initialized")
520 {
521 ret = state != "unmanaged";
522 }
523 };
524
525 // Build a matcher before making the property call to ensure we
526 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500527 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700528 bus,
529 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
530 "'PropertiesChanged',arg0='{}',",
531 svc, path, PROPERTY_INTERFACE, intf)
532 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500533 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700534 std::string intf;
535 std::unordered_map<std::string, std::variant<std::string>> values;
536 try
537 {
538 m.read(intf, values);
539 auto it = values.find(prop);
540 // Ignore properties that aren't AdministrativeState
541 if (it != values.end())
542 {
543 cb(std::get<std::string>(it->second));
544 }
545 }
546 catch (const std::exception& e)
547 {
548 log<level::ERR>(
549 fmt::format(
550 "AdministrativeState match parsing failed on {}: {}",
551 interfaceName(), e.what())
552 .c_str(),
553 entry("INTERFACE=%s", interfaceName().c_str()),
554 entry("ERROR=%s", e.what()));
555 }
556 });
557
558 // Actively call for the value in case the interface is already configured
559 auto method =
560 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
561 method.append(intf, prop);
562 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700563 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700564 auto reply = bus.call(method);
565 std::variant<std::string> state;
566 reply.read(state);
567 cb(std::get<std::string>(state));
568 }
569 catch (const std::exception& e)
570 {
571 log<level::ERR>(
572 fmt::format("Failed to get AdministrativeState on {}: {}",
573 interfaceName(), e.what())
574 .c_str(),
575 entry("INTERFACE=%s", interfaceName().c_str()),
576 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700577 }
578
William A. Kennington III26275a32021-07-13 20:32:42 -0700579 // The interface is not yet configured by systemd-networkd, wait until it
580 // signals us a valid state.
581 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700582 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700583 bus.wait();
584 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700585 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700586
587 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700588}
589
Patrick Williams6aef7692021-05-01 06:39:41 -0500590bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700591{
Patrick Williams6aef7692021-05-01 06:39:41 -0500592 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700593 {
594 return value;
595 }
596
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800597 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700598 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800599 if (!value)
600 {
601 // We only need to bring down the interface, networkd will always bring
602 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700603 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700604 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800605 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700606 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800607
608 return value;
609}
610
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530611ServerList EthernetInterface::staticNameServers(ServerList value)
612{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530613 for (const auto& nameserverip : value)
614 {
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700615 if (!isValidIP(nameserverip))
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530616 {
617 log<level::ERR>("Not a valid IP address"),
618 entry("ADDRESS=%s", nameserverip.c_str());
619 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530620 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530621 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
622 }
623 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530624 try
625 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530626 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700627
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530628 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700629 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530630 }
Patrick Williams5758db32021-10-06 12:29:22 -0500631 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530632 {
633 log<level::ERR>("Exception processing DNS entries");
634 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530635 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530636}
637
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600638void EthernetInterface::loadNTPServers(const config::Parser& config)
639{
640 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
641 EthernetInterfaceIntf::staticNTPServers(
642 config.map.getValueStrings("Network", "NTP"));
643}
644
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700645void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530646{
647 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700648 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700649 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530650}
651
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600652ServerList EthernetInterface::getNTPServerFromTimeSyncd()
653{
654 ServerList servers; // Variable to capture the NTP Server IPs
655 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
656 PROPERTY_INTERFACE, METHOD_GET);
657
658 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
659
660 try
661 {
662 auto reply = bus.call(method);
663 std::variant<ServerList> response;
664 reply.read(response);
665 servers = std::get<ServerList>(response);
666 }
667 catch (const sdbusplus::exception::SdBusError& e)
668 {
669 log<level::ERR>(
670 "Failed to get NTP server information from Systemd-Timesyncd");
671 }
672
673 return servers;
674}
675
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530676ServerList EthernetInterface::getNameServerFromResolvd()
677{
678 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700679 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530680
681 /*
682 The DNS property under org.freedesktop.resolve1.Link interface contains
683 an array containing all DNS servers currently used by resolved. It
684 contains similar information as the DNS server data written to
685 /run/systemd/resolve/resolv.conf.
686
687 Each structure in the array consists of a numeric network interface index,
688 an address family, and a byte array containing the DNS server address
689 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
690 The array contains DNS servers configured system-wide, including those
691 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
692 /etc/systemd/resolved.conf, as well as per-interface DNS server
693 information either retrieved from systemd-networkd or configured by
694 external software via SetLinkDNS().
695 */
696
697 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
698 std::variant<type> name; // Variable to capture the DNS property
699 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
700 PROPERTY_INTERFACE, METHOD_GET);
701
702 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530703
704 try
705 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500706 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530707 reply.read(name);
708 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500709 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530710 {
711 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
712 }
713 auto tupleVector = std::get_if<type>(&name);
714 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
715 {
Alexander Filippov983da552021-02-08 15:26:54 +0300716 int addressFamily = std::get<0>(*i);
717 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700718 servers.push_back(std::to_string(
719 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530720 }
721 return servers;
722}
723
William A. Kennington IIId298f932022-10-17 14:31:38 -0700724ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530725{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700726 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
727 auto idStr = std::to_string(id);
728 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800729 {
730 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700731 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
732 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800733 }
734
William A. Kennington IIId298f932022-10-17 14:31:38 -0700735 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700736 auto macStr = MacAddressIntf::macAddress();
737 std::optional<ether_addr> mac;
738 if (!macStr.empty())
739 {
740 mac.emplace(mac_address::fromString(macStr));
741 }
742 auto info = system::InterfaceInfo{
743 .idx = 0, // TODO: Query the correct value after creation
744 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700745 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700746 .mac = std::move(mac),
747 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700748 .parent_idx = ifIdx,
749 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700750 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530751
Patrick Williams6aef7692021-05-01 06:39:41 -0500752 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530753 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700754 auto vlanIntf = std::make_unique<EthernetInterface>(
755 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700756 nicEnabled());
757 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530758
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700759 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530760
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700761 // write the device file for the vlan interface.
762 config::Parser config;
763 auto& netdev = config.map["NetDev"].emplace_back();
764 netdev["Name"].emplace_back(intfName);
765 netdev["Kind"].emplace_back("vlan");
766 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
767 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700768
769 writeConfigurationFile();
770 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700771
William A. Kennington IIId298f932022-10-17 14:31:38 -0700772 return objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530773}
Ratan Gupta2b106532017-07-25 16:05:02 +0530774
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600775ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530776{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600777 try
778 {
779 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530780
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600781 writeConfigurationFile();
782 manager.reloadConfigs();
783 }
784 catch (InternalFailure& e)
785 {
786 log<level::ERR>("Exception processing NTP entries");
787 }
788 return EthernetInterfaceIntf::staticNTPServers();
789}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700790
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600791ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
792{
793 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530794}
Ratan Gupta2b106532017-07-25 16:05:02 +0530795// Need to merge the below function with the code which writes the
796// config file during factory reset.
797// TODO openbmc/openbmc#1751
798
799void EthernetInterface::writeConfigurationFile()
800{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700801 config::Parser config;
802 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530803 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700804 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800805#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700806 auto mac = MacAddressIntf::macAddress();
807 if (!mac.empty())
808 {
809 link["MACAddress"].emplace_back(mac);
810 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800811#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700812 if (!EthernetInterfaceIntf::nicEnabled())
813 {
814 link["Unmanaged"].emplace_back("yes");
815 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700816 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700817 {
818 auto& network = config.map["Network"].emplace_back();
819 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400820#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700821 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400822#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700823 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400824#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700825 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
826 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
827 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600828 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700829 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700830 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700831 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700832 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
833 {
834 vlans.emplace_back(intf->interfaceName());
835 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700836 }
837 }
838 {
839 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600840 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700841 {
842 ntps.emplace_back(ntp);
843 }
844 }
845 {
846 auto& dnss = network["DNS"];
847 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
848 {
849 dnss.emplace_back(dns);
850 }
851 }
852 {
853 auto& address = network["Address"];
854 for (const auto& addr : getAddresses())
855 {
856 if (originIsManuallyAssigned(addr.second->origin()) &&
857 !dhcpIsEnabled(addr.second->type()))
858 {
859 address.emplace_back(
860 fmt::format("{}/{}", addr.second->address(),
861 addr.second->prefixLength()));
862 }
863 }
864 }
865 {
866 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700867 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700868 {
869 auto gateway = EthernetInterfaceIntf::defaultGateway();
870 if (!gateway.empty())
871 {
872 gateways.emplace_back(gateway);
873 }
874 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530875
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700876 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700877 {
878 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
879 if (!gateway6.empty())
880 {
881 gateways.emplace_back(gateway6);
882 }
883 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600884 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800885 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700886 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700887 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500888 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700889 auto& neighbors = config.map["Neighbor"];
890 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800891 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700892 auto& neighbor = neighbors.emplace_back();
893 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
894 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800895 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500896 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500897 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700898 auto& dhcp = config.map["DHCP"].emplace_back();
899 dhcp["ClientIdentifier"].emplace_back("mac");
900 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800901 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700902 const auto& conf = *manager.getDHCPConf();
903 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
904 dhcp["UseDNS"].emplace_back(dns_enabled);
905 dhcp["UseDomains"].emplace_back(dns_enabled);
906 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
907 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
908 : "false");
909 dhcp["SendHostname"].emplace_back(
910 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800911 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500912 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700913 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
914 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700915 auto msg = fmt::format("Wrote networkd file: {}", path.native());
916 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530917}
918
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800919std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530920{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700921 if (vlan)
922 {
923 log<level::ERR>("Tried to set MAC address on VLAN");
924 elog<InternalFailure>();
925 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800926#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600927 ether_addr newMAC;
928 try
929 {
930 newMAC = mac_address::fromString(value);
931 }
Patrick Williams5758db32021-10-06 12:29:22 -0500932 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600933 {
934 log<level::ERR>("MACAddress is not valid.",
935 entry("MAC=%s", value.c_str()));
936 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
937 Argument::ARGUMENT_VALUE(value.c_str()));
938 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700939 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530940 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500941 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500942 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500943 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
944 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530945 }
946
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300947 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700948 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300949
William A. Kennington III1137a972019-04-20 20:49:58 -0700950 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -0500951 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700952 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530953 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700954 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700955 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530956 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700957 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
958 {
959 intf->MacAddressIntf::macAddress(validMAC);
960 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530961 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500962 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530963
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700964 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800965 manager.addReloadPreHook([interface]() {
966 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700967 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800968 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700969 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530970 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700971
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300972#ifdef HAVE_UBOOT_ENV
973 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700974 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300975 if (envVar)
976 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500977 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
978 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
979 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
980 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300981 }
982#endif // HAVE_UBOOT_ENV
983
William A. Kennington III1137a972019-04-20 20:49:58 -0700984 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800985#else
986 elog<NotAllowed>(
987 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
988#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530989}
990
Ratan Guptae9c9b812017-09-22 17:15:37 +0530991void EthernetInterface::deleteAll()
992{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530993 // clear all the ip on the interface
994 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700995
996 writeConfigurationFile();
997 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530998}
999
Ravi Tejaa5a09442020-07-17 00:57:33 -05001000std::string EthernetInterface::defaultGateway(std::string gateway)
1001{
1002 auto gw = EthernetInterfaceIntf::defaultGateway();
1003 if (gw == gateway)
1004 {
1005 return gw;
1006 }
1007
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001008 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001009 {
1010 log<level::ERR>("Not a valid v4 Gateway",
1011 entry("GATEWAY=%s", gateway.c_str()));
1012 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1013 Argument::ARGUMENT_VALUE(gateway.c_str()));
1014 }
1015 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001016
1017 writeConfigurationFile();
1018 manager.reloadConfigs();
1019
Ravi Tejaa5a09442020-07-17 00:57:33 -05001020 return gw;
1021}
1022
1023std::string EthernetInterface::defaultGateway6(std::string gateway)
1024{
1025 auto gw = EthernetInterfaceIntf::defaultGateway6();
1026 if (gw == gateway)
1027 {
1028 return gw;
1029 }
1030
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001031 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001032 {
1033 log<level::ERR>("Not a valid v6 Gateway",
1034 entry("GATEWAY=%s", gateway.c_str()));
1035 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1036 Argument::ARGUMENT_VALUE(gateway.c_str()));
1037 }
1038 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001039
1040 writeConfigurationFile();
1041 manager.reloadConfigs();
1042
Ravi Tejaa5a09442020-07-17 00:57:33 -05001043 return gw;
1044}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001045
1046EthernetInterface::VlanProperties::VlanProperties(
1047 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
1048 const system::InterfaceInfo& info, EthernetInterface& eth,
1049 bool emitSignal) :
1050 VlanIfaces(bus, objPath.c_str(),
1051 emitSignal ? VlanIfaces::action::defer_emit
1052 : VlanIfaces::action::emit_no_signals),
1053 parentIdx(*info.parent_idx), eth(eth)
1054{
1055 VlanIntf::id(*info.vlan_id);
1056 if (emitSignal)
1057 {
1058 this->emit_object_added();
1059 }
1060}
1061
1062void EthernetInterface::VlanProperties::delete_()
1063{
1064 auto intf = eth.interfaceName();
1065
1066 // Remove all configs for the current interface
1067 const auto& confDir = eth.manager.getConfDir();
1068 std::error_code ec;
1069 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1070 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1071
1072 // Write an updated parent interface since it has a VLAN entry
1073 for (const auto& [_, intf] : eth.manager.interfaces)
1074 {
1075 if (intf->ifIdx == parentIdx)
1076 {
1077 intf->writeConfigurationFile();
1078 }
1079 }
1080
1081 // We need to forcibly delete the interface as systemd does not
1082 deleteInterface(intf);
1083
William A. Kennington III67b09da2022-10-31 14:09:53 -07001084 if (eth.ifIdx > 0)
1085 {
1086 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1087 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001088 eth.manager.interfaces.erase(intf);
1089}
1090
Gunnar Mills57d9c502018-09-14 14:42:34 -05001091} // namespace network
1092} // namespace phosphor