blob: d06d88726b586fc93affa2a684b2105a7ff3bc42 [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 {
759 std::vector<uint8_t> ipaddress = std::get<1>(*i);
760 std::string address;
761 for (auto byte : ipaddress)
762 {
763 address += std::to_string(byte) + ".";
764 }
765 address.pop_back();
766 servers.push_back(address);
767 }
768 return servers;
769}
770
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530771void EthernetInterface::loadVLAN(VlanId id)
772{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500773 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530774 std::string path = objPath;
775 path += "_" + std::to_string(id);
776
Johnathan Mantey817012a2020-01-30 15:07:39 -0800777 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500778 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530779 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800780 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nICEnabled(), id,
781 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530782
Gunnar Mills57d9c502018-09-14 14:42:34 -0500783 // Fetch the ip address from the system
784 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530785 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800786 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530787
788 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
789 std::move(vlanIntf));
790}
791
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700792ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530793{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500794 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530795 std::string path = objPath;
796 path += "_" + std::to_string(id);
797
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530798 // Pass the parents nICEnabled property, so that the child
799 // VLAN interface can inherit.
800
Ratan Gupta5978dd12017-07-25 13:47:13 +0530801 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800802 bus, path.c_str(), EthernetInterface::DHCPConf::none,
803 EthernetInterfaceIntf::nICEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530804
805 // write the device file for the vlan interface.
806 vlanIntf->writeDeviceFile();
807
Gunnar Mills57d9c502018-09-14 14:42:34 -0500808 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530809 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530810 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700811
812 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530813}
Ratan Gupta2b106532017-07-25 16:05:02 +0530814
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700815bool EthernetInterface::getIPv6AcceptRAFromConf()
816{
817 fs::path confPath = manager.getConfDir();
818
819 std::string fileName = systemd::config::networkFilePrefix +
820 interfaceName() + systemd::config::networkFileSuffix;
821 confPath /= fileName;
822 config::ValueList values;
823 config::Parser parser(confPath.string());
824 auto rc = config::ReturnCode::SUCCESS;
825 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
826 if (rc != config::ReturnCode::SUCCESS)
827 {
828 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
829 entry("rc=%d", rc));
830 return false;
831 }
832 return (values[0] == "true");
833}
834
Ratan Gupta497c0c92017-08-22 19:15:59 +0530835ServerList EthernetInterface::getNTPServersFromConf()
836{
837 fs::path confPath = manager.getConfDir();
838
Gunnar Mills57d9c502018-09-14 14:42:34 -0500839 std::string fileName = systemd::config::networkFilePrefix +
840 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530841 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530842
Ratan Gupta497c0c92017-08-22 19:15:59 +0530843 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530844 config::Parser parser(confPath.string());
845 auto rc = config::ReturnCode::SUCCESS;
846
847 std::tie(rc, servers) = parser.getValues("Network", "NTP");
848 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530849 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530850 log<level::DEBUG>("Unable to get the value for Network[NTP]",
851 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530852 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530853
Ratan Gupta497c0c92017-08-22 19:15:59 +0530854 return servers;
855}
856
857ServerList EthernetInterface::nTPServers(ServerList servers)
858{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500859 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530860
861 writeConfigurationFile();
862 // timesynchd reads the NTP server configuration from the
863 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530864 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530865 return ntpServers;
866}
Ratan Gupta2b106532017-07-25 16:05:02 +0530867// Need to merge the below function with the code which writes the
868// config file during factory reset.
869// TODO openbmc/openbmc#1751
870
871void EthernetInterface::writeConfigurationFile()
872{
873 // write all the static ip address in the systemd-network conf file
874
875 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530876 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530877
878 // if there is vlan interafce then write the configuration file
879 // for vlan also.
880
Gunnar Mills57d9c502018-09-14 14:42:34 -0500881 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530882 {
883 intf.second->writeConfigurationFile();
884 }
885
Ratan Gupta2b106532017-07-25 16:05:02 +0530886 fs::path confPath = manager.getConfDir();
887
Gunnar Mills57d9c502018-09-14 14:42:34 -0500888 std::string fileName = systemd::config::networkFilePrefix +
889 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530890 confPath /= fileName;
891 std::fstream stream;
892
893 stream.open(confPath.c_str(), std::fstream::out);
894 if (!stream.is_open())
895 {
896 log<level::ERR>("Unable to open the file",
897 entry("FILE=%s", confPath.c_str()));
898 elog<InternalFailure>();
899 }
900
901 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400902 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530903 stream << "Name=" << interfaceName() << "\n";
904
905 auto addrs = getAddresses();
906
William A. Kennington III15787212019-04-23 19:18:01 -0700907 // Write the link section
908 stream << "[Link]\n";
909 auto mac = MacAddressIntf::mACAddress();
910 if (!mac.empty())
911 {
912 stream << "MACAddress=" << mac << "\n";
913 }
914
Ratan Gupta40a51df2020-04-24 15:11:05 +0530915 if (!EthernetInterfaceIntf::nICEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700916 {
917 stream << "Unmanaged=yes\n";
918 }
919
Ratan Gupta2b106532017-07-25 16:05:02 +0530920 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400921 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400922#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500923 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400924#else
925 stream << "LinkLocalAddressing=no\n";
926#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700927 stream << std::boolalpha
928 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530929
930 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500931 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530932 {
933 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500934 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530935 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530936 // Add the NTP server
937 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
938 {
939 stream << "NTP=" << ntp << "\n";
940 }
941
942 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530943 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530944 {
945 stream << "DNS=" << dns << "\n";
946 }
947
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500948 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -0800949 stream << "DHCP="s +
950 mapDHCPToSystemd[EthernetInterfaceIntf::dHCPEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500951
Johnathan Mantey817012a2020-01-30 15:07:39 -0800952 // Static IP addresses
953 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +0530954 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800955 if (originIsManuallyAssigned(addr.second->origin()) &&
956 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600957 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800958 // Process all static addresses
959 std::string address = addr.second->address() + "/" +
960 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530961
Johnathan Mantey817012a2020-01-30 15:07:39 -0800962 // build the address entries. Do not use [Network] shortcuts to
963 // insert address entries.
964 stream << "[Address]\n";
965 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600966 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800967 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600968
Ravi Tejaa5a09442020-07-17 00:57:33 -0500969 stream << "[Route]\n";
970 auto gateway = EthernetInterfaceIntf::defaultGateway();
971 if (!gateway.empty())
972 {
973 stream << "Gateway=" << gateway << "\n";
974 }
975
976 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
977 if (!gateway6.empty())
978 {
979 stream << "Gateway=" << gateway6 << "\n";
980 }
981
Johnathan Mantey817012a2020-01-30 15:07:39 -0800982 if (manager.getSystemConf())
983 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800984 const auto& gateway = manager.getSystemConf()->defaultGateway();
985 if (!gateway.empty())
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600986 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800987 stream << "Gateway=" << gateway << "\n";
988 }
989 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
990 if (!gateway6.empty())
991 {
992 stream << "Gateway=" << gateway6 << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600993 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530994 }
995
William A. Kennington III08505792019-01-30 16:00:04 -0800996 // Write the neighbor sections
997 for (const auto& neighbor : staticNeighbors)
998 {
999 stream << "[Neighbor]"
1000 << "\n";
1001 stream << "Address=" << neighbor.second->iPAddress() << "\n";
1002 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
1003 }
1004
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001005 // Write the dhcp section irrespective of whether DHCP is enabled or not
1006 writeDHCPSection(stream);
1007
Ratan Gupta2b106532017-07-25 16:05:02 +05301008 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +05301009}
1010
1011void EthernetInterface::writeDHCPSection(std::fstream& stream)
1012{
1013 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301014 // write the dhcp section
1015 stream << "[DHCP]\n";
1016
1017 // Hardcoding the client identifier to mac, to address below issue
1018 // https://github.com/openbmc/openbmc/issues/1280
1019 stream << "ClientIdentifier=mac\n";
1020 if (manager.getDHCPConf())
1021 {
1022 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
1023 stream << "UseDNS="s + value + "\n";
1024
1025 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
1026 stream << "UseNTP="s + value + "\n";
1027
1028 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1029 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001030
1031 value =
1032 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1033 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301034 }
1035}
1036
Ratan Guptabd303b12017-08-18 17:10:07 +05301037std::string EthernetInterface::mACAddress(std::string value)
1038{
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001039 ether_addr newMAC;
1040 try
1041 {
1042 newMAC = mac_address::fromString(value);
1043 }
1044 catch (std::invalid_argument&)
1045 {
1046 log<level::ERR>("MACAddress is not valid.",
1047 entry("MAC=%s", value.c_str()));
1048 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1049 Argument::ARGUMENT_VALUE(value.c_str()));
1050 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001051 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301052 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001053 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001054 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001055 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1056 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301057 }
1058
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001059 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001060 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001061
William A. Kennington III1137a972019-04-20 20:49:58 -07001062 // We don't need to update the system if the address is unchanged
1063 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001064 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301065 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001066 // Update everything that depends on the MAC value
1067 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301068 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001069 intf->MacAddressIntf::mACAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301070 }
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001071 MacAddressIntf::mACAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301072
William A. Kennington III15787212019-04-23 19:18:01 -07001073 // TODO: would remove the call below and
1074 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -07001075 // through https://github.com/systemd/systemd/issues/6696
1076 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
1077 "down");
William A. Kennington III15787212019-04-23 19:18:01 -07001078 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +05301079 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001080
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001081#ifdef HAVE_UBOOT_ENV
1082 // Ensure that the valid address is stored in the u-boot-env
1083 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1084 if (envVar)
1085 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001086 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1087 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1088 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1089 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001090 }
1091#endif // HAVE_UBOOT_ENV
1092
William A. Kennington III1137a972019-04-20 20:49:58 -07001093 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301094}
1095
Ratan Guptae9c9b812017-09-22 17:15:37 +05301096void EthernetInterface::deleteAll()
1097{
Johnathan Mantey817012a2020-01-30 15:07:39 -08001098 if (dhcpIsEnabled(IP::Protocol::IPv4, true))
Ratan Guptae9c9b812017-09-22 17:15:37 +05301099 {
1100 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001101 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301102 }
1103
1104 // clear all the ip on the interface
1105 addrs.clear();
1106 manager.writeToConfigurationFile();
1107}
1108
Ravi Tejaa5a09442020-07-17 00:57:33 -05001109std::string EthernetInterface::defaultGateway(std::string gateway)
1110{
1111 auto gw = EthernetInterfaceIntf::defaultGateway();
1112 if (gw == gateway)
1113 {
1114 return gw;
1115 }
1116
1117 if (!isValidIP(AF_INET, gateway))
1118 {
1119 log<level::ERR>("Not a valid v4 Gateway",
1120 entry("GATEWAY=%s", gateway.c_str()));
1121 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1122 Argument::ARGUMENT_VALUE(gateway.c_str()));
1123 }
1124 gw = EthernetInterfaceIntf::defaultGateway(gateway);
1125 manager.writeToConfigurationFile();
1126 return gw;
1127}
1128
1129std::string EthernetInterface::defaultGateway6(std::string gateway)
1130{
1131 auto gw = EthernetInterfaceIntf::defaultGateway6();
1132 if (gw == gateway)
1133 {
1134 return gw;
1135 }
1136
1137 if (!isValidIP(AF_INET6, gateway))
1138 {
1139 log<level::ERR>("Not a valid v6 Gateway",
1140 entry("GATEWAY=%s", gateway.c_str()));
1141 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1142 Argument::ARGUMENT_VALUE(gateway.c_str()));
1143 }
1144 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
1145 manager.writeToConfigurationFile();
1146 return gw;
1147}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001148} // namespace network
1149} // namespace phosphor