blob: b3179f41ba5103428df9bfb91b77c1c544093bd4 [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 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
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();
219
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700220 NeighborFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700221 filter.interface = ifIdx;
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700222 filter.state = NUD_PERMANENT;
223 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800224 for (const auto& neighbor : neighbors)
225 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700226 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800227 {
228 continue;
229 }
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700230 staticNeighbors.emplace(
William A. Kennington III434a9432022-11-04 18:38:46 -0700231 neighbor.address,
232 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this,
233 neighbor.address, *neighbor.mac,
234 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800235 }
236}
237
Patrick Williams6aef7692021-05-01 06:39:41 -0500238ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700239 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530240{
William A. Kennington III59e5b912022-11-02 02:49:46 -0700241 InAddrAny addr;
242 try
Ratan Guptafc2c7242017-05-29 08:46:06 +0530243 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700244 switch (protType)
245 {
246 case IP::Protocol::IPv4:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700247 addr = ToAddr<in_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700248 break;
249 case IP::Protocol::IPv6:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700250 addr = ToAddr<in6_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700251 break;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700252 default:
253 throw std::logic_error("Exhausted protocols");
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700254 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500255 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700256 catch (const std::exception& e)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500257 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700258 auto msg = fmt::format("Invalid IP `{}`: {}\n", ipaddress, e.what());
259 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipaddress.c_str()));
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500260 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
261 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
262 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700263 IfAddr ifaddr;
264 try
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500265 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700266 ifaddr = {addr, prefixLength};
267 }
268 catch (const std::exception& e)
269 {
270 auto msg = fmt::format("Invalid prefix length `{}`: {}\n", prefixLength,
271 e.what());
272 log<level::ERR>(msg.c_str(),
273 entry("PREFIXLENGTH=%" PRIu8, prefixLength));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500274 elog<InvalidArgument>(
275 Argument::ARGUMENT_NAME("prefixLength"),
276 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530277 }
278
William A. Kennington III434a9432022-11-04 18:38:46 -0700279 auto [it, _] = this->addrs.insert_or_assign(
280 ifaddr,
William A. Kennington III59e5b912022-11-02 02:49:46 -0700281 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
William A. Kennington III434a9432022-11-04 18:38:46 -0700282 ifaddr, IP::AddressOrigin::Static));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530283
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700284 writeConfigurationFile();
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800285 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700286
William A. Kennington III434a9432022-11-04 18:38:46 -0700287 return it->second->getObjPath();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530288}
289
Patrick Williams6aef7692021-05-01 06:39:41 -0500290ObjectPath EthernetInterface::neighbor(std::string ipAddress,
291 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800292{
William A. Kennington III434a9432022-11-04 18:38:46 -0700293 InAddrAny addr;
294 try
William A. Kennington III08505792019-01-30 16:00:04 -0800295 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700296 addr = ToAddr<InAddrAny>{}(ipAddress);
297 }
298 catch (const std::exception& e)
299 {
300 auto msg =
301 fmt::format("Not a valid IP address `{}`: {}", ipAddress, e.what());
302 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500303 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
304 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800305 }
William A. Kennington III434a9432022-11-04 18:38:46 -0700306
307 ether_addr lladdr;
308 try
William A. Kennington III08505792019-01-30 16:00:04 -0800309 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700310 lladdr = ToAddr<ether_addr>{}(macAddress);
311 }
312 catch (const std::exception& e)
313 {
314 auto msg = fmt::format("Not a valid MAC address `{}`: {}", macAddress,
315 e.what());
316 log<level::ERR>(msg.c_str(),
317 entry("MACADDRESS=%s", macAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500318 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
319 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800320 }
321
William A. Kennington III434a9432022-11-04 18:38:46 -0700322 auto [it, _] = staticNeighbors.emplace(
323 addr,
324 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this, addr,
325 lladdr, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700326
327 writeConfigurationFile();
328 manager.reloadConfigs();
329
William A. Kennington III434a9432022-11-04 18:38:46 -0700330 return it->second->getObjPath();
William A. Kennington III08505792019-01-30 16:00:04 -0800331}
332
Patrick Williams6aef7692021-05-01 06:39:41 -0500333bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700334{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700335 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700336 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700337 writeConfigurationFile();
338 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700339 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700340 return value;
341}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700342
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700343bool EthernetInterface::dhcp4(bool value)
344{
345 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
346 {
347 writeConfigurationFile();
348 manager.reloadConfigs();
349 }
350 return value;
351}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700352
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700353bool EthernetInterface::dhcp6(bool value)
354{
355 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
356 {
357 writeConfigurationFile();
358 manager.reloadConfigs();
359 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700360 return value;
361}
362
Patrick Williams6aef7692021-05-01 06:39:41 -0500363EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530364{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700365 auto old4 = EthernetInterfaceIntf::dhcp4();
366 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
367 value == DHCPConf::v4v6stateless ||
368 value == DHCPConf::both);
369 auto old6 = EthernetInterfaceIntf::dhcp6();
370 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
371 value == DHCPConf::both);
372 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
373 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
374 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
375 value == DHCPConf::v6 || value == DHCPConf::both);
376
377 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530378 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700379 writeConfigurationFile();
380 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530381 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530382 return value;
383}
384
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700385EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
386{
387 if (dhcp6())
388 {
389 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
390 }
391 else if (dhcp4())
392 {
393 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
394 }
395 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
396}
397
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800398bool EthernetInterface::linkUp() const
399{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700400 if (ifIdx == 0)
401 {
402 return EthernetInterfaceIntf::linkUp();
403 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700404 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700405}
406
Tejas Patil2c0fc562021-08-03 19:13:46 +0530407size_t EthernetInterface::mtu() const
408{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700409 if (ifIdx == 0)
410 {
411 return EthernetInterfaceIntf::mtu();
412 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700413 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700414 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700415 [&] { return system::getMTU(ifname); })
416 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530417}
418
419size_t EthernetInterface::mtu(size_t value)
420{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700421 const size_t old = EthernetInterfaceIntf::mtu();
422 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530423 {
424 return value;
425 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700426 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700427 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700428 system::setMTU(ifname, value);
429 return value;
430 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530431}
432
William A. Kennington III26275a32021-07-13 20:32:42 -0700433bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700434{
William A. Kennington III26275a32021-07-13 20:32:42 -0700435 constexpr auto svc = "org.freedesktop.network1";
436 constexpr auto intf = "org.freedesktop.network1.Link";
437 constexpr auto prop = "AdministrativeState";
438 char* rpath;
439 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700440 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700441 std::string path(rpath);
442 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700443
William A. Kennington III26275a32021-07-13 20:32:42 -0700444 // Store / Parser for the AdministrativeState return value
445 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700446 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700447 if (state != "initialized")
448 {
449 ret = state != "unmanaged";
450 }
451 };
452
453 // Build a matcher before making the property call to ensure we
454 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500455 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700456 bus,
457 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
458 "'PropertiesChanged',arg0='{}',",
459 svc, path, PROPERTY_INTERFACE, intf)
460 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500461 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700462 std::string intf;
463 std::unordered_map<std::string, std::variant<std::string>> values;
464 try
465 {
466 m.read(intf, values);
467 auto it = values.find(prop);
468 // Ignore properties that aren't AdministrativeState
469 if (it != values.end())
470 {
471 cb(std::get<std::string>(it->second));
472 }
473 }
474 catch (const std::exception& e)
475 {
476 log<level::ERR>(
477 fmt::format(
478 "AdministrativeState match parsing failed on {}: {}",
479 interfaceName(), e.what())
480 .c_str(),
481 entry("INTERFACE=%s", interfaceName().c_str()),
482 entry("ERROR=%s", e.what()));
483 }
484 });
485
486 // Actively call for the value in case the interface is already configured
487 auto method =
488 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
489 method.append(intf, prop);
490 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700491 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700492 auto reply = bus.call(method);
493 std::variant<std::string> state;
494 reply.read(state);
495 cb(std::get<std::string>(state));
496 }
497 catch (const std::exception& e)
498 {
499 log<level::ERR>(
500 fmt::format("Failed to get AdministrativeState on {}: {}",
501 interfaceName(), e.what())
502 .c_str(),
503 entry("INTERFACE=%s", interfaceName().c_str()),
504 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700505 }
506
William A. Kennington III26275a32021-07-13 20:32:42 -0700507 // The interface is not yet configured by systemd-networkd, wait until it
508 // signals us a valid state.
509 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700510 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700511 bus.wait();
512 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700513 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700514
515 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700516}
517
Patrick Williams6aef7692021-05-01 06:39:41 -0500518bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700519{
Patrick Williams6aef7692021-05-01 06:39:41 -0500520 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700521 {
522 return value;
523 }
524
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800525 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700526 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800527 if (!value)
528 {
529 // We only need to bring down the interface, networkd will always bring
530 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700531 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700532 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800533 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700534 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800535
536 return value;
537}
538
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530539ServerList EthernetInterface::staticNameServers(ServerList value)
540{
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700541 for (auto& ip : value)
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530542 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700543 try
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530544 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700545 ip = std::to_string(ToAddr<InAddrAny>{}(ip));
546 }
547 catch (const std::exception& e)
548 {
549 auto msg =
550 fmt::format("Not a valid IP address `{}`: {}", ip, e.what());
551 log<level::ERR>(msg.c_str()), entry("ADDRESS=%s", ip.c_str());
552 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"),
553 Argument::ARGUMENT_VALUE(ip.c_str()));
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530554 }
555 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530556 try
557 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530558 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700559
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530560 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700561 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530562 }
Patrick Williams5758db32021-10-06 12:29:22 -0500563 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530564 {
565 log<level::ERR>("Exception processing DNS entries");
566 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530567 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530568}
569
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600570void EthernetInterface::loadNTPServers(const config::Parser& config)
571{
572 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
573 EthernetInterfaceIntf::staticNTPServers(
574 config.map.getValueStrings("Network", "NTP"));
575}
576
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700577void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530578{
579 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700580 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700581 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530582}
583
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600584ServerList EthernetInterface::getNTPServerFromTimeSyncd()
585{
586 ServerList servers; // Variable to capture the NTP Server IPs
587 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
588 PROPERTY_INTERFACE, METHOD_GET);
589
590 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
591
592 try
593 {
594 auto reply = bus.call(method);
595 std::variant<ServerList> response;
596 reply.read(response);
597 servers = std::get<ServerList>(response);
598 }
599 catch (const sdbusplus::exception::SdBusError& e)
600 {
601 log<level::ERR>(
602 "Failed to get NTP server information from Systemd-Timesyncd");
603 }
604
605 return servers;
606}
607
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530608ServerList EthernetInterface::getNameServerFromResolvd()
609{
610 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700611 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530612
613 /*
614 The DNS property under org.freedesktop.resolve1.Link interface contains
615 an array containing all DNS servers currently used by resolved. It
616 contains similar information as the DNS server data written to
617 /run/systemd/resolve/resolv.conf.
618
619 Each structure in the array consists of a numeric network interface index,
620 an address family, and a byte array containing the DNS server address
621 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
622 The array contains DNS servers configured system-wide, including those
623 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
624 /etc/systemd/resolved.conf, as well as per-interface DNS server
625 information either retrieved from systemd-networkd or configured by
626 external software via SetLinkDNS().
627 */
628
629 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
630 std::variant<type> name; // Variable to capture the DNS property
631 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
632 PROPERTY_INTERFACE, METHOD_GET);
633
634 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530635
636 try
637 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500638 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530639 reply.read(name);
640 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500641 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530642 {
643 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
644 }
645 auto tupleVector = std::get_if<type>(&name);
646 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
647 {
Alexander Filippov983da552021-02-08 15:26:54 +0300648 int addressFamily = std::get<0>(*i);
649 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700650 servers.push_back(std::to_string(
651 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530652 }
653 return servers;
654}
655
William A. Kennington IIId298f932022-10-17 14:31:38 -0700656ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530657{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700658 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
659 auto idStr = std::to_string(id);
660 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800661 {
662 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700663 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
664 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800665 }
666
William A. Kennington IIId298f932022-10-17 14:31:38 -0700667 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700668 auto macStr = MacAddressIntf::macAddress();
669 std::optional<ether_addr> mac;
670 if (!macStr.empty())
671 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700672 mac.emplace(ToAddr<ether_addr>{}(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700673 }
674 auto info = system::InterfaceInfo{
675 .idx = 0, // TODO: Query the correct value after creation
676 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700677 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700678 .mac = std::move(mac),
679 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700680 .parent_idx = ifIdx,
681 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700682 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530683
Patrick Williams6aef7692021-05-01 06:39:41 -0500684 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530685 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700686 auto vlanIntf = std::make_unique<EthernetInterface>(
687 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700688 nicEnabled());
689 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530690
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700691 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530692
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700693 // write the device file for the vlan interface.
694 config::Parser config;
695 auto& netdev = config.map["NetDev"].emplace_back();
696 netdev["Name"].emplace_back(intfName);
697 netdev["Kind"].emplace_back("vlan");
698 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
699 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700700
701 writeConfigurationFile();
702 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700703
William A. Kennington III7b90bc82022-11-17 14:55:12 -0800704 return ret;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530705}
Ratan Gupta2b106532017-07-25 16:05:02 +0530706
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600707ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530708{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600709 try
710 {
711 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530712
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600713 writeConfigurationFile();
714 manager.reloadConfigs();
715 }
716 catch (InternalFailure& e)
717 {
718 log<level::ERR>("Exception processing NTP entries");
719 }
720 return EthernetInterfaceIntf::staticNTPServers();
721}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700722
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600723ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
724{
725 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530726}
Ratan Gupta2b106532017-07-25 16:05:02 +0530727// Need to merge the below function with the code which writes the
728// config file during factory reset.
729// TODO openbmc/openbmc#1751
730
731void EthernetInterface::writeConfigurationFile()
732{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700733 config::Parser config;
734 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530735 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700736 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800737#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700738 auto mac = MacAddressIntf::macAddress();
739 if (!mac.empty())
740 {
741 link["MACAddress"].emplace_back(mac);
742 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800743#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700744 if (!EthernetInterfaceIntf::nicEnabled())
745 {
746 link["Unmanaged"].emplace_back("yes");
747 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700748 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700749 {
750 auto& network = config.map["Network"].emplace_back();
751 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400752#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700753 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400754#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700755 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400756#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700757 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
758 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
759 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600760 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700761 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700762 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700763 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700764 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
765 {
766 vlans.emplace_back(intf->interfaceName());
767 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700768 }
769 }
770 {
771 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600772 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700773 {
774 ntps.emplace_back(ntp);
775 }
776 }
777 {
778 auto& dnss = network["DNS"];
779 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
780 {
781 dnss.emplace_back(dns);
782 }
783 }
784 {
785 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700786 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700787 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700788 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700789 {
790 address.emplace_back(
791 fmt::format("{}/{}", addr.second->address(),
792 addr.second->prefixLength()));
793 }
794 }
795 }
796 {
797 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700798 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700799 {
800 auto gateway = EthernetInterfaceIntf::defaultGateway();
801 if (!gateway.empty())
802 {
803 gateways.emplace_back(gateway);
804 }
805 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530806
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700807 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700808 {
809 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
810 if (!gateway6.empty())
811 {
812 gateways.emplace_back(gateway6);
813 }
814 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600815 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800816 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700817 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700818 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500819 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700820 auto& neighbors = config.map["Neighbor"];
821 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800822 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700823 auto& neighbor = neighbors.emplace_back();
824 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
825 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800826 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500827 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500828 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700829 auto& dhcp = config.map["DHCP"].emplace_back();
830 dhcp["ClientIdentifier"].emplace_back("mac");
831 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800832 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700833 const auto& conf = *manager.getDHCPConf();
834 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
835 dhcp["UseDNS"].emplace_back(dns_enabled);
836 dhcp["UseDomains"].emplace_back(dns_enabled);
837 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
838 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
839 : "false");
840 dhcp["SendHostname"].emplace_back(
841 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800842 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500843 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700844 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
845 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700846 auto msg = fmt::format("Wrote networkd file: {}", path.native());
847 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530848}
849
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800850std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530851{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700852 if (vlan)
853 {
854 log<level::ERR>("Tried to set MAC address on VLAN");
855 elog<InternalFailure>();
856 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800857#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600858 ether_addr newMAC;
859 try
860 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700861 newMAC = ToAddr<ether_addr>{}(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600862 }
Patrick Williams5758db32021-10-06 12:29:22 -0500863 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600864 {
865 log<level::ERR>("MACAddress is not valid.",
866 entry("MAC=%s", value.c_str()));
867 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
868 Argument::ARGUMENT_VALUE(value.c_str()));
869 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700870 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530871 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500872 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500873 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500874 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
875 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530876 }
877
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300878 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700879 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300880
William A. Kennington III1137a972019-04-20 20:49:58 -0700881 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700882 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700883 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530884 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700885 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700886 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530887 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700888 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
889 {
890 intf->MacAddressIntf::macAddress(validMAC);
891 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530892 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500893 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530894
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700895 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800896 manager.addReloadPreHook([interface]() {
897 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700898 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800899 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700900 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530901 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700902
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300903#ifdef HAVE_UBOOT_ENV
904 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700905 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300906 if (envVar)
907 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500908 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
909 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
910 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
911 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300912 }
913#endif // HAVE_UBOOT_ENV
914
William A. Kennington III1137a972019-04-20 20:49:58 -0700915 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800916#else
917 elog<NotAllowed>(
918 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
919#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530920}
921
Ratan Guptae9c9b812017-09-22 17:15:37 +0530922void EthernetInterface::deleteAll()
923{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530924 // clear all the ip on the interface
925 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700926
927 writeConfigurationFile();
928 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530929}
930
Ravi Tejaa5a09442020-07-17 00:57:33 -0500931std::string EthernetInterface::defaultGateway(std::string gateway)
932{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700933 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500934 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700935 if (!gateway.empty())
936 {
937 gateway = std::to_string(ToAddr<in_addr>{}(gateway));
938 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500939 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700940 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500941 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700942 auto msg = fmt::format("Invalid v4 GW `{}`: {}", gateway, e.what());
943 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500944 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
945 Argument::ARGUMENT_VALUE(gateway.c_str()));
946 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700947
948 if (EthernetInterfaceIntf::defaultGateway() == gateway)
949 {
950 return gateway;
951 }
952 EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700953
954 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700955 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700956
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700957 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500958}
959
960std::string EthernetInterface::defaultGateway6(std::string gateway)
961{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700962 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500963 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700964 if (!gateway.empty())
965 {
966 gateway = std::to_string(ToAddr<in6_addr>{}(gateway));
967 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500968 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700969 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500970 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700971 auto msg = fmt::format("Invalid v6 GW `{}`: {}", gateway, e.what());
972 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500973 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
974 Argument::ARGUMENT_VALUE(gateway.c_str()));
975 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700976
977 if (EthernetInterfaceIntf::defaultGateway6() == gateway)
978 {
979 return gateway;
980 }
981 EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700982
983 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700984 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700985
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700986 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500987}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700988
989EthernetInterface::VlanProperties::VlanProperties(
990 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
991 const system::InterfaceInfo& info, EthernetInterface& eth,
992 bool emitSignal) :
993 VlanIfaces(bus, objPath.c_str(),
994 emitSignal ? VlanIfaces::action::defer_emit
995 : VlanIfaces::action::emit_no_signals),
996 parentIdx(*info.parent_idx), eth(eth)
997{
998 VlanIntf::id(*info.vlan_id);
999 if (emitSignal)
1000 {
1001 this->emit_object_added();
1002 }
1003}
1004
1005void EthernetInterface::VlanProperties::delete_()
1006{
1007 auto intf = eth.interfaceName();
1008
1009 // Remove all configs for the current interface
1010 const auto& confDir = eth.manager.getConfDir();
1011 std::error_code ec;
1012 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1013 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1014
1015 // Write an updated parent interface since it has a VLAN entry
1016 for (const auto& [_, intf] : eth.manager.interfaces)
1017 {
1018 if (intf->ifIdx == parentIdx)
1019 {
1020 intf->writeConfigurationFile();
1021 }
1022 }
1023
1024 // We need to forcibly delete the interface as systemd does not
1025 deleteInterface(intf);
1026
William A. Kennington III67b09da2022-10-31 14:09:53 -07001027 if (eth.ifIdx > 0)
1028 {
1029 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1030 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001031 eth.manager.interfaces.erase(intf);
1032}
1033
Gunnar Mills57d9c502018-09-14 14:42:34 -05001034} // namespace network
1035} // namespace phosphor