blob: 49a6eb67a26fbb36078b2a831c79aebf2fc19a98 [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 Gupta6dec3902017-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{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530566 for (const auto& nameserverip : value)
567 {
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700568 if (!isValidIP(nameserverip))
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530569 {
570 log<level::ERR>("Not a valid IP address"),
571 entry("ADDRESS=%s", nameserverip.c_str());
572 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530573 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530574 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
575 }
576 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530577 try
578 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530579 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700580
Ratan Gupta6dec3902017-08-20 15:28:12 +0530581 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700582 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530583 }
Patrick Williams5758db32021-10-06 12:29:22 -0500584 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530585 {
586 log<level::ERR>("Exception processing DNS entries");
587 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530588 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530589}
590
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600591void EthernetInterface::loadNTPServers(const config::Parser& config)
592{
593 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
594 EthernetInterfaceIntf::staticNTPServers(
595 config.map.getValueStrings("Network", "NTP"));
596}
597
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700598void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530599{
600 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700601 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700602 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530603}
604
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600605ServerList EthernetInterface::getNTPServerFromTimeSyncd()
606{
607 ServerList servers; // Variable to capture the NTP Server IPs
608 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
609 PROPERTY_INTERFACE, METHOD_GET);
610
611 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
612
613 try
614 {
615 auto reply = bus.call(method);
616 std::variant<ServerList> response;
617 reply.read(response);
618 servers = std::get<ServerList>(response);
619 }
620 catch (const sdbusplus::exception::SdBusError& e)
621 {
622 log<level::ERR>(
623 "Failed to get NTP server information from Systemd-Timesyncd");
624 }
625
626 return servers;
627}
628
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530629ServerList EthernetInterface::getNameServerFromResolvd()
630{
631 ServerList servers;
William A. Kennington III2e09d272022-10-14 17:15:00 -0700632 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530633
634 /*
635 The DNS property under org.freedesktop.resolve1.Link interface contains
636 an array containing all DNS servers currently used by resolved. It
637 contains similar information as the DNS server data written to
638 /run/systemd/resolve/resolv.conf.
639
640 Each structure in the array consists of a numeric network interface index,
641 an address family, and a byte array containing the DNS server address
642 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
643 The array contains DNS servers configured system-wide, including those
644 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
645 /etc/systemd/resolved.conf, as well as per-interface DNS server
646 information either retrieved from systemd-networkd or configured by
647 external software via SetLinkDNS().
648 */
649
650 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
651 std::variant<type> name; // Variable to capture the DNS property
652 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
653 PROPERTY_INTERFACE, METHOD_GET);
654
655 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530656
657 try
658 {
Asmitha Karunanithi97ddb8d2022-05-05 01:00:18 -0500659 auto reply = bus.call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530660 reply.read(name);
661 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500662 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530663 {
664 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
665 }
666 auto tupleVector = std::get_if<type>(&name);
667 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
668 {
Alexander Filippov983da552021-02-08 15:26:54 +0300669 int addressFamily = std::get<0>(*i);
670 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700671 servers.push_back(std::to_string(
672 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530673 }
674 return servers;
675}
676
William A. Kennington IIId298f932022-10-17 14:31:38 -0700677ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530678{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700679 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id);
680 auto idStr = std::to_string(id);
681 if (manager.interfaces.find(intfName) != manager.interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800682 {
683 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700684 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
685 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800686 }
687
William A. Kennington IIId298f932022-10-17 14:31:38 -0700688 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700689 auto macStr = MacAddressIntf::macAddress();
690 std::optional<ether_addr> mac;
691 if (!macStr.empty())
692 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700693 mac.emplace(ToAddr<ether_addr>{}(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700694 }
695 auto info = system::InterfaceInfo{
696 .idx = 0, // TODO: Query the correct value after creation
697 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700698 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700699 .mac = std::move(mac),
700 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700701 .parent_idx = ifIdx,
702 .vlan_id = id,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700703 };
Ratan Gupta5978dd12017-07-25 13:47:13 +0530704
Patrick Williams6aef7692021-05-01 06:39:41 -0500705 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530706 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700707 auto vlanIntf = std::make_unique<EthernetInterface>(
708 bus, manager, info, objRoot, config::Parser(), /*emit=*/true,
William A. Kennington IIId298f932022-10-17 14:31:38 -0700709 nicEnabled());
710 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530711
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700712 manager.interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530713
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700714 // write the device file for the vlan interface.
715 config::Parser config;
716 auto& netdev = config.map["NetDev"].emplace_back();
717 netdev["Name"].emplace_back(intfName);
718 netdev["Kind"].emplace_back("vlan");
719 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
720 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700721
722 writeConfigurationFile();
723 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700724
William A. Kennington IIId298f932022-10-17 14:31:38 -0700725 return objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530726}
Ratan Gupta2b106532017-07-25 16:05:02 +0530727
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600728ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530729{
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600730 try
731 {
732 EthernetInterfaceIntf::staticNTPServers(value);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530733
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600734 writeConfigurationFile();
735 manager.reloadConfigs();
736 }
737 catch (InternalFailure& e)
738 {
739 log<level::ERR>("Exception processing NTP entries");
740 }
741 return EthernetInterfaceIntf::staticNTPServers();
742}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700743
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600744ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
745{
746 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530747}
Ratan Gupta2b106532017-07-25 16:05:02 +0530748// Need to merge the below function with the code which writes the
749// config file during factory reset.
750// TODO openbmc/openbmc#1751
751
752void EthernetInterface::writeConfigurationFile()
753{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700754 config::Parser config;
755 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530756 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700757 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800758#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700759 auto mac = MacAddressIntf::macAddress();
760 if (!mac.empty())
761 {
762 link["MACAddress"].emplace_back(mac);
763 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800764#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700765 if (!EthernetInterfaceIntf::nicEnabled())
766 {
767 link["Unmanaged"].emplace_back("yes");
768 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700769 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700770 {
771 auto& network = config.map["Network"].emplace_back();
772 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400773#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700774 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400775#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700776 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400777#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700778 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
779 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
780 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600781 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700782 auto& vlans = network["VLAN"];
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700783 for (const auto& [_, intf] : manager.interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700784 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700785 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
786 {
787 vlans.emplace_back(intf->interfaceName());
788 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700789 }
790 }
791 {
792 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600793 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700794 {
795 ntps.emplace_back(ntp);
796 }
797 }
798 {
799 auto& dnss = network["DNS"];
800 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
801 {
802 dnss.emplace_back(dns);
803 }
804 }
805 {
806 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700807 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700808 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700809 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700810 {
811 address.emplace_back(
812 fmt::format("{}/{}", addr.second->address(),
813 addr.second->prefixLength()));
814 }
815 }
816 }
817 {
818 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700819 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700820 {
821 auto gateway = EthernetInterfaceIntf::defaultGateway();
822 if (!gateway.empty())
823 {
824 gateways.emplace_back(gateway);
825 }
826 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530827
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700828 if (!dhcp6())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700829 {
830 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
831 if (!gateway6.empty())
832 {
833 gateways.emplace_back(gateway6);
834 }
835 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600836 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800837 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700838 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700839 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500840 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700841 auto& neighbors = config.map["Neighbor"];
842 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800843 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700844 auto& neighbor = neighbors.emplace_back();
845 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
846 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800847 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500848 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500849 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700850 auto& dhcp = config.map["DHCP"].emplace_back();
851 dhcp["ClientIdentifier"].emplace_back("mac");
852 if (manager.getDHCPConf())
Lei YUcb2d4082021-08-12 15:26:49 +0800853 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700854 const auto& conf = *manager.getDHCPConf();
855 auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
856 dhcp["UseDNS"].emplace_back(dns_enabled);
857 dhcp["UseDomains"].emplace_back(dns_enabled);
858 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
859 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
860 : "false");
861 dhcp["SendHostname"].emplace_back(
862 conf.sendHostNameEnabled() ? "true" : "false");
Lei YUcb2d4082021-08-12 15:26:49 +0800863 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500864 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700865 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName());
866 config.writeFile(path);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700867 auto msg = fmt::format("Wrote networkd file: {}", path.native());
868 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +0530869}
870
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800871std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530872{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700873 if (vlan)
874 {
875 log<level::ERR>("Tried to set MAC address on VLAN");
876 elog<InternalFailure>();
877 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800878#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600879 ether_addr newMAC;
880 try
881 {
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700882 newMAC = ToAddr<ether_addr>{}(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600883 }
Patrick Williams5758db32021-10-06 12:29:22 -0500884 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600885 {
886 log<level::ERR>("MACAddress is not valid.",
887 entry("MAC=%s", value.c_str()));
888 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
889 Argument::ARGUMENT_VALUE(value.c_str()));
890 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700891 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530892 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500893 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500894 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500895 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
896 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530897 }
898
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300899 auto interface = interfaceName();
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700900 auto validMAC = std::to_string(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300901
William A. Kennington III1137a972019-04-20 20:49:58 -0700902 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700903 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700904 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530905 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700906 // Update everything that depends on the MAC value
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700907 for (const auto& [_, intf] : manager.interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530908 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700909 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
910 {
911 intf->MacAddressIntf::macAddress(validMAC);
912 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530913 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500914 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530915
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700916 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800917 manager.addReloadPreHook([interface]() {
918 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700919 system::setNICUp(interface, false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800920 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700921 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530922 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700923
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300924#ifdef HAVE_UBOOT_ENV
925 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700926 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300927 if (envVar)
928 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500929 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
930 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
931 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
932 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300933 }
934#endif // HAVE_UBOOT_ENV
935
William A. Kennington III1137a972019-04-20 20:49:58 -0700936 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800937#else
938 elog<NotAllowed>(
939 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
940#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530941}
942
Ratan Guptae9c9b812017-09-22 17:15:37 +0530943void EthernetInterface::deleteAll()
944{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530945 // clear all the ip on the interface
946 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700947
948 writeConfigurationFile();
949 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530950}
951
Ravi Tejaa5a09442020-07-17 00:57:33 -0500952std::string EthernetInterface::defaultGateway(std::string gateway)
953{
954 auto gw = EthernetInterfaceIntf::defaultGateway();
955 if (gw == gateway)
956 {
957 return gw;
958 }
959
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +0800960 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -0500961 {
962 log<level::ERR>("Not a valid v4 Gateway",
963 entry("GATEWAY=%s", gateway.c_str()));
964 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
965 Argument::ARGUMENT_VALUE(gateway.c_str()));
966 }
967 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700968
969 writeConfigurationFile();
970 manager.reloadConfigs();
971
Ravi Tejaa5a09442020-07-17 00:57:33 -0500972 return gw;
973}
974
975std::string EthernetInterface::defaultGateway6(std::string gateway)
976{
977 auto gw = EthernetInterfaceIntf::defaultGateway6();
978 if (gw == gateway)
979 {
980 return gw;
981 }
982
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +0800983 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -0500984 {
985 log<level::ERR>("Not a valid v6 Gateway",
986 entry("GATEWAY=%s", gateway.c_str()));
987 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
988 Argument::ARGUMENT_VALUE(gateway.c_str()));
989 }
990 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700991
992 writeConfigurationFile();
993 manager.reloadConfigs();
994
Ravi Tejaa5a09442020-07-17 00:57:33 -0500995 return gw;
996}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700997
998EthernetInterface::VlanProperties::VlanProperties(
999 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
1000 const system::InterfaceInfo& info, EthernetInterface& eth,
1001 bool emitSignal) :
1002 VlanIfaces(bus, objPath.c_str(),
1003 emitSignal ? VlanIfaces::action::defer_emit
1004 : VlanIfaces::action::emit_no_signals),
1005 parentIdx(*info.parent_idx), eth(eth)
1006{
1007 VlanIntf::id(*info.vlan_id);
1008 if (emitSignal)
1009 {
1010 this->emit_object_added();
1011 }
1012}
1013
1014void EthernetInterface::VlanProperties::delete_()
1015{
1016 auto intf = eth.interfaceName();
1017
1018 // Remove all configs for the current interface
1019 const auto& confDir = eth.manager.getConfDir();
1020 std::error_code ec;
1021 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
1022 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
1023
1024 // Write an updated parent interface since it has a VLAN entry
1025 for (const auto& [_, intf] : eth.manager.interfaces)
1026 {
1027 if (intf->ifIdx == parentIdx)
1028 {
1029 intf->writeConfigurationFile();
1030 }
1031 }
1032
1033 // We need to forcibly delete the interface as systemd does not
1034 deleteInterface(intf);
1035
William A. Kennington III67b09da2022-10-31 14:09:53 -07001036 if (eth.ifIdx > 0)
1037 {
1038 eth.manager.interfacesByIdx.erase(eth.ifIdx);
1039 }
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001040 eth.manager.interfaces.erase(intf);
1041}
1042
Gunnar Mills57d9c502018-09-14 14:42:34 -05001043} // namespace network
1044} // namespace phosphor