blob: 1830bcda41967e0b4c8aa98d947f1c631f19a19c [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
Ratan Gupta87c13982017-06-15 09:27:27 +0530176void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530177{
Ratan Gupta87c13982017-06-15 09:27:27 +0530178 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530179
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700180 AddressFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700181 filter.interface = ifIdx;
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700182 auto currentAddrs = getCurrentAddresses(filter);
183 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530184 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700185 if (addr.flags & IFA_F_DEPRECATED)
186 {
187 continue;
188 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700189 auto ifaddr = IfAddr(addr.address, addr.prefix);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800190 IP::AddressOrigin origin = IP::AddressOrigin::Static;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700191 if (dhcpIsEnabled(addr.address))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530192 {
193 origin = IP::AddressOrigin::DHCP;
194 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400195#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700196 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530197 {
198 origin = IP::AddressOrigin::LinkLocal;
199 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400200#endif
Ratan Gupta82549cc2017-04-21 08:45:23 +0530201
Lei YU7233c582021-04-08 14:39:43 +0800202 this->addrs.insert_or_assign(
William A. Kennington III59e5b912022-11-02 02:49:46 -0700203 ifaddr, std::make_unique<IPAddress>(bus, std::string_view(objPath),
204 *this, ifaddr, origin));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530205 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530206}
207
William A. Kennington III08505792019-01-30 16:00:04 -0800208void EthernetInterface::createStaticNeighborObjects()
209{
210 staticNeighbors.clear();
211
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700212 NeighborFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700213 filter.interface = ifIdx;
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700214 filter.state = NUD_PERMANENT;
215 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800216 for (const auto& neighbor : neighbors)
217 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700218 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800219 {
220 continue;
221 }
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700222 staticNeighbors.emplace(
William A. Kennington III434a9432022-11-04 18:38:46 -0700223 neighbor.address,
224 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this,
225 neighbor.address, *neighbor.mac,
226 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800227 }
228}
229
Patrick Williams6aef7692021-05-01 06:39:41 -0500230ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700231 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530232{
William A. Kennington III59e5b912022-11-02 02:49:46 -0700233 InAddrAny addr;
234 try
Ratan Guptafc2c7242017-05-29 08:46:06 +0530235 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700236 switch (protType)
237 {
238 case IP::Protocol::IPv4:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700239 addr = ToAddr<in_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700240 break;
241 case IP::Protocol::IPv6:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700242 addr = ToAddr<in6_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700243 break;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700244 default:
245 throw std::logic_error("Exhausted protocols");
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700246 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500247 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700248 catch (const std::exception& e)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500249 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700250 auto msg = fmt::format("Invalid IP `{}`: {}\n", ipaddress, e.what());
251 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipaddress.c_str()));
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500252 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
253 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
254 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700255 IfAddr ifaddr;
256 try
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500257 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700258 ifaddr = {addr, prefixLength};
259 }
260 catch (const std::exception& e)
261 {
262 auto msg = fmt::format("Invalid prefix length `{}`: {}\n", prefixLength,
263 e.what());
264 log<level::ERR>(msg.c_str(),
265 entry("PREFIXLENGTH=%" PRIu8, prefixLength));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500266 elog<InvalidArgument>(
267 Argument::ARGUMENT_NAME("prefixLength"),
268 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530269 }
270
William A. Kennington III434a9432022-11-04 18:38:46 -0700271 auto [it, _] = this->addrs.insert_or_assign(
272 ifaddr,
William A. Kennington III59e5b912022-11-02 02:49:46 -0700273 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
William A. Kennington III434a9432022-11-04 18:38:46 -0700274 ifaddr, IP::AddressOrigin::Static));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530275
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700276 writeConfigurationFile();
277 manager.reloadConfigs();
278
William A. Kennington III434a9432022-11-04 18:38:46 -0700279 return it->second->getObjPath();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530280}
281
Patrick Williams6aef7692021-05-01 06:39:41 -0500282ObjectPath EthernetInterface::neighbor(std::string ipAddress,
283 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800284{
William A. Kennington III434a9432022-11-04 18:38:46 -0700285 InAddrAny addr;
286 try
William A. Kennington III08505792019-01-30 16:00:04 -0800287 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700288 addr = ToAddr<InAddrAny>{}(ipAddress);
289 }
290 catch (const std::exception& e)
291 {
292 auto msg =
293 fmt::format("Not a valid IP address `{}`: {}", ipAddress, e.what());
294 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500295 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
296 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800297 }
William A. Kennington III434a9432022-11-04 18:38:46 -0700298
299 ether_addr lladdr;
300 try
William A. Kennington III08505792019-01-30 16:00:04 -0800301 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700302 lladdr = ToAddr<ether_addr>{}(macAddress);
303 }
304 catch (const std::exception& e)
305 {
306 auto msg = fmt::format("Not a valid MAC address `{}`: {}", macAddress,
307 e.what());
308 log<level::ERR>(msg.c_str(),
309 entry("MACADDRESS=%s", macAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500310 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
311 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800312 }
313
William A. Kennington III434a9432022-11-04 18:38:46 -0700314 auto [it, _] = staticNeighbors.emplace(
315 addr,
316 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this, addr,
317 lladdr, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700318
319 writeConfigurationFile();
320 manager.reloadConfigs();
321
William A. Kennington III434a9432022-11-04 18:38:46 -0700322 return it->second->getObjPath();
William A. Kennington III08505792019-01-30 16:00:04 -0800323}
324
Patrick Williams6aef7692021-05-01 06:39:41 -0500325bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700326{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700327 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700328 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700329 writeConfigurationFile();
330 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700331 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700332 return value;
333}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700334
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700335bool EthernetInterface::dhcp4(bool value)
336{
337 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
338 {
339 writeConfigurationFile();
340 manager.reloadConfigs();
341 }
342 return value;
343}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700344
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700345bool EthernetInterface::dhcp6(bool value)
346{
347 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
348 {
349 writeConfigurationFile();
350 manager.reloadConfigs();
351 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700352 return value;
353}
354
Patrick Williams6aef7692021-05-01 06:39:41 -0500355EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530356{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700357 auto old4 = EthernetInterfaceIntf::dhcp4();
358 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
359 value == DHCPConf::v4v6stateless ||
360 value == DHCPConf::both);
361 auto old6 = EthernetInterfaceIntf::dhcp6();
362 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
363 value == DHCPConf::both);
364 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
365 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
366 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
367 value == DHCPConf::v6 || value == DHCPConf::both);
368
369 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530370 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700371 writeConfigurationFile();
372 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530373 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530374 return value;
375}
376
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700377EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
378{
379 if (dhcp6())
380 {
381 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
382 }
383 else if (dhcp4())
384 {
385 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
386 }
387 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
388}
389
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800390bool EthernetInterface::linkUp() const
391{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700392 if (ifIdx == 0)
393 {
394 return EthernetInterfaceIntf::linkUp();
395 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700396 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700397}
398
Tejas Patil2c0fc562021-08-03 19:13:46 +0530399size_t EthernetInterface::mtu() const
400{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700401 if (ifIdx == 0)
402 {
403 return EthernetInterfaceIntf::mtu();
404 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700405 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700406 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700407 [&] { return system::getMTU(ifname); })
408 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530409}
410
411size_t EthernetInterface::mtu(size_t value)
412{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700413 const size_t old = EthernetInterfaceIntf::mtu();
414 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530415 {
416 return value;
417 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700418 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700419 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700420 system::setMTU(ifname, value);
421 return value;
422 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530423}
424
William A. Kennington III26275a32021-07-13 20:32:42 -0700425bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700426{
William A. Kennington III26275a32021-07-13 20:32:42 -0700427 constexpr auto svc = "org.freedesktop.network1";
428 constexpr auto intf = "org.freedesktop.network1.Link";
429 constexpr auto prop = "AdministrativeState";
430 char* rpath;
431 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700432 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700433 std::string path(rpath);
434 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700435
William A. Kennington III26275a32021-07-13 20:32:42 -0700436 // Store / Parser for the AdministrativeState return value
437 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700438 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700439 if (state != "initialized")
440 {
441 ret = state != "unmanaged";
442 }
443 };
444
445 // Build a matcher before making the property call to ensure we
446 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500447 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700448 bus,
449 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
450 "'PropertiesChanged',arg0='{}',",
451 svc, path, PROPERTY_INTERFACE, intf)
452 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500453 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700454 std::string intf;
455 std::unordered_map<std::string, std::variant<std::string>> values;
456 try
457 {
458 m.read(intf, values);
459 auto it = values.find(prop);
460 // Ignore properties that aren't AdministrativeState
461 if (it != values.end())
462 {
463 cb(std::get<std::string>(it->second));
464 }
465 }
466 catch (const std::exception& e)
467 {
468 log<level::ERR>(
469 fmt::format(
470 "AdministrativeState match parsing failed on {}: {}",
471 interfaceName(), e.what())
472 .c_str(),
473 entry("INTERFACE=%s", interfaceName().c_str()),
474 entry("ERROR=%s", e.what()));
475 }
476 });
477
478 // Actively call for the value in case the interface is already configured
479 auto method =
480 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
481 method.append(intf, prop);
482 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700483 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700484 auto reply = bus.call(method);
485 std::variant<std::string> state;
486 reply.read(state);
487 cb(std::get<std::string>(state));
488 }
489 catch (const std::exception& e)
490 {
491 log<level::ERR>(
492 fmt::format("Failed to get AdministrativeState on {}: {}",
493 interfaceName(), e.what())
494 .c_str(),
495 entry("INTERFACE=%s", interfaceName().c_str()),
496 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700497 }
498
William A. Kennington III26275a32021-07-13 20:32:42 -0700499 // The interface is not yet configured by systemd-networkd, wait until it
500 // signals us a valid state.
501 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700502 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700503 bus.wait();
504 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700505 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700506
507 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700508}
509
Patrick Williams6aef7692021-05-01 06:39:41 -0500510bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700511{
Patrick Williams6aef7692021-05-01 06:39:41 -0500512 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700513 {
514 return value;
515 }
516
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800517 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700518 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800519 if (!value)
520 {
521 // We only need to bring down the interface, networkd will always bring
522 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700523 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700524 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800525 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700526 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800527
528 return value;
529}
530
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530531ServerList EthernetInterface::staticNameServers(ServerList value)
532{
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700533 for (auto& ip : value)
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530534 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700535 try
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530536 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700537 ip = std::to_string(ToAddr<InAddrAny>{}(ip));
538 }
539 catch (const std::exception& e)
540 {
541 auto msg =
542 fmt::format("Not a valid IP address `{}`: {}", ip, e.what());
543 log<level::ERR>(msg.c_str()), entry("ADDRESS=%s", ip.c_str());
544 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"),
545 Argument::ARGUMENT_VALUE(ip.c_str()));
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530546 }
547 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530548 try
549 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530550 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700551
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530552 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700553 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530554 }
Patrick Williams5758db32021-10-06 12:29:22 -0500555 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530556 {
557 log<level::ERR>("Exception processing DNS entries");
558 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530559 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530560}
561
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600562void EthernetInterface::loadNTPServers(const config::Parser& config)
563{
564 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
565 EthernetInterfaceIntf::staticNTPServers(
566 config.map.getValueStrings("Network", "NTP"));
567}
568
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700569void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530570{
571 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700572 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700573 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530574}
575
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600576ServerList EthernetInterface::getNTPServerFromTimeSyncd()
577{
578 ServerList servers; // Variable to capture the NTP Server IPs
579 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
580 PROPERTY_INTERFACE, METHOD_GET);
581
582 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
583
584 try
585 {
586 auto reply = bus.call(method);
587 std::variant<ServerList> response;
588 reply.read(response);
589 servers = std::get<ServerList>(response);
590 }
591 catch (const sdbusplus::exception::SdBusError& e)
592 {
593 log<level::ERR>(
594 "Failed to get NTP server information from Systemd-Timesyncd");
595 }
596
597 return servers;
598}
599
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530600ServerList EthernetInterface::getNameServerFromResolvd()
601{
602 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700603 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530604
605 /*
606 The DNS property under org.freedesktop.resolve1.Link interface contains
607 an array containing all DNS servers currently used by resolved. It
608 contains similar information as the DNS server data written to
609 /run/systemd/resolve/resolv.conf.
610
611 Each structure in the array consists of a numeric network interface index,
612 an address family, and a byte array containing the DNS server address
613 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
614 The array contains DNS servers configured system-wide, including those
615 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
616 /etc/systemd/resolved.conf, as well as per-interface DNS server
617 information either retrieved from systemd-networkd or configured by
618 external software via SetLinkDNS().
619 */
620
621 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
622 std::variant<type> name; // Variable to capture the DNS property
623 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
624 PROPERTY_INTERFACE, METHOD_GET);
625
626 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530627
628 try
629 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500630 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530631 reply.read(name);
632 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500633 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530634 {
635 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
636 }
637 auto tupleVector = std::get_if<type>(&name);
638 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
639 {
Alexander Filippov983da552021-02-08 15:26:54 +0300640 int addressFamily = std::get<0>(*i);
641 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700642 servers.push_back(std::to_string(
643 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530644 }
645 return servers;
646}
647
William A. Kennington IIId298f932022-10-17 14:31:38 -0700648ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530649{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700650 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
651 auto idStr = std::to_string(id);
652 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800653 {
654 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700655 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
656 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800657 }
658
William A. Kennington IIId298f932022-10-17 14:31:38 -0700659 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700660 auto macStr = MacAddressIntf::macAddress();
661 std::optional<ether_addr> mac;
662 if (!macStr.empty())
663 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700664 mac.emplace(ToAddr<ether_addr>{}(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700665 }
666 auto info = system::InterfaceInfo{
667 .idx = 0, // TODO: Query the correct value after creation
668 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700669 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700670 .mac = std::move(mac),
671 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700672 .parent_idx = ifIdx,
673 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700674 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530675
Patrick Williams6aef7692021-05-01 06:39:41 -0500676 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530677 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700678 auto vlanIntf = std::make_unique<EthernetInterface>(
679 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700680 nicEnabled());
681 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530682
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700683 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530684
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700685 // write the device file for the vlan interface.
686 config::Parser config;
687 auto& netdev = config.map["NetDev"].emplace_back();
688 netdev["Name"].emplace_back(intfName);
689 netdev["Kind"].emplace_back("vlan");
690 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
691 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700692
693 writeConfigurationFile();
694 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700695
William A. Kennington IIId298f932022-10-17 14:31:38 -0700696 return objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530697}
Ratan Gupta2b106532017-07-25 16:05:02 +0530698
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600699ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530700{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600701 try
702 {
703 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530704
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600705 writeConfigurationFile();
706 manager.reloadConfigs();
707 }
708 catch (InternalFailure& e)
709 {
710 log<level::ERR>("Exception processing NTP entries");
711 }
712 return EthernetInterfaceIntf::staticNTPServers();
713}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700714
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600715ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
716{
717 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530718}
Ratan Gupta2b106532017-07-25 16:05:02 +0530719// Need to merge the below function with the code which writes the
720// config file during factory reset.
721// TODO openbmc/openbmc#1751
722
723void EthernetInterface::writeConfigurationFile()
724{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700725 config::Parser config;
726 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530727 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700728 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800729#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700730 auto mac = MacAddressIntf::macAddress();
731 if (!mac.empty())
732 {
733 link["MACAddress"].emplace_back(mac);
734 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800735#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700736 if (!EthernetInterfaceIntf::nicEnabled())
737 {
738 link["Unmanaged"].emplace_back("yes");
739 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700740 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700741 {
742 auto& network = config.map["Network"].emplace_back();
743 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400744#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700745 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400746#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700747 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400748#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700749 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
750 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
751 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600752 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700753 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700754 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700755 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700756 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
757 {
758 vlans.emplace_back(intf->interfaceName());
759 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700760 }
761 }
762 {
763 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600764 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700765 {
766 ntps.emplace_back(ntp);
767 }
768 }
769 {
770 auto& dnss = network["DNS"];
771 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
772 {
773 dnss.emplace_back(dns);
774 }
775 }
776 {
777 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700778 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700779 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700780 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700781 {
782 address.emplace_back(
783 fmt::format("{}/{}", addr.second->address(),
784 addr.second->prefixLength()));
785 }
786 }
787 }
788 {
789 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700790 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700791 {
792 auto gateway = EthernetInterfaceIntf::defaultGateway();
793 if (!gateway.empty())
794 {
795 gateways.emplace_back(gateway);
796 }
797 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530798
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700799 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700800 {
801 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
802 if (!gateway6.empty())
803 {
804 gateways.emplace_back(gateway6);
805 }
806 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600807 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800808 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700809 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700810 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500811 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700812 auto& neighbors = config.map["Neighbor"];
813 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800814 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700815 auto& neighbor = neighbors.emplace_back();
816 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
817 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800818 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500819 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500820 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700821 auto& dhcp = config.map["DHCP"].emplace_back();
822 dhcp["ClientIdentifier"].emplace_back("mac");
823 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800824 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700825 const auto& conf = *manager.getDHCPConf();
826 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
827 dhcp["UseDNS"].emplace_back(dns_enabled);
828 dhcp["UseDomains"].emplace_back(dns_enabled);
829 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
830 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
831 : "false");
832 dhcp["SendHostname"].emplace_back(
833 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800834 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500835 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700836 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
837 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700838 auto msg = fmt::format("Wrote networkd file: {}", path.native());
839 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530840}
841
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800842std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530843{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700844 if (vlan)
845 {
846 log<level::ERR>("Tried to set MAC address on VLAN");
847 elog<InternalFailure>();
848 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800849#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600850 ether_addr newMAC;
851 try
852 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700853 newMAC = ToAddr<ether_addr>{}(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600854 }
Patrick Williams5758db32021-10-06 12:29:22 -0500855 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600856 {
857 log<level::ERR>("MACAddress is not valid.",
858 entry("MAC=%s", value.c_str()));
859 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
860 Argument::ARGUMENT_VALUE(value.c_str()));
861 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700862 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530863 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500864 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500865 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500866 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
867 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530868 }
869
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300870 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700871 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300872
William A. Kennington III1137a972019-04-20 20:49:58 -0700873 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700874 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700875 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530876 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700877 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700878 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530879 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700880 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
881 {
882 intf->MacAddressIntf::macAddress(validMAC);
883 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530884 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500885 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530886
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700887 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800888 manager.addReloadPreHook([interface]() {
889 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700890 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800891 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700892 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530893 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700894
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300895#ifdef HAVE_UBOOT_ENV
896 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700897 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300898 if (envVar)
899 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500900 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
901 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
902 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
903 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300904 }
905#endif // HAVE_UBOOT_ENV
906
William A. Kennington III1137a972019-04-20 20:49:58 -0700907 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800908#else
909 elog<NotAllowed>(
910 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
911#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530912}
913
Ratan Guptae9c9b812017-09-22 17:15:37 +0530914void EthernetInterface::deleteAll()
915{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530916 // clear all the ip on the interface
917 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700918
919 writeConfigurationFile();
920 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530921}
922
Ravi Tejaa5a09442020-07-17 00:57:33 -0500923std::string EthernetInterface::defaultGateway(std::string gateway)
924{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700925 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500926 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700927 if (!gateway.empty())
928 {
929 gateway = std::to_string(ToAddr<in_addr>{}(gateway));
930 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500931 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700932 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500933 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700934 auto msg = fmt::format("Invalid v4 GW `{}`: {}", gateway, e.what());
935 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500936 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
937 Argument::ARGUMENT_VALUE(gateway.c_str()));
938 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700939
940 if (EthernetInterfaceIntf::defaultGateway() == gateway)
941 {
942 return gateway;
943 }
944 EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700945
946 writeConfigurationFile();
947 manager.reloadConfigs();
948
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700949 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500950}
951
952std::string EthernetInterface::defaultGateway6(std::string gateway)
953{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700954 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500955 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700956 if (!gateway.empty())
957 {
958 gateway = std::to_string(ToAddr<in6_addr>{}(gateway));
959 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500960 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700961 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500962 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700963 auto msg = fmt::format("Invalid v6 GW `{}`: {}", gateway, e.what());
964 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500965 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
966 Argument::ARGUMENT_VALUE(gateway.c_str()));
967 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700968
969 if (EthernetInterfaceIntf::defaultGateway6() == gateway)
970 {
971 return gateway;
972 }
973 EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700974
975 writeConfigurationFile();
976 manager.reloadConfigs();
977
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700978 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500979}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700980
981EthernetInterface::VlanProperties::VlanProperties(
982 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
983 const system::InterfaceInfo& info, EthernetInterface& eth,
984 bool emitSignal) :
985 VlanIfaces(bus, objPath.c_str(),
986 emitSignal ? VlanIfaces::action::defer_emit
987 : VlanIfaces::action::emit_no_signals),
988 parentIdx(*info.parent_idx), eth(eth)
989{
990 VlanIntf::id(*info.vlan_id);
991 if (emitSignal)
992 {
993 this->emit_object_added();
994 }
995}
996
997void EthernetInterface::VlanProperties::delete_()
998{
999 auto intf = eth.interfaceName();
1000
1001 // Remove all configs for the current interface
1002 const auto& confDir = eth.manager.getConfDir();
1003 std::error_code ec;
1004 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1005 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1006
1007 // Write an updated parent interface since it has a VLAN entry
1008 for (const auto& [_, intf] : eth.manager.interfaces)
1009 {
1010 if (intf->ifIdx == parentIdx)
1011 {
1012 intf->writeConfigurationFile();
1013 }
1014 }
1015
1016 // We need to forcibly delete the interface as systemd does not
1017 deleteInterface(intf);
1018
William A. Kennington III67b09da2022-10-31 14:09:53 -07001019 if (eth.ifIdx > 0)
1020 {
1021 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1022 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001023 eth.manager.interfaces.erase(intf);
1024}
1025
Gunnar Mills57d9c502018-09-14 14:42:34 -05001026} // namespace network
1027} // namespace phosphor