blob: 7f4f93063c2328bb28ded5f5c1ea7196badea2cc [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"
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -07006#include "ipaddress.hpp"
William A. Kennington III08505792019-01-30 16:00:04 -08007#include "neighbor.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05308#include "network_manager.hpp"
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -07009#include "types.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +053010#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +053011
Ratan Gupta82549cc2017-04-21 08:45:23 +053012#include <arpa/inet.h>
William A. Kennington III26275a32021-07-13 20:32:42 -070013#include <fmt/format.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070015#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053016#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053017#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053018
Ratan Gupta82549cc2017-04-21 08:45:23 +053019#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053020#include <filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053021#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070022#include <phosphor-logging/elog-errors.hpp>
23#include <phosphor-logging/log.hpp>
William A. Kennington III26275a32021-07-13 20:32:42 -070024#include <sdbusplus/bus/match.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053025#include <sstream>
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080026#include <stdplus/fd/create.hpp>
William A. Kennington III12beaad2020-06-13 19:30:41 -070027#include <stdplus/raw.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053028#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070029#include <string_view>
William A. Kennington III26275a32021-07-13 20:32:42 -070030#include <unordered_map>
31#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070032#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053033
Ratan Gupta91a99cc2017-04-14 16:32:09 +053034namespace phosphor
35{
36namespace network
37{
38
39using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053040using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053041using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
42using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050043using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053044constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
45constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
46constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
47constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
48constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053049
Johnathan Mantey817012a2020-01-30 15:07:39 -080050std::map<EthernetInterface::DHCPConf, std::string> mapDHCPToSystemd = {
51 {EthernetInterface::DHCPConf::both, "true"},
52 {EthernetInterface::DHCPConf::v4, "ipv4"},
53 {EthernetInterface::DHCPConf::v6, "ipv6"},
54 {EthernetInterface::DHCPConf::none, "false"}};
55
William A. Kennington III5dad2aa2022-01-21 16:00:17 -080056static stdplus::Fd& getIFSock()
57{
58 using namespace stdplus::fd;
59 static auto fd =
60 socket(SocketDomain::INet, SocketType::Datagram, SocketProto::IP);
61 return fd;
62}
63
Patrick Williamsc38b0712022-07-22 19:26:54 -050064EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus,
Ratan Gupta91a99cc2017-04-14 16:32:09 +053065 const std::string& objPath,
Johnathan Mantey817012a2020-01-30 15:07:39 -080066 DHCPConf dhcpEnabled, Manager& parent,
William A. Kennington III26275a32021-07-13 20:32:42 -070067 bool emitSignal,
68 std::optional<bool> enabled) :
Patrick Williams166b9592022-03-30 16:09:16 -050069 Ifaces(bus, objPath.c_str(),
70 emitSignal ? Ifaces::action::defer_emit
71 : Ifaces::action::emit_no_signals),
Gunnar Mills57d9c502018-09-14 14:42:34 -050072 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053073{
74 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053075 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053076 interfaceName(intfName);
Patrick Williams6aef7692021-05-01 06:39:41 -050077 EthernetInterfaceIntf::dhcpEnabled(dhcpEnabled);
78 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRAFromConf());
William A. Kennington III26275a32021-07-13 20:32:42 -070079 EthernetInterfaceIntf::nicEnabled(enabled ? *enabled : queryNicEnabled());
William A. Kennington IIIe0564842021-10-23 16:02:22 -070080 const auto& gatewayList = manager.getRouteTable().getDefaultGateway();
81 const auto& gateway6List = manager.getRouteTable().getDefaultGateway6();
Ravi Tejaa5a09442020-07-17 00:57:33 -050082 std::string defaultGateway;
83 std::string defaultGateway6;
84
William A. Kennington IIIe0564842021-10-23 16:02:22 -070085 for (const auto& gateway : gatewayList)
Ravi Tejaa5a09442020-07-17 00:57:33 -050086 {
87 if (gateway.first == intfName)
88 {
89 defaultGateway = gateway.second;
90 break;
91 }
92 }
93
William A. Kennington IIIe0564842021-10-23 16:02:22 -070094 for (const auto& gateway6 : gateway6List)
Ravi Tejaa5a09442020-07-17 00:57:33 -050095 {
96 if (gateway6.first == intfName)
97 {
98 defaultGateway6 = gateway6.second;
99 break;
100 }
101 }
102
103 EthernetInterfaceIntf::defaultGateway(defaultGateway);
104 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
Ratan Gupta99801ce2020-01-09 18:37:16 +0530105 // Don't get the mac address from the system as the mac address
106 // would be same as parent interface.
107 if (intfName.find(".") == std::string::npos)
108 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500109 MacAddressIntf::macAddress(getMACAddress(intfName));
Ratan Gupta99801ce2020-01-09 18:37:16 +0530110 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500111 EthernetInterfaceIntf::ntpServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +0530112
113 EthernetInterfaceIntf::linkUp(linkUp());
Tejas Patil2c0fc562021-08-03 19:13:46 +0530114 EthernetInterfaceIntf::mtu(mtu());
Ratan Gupta613a0122020-04-24 15:18:53 +0530115
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700116#ifdef NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -0700117 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
118
119 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
120 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800121#endif
Ratan Gupta6dec3902017-08-20 15:28:12 +0530122
Ratan Gupta29b0e432017-05-25 12:51:40 +0530123 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530124 if (emitSignal)
125 {
126 this->emit_object_added();
127 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530128}
129
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700130static IP::Protocol getProtocol(const InAddrAny& addr)
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800131{
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700132 if (std::holds_alternative<in_addr>(addr))
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800133 {
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700134 return IP::Protocol::IPv4;
135 }
136 else if (std::holds_alternative<in6_addr>(addr))
137 {
138 return IP::Protocol::IPv6;
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800139 }
140
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700141 throw std::runtime_error("Invalid addr type");
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800142}
143
Johnathan Mantey817012a2020-01-30 15:07:39 -0800144void EthernetInterface::disableDHCP(IP::Protocol protocol)
145{
Patrick Williams6aef7692021-05-01 06:39:41 -0500146 DHCPConf dhcpState = EthernetInterfaceIntf::dhcpEnabled();
Johnathan Mantey817012a2020-01-30 15:07:39 -0800147 if (dhcpState == EthernetInterface::DHCPConf::both)
148 {
149 if (protocol == IP::Protocol::IPv4)
150 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500151 dhcpEnabled(EthernetInterface::DHCPConf::v6);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800152 }
153 else if (protocol == IP::Protocol::IPv6)
154 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500155 dhcpEnabled(EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800156 }
157 }
158 else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
159 (protocol == IP::Protocol::IPv4))
160 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500161 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800162 }
163 else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
164 (protocol == IP::Protocol::IPv6))
165 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500166 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800167 }
168}
169
William A. Kennington III24957b92021-12-03 13:59:19 -0800170bool EthernetInterface::dhcpIsEnabled(IP::Protocol family)
Johnathan Mantey817012a2020-01-30 15:07:39 -0800171{
William A. Kennington III24957b92021-12-03 13:59:19 -0800172 const auto cur = EthernetInterfaceIntf::dhcpEnabled();
173 return cur == EthernetInterface::DHCPConf::both ||
174 (family == IP::Protocol::IPv6 &&
175 cur == EthernetInterface::DHCPConf::v6) ||
176 (family == IP::Protocol::IPv4 &&
177 cur == EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800178}
179
Johnathan Mantey817012a2020-01-30 15:07:39 -0800180bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
181{
182 return (
183#ifdef LINK_LOCAL_AUTOCONFIGURATION
184 (origin == IP::AddressOrigin::Static)
185#else
186 (origin == IP::AddressOrigin::Static ||
187 origin == IP::AddressOrigin::LinkLocal)
188#endif
189
190 );
191}
192
Ratan Gupta87c13982017-06-15 09:27:27 +0530193void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530194{
Ratan Gupta87c13982017-06-15 09:27:27 +0530195 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530196
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700197 AddressFilter filter;
198 filter.interface = ifIndex();
199 auto currentAddrs = getCurrentAddresses(filter);
200 for (const auto& addr : currentAddrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530201 {
William A. Kennington III13d17082021-11-04 21:36:54 -0700202 if (addr.flags & IFA_F_DEPRECATED)
203 {
204 continue;
205 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700206 auto address = toString(addr.address);
207 IP::Protocol addressType = getProtocol(addr.address);
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800208 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800209 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530210 {
211 origin = IP::AddressOrigin::DHCP;
212 }
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700213 if (addr.scope == RT_SCOPE_LINK)
Ratan Guptafc2c7242017-05-29 08:46:06 +0530214 {
215 origin = IP::AddressOrigin::LinkLocal;
216 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700217 // Obsolete parameter
218 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530219
Gunnar Mills57d9c502018-09-14 14:42:34 -0500220 std::string ipAddressObjectPath = generateObjectPath(
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700221 addressType, address, addr.prefix, gateway, origin);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530222
Lei YU7233c582021-04-08 14:39:43 +0800223 this->addrs.insert_or_assign(
William A. Kennington IIIc2e5e0e2019-04-22 01:26:06 -0700224 address, std::make_shared<phosphor::network::IPAddress>(
225 bus, ipAddressObjectPath.c_str(), *this, addressType,
226 address, origin, addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530227 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530228}
229
William A. Kennington III08505792019-01-30 16:00:04 -0800230void EthernetInterface::createStaticNeighborObjects()
231{
232 staticNeighbors.clear();
233
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700234 NeighborFilter filter;
235 filter.interface = ifIndex();
236 filter.state = NUD_PERMANENT;
237 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800238 for (const auto& neighbor : neighbors)
239 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700240 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800241 {
242 continue;
243 }
244 std::string ip = toString(neighbor.address);
245 std::string mac = mac_address::toString(*neighbor.mac);
246 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
247 staticNeighbors.emplace(ip,
248 std::make_shared<phosphor::network::Neighbor>(
249 bus, objectPath.c_str(), *this, ip, mac,
250 Neighbor::State::Permanent));
251 }
252}
253
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700254unsigned EthernetInterface::ifIndex() const
255{
256 unsigned idx = if_nametoindex(interfaceName().c_str());
257 if (idx == 0)
258 {
259 throw std::system_error(errno, std::generic_category(),
260 "if_nametoindex");
261 }
262 return idx;
263}
264
Patrick Williams6aef7692021-05-01 06:39:41 -0500265ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
raviteja-bce379562019-03-28 05:59:36 -0500266 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530267{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800268 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530269 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530270 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500271 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800272 disableDHCP(protType);
Ravi Teja07450442022-07-07 04:30:57 -0500273 // Delete the IP address object and that reloads the networkd
274 // to allow the same IP address to be set as Static IP
275 deleteObject(ipaddress);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500276 }
277
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500278 IP::AddressOrigin origin = IP::AddressOrigin::Static;
279
280 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
281
282 if (!isValidIP(addressFamily, ipaddress))
283 {
284 log<level::ERR>("Not a valid IP address"),
285 entry("ADDRESS=%s", ipaddress.c_str());
286 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
287 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
288 }
289
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700290 // Gateway is an obsolete parameter
291 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500292
293 if (!isValidPrefix(addressFamily, prefixLength))
294 {
295 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700296 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500297 elog<InvalidArgument>(
298 Argument::ARGUMENT_NAME("prefixLength"),
299 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530300 }
301
Gunnar Mills57d9c502018-09-14 14:42:34 -0500302 std::string objectPath =
Lei YU34027572021-08-11 15:23:52 +0800303 generateObjectPath(protType, ipaddress, prefixLength, gateway, origin);
Lei YU7233c582021-04-08 14:39:43 +0800304 this->addrs.insert_or_assign(ipaddress,
305 std::make_shared<phosphor::network::IPAddress>(
306 bus, objectPath.c_str(), *this, protType,
307 ipaddress, origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530308
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700309 writeConfigurationFile();
310 manager.reloadConfigs();
311
raviteja-bce379562019-03-28 05:59:36 -0500312 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530313}
314
Patrick Williams6aef7692021-05-01 06:39:41 -0500315ObjectPath EthernetInterface::neighbor(std::string ipAddress,
316 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800317{
Patrick Williams6aef7692021-05-01 06:39:41 -0500318 if (!isValidIP(AF_INET, ipAddress) && !isValidIP(AF_INET6, ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800319 {
320 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500321 entry("ADDRESS=%s", ipAddress.c_str()));
322 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
323 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800324 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500325 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800326 {
327 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500328 entry("MACADDRESS=%s", ipAddress.c_str()));
329 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
330 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800331 }
332
333 std::string objectPath =
Patrick Williams6aef7692021-05-01 06:39:41 -0500334 generateStaticNeighborObjectPath(ipAddress, macAddress);
335 staticNeighbors.emplace(ipAddress,
William A. Kennington III08505792019-01-30 16:00:04 -0800336 std::make_shared<phosphor::network::Neighbor>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500337 bus, objectPath.c_str(), *this, ipAddress,
338 macAddress, Neighbor::State::Permanent));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700339
340 writeConfigurationFile();
341 manager.reloadConfigs();
342
William A. Kennington III08505792019-01-30 16:00:04 -0800343 return objectPath;
344}
345
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700346#ifdef NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530347/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800348 Enable this code if your NIC driver supports the ETHTOOL features.
349 Do this by adding the following to your phosphor-network*.bbappend file.
350 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
351 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530352*/
353InterfaceInfo EthernetInterface::getInterfaceInfo() const
354{
William A. Kennington III05368f12021-05-13 18:40:47 -0700355 ifreq ifr = {};
356 ethtool_cmd edata = {};
357 LinkSpeed speed = {};
358 Autoneg autoneg = {};
359 DuplexMode duplex = {};
360 LinkUp linkState = {};
361 NICEnabled enabled = {};
Tejas Patil2c0fc562021-08-03 19:13:46 +0530362 MTU mtuSize = {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530363
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800364 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
365 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530366
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800367 edata.cmd = ETHTOOL_GSET;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800368 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800369 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800370 getIFSock().ioctl(SIOCETHTOOL, &ifr);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530371 speed = edata.speed;
372 duplex = edata.duplex;
373 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530374 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800375 catch (const std::exception& e)
376 {
377 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800378
William A. Kennington III96203312021-05-07 12:50:41 -0700379 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800380 linkState = linkUp();
Tejas Patil2c0fc562021-08-03 19:13:46 +0530381 mtuSize = mtu();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800382
Tejas Patil2c0fc562021-08-03 19:13:46 +0530383 return std::make_tuple(speed, duplex, autoneg, linkState, enabled, mtuSize);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530384}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800385#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530386
387/** @brief get the mac address of the interface.
388 * @return macaddress on success
389 */
390
Gunnar Mills57d9c502018-09-14 14:42:34 -0500391std::string
392 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530393{
Patrick Williams6aef7692021-05-01 06:39:41 -0500394 std::string activeMACAddr = MacAddressIntf::macAddress();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530395
William A. Kennington III05368f12021-05-13 18:40:47 -0700396 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800397 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800398 try
399 {
400 getIFSock().ioctl(SIOCGIFHWADDR, &ifr);
401 }
402 catch (const std::exception& e)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530403 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530404 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800405 entry("ERROR=%s", e.what()));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700406 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530407 }
408
William A. Kennington III1137a972019-04-20 20:49:58 -0700409 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
410 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
411 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700412 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530413}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530414
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530415std::string EthernetInterface::generateId(const std::string& ipaddress,
416 uint8_t prefixLength,
Lei YU34027572021-08-11 15:23:52 +0800417 const std::string& gateway,
418 const std::string& origin)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530419{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530420 std::stringstream hexId;
421 std::string hashString = ipaddress;
422 hashString += std::to_string(prefixLength);
423 hashString += gateway;
Lei YU34027572021-08-11 15:23:52 +0800424 hashString += origin;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530425
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530426 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530428 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530429}
430
Patrick Williams6aef7692021-05-01 06:39:41 -0500431std::string EthernetInterface::generateNeighborId(const std::string& ipAddress,
432 const std::string& macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800433{
434 std::stringstream hexId;
Patrick Williams6aef7692021-05-01 06:39:41 -0500435 std::string hashString = ipAddress + macAddress;
William A. Kennington III08505792019-01-30 16:00:04 -0800436
437 // Only want 8 hex digits.
438 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
439 return hexId.str();
440}
441
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530442void EthernetInterface::deleteObject(const std::string& ipaddress)
443{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530444 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530445 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530446 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530447 log<level::ERR>("DeleteObject:Unable to find the object.");
448 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530449 }
450 this->addrs.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700451
452 writeConfigurationFile();
453 manager.reloadConfigs();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530454}
455
Patrick Williams6aef7692021-05-01 06:39:41 -0500456void EthernetInterface::deleteStaticNeighborObject(const std::string& ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800457{
Patrick Williams6aef7692021-05-01 06:39:41 -0500458 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800459 if (it == staticNeighbors.end())
460 {
461 log<level::ERR>(
462 "DeleteStaticNeighborObject:Unable to find the object.");
463 return;
464 }
465 staticNeighbors.erase(it);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700466
467 writeConfigurationFile();
468 manager.reloadConfigs();
William A. Kennington III08505792019-01-30 16:00:04 -0800469}
470
Ratan Guptae9c9b812017-09-22 17:15:37 +0530471void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530472{
Ratan Guptabc886292017-07-25 18:29:57 +0530473 auto confDir = manager.getConfDir();
474 fs::path networkFile = confDir;
475 networkFile /= systemd::config::networkFilePrefix + interface +
476 systemd::config::networkFileSuffix;
477
478 fs::path deviceFile = confDir;
479 deviceFile /= interface + systemd::config::deviceFileSuffix;
480
481 // delete the vlan network file
482 if (fs::is_regular_file(networkFile))
483 {
484 fs::remove(networkFile);
485 }
486
487 // delete the vlan device file
488 if (fs::is_regular_file(deviceFile))
489 {
490 fs::remove(deviceFile);
491 }
Ratan Guptabc886292017-07-25 18:29:57 +0530492
493 // TODO systemd doesn't delete the virtual network interface
494 // even after deleting all the related configuartion.
495 // https://github.com/systemd/systemd/issues/6600
496 try
497 {
498 deleteInterface(interface);
499 }
Patrick Williams5758db32021-10-06 12:29:22 -0500500 catch (const InternalFailure& e)
Ratan Guptabc886292017-07-25 18:29:57 +0530501 {
502 commit<InternalFailure>();
503 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530504}
505
506void EthernetInterface::deleteVLANObject(const std::string& interface)
507{
508 auto it = vlanInterfaces.find(interface);
509 if (it == vlanInterfaces.end())
510 {
511 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500512 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530513 return;
514 }
515
516 deleteVLANFromSystem(interface);
517 // delete the interface
518 vlanInterfaces.erase(it);
519
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700520 writeConfigurationFile();
521 manager.reloadConfigs();
Ratan Guptabc886292017-07-25 18:29:57 +0530522}
523
Gunnar Mills57d9c502018-09-14 14:42:34 -0500524std::string EthernetInterface::generateObjectPath(
525 IP::Protocol addressType, const std::string& ipaddress,
Lei YU34027572021-08-11 15:23:52 +0800526 uint8_t prefixLength, const std::string& gateway,
527 IP::AddressOrigin origin) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530528{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530529 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530530 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530531 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
532
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530533 std::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530534 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530535 objectPath /= type;
Lei YU34027572021-08-11 15:23:52 +0800536 objectPath /=
537 generateId(ipaddress, prefixLength, gateway, convertForMessage(origin));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530538 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530539}
540
William A. Kennington III08505792019-01-30 16:00:04 -0800541std::string EthernetInterface::generateStaticNeighborObjectPath(
Patrick Williams6aef7692021-05-01 06:39:41 -0500542 const std::string& ipAddress, const std::string& macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800543{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530544 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800545 objectPath /= objPath;
546 objectPath /= "static_neighbor";
Patrick Williams6aef7692021-05-01 06:39:41 -0500547 objectPath /= generateNeighborId(ipAddress, macAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800548 return objectPath.string();
549}
550
Patrick Williams6aef7692021-05-01 06:39:41 -0500551bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700552{
Patrick Williams6aef7692021-05-01 06:39:41 -0500553 if (value == EthernetInterfaceIntf::ipv6AcceptRA())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700554 {
555 return value;
556 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500557 EthernetInterfaceIntf::ipv6AcceptRA(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700558
559 writeConfigurationFile();
560 manager.reloadConfigs();
561
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700562 return value;
563}
564
Patrick Williams6aef7692021-05-01 06:39:41 -0500565EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530566{
Patrick Williams6aef7692021-05-01 06:39:41 -0500567 if (value == EthernetInterfaceIntf::dhcpEnabled())
Ratan Gupta5978dd12017-07-25 13:47:13 +0530568 {
569 return value;
570 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500571 EthernetInterfaceIntf::dhcpEnabled(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700572
573 writeConfigurationFile();
574 manager.reloadConfigs();
575
Ratan Gupta87c13982017-06-15 09:27:27 +0530576 return value;
577}
578
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800579bool EthernetInterface::linkUp() const
580{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800581 bool value = EthernetInterfaceIntf::linkUp();
582
William A. Kennington III05368f12021-05-13 18:40:47 -0700583 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800584 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800585 try
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800586 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800587 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800588 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
589 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800590 catch (const std::exception& e)
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800591 {
592 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800593 entry("ERROR=%s", e.what()));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800594 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700595 return value;
596}
597
Tejas Patil2c0fc562021-08-03 19:13:46 +0530598size_t EthernetInterface::mtu() const
599{
Tejas Patil2c0fc562021-08-03 19:13:46 +0530600 size_t value = EthernetInterfaceIntf::mtu();
601
Tejas Patil2c0fc562021-08-03 19:13:46 +0530602 ifreq ifr = {};
603 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800604 try
Tejas Patil2c0fc562021-08-03 19:13:46 +0530605 {
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800606 getIFSock().ioctl(SIOCGIFMTU, &ifr);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530607 value = ifr.ifr_mtu;
608 }
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800609 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530610 {
611 log<level::ERR>("ioctl failed for SIOCGIFMTU:",
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800612 entry("ERROR=%s", e.what()));
Tejas Patil2c0fc562021-08-03 19:13:46 +0530613 }
614 return value;
615}
616
617size_t EthernetInterface::mtu(size_t value)
618{
619 if (value == EthernetInterfaceIntf::mtu())
620 {
621 return value;
622 }
623 else if (value == 0)
624 {
625 return EthernetInterfaceIntf::mtu();
626 }
627
Tejas Patil2c0fc562021-08-03 19:13:46 +0530628 ifreq ifr = {};
629 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
630 ifr.ifr_mtu = value;
631
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800632 try
633 {
634 getIFSock().ioctl(SIOCSIFMTU, &ifr);
635 }
636 catch (const std::exception& e)
Tejas Patil2c0fc562021-08-03 19:13:46 +0530637 {
638 log<level::ERR>("ioctl failed for SIOCSIFMTU:",
639 entry("ERROR=%s", strerror(errno)));
640 return EthernetInterfaceIntf::mtu();
641 }
Tejas Patil2c0fc562021-08-03 19:13:46 +0530642
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800643 EthernetInterfaceIntf::mtu(value);
Tejas Patil2c0fc562021-08-03 19:13:46 +0530644 return value;
645}
646
William A. Kennington III26275a32021-07-13 20:32:42 -0700647bool EthernetInterface::queryNicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700648{
William A. Kennington III26275a32021-07-13 20:32:42 -0700649 constexpr auto svc = "org.freedesktop.network1";
650 constexpr auto intf = "org.freedesktop.network1.Link";
651 constexpr auto prop = "AdministrativeState";
652 char* rpath;
653 sd_bus_path_encode("/org/freedesktop/network1/link",
654 std::to_string(ifIndex()).c_str(), &rpath);
655 std::string path(rpath);
656 free(rpath);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700657
William A. Kennington III26275a32021-07-13 20:32:42 -0700658 // Store / Parser for the AdministrativeState return value
659 std::optional<bool> ret;
660 auto cb = [&](const std::string& state) {
661 if (state != "initialized")
662 {
663 ret = state != "unmanaged";
664 }
665 };
666
667 // Build a matcher before making the property call to ensure we
668 // can eventually get the value.
Patrick Williamsc38b0712022-07-22 19:26:54 -0500669 sdbusplus::bus::match_t match(
William A. Kennington III26275a32021-07-13 20:32:42 -0700670 bus,
671 fmt::format("type='signal',sender='{}',path='{}',interface='{}',member="
672 "'PropertiesChanged',arg0='{}',",
673 svc, path, PROPERTY_INTERFACE, intf)
674 .c_str(),
Patrick Williamsc38b0712022-07-22 19:26:54 -0500675 [&](sdbusplus::message_t& m) {
William A. Kennington III26275a32021-07-13 20:32:42 -0700676 std::string intf;
677 std::unordered_map<std::string, std::variant<std::string>> values;
678 try
679 {
680 m.read(intf, values);
681 auto it = values.find(prop);
682 // Ignore properties that aren't AdministrativeState
683 if (it != values.end())
684 {
685 cb(std::get<std::string>(it->second));
686 }
687 }
688 catch (const std::exception& e)
689 {
690 log<level::ERR>(
691 fmt::format(
692 "AdministrativeState match parsing failed on {}: {}",
693 interfaceName(), e.what())
694 .c_str(),
695 entry("INTERFACE=%s", interfaceName().c_str()),
696 entry("ERROR=%s", e.what()));
697 }
698 });
699
700 // Actively call for the value in case the interface is already configured
701 auto method =
702 bus.new_method_call(svc, path.c_str(), PROPERTY_INTERFACE, METHOD_GET);
703 method.append(intf, prop);
704 try
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700705 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700706 auto reply = bus.call(method);
707 std::variant<std::string> state;
708 reply.read(state);
709 cb(std::get<std::string>(state));
710 }
711 catch (const std::exception& e)
712 {
713 log<level::ERR>(
714 fmt::format("Failed to get AdministrativeState on {}: {}",
715 interfaceName(), e.what())
716 .c_str(),
717 entry("INTERFACE=%s", interfaceName().c_str()),
718 entry("ERROR=%s", e.what()));
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700719 }
720
William A. Kennington III26275a32021-07-13 20:32:42 -0700721 // The interface is not yet configured by systemd-networkd, wait until it
722 // signals us a valid state.
723 while (!ret)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700724 {
William A. Kennington III26275a32021-07-13 20:32:42 -0700725 bus.wait();
726 bus.process_discard();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700727 }
William A. Kennington III26275a32021-07-13 20:32:42 -0700728
729 return *ret;
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700730}
731
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800732static void setNICAdminState(const char* intf, bool up)
William A. Kennington III4209cee2021-10-23 18:14:21 -0700733{
734 ifreq ifr = {};
735 std::strncpy(ifr.ifr_name, intf, IF_NAMESIZE - 1);
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800736 getIFSock().ioctl(SIOCGIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700737
738 ifr.ifr_flags &= ~IFF_UP;
739 ifr.ifr_flags |= up ? IFF_UP : 0;
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800740 getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
William A. Kennington III4209cee2021-10-23 18:14:21 -0700741}
742
Patrick Williams6aef7692021-05-01 06:39:41 -0500743bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700744{
Patrick Williams6aef7692021-05-01 06:39:41 -0500745 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700746 {
747 return value;
748 }
749
William A. Kennington IIIc922d5e2022-01-21 01:08:31 -0800750 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700751 writeConfigurationFile();
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800752 if (!value)
753 {
754 // We only need to bring down the interface, networkd will always bring
755 // up managed interfaces
William A. Kennington III5dad2aa2022-01-21 16:00:17 -0800756 manager.addReloadPreHook([ifname = interfaceName()]() {
757 setNICAdminState(ifname.c_str(), false);
758 });
William A. Kennington III329b5fb2021-11-09 17:19:30 -0800759 }
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700760 manager.reloadConfigs();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800761
762 return value;
763}
764
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530765ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530766{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530767 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
768 return EthernetInterfaceIntf::nameservers();
769}
770
771ServerList EthernetInterface::staticNameServers(ServerList value)
772{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530773 for (const auto& nameserverip : value)
774 {
775 if (!isValidIP(AF_INET, nameserverip) &&
776 !isValidIP(AF_INET6, nameserverip))
777 {
778 log<level::ERR>("Not a valid IP address"),
779 entry("ADDRESS=%s", nameserverip.c_str());
780 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530781 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530782 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
783 }
784 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530785 try
786 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530787 EthernetInterfaceIntf::staticNameServers(value);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700788
Ratan Gupta6dec3902017-08-20 15:28:12 +0530789 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700790 manager.reloadConfigs();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530791 }
Patrick Williams5758db32021-10-06 12:29:22 -0500792 catch (const InternalFailure& e)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530793 {
794 log<level::ERR>("Exception processing DNS entries");
795 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530796 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530797}
798
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530799void EthernetInterface::loadNameServers()
800{
801 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
802 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
803}
804
805ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec3902017-08-20 15:28:12 +0530806{
807 fs::path confPath = manager.getConfDir();
808
809 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500810 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530811 confPath /= fileName;
812 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530813 config::Parser parser(confPath.string());
814 auto rc = config::ReturnCode::SUCCESS;
815
816 std::tie(rc, servers) = parser.getValues("Network", "DNS");
817 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530818 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530819 log<level::DEBUG>("Unable to get the value for network[DNS]",
820 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530821 }
822 return servers;
823}
824
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530825ServerList EthernetInterface::getNameServerFromResolvd()
826{
827 ServerList servers;
828 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
829
830 /*
831 The DNS property under org.freedesktop.resolve1.Link interface contains
832 an array containing all DNS servers currently used by resolved. It
833 contains similar information as the DNS server data written to
834 /run/systemd/resolve/resolv.conf.
835
836 Each structure in the array consists of a numeric network interface index,
837 an address family, and a byte array containing the DNS server address
838 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
839 The array contains DNS servers configured system-wide, including those
840 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
841 /etc/systemd/resolved.conf, as well as per-interface DNS server
842 information either retrieved from systemd-networkd or configured by
843 external software via SetLinkDNS().
844 */
845
846 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
847 std::variant<type> name; // Variable to capture the DNS property
848 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
849 PROPERTY_INTERFACE, METHOD_GET);
850
851 method.append(RESOLVED_INTERFACE, "DNS");
852 auto reply = bus.call(method);
853
854 try
855 {
856 reply.read(name);
857 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500858 catch (const sdbusplus::exception_t& e)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530859 {
860 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
861 }
862 auto tupleVector = std::get_if<type>(&name);
863 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
864 {
Alexander Filippov983da552021-02-08 15:26:54 +0300865 int addressFamily = std::get<0>(*i);
866 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
867
868 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530869 {
Alexander Filippov983da552021-02-08 15:26:54 +0300870 case AF_INET:
871 if (ipaddress.size() == sizeof(struct in_addr))
872 {
873 servers.push_back(toString(
874 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
875 }
876 else
877 {
878 log<level::ERR>(
879 "Invalid data recived from Systemd-Resolved");
880 }
881 break;
882
883 case AF_INET6:
884 if (ipaddress.size() == sizeof(struct in6_addr))
885 {
886 servers.push_back(toString(
887 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
888 }
889 else
890 {
891 log<level::ERR>(
892 "Invalid data recived from Systemd-Resolved");
893 }
894 break;
895
896 default:
897 log<level::ERR>(
898 "Unsupported address family in DNS from Systemd-Resolved");
899 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530900 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530901 }
902 return servers;
903}
904
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530905void EthernetInterface::loadVLAN(VlanId id)
906{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500907 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530908 std::string path = objPath;
909 path += "_" + std::to_string(id);
910
Johnathan Mantey817012a2020-01-30 15:07:39 -0800911 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500912 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530913 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500914 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nicEnabled(), id,
Johnathan Mantey817012a2020-01-30 15:07:39 -0800915 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530916
Gunnar Mills57d9c502018-09-14 14:42:34 -0500917 // Fetch the ip address from the system
918 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530919 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800920 vlanIntf->createStaticNeighborObjects();
Jiaqing Zhaocc5a6702021-12-31 14:58:55 +0800921 vlanIntf->loadNameServers();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530922
923 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
924 std::move(vlanIntf));
925}
926
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700927ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530928{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500929 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Jiaqing Zhao33b4eaa2022-04-12 23:11:40 +0800930
931 if (this->vlanInterfaces.count(vlanInterfaceName))
932 {
933 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id));
934 elog<InvalidArgument>(
935 Argument::ARGUMENT_NAME("VLANId"),
936 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
937 }
938
Ratan Gupta5978dd12017-07-25 13:47:13 +0530939 std::string path = objPath;
940 path += "_" + std::to_string(id);
941
Patrick Williams6aef7692021-05-01 06:39:41 -0500942 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530943 // VLAN interface can inherit.
Ratan Gupta5978dd12017-07-25 13:47:13 +0530944 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800945 bus, path.c_str(), EthernetInterface::DHCPConf::none,
Patrick Williams6aef7692021-05-01 06:39:41 -0500946 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530947
948 // write the device file for the vlan interface.
949 vlanIntf->writeDeviceFile();
950
Gunnar Mills57d9c502018-09-14 14:42:34 -0500951 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700952
953 writeConfigurationFile();
954 manager.reloadConfigs();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700955
956 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530957}
Ratan Gupta2b106532017-07-25 16:05:02 +0530958
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700959bool EthernetInterface::getIPv6AcceptRAFromConf()
960{
961 fs::path confPath = manager.getConfDir();
962
963 std::string fileName = systemd::config::networkFilePrefix +
964 interfaceName() + systemd::config::networkFileSuffix;
965 confPath /= fileName;
966 config::ValueList values;
967 config::Parser parser(confPath.string());
968 auto rc = config::ReturnCode::SUCCESS;
969 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
970 if (rc != config::ReturnCode::SUCCESS)
971 {
972 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
973 entry("rc=%d", rc));
974 return false;
975 }
976 return (values[0] == "true");
977}
978
Ratan Gupta497c0c92017-08-22 19:15:59 +0530979ServerList EthernetInterface::getNTPServersFromConf()
980{
981 fs::path confPath = manager.getConfDir();
982
Gunnar Mills57d9c502018-09-14 14:42:34 -0500983 std::string fileName = systemd::config::networkFilePrefix +
984 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530985 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530986
Ratan Gupta497c0c92017-08-22 19:15:59 +0530987 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530988 config::Parser parser(confPath.string());
989 auto rc = config::ReturnCode::SUCCESS;
990
991 std::tie(rc, servers) = parser.getValues("Network", "NTP");
992 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530993 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530994 log<level::DEBUG>("Unable to get the value for Network[NTP]",
995 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530996 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530997
Ratan Gupta497c0c92017-08-22 19:15:59 +0530998 return servers;
999}
1000
Patrick Williams6aef7692021-05-01 06:39:41 -05001001ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +05301002{
Patrick Williams6aef7692021-05-01 06:39:41 -05001003 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +05301004
1005 writeConfigurationFile();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001006 manager.reloadConfigs();
1007
Ratan Gupta497c0c92017-08-22 19:15:59 +05301008 return ntpServers;
1009}
Ratan Gupta2b106532017-07-25 16:05:02 +05301010// Need to merge the below function with the code which writes the
1011// config file during factory reset.
1012// TODO openbmc/openbmc#1751
1013
1014void EthernetInterface::writeConfigurationFile()
1015{
1016 // write all the static ip address in the systemd-network conf file
1017
1018 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +05301019 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +05301020
1021 // if there is vlan interafce then write the configuration file
1022 // for vlan also.
1023
Gunnar Mills57d9c502018-09-14 14:42:34 -05001024 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +05301025 {
1026 intf.second->writeConfigurationFile();
1027 }
1028
Ratan Gupta2b106532017-07-25 16:05:02 +05301029 fs::path confPath = manager.getConfDir();
1030
Gunnar Mills57d9c502018-09-14 14:42:34 -05001031 std::string fileName = systemd::config::networkFilePrefix +
1032 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +05301033 confPath /= fileName;
1034 std::fstream stream;
1035
1036 stream.open(confPath.c_str(), std::fstream::out);
1037 if (!stream.is_open())
1038 {
1039 log<level::ERR>("Unable to open the file",
1040 entry("FILE=%s", confPath.c_str()));
1041 elog<InternalFailure>();
1042 }
1043
1044 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001045 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301046 stream << "Name=" << interfaceName() << "\n";
1047
1048 auto addrs = getAddresses();
1049
William A. Kennington III15787212019-04-23 19:18:01 -07001050 // Write the link section
1051 stream << "[Link]\n";
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001052#ifdef PERSIST_MAC
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001053 auto mac = MacAddressIntf::macAddress();
William A. Kennington III15787212019-04-23 19:18:01 -07001054 if (!mac.empty())
1055 {
1056 stream << "MACAddress=" << mac << "\n";
1057 }
Johnathan Mantey609c12d2022-02-03 09:23:09 -08001058#endif
William A. Kennington III15787212019-04-23 19:18:01 -07001059
Patrick Williams6aef7692021-05-01 06:39:41 -05001060 if (!EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -07001061 {
1062 stream << "Unmanaged=yes\n";
1063 }
1064
Ratan Gupta2b106532017-07-25 16:05:02 +05301065 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -04001066 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001067#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -05001068 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -04001069#else
1070 stream << "LinkLocalAddressing=no\n";
1071#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -07001072 stream << std::boolalpha
Patrick Williams6aef7692021-05-01 06:39:41 -05001073 << "IPv6AcceptRA=" << EthernetInterfaceIntf::ipv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301074
1075 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -05001076 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301077 {
1078 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -05001079 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +05301080 }
Ratan Gupta046b2a02019-09-20 15:49:51 +05301081 // Add the NTP server
Patrick Williams6aef7692021-05-01 06:39:41 -05001082 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301083 {
1084 stream << "NTP=" << ntp << "\n";
1085 }
1086
1087 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +05301088 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +05301089 {
1090 stream << "DNS=" << dns << "\n";
1091 }
1092
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001093 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -08001094 stream << "DHCP="s +
Patrick Williams6aef7692021-05-01 06:39:41 -05001095 mapDHCPToSystemd[EthernetInterfaceIntf::dhcpEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -05001096
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001097 stream << "[IPv6AcceptRA]\n";
1098 stream << "DHCPv6Client=";
1099 stream << (dhcpIsEnabled(IP::Protocol::IPv6) ? "true" : "false");
Johnathan Manteyb353ba02021-12-09 12:27:32 -08001100 stream << "\n";
William A. Kennington IIIe6d1c0e2021-12-03 14:00:30 -08001101
Johnathan Mantey817012a2020-01-30 15:07:39 -08001102 // Static IP addresses
1103 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +05301104 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001105 if (originIsManuallyAssigned(addr.second->origin()) &&
1106 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001107 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001108 // Process all static addresses
1109 std::string address = addr.second->address() + "/" +
1110 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +05301111
Johnathan Mantey817012a2020-01-30 15:07:39 -08001112 // build the address entries. Do not use [Network] shortcuts to
1113 // insert address entries.
1114 stream << "[Address]\n";
1115 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001116 }
Johnathan Mantey817012a2020-01-30 15:07:39 -08001117 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001118
Lei YUcb2d4082021-08-12 15:26:49 +08001119 if (!dhcpIsEnabled(IP::Protocol::IPv4))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001120 {
Lei YUcb2d4082021-08-12 15:26:49 +08001121 auto gateway = EthernetInterfaceIntf::defaultGateway();
1122 if (!gateway.empty())
1123 {
1124 stream << "[Route]\n";
1125 stream << "Gateway=" << gateway << "\n";
1126 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001127 }
1128
Lei YUcb2d4082021-08-12 15:26:49 +08001129 if (!dhcpIsEnabled(IP::Protocol::IPv6))
Ravi Tejaa5a09442020-07-17 00:57:33 -05001130 {
Lei YUcb2d4082021-08-12 15:26:49 +08001131 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1132 if (!gateway6.empty())
1133 {
1134 stream << "[Route]\n";
1135 stream << "Gateway=" << gateway6 << "\n";
1136 }
Ravi Tejaa5a09442020-07-17 00:57:33 -05001137 }
1138
William A. Kennington III08505792019-01-30 16:00:04 -08001139 // Write the neighbor sections
1140 for (const auto& neighbor : staticNeighbors)
1141 {
1142 stream << "[Neighbor]"
1143 << "\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001144 stream << "Address=" << neighbor.second->ipAddress() << "\n";
1145 stream << "MACAddress=" << neighbor.second->macAddress() << "\n";
William A. Kennington III08505792019-01-30 16:00:04 -08001146 }
1147
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001148 // Write the dhcp section irrespective of whether DHCP is enabled or not
1149 writeDHCPSection(stream);
1150
Ratan Gupta2b106532017-07-25 16:05:02 +05301151 stream.close();
William A. Kennington IIIf8b3fc32022-08-22 15:16:48 -07001152 auto msg = fmt::format("Wrote networkd file: {}", confPath.native());
1153 log<level::INFO>(msg.c_str(), entry("FILE=%s", confPath.c_str()));
Ratan Gupta2b106532017-07-25 16:05:02 +05301154}
1155
1156void EthernetInterface::writeDHCPSection(std::fstream& stream)
1157{
1158 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301159 // write the dhcp section
1160 stream << "[DHCP]\n";
1161
1162 // Hardcoding the client identifier to mac, to address below issue
1163 // https://github.com/openbmc/openbmc/issues/1280
1164 stream << "ClientIdentifier=mac\n";
1165 if (manager.getDHCPConf())
1166 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001167 auto value = manager.getDHCPConf()->dnsEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301168 stream << "UseDNS="s + value + "\n";
sunharisdd1e5922022-03-31 01:49:21 -05001169 stream << "UseDomains="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301170
Patrick Williams6aef7692021-05-01 06:39:41 -05001171 value = manager.getDHCPConf()->ntpEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301172 stream << "UseNTP="s + value + "\n";
1173
1174 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1175 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001176
1177 value =
1178 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1179 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301180 }
1181}
1182
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001183std::string EthernetInterface::macAddress([[maybe_unused]] std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301184{
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001185#ifdef PERSIST_MAC
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001186 ether_addr newMAC;
1187 try
1188 {
1189 newMAC = mac_address::fromString(value);
1190 }
Patrick Williams5758db32021-10-06 12:29:22 -05001191 catch (const std::invalid_argument&)
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001192 {
1193 log<level::ERR>("MACAddress is not valid.",
1194 entry("MAC=%s", value.c_str()));
1195 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1196 Argument::ARGUMENT_VALUE(value.c_str()));
1197 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001198 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301199 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001200 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001201 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001202 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1203 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301204 }
1205
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001206 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001207 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001208
William A. Kennington III1137a972019-04-20 20:49:58 -07001209 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001210 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001211 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301212 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001213 // Update everything that depends on the MAC value
1214 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301215 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001216 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301217 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001218 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301219
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001220 writeConfigurationFile();
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001221 manager.addReloadPreHook([interface]() {
1222 // The MAC and LLADDRs will only update if the NIC is already down
William A. Kennington III5dad2aa2022-01-21 16:00:17 -08001223 setNICAdminState(interface.c_str(), false);
William A. Kennington III6bfdf3e2021-11-09 17:15:12 -08001224 });
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001225 manager.reloadConfigs();
Ratan Gupta677ae122017-09-18 16:28:50 +05301226 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001227
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001228#ifdef HAVE_UBOOT_ENV
1229 // Ensure that the valid address is stored in the u-boot-env
1230 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1231 if (envVar)
1232 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001233 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1234 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1235 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1236 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001237 }
1238#endif // HAVE_UBOOT_ENV
1239
William A. Kennington III1137a972019-04-20 20:49:58 -07001240 return value;
Jiaqing Zhao69cfa312022-02-18 16:52:55 +08001241#else
1242 elog<NotAllowed>(
1243 NotAllowedArgument::REASON("Writing MAC address is not allowed"));
1244#endif // PERSIST_MAC
Ratan Guptabd303b12017-08-18 17:10:07 +05301245}
1246
Ratan Guptae9c9b812017-09-22 17:15:37 +05301247void EthernetInterface::deleteAll()
1248{
Ratan Guptae9c9b812017-09-22 17:15:37 +05301249 // clear all the ip on the interface
1250 addrs.clear();
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001251
1252 writeConfigurationFile();
1253 manager.reloadConfigs();
Ratan Guptae9c9b812017-09-22 17:15:37 +05301254}
1255
Ravi Tejaa5a09442020-07-17 00:57:33 -05001256std::string EthernetInterface::defaultGateway(std::string gateway)
1257{
1258 auto gw = EthernetInterfaceIntf::defaultGateway();
1259 if (gw == gateway)
1260 {
1261 return gw;
1262 }
1263
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001264 if (!isValidIP(AF_INET, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001265 {
1266 log<level::ERR>("Not a valid v4 Gateway",
1267 entry("GATEWAY=%s", gateway.c_str()));
1268 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1269 Argument::ARGUMENT_VALUE(gateway.c_str()));
1270 }
1271 gw = EthernetInterfaceIntf::defaultGateway(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001272
1273 writeConfigurationFile();
1274 manager.reloadConfigs();
1275
Ravi Tejaa5a09442020-07-17 00:57:33 -05001276 return gw;
1277}
1278
1279std::string EthernetInterface::defaultGateway6(std::string gateway)
1280{
1281 auto gw = EthernetInterfaceIntf::defaultGateway6();
1282 if (gw == gateway)
1283 {
1284 return gw;
1285 }
1286
Jiaqing Zhaoc2e061f2022-04-07 21:55:48 +08001287 if (!isValidIP(AF_INET6, gateway) && !gateway.empty())
Ravi Tejaa5a09442020-07-17 00:57:33 -05001288 {
1289 log<level::ERR>("Not a valid v6 Gateway",
1290 entry("GATEWAY=%s", gateway.c_str()));
1291 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1292 Argument::ARGUMENT_VALUE(gateway.c_str()));
1293 }
1294 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -07001295
1296 writeConfigurationFile();
1297 manager.reloadConfigs();
1298
Ravi Tejaa5a09442020-07-17 00:57:33 -05001299 return gw;
1300}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001301} // namespace network
1302} // namespace phosphor