blob: 466465561586a05b66b870d452488744177263fb [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 III59e5b912022-11-02 02:49:46 -070095 manager(manager), bus(bus), 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 Gupta6dec3902017-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
Johnathan Mantey817012a2020-01-30 15:07:39 -0800163bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
164{
165 return (
166#ifdef LINK_LOCAL_AUTOCONFIGURATION
167 (origin == IP::AddressOrigin::Static)
168#else
169 (origin == IP::AddressOrigin::Static ||
170 origin == IP::AddressOrigin::LinkLocal)
171#endif
172
173 );
174}
175
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800176void EthernetInterface::addAddr(const AddressInfo& info)
177{
178 if (info.flags & IFA_F_DEPRECATED)
179 {
180 return;
181 }
182 IP::AddressOrigin origin = IP::AddressOrigin::Static;
183 if (dhcpIsEnabled(info.ifaddr.getAddr()))
184 {
185 origin = IP::AddressOrigin::DHCP;
186 }
187#ifdef LINK_LOCAL_AUTOCONFIGURATION
188 if (info.scope == RT_SCOPE_LINK)
189 {
190 origin = IP::AddressOrigin::LinkLocal;
191 }
192#endif
193
William A. Kennington III77747f62022-11-07 23:11:15 -0800194 auto it = addrs.find(info.ifaddr);
195 if (it == addrs.end())
196 {
197 addrs.emplace(info.ifaddr, std::make_unique<IPAddress>(
198 bus, std::string_view(objPath), *this,
199 info.ifaddr, origin));
200 }
201 else
202 {
203 it->second->IPIfaces::origin(origin);
204 }
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800205}
206
Ratan Gupta87c13982017-06-15 09:27:27 +0530207void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530208{
Ratan Gupta87c13982017-06-15 09:27:27 +0530209 addrs.clear();
William A. Kennington III6a923632022-11-06 18:17:33 -0800210 for (const auto& addr : system::getAddresses({.ifidx = ifIdx}))
Ratan Gupta82549cc2017-04-21 08:45:23 +0530211 {
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800212 addAddr(addr);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530213 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530214}
215
William A. Kennington III08505792019-01-30 16:00:04 -0800216void EthernetInterface::createStaticNeighborObjects()
217{
218 staticNeighbors.clear();
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800219 for (const auto& neighbor : system::getNeighbors({.ifidx = ifIdx}))
William A. Kennington III08505792019-01-30 16:00:04 -0800220 {
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800221 if (!neighbor.mac || (neighbor.state & NUD_PERMANENT) == 0)
William A. Kennington III08505792019-01-30 16:00:04 -0800222 {
223 continue;
224 }
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700225 staticNeighbors.emplace(
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800226 neighbor.addr,
William A. Kennington III434a9432022-11-04 18:38:46 -0700227 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this,
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800228 neighbor.addr, *neighbor.mac,
William A. Kennington III434a9432022-11-04 18:38:46 -0700229 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800230 }
231}
232
Patrick Williams6aef7692021-05-01 06:39:41 -0500233ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700234 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530235{
William A. Kennington III59e5b912022-11-02 02:49:46 -0700236 InAddrAny addr;
237 try
Ratan Guptafc2c7242017-05-29 08:46:06 +0530238 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700239 switch (protType)
240 {
241 case IP::Protocol::IPv4:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700242 addr = ToAddr<in_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700243 break;
244 case IP::Protocol::IPv6:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700245 addr = ToAddr<in6_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700246 break;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700247 default:
248 throw std::logic_error("Exhausted protocols");
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700249 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500250 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700251 catch (const std::exception& e)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500252 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700253 auto msg = fmt::format("Invalid IP `{}`: {}\n", ipaddress, e.what());
254 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipaddress.c_str()));
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500255 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
256 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
257 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700258 IfAddr ifaddr;
259 try
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500260 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700261 ifaddr = {addr, prefixLength};
262 }
263 catch (const std::exception& e)
264 {
265 auto msg = fmt::format("Invalid prefix length `{}`: {}\n", prefixLength,
266 e.what());
267 log<level::ERR>(msg.c_str(),
268 entry("PREFIXLENGTH=%" PRIu8, prefixLength));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500269 elog<InvalidArgument>(
270 Argument::ARGUMENT_NAME("prefixLength"),
271 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530272 }
273
William A. Kennington III434a9432022-11-04 18:38:46 -0700274 auto [it, _] = this->addrs.insert_or_assign(
275 ifaddr,
William A. Kennington III59e5b912022-11-02 02:49:46 -0700276 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
William A. Kennington III434a9432022-11-04 18:38:46 -0700277 ifaddr, IP::AddressOrigin::Static));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530278
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700279 writeConfigurationFile();
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800280 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700281
William A. Kennington III434a9432022-11-04 18:38:46 -0700282 return it->second->getObjPath();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530283}
284
Patrick Williams6aef7692021-05-01 06:39:41 -0500285ObjectPath EthernetInterface::neighbor(std::string ipAddress,
286 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800287{
William A. Kennington III434a9432022-11-04 18:38:46 -0700288 InAddrAny addr;
289 try
William A. Kennington III08505792019-01-30 16:00:04 -0800290 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700291 addr = ToAddr<InAddrAny>{}(ipAddress);
292 }
293 catch (const std::exception& e)
294 {
295 auto msg =
296 fmt::format("Not a valid IP address `{}`: {}", ipAddress, e.what());
297 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500298 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
299 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800300 }
William A. Kennington III434a9432022-11-04 18:38:46 -0700301
302 ether_addr lladdr;
303 try
William A. Kennington III08505792019-01-30 16:00:04 -0800304 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700305 lladdr = ToAddr<ether_addr>{}(macAddress);
306 }
307 catch (const std::exception& e)
308 {
309 auto msg = fmt::format("Not a valid MAC address `{}`: {}", macAddress,
310 e.what());
311 log<level::ERR>(msg.c_str(),
312 entry("MACADDRESS=%s", macAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500313 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
314 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800315 }
316
William A. Kennington III434a9432022-11-04 18:38:46 -0700317 auto [it, _] = staticNeighbors.emplace(
318 addr,
319 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this, addr,
320 lladdr, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700321
322 writeConfigurationFile();
323 manager.reloadConfigs();
324
William A. Kennington III434a9432022-11-04 18:38:46 -0700325 return it->second->getObjPath();
William A. Kennington III08505792019-01-30 16:00:04 -0800326}
327
Patrick Williams6aef7692021-05-01 06:39:41 -0500328bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700329{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700330 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700331 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700332 writeConfigurationFile();
333 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700334 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700335 return value;
336}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700337
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700338bool EthernetInterface::dhcp4(bool value)
339{
340 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
341 {
342 writeConfigurationFile();
343 manager.reloadConfigs();
344 }
345 return value;
346}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700347
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700348bool EthernetInterface::dhcp6(bool value)
349{
350 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
351 {
352 writeConfigurationFile();
353 manager.reloadConfigs();
354 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700355 return value;
356}
357
Patrick Williams6aef7692021-05-01 06:39:41 -0500358EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530359{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700360 auto old4 = EthernetInterfaceIntf::dhcp4();
361 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
362 value == DHCPConf::v4v6stateless ||
363 value == DHCPConf::both);
364 auto old6 = EthernetInterfaceIntf::dhcp6();
365 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
366 value == DHCPConf::both);
367 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
368 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
369 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
370 value == DHCPConf::v6 || value == DHCPConf::both);
371
372 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530373 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700374 writeConfigurationFile();
375 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530376 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530377 return value;
378}
379
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700380EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
381{
382 if (dhcp6())
383 {
384 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
385 }
386 else if (dhcp4())
387 {
388 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
389 }
390 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
391}
392
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800393bool EthernetInterface::linkUp() const
394{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700395 if (ifIdx == 0)
396 {
397 return EthernetInterfaceIntf::linkUp();
398 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700399 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700400}
401
Tejas Patil2c0fc562021-08-03 19:13:46 +0530402size_t EthernetInterface::mtu() const
403{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700404 if (ifIdx == 0)
405 {
406 return EthernetInterfaceIntf::mtu();
407 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700408 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700409 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700410 [&] { return system::getMTU(ifname); })
411 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530412}
413
414size_t EthernetInterface::mtu(size_t value)
415{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700416 const size_t old = EthernetInterfaceIntf::mtu();
417 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530418 {
419 return value;
420 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700421 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700422 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700423 system::setMTU(ifname, value);
424 return value;
425 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530426}
427
William A. Kennington III26275a32021-07-13 20:32:42 -0700428bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700429{
William A. Kennington III26275a32021-07-13 20:32:42 -0700430 constexpr auto svc = "org.freedesktop.network1";
431 constexpr auto intf = "org.freedesktop.network1.Link";
432 constexpr auto prop = "AdministrativeState";
433 char* rpath;
434 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700435 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700436 std::string path(rpath);
437 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700438
William A. Kennington III26275a32021-07-13 20:32:42 -0700439 // Store / Parser for the AdministrativeState return value
440 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700441 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700442 if (state != "initialized")
443 {
444 ret = state != "unmanaged";
445 }
446 };
447
448 // Build a matcher before making the property call to ensure we
449 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500450 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700451 bus,
452 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
453 "'PropertiesChanged',arg0='{}',",
454 svc, path, PROPERTY_INTERFACE, intf)
455 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500456 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700457 std::string intf;
458 std::unordered_map<std::string, std::variant<std::string>> values;
459 try
460 {
461 m.read(intf, values);
462 auto it = values.find(prop);
463 // Ignore properties that aren't AdministrativeState
464 if (it != values.end())
465 {
466 cb(std::get<std::string>(it->second));
467 }
468 }
469 catch (const std::exception& e)
470 {
471 log<level::ERR>(
472 fmt::format(
473 "AdministrativeState match parsing failed on {}: {}",
474 interfaceName(), e.what())
475 .c_str(),
476 entry("INTERFACE=%s", interfaceName().c_str()),
477 entry("ERROR=%s", e.what()));
478 }
479 });
480
481 // Actively call for the value in case the interface is already configured
482 auto method =
483 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
484 method.append(intf, prop);
485 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700486 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700487 auto reply = bus.call(method);
488 std::variant<std::string> state;
489 reply.read(state);
490 cb(std::get<std::string>(state));
491 }
492 catch (const std::exception& e)
493 {
494 log<level::ERR>(
495 fmt::format("Failed to get AdministrativeState on {}: {}",
496 interfaceName(), e.what())
497 .c_str(),
498 entry("INTERFACE=%s", interfaceName().c_str()),
499 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700500 }
501
William A. Kennington III26275a32021-07-13 20:32:42 -0700502 // The interface is not yet configured by systemd-networkd, wait until it
503 // signals us a valid state.
504 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700505 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700506 bus.wait();
507 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700508 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700509
510 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700511}
512
Patrick Williams6aef7692021-05-01 06:39:41 -0500513bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700514{
Patrick Williams6aef7692021-05-01 06:39:41 -0500515 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700516 {
517 return value;
518 }
519
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800520 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700521 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800522 if (!value)
523 {
524 // We only need to bring down the interface, networkd will always bring
525 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700526 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700527 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800528 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700529 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800530
531 return value;
532}
533
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530534ServerList EthernetInterface::staticNameServers(ServerList value)
535{
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700536 for (auto& ip : value)
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530537 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700538 try
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530539 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700540 ip = std::to_string(ToAddr<InAddrAny>{}(ip));
541 }
542 catch (const std::exception& e)
543 {
544 auto msg =
545 fmt::format("Not a valid IP address `{}`: {}", ip, e.what());
546 log<level::ERR>(msg.c_str()), entry("ADDRESS=%s", ip.c_str());
547 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"),
548 Argument::ARGUMENT_VALUE(ip.c_str()));
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530549 }
550 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530551 try
552 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530553 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700554
Ratan Gupta6dec3902017-08-20 15:28:12 +0530555 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700556 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530557 }
Patrick Williams5758db32021-10-06 12:29:22 -0500558 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530559 {
560 log<level::ERR>("Exception processing DNS entries");
561 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530562 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530563}
564
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600565void EthernetInterface::loadNTPServers(const config::Parser& config)
566{
567 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
568 EthernetInterfaceIntf::staticNTPServers(
569 config.map.getValueStrings("Network", "NTP"));
570}
571
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700572void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530573{
574 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700575 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700576 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530577}
578
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600579ServerList EthernetInterface::getNTPServerFromTimeSyncd()
580{
581 ServerList servers; // Variable to capture the NTP Server IPs
582 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
583 PROPERTY_INTERFACE, METHOD_GET);
584
585 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
586
587 try
588 {
589 auto reply = bus.call(method);
590 std::variant<ServerList> response;
591 reply.read(response);
592 servers = std::get<ServerList>(response);
593 }
594 catch (const sdbusplus::exception::SdBusError& e)
595 {
596 log<level::ERR>(
597 "Failed to get NTP server information from Systemd-Timesyncd");
598 }
599
600 return servers;
601}
602
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530603ServerList EthernetInterface::getNameServerFromResolvd()
604{
605 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700606 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530607
608 /*
609 The DNS property under org.freedesktop.resolve1.Link interface contains
610 an array containing all DNS servers currently used by resolved. It
611 contains similar information as the DNS server data written to
612 /run/systemd/resolve/resolv.conf.
613
614 Each structure in the array consists of a numeric network interface index,
615 an address family, and a byte array containing the DNS server address
616 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
617 The array contains DNS servers configured system-wide, including those
618 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
619 /etc/systemd/resolved.conf, as well as per-interface DNS server
620 information either retrieved from systemd-networkd or configured by
621 external software via SetLinkDNS().
622 */
623
624 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
625 std::variant<type> name; // Variable to capture the DNS property
626 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
627 PROPERTY_INTERFACE, METHOD_GET);
628
629 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530630
631 try
632 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500633 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530634 reply.read(name);
635 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500636 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530637 {
638 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
639 }
640 auto tupleVector = std::get_if<type>(&name);
641 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
642 {
Alexander Filippov983da552021-02-08 15:26:54 +0300643 int addressFamily = std::get<0>(*i);
644 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700645 servers.push_back(std::to_string(
646 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530647 }
648 return servers;
649}
650
William A. Kennington IIId298f932022-10-17 14:31:38 -0700651ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530652{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700653 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
654 auto idStr = std::to_string(id);
655 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800656 {
657 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700658 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
659 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800660 }
661
William A. Kennington IIId298f932022-10-17 14:31:38 -0700662 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700663 auto macStr = MacAddressIntf::macAddress();
664 std::optional<ether_addr> mac;
665 if (!macStr.empty())
666 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700667 mac.emplace(ToAddr<ether_addr>{}(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700668 }
669 auto info = system::InterfaceInfo{
670 .idx = 0, // TODO: Query the correct value after creation
671 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700672 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700673 .mac = std::move(mac),
674 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700675 .parent_idx = ifIdx,
676 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700677 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530678
Patrick Williams6aef7692021-05-01 06:39:41 -0500679 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530680 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700681 auto vlanIntf = std::make_unique<EthernetInterface>(
682 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700683 nicEnabled());
684 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530685
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700686 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530687
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700688 // write the device file for the vlan interface.
689 config::Parser config;
690 auto& netdev = config.map["NetDev"].emplace_back();
691 netdev["Name"].emplace_back(intfName);
692 netdev["Kind"].emplace_back("vlan");
693 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
694 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700695
696 writeConfigurationFile();
697 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700698
William A. Kennington III7b90bc82022-11-17 14:55:12 -0800699 return ret;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530700}
Ratan Gupta2b106532017-07-25 16:05:02 +0530701
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600702ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530703{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600704 try
705 {
706 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530707
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600708 writeConfigurationFile();
709 manager.reloadConfigs();
710 }
711 catch (InternalFailure& e)
712 {
713 log<level::ERR>("Exception processing NTP entries");
714 }
715 return EthernetInterfaceIntf::staticNTPServers();
716}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700717
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600718ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
719{
720 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530721}
Ratan Gupta2b106532017-07-25 16:05:02 +0530722// Need to merge the below function with the code which writes the
723// config file during factory reset.
724// TODO openbmc/openbmc#1751
725
726void EthernetInterface::writeConfigurationFile()
727{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700728 config::Parser config;
729 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530730 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700731 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800732#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700733 auto mac = MacAddressIntf::macAddress();
734 if (!mac.empty())
735 {
736 link["MACAddress"].emplace_back(mac);
737 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800738#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700739 if (!EthernetInterfaceIntf::nicEnabled())
740 {
741 link["Unmanaged"].emplace_back("yes");
742 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700743 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700744 {
745 auto& network = config.map["Network"].emplace_back();
746 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400747#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700748 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400749#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700750 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400751#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700752 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
753 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
754 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600755 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700756 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700757 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700758 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700759 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
760 {
761 vlans.emplace_back(intf->interfaceName());
762 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700763 }
764 }
765 {
766 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600767 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700768 {
769 ntps.emplace_back(ntp);
770 }
771 }
772 {
773 auto& dnss = network["DNS"];
774 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
775 {
776 dnss.emplace_back(dns);
777 }
778 }
779 {
780 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700781 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700782 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700783 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700784 {
785 address.emplace_back(
786 fmt::format("{}/{}", addr.second->address(),
787 addr.second->prefixLength()));
788 }
789 }
790 }
791 {
792 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700793 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700794 {
795 auto gateway = EthernetInterfaceIntf::defaultGateway();
796 if (!gateway.empty())
797 {
798 gateways.emplace_back(gateway);
799 }
800 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530801
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700802 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700803 {
804 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
805 if (!gateway6.empty())
806 {
807 gateways.emplace_back(gateway6);
808 }
809 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600810 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800811 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700812 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700813 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500814 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700815 auto& neighbors = config.map["Neighbor"];
816 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800817 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700818 auto& neighbor = neighbors.emplace_back();
819 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
820 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800821 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500822 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500823 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700824 auto& dhcp = config.map["DHCP"].emplace_back();
825 dhcp["ClientIdentifier"].emplace_back("mac");
826 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800827 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700828 const auto& conf = *manager.getDHCPConf();
829 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
830 dhcp["UseDNS"].emplace_back(dns_enabled);
831 dhcp["UseDomains"].emplace_back(dns_enabled);
832 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
833 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
834 : "false");
835 dhcp["SendHostname"].emplace_back(
836 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800837 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500838 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700839 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
840 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700841 auto msg = fmt::format("Wrote networkd file: {}", path.native());
842 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530843}
844
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800845std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530846{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700847 if (vlan)
848 {
849 log<level::ERR>("Tried to set MAC address on VLAN");
850 elog<InternalFailure>();
851 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800852#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600853 ether_addr newMAC;
854 try
855 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700856 newMAC = ToAddr<ether_addr>{}(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600857 }
Patrick Williams5758db32021-10-06 12:29:22 -0500858 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600859 {
860 log<level::ERR>("MACAddress is not valid.",
861 entry("MAC=%s", value.c_str()));
862 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
863 Argument::ARGUMENT_VALUE(value.c_str()));
864 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700865 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530866 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500867 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500868 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500869 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
870 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530871 }
872
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300873 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700874 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300875
William A. Kennington III1137a972019-04-20 20:49:58 -0700876 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700877 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700878 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530879 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700880 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700881 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530882 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700883 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
884 {
885 intf->MacAddressIntf::macAddress(validMAC);
886 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530887 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500888 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530889
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700890 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800891 manager.addReloadPreHook([interface]() {
892 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700893 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800894 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700895 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530896 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700897
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300898#ifdef HAVE_UBOOT_ENV
899 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700900 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300901 if (envVar)
902 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500903 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
904 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
905 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
906 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300907 }
908#endif // HAVE_UBOOT_ENV
909
William A. Kennington III1137a972019-04-20 20:49:58 -0700910 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800911#else
912 elog<NotAllowed>(
913 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
914#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530915}
916
Ratan Guptae9c9b812017-09-22 17:15:37 +0530917void EthernetInterface::deleteAll()
918{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530919 // clear all the ip on the interface
920 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700921
922 writeConfigurationFile();
923 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530924}
925
Ravi Tejaa5a09442020-07-17 00:57:33 -0500926std::string EthernetInterface::defaultGateway(std::string gateway)
927{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700928 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500929 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700930 if (!gateway.empty())
931 {
932 gateway = std::to_string(ToAddr<in_addr>{}(gateway));
933 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500934 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700935 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500936 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700937 auto msg = fmt::format("Invalid v4 GW `{}`: {}", gateway, e.what());
938 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500939 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
940 Argument::ARGUMENT_VALUE(gateway.c_str()));
941 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700942
943 if (EthernetInterfaceIntf::defaultGateway() == gateway)
944 {
945 return gateway;
946 }
947 EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700948
949 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700950 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700951
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700952 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500953}
954
955std::string EthernetInterface::defaultGateway6(std::string gateway)
956{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700957 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500958 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700959 if (!gateway.empty())
960 {
961 gateway = std::to_string(ToAddr<in6_addr>{}(gateway));
962 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500963 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700964 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500965 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700966 auto msg = fmt::format("Invalid v6 GW `{}`: {}", gateway, e.what());
967 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500968 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
969 Argument::ARGUMENT_VALUE(gateway.c_str()));
970 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700971
972 if (EthernetInterfaceIntf::defaultGateway6() == gateway)
973 {
974 return gateway;
975 }
976 EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700977
978 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700979 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700980
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700981 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500982}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700983
984EthernetInterface::VlanProperties::VlanProperties(
985 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
986 const system::InterfaceInfo& info, EthernetInterface& eth,
987 bool emitSignal) :
988 VlanIfaces(bus, objPath.c_str(),
989 emitSignal ? VlanIfaces::action::defer_emit
990 : VlanIfaces::action::emit_no_signals),
991 parentIdx(*info.parent_idx), eth(eth)
992{
993 VlanIntf::id(*info.vlan_id);
994 if (emitSignal)
995 {
996 this->emit_object_added();
997 }
998}
999
1000void EthernetInterface::VlanProperties::delete_()
1001{
1002 auto intf = eth.interfaceName();
1003
1004 // Remove all configs for the current interface
1005 const auto& confDir = eth.manager.getConfDir();
1006 std::error_code ec;
1007 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1008 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1009
1010 // Write an updated parent interface since it has a VLAN entry
1011 for (const auto& [_, intf] : eth.manager.interfaces)
1012 {
1013 if (intf->ifIdx == parentIdx)
1014 {
1015 intf->writeConfigurationFile();
1016 }
1017 }
1018
1019 // We need to forcibly delete the interface as systemd does not
1020 deleteInterface(intf);
1021
William A. Kennington III67b09da2022-10-31 14:09:53 -07001022 if (eth.ifIdx > 0)
1023 {
1024 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1025 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001026 eth.manager.interfaces.erase(intf);
1027}
1028
Gunnar Mills57d9c502018-09-14 14:42:34 -05001029} // namespace network
1030} // namespace phosphor