blob: 1467240794f9319e0ddfc470fd298bf739c7885f [file] [log] [blame]
Patrick Rudolph9caa64d2023-09-04 11:22:31 +02001#include "config.h"
Gunnar Mills57d9c502018-09-14 14:42:34 -05002
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 IIId7946a72019-04-19 14:24:09 -070010#include <linux/rtnetlink.h>
William A. Kennington IIIfd862be2022-10-09 18:40:55 -070011#include <net/if.h>
William A. Kennington III9c441fd2023-02-24 13:40:01 -080012#include <net/if_arp.h>
Yuxiao Zhang46938072023-09-26 17:59:14 -070013#include <sys/stat.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014
Patrick Venture189d44e2018-07-09 12:30:59 -070015#include <phosphor-logging/elog-errors.hpp>
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -070016#include <phosphor-logging/lg2.hpp>
William A. Kennington III945878a2024-04-17 01:05:27 -070017#include <stdplus/fd/create.hpp>
William A. Kennington III12beaad2020-06-13 19:30:41 -070018#include <stdplus/raw.hpp>
William A. Kennington III86642522023-07-24 17:55:55 -070019#include <stdplus/str/cat.hpp>
William A. Kennington III69f45542022-09-24 23:28:14 -070020#include <stdplus/zstring.hpp>
Patrick Williams89d734b2023-05-10 07:50:25 -050021#include <xyz/openbmc_project/Common/error.hpp>
22
23#include <algorithm>
24#include <filesystem>
William A. Kennington IIIcafc1512023-07-25 02:22:32 -070025#include <format>
Ratan Gupta2b106532017-07-25 16:05:02 +053026#include <string>
William A. Kennington III26275a32021-07-13 20:32:42 -070027#include <unordered_map>
28#include <variant>
Ratan Gupta82549cc2017-04-21 08:45:23 +053029
Ratan Gupta91a99cc2017-04-14 16:32:09 +053030namespace phosphor
31{
32namespace network
33{
34
35using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053036using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053037using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
38using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050039using Argument = xyz::openbmc_project::Common::InvalidArgument;
William A. Kennington III991a8e82022-10-11 15:02:47 -070040using std::literals::string_view_literals::operator""sv;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053041constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
42constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
43constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
44constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -060045
46constexpr auto TIMESYNCD_SERVICE = "org.freedesktop.timesync1";
47constexpr auto TIMESYNCD_INTERFACE = "org.freedesktop.timesync1.Manager";
48constexpr auto TIMESYNCD_SERVICE_PATH = "/org/freedesktop/timesync1";
49
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053050constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053051
William A. Kennington III2e09d272022-10-14 17:15:00 -070052template <typename Func>
53inline decltype(std::declval<Func>()())
54 ignoreError(std::string_view msg, stdplus::zstring_view intf,
55 decltype(std::declval<Func>()()) fallback, Func&& func) noexcept
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080056{
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070057 try
58 {
William A. Kennington III2e09d272022-10-14 17:15:00 -070059 return func();
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070060 }
William A. Kennington III2e09d272022-10-14 17:15:00 -070061 catch (const std::exception& e)
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070062 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -070063 lg2::error("{MSG} failed on {NET_INTF}: {ERROR}", "MSG", msg,
64 "NET_INTF", intf, "ERROR", e);
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070065 }
William A. Kennington III2e09d272022-10-14 17:15:00 -070066 return fallback;
William A. Kennington III4ee7a7e2022-10-11 16:37:22 -070067}
William A. Kennington IIId298f932022-10-17 14:31:38 -070068
William A. Kennington IIId298f932022-10-17 14:31:38 -070069static std::string makeObjPath(std::string_view root, std::string_view intf)
70{
William A. Kennington III86642522023-07-24 17:55:55 -070071 auto ret = stdplus::strCat(root, "/"sv, intf);
William A. Kennington IIId298f932022-10-17 14:31:38 -070072 std::replace(ret.begin() + ret.size() - intf.size(), ret.end(), '.', '_');
73 return ret;
74}
75
William A. Kennington IIIbbf5e9e2023-02-01 14:58:38 -080076template <typename Addr>
77static bool validIntfIP(Addr a) noexcept
78{
79 return a.isUnicast() && !a.isLoopback();
80}
81
William A. Kennington III9ede1b72022-11-21 01:59:28 -080082EthernetInterface::EthernetInterface(stdplus::PinnedRef<sdbusplus::bus_t> bus,
83 stdplus::PinnedRef<Manager> manager,
William A. Kennington III13d665c2022-11-15 20:34:40 -080084 const AllIntfInfo& info,
William A. Kennington IIId298f932022-10-17 14:31:38 -070085 std::string_view objRoot,
William A. Kennington IIIa520a392022-08-08 12:17:34 -070086 const config::Parser& config,
William A. Kennington IIIb6452542022-11-15 18:09:12 -080087 bool enabled) :
William A. Kennington III13d665c2022-11-15 20:34:40 -080088 EthernetInterface(bus, manager, info, makeObjPath(objRoot, *info.intf.name),
William A. Kennington IIIb6452542022-11-15 18:09:12 -080089 config, enabled)
Patrick Williams89d734b2023-05-10 07:50:25 -050090{}
William A. Kennington IIId298f932022-10-17 14:31:38 -070091
William A. Kennington III9ede1b72022-11-21 01:59:28 -080092EthernetInterface::EthernetInterface(stdplus::PinnedRef<sdbusplus::bus_t> bus,
93 stdplus::PinnedRef<Manager> manager,
William A. Kennington III13d665c2022-11-15 20:34:40 -080094 const AllIntfInfo& info,
William A. Kennington IIId298f932022-10-17 14:31:38 -070095 std::string&& objPath,
96 const config::Parser& config,
William A. Kennington IIIb6452542022-11-15 18:09:12 -080097 bool enabled) :
98 Ifaces(bus, objPath.c_str(), Ifaces::action::defer_emit),
William A. Kennington III876927c2022-11-17 16:20:15 -080099 manager(manager), bus(bus), objPath(std::move(objPath))
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530100{
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800101 interfaceName(*info.intf.name, true);
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700102 auto dhcpVal = getDHCPValue(config);
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800103 EthernetInterfaceIntf::dhcp4(dhcpVal.v4, true);
104 EthernetInterfaceIntf::dhcp6(dhcpVal.v6, true);
105 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRA(config), true);
106 EthernetInterfaceIntf::nicEnabled(enabled, true);
Ravi Tejaa5a09442020-07-17 00:57:33 -0500107
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700108 EthernetInterfaceIntf::ntpServers(
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800109 config.map.getValueStrings("Network", "NTP"), true);
Ratan Gupta613a0122020-04-24 15:18:53 +0530110
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800111 updateInfo(info.intf, true);
112
113 if (info.defgw4)
114 {
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700115 EthernetInterface::defaultGateway(stdplus::toStr(*info.defgw4), true);
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800116 }
117 if (info.defgw6)
118 {
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700119 EthernetInterface::defaultGateway6(stdplus::toStr(*info.defgw6), true);
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800120 }
121 emit_object_added();
William A. Kennington IIId298f932022-10-17 14:31:38 -0700122
William A. Kennington III13d665c2022-11-15 20:34:40 -0800123 if (info.intf.vlan_id)
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700124 {
William A. Kennington III13d665c2022-11-15 20:34:40 -0800125 if (!info.intf.parent_idx)
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700126 {
127 std::runtime_error("Missing parent link");
128 }
William A. Kennington III13d665c2022-11-15 20:34:40 -0800129 vlan.emplace(bus, this->objPath.c_str(), info.intf, *this);
130 }
William A. Kennington IIIfad525c2024-04-17 00:51:59 -0700131 dhcp4Conf.emplace(bus, this->objPath + "/dhcp4", *this, DHCPType::v4);
132 dhcp6Conf.emplace(bus, this->objPath + "/dhcp6", *this, DHCPType::v6);
William A. Kennington III13d665c2022-11-15 20:34:40 -0800133 for (const auto& [_, addr] : info.addrs)
134 {
135 addAddr(addr);
136 }
137 for (const auto& [_, neigh] : info.staticNeighs)
138 {
139 addStaticNeigh(neigh);
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700140 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530141}
142
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800143void EthernetInterface::updateInfo(const InterfaceInfo& info, bool skipSignal)
William A. Kennington IIId298f932022-10-17 14:31:38 -0700144{
William A. Kennington III876927c2022-11-17 16:20:15 -0800145 ifIdx = info.idx;
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800146 EthernetInterfaceIntf::linkUp(info.flags & IFF_RUNNING, skipSignal);
William A. Kennington IIId298f932022-10-17 14:31:38 -0700147 if (info.mac)
148 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700149 MacAddressIntf::macAddress(stdplus::toStr(*info.mac), skipSignal);
William A. Kennington IIId298f932022-10-17 14:31:38 -0700150 }
151 if (info.mtu)
152 {
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800153 EthernetInterfaceIntf::mtu(*info.mtu, skipSignal);
William A. Kennington IIId298f932022-10-17 14:31:38 -0700154 }
William A. Kennington III21539662022-11-15 14:53:11 -0800155 if (ifIdx > 0)
156 {
157 auto ethInfo = ignoreError("GetEthInfo", *info.name, {}, [&] {
158 return system::getEthInfo(*info.name);
159 });
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800160 EthernetInterfaceIntf::autoNeg(ethInfo.autoneg, skipSignal);
161 EthernetInterfaceIntf::speed(ethInfo.speed, skipSignal);
William A. Kennington III21539662022-11-15 14:53:11 -0800162 }
William A. Kennington IIId298f932022-10-17 14:31:38 -0700163}
164
Johnathan Mantey817012a2020-01-30 15:07:39 -0800165bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
166{
167 return (
168#ifdef LINK_LOCAL_AUTOCONFIGURATION
Johnathan Manteyfabe3952023-09-08 13:21:05 -0700169 (origin == IP::AddressOrigin::Static)
170#else
Johnathan Mantey817012a2020-01-30 15:07:39 -0800171 (origin == IP::AddressOrigin::Static ||
172 origin == IP::AddressOrigin::LinkLocal)
173#endif
174
175 );
176}
177
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800178void EthernetInterface::addAddr(const AddressInfo& info)
179{
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800180 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ravi Teja86c4f442023-07-19 22:26:39 -0500181 if (dhcpIsEnabled(info.ifaddr.getAddr()))
182 {
183 origin = IP::AddressOrigin::DHCP;
184 }
185
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800186#ifdef LINK_LOCAL_AUTOCONFIGURATION
187 if (info.scope == RT_SCOPE_LINK)
188 {
189 origin = IP::AddressOrigin::LinkLocal;
190 }
191#endif
192
Ravi Tejac6201202023-03-28 21:29:58 -0500193 if ((info.scope == RT_SCOPE_UNIVERSE) && (info.flags & IFA_F_PERMANENT))
194 {
195 origin = IP::AddressOrigin::Static;
196 }
197 if ((info.scope == RT_SCOPE_UNIVERSE) &&
198 ((info.flags & IFA_F_NOPREFIXROUTE) &&
199 (info.flags & IFA_F_MANAGETEMPADDR)))
200 {
201 origin = IP::AddressOrigin::SLAAC;
202 }
203 else if ((info.scope == RT_SCOPE_UNIVERSE) &&
204 ((info.flags & IFA_F_NOPREFIXROUTE)))
205 {
206 origin = IP::AddressOrigin::DHCP;
207 }
208
William A. Kennington III77747f62022-11-07 23:11:15 -0800209 auto it = addrs.find(info.ifaddr);
210 if (it == addrs.end())
211 {
212 addrs.emplace(info.ifaddr, std::make_unique<IPAddress>(
213 bus, std::string_view(objPath), *this,
214 info.ifaddr, origin));
215 }
216 else
217 {
218 it->second->IPIfaces::origin(origin);
219 }
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800220}
221
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -0800222void EthernetInterface::addStaticNeigh(const NeighborInfo& info)
223{
William A. Kennington IIId3615142022-11-12 01:28:33 -0800224 if (!info.mac || !info.addr)
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -0800225 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700226 lg2::error("Missing neighbor mac on {NET_INTF}", "NET_INTF",
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -0700227 interfaceName());
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -0800228 return;
229 }
William A. Kennington III4e75acc2022-11-14 19:13:31 -0800230
231 if (auto it = staticNeighbors.find(*info.addr); it != staticNeighbors.end())
232 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700233 it->second->NeighborObj::macAddress(stdplus::toStr(*info.mac));
William A. Kennington III4e75acc2022-11-14 19:13:31 -0800234 }
235 else
236 {
237 staticNeighbors.emplace(*info.addr, std::make_unique<Neighbor>(
238 bus, std::string_view(objPath),
239 *this, *info.addr, *info.mac,
240 Neighbor::State::Permanent));
241 }
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -0800242}
243
Patrick Williams6aef7692021-05-01 06:39:41 -0500244ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
William A. Kennington IIIe25f8b42022-10-11 14:43:28 -0700245 uint8_t prefixLength, std::string)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530246{
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700247 std::optional<stdplus::InAnyAddr> addr;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700248 try
Ratan Guptafc2c7242017-05-29 08:46:06 +0530249 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700250 switch (protType)
251 {
252 case IP::Protocol::IPv4:
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700253 addr.emplace(stdplus::fromStr<stdplus::In4Addr>(ipaddress));
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700254 break;
255 case IP::Protocol::IPv6:
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700256 addr.emplace(stdplus::fromStr<stdplus::In6Addr>(ipaddress));
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700257 break;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700258 default:
259 throw std::logic_error("Exhausted protocols");
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700260 }
William A. Kennington III30f3ba22023-06-28 15:50:12 -0700261 if (!std::visit([](auto ip) { return validIntfIP(ip); }, *addr))
262 {
263 throw std::invalid_argument("not unicast");
264 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500265 }
William A. Kennington III59e5b912022-11-02 02:49:46 -0700266 catch (const std::exception& e)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500267 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700268 lg2::error("Invalid IP {NET_IP}: {ERROR}", "NET_IP", ipaddress, "ERROR",
269 e);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500270 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
271 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
272 }
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700273 std::optional<stdplus::SubnetAny> ifaddr;
William A. Kennington III59e5b912022-11-02 02:49:46 -0700274 try
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500275 {
William A. Kennington III30f3ba22023-06-28 15:50:12 -0700276 if (prefixLength == 0)
277 {
278 throw std::invalid_argument("default route");
279 }
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700280 ifaddr.emplace(*addr, prefixLength);
William A. Kennington III59e5b912022-11-02 02:49:46 -0700281 }
282 catch (const std::exception& e)
283 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700284 lg2::error("Invalid prefix length {NET_PFX}: {ERROR}", "NET_PFX",
285 prefixLength, "ERROR", e);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500286 elog<InvalidArgument>(
287 Argument::ARGUMENT_NAME("prefixLength"),
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700288 Argument::ARGUMENT_VALUE(stdplus::toStr(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530289 }
290
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700291 auto it = addrs.find(*ifaddr);
William A. Kennington IIIa429c9d2022-11-15 18:00:45 -0800292 if (it == addrs.end())
293 {
294 it = std::get<0>(addrs.emplace(
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700295 *ifaddr,
William A. Kennington IIIa429c9d2022-11-15 18:00:45 -0800296 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700297 *ifaddr, IP::AddressOrigin::Static)));
William A. Kennington IIIa429c9d2022-11-15 18:00:45 -0800298 }
299 else
300 {
William A. Kennington IIIadd08712022-11-17 16:31:19 -0800301 if (it->second->origin() == IP::AddressOrigin::Static)
302 {
303 return it->second->getObjPath();
304 }
William A. Kennington IIIa429c9d2022-11-15 18:00:45 -0800305 it->second->IPIfaces::origin(IP::AddressOrigin::Static);
306 }
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530307
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700308 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800309 manager.get().reloadConfigs();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700310
William A. Kennington III434a9432022-11-04 18:38:46 -0700311 return it->second->getObjPath();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530312}
313
Patrick Williams6aef7692021-05-01 06:39:41 -0500314ObjectPath EthernetInterface::neighbor(std::string ipAddress,
315 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800316{
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700317 std::optional<stdplus::InAnyAddr> addr;
William A. Kennington III434a9432022-11-04 18:38:46 -0700318 try
William A. Kennington III08505792019-01-30 16:00:04 -0800319 {
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700320 addr.emplace(stdplus::fromStr<stdplus::InAnyAddr>(ipAddress));
William A. Kennington III434a9432022-11-04 18:38:46 -0700321 }
322 catch (const std::exception& e)
323 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700324 lg2::error("Not a valid IP address {NET_IP}: {ERROR}", "NET_IP",
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -0700325 ipAddress, "ERROR", e);
Patrick Williams6aef7692021-05-01 06:39:41 -0500326 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
327 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800328 }
William A. Kennington III434a9432022-11-04 18:38:46 -0700329
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700330 std::optional<stdplus::EtherAddr> lladdr;
William A. Kennington III434a9432022-11-04 18:38:46 -0700331 try
William A. Kennington III08505792019-01-30 16:00:04 -0800332 {
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700333 lladdr.emplace(stdplus::fromStr<stdplus::EtherAddr>(macAddress));
William A. Kennington III434a9432022-11-04 18:38:46 -0700334 }
335 catch (const std::exception& e)
336 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700337 lg2::error("Not a valid MAC address {NET_MAC}: {ERROR}", "NET_MAC",
338 macAddress, "ERROR", e);
Patrick Williams6aef7692021-05-01 06:39:41 -0500339 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
340 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800341 }
342
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700343 auto it = staticNeighbors.find(*addr);
William A. Kennington IIIa429c9d2022-11-15 18:00:45 -0800344 if (it == staticNeighbors.end())
345 {
346 it = std::get<0>(staticNeighbors.emplace(
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700347 *addr, std::make_unique<Neighbor>(bus, std::string_view(objPath),
348 *this, *addr, *lladdr,
349 Neighbor::State::Permanent)));
William A. Kennington IIIa429c9d2022-11-15 18:00:45 -0800350 }
351 else
352 {
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700353 auto str = stdplus::toStr(*lladdr);
William A. Kennington IIIadd08712022-11-17 16:31:19 -0800354 if (it->second->macAddress() == str)
355 {
356 return it->second->getObjPath();
357 }
358 it->second->NeighborObj::macAddress(str);
William A. Kennington IIIa429c9d2022-11-15 18:00:45 -0800359 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700360
361 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800362 manager.get().reloadConfigs();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700363
William A. Kennington III434a9432022-11-04 18:38:46 -0700364 return it->second->getObjPath();
William A. Kennington III08505792019-01-30 16:00:04 -0800365}
366
Patrick Williams6aef7692021-05-01 06:39:41 -0500367bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700368{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700369 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700370 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700371 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800372 manager.get().reloadConfigs();
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700373 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700374 return value;
375}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700376
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700377bool EthernetInterface::dhcp4(bool value)
378{
379 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value))
380 {
381 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800382 manager.get().reloadConfigs();
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700383 }
384 return value;
385}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700386
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700387bool EthernetInterface::dhcp6(bool value)
388{
389 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value))
390 {
391 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800392 manager.get().reloadConfigs();
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700393 }
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700394 return value;
395}
396
Patrick Williams6aef7692021-05-01 06:39:41 -0500397EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530398{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700399 auto old4 = EthernetInterfaceIntf::dhcp4();
400 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 ||
401 value == DHCPConf::v4v6stateless ||
402 value == DHCPConf::both);
403 auto old6 = EthernetInterfaceIntf::dhcp6();
404 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 ||
405 value == DHCPConf::both);
406 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA();
407 auto newra = EthernetInterfaceIntf::ipv6AcceptRA(
408 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless ||
409 value == DHCPConf::v6 || value == DHCPConf::both);
410
411 if (old4 != new4 || old6 != new6 || oldra != newra)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530412 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700413 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800414 manager.get().reloadConfigs();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530415 }
Ratan Gupta87c13982017-06-15 09:27:27 +0530416 return value;
417}
418
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700419EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const
420{
421 if (dhcp6())
422 {
423 return dhcp4() ? DHCPConf::both : DHCPConf::v6;
424 }
425 else if (dhcp4())
426 {
427 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4;
428 }
429 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none;
430}
431
Tejas Patil2c0fc562021-08-03 19:13:46 +0530432size_t EthernetInterface::mtu(size_t value)
433{
William A. Kennington III2e09d272022-10-14 17:15:00 -0700434 const size_t old = EthernetInterfaceIntf::mtu();
435 if (value == old)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530436 {
437 return value;
438 }
William A. Kennington III2e09d272022-10-14 17:15:00 -0700439 const auto ifname = interfaceName();
William A. Kennington III3e471c52022-10-27 19:46:07 -0700440 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] {
William A. Kennington III2e09d272022-10-14 17:15:00 -0700441 system::setMTU(ifname, value);
442 return value;
443 }));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530444}
445
Patrick Williams6aef7692021-05-01 06:39:41 -0500446bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700447{
Patrick Williams6aef7692021-05-01 06:39:41 -0500448 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700449 {
450 return value;
451 }
452
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800453 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700454 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800455 if (!value)
456 {
457 // We only need to bring down the interface, networkd will always bring
458 // up managed interfaces
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800459 manager.get().addReloadPreHook(
William A. Kennington III2e09d272022-10-14 17:15:00 -0700460 [ifname = interfaceName()]() { system::setNICUp(ifname, false); });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800461 }
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800462 manager.get().reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800463
464 return value;
465}
466
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530467ServerList EthernetInterface::staticNameServers(ServerList value)
468{
nitinkotania581cb0b2023-03-21 00:28:55 -0500469 std::vector<std::string> dnsUniqueValues;
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700470 for (auto& ip : value)
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530471 {
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700472 try
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530473 {
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700474 ip = stdplus::toStr(stdplus::fromStr<stdplus::InAnyAddr>(ip));
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700475 }
476 catch (const std::exception& e)
477 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700478 lg2::error("Not a valid IP address {NET_IP}: {ERROR}", "NET_IP", ip,
479 "ERROR", e);
William A. Kennington IIIc9f672e2022-11-04 14:35:53 -0700480 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"),
481 Argument::ARGUMENT_VALUE(ip.c_str()));
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530482 }
nitinkotania581cb0b2023-03-21 00:28:55 -0500483 if (std::find(dnsUniqueValues.begin(), dnsUniqueValues.end(), ip) ==
484 dnsUniqueValues.end())
485 {
486 dnsUniqueValues.push_back(ip);
487 }
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530488 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700489
nitinkotania581cb0b2023-03-21 00:28:55 -0500490 value =
491 EthernetInterfaceIntf::staticNameServers(std::move(dnsUniqueValues));
William A. Kennington IIIa7485302023-05-30 16:57:57 -0700492
493 writeConfigurationFile();
494 manager.get().reloadConfigs();
495
496 return value;
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530497}
498
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600499void EthernetInterface::loadNTPServers(const config::Parser& config)
500{
501 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
502 EthernetInterfaceIntf::staticNTPServers(
503 config.map.getValueStrings("Network", "NTP"));
504}
505
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700506void EthernetInterface::loadNameServers(const config::Parser& config)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530507{
508 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700509 EthernetInterfaceIntf::staticNameServers(
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700510 config.map.getValueStrings("Network", "DNS"));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530511}
512
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600513ServerList EthernetInterface::getNTPServerFromTimeSyncd()
514{
515 ServerList servers; // Variable to capture the NTP Server IPs
Patrick Williams89d734b2023-05-10 07:50:25 -0500516 auto method = bus.get().new_method_call(TIMESYNCD_SERVICE,
517 TIMESYNCD_SERVICE_PATH,
518 PROPERTY_INTERFACE, METHOD_GET);
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600519
520 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
521
522 try
523 {
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800524 auto reply = bus.get().call(method);
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600525 std::variant<ServerList> response;
526 reply.read(response);
527 servers = std::get<ServerList>(response);
528 }
529 catch (const sdbusplus::exception::SdBusError& e)
530 {
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -0700531 lg2::error("Failed to get NTP server information from "
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700532 "systemd-timesyncd: {ERROR}",
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -0700533 "ERROR", e);
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600534 }
535
536 return servers;
537}
538
Ravi Teja4f8b9a02023-09-06 13:41:52 -0500539ServerList EthernetInterface::nameservers() const
540{
541 return getNameServerFromResolvd();
542}
543
544ServerList EthernetInterface::getNameServerFromResolvd() const
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530545{
546 ServerList servers;
William A. Kennington IIIcafc1512023-07-25 02:22:32 -0700547 auto OBJ_PATH = std::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530548
549 /*
550 The DNS property under org.freedesktop.resolve1.Link interface contains
551 an array containing all DNS servers currently used by resolved. It
552 contains similar information as the DNS server data written to
553 /run/systemd/resolve/resolv.conf.
554
555 Each structure in the array consists of a numeric network interface index,
556 an address family, and a byte array containing the DNS server address
557 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
558 The array contains DNS servers configured system-wide, including those
559 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
560 /etc/systemd/resolved.conf, as well as per-interface DNS server
561 information either retrieved from systemd-networkd or configured by
562 external software via SetLinkDNS().
563 */
564
565 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
566 std::variant<type> name; // Variable to capture the DNS property
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800567 auto method = bus.get().new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
568 PROPERTY_INTERFACE, METHOD_GET);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530569
570 method.append(RESOLVED_INTERFACE, "DNS");
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530571
572 try
573 {
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800574 auto reply = bus.get().call(method);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530575 reply.read(name);
576 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500577 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530578 {
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -0700579 lg2::error(
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700580 "Failed to get DNS information from systemd-resolved: {ERROR}",
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -0700581 "ERROR", e);
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530582 }
583 auto tupleVector = std::get_if<type>(&name);
584 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
585 {
Alexander Filippov983da552021-02-08 15:26:54 +0300586 int addressFamily = std::get<0>(*i);
587 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700588 servers.push_back(stdplus::toStr(
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700589 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress))));
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530590 }
591 return servers;
592}
593
William A. Kennington IIId298f932022-10-17 14:31:38 -0700594ObjectPath EthernetInterface::createVLAN(uint16_t id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530595{
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700596 auto idStr = stdplus::toStr(id);
William A. Kennington III86642522023-07-24 17:55:55 -0700597 auto intfName = stdplus::strCat(interfaceName(), "."sv, idStr);
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800598 if (manager.get().interfaces.find(intfName) !=
599 manager.get().interfaces.end())
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800600 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700601 lg2::error("VLAN {NET_VLAN} already exists", "NET_VLAN", id);
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700602 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"),
603 Argument::ARGUMENT_VALUE(idStr.c_str()));
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800604 }
605
William A. Kennington IIId298f932022-10-17 14:31:38 -0700606 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/'));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700607 auto macStr = MacAddressIntf::macAddress();
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700608 std::optional<stdplus::EtherAddr> mac;
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700609 if (!macStr.empty())
610 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700611 mac.emplace(stdplus::fromStr<stdplus::EtherAddr>(macStr));
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700612 }
William A. Kennington III13d665c2022-11-15 20:34:40 -0800613 auto info = AllIntfInfo{InterfaceInfo{
William A. Kennington III9c441fd2023-02-24 13:40:01 -0800614 .type = ARPHRD_ETHER,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700615 .idx = 0, // TODO: Query the correct value after creation
616 .flags = 0,
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700617 .name = intfName,
William A. Kennington IIIfd862be2022-10-09 18:40:55 -0700618 .mac = std::move(mac),
619 .mtu = mtu(),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700620 .parent_idx = ifIdx,
621 .vlan_id = id,
William A. Kennington III13d665c2022-11-15 20:34:40 -0800622 }};
Ratan Gupta5978dd12017-07-25 13:47:13 +0530623
Patrick Williams6aef7692021-05-01 06:39:41 -0500624 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530625 // VLAN interface can inherit.
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700626 auto vlanIntf = std::make_unique<EthernetInterface>(
William A. Kennington IIIb6452542022-11-15 18:09:12 -0800627 bus, manager, info, objRoot, config::Parser(), nicEnabled());
William A. Kennington IIId298f932022-10-17 14:31:38 -0700628 ObjectPath ret = vlanIntf->objPath;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530629
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800630 manager.get().interfaces.emplace(intfName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530631
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700632 // write the device file for the vlan interface.
633 config::Parser config;
634 auto& netdev = config.map["NetDev"].emplace_back();
635 netdev["Name"].emplace_back(intfName);
636 netdev["Kind"].emplace_back("vlan");
637 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr));
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800638 config.writeFile(
639 config::pathForIntfDev(manager.get().getConfDir(), intfName));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700640
641 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800642 manager.get().reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700643
William A. Kennington III7b90bc82022-11-17 14:55:12 -0800644 return ret;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530645}
Ratan Gupta2b106532017-07-25 16:05:02 +0530646
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600647ServerList EthernetInterface::staticNTPServers(ServerList value)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530648{
William A. Kennington IIIa7485302023-05-30 16:57:57 -0700649 value = EthernetInterfaceIntf::staticNTPServers(std::move(value));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530650
William A. Kennington IIIa7485302023-05-30 16:57:57 -0700651 writeConfigurationFile();
652 manager.get().reloadConfigs();
653
654 return value;
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600655}
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700656
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600657ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
658{
659 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530660}
Ratan Gupta2b106532017-07-25 16:05:02 +0530661
William A. Kennington IIIf179e702024-04-17 00:50:28 -0700662static constexpr std::string_view tfStr(bool value)
663{
664 return value ? "true"sv : "false"sv;
665}
666
William A. Kennington III945878a2024-04-17 01:05:27 -0700667static void writeUpdatedTime(const Manager& manager,
668 const std::filesystem::path& netFile)
669{
670 // JFFS2 doesn't have the time granularity to deal with sub-second
671 // updates. Since we can have multiple file updates within a second
672 // around a reload, we need a location which gives that precision for
673 // future networkd detected reloads. TMPFS gives us this property.
674 if (manager.getConfDir() == "/etc/systemd/network"sv)
675 {
676 auto dir = stdplus::strCat(netFile.native(), ".d");
677 dir.replace(1, 3, "run"); // Replace /etc with /run
678 auto file = dir + "/updated.conf";
679 try
680 {
681 std::filesystem::create_directories(dir);
682 using namespace stdplus::fd;
683 futimens(
684 open(file,
685 OpenFlags(OpenAccess::WriteOnly).set(OpenFlag::Create),
686 0644)
687 .get(),
688 nullptr);
689 }
690 catch (const std::exception& e)
691 {
692 lg2::error("Failed to write time updated file {FILE}: {ERROR}",
693 "FILE", file, "ERROR", e.what());
694 }
695 }
696}
697
Ratan Gupta2b106532017-07-25 16:05:02 +0530698void EthernetInterface::writeConfigurationFile()
699{
William A. Kennington III95a49a22022-08-18 17:50:05 -0700700 config::Parser config;
701 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName());
Ratan Gupta2b106532017-07-25 16:05:02 +0530702 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700703 auto& link = config.map["Link"].emplace_back();
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800704#ifdef PERSIST_MAC
William A. Kennington III95a49a22022-08-18 17:50:05 -0700705 auto mac = MacAddressIntf::macAddress();
706 if (!mac.empty())
707 {
708 link["MACAddress"].emplace_back(mac);
709 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -0800710#endif
William A. Kennington III95a49a22022-08-18 17:50:05 -0700711 if (!EthernetInterfaceIntf::nicEnabled())
712 {
713 link["Unmanaged"].emplace_back("yes");
714 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700715 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700716 {
717 auto& network = config.map["Network"].emplace_back();
718 auto& lla = network["LinkLocalAddressing"];
Oskar Senftad21fc22018-07-26 16:32:23 -0400719#ifdef LINK_LOCAL_AUTOCONFIGURATION
William A. Kennington III95a49a22022-08-18 17:50:05 -0700720 lla.emplace_back("yes");
Oskar Senftad21fc22018-07-26 16:32:23 -0400721#else
William A. Kennington III95a49a22022-08-18 17:50:05 -0700722 lla.emplace_back("no");
Oskar Senftad21fc22018-07-26 16:32:23 -0400723#endif
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700724 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false");
725 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4")
726 : (dhcp6() ? "ipv6" : "false"));
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600727 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700728 auto& vlans = network["VLAN"];
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800729 for (const auto& [_, intf] : manager.get().interfaces)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700730 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700731 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
732 {
733 vlans.emplace_back(intf->interfaceName());
734 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700735 }
736 }
737 {
738 auto& ntps = network["NTP"];
Asmitha Karunanithi003b8b72022-01-06 04:17:59 -0600739 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700740 {
741 ntps.emplace_back(ntp);
742 }
743 }
744 {
745 auto& dnss = network["DNS"];
746 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
747 {
748 dnss.emplace_back(dns);
749 }
750 }
751 {
752 auto& address = network["Address"];
William A. Kennington III59e5b912022-11-02 02:49:46 -0700753 for (const auto& addr : addrs)
William A. Kennington III95a49a22022-08-18 17:50:05 -0700754 {
William A. Kennington III59e5b912022-11-02 02:49:46 -0700755 if (originIsManuallyAssigned(addr.second->origin()))
William A. Kennington III95a49a22022-08-18 17:50:05 -0700756 {
William A. Kennington IIIcafc1512023-07-25 02:22:32 -0700757 address.emplace_back(stdplus::toStr(addr.first));
William A. Kennington III95a49a22022-08-18 17:50:05 -0700758 }
759 }
760 }
761 {
762 auto& gateways = network["Gateway"];
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700763 if (!dhcp4())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700764 {
765 auto gateway = EthernetInterfaceIntf::defaultGateway();
766 if (!gateway.empty())
767 {
768 gateways.emplace_back(gateway);
769 }
770 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530771
William A. Kennington III05cbc5b2023-07-20 19:37:30 -0700772 if (!ipv6AcceptRA())
William A. Kennington III95a49a22022-08-18 17:50:05 -0700773 {
774 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
775 if (!gateway6.empty())
776 {
777 gateways.emplace_back(gateway6);
778 }
779 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600780 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800781 }
William A. Kennington III95a49a22022-08-18 17:50:05 -0700782 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back(
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700783 dhcp6() ? "true" : "false");
Ravi Tejaa5a09442020-07-17 00:57:33 -0500784 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700785 auto& neighbors = config.map["Neighbor"];
786 for (const auto& sneighbor : staticNeighbors)
Lei YUcb2d4082021-08-12 15:26:49 +0800787 {
William A. Kennington III95a49a22022-08-18 17:50:05 -0700788 auto& neighbor = neighbors.emplace_back();
789 neighbor["Address"].emplace_back(sneighbor.second->ipAddress());
790 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress());
Lei YUcb2d4082021-08-12 15:26:49 +0800791 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500792 }
Ravi Tejaa5a09442020-07-17 00:57:33 -0500793 {
Jishnu CM57dfea92023-05-05 06:07:26 -0500794 auto& dhcp4 = config.map["DHCPv4"].emplace_back();
795 dhcp4["ClientIdentifier"].emplace_back("mac");
William A. Kennington IIIf179e702024-04-17 00:50:28 -0700796 dhcp4["UseDNS"].emplace_back(tfStr(dhcp4Conf->dnsEnabled()));
797 dhcp4["UseDomains"].emplace_back(tfStr(dhcp4Conf->domainEnabled()));
798 dhcp4["UseNTP"].emplace_back(tfStr(dhcp4Conf->ntpEnabled()));
799 dhcp4["UseHostname"].emplace_back(tfStr(dhcp4Conf->hostNameEnabled()));
Jishnu CM57dfea92023-05-05 06:07:26 -0500800 dhcp4["SendHostname"].emplace_back(
William A. Kennington IIIf179e702024-04-17 00:50:28 -0700801 tfStr(dhcp4Conf->sendHostNameEnabled()));
Jishnu CM57dfea92023-05-05 06:07:26 -0500802 }
803 {
804 auto& dhcp6 = config.map["DHCPv6"].emplace_back();
William A. Kennington IIIf179e702024-04-17 00:50:28 -0700805 dhcp6["UseDNS"].emplace_back(tfStr(dhcp6Conf->dnsEnabled()));
806 dhcp6["UseDomains"].emplace_back(tfStr(dhcp6Conf->domainEnabled()));
807 dhcp6["UseNTP"].emplace_back(tfStr(dhcp6Conf->ntpEnabled()));
808 dhcp6["UseHostname"].emplace_back(tfStr(dhcp6Conf->hostNameEnabled()));
William A. Kennington III44937b12024-04-17 00:28:20 -0700809 dhcp6["SendHostname"].emplace_back(
810 tfStr(dhcp6Conf->sendHostNameEnabled()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500811 }
Patrick Williams89d734b2023-05-10 07:50:25 -0500812 auto path = config::pathForIntfConf(manager.get().getConfDir(),
813 interfaceName());
William A. Kennington III95a49a22022-08-18 17:50:05 -0700814 config.writeFile(path);
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700815 lg2::info("Wrote networkd file: {CFG_FILE}", "CFG_FILE", path);
William A. Kennington III945878a2024-04-17 01:05:27 -0700816 writeUpdatedTime(manager, path);
Ratan Gupta2b106532017-07-25 16:05:02 +0530817}
818
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800819std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +0530820{
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700821 if (vlan)
822 {
Jagpal Singh Gillf78a4152023-04-17 21:17:56 -0700823 lg2::error("Tried to set MAC address on VLAN");
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700824 elog<InternalFailure>();
825 }
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800826#ifdef PERSIST_MAC
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700827 stdplus::EtherAddr newMAC;
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600828 try
829 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700830 newMAC = stdplus::fromStr<stdplus::EtherAddr>(value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600831 }
Patrick Williams5758db32021-10-06 12:29:22 -0500832 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600833 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700834 lg2::error("MAC Address {NET_MAC} is not valid", "NET_MAC", value);
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600835 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
836 Argument::ARGUMENT_VALUE(value.c_str()));
837 }
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700838 if (!newMAC.isUnicast())
Ratan Guptabd303b12017-08-18 17:10:07 +0530839 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700840 lg2::error("MAC Address {NET_MAC} is not valid", "NET_MAC", value);
Gunnar Mills90480c42018-06-19 16:02:17 -0500841 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
842 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530843 }
844
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300845 auto interface = interfaceName();
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700846 auto validMAC = stdplus::toStr(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300847
William A. Kennington III1137a972019-04-20 20:49:58 -0700848 // We don't need to update the system if the address is unchanged
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700849 auto oldMAC =
850 stdplus::fromStr<stdplus::EtherAddr>(MacAddressIntf::macAddress());
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700851 if (newMAC != oldMAC)
Ratan Guptabd303b12017-08-18 17:10:07 +0530852 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700853 // Update everything that depends on the MAC value
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800854 for (const auto& [_, intf] : manager.get().interfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530855 {
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700856 if (intf->vlan && intf->vlan->parentIdx == ifIdx)
857 {
858 intf->MacAddressIntf::macAddress(validMAC);
859 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530860 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500861 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +0530862
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700863 writeConfigurationFile();
William A. Kennington III945878a2024-04-17 01:05:27 -0700864 manager.get().addReloadPreHook([interface, manager = manager]() {
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800865 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III2e09d272022-10-14 17:15:00 -0700866 system::setNICUp(interface, false);
William A. Kennington III945878a2024-04-17 01:05:27 -0700867 writeUpdatedTime(
868 manager,
869 config::pathForIntfConf(manager.get().getConfDir(), interface));
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -0800870 });
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800871 manager.get().reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +0530872 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700873
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300874#ifdef HAVE_UBOOT_ENV
875 // Ensure that the valid address is stored in the u-boot-env
William A. Kennington III69f45542022-09-24 23:28:14 -0700876 auto envVar = interfaceToUbootEthAddr(interface);
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300877 if (envVar)
878 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -0500879 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
880 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
881 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
882 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +0300883 }
884#endif // HAVE_UBOOT_ENV
885
William A. Kennington III1137a972019-04-20 20:49:58 -0700886 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +0800887#else
888 elog<NotAllowed>(
889 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
890#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +0530891}
892
Ratan Guptae9c9b812017-09-22 17:15:37 +0530893void EthernetInterface::deleteAll()
894{
Ratan Guptae9c9b812017-09-22 17:15:37 +0530895 // clear all the ip on the interface
896 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700897
898 writeConfigurationFile();
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800899 manager.get().reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +0530900}
901
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800902template <typename Addr>
903static void normalizeGateway(std::string& gw)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500904{
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800905 if (gw.empty())
906 {
907 return;
908 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700909 try
Ravi Tejaa5a09442020-07-17 00:57:33 -0500910 {
William A. Kennington III9ca5c8e2022-12-14 14:40:52 -0800911 auto ip = stdplus::fromStr<Addr>(gw);
912 if (ip == Addr{})
913 {
914 gw.clear();
915 return;
916 }
William A. Kennington IIIbbf5e9e2023-02-01 14:58:38 -0800917 if (!validIntfIP(ip))
918 {
919 throw std::invalid_argument("Invalid unicast");
920 }
William A. Kennington III9ca5c8e2022-12-14 14:40:52 -0800921 gw = stdplus::toStr(ip);
Ravi Tejaa5a09442020-07-17 00:57:33 -0500922 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700923 catch (const std::exception& e)
Ravi Tejaa5a09442020-07-17 00:57:33 -0500924 {
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800925 lg2::error("Invalid GW `{NET_GW}`: {ERROR}", "NET_GW", gw, "ERROR", e);
Ravi Tejaa5a09442020-07-17 00:57:33 -0500926 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800927 Argument::ARGUMENT_VALUE(gw.c_str()));
Ravi Tejaa5a09442020-07-17 00:57:33 -0500928 }
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800929}
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700930
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800931std::string EthernetInterface::defaultGateway(std::string gateway)
932{
933 normalizeGateway<stdplus::In4Addr>(gateway);
934 if (gateway != defaultGateway())
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700935 {
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800936 gateway = EthernetInterfaceIntf::defaultGateway(std::move(gateway));
Yuxiao Zhangaf38fe92023-10-12 13:50:50 -0700937 writeConfigurationFile();
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800938 manager.get().reloadConfigs();
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700939 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700940 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500941}
942
943std::string EthernetInterface::defaultGateway6(std::string gateway)
944{
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800945 normalizeGateway<stdplus::In6Addr>(gateway);
946 if (gateway != defaultGateway6())
Ravi Tejaa5a09442020-07-17 00:57:33 -0500947 {
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800948 gateway = EthernetInterfaceIntf::defaultGateway6(std::move(gateway));
Yuxiao Zhangaf38fe92023-10-12 13:50:50 -0700949 writeConfigurationFile();
William A. Kennington IIId4ff7312023-02-03 14:19:17 -0800950 manager.get().reloadConfigs();
Ravi Tejaa5a09442020-07-17 00:57:33 -0500951 }
William A. Kennington IIIf6f0cf32022-11-04 14:28:42 -0700952 return gateway;
Ravi Tejaa5a09442020-07-17 00:57:33 -0500953}
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700954
955EthernetInterface::VlanProperties::VlanProperties(
956 sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800957 const InterfaceInfo& info, stdplus::PinnedRef<EthernetInterface> eth) :
William A. Kennington IIIb6452542022-11-15 18:09:12 -0800958 VlanIfaces(bus, objPath.c_str(), VlanIfaces::action::defer_emit),
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700959 parentIdx(*info.parent_idx), eth(eth)
960{
William A. Kennington IIId99e6db2022-11-15 20:39:45 -0800961 VlanIntf::id(*info.vlan_id, true);
962 emit_object_added();
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700963}
964
965void EthernetInterface::VlanProperties::delete_()
966{
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800967 auto intf = eth.get().interfaceName();
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700968
969 // Remove all configs for the current interface
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800970 const auto& confDir = eth.get().manager.get().getConfDir();
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700971 std::error_code ec;
972 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec);
973 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec);
974
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800975 if (eth.get().ifIdx > 0)
William A. Kennington III93f5c6d2022-11-17 16:23:44 -0800976 {
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800977 eth.get().manager.get().interfacesByIdx.erase(eth.get().ifIdx);
William A. Kennington III93f5c6d2022-11-17 16:23:44 -0800978 }
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800979 auto it = eth.get().manager.get().interfaces.find(intf);
William A. Kennington III93f5c6d2022-11-17 16:23:44 -0800980 auto obj = std::move(it->second);
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800981 eth.get().manager.get().interfaces.erase(it);
William A. Kennington III93f5c6d2022-11-17 16:23:44 -0800982
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700983 // Write an updated parent interface since it has a VLAN entry
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800984 for (const auto& [_, intf] : eth.get().manager.get().interfaces)
William A. Kennington III09f3a4a2022-10-25 02:59:16 -0700985 {
986 if (intf->ifIdx == parentIdx)
987 {
988 intf->writeConfigurationFile();
989 }
990 }
991
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800992 if (eth.get().ifIdx > 0)
William A. Kennington III67b09da2022-10-31 14:09:53 -0700993 {
William A. Kennington III6d217512022-11-17 16:18:01 -0800994 // We need to forcibly delete the interface as systemd does not
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800995 eth.get().manager.get().addReloadPostHook(
996 [idx = eth.get().ifIdx]() { system::deleteIntf(idx); });
William A. Kennington III6d217512022-11-17 16:18:01 -0800997
William A. Kennington III93f5c6d2022-11-17 16:23:44 -0800998 // Ignore the interface so the reload doesn't re-query it
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800999 eth.get().manager.get().ignoredIntf.emplace(eth.get().ifIdx);
William A. Kennington III67b09da2022-10-31 14:09:53 -07001000 }
William A. Kennington III93f5c6d2022-11-17 16:23:44 -08001001
William A. Kennington III9ede1b72022-11-21 01:59:28 -08001002 eth.get().manager.get().reloadConfigs();
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07001003}
1004
Jishnu CM57dfea92023-05-05 06:07:26 -05001005void EthernetInterface::reloadConfigs()
1006{
1007 manager.get().reloadConfigs();
1008}
1009
Gunnar Mills57d9c502018-09-14 14:42:34 -05001010} // namespace network
1011} // namespace phosphor