blob: 6b3099e7f8bf8f40ae425a34a3176436c99b4625 [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 III08505792019-01-30 16:00:04 -08006#include "neighbor.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05307#include "network_manager.hpp"
Ravi Tejaa5a09442020-07-17 00:57:33 -05008#include "routing_table.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05309#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +053010
Ratan Gupta82549cc2017-04-21 08:45:23 +053011#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053012#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070013#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053015#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053016#include <netinet/in.h>
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <unistd.h>
20
Ratan Gupta82549cc2017-04-21 08:45:23 +053021#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053022#include <filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053023#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070024#include <phosphor-logging/elog-errors.hpp>
25#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053026#include <sstream>
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>
Patrick Venture189d44e2018-07-09 12:30:59 -070030#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053031
Ratan Gupta91a99cc2017-04-14 16:32:09 +053032namespace phosphor
33{
34namespace network
35{
36
37using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053038using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053039using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
40using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050041using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053042constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
43constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
44constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
45constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
46constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053047
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080048struct EthernetIntfSocket
49{
50 EthernetIntfSocket(int domain, int type, int protocol)
51 {
52 if ((sock = socket(domain, type, protocol)) < 0)
53 {
54 log<level::ERR>("socket creation failed:",
55 entry("ERROR=%s", strerror(errno)));
56 }
57 }
58
59 ~EthernetIntfSocket()
60 {
61 if (sock >= 0)
62 {
63 close(sock);
64 }
65 }
66
67 int sock{-1};
68};
69
Johnathan Mantey817012a2020-01-30 15:07:39 -080070std::map<EthernetInterface::DHCPConf, std::string> mapDHCPToSystemd = {
71 {EthernetInterface::DHCPConf::both, "true"},
72 {EthernetInterface::DHCPConf::v4, "ipv4"},
73 {EthernetInterface::DHCPConf::v6, "ipv6"},
74 {EthernetInterface::DHCPConf::none, "false"}};
75
Ratan Gupta91a99cc2017-04-14 16:32:09 +053076EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
77 const std::string& objPath,
Johnathan Mantey817012a2020-01-30 15:07:39 -080078 DHCPConf dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053079 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050080 Ifaces(bus, objPath.c_str(), true),
81 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053082{
83 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053084 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053085 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053086 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Johnathan Mantey5b023f52019-06-24 16:06:37 -070087 EthernetInterfaceIntf::iPv6AcceptRA(getIPv6AcceptRAFromConf());
Ravi Tejaa5a09442020-07-17 00:57:33 -050088 route::Table routingTable;
89 auto gatewayList = routingTable.getDefaultGateway();
90 auto gateway6List = routingTable.getDefaultGateway6();
91 std::string defaultGateway;
92 std::string defaultGateway6;
93
94 for (auto& gateway : gatewayList)
95 {
96 if (gateway.first == intfName)
97 {
98 defaultGateway = gateway.second;
99 break;
100 }
101 }
102
103 for (auto& gateway6 : gateway6List)
104 {
105 if (gateway6.first == intfName)
106 {
107 defaultGateway6 = gateway6.second;
108 break;
109 }
110 }
111
112 EthernetInterfaceIntf::defaultGateway(defaultGateway);
113 EthernetInterfaceIntf::defaultGateway6(defaultGateway6);
Ratan Gupta99801ce2020-01-09 18:37:16 +0530114 // Don't get the mac address from the system as the mac address
115 // would be same as parent interface.
116 if (intfName.find(".") == std::string::npos)
117 {
118 MacAddressIntf::mACAddress(getMACAddress(intfName));
119 }
Ratan Gupta497c0c92017-08-22 19:15:59 +0530120 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +0530121
122 EthernetInterfaceIntf::linkUp(linkUp());
123 EthernetInterfaceIntf::nICEnabled(nICEnabled());
124
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800125#if NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -0700126 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
127
128 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
129 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800130#endif
Ratan Gupta6dec3902017-08-20 15:28:12 +0530131
Ratan Gupta29b0e432017-05-25 12:51:40 +0530132 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530133 if (emitSignal)
134 {
135 this->emit_object_added();
136 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530137}
138
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800139static IP::Protocol convertFamily(int family)
140{
141 switch (family)
142 {
143 case AF_INET:
144 return IP::Protocol::IPv4;
145 case AF_INET6:
146 return IP::Protocol::IPv6;
147 }
148
149 throw std::invalid_argument("Bad address family");
150}
151
Johnathan Mantey817012a2020-01-30 15:07:39 -0800152void EthernetInterface::disableDHCP(IP::Protocol protocol)
153{
154 DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled();
155 if (dhcpState == EthernetInterface::DHCPConf::both)
156 {
157 if (protocol == IP::Protocol::IPv4)
158 {
159 dHCPEnabled(EthernetInterface::DHCPConf::v6);
160 }
161 else if (protocol == IP::Protocol::IPv6)
162 {
163 dHCPEnabled(EthernetInterface::DHCPConf::v4);
164 }
165 }
166 else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
167 (protocol == IP::Protocol::IPv4))
168 {
169 dHCPEnabled(EthernetInterface::DHCPConf::none);
170 }
171 else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
172 (protocol == IP::Protocol::IPv6))
173 {
174 dHCPEnabled(EthernetInterface::DHCPConf::none);
175 }
176}
177
178bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol)
179{
180 return ((EthernetInterfaceIntf::dHCPEnabled() ==
181 EthernetInterface::DHCPConf::both) ||
182 ((EthernetInterfaceIntf::dHCPEnabled() ==
183 EthernetInterface::DHCPConf::v6) &&
184 ((family == IP::Protocol::IPv6) || ignoreProtocol)) ||
185 ((EthernetInterfaceIntf::dHCPEnabled() ==
186 EthernetInterface::DHCPConf::v4) &&
187 ((family == IP::Protocol::IPv4) || ignoreProtocol)));
188}
189
190bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family,
191 const std::string& nextDHCPState)
192{
193 return ((nextDHCPState == "true") ||
194 ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) ||
195 ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4)));
196}
197
198bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
199{
200 return (
201#ifdef LINK_LOCAL_AUTOCONFIGURATION
202 (origin == IP::AddressOrigin::Static)
203#else
204 (origin == IP::AddressOrigin::Static ||
205 origin == IP::AddressOrigin::LinkLocal)
206#endif
207
208 );
209}
210
Ratan Gupta87c13982017-06-15 09:27:27 +0530211void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530212{
Ratan Gupta87c13982017-06-15 09:27:27 +0530213 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530214
Ratan Gupta87c13982017-06-15 09:27:27 +0530215 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530216
Ratan Gupta6a387c12017-08-03 13:26:19 +0530217 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530218 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800219 IP::Protocol addressType = convertFamily(addr.addrType);
220 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800221 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530222 {
223 origin = IP::AddressOrigin::DHCP;
224 }
William A. Kennington III16893802019-01-30 16:01:01 -0800225 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530226 {
227 origin = IP::AddressOrigin::LinkLocal;
228 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700229 // Obsolete parameter
230 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530231
Gunnar Mills57d9c502018-09-14 14:42:34 -0500232 std::string ipAddressObjectPath = generateObjectPath(
233 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530234
Gunnar Mills57d9c502018-09-14 14:42:34 -0500235 this->addrs.emplace(addr.ipaddress,
236 std::make_shared<phosphor::network::IPAddress>(
237 bus, ipAddressObjectPath.c_str(), *this,
238 addressType, addr.ipaddress, origin,
239 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530240 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530241}
242
William A. Kennington III08505792019-01-30 16:00:04 -0800243void EthernetInterface::createStaticNeighborObjects()
244{
245 staticNeighbors.clear();
246
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700247 NeighborFilter filter;
248 filter.interface = ifIndex();
249 filter.state = NUD_PERMANENT;
250 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800251 for (const auto& neighbor : neighbors)
252 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700253 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800254 {
255 continue;
256 }
257 std::string ip = toString(neighbor.address);
258 std::string mac = mac_address::toString(*neighbor.mac);
259 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
260 staticNeighbors.emplace(ip,
261 std::make_shared<phosphor::network::Neighbor>(
262 bus, objectPath.c_str(), *this, ip, mac,
263 Neighbor::State::Permanent));
264 }
265}
266
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700267unsigned EthernetInterface::ifIndex() const
268{
269 unsigned idx = if_nametoindex(interfaceName().c_str());
270 if (idx == 0)
271 {
272 throw std::system_error(errno, std::generic_category(),
273 "if_nametoindex");
274 }
275 return idx;
276}
277
raviteja-bce379562019-03-28 05:59:36 -0500278ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
279 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530280{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530281
Johnathan Mantey817012a2020-01-30 15:07:39 -0800282 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530283 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530284 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500285 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800286 disableDHCP(protType);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500287 }
288
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500289 IP::AddressOrigin origin = IP::AddressOrigin::Static;
290
291 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
292
293 if (!isValidIP(addressFamily, ipaddress))
294 {
295 log<level::ERR>("Not a valid IP address"),
296 entry("ADDRESS=%s", ipaddress.c_str());
297 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
298 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
299 }
300
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700301 // Gateway is an obsolete parameter
302 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500303
304 if (!isValidPrefix(addressFamily, prefixLength))
305 {
306 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700307 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500308 elog<InvalidArgument>(
309 Argument::ARGUMENT_NAME("prefixLength"),
310 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530311 }
312
Gunnar Mills57d9c502018-09-14 14:42:34 -0500313 std::string objectPath =
314 generateObjectPath(protType, ipaddress, prefixLength, gateway);
315 this->addrs.emplace(ipaddress,
316 std::make_shared<phosphor::network::IPAddress>(
317 bus, objectPath.c_str(), *this, protType, ipaddress,
318 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530319
Ratan Guptae05083a2017-09-16 07:12:11 +0530320 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500321 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530322}
323
William A. Kennington III08505792019-01-30 16:00:04 -0800324ObjectPath EthernetInterface::neighbor(std::string iPAddress,
325 std::string mACAddress)
326{
327 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
328 {
329 log<level::ERR>("Not a valid IP address",
330 entry("ADDRESS=%s", iPAddress.c_str()));
331 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
332 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
333 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700334 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800335 {
336 log<level::ERR>("Not a valid MAC address",
337 entry("MACADDRESS=%s", iPAddress.c_str()));
338 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
339 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
340 }
341
342 std::string objectPath =
343 generateStaticNeighborObjectPath(iPAddress, mACAddress);
344 staticNeighbors.emplace(iPAddress,
345 std::make_shared<phosphor::network::Neighbor>(
346 bus, objectPath.c_str(), *this, iPAddress,
347 mACAddress, Neighbor::State::Permanent));
348 manager.writeToConfigurationFile();
349 return objectPath;
350}
351
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800352#if NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530353/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800354 Enable this code if your NIC driver supports the ETHTOOL features.
355 Do this by adding the following to your phosphor-network*.bbappend file.
356 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
357 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530358*/
359InterfaceInfo EthernetInterface::getInterfaceInfo() const
360{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400361 ifreq ifr{0};
362 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500363 LinkSpeed speed{0};
364 Autoneg autoneg{0};
365 DuplexMode duplex{0};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800366 LinkUp linkState{false};
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700367 NICEnabled nicEnabled{false};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800368 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
369
370 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530371 {
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700372 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800373 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530374
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800375 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
376 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530377
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800378 edata.cmd = ETHTOOL_GSET;
379 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
380 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530381 speed = edata.speed;
382 duplex = edata.duplex;
383 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530384 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800385
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700386 nicEnabled = nICEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800387 linkState = linkUp();
388
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700389 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530390}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800391#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530392
393/** @brief get the mac address of the interface.
394 * @return macaddress on success
395 */
396
Gunnar Mills57d9c502018-09-14 14:42:34 -0500397std::string
398 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530399{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800400 std::string activeMACAddr = MacAddressIntf::mACAddress();
401 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
402
403 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530404 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800405 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530406 }
407
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800408 ifreq ifr{0};
409 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
410 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530411 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530412 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500413 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700414 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530415 }
416
William A. Kennington III1137a972019-04-20 20:49:58 -0700417 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
418 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
419 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700420 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530421}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530422
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530423std::string EthernetInterface::generateId(const std::string& ipaddress,
424 uint8_t prefixLength,
425 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530426{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530427 std::stringstream hexId;
428 std::string hashString = ipaddress;
429 hashString += std::to_string(prefixLength);
430 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530431
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530432 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500433 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530434 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530435}
436
William A. Kennington III08505792019-01-30 16:00:04 -0800437std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
438 const std::string& mACAddress)
439{
440 std::stringstream hexId;
441 std::string hashString = iPAddress + mACAddress;
442
443 // Only want 8 hex digits.
444 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
445 return hexId.str();
446}
447
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530448void EthernetInterface::deleteObject(const std::string& ipaddress)
449{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530450 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530451 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530452 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530453 log<level::ERR>("DeleteObject:Unable to find the object.");
454 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530455 }
456 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530457 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530458}
459
William A. Kennington III08505792019-01-30 16:00:04 -0800460void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
461{
462 auto it = staticNeighbors.find(iPAddress);
463 if (it == staticNeighbors.end())
464 {
465 log<level::ERR>(
466 "DeleteStaticNeighborObject:Unable to find the object.");
467 return;
468 }
469 staticNeighbors.erase(it);
470 manager.writeToConfigurationFile();
471}
472
Ratan Guptae9c9b812017-09-22 17:15:37 +0530473void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530474{
Ratan Guptabc886292017-07-25 18:29:57 +0530475 auto confDir = manager.getConfDir();
476 fs::path networkFile = confDir;
477 networkFile /= systemd::config::networkFilePrefix + interface +
478 systemd::config::networkFileSuffix;
479
480 fs::path deviceFile = confDir;
481 deviceFile /= interface + systemd::config::deviceFileSuffix;
482
483 // delete the vlan network file
484 if (fs::is_regular_file(networkFile))
485 {
486 fs::remove(networkFile);
487 }
488
489 // delete the vlan device file
490 if (fs::is_regular_file(deviceFile))
491 {
492 fs::remove(deviceFile);
493 }
Ratan Guptabc886292017-07-25 18:29:57 +0530494
495 // TODO systemd doesn't delete the virtual network interface
496 // even after deleting all the related configuartion.
497 // https://github.com/systemd/systemd/issues/6600
498 try
499 {
500 deleteInterface(interface);
501 }
502 catch (InternalFailure& e)
503 {
504 commit<InternalFailure>();
505 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530506}
507
508void EthernetInterface::deleteVLANObject(const std::string& interface)
509{
510 auto it = vlanInterfaces.find(interface);
511 if (it == vlanInterfaces.end())
512 {
513 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500514 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530515 return;
516 }
517
518 deleteVLANFromSystem(interface);
519 // delete the interface
520 vlanInterfaces.erase(it);
521
Ratan Guptae05083a2017-09-16 07:12:11 +0530522 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530523}
524
Gunnar Mills57d9c502018-09-14 14:42:34 -0500525std::string EthernetInterface::generateObjectPath(
526 IP::Protocol addressType, const std::string& ipaddress,
527 uint8_t prefixLength, const std::string& gateway) 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;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530536 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530537 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530538}
539
William A. Kennington III08505792019-01-30 16:00:04 -0800540std::string EthernetInterface::generateStaticNeighborObjectPath(
541 const std::string& iPAddress, const std::string& mACAddress) const
542{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530543 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800544 objectPath /= objPath;
545 objectPath /= "static_neighbor";
546 objectPath /= generateNeighborId(iPAddress, mACAddress);
547 return objectPath.string();
548}
549
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700550bool EthernetInterface::iPv6AcceptRA(bool value)
551{
552 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
553 {
554 return value;
555 }
556 EthernetInterfaceIntf::iPv6AcceptRA(value);
557 manager.writeToConfigurationFile();
558 return value;
559}
560
Johnathan Mantey817012a2020-01-30 15:07:39 -0800561EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530562{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530563 if (value == EthernetInterfaceIntf::dHCPEnabled())
564 {
565 return value;
566 }
567
Ratan Gupta87c13982017-06-15 09:27:27 +0530568 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530569 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530570 return value;
571}
572
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800573bool EthernetInterface::linkUp() const
574{
575 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
576 bool value = EthernetInterfaceIntf::linkUp();
577
578 if (eifSocket.sock < 0)
579 {
580 return value;
581 }
582
583 ifreq ifr{0};
584 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
585 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
586 {
587 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
588 }
589 else
590 {
591 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
592 entry("ERROR=%s", strerror(errno)));
593 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700594 return value;
595}
596
597bool EthernetInterface::nICEnabled() const
598{
599 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
600 bool value = EthernetInterfaceIntf::nICEnabled();
601
602 if (eifSocket.sock < 0)
603 {
604 return value;
605 }
606
607 ifreq ifr{0};
608 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
609 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
610 {
611 value = static_cast<bool>(ifr.ifr_flags & IFF_UP);
612 }
613 else
614 {
615 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
616 entry("ERROR=%s", strerror(errno)));
617 }
618 return value;
619}
620
621bool EthernetInterface::nICEnabled(bool value)
622{
623 if (value == EthernetInterfaceIntf::nICEnabled())
624 {
625 return value;
626 }
627
628 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
629 if (eifSocket.sock < 0)
630 {
631 return EthernetInterfaceIntf::nICEnabled();
632 }
633
634 ifreq ifr{0};
635 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
636 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) != 0)
637 {
638 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
639 entry("ERROR=%s", strerror(errno)));
640 return EthernetInterfaceIntf::nICEnabled();
641 }
642
643 ifr.ifr_flags &= ~IFF_UP;
644 ifr.ifr_flags |= value ? IFF_UP : 0;
645
646 if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
647 {
648 log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
649 entry("ERROR=%s", strerror(errno)));
650 return EthernetInterfaceIntf::nICEnabled();
651 }
652 EthernetInterfaceIntf::nICEnabled(value);
653 writeConfigurationFile();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800654
655 return value;
656}
657
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530658ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530659{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530660 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
661 return EthernetInterfaceIntf::nameservers();
662}
663
664ServerList EthernetInterface::staticNameServers(ServerList value)
665{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530666 for (const auto& nameserverip : value)
667 {
668 if (!isValidIP(AF_INET, nameserverip) &&
669 !isValidIP(AF_INET6, nameserverip))
670 {
671 log<level::ERR>("Not a valid IP address"),
672 entry("ADDRESS=%s", nameserverip.c_str());
673 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530674 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530675 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
676 }
677 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530678 try
679 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530680 EthernetInterfaceIntf::staticNameServers(value);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530681 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530682 // resolved reads the DNS server configuration from the
683 // network file.
684 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530685 }
686 catch (InternalFailure& e)
687 {
688 log<level::ERR>("Exception processing DNS entries");
689 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530690 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530691}
692
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530693void EthernetInterface::loadNameServers()
694{
695 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
696 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
697}
698
699ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec3902017-08-20 15:28:12 +0530700{
701 fs::path confPath = manager.getConfDir();
702
703 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500704 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530705 confPath /= fileName;
706 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530707 config::Parser parser(confPath.string());
708 auto rc = config::ReturnCode::SUCCESS;
709
710 std::tie(rc, servers) = parser.getValues("Network", "DNS");
711 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530712 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530713 log<level::DEBUG>("Unable to get the value for network[DNS]",
714 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530715 }
716 return servers;
717}
718
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530719ServerList EthernetInterface::getNameServerFromResolvd()
720{
721 ServerList servers;
722 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
723
724 /*
725 The DNS property under org.freedesktop.resolve1.Link interface contains
726 an array containing all DNS servers currently used by resolved. It
727 contains similar information as the DNS server data written to
728 /run/systemd/resolve/resolv.conf.
729
730 Each structure in the array consists of a numeric network interface index,
731 an address family, and a byte array containing the DNS server address
732 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
733 The array contains DNS servers configured system-wide, including those
734 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
735 /etc/systemd/resolved.conf, as well as per-interface DNS server
736 information either retrieved from systemd-networkd or configured by
737 external software via SetLinkDNS().
738 */
739
740 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
741 std::variant<type> name; // Variable to capture the DNS property
742 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
743 PROPERTY_INTERFACE, METHOD_GET);
744
745 method.append(RESOLVED_INTERFACE, "DNS");
746 auto reply = bus.call(method);
747
748 try
749 {
750 reply.read(name);
751 }
752 catch (const sdbusplus::exception::SdBusError& e)
753 {
754 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
755 }
756 auto tupleVector = std::get_if<type>(&name);
757 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
758 {
Alexander Filippov983da552021-02-08 15:26:54 +0300759 int addressFamily = std::get<0>(*i);
760 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
761
762 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530763 {
Alexander Filippov983da552021-02-08 15:26:54 +0300764 case AF_INET:
765 if (ipaddress.size() == sizeof(struct in_addr))
766 {
767 servers.push_back(toString(
768 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
769 }
770 else
771 {
772 log<level::ERR>(
773 "Invalid data recived from Systemd-Resolved");
774 }
775 break;
776
777 case AF_INET6:
778 if (ipaddress.size() == sizeof(struct in6_addr))
779 {
780 servers.push_back(toString(
781 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
782 }
783 else
784 {
785 log<level::ERR>(
786 "Invalid data recived from Systemd-Resolved");
787 }
788 break;
789
790 default:
791 log<level::ERR>(
792 "Unsupported address family in DNS from Systemd-Resolved");
793 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530794 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530795 }
796 return servers;
797}
798
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530799void EthernetInterface::loadVLAN(VlanId id)
800{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500801 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530802 std::string path = objPath;
803 path += "_" + std::to_string(id);
804
Johnathan Mantey817012a2020-01-30 15:07:39 -0800805 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500806 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530807 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800808 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nICEnabled(), id,
809 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530810
Gunnar Mills57d9c502018-09-14 14:42:34 -0500811 // Fetch the ip address from the system
812 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530813 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800814 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530815
816 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
817 std::move(vlanIntf));
818}
819
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700820ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530821{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500822 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530823 std::string path = objPath;
824 path += "_" + std::to_string(id);
825
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530826 // Pass the parents nICEnabled property, so that the child
827 // VLAN interface can inherit.
828
Ratan Gupta5978dd12017-07-25 13:47:13 +0530829 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800830 bus, path.c_str(), EthernetInterface::DHCPConf::none,
831 EthernetInterfaceIntf::nICEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530832
833 // write the device file for the vlan interface.
834 vlanIntf->writeDeviceFile();
835
Gunnar Mills57d9c502018-09-14 14:42:34 -0500836 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530837 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530838 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700839
840 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530841}
Ratan Gupta2b106532017-07-25 16:05:02 +0530842
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700843bool EthernetInterface::getIPv6AcceptRAFromConf()
844{
845 fs::path confPath = manager.getConfDir();
846
847 std::string fileName = systemd::config::networkFilePrefix +
848 interfaceName() + systemd::config::networkFileSuffix;
849 confPath /= fileName;
850 config::ValueList values;
851 config::Parser parser(confPath.string());
852 auto rc = config::ReturnCode::SUCCESS;
853 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
854 if (rc != config::ReturnCode::SUCCESS)
855 {
856 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
857 entry("rc=%d", rc));
858 return false;
859 }
860 return (values[0] == "true");
861}
862
Ratan Gupta497c0c92017-08-22 19:15:59 +0530863ServerList EthernetInterface::getNTPServersFromConf()
864{
865 fs::path confPath = manager.getConfDir();
866
Gunnar Mills57d9c502018-09-14 14:42:34 -0500867 std::string fileName = systemd::config::networkFilePrefix +
868 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530869 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530870
Ratan Gupta497c0c92017-08-22 19:15:59 +0530871 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530872 config::Parser parser(confPath.string());
873 auto rc = config::ReturnCode::SUCCESS;
874
875 std::tie(rc, servers) = parser.getValues("Network", "NTP");
876 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530877 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530878 log<level::DEBUG>("Unable to get the value for Network[NTP]",
879 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530880 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530881
Ratan Gupta497c0c92017-08-22 19:15:59 +0530882 return servers;
883}
884
885ServerList EthernetInterface::nTPServers(ServerList servers)
886{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500887 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530888
889 writeConfigurationFile();
890 // timesynchd reads the NTP server configuration from the
891 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530892 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530893 return ntpServers;
894}
Ratan Gupta2b106532017-07-25 16:05:02 +0530895// Need to merge the below function with the code which writes the
896// config file during factory reset.
897// TODO openbmc/openbmc#1751
898
899void EthernetInterface::writeConfigurationFile()
900{
901 // write all the static ip address in the systemd-network conf file
902
903 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530904 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530905
906 // if there is vlan interafce then write the configuration file
907 // for vlan also.
908
Gunnar Mills57d9c502018-09-14 14:42:34 -0500909 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530910 {
911 intf.second->writeConfigurationFile();
912 }
913
Ratan Gupta2b106532017-07-25 16:05:02 +0530914 fs::path confPath = manager.getConfDir();
915
Gunnar Mills57d9c502018-09-14 14:42:34 -0500916 std::string fileName = systemd::config::networkFilePrefix +
917 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530918 confPath /= fileName;
919 std::fstream stream;
920
921 stream.open(confPath.c_str(), std::fstream::out);
922 if (!stream.is_open())
923 {
924 log<level::ERR>("Unable to open the file",
925 entry("FILE=%s", confPath.c_str()));
926 elog<InternalFailure>();
927 }
928
929 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400930 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530931 stream << "Name=" << interfaceName() << "\n";
932
933 auto addrs = getAddresses();
934
William A. Kennington III15787212019-04-23 19:18:01 -0700935 // Write the link section
936 stream << "[Link]\n";
937 auto mac = MacAddressIntf::mACAddress();
938 if (!mac.empty())
939 {
940 stream << "MACAddress=" << mac << "\n";
941 }
942
Ratan Gupta40a51df2020-04-24 15:11:05 +0530943 if (!EthernetInterfaceIntf::nICEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700944 {
945 stream << "Unmanaged=yes\n";
946 }
947
Ratan Gupta2b106532017-07-25 16:05:02 +0530948 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400949 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400950#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500951 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400952#else
953 stream << "LinkLocalAddressing=no\n";
954#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700955 stream << std::boolalpha
956 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530957
958 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500959 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530960 {
961 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500962 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530963 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530964 // Add the NTP server
965 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
966 {
967 stream << "NTP=" << ntp << "\n";
968 }
969
970 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530971 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530972 {
973 stream << "DNS=" << dns << "\n";
974 }
975
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500976 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -0800977 stream << "DHCP="s +
978 mapDHCPToSystemd[EthernetInterfaceIntf::dHCPEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500979
Johnathan Mantey817012a2020-01-30 15:07:39 -0800980 // Static IP addresses
981 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +0530982 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800983 if (originIsManuallyAssigned(addr.second->origin()) &&
984 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600985 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800986 // Process all static addresses
987 std::string address = addr.second->address() + "/" +
988 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530989
Johnathan Mantey817012a2020-01-30 15:07:39 -0800990 // build the address entries. Do not use [Network] shortcuts to
991 // insert address entries.
992 stream << "[Address]\n";
993 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600994 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800995 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600996
Ravi Tejaa5a09442020-07-17 00:57:33 -0500997 auto gateway = EthernetInterfaceIntf::defaultGateway();
998 if (!gateway.empty())
999 {
Ravi Tejac14b4b32021-03-16 00:01:17 -05001000 stream << "[Route]\n";
Ravi Tejaa5a09442020-07-17 00:57:33 -05001001 stream << "Gateway=" << gateway << "\n";
1002 }
1003
1004 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1005 if (!gateway6.empty())
1006 {
Ravi Tejac14b4b32021-03-16 00:01:17 -05001007 stream << "[Route]\n";
Ravi Tejaa5a09442020-07-17 00:57:33 -05001008 stream << "Gateway=" << gateway6 << "\n";
1009 }
1010
Johnathan Mantey817012a2020-01-30 15:07:39 -08001011 if (manager.getSystemConf())
1012 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001013 const auto& gateway = manager.getSystemConf()->defaultGateway();
1014 if (!gateway.empty())
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001015 {
Ravi Tejac14b4b32021-03-16 00:01:17 -05001016 stream << "[Route]\n";
Johnathan Mantey817012a2020-01-30 15:07:39 -08001017 stream << "Gateway=" << gateway << "\n";
1018 }
1019 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
1020 if (!gateway6.empty())
1021 {
Ravi Tejac14b4b32021-03-16 00:01:17 -05001022 stream << "[Route]\n";
Johnathan Mantey817012a2020-01-30 15:07:39 -08001023 stream << "Gateway=" << gateway6 << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001024 }
Ratan Gupta2b106532017-07-25 16:05:02 +05301025 }
1026
William A. Kennington III08505792019-01-30 16:00:04 -08001027 // Write the neighbor sections
1028 for (const auto& neighbor : staticNeighbors)
1029 {
1030 stream << "[Neighbor]"
1031 << "\n";
1032 stream << "Address=" << neighbor.second->iPAddress() << "\n";
1033 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
1034 }
1035
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001036 // Write the dhcp section irrespective of whether DHCP is enabled or not
1037 writeDHCPSection(stream);
1038
Ratan Gupta2b106532017-07-25 16:05:02 +05301039 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +05301040}
1041
1042void EthernetInterface::writeDHCPSection(std::fstream& stream)
1043{
1044 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301045 // write the dhcp section
1046 stream << "[DHCP]\n";
1047
1048 // Hardcoding the client identifier to mac, to address below issue
1049 // https://github.com/openbmc/openbmc/issues/1280
1050 stream << "ClientIdentifier=mac\n";
1051 if (manager.getDHCPConf())
1052 {
1053 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
1054 stream << "UseDNS="s + value + "\n";
1055
1056 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
1057 stream << "UseNTP="s + value + "\n";
1058
1059 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1060 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001061
1062 value =
1063 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1064 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301065 }
1066}
1067
Ratan Guptabd303b12017-08-18 17:10:07 +05301068std::string EthernetInterface::mACAddress(std::string value)
1069{
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001070 ether_addr newMAC;
1071 try
1072 {
1073 newMAC = mac_address::fromString(value);
1074 }
1075 catch (std::invalid_argument&)
1076 {
1077 log<level::ERR>("MACAddress is not valid.",
1078 entry("MAC=%s", value.c_str()));
1079 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1080 Argument::ARGUMENT_VALUE(value.c_str()));
1081 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001082 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301083 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001084 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001085 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001086 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1087 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301088 }
1089
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001090 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001091 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001092
William A. Kennington III1137a972019-04-20 20:49:58 -07001093 // We don't need to update the system if the address is unchanged
1094 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001095 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301096 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001097 // Update everything that depends on the MAC value
1098 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301099 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001100 intf->MacAddressIntf::mACAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301101 }
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001102 MacAddressIntf::mACAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301103
William A. Kennington III15787212019-04-23 19:18:01 -07001104 // TODO: would remove the call below and
1105 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -07001106 // through https://github.com/systemd/systemd/issues/6696
1107 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
1108 "down");
William A. Kennington III15787212019-04-23 19:18:01 -07001109 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +05301110 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001111
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001112#ifdef HAVE_UBOOT_ENV
1113 // Ensure that the valid address is stored in the u-boot-env
1114 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1115 if (envVar)
1116 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001117 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1118 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1119 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1120 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001121 }
1122#endif // HAVE_UBOOT_ENV
1123
William A. Kennington III1137a972019-04-20 20:49:58 -07001124 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301125}
1126
Ratan Guptae9c9b812017-09-22 17:15:37 +05301127void EthernetInterface::deleteAll()
1128{
Johnathan Mantey817012a2020-01-30 15:07:39 -08001129 if (dhcpIsEnabled(IP::Protocol::IPv4, true))
Ratan Guptae9c9b812017-09-22 17:15:37 +05301130 {
1131 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001132 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301133 }
1134
1135 // clear all the ip on the interface
1136 addrs.clear();
1137 manager.writeToConfigurationFile();
1138}
1139
Ravi Tejaa5a09442020-07-17 00:57:33 -05001140std::string EthernetInterface::defaultGateway(std::string gateway)
1141{
1142 auto gw = EthernetInterfaceIntf::defaultGateway();
1143 if (gw == gateway)
1144 {
1145 return gw;
1146 }
1147
1148 if (!isValidIP(AF_INET, gateway))
1149 {
1150 log<level::ERR>("Not a valid v4 Gateway",
1151 entry("GATEWAY=%s", gateway.c_str()));
1152 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1153 Argument::ARGUMENT_VALUE(gateway.c_str()));
1154 }
1155 gw = EthernetInterfaceIntf::defaultGateway(gateway);
1156 manager.writeToConfigurationFile();
1157 return gw;
1158}
1159
1160std::string EthernetInterface::defaultGateway6(std::string gateway)
1161{
1162 auto gw = EthernetInterfaceIntf::defaultGateway6();
1163 if (gw == gateway)
1164 {
1165 return gw;
1166 }
1167
1168 if (!isValidIP(AF_INET6, gateway))
1169 {
1170 log<level::ERR>("Not a valid v6 Gateway",
1171 entry("GATEWAY=%s", gateway.c_str()));
1172 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1173 Argument::ARGUMENT_VALUE(gateway.c_str()));
1174 }
1175 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
1176 manager.writeToConfigurationFile();
1177 return gw;
1178}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001179} // namespace network
1180} // namespace phosphor