blob: ce424ff8211cdbc63b82a13cdc49c4d786593d08 [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);
Patrick Williams6aef7692021-05-01 06:39:41 -050086 EthernetInterfaceIntf::dhcpEnabled(dhcpEnabled);
87 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 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500118 MacAddressIntf::macAddress(getMACAddress(intfName));
Ratan Gupta99801ce2020-01-09 18:37:16 +0530119 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500120 EthernetInterfaceIntf::ntpServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +0530121
122 EthernetInterfaceIntf::linkUp(linkUp());
Patrick Williams6aef7692021-05-01 06:39:41 -0500123 EthernetInterfaceIntf::nicEnabled(nicEnabled());
Ratan Gupta613a0122020-04-24 15:18:53 +0530124
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700125#ifdef 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{
Patrick Williams6aef7692021-05-01 06:39:41 -0500154 DHCPConf dhcpState = EthernetInterfaceIntf::dhcpEnabled();
Johnathan Mantey817012a2020-01-30 15:07:39 -0800155 if (dhcpState == EthernetInterface::DHCPConf::both)
156 {
157 if (protocol == IP::Protocol::IPv4)
158 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500159 dhcpEnabled(EthernetInterface::DHCPConf::v6);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800160 }
161 else if (protocol == IP::Protocol::IPv6)
162 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500163 dhcpEnabled(EthernetInterface::DHCPConf::v4);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800164 }
165 }
166 else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
167 (protocol == IP::Protocol::IPv4))
168 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500169 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800170 }
171 else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
172 (protocol == IP::Protocol::IPv6))
173 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500174 dhcpEnabled(EthernetInterface::DHCPConf::none);
Johnathan Mantey817012a2020-01-30 15:07:39 -0800175 }
176}
177
178bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol)
179{
Patrick Williams6aef7692021-05-01 06:39:41 -0500180 return ((EthernetInterfaceIntf::dhcpEnabled() ==
Johnathan Mantey817012a2020-01-30 15:07:39 -0800181 EthernetInterface::DHCPConf::both) ||
Patrick Williams6aef7692021-05-01 06:39:41 -0500182 ((EthernetInterfaceIntf::dhcpEnabled() ==
Johnathan Mantey817012a2020-01-30 15:07:39 -0800183 EthernetInterface::DHCPConf::v6) &&
184 ((family == IP::Protocol::IPv6) || ignoreProtocol)) ||
Patrick Williams6aef7692021-05-01 06:39:41 -0500185 ((EthernetInterfaceIntf::dhcpEnabled() ==
Johnathan Mantey817012a2020-01-30 15:07:39 -0800186 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
Lei YU7233c582021-04-08 14:39:43 +0800235 this->addrs.insert_or_assign(
236 addr.ipaddress,
237 std::make_shared<phosphor::network::IPAddress>(
238 bus, ipAddressObjectPath.c_str(), *this, addressType,
239 addr.ipaddress, origin, 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
Patrick Williams6aef7692021-05-01 06:39:41 -0500278ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
raviteja-bce379562019-03-28 05:59:36 -0500279 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530280{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800281 if (dhcpIsEnabled(protType))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530282 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530283 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500284 entry("INTERFACE=%s", interfaceName().c_str());
Johnathan Mantey817012a2020-01-30 15:07:39 -0800285 disableDHCP(protType);
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500286 }
287
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500288 IP::AddressOrigin origin = IP::AddressOrigin::Static;
289
290 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
291
292 if (!isValidIP(addressFamily, ipaddress))
293 {
294 log<level::ERR>("Not a valid IP address"),
295 entry("ADDRESS=%s", ipaddress.c_str());
296 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
297 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
298 }
299
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700300 // Gateway is an obsolete parameter
301 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500302
303 if (!isValidPrefix(addressFamily, prefixLength))
304 {
305 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700306 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500307 elog<InvalidArgument>(
308 Argument::ARGUMENT_NAME("prefixLength"),
309 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530310 }
311
Gunnar Mills57d9c502018-09-14 14:42:34 -0500312 std::string objectPath =
313 generateObjectPath(protType, ipaddress, prefixLength, gateway);
Lei YU7233c582021-04-08 14:39:43 +0800314 this->addrs.insert_or_assign(ipaddress,
315 std::make_shared<phosphor::network::IPAddress>(
316 bus, objectPath.c_str(), *this, protType,
317 ipaddress, origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530318
Ratan Guptae05083a2017-09-16 07:12:11 +0530319 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500320 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530321}
322
Patrick Williams6aef7692021-05-01 06:39:41 -0500323ObjectPath EthernetInterface::neighbor(std::string ipAddress,
324 std::string macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800325{
Patrick Williams6aef7692021-05-01 06:39:41 -0500326 if (!isValidIP(AF_INET, ipAddress) && !isValidIP(AF_INET6, ipAddress))
William A. Kennington III08505792019-01-30 16:00:04 -0800327 {
328 log<level::ERR>("Not a valid IP address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500329 entry("ADDRESS=%s", ipAddress.c_str()));
330 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"),
331 Argument::ARGUMENT_VALUE(ipAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800332 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500333 if (!mac_address::isUnicast(mac_address::fromString(macAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800334 {
335 log<level::ERR>("Not a valid MAC address",
Patrick Williams6aef7692021-05-01 06:39:41 -0500336 entry("MACADDRESS=%s", ipAddress.c_str()));
337 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"),
338 Argument::ARGUMENT_VALUE(macAddress.c_str()));
William A. Kennington III08505792019-01-30 16:00:04 -0800339 }
340
341 std::string objectPath =
Patrick Williams6aef7692021-05-01 06:39:41 -0500342 generateStaticNeighborObjectPath(ipAddress, macAddress);
343 staticNeighbors.emplace(ipAddress,
William A. Kennington III08505792019-01-30 16:00:04 -0800344 std::make_shared<phosphor::network::Neighbor>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500345 bus, objectPath.c_str(), *this, ipAddress,
346 macAddress, Neighbor::State::Permanent));
William A. Kennington III08505792019-01-30 16:00:04 -0800347 manager.writeToConfigurationFile();
348 return objectPath;
349}
350
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700351#ifdef NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530352/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800353 Enable this code if your NIC driver supports the ETHTOOL features.
354 Do this by adding the following to your phosphor-network*.bbappend file.
355 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
356 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530357*/
358InterfaceInfo EthernetInterface::getInterfaceInfo() const
359{
William A. Kennington III05368f12021-05-13 18:40:47 -0700360 ifreq ifr = {};
361 ethtool_cmd edata = {};
362 LinkSpeed speed = {};
363 Autoneg autoneg = {};
364 DuplexMode duplex = {};
365 LinkUp linkState = {};
366 NICEnabled enabled = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800367 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
368
369 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530370 {
William A. Kennington III96203312021-05-07 12:50:41 -0700371 return std::make_tuple(speed, duplex, autoneg, linkState, enabled);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800372 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530373
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800374 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
375 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530376
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800377 edata.cmd = ETHTOOL_GSET;
378 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
379 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530380 speed = edata.speed;
381 duplex = edata.duplex;
382 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530383 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800384
William A. Kennington III96203312021-05-07 12:50:41 -0700385 enabled = nicEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800386 linkState = linkUp();
387
William A. Kennington III96203312021-05-07 12:50:41 -0700388 return std::make_tuple(speed, duplex, autoneg, linkState, enabled);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530389}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800390#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530391
392/** @brief get the mac address of the interface.
393 * @return macaddress on success
394 */
395
Gunnar Mills57d9c502018-09-14 14:42:34 -0500396std::string
397 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530398{
Patrick Williams6aef7692021-05-01 06:39:41 -0500399 std::string activeMACAddr = MacAddressIntf::macAddress();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800400 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
401
402 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530403 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800404 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530405 }
406
William A. Kennington III05368f12021-05-13 18:40:47 -0700407 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800408 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
409 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530410 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530411 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500412 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700413 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530414 }
415
William A. Kennington III1137a972019-04-20 20:49:58 -0700416 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
417 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
418 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700419 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530420}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530421
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530422std::string EthernetInterface::generateId(const std::string& ipaddress,
423 uint8_t prefixLength,
424 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530425{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530426 std::stringstream hexId;
427 std::string hashString = ipaddress;
428 hashString += std::to_string(prefixLength);
429 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530430
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530431 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500432 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530433 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530434}
435
Patrick Williams6aef7692021-05-01 06:39:41 -0500436std::string EthernetInterface::generateNeighborId(const std::string& ipAddress,
437 const std::string& macAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800438{
439 std::stringstream hexId;
Patrick Williams6aef7692021-05-01 06:39:41 -0500440 std::string hashString = ipAddress + macAddress;
William A. Kennington III08505792019-01-30 16:00:04 -0800441
442 // Only want 8 hex digits.
443 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
444 return hexId.str();
445}
446
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530447void EthernetInterface::deleteObject(const std::string& ipaddress)
448{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530449 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530450 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530451 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530452 log<level::ERR>("DeleteObject:Unable to find the object.");
453 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530454 }
455 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530456 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530457}
458
Patrick Williams6aef7692021-05-01 06:39:41 -0500459void EthernetInterface::deleteStaticNeighborObject(const std::string& ipAddress)
William A. Kennington III08505792019-01-30 16:00:04 -0800460{
Patrick Williams6aef7692021-05-01 06:39:41 -0500461 auto it = staticNeighbors.find(ipAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800462 if (it == staticNeighbors.end())
463 {
464 log<level::ERR>(
465 "DeleteStaticNeighborObject:Unable to find the object.");
466 return;
467 }
468 staticNeighbors.erase(it);
469 manager.writeToConfigurationFile();
470}
471
Ratan Guptae9c9b812017-09-22 17:15:37 +0530472void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530473{
Ratan Guptabc886292017-07-25 18:29:57 +0530474 auto confDir = manager.getConfDir();
475 fs::path networkFile = confDir;
476 networkFile /= systemd::config::networkFilePrefix + interface +
477 systemd::config::networkFileSuffix;
478
479 fs::path deviceFile = confDir;
480 deviceFile /= interface + systemd::config::deviceFileSuffix;
481
482 // delete the vlan network file
483 if (fs::is_regular_file(networkFile))
484 {
485 fs::remove(networkFile);
486 }
487
488 // delete the vlan device file
489 if (fs::is_regular_file(deviceFile))
490 {
491 fs::remove(deviceFile);
492 }
Ratan Guptabc886292017-07-25 18:29:57 +0530493
494 // TODO systemd doesn't delete the virtual network interface
495 // even after deleting all the related configuartion.
496 // https://github.com/systemd/systemd/issues/6600
497 try
498 {
499 deleteInterface(interface);
500 }
501 catch (InternalFailure& e)
502 {
503 commit<InternalFailure>();
504 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530505}
506
507void EthernetInterface::deleteVLANObject(const std::string& interface)
508{
509 auto it = vlanInterfaces.find(interface);
510 if (it == vlanInterfaces.end())
511 {
512 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500513 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530514 return;
515 }
516
517 deleteVLANFromSystem(interface);
518 // delete the interface
519 vlanInterfaces.erase(it);
520
Ratan Guptae05083a2017-09-16 07:12:11 +0530521 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530522}
523
Gunnar Mills57d9c502018-09-14 14:42:34 -0500524std::string EthernetInterface::generateObjectPath(
525 IP::Protocol addressType, const std::string& ipaddress,
526 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530527{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530528 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530529 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530530 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
531
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530532 std::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530533 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530534 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530535 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530536 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530537}
538
William A. Kennington III08505792019-01-30 16:00:04 -0800539std::string EthernetInterface::generateStaticNeighborObjectPath(
Patrick Williams6aef7692021-05-01 06:39:41 -0500540 const std::string& ipAddress, const std::string& macAddress) const
William A. Kennington III08505792019-01-30 16:00:04 -0800541{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530542 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800543 objectPath /= objPath;
544 objectPath /= "static_neighbor";
Patrick Williams6aef7692021-05-01 06:39:41 -0500545 objectPath /= generateNeighborId(ipAddress, macAddress);
William A. Kennington III08505792019-01-30 16:00:04 -0800546 return objectPath.string();
547}
548
Patrick Williams6aef7692021-05-01 06:39:41 -0500549bool EthernetInterface::ipv6AcceptRA(bool value)
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700550{
Patrick Williams6aef7692021-05-01 06:39:41 -0500551 if (value == EthernetInterfaceIntf::ipv6AcceptRA())
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700552 {
553 return value;
554 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500555 EthernetInterfaceIntf::ipv6AcceptRA(value);
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700556 manager.writeToConfigurationFile();
557 return value;
558}
559
Patrick Williams6aef7692021-05-01 06:39:41 -0500560EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value)
Ratan Gupta87c13982017-06-15 09:27:27 +0530561{
Patrick Williams6aef7692021-05-01 06:39:41 -0500562 if (value == EthernetInterfaceIntf::dhcpEnabled())
Ratan Gupta5978dd12017-07-25 13:47:13 +0530563 {
564 return value;
565 }
566
Patrick Williams6aef7692021-05-01 06:39:41 -0500567 EthernetInterfaceIntf::dhcpEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530568 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530569 return value;
570}
571
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800572bool EthernetInterface::linkUp() const
573{
574 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
575 bool value = EthernetInterfaceIntf::linkUp();
576
577 if (eifSocket.sock < 0)
578 {
579 return value;
580 }
581
William A. Kennington III05368f12021-05-13 18:40:47 -0700582 ifreq ifr = {};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800583 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
584 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
585 {
586 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
587 }
588 else
589 {
590 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
591 entry("ERROR=%s", strerror(errno)));
592 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700593 return value;
594}
595
Patrick Williams6aef7692021-05-01 06:39:41 -0500596bool EthernetInterface::nicEnabled() const
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700597{
598 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
Patrick Williams6aef7692021-05-01 06:39:41 -0500599 bool value = EthernetInterfaceIntf::nicEnabled();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700600
601 if (eifSocket.sock < 0)
602 {
603 return value;
604 }
605
William A. Kennington III05368f12021-05-13 18:40:47 -0700606 ifreq ifr = {};
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700607 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
608 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
609 {
610 value = static_cast<bool>(ifr.ifr_flags & IFF_UP);
611 }
612 else
613 {
614 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
615 entry("ERROR=%s", strerror(errno)));
616 }
617 return value;
618}
619
Patrick Williams6aef7692021-05-01 06:39:41 -0500620bool EthernetInterface::nicEnabled(bool value)
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700621{
Patrick Williams6aef7692021-05-01 06:39:41 -0500622 if (value == EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700623 {
624 return value;
625 }
626
627 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
628 if (eifSocket.sock < 0)
629 {
Patrick Williams6aef7692021-05-01 06:39:41 -0500630 return EthernetInterfaceIntf::nicEnabled();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700631 }
632
William A. Kennington III05368f12021-05-13 18:40:47 -0700633 ifreq ifr = {};
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700634 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
635 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) != 0)
636 {
637 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
638 entry("ERROR=%s", strerror(errno)));
Patrick Williams6aef7692021-05-01 06:39:41 -0500639 return EthernetInterfaceIntf::nicEnabled();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700640 }
641
642 ifr.ifr_flags &= ~IFF_UP;
643 ifr.ifr_flags |= value ? IFF_UP : 0;
644
645 if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
646 {
647 log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
648 entry("ERROR=%s", strerror(errno)));
Patrick Williams6aef7692021-05-01 06:39:41 -0500649 return EthernetInterfaceIntf::nicEnabled();
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700650 }
Patrick Williams6aef7692021-05-01 06:39:41 -0500651 EthernetInterfaceIntf::nicEnabled(value);
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700652 writeConfigurationFile();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800653
654 return value;
655}
656
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530657ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530658{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530659 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
660 return EthernetInterfaceIntf::nameservers();
661}
662
663ServerList EthernetInterface::staticNameServers(ServerList value)
664{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530665 for (const auto& nameserverip : value)
666 {
667 if (!isValidIP(AF_INET, nameserverip) &&
668 !isValidIP(AF_INET6, nameserverip))
669 {
670 log<level::ERR>("Not a valid IP address"),
671 entry("ADDRESS=%s", nameserverip.c_str());
672 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530673 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530674 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
675 }
676 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530677 try
678 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530679 EthernetInterfaceIntf::staticNameServers(value);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530680 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530681 // resolved reads the DNS server configuration from the
682 // network file.
683 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530684 }
685 catch (InternalFailure& e)
686 {
687 log<level::ERR>("Exception processing DNS entries");
688 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530689 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530690}
691
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530692void EthernetInterface::loadNameServers()
693{
694 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
695 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
696}
697
698ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec3902017-08-20 15:28:12 +0530699{
700 fs::path confPath = manager.getConfDir();
701
702 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500703 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530704 confPath /= fileName;
705 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530706 config::Parser parser(confPath.string());
707 auto rc = config::ReturnCode::SUCCESS;
708
709 std::tie(rc, servers) = parser.getValues("Network", "DNS");
710 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530711 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530712 log<level::DEBUG>("Unable to get the value for network[DNS]",
713 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530714 }
715 return servers;
716}
717
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530718ServerList EthernetInterface::getNameServerFromResolvd()
719{
720 ServerList servers;
721 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
722
723 /*
724 The DNS property under org.freedesktop.resolve1.Link interface contains
725 an array containing all DNS servers currently used by resolved. It
726 contains similar information as the DNS server data written to
727 /run/systemd/resolve/resolv.conf.
728
729 Each structure in the array consists of a numeric network interface index,
730 an address family, and a byte array containing the DNS server address
731 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
732 The array contains DNS servers configured system-wide, including those
733 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
734 /etc/systemd/resolved.conf, as well as per-interface DNS server
735 information either retrieved from systemd-networkd or configured by
736 external software via SetLinkDNS().
737 */
738
739 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
740 std::variant<type> name; // Variable to capture the DNS property
741 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
742 PROPERTY_INTERFACE, METHOD_GET);
743
744 method.append(RESOLVED_INTERFACE, "DNS");
745 auto reply = bus.call(method);
746
747 try
748 {
749 reply.read(name);
750 }
751 catch (const sdbusplus::exception::SdBusError& e)
752 {
753 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
754 }
755 auto tupleVector = std::get_if<type>(&name);
756 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
757 {
Alexander Filippov983da552021-02-08 15:26:54 +0300758 int addressFamily = std::get<0>(*i);
759 std::vector<uint8_t>& ipaddress = std::get<1>(*i);
760
761 switch (addressFamily)
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530762 {
Alexander Filippov983da552021-02-08 15:26:54 +0300763 case AF_INET:
764 if (ipaddress.size() == sizeof(struct in_addr))
765 {
766 servers.push_back(toString(
767 *reinterpret_cast<struct in_addr*>(ipaddress.data())));
768 }
769 else
770 {
771 log<level::ERR>(
772 "Invalid data recived from Systemd-Resolved");
773 }
774 break;
775
776 case AF_INET6:
777 if (ipaddress.size() == sizeof(struct in6_addr))
778 {
779 servers.push_back(toString(
780 *reinterpret_cast<struct in6_addr*>(ipaddress.data())));
781 }
782 else
783 {
784 log<level::ERR>(
785 "Invalid data recived from Systemd-Resolved");
786 }
787 break;
788
789 default:
790 log<level::ERR>(
791 "Unsupported address family in DNS from Systemd-Resolved");
792 break;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530793 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530794 }
795 return servers;
796}
797
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530798void EthernetInterface::loadVLAN(VlanId id)
799{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500800 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530801 std::string path = objPath;
802 path += "_" + std::to_string(id);
803
Johnathan Mantey817012a2020-01-30 15:07:39 -0800804 DHCPConf dhcpEnabled =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500805 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530806 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Patrick Williams6aef7692021-05-01 06:39:41 -0500807 bus, path.c_str(), dhcpEnabled, EthernetInterfaceIntf::nicEnabled(), id,
Johnathan Mantey817012a2020-01-30 15:07:39 -0800808 *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530809
Gunnar Mills57d9c502018-09-14 14:42:34 -0500810 // Fetch the ip address from the system
811 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530812 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800813 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530814
815 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
816 std::move(vlanIntf));
817}
818
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700819ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530820{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500821 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530822 std::string path = objPath;
823 path += "_" + std::to_string(id);
824
Patrick Williams6aef7692021-05-01 06:39:41 -0500825 // Pass the parents nicEnabled property, so that the child
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530826 // VLAN interface can inherit.
827
Ratan Gupta5978dd12017-07-25 13:47:13 +0530828 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Johnathan Mantey817012a2020-01-30 15:07:39 -0800829 bus, path.c_str(), EthernetInterface::DHCPConf::none,
Patrick Williams6aef7692021-05-01 06:39:41 -0500830 EthernetInterfaceIntf::nicEnabled(), id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530831
832 // write the device file for the vlan interface.
833 vlanIntf->writeDeviceFile();
834
Gunnar Mills57d9c502018-09-14 14:42:34 -0500835 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530836 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530837 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700838
839 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530840}
Ratan Gupta2b106532017-07-25 16:05:02 +0530841
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700842bool EthernetInterface::getIPv6AcceptRAFromConf()
843{
844 fs::path confPath = manager.getConfDir();
845
846 std::string fileName = systemd::config::networkFilePrefix +
847 interfaceName() + systemd::config::networkFileSuffix;
848 confPath /= fileName;
849 config::ValueList values;
850 config::Parser parser(confPath.string());
851 auto rc = config::ReturnCode::SUCCESS;
852 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
853 if (rc != config::ReturnCode::SUCCESS)
854 {
855 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
856 entry("rc=%d", rc));
857 return false;
858 }
859 return (values[0] == "true");
860}
861
Ratan Gupta497c0c92017-08-22 19:15:59 +0530862ServerList EthernetInterface::getNTPServersFromConf()
863{
864 fs::path confPath = manager.getConfDir();
865
Gunnar Mills57d9c502018-09-14 14:42:34 -0500866 std::string fileName = systemd::config::networkFilePrefix +
867 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530868 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530869
Ratan Gupta497c0c92017-08-22 19:15:59 +0530870 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530871 config::Parser parser(confPath.string());
872 auto rc = config::ReturnCode::SUCCESS;
873
874 std::tie(rc, servers) = parser.getValues("Network", "NTP");
875 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530876 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530877 log<level::DEBUG>("Unable to get the value for Network[NTP]",
878 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530879 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530880
Ratan Gupta497c0c92017-08-22 19:15:59 +0530881 return servers;
882}
883
Patrick Williams6aef7692021-05-01 06:39:41 -0500884ServerList EthernetInterface::ntpServers(ServerList servers)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530885{
Patrick Williams6aef7692021-05-01 06:39:41 -0500886 auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530887
888 writeConfigurationFile();
889 // timesynchd reads the NTP server configuration from the
890 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530891 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530892 return ntpServers;
893}
Ratan Gupta2b106532017-07-25 16:05:02 +0530894// Need to merge the below function with the code which writes the
895// config file during factory reset.
896// TODO openbmc/openbmc#1751
897
898void EthernetInterface::writeConfigurationFile()
899{
900 // write all the static ip address in the systemd-network conf file
901
902 using namespace std::string_literals;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530903 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530904
905 // if there is vlan interafce then write the configuration file
906 // for vlan also.
907
Gunnar Mills57d9c502018-09-14 14:42:34 -0500908 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530909 {
910 intf.second->writeConfigurationFile();
911 }
912
Ratan Gupta2b106532017-07-25 16:05:02 +0530913 fs::path confPath = manager.getConfDir();
914
Gunnar Mills57d9c502018-09-14 14:42:34 -0500915 std::string fileName = systemd::config::networkFilePrefix +
916 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530917 confPath /= fileName;
918 std::fstream stream;
919
920 stream.open(confPath.c_str(), std::fstream::out);
921 if (!stream.is_open())
922 {
923 log<level::ERR>("Unable to open the file",
924 entry("FILE=%s", confPath.c_str()));
925 elog<InternalFailure>();
926 }
927
928 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400929 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530930 stream << "Name=" << interfaceName() << "\n";
931
932 auto addrs = getAddresses();
933
William A. Kennington III15787212019-04-23 19:18:01 -0700934 // Write the link section
935 stream << "[Link]\n";
Patrick Williams6aef7692021-05-01 06:39:41 -0500936 auto mac = MacAddressIntf::macAddress();
William A. Kennington III15787212019-04-23 19:18:01 -0700937 if (!mac.empty())
938 {
939 stream << "MACAddress=" << mac << "\n";
940 }
941
Patrick Williams6aef7692021-05-01 06:39:41 -0500942 if (!EthernetInterfaceIntf::nicEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700943 {
944 stream << "Unmanaged=yes\n";
945 }
946
Ratan Gupta2b106532017-07-25 16:05:02 +0530947 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400948 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400949#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500950 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400951#else
952 stream << "LinkLocalAddressing=no\n";
953#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700954 stream << std::boolalpha
Patrick Williams6aef7692021-05-01 06:39:41 -0500955 << "IPv6AcceptRA=" << EthernetInterfaceIntf::ipv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530956
957 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500958 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530959 {
960 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500961 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530962 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530963 // Add the NTP server
Patrick Williams6aef7692021-05-01 06:39:41 -0500964 for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530965 {
966 stream << "NTP=" << ntp << "\n";
967 }
968
969 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530970 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530971 {
972 stream << "DNS=" << dns << "\n";
973 }
974
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500975 // Add the DHCP entry
Johnathan Mantey817012a2020-01-30 15:07:39 -0800976 stream << "DHCP="s +
Patrick Williams6aef7692021-05-01 06:39:41 -0500977 mapDHCPToSystemd[EthernetInterfaceIntf::dhcpEnabled()] + "\n";
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500978
Johnathan Mantey817012a2020-01-30 15:07:39 -0800979 // Static IP addresses
980 for (const auto& addr : addrs)
Ratan Gupta2b106532017-07-25 16:05:02 +0530981 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800982 if (originIsManuallyAssigned(addr.second->origin()) &&
983 !dhcpIsEnabled(addr.second->type()))
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600984 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800985 // Process all static addresses
986 std::string address = addr.second->address() + "/" +
987 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530988
Johnathan Mantey817012a2020-01-30 15:07:39 -0800989 // build the address entries. Do not use [Network] shortcuts to
990 // insert address entries.
991 stream << "[Address]\n";
992 stream << "Address=" << address << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600993 }
Johnathan Mantey817012a2020-01-30 15:07:39 -0800994 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600995
Ravi Tejaa5a09442020-07-17 00:57:33 -0500996 auto gateway = EthernetInterfaceIntf::defaultGateway();
997 if (!gateway.empty())
998 {
Ravi Tejac14b4b32021-03-16 00:01:17 -0500999 stream << "[Route]\n";
Ravi Tejaa5a09442020-07-17 00:57:33 -05001000 stream << "Gateway=" << gateway << "\n";
1001 }
1002
1003 auto gateway6 = EthernetInterfaceIntf::defaultGateway6();
1004 if (!gateway6.empty())
1005 {
Ravi Tejac14b4b32021-03-16 00:01:17 -05001006 stream << "[Route]\n";
Ravi Tejaa5a09442020-07-17 00:57:33 -05001007 stream << "Gateway=" << gateway6 << "\n";
1008 }
1009
Johnathan Mantey817012a2020-01-30 15:07:39 -08001010 if (manager.getSystemConf())
1011 {
Johnathan Mantey817012a2020-01-30 15:07:39 -08001012 const auto& gateway = manager.getSystemConf()->defaultGateway();
1013 if (!gateway.empty())
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001014 {
Ravi Tejac14b4b32021-03-16 00:01:17 -05001015 stream << "[Route]\n";
Johnathan Mantey817012a2020-01-30 15:07:39 -08001016 stream << "Gateway=" << gateway << "\n";
1017 }
1018 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
1019 if (!gateway6.empty())
1020 {
Ravi Tejac14b4b32021-03-16 00:01:17 -05001021 stream << "[Route]\n";
Johnathan Mantey817012a2020-01-30 15:07:39 -08001022 stream << "Gateway=" << gateway6 << "\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001023 }
Ratan Gupta2b106532017-07-25 16:05:02 +05301024 }
1025
William A. Kennington III08505792019-01-30 16:00:04 -08001026 // Write the neighbor sections
1027 for (const auto& neighbor : staticNeighbors)
1028 {
1029 stream << "[Neighbor]"
1030 << "\n";
Patrick Williams6aef7692021-05-01 06:39:41 -05001031 stream << "Address=" << neighbor.second->ipAddress() << "\n";
1032 stream << "MACAddress=" << neighbor.second->macAddress() << "\n";
William A. Kennington III08505792019-01-30 16:00:04 -08001033 }
1034
Nagaraju Goruganti210420a2018-03-07 09:22:28 -06001035 // Write the dhcp section irrespective of whether DHCP is enabled or not
1036 writeDHCPSection(stream);
1037
Ratan Gupta2b106532017-07-25 16:05:02 +05301038 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +05301039}
1040
1041void EthernetInterface::writeDHCPSection(std::fstream& stream)
1042{
1043 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +05301044 // write the dhcp section
1045 stream << "[DHCP]\n";
1046
1047 // Hardcoding the client identifier to mac, to address below issue
1048 // https://github.com/openbmc/openbmc/issues/1280
1049 stream << "ClientIdentifier=mac\n";
1050 if (manager.getDHCPConf())
1051 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001052 auto value = manager.getDHCPConf()->dnsEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301053 stream << "UseDNS="s + value + "\n";
1054
Patrick Williams6aef7692021-05-01 06:39:41 -05001055 value = manager.getDHCPConf()->ntpEnabled() ? "true"s : "false"s;
Ratan Gupta2b106532017-07-25 16:05:02 +05301056 stream << "UseNTP="s + value + "\n";
1057
1058 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
1059 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -06001060
1061 value =
1062 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
1063 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +05301064 }
1065}
1066
Patrick Williams6aef7692021-05-01 06:39:41 -05001067std::string EthernetInterface::macAddress(std::string value)
Ratan Guptabd303b12017-08-18 17:10:07 +05301068{
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -06001069 ether_addr newMAC;
1070 try
1071 {
1072 newMAC = mac_address::fromString(value);
1073 }
1074 catch (std::invalid_argument&)
1075 {
1076 log<level::ERR>("MACAddress is not valid.",
1077 entry("MAC=%s", value.c_str()));
1078 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1079 Argument::ARGUMENT_VALUE(value.c_str()));
1080 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001081 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301082 {
Gunnar Mills90480c42018-06-19 16:02:17 -05001083 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -05001084 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -05001085 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
1086 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +05301087 }
1088
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001089 auto interface = interfaceName();
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001090 std::string validMAC = mac_address::toString(newMAC);
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001091
William A. Kennington III1137a972019-04-20 20:49:58 -07001092 // We don't need to update the system if the address is unchanged
Patrick Williams6aef7692021-05-01 06:39:41 -05001093 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::macAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -07001094 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +05301095 {
William A. Kennington III1137a972019-04-20 20:49:58 -07001096 // Update everything that depends on the MAC value
1097 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +05301098 {
Patrick Williams6aef7692021-05-01 06:39:41 -05001099 intf->MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301100 }
Patrick Williams6aef7692021-05-01 06:39:41 -05001101 MacAddressIntf::macAddress(validMAC);
Ratan Guptabd303b12017-08-18 17:10:07 +05301102
William A. Kennington III15787212019-04-23 19:18:01 -07001103 // TODO: would remove the call below and
1104 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -07001105 // through https://github.com/systemd/systemd/issues/6696
1106 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
1107 "down");
William A. Kennington III15787212019-04-23 19:18:01 -07001108 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +05301109 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001110
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001111#ifdef HAVE_UBOOT_ENV
1112 // Ensure that the valid address is stored in the u-boot-env
1113 auto envVar = interfaceToUbootEthAddr(interface.c_str());
1114 if (envVar)
1115 {
Asmitha Karunanithi33bc9a92020-08-13 08:48:33 -05001116 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100;
1117 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB
1118 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
1119 validMAC.c_str());
Alexander Filippov76b2aa32020-07-10 13:28:55 +03001120 }
1121#endif // HAVE_UBOOT_ENV
1122
William A. Kennington III1137a972019-04-20 20:49:58 -07001123 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301124}
1125
Ratan Guptae9c9b812017-09-22 17:15:37 +05301126void EthernetInterface::deleteAll()
1127{
Johnathan Mantey817012a2020-01-30 15:07:39 -08001128 if (dhcpIsEnabled(IP::Protocol::IPv4, true))
Ratan Guptae9c9b812017-09-22 17:15:37 +05301129 {
1130 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001131 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301132 }
1133
1134 // clear all the ip on the interface
1135 addrs.clear();
1136 manager.writeToConfigurationFile();
1137}
1138
Ravi Tejaa5a09442020-07-17 00:57:33 -05001139std::string EthernetInterface::defaultGateway(std::string gateway)
1140{
1141 auto gw = EthernetInterfaceIntf::defaultGateway();
1142 if (gw == gateway)
1143 {
1144 return gw;
1145 }
1146
1147 if (!isValidIP(AF_INET, gateway))
1148 {
1149 log<level::ERR>("Not a valid v4 Gateway",
1150 entry("GATEWAY=%s", gateway.c_str()));
1151 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1152 Argument::ARGUMENT_VALUE(gateway.c_str()));
1153 }
1154 gw = EthernetInterfaceIntf::defaultGateway(gateway);
1155 manager.writeToConfigurationFile();
1156 return gw;
1157}
1158
1159std::string EthernetInterface::defaultGateway6(std::string gateway)
1160{
1161 auto gw = EthernetInterfaceIntf::defaultGateway6();
1162 if (gw == gateway)
1163 {
1164 return gw;
1165 }
1166
1167 if (!isValidIP(AF_INET6, gateway))
1168 {
1169 log<level::ERR>("Not a valid v6 Gateway",
1170 entry("GATEWAY=%s", gateway.c_str()));
1171 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"),
1172 Argument::ARGUMENT_VALUE(gateway.c_str()));
1173 }
1174 gw = EthernetInterfaceIntf::defaultGateway6(gateway);
1175 manager.writeToConfigurationFile();
1176 return gw;
1177}
Gunnar Mills57d9c502018-09-14 14:42:34 -05001178} // namespace network
1179} // namespace phosphor