blob: 76bbe7814eab55f471bbbb65d427b5efb8f9b825 [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 IIIbb0eacc2022-10-21 15:22:06 -0700222 auto ip = std::to_string(neighbor.address);
223 auto mac = std::to_string(*neighbor.mac);
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700224 auto objectPath = generateStaticNeighborObjectPath(ip, mac);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700225 staticNeighbors.emplace(
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700226 ip, std::make_unique<Neighbor>(bus, objectPath, *this, ip, mac,
227 Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800228 }
229}
230
Patrick Williams6aef7692021-05-01 06:39:41 -0500231ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700232 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530233{
William A. Kennington III59e5b912022-11-02 02:49:46 -0700234 InAddrAny addr;
235 try
Ratan Guptafc2c7242017-05-29 08:46:06 +0530236 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700237 switch (protType)
238 {
239 case IP::Protocol::IPv4:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700240 addr = ToAddr<in_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700241 break;
242 case IP::Protocol::IPv6:
William A. Kennington III59e5b912022-11-02 02:49:46 -0700243 addr = ToAddr<in6_addr>{}(ipaddress);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700244 break;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700245 default:
246 throw std::logic_error("Exhausted protocols");
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700247 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500248 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700249 catch (const std::exception& e)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500250 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700251 auto msg = fmt::format("Invalid IP `{}`: {}\n", ipaddress, e.what());
252 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipaddress.c_str()));
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500253 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
254 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
255 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700256 IfAddr ifaddr;
257 try
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500258 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700259 ifaddr = {addr, prefixLength};
260 }
261 catch (const std::exception& e)
262 {
263 auto msg = fmt::format("Invalid prefix length `{}`: {}\n", prefixLength,
264 e.what());
265 log<level::ERR>(msg.c_str(),
266 entry("PREFIXLENGTH=%" PRIu8, prefixLength));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500267 elog<InvalidArgument>(
268 Argument::ARGUMENT_NAME("prefixLength"),
269 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530270 }
271
William A. Kennington III59e5b912022-11-02 02:49:46 -0700272 auto obj =
273 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
274 ifaddr, IP::AddressOrigin::Static);
275 auto path = obj->getObjPath();
276 this->addrs.insert_or_assign(ifaddr, std::move(obj));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530277
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700278 writeConfigurationFile();
279 manager.reloadConfigs();
280
William A. Kennington III59e5b912022-11-02 02:49:46 -0700281 return path;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530282}
283
Patrick Williams6aef7692021-05-01 06:39:41 -0500284ObjectPath EthernetInterface::neighbor(std::string ipAddress,
285 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800286{
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700287 if (!isValidIP(ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800288 {
289 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500290 entry("ADDRESS=%s", ipAddress.c_str()));
291 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 IIIb01d08f2022-11-03 12:50:00 -0700294 if (!mac_address::isUnicast(ToAddr<ether_addr>{}(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800295 {
296 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500297 entry("MACADDRESS=%s", ipAddress.c_str()));
298 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
299 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800300 }
301
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700302 auto objectPath = generateStaticNeighborObjectPath(ipAddress, macAddress);
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700303 staticNeighbors.emplace(
304 ipAddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700305 std::make_unique<Neighbor>(bus, objectPath, *this, ipAddress,
William A. Kennington III9a20a6e2022-10-05 13:41:12 -0700306 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700307
308 writeConfigurationFile();
309 manager.reloadConfigs();
310
William A. Kennington III08505792019-01-30 16:00:04 -0800311 return objectPath;
312}
313
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700314void EthernetInterface::deleteStaticNeighborObject(std::string_view ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800315{
Patrick Williams6aef7692021-05-01 06:39:41 -0500316 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800317 if (it == staticNeighbors.end())
318 {
319 log<level::ERR>(
320 "DeleteStaticNeighborObject:Unable to find the object.");
321 return;
322 }
323 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700324
325 writeConfigurationFile();
326 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800327}
328
Gunnar Mills57d9c502018-09-14 14:42:34 -0500329std::string EthernetInterface::generateObjectPath(
William A. Kennington III991a8e82022-10-11 15:02:47 -0700330 IP::Protocol addressType, std::string_view ipAddress, uint8_t prefixLength,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700331 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530332{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700333 std::string_view type;
334 switch (addressType)
335 {
336 case IP::Protocol::IPv4:
337 type = "ipv4"sv;
338 break;
339 case IP::Protocol::IPv6:
340 type = "ipv6"sv;
341 break;
342 }
343 return fmt::format(
344 FMT_COMPILE("{}/{}/{:08x}"), objPath, type,
345 static_cast<uint32_t>(hash_multi(
346 ipAddress, prefixLength,
347 static_cast<std::underlying_type_t<IP::AddressOrigin>>(origin))));
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530348}
349
William A. Kennington III08505792019-01-30 16:00:04 -0800350std::string EthernetInterface::generateStaticNeighborObjectPath(
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700351 std::string_view ipAddress, std::string_view macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800352{
William A. Kennington III991a8e82022-10-11 15:02:47 -0700353 return fmt::format(
354 FMT_COMPILE("{}/static_neighbor/{:08x}"), objPath,
355 static_cast<uint32_t>(hash_multi(ipAddress, macAddress)));
William A. Kennington III08505792019-01-30 16:00:04 -0800356}
357
Patrick Williams6aef7692021-05-01 06:39:41 -0500358bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700359{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700360 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700361 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700362 writeConfigurationFile();
363 manager.reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700364 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700365 return value;
366}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700367
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700368bool EthernetInterface::dhcp4(bool value)
369{
370 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
371 {
372 writeConfigurationFile();
373 manager.reloadConfigs();
374 }
375 return value;
376}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700377
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700378bool EthernetInterface::dhcp6(bool value)
379{
380 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
381 {
382 writeConfigurationFile();
383 manager.reloadConfigs();
384 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700385 return value;
386}
387
Patrick Williams6aef7692021-05-01 06:39:41 -0500388EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530389{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700390 auto old4 = EthernetInterfaceIntf::dhcp4();
391 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
392 value == DHCPConf::v4v6stateless ||
393 value == DHCPConf::both);
394 auto old6 = EthernetInterfaceIntf::dhcp6();
395 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
396 value == DHCPConf::both);
397 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
398 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
399 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
400 value == DHCPConf::v6 || value == DHCPConf::both);
401
402 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530403 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700404 writeConfigurationFile();
405 manager.reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530406 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530407 return value;
408}
409
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700410EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
411{
412 if (dhcp6())
413 {
414 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
415 }
416 else if (dhcp4())
417 {
418 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
419 }
420 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
421}
422
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800423bool EthernetInterface::linkUp() const
424{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700425 if (ifIdx == 0)
426 {
427 return EthernetInterfaceIntf::linkUp();
428 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700429 return system::intfIsRunning(interfaceName());
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700430}
431
Tejas Patil2c0fc562021-08-03 19:13:46 +0530432size_t EthernetInterface::mtu() const
433{
William A. Kennington III3e471c52022-10-27 19:46:07 -0700434 if (ifIdx == 0)
435 {
436 return EthernetInterfaceIntf::mtu();
437 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700438 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700439 return ignoreError("GetMTU", ifname, std::nullopt,
William A. Kennington III2e09d272022-10-14 17:15:00 -0700440 [&] { return system::getMTU(ifname); })
441 .value_or(EthernetInterfaceIntf::mtu());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530442}
443
444size_t EthernetInterface::mtu(size_t value)
445{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700446 const size_t old = EthernetInterfaceIntf::mtu();
447 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530448 {
449 return value;
450 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700451 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700452 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700453 system::setMTU(ifname, value);
454 return value;
455 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530456}
457
William A. Kennington III26275a32021-07-13 20:32:42 -0700458bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700459{
William A. Kennington III26275a32021-07-13 20:32:42 -0700460 constexpr auto svc = "org.freedesktop.network1";
461 constexpr auto intf = "org.freedesktop.network1.Link";
462 constexpr auto prop = "AdministrativeState";
463 char* rpath;
464 sd_bus_path_encode("/org/freedesktop/network1/link",
William A. Kennington III2e09d272022-10-14 17:15:00 -0700465 std::to_string(ifIdx).c_str(), &rpath);
William A. Kennington III26275a32021-07-13 20:32:42 -0700466 std::string path(rpath);
467 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700468
William A. Kennington III26275a32021-07-13 20:32:42 -0700469 // Store / Parser for the AdministrativeState return value
470 std::optional<bool> ret;
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -0700471 auto cb = [&](std::string_view state) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700472 if (state != "initialized")
473 {
474 ret = state != "unmanaged";
475 }
476 };
477
478 // Build a matcher before making the property call to ensure we
479 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500480 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700481 bus,
482 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
483 "'PropertiesChanged',arg0='{}',",
484 svc, path, PROPERTY_INTERFACE, intf)
485 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500486 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700487 std::string intf;
488 std::unordered_map<std::string, std::variant<std::string>> values;
489 try
490 {
491 m.read(intf, values);
492 auto it = values.find(prop);
493 // Ignore properties that aren't AdministrativeState
494 if (it != values.end())
495 {
496 cb(std::get<std::string>(it->second));
497 }
498 }
499 catch (const std::exception& e)
500 {
501 log<level::ERR>(
502 fmt::format(
503 "AdministrativeState match parsing failed on {}: {}",
504 interfaceName(), e.what())
505 .c_str(),
506 entry("INTERFACE=%s", interfaceName().c_str()),
507 entry("ERROR=%s", e.what()));
508 }
509 });
510
511 // Actively call for the value in case the interface is already configured
512 auto method =
513 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
514 method.append(intf, prop);
515 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700516 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700517 auto reply = bus.call(method);
518 std::variant<std::string> state;
519 reply.read(state);
520 cb(std::get<std::string>(state));
521 }
522 catch (const std::exception& e)
523 {
524 log<level::ERR>(
525 fmt::format("Failed to get AdministrativeState on {}: {}",
526 interfaceName(), e.what())
527 .c_str(),
528 entry("INTERFACE=%s", interfaceName().c_str()),
529 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700530 }
531
William A. Kennington III26275a32021-07-13 20:32:42 -0700532 // The interface is not yet configured by systemd-networkd, wait until it
533 // signals us a valid state.
534 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700535 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700536 bus.wait();
537 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700538 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700539
540 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700541}
542
Patrick Williams6aef7692021-05-01 06:39:41 -0500543bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700544{
Patrick Williams6aef7692021-05-01 06:39:41 -0500545 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700546 {
547 return value;
548 }
549
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800550 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700551 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800552 if (!value)
553 {
554 // We only need to bring down the interface, networkd will always bring
555 // up managed interfaces
William A. Kennington III69f45542022-09-24 23:28:14 -0700556 manager.addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700557 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800558 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700559 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800560
561 return value;
562}
563
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530564ServerList EthernetInterface::staticNameServers(ServerList value)
565{
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700566 for (auto& ip : value)
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530567 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700568 try
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530569 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700570 ip = std::to_string(ToAddr<InAddrAny>{}(ip));
571 }
572 catch (const std::exception& e)
573 {
574 auto msg =
575 fmt::format("Not a valid IP address `{}`: {}", ip, e.what());
576 log<level::ERR>(msg.c_str()), entry("ADDRESS=%s", ip.c_str());
577 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"),
578 Argument::ARGUMENT_VALUE(ip.c_str()));
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530579 }
580 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530581 try
582 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530583 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700584
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530585 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700586 manager.reloadConfigs();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530587 }
Patrick Williams5758db32021-10-06 12:29:22 -0500588 catch (const InternalFailure& e)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530589 {
590 log<level::ERR>("Exception processing DNS entries");
591 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530592 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530593}
594
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600595void EthernetInterface::loadNTPServers(const config::Parser& config)
596{
597 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
598 EthernetInterfaceIntf::staticNTPServers(
599 config.map.getValueStrings("Network", "NTP"));
600}
601
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700602void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530603{
604 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700605 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700606 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530607}
608
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600609ServerList EthernetInterface::getNTPServerFromTimeSyncd()
610{
611 ServerList servers; // Variable to capture the NTP Server IPs
612 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
613 PROPERTY_INTERFACE, METHOD_GET);
614
615 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
616
617 try
618 {
619 auto reply = bus.call(method);
620 std::variant<ServerList> response;
621 reply.read(response);
622 servers = std::get<ServerList>(response);
623 }
624 catch (const sdbusplus::exception::SdBusError& e)
625 {
626 log<level::ERR>(
627 "Failed to get NTP server information from Systemd-Timesyncd");
628 }
629
630 return servers;
631}
632
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530633ServerList EthernetInterface::getNameServerFromResolvd()
634{
635 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700636 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530637
638 /*
639 The DNS property under org.freedesktop.resolve1.Link interface contains
640 an array containing all DNS servers currently used by resolved. It
641 contains similar information as the DNS server data written to
642 /run/systemd/resolve/resolv.conf.
643
644 Each structure in the array consists of a numeric network interface index,
645 an address family, and a byte array containing the DNS server address
646 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
647 The array contains DNS servers configured system-wide, including those
648 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
649 /etc/systemd/resolved.conf, as well as per-interface DNS server
650 information either retrieved from systemd-networkd or configured by
651 external software via SetLinkDNS().
652 */
653
654 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
655 std::variant<type> name; // Variable to capture the DNS property
656 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
657 PROPERTY_INTERFACE, METHOD_GET);
658
659 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530660
661 try
662 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500663 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530664 reply.read(name);
665 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500666 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530667 {
668 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
669 }
670 auto tupleVector = std::get_if<type>(&name);
671 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
672 {
Alexander Filippov983da552021-02-08 15:26:54 +0300673 int addressFamily = std::get<0>(*i);
674 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700675 servers.push_back(std::to_string(
676 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530677 }
678 return servers;
679}
680
William A. Kennington IIId298f932022-10-17 14:31:38 -0700681ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530682{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700683 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
684 auto idStr = std::to_string(id);
685 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800686 {
687 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700688 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
689 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800690 }
691
William A. Kennington IIId298f932022-10-17 14:31:38 -0700692 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700693 auto macStr = MacAddressIntf::macAddress();
694 std::optional<ether_addr> mac;
695 if (!macStr.empty())
696 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700697 mac.emplace(ToAddr<ether_addr>{}(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700698 }
699 auto info = system::InterfaceInfo{
700 .idx = 0, // TODO: Query the correct value after creation
701 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700702 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700703 .mac = std::move(mac),
704 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700705 .parent_idx = ifIdx,
706 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700707 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530708
Patrick Williams6aef7692021-05-01 06:39:41 -0500709 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530710 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700711 auto vlanIntf = std::make_unique<EthernetInterface>(
712 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700713 nicEnabled());
714 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530715
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700716 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530717
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700718 // write the device file for the vlan interface.
719 config::Parser config;
720 auto& netdev = config.map["NetDev"].emplace_back();
721 netdev["Name"].emplace_back(intfName);
722 netdev["Kind"].emplace_back("vlan");
723 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
724 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700725
726 writeConfigurationFile();
727 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700728
William A. Kennington IIId298f932022-10-17 14:31:38 -0700729 return objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530730}
Ratan Gupta2b106532017-07-25 16:05:02 +0530731
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600732ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530733{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600734 try
735 {
736 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530737
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600738 writeConfigurationFile();
739 manager.reloadConfigs();
740 }
741 catch (InternalFailure& e)
742 {
743 log<level::ERR>("Exception processing NTP entries");
744 }
745 return EthernetInterfaceIntf::staticNTPServers();
746}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700747
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600748ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
749{
750 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530751}
Ratan Gupta2b106532017-07-25 16:05:02 +0530752// Need to merge the below function with the code which writes the
753// config file during factory reset.
754// TODO openbmc/openbmc#1751
755
756void EthernetInterface::writeConfigurationFile()
757{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700758 config::Parser config;
759 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530760 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700761 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800762#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700763 auto mac = MacAddressIntf::macAddress();
764 if (!mac.empty())
765 {
766 link["MACAddress"].emplace_back(mac);
767 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800768#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700769 if (!EthernetInterfaceIntf::nicEnabled())
770 {
771 link["Unmanaged"].emplace_back("yes");
772 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700773 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700774 {
775 auto& network = config.map["Network"].emplace_back();
776 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400777#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700778 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400779#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700780 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400781#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700782 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
783 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
784 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600785 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700786 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700787 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700788 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700789 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
790 {
791 vlans.emplace_back(intf->interfaceName());
792 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700793 }
794 }
795 {
796 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600797 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700798 {
799 ntps.emplace_back(ntp);
800 }
801 }
802 {
803 auto& dnss = network["DNS"];
804 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
805 {
806 dnss.emplace_back(dns);
807 }
808 }
809 {
810 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700811 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700812 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700813 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700814 {
815 address.emplace_back(
816 fmt::format("{}/{}", addr.second->address(),
817 addr.second->prefixLength()));
818 }
819 }
820 }
821 {
822 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700823 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700824 {
825 auto gateway = EthernetInterfaceIntf::defaultGateway();
826 if (!gateway.empty())
827 {
828 gateways.emplace_back(gateway);
829 }
830 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530831
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700832 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700833 {
834 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
835 if (!gateway6.empty())
836 {
837 gateways.emplace_back(gateway6);
838 }
839 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600840 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800841 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700842 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700843 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500844 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700845 auto& neighbors = config.map["Neighbor"];
846 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800847 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700848 auto& neighbor = neighbors.emplace_back();
849 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
850 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800851 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500852 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500853 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700854 auto& dhcp = config.map["DHCP"].emplace_back();
855 dhcp["ClientIdentifier"].emplace_back("mac");
856 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800857 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700858 const auto& conf = *manager.getDHCPConf();
859 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
860 dhcp["UseDNS"].emplace_back(dns_enabled);
861 dhcp["UseDomains"].emplace_back(dns_enabled);
862 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
863 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
864 : "false");
865 dhcp["SendHostname"].emplace_back(
866 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800867 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500868 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700869 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
870 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700871 auto msg = fmt::format("Wrote networkd file: {}", path.native());
872 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530873}
874
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800875std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530876{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700877 if (vlan)
878 {
879 log<level::ERR>("Tried to set MAC address on VLAN");
880 elog<InternalFailure>();
881 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800882#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600883 ether_addr newMAC;
884 try
885 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700886 newMAC = ToAddr<ether_addr>{}(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600887 }
Patrick Williams5758db32021-10-06 12:29:22 -0500888 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600889 {
890 log<level::ERR>("MACAddress is not valid.",
891 entry("MAC=%s", value.c_str()));
892 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
893 Argument::ARGUMENT_VALUE(value.c_str()));
894 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700895 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530896 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500897 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500898 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500899 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
900 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530901 }
902
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300903 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700904 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300905
William A. Kennington III1137a972019-04-20 20:49:58 -0700906 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700907 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700908 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530909 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700910 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700911 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530912 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700913 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
914 {
915 intf->MacAddressIntf::macAddress(validMAC);
916 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530917 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500918 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530919
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700920 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800921 manager.addReloadPreHook([interface]() {
922 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700923 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800924 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700925 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530926 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700927
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300928#ifdef HAVE_UBOOT_ENV
929 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700930 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300931 if (envVar)
932 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500933 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
934 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
935 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
936 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300937 }
938#endif // HAVE_UBOOT_ENV
939
William A. Kennington III1137a972019-04-20 20:49:58 -0700940 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800941#else
942 elog<NotAllowed>(
943 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
944#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530945}
946
Ratan Guptae9c9b812017-09-22 17:15:37 +0530947void EthernetInterface::deleteAll()
948{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530949 // clear all the ip on the interface
950 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700951
952 writeConfigurationFile();
953 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530954}
955
Ravi Tejaa5a09442020-07-17 00:57:33 -0500956std::string EthernetInterface::defaultGateway(std::string gateway)
957{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700958 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500959 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700960 if (!gateway.empty())
961 {
962 gateway = std::to_string(ToAddr<in_addr>{}(gateway));
963 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500964 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700965 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500966 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700967 auto msg = fmt::format("Invalid v4 GW `{}`: {}", gateway, e.what());
968 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500969 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
970 Argument::ARGUMENT_VALUE(gateway.c_str()));
971 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700972
973 if (EthernetInterfaceIntf::defaultGateway() == gateway)
974 {
975 return gateway;
976 }
977 EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700978
979 writeConfigurationFile();
980 manager.reloadConfigs();
981
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700982 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500983}
984
985std::string EthernetInterface::defaultGateway6(std::string gateway)
986{
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700987 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500988 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700989 if (!gateway.empty())
990 {
991 gateway = std::to_string(ToAddr<in6_addr>{}(gateway));
992 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500993 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700994 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500995 {
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700996 auto msg = fmt::format("Invalid v6 GW `{}`: {}", gateway, e.what());
997 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500998 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
999 Argument::ARGUMENT_VALUE(gateway.c_str()));
1000 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -07001001
1002 if (EthernetInterfaceIntf::defaultGateway6() == gateway)
1003 {
1004 return gateway;
1005 }
1006 EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001007
1008 writeConfigurationFile();
1009 manager.reloadConfigs();
1010
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -07001011 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -05001012}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001013
1014EthernetInterface::VlanProperties::VlanProperties(
1015 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
1016 const system::InterfaceInfo& info, EthernetInterface& eth,
1017 bool emitSignal) :
1018 VlanIfaces(bus, objPath.c_str(),
1019 emitSignal ? VlanIfaces::action::defer_emit
1020 : VlanIfaces::action::emit_no_signals),
1021 parentIdx(*info.parent_idx), eth(eth)
1022{
1023 VlanIntf::id(*info.vlan_id);
1024 if (emitSignal)
1025 {
1026 this->emit_object_added();
1027 }
1028}
1029
1030void EthernetInterface::VlanProperties::delete_()
1031{
1032 auto intf = eth.interfaceName();
1033
1034 // Remove all configs for the current interface
1035 const auto& confDir = eth.manager.getConfDir();
1036 std::error_code ec;
1037 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1038 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1039
1040 // Write an updated parent interface since it has a VLAN entry
1041 for (const auto& [_, intf] : eth.manager.interfaces)
1042 {
1043 if (intf->ifIdx == parentIdx)
1044 {
1045 intf->writeConfigurationFile();
1046 }
1047 }
1048
1049 // We need to forcibly delete the interface as systemd does not
1050 deleteInterface(intf);
1051
William A. Kennington III67b09da2022-10-31 14:09:53 -07001052 if (eth.ifIdx > 0)
1053 {
1054 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1055 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001056 eth.manager.interfaces.erase(intf);
1057}
1058
Gunnar Mills57d9c502018-09-14 14:42:34 -05001059} // namespace network
1060} // namespace phosphor