blob: e5a3110e081e398346e6127de1081b9748c53284 [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 IIIbc2502c2022-11-07 16:31:54 -0800216void EthernetInterface::addStaticNeigh(const NeighborInfo& info)
217{
218 if ((info.state & NUD_PERMANENT) == 0)
219 {
220 return;
221 }
222 if (!info.mac)
223 {
224 auto msg = fmt::format("Missing neighbor mac for `{}` on {}\n",
225 info.addr, interfaceName());
226 log<level::ERR>(msg.c_str());
227 return;
228 }
229 staticNeighbors.emplace(
230 info.addr, std::make_unique<Neighbor>(bus, std::string_view(objPath),
231 *this, info.addr, *info.mac,
232 Neighbor::State::Permanent));
233}
234
William A. Kennington III08505792019-01-30 16:00:04 -0800235void EthernetInterface::createStaticNeighborObjects()
236{
237 staticNeighbors.clear();
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800238 for (const auto& neighbor : system::getNeighbors({.ifidx = ifIdx}))
William A. Kennington III08505792019-01-30 16:00:04 -0800239 {
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -0800240 addStaticNeigh(neighbor);
William A. Kennington III08505792019-01-30 16:00:04 -0800241 }
242}
243
Patrick Williams6aef7692021-05-01 06:39:41 -0500244ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700245 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530246{
William A. Kennington III59e5b912022-11-02 02:49:46 -0700247 InAddrAny addr;
248 try
Ratan Guptafc2c7242017-05-29 08:46:06 +0530249 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700250 switch (protType)
251 {
252 case IP::Protocol::IPv4:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700253 addr = ToAddr<in_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700254 break;
255 case IP::Protocol::IPv6:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700256 addr = ToAddr<in6_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700257 break;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700258 default:
259 throw std::logic_error("Exhausted protocols");
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700260 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500261 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700262 catch (const std::exception& e)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500263 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700264 auto msg = fmt::format("Invalid IP `{}`: {}\n", ipaddress, e.what());
265 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipaddress.c_str()));
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500266 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
267 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
268 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700269 IfAddr ifaddr;
270 try
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500271 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700272 ifaddr = {addr, prefixLength};
273 }
274 catch (const std::exception& e)
275 {
276 auto msg = fmt::format("Invalid prefix length `{}`: {}\n", prefixLength,
277 e.what());
278 log<level::ERR>(msg.c_str(),
279 entry("PREFIXLENGTH=%" PRIu8, prefixLength));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500280 elog<InvalidArgument>(
281 Argument::ARGUMENT_NAME("prefixLength"),
282 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530283 }
284
William A. Kennington III434a9432022-11-04 18:38:46 -0700285 auto [it, _] = this->addrs.insert_or_assign(
286 ifaddr,
William A. Kennington III59e5b912022-11-02 02:49:46 -0700287 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
William A. Kennington III434a9432022-11-04 18:38:46 -0700288 ifaddr, IP::AddressOrigin::Static));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530289
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700290 writeConfigurationFile();
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800291 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700292
William A. Kennington III434a9432022-11-04 18:38:46 -0700293 return it->second->getObjPath();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530294}
295
Patrick Williams6aef7692021-05-01 06:39:41 -0500296ObjectPath EthernetInterface::neighbor(std::string ipAddress,
297 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800298{
William A. Kennington III434a9432022-11-04 18:38:46 -0700299 InAddrAny addr;
300 try
William A. Kennington III08505792019-01-30 16:00:04 -0800301 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700302 addr = ToAddr<InAddrAny>{}(ipAddress);
303 }
304 catch (const std::exception& e)
305 {
306 auto msg =
307 fmt::format("Not a valid IP address `{}`: {}", ipAddress, e.what());
308 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500309 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
310 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800311 }
William A. Kennington III434a9432022-11-04 18:38:46 -0700312
313 ether_addr lladdr;
314 try
William A. Kennington III08505792019-01-30 16:00:04 -0800315 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700316 lladdr = ToAddr<ether_addr>{}(macAddress);
317 }
318 catch (const std::exception& e)
319 {
320 auto msg = fmt::format("Not a valid MAC address `{}`: {}", macAddress,
321 e.what());
322 log<level::ERR>(msg.c_str(),
323 entry("MACADDRESS=%s", macAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500324 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
325 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800326 }
327
William A. Kennington III434a9432022-11-04 18:38:46 -0700328 auto [it, _] = staticNeighbors.emplace(
329 addr,
330 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this, addr,
331 lladdr, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700332
333 writeConfigurationFile();
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -0800334 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700335
William A. Kennington III434a9432022-11-04 18:38:46 -0700336 return it->second->getObjPath();
William A. Kennington III08505792019-01-30 16:00:04 -0800337}
338
Patrick Williams6aef7692021-05-01 06:39:41 -0500339bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700340{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700341 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700342 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700343 writeConfigurationFile();
344 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700345 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700346 return value;
347}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700348
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700349bool EthernetInterface::dhcp4(bool value)
350{
351 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
352 {
353 writeConfigurationFile();
354 manager.reloadConfigs();
355 }
356 return value;
357}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700358
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700359bool EthernetInterface::dhcp6(bool value)
360{
361 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
362 {
363 writeConfigurationFile();
364 manager.reloadConfigs();
365 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700366 return value;
367}
368
Patrick Williams6aef7692021-05-01 06:39:41 -0500369EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530370{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700371 auto old4 = EthernetInterfaceIntf::dhcp4();
372 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
373 value == DHCPConf::v4v6stateless ||
374 value == DHCPConf::both);
375 auto old6 = EthernetInterfaceIntf::dhcp6();
376 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
377 value == DHCPConf::both);
378 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
379 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
380 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
381 value == DHCPConf::v6 || value == DHCPConf::both);
382
383 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530384 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700385 writeConfigurationFile();
386 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530387 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530388 return value;
389}
390
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700391EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
392{
393 if (dhcp6())
394 {
395 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
396 }
397 else if (dhcp4())
398 {
399 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
400 }
401 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
402}
403
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800404bool EthernetInterface::linkUp() const
405{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700406 if (ifIdx == 0)
407 {
408 return EthernetInterfaceIntf::linkUp();
409 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700410 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700411}
412
Tejas Patil2c0fc562021-08-03 19:13:46 +0530413size_t EthernetInterface::mtu() const
414{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700415 if (ifIdx == 0)
416 {
417 return EthernetInterfaceIntf::mtu();
418 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700419 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700420 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700421 [&] { return system::getMTU(ifname); })
422 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530423}
424
425size_t EthernetInterface::mtu(size_t value)
426{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700427 const size_t old = EthernetInterfaceIntf::mtu();
428 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530429 {
430 return value;
431 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700432 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700433 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700434 system::setMTU(ifname, value);
435 return value;
436 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530437}
438
William A. Kennington III26275a32021-07-13 20:32:42 -0700439bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700440{
William A. Kennington III26275a32021-07-13 20:32:42 -0700441 constexpr auto svc = "org.freedesktop.network1";
442 constexpr auto intf = "org.freedesktop.network1.Link";
443 constexpr auto prop = "AdministrativeState";
444 char* rpath;
445 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700446 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700447 std::string path(rpath);
448 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700449
William A. Kennington III26275a32021-07-13 20:32:42 -0700450 // Store / Parser for the AdministrativeState return value
451 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700452 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700453 if (state != "initialized")
454 {
455 ret = state != "unmanaged";
456 }
457 };
458
459 // Build a matcher before making the property call to ensure we
460 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500461 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700462 bus,
463 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
464 "'PropertiesChanged',arg0='{}',",
465 svc, path, PROPERTY_INTERFACE, intf)
466 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500467 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700468 std::string intf;
469 std::unordered_map<std::string, std::variant<std::string>> values;
470 try
471 {
472 m.read(intf, values);
473 auto it = values.find(prop);
474 // Ignore properties that aren't AdministrativeState
475 if (it != values.end())
476 {
477 cb(std::get<std::string>(it->second));
478 }
479 }
480 catch (const std::exception& e)
481 {
482 log<level::ERR>(
483 fmt::format(
484 "AdministrativeState match parsing failed on {}: {}",
485 interfaceName(), e.what())
486 .c_str(),
487 entry("INTERFACE=%s", interfaceName().c_str()),
488 entry("ERROR=%s", e.what()));
489 }
490 });
491
492 // Actively call for the value in case the interface is already configured
493 auto method =
494 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
495 method.append(intf, prop);
496 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700497 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700498 auto reply = bus.call(method);
499 std::variant<std::string> state;
500 reply.read(state);
501 cb(std::get<std::string>(state));
502 }
503 catch (const std::exception& e)
504 {
505 log<level::ERR>(
506 fmt::format("Failed to get AdministrativeState on {}: {}",
507 interfaceName(), e.what())
508 .c_str(),
509 entry("INTERFACE=%s", interfaceName().c_str()),
510 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700511 }
512
William A. Kennington III26275a32021-07-13 20:32:42 -0700513 // The interface is not yet configured by systemd-networkd, wait until it
514 // signals us a valid state.
515 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700516 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700517 bus.wait();
518 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700519 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700520
521 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700522}
523
Patrick Williams6aef7692021-05-01 06:39:41 -0500524bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700525{
Patrick Williams6aef7692021-05-01 06:39:41 -0500526 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700527 {
528 return value;
529 }
530
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800531 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700532 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800533 if (!value)
534 {
535 // We only need to bring down the interface, networkd will always bring
536 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700537 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700538 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800539 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700540 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800541
542 return value;
543}
544
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530545ServerList EthernetInterface::staticNameServers(ServerList value)
546{
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700547 for (auto& ip : value)
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530548 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700549 try
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530550 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700551 ip = std::to_string(ToAddr<InAddrAny>{}(ip));
552 }
553 catch (const std::exception& e)
554 {
555 auto msg =
556 fmt::format("Not a valid IP address `{}`: {}", ip, e.what());
557 log<level::ERR>(msg.c_str()), entry("ADDRESS=%s", ip.c_str());
558 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"),
559 Argument::ARGUMENT_VALUE(ip.c_str()));
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530560 }
561 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530562 try
563 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530564 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700565
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530566 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700567 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530568 }
Patrick Williams5758db32021-10-06 12:29:22 -0500569 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530570 {
571 log<level::ERR>("Exception processing DNS entries");
572 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530573 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530574}
575
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600576void EthernetInterface::loadNTPServers(const config::Parser& config)
577{
578 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
579 EthernetInterfaceIntf::staticNTPServers(
580 config.map.getValueStrings("Network", "NTP"));
581}
582
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700583void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530584{
585 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700586 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700587 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530588}
589
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600590ServerList EthernetInterface::getNTPServerFromTimeSyncd()
591{
592 ServerList servers; // Variable to capture the NTP Server IPs
593 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
594 PROPERTY_INTERFACE, METHOD_GET);
595
596 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
597
598 try
599 {
600 auto reply = bus.call(method);
601 std::variant<ServerList> response;
602 reply.read(response);
603 servers = std::get<ServerList>(response);
604 }
605 catch (const sdbusplus::exception::SdBusError& e)
606 {
607 log<level::ERR>(
608 "Failed to get NTP server information from Systemd-Timesyncd");
609 }
610
611 return servers;
612}
613
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530614ServerList EthernetInterface::getNameServerFromResolvd()
615{
616 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700617 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530618
619 /*
620 The DNS property under org.freedesktop.resolve1.Link interface contains
621 an array containing all DNS servers currently used by resolved. It
622 contains similar information as the DNS server data written to
623 /run/systemd/resolve/resolv.conf.
624
625 Each structure in the array consists of a numeric network interface index,
626 an address family, and a byte array containing the DNS server address
627 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
628 The array contains DNS servers configured system-wide, including those
629 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
630 /etc/systemd/resolved.conf, as well as per-interface DNS server
631 information either retrieved from systemd-networkd or configured by
632 external software via SetLinkDNS().
633 */
634
635 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
636 std::variant<type> name; // Variable to capture the DNS property
637 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
638 PROPERTY_INTERFACE, METHOD_GET);
639
640 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530641
642 try
643 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500644 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530645 reply.read(name);
646 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500647 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530648 {
649 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
650 }
651 auto tupleVector = std::get_if<type>(&name);
652 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
653 {
Alexander Filippov983da552021-02-08 15:26:54 +0300654 int addressFamily = std::get<0>(*i);
655 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700656 servers.push_back(std::to_string(
657 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530658 }
659 return servers;
660}
661
William A. Kennington IIId298f932022-10-17 14:31:38 -0700662ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530663{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700664 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
665 auto idStr = std::to_string(id);
666 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800667 {
668 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700669 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
670 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800671 }
672
William A. Kennington IIId298f932022-10-17 14:31:38 -0700673 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700674 auto macStr = MacAddressIntf::macAddress();
675 std::optional<ether_addr> mac;
676 if (!macStr.empty())
677 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700678 mac.emplace(ToAddr<ether_addr>{}(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700679 }
680 auto info = system::InterfaceInfo{
681 .idx = 0, // TODO: Query the correct value after creation
682 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700683 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700684 .mac = std::move(mac),
685 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700686 .parent_idx = ifIdx,
687 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700688 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530689
Patrick Williams6aef7692021-05-01 06:39:41 -0500690 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530691 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700692 auto vlanIntf = std::make_unique<EthernetInterface>(
693 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700694 nicEnabled());
695 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530696
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700697 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530698
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700699 // write the device file for the vlan interface.
700 config::Parser config;
701 auto& netdev = config.map["NetDev"].emplace_back();
702 netdev["Name"].emplace_back(intfName);
703 netdev["Kind"].emplace_back("vlan");
704 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
705 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700706
707 writeConfigurationFile();
708 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700709
William A. Kennington III7b90bc82022-11-17 14:55:12 -0800710 return ret;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530711}
Ratan Gupta2b106532017-07-25 16:05:02 +0530712
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600713ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530714{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600715 try
716 {
717 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530718
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600719 writeConfigurationFile();
720 manager.reloadConfigs();
721 }
722 catch (InternalFailure& e)
723 {
724 log<level::ERR>("Exception processing NTP entries");
725 }
726 return EthernetInterfaceIntf::staticNTPServers();
727}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700728
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600729ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
730{
731 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530732}
Ratan Gupta2b106532017-07-25 16:05:02 +0530733// Need to merge the below function with the code which writes the
734// config file during factory reset.
735// TODO openbmc/openbmc#1751
736
737void EthernetInterface::writeConfigurationFile()
738{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700739 config::Parser config;
740 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530741 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700742 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800743#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700744 auto mac = MacAddressIntf::macAddress();
745 if (!mac.empty())
746 {
747 link["MACAddress"].emplace_back(mac);
748 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800749#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700750 if (!EthernetInterfaceIntf::nicEnabled())
751 {
752 link["Unmanaged"].emplace_back("yes");
753 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700754 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700755 {
756 auto& network = config.map["Network"].emplace_back();
757 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400758#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700759 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400760#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700761 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400762#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700763 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
764 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
765 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600766 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700767 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700768 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700769 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700770 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
771 {
772 vlans.emplace_back(intf->interfaceName());
773 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700774 }
775 }
776 {
777 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600778 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700779 {
780 ntps.emplace_back(ntp);
781 }
782 }
783 {
784 auto& dnss = network["DNS"];
785 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
786 {
787 dnss.emplace_back(dns);
788 }
789 }
790 {
791 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700792 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700793 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700794 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700795 {
796 address.emplace_back(
797 fmt::format("{}/{}", addr.second->address(),
798 addr.second->prefixLength()));
799 }
800 }
801 }
802 {
803 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700804 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700805 {
806 auto gateway = EthernetInterfaceIntf::defaultGateway();
807 if (!gateway.empty())
808 {
809 gateways.emplace_back(gateway);
810 }
811 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530812
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700813 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700814 {
815 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
816 if (!gateway6.empty())
817 {
818 gateways.emplace_back(gateway6);
819 }
820 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600821 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800822 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700823 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700824 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500825 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700826 auto& neighbors = config.map["Neighbor"];
827 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800828 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700829 auto& neighbor = neighbors.emplace_back();
830 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
831 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800832 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500833 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500834 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700835 auto& dhcp = config.map["DHCP"].emplace_back();
836 dhcp["ClientIdentifier"].emplace_back("mac");
837 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800838 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700839 const auto& conf = *manager.getDHCPConf();
840 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
841 dhcp["UseDNS"].emplace_back(dns_enabled);
842 dhcp["UseDomains"].emplace_back(dns_enabled);
843 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
844 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
845 : "false");
846 dhcp["SendHostname"].emplace_back(
847 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800848 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500849 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700850 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
851 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700852 auto msg = fmt::format("Wrote networkd file: {}", path.native());
853 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530854}
855
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800856std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530857{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700858 if (vlan)
859 {
860 log<level::ERR>("Tried to set MAC address on VLAN");
861 elog<InternalFailure>();
862 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800863#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600864 ether_addr newMAC;
865 try
866 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700867 newMAC = ToAddr<ether_addr>{}(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600868 }
Patrick Williams5758db32021-10-06 12:29:22 -0500869 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600870 {
871 log<level::ERR>("MACAddress is not valid.",
872 entry("MAC=%s", value.c_str()));
873 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
874 Argument::ARGUMENT_VALUE(value.c_str()));
875 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700876 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530877 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500878 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500879 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500880 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
881 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530882 }
883
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300884 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700885 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300886
William A. Kennington III1137a972019-04-20 20:49:58 -0700887 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700888 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700889 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530890 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700891 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700892 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530893 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700894 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
895 {
896 intf->MacAddressIntf::macAddress(validMAC);
897 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530898 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500899 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530900
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700901 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800902 manager.addReloadPreHook([interface]() {
903 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700904 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800905 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700906 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530907 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700908
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300909#ifdef HAVE_UBOOT_ENV
910 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700911 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300912 if (envVar)
913 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500914 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
915 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
916 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
917 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300918 }
919#endif // HAVE_UBOOT_ENV
920
William A. Kennington III1137a972019-04-20 20:49:58 -0700921 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800922#else
923 elog<NotAllowed>(
924 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
925#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530926}
927
Ratan Guptae9c9b812017-09-22 17:15:37 +0530928void EthernetInterface::deleteAll()
929{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530930 // clear all the ip on the interface
931 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700932
933 writeConfigurationFile();
934 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530935}
936
Ravi Tejaa5a09442020-07-17 00:57:33 -0500937std::string EthernetInterface::defaultGateway(std::string gateway)
938{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700939 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500940 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700941 if (!gateway.empty())
942 {
943 gateway = std::to_string(ToAddr<in_addr>{}(gateway));
944 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500945 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700946 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500947 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700948 auto msg = fmt::format("Invalid v4 GW `{}`: {}", gateway, e.what());
949 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500950 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
951 Argument::ARGUMENT_VALUE(gateway.c_str()));
952 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700953
954 if (EthernetInterfaceIntf::defaultGateway() == gateway)
955 {
956 return gateway;
957 }
958 EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700959
960 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700961 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700962
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700963 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500964}
965
966std::string EthernetInterface::defaultGateway6(std::string gateway)
967{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700968 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500969 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700970 if (!gateway.empty())
971 {
972 gateway = std::to_string(ToAddr<in6_addr>{}(gateway));
973 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500974 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700975 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500976 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700977 auto msg = fmt::format("Invalid v6 GW `{}`: {}", gateway, e.what());
978 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500979 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
980 Argument::ARGUMENT_VALUE(gateway.c_str()));
981 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700982
983 if (EthernetInterfaceIntf::defaultGateway6() == gateway)
984 {
985 return gateway;
986 }
987 EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700988
989 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700990 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700991
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700992 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500993}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700994
995EthernetInterface::VlanProperties::VlanProperties(
996 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
997 const system::InterfaceInfo& info, EthernetInterface& eth,
998 bool emitSignal) :
999 VlanIfaces(bus, objPath.c_str(),
1000 emitSignal ? VlanIfaces::action::defer_emit
1001 : VlanIfaces::action::emit_no_signals),
1002 parentIdx(*info.parent_idx), eth(eth)
1003{
1004 VlanIntf::id(*info.vlan_id);
1005 if (emitSignal)
1006 {
1007 this->emit_object_added();
1008 }
1009}
1010
1011void EthernetInterface::VlanProperties::delete_()
1012{
1013 auto intf = eth.interfaceName();
1014
1015 // Remove all configs for the current interface
1016 const auto& confDir = eth.manager.getConfDir();
1017 std::error_code ec;
1018 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1019 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1020
1021 // Write an updated parent interface since it has a VLAN entry
1022 for (const auto& [_, intf] : eth.manager.interfaces)
1023 {
1024 if (intf->ifIdx == parentIdx)
1025 {
1026 intf->writeConfigurationFile();
1027 }
1028 }
1029
1030 // We need to forcibly delete the interface as systemd does not
1031 deleteInterface(intf);
1032
William A. Kennington III67b09da2022-10-31 14:09:53 -07001033 if (eth.ifIdx > 0)
1034 {
1035 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1036 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001037 eth.manager.interfaces.erase(intf);
1038}
1039
Gunnar Mills57d9c502018-09-14 14:42:34 -05001040} // namespace network
1041} // namespace phosphor