blob: eddcb7b26f834cdf118584afe388034037af3417 [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"
Ratan Gupta2b106532017-07-25 16:05:02 +05308#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05309
Ratan Gupta82549cc2017-04-21 08:45:23 +053010#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053011#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070012#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053013#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053014#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053015#include <netinet/in.h>
16#include <sys/ioctl.h>
17#include <sys/socket.h>
18#include <unistd.h>
19
Ratan Gupta82549cc2017-04-21 08:45:23 +053020#include <algorithm>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053021#include <filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053022#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070023#include <phosphor-logging/elog-errors.hpp>
24#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053025#include <sstream>
William A. Kennington III12beaad2020-06-13 19:30:41 -070026#include <stdplus/raw.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053027#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070028#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070029#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053030
Ratan Gupta91a99cc2017-04-14 16:32:09 +053031namespace phosphor
32{
33namespace network
34{
35
36using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053037using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053038using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
39using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050040using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053041constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
42constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
43constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
44constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
45constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053046
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080047struct EthernetIntfSocket
48{
49 EthernetIntfSocket(int domain, int type, int protocol)
50 {
51 if ((sock = socket(domain, type, protocol)) < 0)
52 {
53 log<level::ERR>("socket creation failed:",
54 entry("ERROR=%s", strerror(errno)));
55 }
56 }
57
58 ~EthernetIntfSocket()
59 {
60 if (sock >= 0)
61 {
62 close(sock);
63 }
64 }
65
66 int sock{-1};
67};
68
Johnathan Mantey817012a2020-01-30 15:07:39 -080069std::map<EthernetInterface::DHCPConf, std::string> mapDHCPToSystemd = {
70 {EthernetInterface::DHCPConf::both, "true"},
71 {EthernetInterface::DHCPConf::v4, "ipv4"},
72 {EthernetInterface::DHCPConf::v6, "ipv6"},
73 {EthernetInterface::DHCPConf::none, "false"}};
74
Ratan Gupta91a99cc2017-04-14 16:32:09 +053075EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
76 const std::string& objPath,
Johnathan Mantey817012a2020-01-30 15:07:39 -080077 DHCPConf dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053078 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050079 Ifaces(bus, objPath.c_str(), true),
80 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053081{
82 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053083 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053084 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053085 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Johnathan Mantey5b023f52019-06-24 16:06:37 -070086 EthernetInterfaceIntf::iPv6AcceptRA(getIPv6AcceptRAFromConf());
Ratan Gupta99801ce2020-01-09 18:37:16 +053087 // Don't get the mac address from the system as the mac address
88 // would be same as parent interface.
89 if (intfName.find(".") == std::string::npos)
90 {
91 MacAddressIntf::mACAddress(getMACAddress(intfName));
92 }
Ratan Gupta497c0c92017-08-22 19:15:59 +053093 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +053094
95 EthernetInterfaceIntf::linkUp(linkUp());
96 EthernetInterfaceIntf::nICEnabled(nICEnabled());
97
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -080098#if NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -070099 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
100
101 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
102 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800103#endif
Ratan Gupta6dec3902017-08-20 15:28:12 +0530104
Ratan Gupta29b0e432017-05-25 12:51:40 +0530105 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530106 if (emitSignal)
107 {
108 this->emit_object_added();
109 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530110}
111
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800112static IP::Protocol convertFamily(int family)
113{
114 switch (family)
115 {
116 case AF_INET:
117 return IP::Protocol::IPv4;
118 case AF_INET6:
119 return IP::Protocol::IPv6;
120 }
121
122 throw std::invalid_argument("Bad address family");
123}
124
Johnathan Mantey817012a2020-01-30 15:07:39 -0800125void EthernetInterface::disableDHCP(IP::Protocol protocol)
126{
127 DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled();
128 if (dhcpState == EthernetInterface::DHCPConf::both)
129 {
130 if (protocol == IP::Protocol::IPv4)
131 {
132 dHCPEnabled(EthernetInterface::DHCPConf::v6);
133 }
134 else if (protocol == IP::Protocol::IPv6)
135 {
136 dHCPEnabled(EthernetInterface::DHCPConf::v4);
137 }
138 }
139 else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
140 (protocol == IP::Protocol::IPv4))
141 {
142 dHCPEnabled(EthernetInterface::DHCPConf::none);
143 }
144 else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
145 (protocol == IP::Protocol::IPv6))
146 {
147 dHCPEnabled(EthernetInterface::DHCPConf::none);
148 }
149}
150
151bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol)
152{
153 return ((EthernetInterfaceIntf::dHCPEnabled() ==
154 EthernetInterface::DHCPConf::both) ||
155 ((EthernetInterfaceIntf::dHCPEnabled() ==
156 EthernetInterface::DHCPConf::v6) &&
157 ((family == IP::Protocol::IPv6) || ignoreProtocol)) ||
158 ((EthernetInterfaceIntf::dHCPEnabled() ==
159 EthernetInterface::DHCPConf::v4) &&
160 ((family == IP::Protocol::IPv4) || ignoreProtocol)));
161}
162
163bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family,
164 const std::string& nextDHCPState)
165{
166 return ((nextDHCPState == "true") ||
167 ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) ||
168 ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4)));
169}
170
171bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin)
172{
173 return (
174#ifdef LINK_LOCAL_AUTOCONFIGURATION
175 (origin == IP::AddressOrigin::Static)
176#else
177 (origin == IP::AddressOrigin::Static ||
178 origin == IP::AddressOrigin::LinkLocal)
179#endif
180
181 );
182}
183
Ratan Gupta87c13982017-06-15 09:27:27 +0530184void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530185{
Ratan Gupta87c13982017-06-15 09:27:27 +0530186 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530187
Ratan Gupta87c13982017-06-15 09:27:27 +0530188 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530189
Ratan Gupta6a387c12017-08-03 13:26:19 +0530190 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530191 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800192 IP::Protocol addressType = convertFamily(addr.addrType);
193 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800194 if (dhcpIsEnabled(addressType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530195 {
196 origin = IP::AddressOrigin::DHCP;
197 }
William A. Kennington III16893802019-01-30 16:01:01 -0800198 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530199 {
200 origin = IP::AddressOrigin::LinkLocal;
201 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700202 // Obsolete parameter
203 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530204
Gunnar Mills57d9c502018-09-14 14:42:34 -0500205 std::string ipAddressObjectPath = generateObjectPath(
206 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530207
Gunnar Mills57d9c502018-09-14 14:42:34 -0500208 this->addrs.emplace(addr.ipaddress,
209 std::make_shared<phosphor::network::IPAddress>(
210 bus, ipAddressObjectPath.c_str(), *this,
211 addressType, addr.ipaddress, origin,
212 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530213 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530214}
215
William A. Kennington III08505792019-01-30 16:00:04 -0800216void EthernetInterface::createStaticNeighborObjects()
217{
218 staticNeighbors.clear();
219
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700220 NeighborFilter filter;
221 filter.interface = ifIndex();
222 filter.state = NUD_PERMANENT;
223 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800224 for (const auto& neighbor : neighbors)
225 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700226 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800227 {
228 continue;
229 }
230 std::string ip = toString(neighbor.address);
231 std::string mac = mac_address::toString(*neighbor.mac);
232 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
233 staticNeighbors.emplace(ip,
234 std::make_shared<phosphor::network::Neighbor>(
235 bus, objectPath.c_str(), *this, ip, mac,
236 Neighbor::State::Permanent));
237 }
238}
239
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700240unsigned EthernetInterface::ifIndex() const
241{
242 unsigned idx = if_nametoindex(interfaceName().c_str());
243 if (idx == 0)
244 {
245 throw std::system_error(errno, std::generic_category(),
246 "if_nametoindex");
247 }
248 return idx;
249}
250
raviteja-bce379562019-03-28 05:59:36 -0500251ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
252 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530253{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530254
Johnathan Mantey817012a2020-01-30 15:07:39 -0800255 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530256 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530257 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500258 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800259 disableDHCP(protType);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500260 }
261
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500262 IP::AddressOrigin origin = IP::AddressOrigin::Static;
263
264 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
265
266 if (!isValidIP(addressFamily, ipaddress))
267 {
268 log<level::ERR>("Not a valid IP address"),
269 entry("ADDRESS=%s", ipaddress.c_str());
270 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
271 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
272 }
273
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700274 // Gateway is an obsolete parameter
275 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500276
277 if (!isValidPrefix(addressFamily, prefixLength))
278 {
279 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700280 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500281 elog<InvalidArgument>(
282 Argument::ARGUMENT_NAME("prefixLength"),
283 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530284 }
285
Gunnar Mills57d9c502018-09-14 14:42:34 -0500286 std::string objectPath =
287 generateObjectPath(protType, ipaddress, prefixLength, gateway);
288 this->addrs.emplace(ipaddress,
289 std::make_shared<phosphor::network::IPAddress>(
290 bus, objectPath.c_str(), *this, protType, ipaddress,
291 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530292
Ratan Guptae05083a2017-09-16 07:12:11 +0530293 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500294 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530295}
296
William A. Kennington III08505792019-01-30 16:00:04 -0800297ObjectPath EthernetInterface::neighbor(std::string iPAddress,
298 std::string mACAddress)
299{
300 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
301 {
302 log<level::ERR>("Not a valid IP address",
303 entry("ADDRESS=%s", iPAddress.c_str()));
304 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
305 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
306 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700307 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800308 {
309 log<level::ERR>("Not a valid MAC address",
310 entry("MACADDRESS=%s", iPAddress.c_str()));
311 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
312 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
313 }
314
315 std::string objectPath =
316 generateStaticNeighborObjectPath(iPAddress, mACAddress);
317 staticNeighbors.emplace(iPAddress,
318 std::make_shared<phosphor::network::Neighbor>(
319 bus, objectPath.c_str(), *this, iPAddress,
320 mACAddress, Neighbor::State::Permanent));
321 manager.writeToConfigurationFile();
322 return objectPath;
323}
324
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800325#if NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530326/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800327 Enable this code if your NIC driver supports the ETHTOOL features.
328 Do this by adding the following to your phosphor-network*.bbappend file.
329 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
330 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530331*/
332InterfaceInfo EthernetInterface::getInterfaceInfo() const
333{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400334 ifreq ifr{0};
335 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500336 LinkSpeed speed{0};
337 Autoneg autoneg{0};
338 DuplexMode duplex{0};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800339 LinkUp linkState{false};
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700340 NICEnabled nicEnabled{false};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800341 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
342
343 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530344 {
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700345 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800346 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530347
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800348 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
349 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530350
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800351 edata.cmd = ETHTOOL_GSET;
352 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
353 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530354 speed = edata.speed;
355 duplex = edata.duplex;
356 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530357 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800358
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700359 nicEnabled = nICEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800360 linkState = linkUp();
361
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700362 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530363}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800364#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530365
366/** @brief get the mac address of the interface.
367 * @return macaddress on success
368 */
369
Gunnar Mills57d9c502018-09-14 14:42:34 -0500370std::string
371 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530372{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800373 std::string activeMACAddr = MacAddressIntf::mACAddress();
374 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
375
376 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530377 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800378 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530379 }
380
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800381 ifreq ifr{0};
382 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
383 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530384 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530385 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500386 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700387 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530388 }
389
William A. Kennington III1137a972019-04-20 20:49:58 -0700390 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
391 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
392 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700393 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530394}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530395
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530396std::string EthernetInterface::generateId(const std::string& ipaddress,
397 uint8_t prefixLength,
398 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530399{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530400 std::stringstream hexId;
401 std::string hashString = ipaddress;
402 hashString += std::to_string(prefixLength);
403 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530404
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530405 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500406 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530407 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530408}
409
William A. Kennington III08505792019-01-30 16:00:04 -0800410std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
411 const std::string& mACAddress)
412{
413 std::stringstream hexId;
414 std::string hashString = iPAddress + mACAddress;
415
416 // Only want 8 hex digits.
417 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
418 return hexId.str();
419}
420
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530421void EthernetInterface::deleteObject(const std::string& ipaddress)
422{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530423 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530424 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530425 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530426 log<level::ERR>("DeleteObject:Unable to find the object.");
427 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530428 }
429 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530430 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530431}
432
William A. Kennington III08505792019-01-30 16:00:04 -0800433void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
434{
435 auto it = staticNeighbors.find(iPAddress);
436 if (it == staticNeighbors.end())
437 {
438 log<level::ERR>(
439 "DeleteStaticNeighborObject:Unable to find the object.");
440 return;
441 }
442 staticNeighbors.erase(it);
443 manager.writeToConfigurationFile();
444}
445
Ratan Guptae9c9b812017-09-22 17:15:37 +0530446void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530447{
Ratan Guptabc886292017-07-25 18:29:57 +0530448 auto confDir = manager.getConfDir();
449 fs::path networkFile = confDir;
450 networkFile /= systemd::config::networkFilePrefix + interface +
451 systemd::config::networkFileSuffix;
452
453 fs::path deviceFile = confDir;
454 deviceFile /= interface + systemd::config::deviceFileSuffix;
455
456 // delete the vlan network file
457 if (fs::is_regular_file(networkFile))
458 {
459 fs::remove(networkFile);
460 }
461
462 // delete the vlan device file
463 if (fs::is_regular_file(deviceFile))
464 {
465 fs::remove(deviceFile);
466 }
Ratan Guptabc886292017-07-25 18:29:57 +0530467
468 // TODO systemd doesn't delete the virtual network interface
469 // even after deleting all the related configuartion.
470 // https://github.com/systemd/systemd/issues/6600
471 try
472 {
473 deleteInterface(interface);
474 }
475 catch (InternalFailure& e)
476 {
477 commit<InternalFailure>();
478 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530479}
480
481void EthernetInterface::deleteVLANObject(const std::string& interface)
482{
483 auto it = vlanInterfaces.find(interface);
484 if (it == vlanInterfaces.end())
485 {
486 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500487 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530488 return;
489 }
490
491 deleteVLANFromSystem(interface);
492 // delete the interface
493 vlanInterfaces.erase(it);
494
Ratan Guptae05083a2017-09-16 07:12:11 +0530495 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530496}
497
Gunnar Mills57d9c502018-09-14 14:42:34 -0500498std::string EthernetInterface::generateObjectPath(
499 IP::Protocol addressType, const std::string& ipaddress,
500 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530501{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530502 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530503 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530504 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
505
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530506 std::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530507 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530508 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530509 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530510 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530511}
512
William A. Kennington III08505792019-01-30 16:00:04 -0800513std::string EthernetInterface::generateStaticNeighborObjectPath(
514 const std::string& iPAddress, const std::string& mACAddress) const
515{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530516 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800517 objectPath /= objPath;
518 objectPath /= "static_neighbor";
519 objectPath /= generateNeighborId(iPAddress, mACAddress);
520 return objectPath.string();
521}
522
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700523bool EthernetInterface::iPv6AcceptRA(bool value)
524{
525 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
526 {
527 return value;
528 }
529 EthernetInterfaceIntf::iPv6AcceptRA(value);
530 manager.writeToConfigurationFile();
531 return value;
532}
533
Johnathan Mantey817012a2020-01-30 15:07:39 -0800534EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530535{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530536 if (value == EthernetInterfaceIntf::dHCPEnabled())
537 {
538 return value;
539 }
540
Ratan Gupta87c13982017-06-15 09:27:27 +0530541 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530542 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530543 return value;
544}
545
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800546bool EthernetInterface::linkUp() const
547{
548 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
549 bool value = EthernetInterfaceIntf::linkUp();
550
551 if (eifSocket.sock < 0)
552 {
553 return value;
554 }
555
556 ifreq ifr{0};
557 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
558 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
559 {
560 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
561 }
562 else
563 {
564 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
565 entry("ERROR=%s", strerror(errno)));
566 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700567 return value;
568}
569
570bool EthernetInterface::nICEnabled() const
571{
572 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
573 bool value = EthernetInterfaceIntf::nICEnabled();
574
575 if (eifSocket.sock < 0)
576 {
577 return value;
578 }
579
580 ifreq ifr{0};
581 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
582 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
583 {
584 value = static_cast<bool>(ifr.ifr_flags & IFF_UP);
585 }
586 else
587 {
588 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
589 entry("ERROR=%s", strerror(errno)));
590 }
591 return value;
592}
593
594bool EthernetInterface::nICEnabled(bool value)
595{
596 if (value == EthernetInterfaceIntf::nICEnabled())
597 {
598 return value;
599 }
600
601 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
602 if (eifSocket.sock < 0)
603 {
604 return EthernetInterfaceIntf::nICEnabled();
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 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
612 entry("ERROR=%s", strerror(errno)));
613 return EthernetInterfaceIntf::nICEnabled();
614 }
615
616 ifr.ifr_flags &= ~IFF_UP;
617 ifr.ifr_flags |= value ? IFF_UP : 0;
618
619 if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
620 {
621 log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
622 entry("ERROR=%s", strerror(errno)));
623 return EthernetInterfaceIntf::nICEnabled();
624 }
625 EthernetInterfaceIntf::nICEnabled(value);
626 writeConfigurationFile();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800627
628 return value;
629}
630
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530631ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530632{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530633 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
634 return EthernetInterfaceIntf::nameservers();
635}
636
637ServerList EthernetInterface::staticNameServers(ServerList value)
638{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530639 for (const auto& nameserverip : value)
640 {
641 if (!isValidIP(AF_INET, nameserverip) &&
642 !isValidIP(AF_INET6, nameserverip))
643 {
644 log<level::ERR>("Not a valid IP address"),
645 entry("ADDRESS=%s", nameserverip.c_str());
646 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530647 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530648 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
649 }
650 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530651 try
652 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530653 EthernetInterfaceIntf::staticNameServers(value);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530654 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530655 // resolved reads the DNS server configuration from the
656 // network file.
657 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530658 }
659 catch (InternalFailure& e)
660 {
661 log<level::ERR>("Exception processing DNS entries");
662 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530663 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530664}
665
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530666void EthernetInterface::loadNameServers()
667{
668 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
669 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
670}
671
672ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec3902017-08-20 15:28:12 +0530673{
674 fs::path confPath = manager.getConfDir();
675
676 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500677 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530678 confPath /= fileName;
679 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530680 config::Parser parser(confPath.string());
681 auto rc = config::ReturnCode::SUCCESS;
682
683 std::tie(rc, servers) = parser.getValues("Network", "DNS");
684 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530685 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530686 log<level::DEBUG>("Unable to get the value for network[DNS]",
687 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530688 }
689 return servers;
690}
691
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530692ServerList EthernetInterface::getNameServerFromResolvd()
693{
694 ServerList servers;
695 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
696
697 /*
698 The DNS property under org.freedesktop.resolve1.Link interface contains
699 an array containing all DNS servers currently used by resolved. It
700 contains similar information as the DNS server data written to
701 /run/systemd/resolve/resolv.conf.
702
703 Each structure in the array consists of a numeric network interface index,
704 an address family, and a byte array containing the DNS server address
705 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
706 The array contains DNS servers configured system-wide, including those
707 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
708 /etc/systemd/resolved.conf, as well as per-interface DNS server
709 information either retrieved from systemd-networkd or configured by
710 external software via SetLinkDNS().
711 */
712
713 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
714 std::variant<type> name; // Variable to capture the DNS property
715 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
716 PROPERTY_INTERFACE, METHOD_GET);
717
718 method.append(RESOLVED_INTERFACE, "DNS");
719 auto reply = bus.call(method);
720
721 try
722 {
723 reply.read(name);
724 }
725 catch (const sdbusplus::exception::SdBusError& e)
726 {
727 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
728 }
729 auto tupleVector = std::get_if<type>(&name);
730 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
731 {
732 std::vector<uint8_t> ipaddress = std::get<1>(*i);
733 std::string address;
734 for (auto byte : ipaddress)
735 {
736 address += std::to_string(byte) + ".";
737 }
738 address.pop_back();
739 servers.push_back(address);
740 }
741 return servers;
742}
743
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530744void EthernetInterface::loadVLAN(VlanId id)
745{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500746 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530747 std::string path = objPath;
748 path += "_" + std::to_string(id);
749
Johnathan Mantey817012a2020-01-30 15:07:39 -0800750 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500751 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530752 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800753 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nICEnabled(), id,
754 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530755
Gunnar Mills57d9c502018-09-14 14:42:34 -0500756 // Fetch the ip address from the system
757 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530758 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800759 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530760
761 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
762 std::move(vlanIntf));
763}
764
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700765ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530766{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500767 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530768 std::string path = objPath;
769 path += "_" + std::to_string(id);
770
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530771 // Pass the parents nICEnabled property, so that the child
772 // VLAN interface can inherit.
773
Ratan Gupta5978dd12017-07-25 13:47:13 +0530774 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800775 bus, path.c_str(), EthernetInterface::DHCPConf::none,
776 EthernetInterfaceIntf::nICEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530777
778 // write the device file for the vlan interface.
779 vlanIntf->writeDeviceFile();
780
Gunnar Mills57d9c502018-09-14 14:42:34 -0500781 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530782 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530783 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700784
785 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530786}
Ratan Gupta2b106532017-07-25 16:05:02 +0530787
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700788bool EthernetInterface::getIPv6AcceptRAFromConf()
789{
790 fs::path confPath = manager.getConfDir();
791
792 std::string fileName = systemd::config::networkFilePrefix +
793 interfaceName() + systemd::config::networkFileSuffix;
794 confPath /= fileName;
795 config::ValueList values;
796 config::Parser parser(confPath.string());
797 auto rc = config::ReturnCode::SUCCESS;
798 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
799 if (rc != config::ReturnCode::SUCCESS)
800 {
801 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
802 entry("rc=%d", rc));
803 return false;
804 }
805 return (values[0] == "true");
806}
807
Ratan Gupta497c0c92017-08-22 19:15:59 +0530808ServerList EthernetInterface::getNTPServersFromConf()
809{
810 fs::path confPath = manager.getConfDir();
811
Gunnar Mills57d9c502018-09-14 14:42:34 -0500812 std::string fileName = systemd::config::networkFilePrefix +
813 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530814 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530815
Ratan Gupta497c0c92017-08-22 19:15:59 +0530816 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530817 config::Parser parser(confPath.string());
818 auto rc = config::ReturnCode::SUCCESS;
819
820 std::tie(rc, servers) = parser.getValues("Network", "NTP");
821 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530822 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530823 log<level::DEBUG>("Unable to get the value for Network[NTP]",
824 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530825 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530826
Ratan Gupta497c0c92017-08-22 19:15:59 +0530827 return servers;
828}
829
830ServerList EthernetInterface::nTPServers(ServerList servers)
831{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500832 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530833
834 writeConfigurationFile();
835 // timesynchd reads the NTP server configuration from the
836 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530837 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530838 return ntpServers;
839}
Ratan Gupta2b106532017-07-25 16:05:02 +0530840// Need to merge the below function with the code which writes the
841// config file during factory reset.
842// TODO openbmc/openbmc#1751
843
844void EthernetInterface::writeConfigurationFile()
845{
846 // write all the static ip address in the systemd-network conf file
847
848 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530849 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530850
851 // if there is vlan interafce then write the configuration file
852 // for vlan also.
853
Gunnar Mills57d9c502018-09-14 14:42:34 -0500854 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530855 {
856 intf.second->writeConfigurationFile();
857 }
858
Ratan Gupta2b106532017-07-25 16:05:02 +0530859 fs::path confPath = manager.getConfDir();
860
Gunnar Mills57d9c502018-09-14 14:42:34 -0500861 std::string fileName = systemd::config::networkFilePrefix +
862 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530863 confPath /= fileName;
864 std::fstream stream;
865
866 stream.open(confPath.c_str(), std::fstream::out);
867 if (!stream.is_open())
868 {
869 log<level::ERR>("Unable to open the file",
870 entry("FILE=%s", confPath.c_str()));
871 elog<InternalFailure>();
872 }
873
874 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400875 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530876 stream << "Name=" << interfaceName() << "\n";
877
878 auto addrs = getAddresses();
879
William A. Kennington III15787212019-04-23 19:18:01 -0700880 // Write the link section
881 stream << "[Link]\n";
882 auto mac = MacAddressIntf::mACAddress();
883 if (!mac.empty())
884 {
885 stream << "MACAddress=" << mac << "\n";
886 }
887
Ratan Gupta40a51df2020-04-24 15:11:05 +0530888 if (!EthernetInterfaceIntf::nICEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700889 {
890 stream << "Unmanaged=yes\n";
891 }
892
Ratan Gupta2b106532017-07-25 16:05:02 +0530893 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400894 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400895#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500896 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400897#else
898 stream << "LinkLocalAddressing=no\n";
899#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700900 stream << std::boolalpha
901 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530902
903 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500904 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530905 {
906 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500907 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530908 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530909 // Add the NTP server
910 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
911 {
912 stream << "NTP=" << ntp << "\n";
913 }
914
915 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530916 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530917 {
918 stream << "DNS=" << dns << "\n";
919 }
920
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500921 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -0800922 stream << "DHCP="s +
923 mapDHCPToSystemd[EthernetInterfaceIntf::dHCPEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500924
Johnathan Mantey817012a2020-01-30 15:07:39 -0800925 // Static IP addresses
926 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +0530927 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800928 if (originIsManuallyAssigned(addr.second->origin()) &&
929 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600930 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800931 // Process all static addresses
932 std::string address = addr.second->address() + "/" +
933 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530934
Johnathan Mantey817012a2020-01-30 15:07:39 -0800935 // build the address entries. Do not use [Network] shortcuts to
936 // insert address entries.
937 stream << "[Address]\n";
938 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600939 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800940 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600941
Johnathan Mantey817012a2020-01-30 15:07:39 -0800942 if (manager.getSystemConf())
943 {
944 stream << "[Route]\n";
945 const auto& gateway = manager.getSystemConf()->defaultGateway();
946 if (!gateway.empty())
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600947 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800948 stream << "Gateway=" << gateway << "\n";
949 }
950 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
951 if (!gateway6.empty())
952 {
953 stream << "Gateway=" << gateway6 << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600954 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530955 }
956
William A. Kennington III08505792019-01-30 16:00:04 -0800957 // Write the neighbor sections
958 for (const auto& neighbor : staticNeighbors)
959 {
960 stream << "[Neighbor]"
961 << "\n";
962 stream << "Address=" << neighbor.second->iPAddress() << "\n";
963 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
964 }
965
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600966 // Write the dhcp section irrespective of whether DHCP is enabled or not
967 writeDHCPSection(stream);
968
Ratan Gupta2b106532017-07-25 16:05:02 +0530969 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530970}
971
972void EthernetInterface::writeDHCPSection(std::fstream& stream)
973{
974 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530975 // write the dhcp section
976 stream << "[DHCP]\n";
977
978 // Hardcoding the client identifier to mac, to address below issue
979 // https://github.com/openbmc/openbmc/issues/1280
980 stream << "ClientIdentifier=mac\n";
981 if (manager.getDHCPConf())
982 {
983 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
984 stream << "UseDNS="s + value + "\n";
985
986 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
987 stream << "UseNTP="s + value + "\n";
988
989 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
990 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600991
992 value =
993 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
994 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530995 }
996}
997
Ratan Guptabd303b12017-08-18 17:10:07 +0530998std::string EthernetInterface::mACAddress(std::string value)
999{
William A. Kennington III1137a972019-04-20 20:49:58 -07001000 ether_addr newMAC = mac_address::fromString(value);
1001 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301002 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001003 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001004 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001005 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1006 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301007 }
1008
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001009 auto interface = interfaceName();
1010
William A. Kennington III1137a972019-04-20 20:49:58 -07001011 // We don't need to update the system if the address is unchanged
1012 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001013 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301014 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001015 // Update everything that depends on the MAC value
1016 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301017 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001018 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +05301019 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001020 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +05301021
William A. Kennington III15787212019-04-23 19:18:01 -07001022 // TODO: would remove the call below and
1023 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -07001024 // through https://github.com/systemd/systemd/issues/6696
1025 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
1026 "down");
William A. Kennington III15787212019-04-23 19:18:01 -07001027 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +05301028 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001029
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001030#ifdef HAVE_UBOOT_ENV
1031 // Ensure that the valid address is stored in the u-boot-env
1032 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1033 if (envVar)
1034 {
1035 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(), value.c_str());
1036 }
1037#endif // HAVE_UBOOT_ENV
1038
William A. Kennington III1137a972019-04-20 20:49:58 -07001039 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301040}
1041
Ratan Guptae9c9b812017-09-22 17:15:37 +05301042void EthernetInterface::deleteAll()
1043{
Johnathan Mantey817012a2020-01-30 15:07:39 -08001044 if (dhcpIsEnabled(IP::Protocol::IPv4, true))
Ratan Guptae9c9b812017-09-22 17:15:37 +05301045 {
1046 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001047 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301048 }
1049
1050 // clear all the ip on the interface
1051 addrs.clear();
1052 manager.writeToConfigurationFile();
1053}
1054
Gunnar Mills57d9c502018-09-14 14:42:34 -05001055} // namespace network
1056} // namespace phosphor