blob: a0c61939385e8a2462f9d40d378e652baf6738a9 [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();
William A. Kennington III6a923632022-11-06 18:17:33 -0800179 for (const auto& addr : system::getAddresses({.ifidx = ifIdx}))
Ratan Gupta82549cc2017-04-21 08:45:23 +0530180 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700181 if (addr.flags & IFA_F_DEPRECATED)
182 {
183 continue;
184 }
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800185 IP::AddressOrigin origin = IP::AddressOrigin::Static;
William A. Kennington III6a923632022-11-06 18:17:33 -0800186 if (dhcpIsEnabled(addr.ifaddr.getAddr()))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530187 {
188 origin = IP::AddressOrigin::DHCP;
189 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400190#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700191 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530192 {
193 origin = IP::AddressOrigin::LinkLocal;
194 }
Ali El-Haj-Mahmoud300ed5c2022-10-26 09:58:04 -0400195#endif
Ratan Gupta82549cc2017-04-21 08:45:23 +0530196
Lei YU7233c582021-04-08 14:39:43 +0800197 this->addrs.insert_or_assign(
William A. Kennington III6a923632022-11-06 18:17:33 -0800198 addr.ifaddr,
199 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
200 addr.ifaddr, origin));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530201 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530202}
203
William A. Kennington III08505792019-01-30 16:00:04 -0800204void EthernetInterface::createStaticNeighborObjects()
205{
206 staticNeighbors.clear();
207
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700208 NeighborFilter filter;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700209 filter.interface = ifIdx;
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700210 filter.state = NUD_PERMANENT;
211 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800212 for (const auto& neighbor : neighbors)
213 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700214 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800215 {
216 continue;
217 }
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700218 staticNeighbors.emplace(
William A. Kennington III434a9432022-11-04 18:38:46 -0700219 neighbor.address,
220 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this,
221 neighbor.address, *neighbor.mac,
222 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800223 }
224}
225
Patrick Williams6aef7692021-05-01 06:39:41 -0500226ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700227 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530228{
William A. Kennington III59e5b912022-11-02 02:49:46 -0700229 InAddrAny addr;
230 try
Ratan Guptafc2c7242017-05-29 08:46:06 +0530231 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700232 switch (protType)
233 {
234 case IP::Protocol::IPv4:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700235 addr = ToAddr<in_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700236 break;
237 case IP::Protocol::IPv6:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700238 addr = ToAddr<in6_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700239 break;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700240 default:
241 throw std::logic_error("Exhausted protocols");
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700242 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500243 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700244 catch (const std::exception& e)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500245 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700246 auto msg = fmt::format("Invalid IP `{}`: {}\n", ipaddress, e.what());
247 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipaddress.c_str()));
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500248 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
249 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
250 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700251 IfAddr ifaddr;
252 try
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500253 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700254 ifaddr = {addr, prefixLength};
255 }
256 catch (const std::exception& e)
257 {
258 auto msg = fmt::format("Invalid prefix length `{}`: {}\n", prefixLength,
259 e.what());
260 log<level::ERR>(msg.c_str(),
261 entry("PREFIXLENGTH=%" PRIu8, prefixLength));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500262 elog<InvalidArgument>(
263 Argument::ARGUMENT_NAME("prefixLength"),
264 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530265 }
266
William A. Kennington III434a9432022-11-04 18:38:46 -0700267 auto [it, _] = this->addrs.insert_or_assign(
268 ifaddr,
William A. Kennington III59e5b912022-11-02 02:49:46 -0700269 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
William A. Kennington III434a9432022-11-04 18:38:46 -0700270 ifaddr, IP::AddressOrigin::Static));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530271
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700272 writeConfigurationFile();
273 manager.reloadConfigs();
274
William A. Kennington III434a9432022-11-04 18:38:46 -0700275 return it->second->getObjPath();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530276}
277
Patrick Williams6aef7692021-05-01 06:39:41 -0500278ObjectPath EthernetInterface::neighbor(std::string ipAddress,
279 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800280{
William A. Kennington III434a9432022-11-04 18:38:46 -0700281 InAddrAny addr;
282 try
William A. Kennington III08505792019-01-30 16:00:04 -0800283 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700284 addr = ToAddr<InAddrAny>{}(ipAddress);
285 }
286 catch (const std::exception& e)
287 {
288 auto msg =
289 fmt::format("Not a valid IP address `{}`: {}", ipAddress, e.what());
290 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500291 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
292 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800293 }
William A. Kennington III434a9432022-11-04 18:38:46 -0700294
295 ether_addr lladdr;
296 try
William A. Kennington III08505792019-01-30 16:00:04 -0800297 {
William A. Kennington III434a9432022-11-04 18:38:46 -0700298 lladdr = ToAddr<ether_addr>{}(macAddress);
299 }
300 catch (const std::exception& e)
301 {
302 auto msg = fmt::format("Not a valid MAC address `{}`: {}", macAddress,
303 e.what());
304 log<level::ERR>(msg.c_str(),
305 entry("MACADDRESS=%s", macAddress.c_str()));
Patrick Williams6aef7692021-05-01 06:39:41 -0500306 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
307 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800308 }
309
William A. Kennington III434a9432022-11-04 18:38:46 -0700310 auto [it, _] = staticNeighbors.emplace(
311 addr,
312 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this, addr,
313 lladdr, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700314
315 writeConfigurationFile();
316 manager.reloadConfigs();
317
William A. Kennington III434a9432022-11-04 18:38:46 -0700318 return it->second->getObjPath();
William A. Kennington III08505792019-01-30 16:00:04 -0800319}
320
Patrick Williams6aef7692021-05-01 06:39:41 -0500321bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700322{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700323 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700324 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700325 writeConfigurationFile();
326 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700327 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700328 return value;
329}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700330
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700331bool EthernetInterface::dhcp4(bool value)
332{
333 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
334 {
335 writeConfigurationFile();
336 manager.reloadConfigs();
337 }
338 return value;
339}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700340
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700341bool EthernetInterface::dhcp6(bool value)
342{
343 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
344 {
345 writeConfigurationFile();
346 manager.reloadConfigs();
347 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700348 return value;
349}
350
Patrick Williams6aef7692021-05-01 06:39:41 -0500351EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530352{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700353 auto old4 = EthernetInterfaceIntf::dhcp4();
354 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
355 value == DHCPConf::v4v6stateless ||
356 value == DHCPConf::both);
357 auto old6 = EthernetInterfaceIntf::dhcp6();
358 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
359 value == DHCPConf::both);
360 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
361 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
362 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
363 value == DHCPConf::v6 || value == DHCPConf::both);
364
365 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530366 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700367 writeConfigurationFile();
368 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530369 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530370 return value;
371}
372
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700373EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
374{
375 if (dhcp6())
376 {
377 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
378 }
379 else if (dhcp4())
380 {
381 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
382 }
383 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
384}
385
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800386bool EthernetInterface::linkUp() const
387{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700388 if (ifIdx == 0)
389 {
390 return EthernetInterfaceIntf::linkUp();
391 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700392 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700393}
394
Tejas Patil2c0fc562021-08-03 19:13:46 +0530395size_t EthernetInterface::mtu() const
396{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700397 if (ifIdx == 0)
398 {
399 return EthernetInterfaceIntf::mtu();
400 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700401 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700402 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700403 [&] { return system::getMTU(ifname); })
404 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530405}
406
407size_t EthernetInterface::mtu(size_t value)
408{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700409 const size_t old = EthernetInterfaceIntf::mtu();
410 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530411 {
412 return value;
413 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700414 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700415 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700416 system::setMTU(ifname, value);
417 return value;
418 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530419}
420
William A. Kennington III26275a32021-07-13 20:32:42 -0700421bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700422{
William A. Kennington III26275a32021-07-13 20:32:42 -0700423 constexpr auto svc = "org.freedesktop.network1";
424 constexpr auto intf = "org.freedesktop.network1.Link";
425 constexpr auto prop = "AdministrativeState";
426 char* rpath;
427 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700428 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700429 std::string path(rpath);
430 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700431
William A. Kennington III26275a32021-07-13 20:32:42 -0700432 // Store / Parser for the AdministrativeState return value
433 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700434 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700435 if (state != "initialized")
436 {
437 ret = state != "unmanaged";
438 }
439 };
440
441 // Build a matcher before making the property call to ensure we
442 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500443 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700444 bus,
445 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
446 "'PropertiesChanged',arg0='{}',",
447 svc, path, PROPERTY_INTERFACE, intf)
448 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500449 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700450 std::string intf;
451 std::unordered_map<std::string, std::variant<std::string>> values;
452 try
453 {
454 m.read(intf, values);
455 auto it = values.find(prop);
456 // Ignore properties that aren't AdministrativeState
457 if (it != values.end())
458 {
459 cb(std::get<std::string>(it->second));
460 }
461 }
462 catch (const std::exception& e)
463 {
464 log<level::ERR>(
465 fmt::format(
466 "AdministrativeState match parsing failed on {}: {}",
467 interfaceName(), e.what())
468 .c_str(),
469 entry("INTERFACE=%s", interfaceName().c_str()),
470 entry("ERROR=%s", e.what()));
471 }
472 });
473
474 // Actively call for the value in case the interface is already configured
475 auto method =
476 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
477 method.append(intf, prop);
478 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700479 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700480 auto reply = bus.call(method);
481 std::variant<std::string> state;
482 reply.read(state);
483 cb(std::get<std::string>(state));
484 }
485 catch (const std::exception& e)
486 {
487 log<level::ERR>(
488 fmt::format("Failed to get AdministrativeState on {}: {}",
489 interfaceName(), e.what())
490 .c_str(),
491 entry("INTERFACE=%s", interfaceName().c_str()),
492 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700493 }
494
William A. Kennington III26275a32021-07-13 20:32:42 -0700495 // The interface is not yet configured by systemd-networkd, wait until it
496 // signals us a valid state.
497 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700498 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700499 bus.wait();
500 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700501 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700502
503 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700504}
505
Patrick Williams6aef7692021-05-01 06:39:41 -0500506bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700507{
Patrick Williams6aef7692021-05-01 06:39:41 -0500508 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700509 {
510 return value;
511 }
512
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800513 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700514 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800515 if (!value)
516 {
517 // We only need to bring down the interface, networkd will always bring
518 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700519 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700520 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800521 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700522 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800523
524 return value;
525}
526
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530527ServerList EthernetInterface::staticNameServers(ServerList value)
528{
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700529 for (auto& ip : value)
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530530 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700531 try
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530532 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700533 ip = std::to_string(ToAddr<InAddrAny>{}(ip));
534 }
535 catch (const std::exception& e)
536 {
537 auto msg =
538 fmt::format("Not a valid IP address `{}`: {}", ip, e.what());
539 log<level::ERR>(msg.c_str()), entry("ADDRESS=%s", ip.c_str());
540 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"),
541 Argument::ARGUMENT_VALUE(ip.c_str()));
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530542 }
543 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530544 try
545 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530546 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700547
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530548 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700549 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530550 }
Patrick Williams5758db32021-10-06 12:29:22 -0500551 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530552 {
553 log<level::ERR>("Exception processing DNS entries");
554 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530555 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530556}
557
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600558void EthernetInterface::loadNTPServers(const config::Parser& config)
559{
560 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
561 EthernetInterfaceIntf::staticNTPServers(
562 config.map.getValueStrings("Network", "NTP"));
563}
564
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700565void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530566{
567 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700568 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700569 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530570}
571
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600572ServerList EthernetInterface::getNTPServerFromTimeSyncd()
573{
574 ServerList servers; // Variable to capture the NTP Server IPs
575 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
576 PROPERTY_INTERFACE, METHOD_GET);
577
578 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
579
580 try
581 {
582 auto reply = bus.call(method);
583 std::variant<ServerList> response;
584 reply.read(response);
585 servers = std::get<ServerList>(response);
586 }
587 catch (const sdbusplus::exception::SdBusError& e)
588 {
589 log<level::ERR>(
590 "Failed to get NTP server information from Systemd-Timesyncd");
591 }
592
593 return servers;
594}
595
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530596ServerList EthernetInterface::getNameServerFromResolvd()
597{
598 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700599 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530600
601 /*
602 The DNS property under org.freedesktop.resolve1.Link interface contains
603 an array containing all DNS servers currently used by resolved. It
604 contains similar information as the DNS server data written to
605 /run/systemd/resolve/resolv.conf.
606
607 Each structure in the array consists of a numeric network interface index,
608 an address family, and a byte array containing the DNS server address
609 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
610 The array contains DNS servers configured system-wide, including those
611 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
612 /etc/systemd/resolved.conf, as well as per-interface DNS server
613 information either retrieved from systemd-networkd or configured by
614 external software via SetLinkDNS().
615 */
616
617 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
618 std::variant<type> name; // Variable to capture the DNS property
619 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
620 PROPERTY_INTERFACE, METHOD_GET);
621
622 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530623
624 try
625 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500626 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530627 reply.read(name);
628 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500629 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530630 {
631 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
632 }
633 auto tupleVector = std::get_if<type>(&name);
634 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
635 {
Alexander Filippov983da552021-02-08 15:26:54 +0300636 int addressFamily = std::get<0>(*i);
637 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700638 servers.push_back(std::to_string(
639 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530640 }
641 return servers;
642}
643
William A. Kennington IIId298f932022-10-17 14:31:38 -0700644ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530645{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700646 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
647 auto idStr = std::to_string(id);
648 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800649 {
650 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700651 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
652 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800653 }
654
William A. Kennington IIId298f932022-10-17 14:31:38 -0700655 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700656 auto macStr = MacAddressIntf::macAddress();
657 std::optional<ether_addr> mac;
658 if (!macStr.empty())
659 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700660 mac.emplace(ToAddr<ether_addr>{}(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700661 }
662 auto info = system::InterfaceInfo{
663 .idx = 0, // TODO: Query the correct value after creation
664 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700665 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700666 .mac = std::move(mac),
667 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700668 .parent_idx = ifIdx,
669 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700670 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530671
Patrick Williams6aef7692021-05-01 06:39:41 -0500672 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530673 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700674 auto vlanIntf = std::make_unique<EthernetInterface>(
675 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700676 nicEnabled());
677 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530678
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700679 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530680
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700681 // write the device file for the vlan interface.
682 config::Parser config;
683 auto& netdev = config.map["NetDev"].emplace_back();
684 netdev["Name"].emplace_back(intfName);
685 netdev["Kind"].emplace_back("vlan");
686 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
687 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700688
689 writeConfigurationFile();
690 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700691
William A. Kennington III7b90bc82022-11-17 14:55:12 -0800692 return ret;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530693}
Ratan Gupta2b106532017-07-25 16:05:02 +0530694
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600695ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530696{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600697 try
698 {
699 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530700
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600701 writeConfigurationFile();
702 manager.reloadConfigs();
703 }
704 catch (InternalFailure& e)
705 {
706 log<level::ERR>("Exception processing NTP entries");
707 }
708 return EthernetInterfaceIntf::staticNTPServers();
709}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700710
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600711ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
712{
713 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530714}
Ratan Gupta2b106532017-07-25 16:05:02 +0530715// Need to merge the below function with the code which writes the
716// config file during factory reset.
717// TODO openbmc/openbmc#1751
718
719void EthernetInterface::writeConfigurationFile()
720{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700721 config::Parser config;
722 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530723 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700724 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800725#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700726 auto mac = MacAddressIntf::macAddress();
727 if (!mac.empty())
728 {
729 link["MACAddress"].emplace_back(mac);
730 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800731#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700732 if (!EthernetInterfaceIntf::nicEnabled())
733 {
734 link["Unmanaged"].emplace_back("yes");
735 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700736 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700737 {
738 auto& network = config.map["Network"].emplace_back();
739 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400740#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700741 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400742#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700743 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400744#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700745 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
746 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
747 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600748 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700749 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700750 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700751 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700752 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
753 {
754 vlans.emplace_back(intf->interfaceName());
755 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700756 }
757 }
758 {
759 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600760 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700761 {
762 ntps.emplace_back(ntp);
763 }
764 }
765 {
766 auto& dnss = network["DNS"];
767 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
768 {
769 dnss.emplace_back(dns);
770 }
771 }
772 {
773 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700774 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700775 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700776 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700777 {
778 address.emplace_back(
779 fmt::format("{}/{}", addr.second->address(),
780 addr.second->prefixLength()));
781 }
782 }
783 }
784 {
785 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700786 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700787 {
788 auto gateway = EthernetInterfaceIntf::defaultGateway();
789 if (!gateway.empty())
790 {
791 gateways.emplace_back(gateway);
792 }
793 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530794
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700795 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700796 {
797 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
798 if (!gateway6.empty())
799 {
800 gateways.emplace_back(gateway6);
801 }
802 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600803 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800804 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700805 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700806 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500807 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700808 auto& neighbors = config.map["Neighbor"];
809 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800810 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700811 auto& neighbor = neighbors.emplace_back();
812 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
813 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800814 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500815 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500816 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700817 auto& dhcp = config.map["DHCP"].emplace_back();
818 dhcp["ClientIdentifier"].emplace_back("mac");
819 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800820 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700821 const auto& conf = *manager.getDHCPConf();
822 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
823 dhcp["UseDNS"].emplace_back(dns_enabled);
824 dhcp["UseDomains"].emplace_back(dns_enabled);
825 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
826 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
827 : "false");
828 dhcp["SendHostname"].emplace_back(
829 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800830 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500831 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700832 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
833 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700834 auto msg = fmt::format("Wrote networkd file: {}", path.native());
835 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530836}
837
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800838std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530839{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700840 if (vlan)
841 {
842 log<level::ERR>("Tried to set MAC address on VLAN");
843 elog<InternalFailure>();
844 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800845#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600846 ether_addr newMAC;
847 try
848 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700849 newMAC = ToAddr<ether_addr>{}(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600850 }
Patrick Williams5758db32021-10-06 12:29:22 -0500851 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600852 {
853 log<level::ERR>("MACAddress is not valid.",
854 entry("MAC=%s", value.c_str()));
855 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
856 Argument::ARGUMENT_VALUE(value.c_str()));
857 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700858 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530859 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500860 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500861 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500862 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
863 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530864 }
865
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300866 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700867 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300868
William A. Kennington III1137a972019-04-20 20:49:58 -0700869 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700870 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700871 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530872 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700873 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700874 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530875 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700876 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
877 {
878 intf->MacAddressIntf::macAddress(validMAC);
879 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530880 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500881 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530882
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700883 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800884 manager.addReloadPreHook([interface]() {
885 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700886 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800887 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700888 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530889 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700890
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300891#ifdef HAVE_UBOOT_ENV
892 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700893 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300894 if (envVar)
895 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500896 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
897 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
898 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
899 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300900 }
901#endif // HAVE_UBOOT_ENV
902
William A. Kennington III1137a972019-04-20 20:49:58 -0700903 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800904#else
905 elog<NotAllowed>(
906 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
907#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530908}
909
Ratan Guptae9c9b812017-09-22 17:15:37 +0530910void EthernetInterface::deleteAll()
911{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530912 // clear all the ip on the interface
913 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700914
915 writeConfigurationFile();
916 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530917}
918
Ravi Tejaa5a09442020-07-17 00:57:33 -0500919std::string EthernetInterface::defaultGateway(std::string gateway)
920{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700921 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500922 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700923 if (!gateway.empty())
924 {
925 gateway = std::to_string(ToAddr<in_addr>{}(gateway));
926 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500927 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700928 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500929 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700930 auto msg = fmt::format("Invalid v4 GW `{}`: {}", gateway, e.what());
931 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500932 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
933 Argument::ARGUMENT_VALUE(gateway.c_str()));
934 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700935
936 if (EthernetInterfaceIntf::defaultGateway() == gateway)
937 {
938 return gateway;
939 }
940 EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700941
942 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700943 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700944
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700945 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500946}
947
948std::string EthernetInterface::defaultGateway6(std::string gateway)
949{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700950 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500951 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700952 if (!gateway.empty())
953 {
954 gateway = std::to_string(ToAddr<in6_addr>{}(gateway));
955 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500956 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700957 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500958 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700959 auto msg = fmt::format("Invalid v6 GW `{}`: {}", gateway, e.what());
960 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500961 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
962 Argument::ARGUMENT_VALUE(gateway.c_str()));
963 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700964
965 if (EthernetInterfaceIntf::defaultGateway6() == gateway)
966 {
967 return gateway;
968 }
969 EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700970
971 writeConfigurationFile();
William A. Kennington III71590bf2022-10-31 14:14:16 -0700972 manager.reloadConfigsNoRefresh();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700973
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700974 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500975}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700976
977EthernetInterface::VlanProperties::VlanProperties(
978 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
979 const system::InterfaceInfo& info, EthernetInterface& eth,
980 bool emitSignal) :
981 VlanIfaces(bus, objPath.c_str(),
982 emitSignal ? VlanIfaces::action::defer_emit
983 : VlanIfaces::action::emit_no_signals),
984 parentIdx(*info.parent_idx), eth(eth)
985{
986 VlanIntf::id(*info.vlan_id);
987 if (emitSignal)
988 {
989 this->emit_object_added();
990 }
991}
992
993void EthernetInterface::VlanProperties::delete_()
994{
995 auto intf = eth.interfaceName();
996
997 // Remove all configs for the current interface
998 const auto& confDir = eth.manager.getConfDir();
999 std::error_code ec;
1000 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1001 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1002
1003 // Write an updated parent interface since it has a VLAN entry
1004 for (const auto& [_, intf] : eth.manager.interfaces)
1005 {
1006 if (intf->ifIdx == parentIdx)
1007 {
1008 intf->writeConfigurationFile();
1009 }
1010 }
1011
1012 // We need to forcibly delete the interface as systemd does not
1013 deleteInterface(intf);
1014
William A. Kennington III67b09da2022-10-31 14:09:53 -07001015 if (eth.ifIdx > 0)
1016 {
1017 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1018 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001019 eth.manager.interfaces.erase(intf);
1020}
1021
Gunnar Mills57d9c502018-09-14 14:42:34 -05001022} // namespace network
1023} // namespace phosphor