blob: f293ef59e327151622ad404592db90dbdcf18d5f [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"
Ratan Gupta2b106532017-07-25 16:05:02 +05306#include "ipaddress.hpp"
William A. Kennington III08505792019-01-30 16:00:04 -08007#include "neighbor.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05308#include "network_manager.hpp"
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>
22#include <experimental/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>
27#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;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050038using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta2b106532017-07-25 16:05:02 +053039
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080040struct EthernetIntfSocket
41{
42 EthernetIntfSocket(int domain, int type, int protocol)
43 {
44 if ((sock = socket(domain, type, protocol)) < 0)
45 {
46 log<level::ERR>("socket creation failed:",
47 entry("ERROR=%s", strerror(errno)));
48 }
49 }
50
51 ~EthernetIntfSocket()
52 {
53 if (sock >= 0)
54 {
55 close(sock);
56 }
57 }
58
59 int sock{-1};
60};
61
Ratan Gupta91a99cc2017-04-14 16:32:09 +053062EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
63 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050064 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053065 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050066 Ifaces(bus, objPath.c_str(), true),
67 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053068{
69 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053070 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053071 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053072 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Johnathan Mantey5b023f52019-06-24 16:06:37 -070073 EthernetInterfaceIntf::iPv6AcceptRA(getIPv6AcceptRAFromConf());
Ratan Guptabd303b12017-08-18 17:10:07 +053074 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053075 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec3902017-08-20 15:28:12 +053076 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
Johnathan Manteycb42fe22019-08-01 13:35:29 -070077 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
78
79 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
80 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080081 EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo));
Ratan Gupta6dec3902017-08-20 15:28:12 +053082
Ratan Gupta29b0e432017-05-25 12:51:40 +053083 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053084 if (emitSignal)
85 {
86 this->emit_object_added();
87 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053088}
89
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080090static IP::Protocol convertFamily(int family)
91{
92 switch (family)
93 {
94 case AF_INET:
95 return IP::Protocol::IPv4;
96 case AF_INET6:
97 return IP::Protocol::IPv6;
98 }
99
100 throw std::invalid_argument("Bad address family");
101}
102
Ratan Gupta87c13982017-06-15 09:27:27 +0530103void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530104{
Ratan Gupta87c13982017-06-15 09:27:27 +0530105 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530106
Ratan Gupta87c13982017-06-15 09:27:27 +0530107 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530108
Ratan Gupta6a387c12017-08-03 13:26:19 +0530109 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530110 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800111 IP::Protocol addressType = convertFamily(addr.addrType);
112 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +0530113 if (dHCPEnabled())
114 {
115 origin = IP::AddressOrigin::DHCP;
116 }
William A. Kennington III16893802019-01-30 16:01:01 -0800117 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530118 {
119 origin = IP::AddressOrigin::LinkLocal;
120 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700121 // Obsolete parameter
122 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530123
Gunnar Mills57d9c502018-09-14 14:42:34 -0500124 std::string ipAddressObjectPath = generateObjectPath(
125 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530126
Gunnar Mills57d9c502018-09-14 14:42:34 -0500127 this->addrs.emplace(addr.ipaddress,
128 std::make_shared<phosphor::network::IPAddress>(
129 bus, ipAddressObjectPath.c_str(), *this,
130 addressType, addr.ipaddress, origin,
131 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530132 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530133}
134
William A. Kennington III08505792019-01-30 16:00:04 -0800135void EthernetInterface::createStaticNeighborObjects()
136{
137 staticNeighbors.clear();
138
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700139 NeighborFilter filter;
140 filter.interface = ifIndex();
141 filter.state = NUD_PERMANENT;
142 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800143 for (const auto& neighbor : neighbors)
144 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700145 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800146 {
147 continue;
148 }
149 std::string ip = toString(neighbor.address);
150 std::string mac = mac_address::toString(*neighbor.mac);
151 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
152 staticNeighbors.emplace(ip,
153 std::make_shared<phosphor::network::Neighbor>(
154 bus, objectPath.c_str(), *this, ip, mac,
155 Neighbor::State::Permanent));
156 }
157}
158
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700159unsigned EthernetInterface::ifIndex() const
160{
161 unsigned idx = if_nametoindex(interfaceName().c_str());
162 if (idx == 0)
163 {
164 throw std::system_error(errno, std::generic_category(),
165 "if_nametoindex");
166 }
167 return idx;
168}
169
raviteja-bce379562019-03-28 05:59:36 -0500170ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
171 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530172{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530173
174 if (dHCPEnabled())
175 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530176 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500177 entry("INTERFACE=%s", interfaceName().c_str());
178 dHCPEnabled(false);
179 }
180
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500181 IP::AddressOrigin origin = IP::AddressOrigin::Static;
182
183 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
184
185 if (!isValidIP(addressFamily, ipaddress))
186 {
187 log<level::ERR>("Not a valid IP address"),
188 entry("ADDRESS=%s", ipaddress.c_str());
189 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
190 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
191 }
192
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700193 // Gateway is an obsolete parameter
194 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500195
196 if (!isValidPrefix(addressFamily, prefixLength))
197 {
198 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700199 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500200 elog<InvalidArgument>(
201 Argument::ARGUMENT_NAME("prefixLength"),
202 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530203 }
204
Gunnar Mills57d9c502018-09-14 14:42:34 -0500205 std::string objectPath =
206 generateObjectPath(protType, ipaddress, prefixLength, gateway);
207 this->addrs.emplace(ipaddress,
208 std::make_shared<phosphor::network::IPAddress>(
209 bus, objectPath.c_str(), *this, protType, ipaddress,
210 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530211
Ratan Guptae05083a2017-09-16 07:12:11 +0530212 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500213 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530214}
215
William A. Kennington III08505792019-01-30 16:00:04 -0800216ObjectPath EthernetInterface::neighbor(std::string iPAddress,
217 std::string mACAddress)
218{
219 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
220 {
221 log<level::ERR>("Not a valid IP address",
222 entry("ADDRESS=%s", iPAddress.c_str()));
223 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
224 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
225 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700226 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800227 {
228 log<level::ERR>("Not a valid MAC address",
229 entry("MACADDRESS=%s", iPAddress.c_str()));
230 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
231 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
232 }
233
234 std::string objectPath =
235 generateStaticNeighborObjectPath(iPAddress, mACAddress);
236 staticNeighbors.emplace(iPAddress,
237 std::make_shared<phosphor::network::Neighbor>(
238 bus, objectPath.c_str(), *this, iPAddress,
239 mACAddress, Neighbor::State::Permanent));
240 manager.writeToConfigurationFile();
241 return objectPath;
242}
243
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530244/*
245Note: We don't have support for ethtool now
246will enable this code once we bring the ethtool
247in the image.
248TODO: https://github.com/openbmc/openbmc/issues/1484
249*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530250
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530251InterfaceInfo EthernetInterface::getInterfaceInfo() const
252{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400253 ifreq ifr{0};
254 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500255 LinkSpeed speed{0};
256 Autoneg autoneg{0};
257 DuplexMode duplex{0};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800258 LinkUp linkState{false};
259 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
260
261 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530262 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800263 return std::make_tuple(speed, duplex, autoneg, linkState);
264 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530265
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800266 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
267 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530268
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800269 edata.cmd = ETHTOOL_GSET;
270 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
271 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530272 speed = edata.speed;
273 duplex = edata.duplex;
274 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530275 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800276
277 linkState = linkUp();
278
279 return std::make_tuple(speed, duplex, autoneg, linkState);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530280}
281
282/** @brief get the mac address of the interface.
283 * @return macaddress on success
284 */
285
Gunnar Mills57d9c502018-09-14 14:42:34 -0500286std::string
287 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530288{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800289 std::string activeMACAddr = MacAddressIntf::mACAddress();
290 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
291
292 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530293 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800294 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530295 }
296
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800297 ifreq ifr{0};
298 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
299 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530300 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530301 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500302 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700303 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530304 }
305
William A. Kennington III1137a972019-04-20 20:49:58 -0700306 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
307 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
308 sizeof(ifr.ifr_hwaddr.sa_data));
309 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530310}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530311
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530312std::string EthernetInterface::generateId(const std::string& ipaddress,
313 uint8_t prefixLength,
314 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530315{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530316 std::stringstream hexId;
317 std::string hashString = ipaddress;
318 hashString += std::to_string(prefixLength);
319 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530320
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530321 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500322 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530323 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530324}
325
William A. Kennington III08505792019-01-30 16:00:04 -0800326std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
327 const std::string& mACAddress)
328{
329 std::stringstream hexId;
330 std::string hashString = iPAddress + mACAddress;
331
332 // Only want 8 hex digits.
333 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
334 return hexId.str();
335}
336
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530337void EthernetInterface::deleteObject(const std::string& ipaddress)
338{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530339 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530340 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530341 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530342 log<level::ERR>("DeleteObject:Unable to find the object.");
343 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530344 }
345 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530346 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530347}
348
William A. Kennington III08505792019-01-30 16:00:04 -0800349void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
350{
351 auto it = staticNeighbors.find(iPAddress);
352 if (it == staticNeighbors.end())
353 {
354 log<level::ERR>(
355 "DeleteStaticNeighborObject:Unable to find the object.");
356 return;
357 }
358 staticNeighbors.erase(it);
359 manager.writeToConfigurationFile();
360}
361
Ratan Guptae9c9b812017-09-22 17:15:37 +0530362void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530363{
Ratan Guptabc886292017-07-25 18:29:57 +0530364 auto confDir = manager.getConfDir();
365 fs::path networkFile = confDir;
366 networkFile /= systemd::config::networkFilePrefix + interface +
367 systemd::config::networkFileSuffix;
368
369 fs::path deviceFile = confDir;
370 deviceFile /= interface + systemd::config::deviceFileSuffix;
371
372 // delete the vlan network file
373 if (fs::is_regular_file(networkFile))
374 {
375 fs::remove(networkFile);
376 }
377
378 // delete the vlan device file
379 if (fs::is_regular_file(deviceFile))
380 {
381 fs::remove(deviceFile);
382 }
Ratan Guptabc886292017-07-25 18:29:57 +0530383
384 // TODO systemd doesn't delete the virtual network interface
385 // even after deleting all the related configuartion.
386 // https://github.com/systemd/systemd/issues/6600
387 try
388 {
389 deleteInterface(interface);
390 }
391 catch (InternalFailure& e)
392 {
393 commit<InternalFailure>();
394 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530395}
396
397void EthernetInterface::deleteVLANObject(const std::string& interface)
398{
399 auto it = vlanInterfaces.find(interface);
400 if (it == vlanInterfaces.end())
401 {
402 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500403 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530404 return;
405 }
406
407 deleteVLANFromSystem(interface);
408 // delete the interface
409 vlanInterfaces.erase(it);
410
Ratan Guptae05083a2017-09-16 07:12:11 +0530411 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530412}
413
Gunnar Mills57d9c502018-09-14 14:42:34 -0500414std::string EthernetInterface::generateObjectPath(
415 IP::Protocol addressType, const std::string& ipaddress,
416 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530417{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530418 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530419 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530420 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
421
422 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530423 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530424 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530425 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530426 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530427}
428
William A. Kennington III08505792019-01-30 16:00:04 -0800429std::string EthernetInterface::generateStaticNeighborObjectPath(
430 const std::string& iPAddress, const std::string& mACAddress) const
431{
432 std::experimental::filesystem::path objectPath;
433 objectPath /= objPath;
434 objectPath /= "static_neighbor";
435 objectPath /= generateNeighborId(iPAddress, mACAddress);
436 return objectPath.string();
437}
438
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700439bool EthernetInterface::iPv6AcceptRA(bool value)
440{
441 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
442 {
443 return value;
444 }
445 EthernetInterfaceIntf::iPv6AcceptRA(value);
446 manager.writeToConfigurationFile();
447 return value;
448}
449
Ratan Gupta87c13982017-06-15 09:27:27 +0530450bool EthernetInterface::dHCPEnabled(bool value)
451{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530452 if (value == EthernetInterfaceIntf::dHCPEnabled())
453 {
454 return value;
455 }
456
Ratan Gupta87c13982017-06-15 09:27:27 +0530457 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530458 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530459 return value;
460}
461
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800462bool EthernetInterface::linkUp() const
463{
464 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
465 bool value = EthernetInterfaceIntf::linkUp();
466
467 if (eifSocket.sock < 0)
468 {
469 return value;
470 }
471
472 ifreq ifr{0};
473 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
474 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
475 {
476 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
477 }
478 else
479 {
480 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
481 entry("ERROR=%s", strerror(errno)));
482 }
483
484 return value;
485}
486
Ratan Gupta6dec3902017-08-20 15:28:12 +0530487ServerList EthernetInterface::nameservers(ServerList value)
488{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530489 for (const auto& nameserverip : value)
490 {
491 if (!isValidIP(AF_INET, nameserverip) &&
492 !isValidIP(AF_INET6, nameserverip))
493 {
494 log<level::ERR>("Not a valid IP address"),
495 entry("ADDRESS=%s", nameserverip.c_str());
496 elog<InvalidArgument>(
497 Argument::ARGUMENT_NAME("Nameserver"),
498 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
499 }
500 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530501 try
502 {
503 EthernetInterfaceIntf::nameservers(value);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530504 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530505 // resolved reads the DNS server configuration from the
506 // network file.
507 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530508 }
509 catch (InternalFailure& e)
510 {
511 log<level::ERR>("Exception processing DNS entries");
512 }
513 return EthernetInterfaceIntf::nameservers();
514}
515
516ServerList EthernetInterface::getNameServerFromConf()
517{
518 fs::path confPath = manager.getConfDir();
519
520 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500521 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530522 confPath /= fileName;
523 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530524 config::Parser parser(confPath.string());
525 auto rc = config::ReturnCode::SUCCESS;
526
527 std::tie(rc, servers) = parser.getValues("Network", "DNS");
528 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530529 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530530 log<level::DEBUG>("Unable to get the value for network[DNS]",
531 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530532 }
533 return servers;
534}
535
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530536void EthernetInterface::loadVLAN(VlanId id)
537{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500538 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530539 std::string path = objPath;
540 path += "_" + std::to_string(id);
541
Gunnar Mills57d9c502018-09-14 14:42:34 -0500542 auto dhcpEnabled =
543 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530544
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530545 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500546 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530547
Gunnar Mills57d9c502018-09-14 14:42:34 -0500548 // Fetch the ip address from the system
549 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530550 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800551 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530552
553 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
554 std::move(vlanIntf));
555}
556
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700557ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530558{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500559 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530560 std::string path = objPath;
561 path += "_" + std::to_string(id);
562
Ratan Gupta5978dd12017-07-25 13:47:13 +0530563 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500564 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530565
566 // write the device file for the vlan interface.
567 vlanIntf->writeDeviceFile();
568
Gunnar Mills57d9c502018-09-14 14:42:34 -0500569 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530570 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530571 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700572
573 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530574}
Ratan Gupta2b106532017-07-25 16:05:02 +0530575
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700576bool EthernetInterface::getIPv6AcceptRAFromConf()
577{
578 fs::path confPath = manager.getConfDir();
579
580 std::string fileName = systemd::config::networkFilePrefix +
581 interfaceName() + systemd::config::networkFileSuffix;
582 confPath /= fileName;
583 config::ValueList values;
584 config::Parser parser(confPath.string());
585 auto rc = config::ReturnCode::SUCCESS;
586 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
587 if (rc != config::ReturnCode::SUCCESS)
588 {
589 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
590 entry("rc=%d", rc));
591 return false;
592 }
593 return (values[0] == "true");
594}
595
Ratan Gupta497c0c92017-08-22 19:15:59 +0530596ServerList EthernetInterface::getNTPServersFromConf()
597{
598 fs::path confPath = manager.getConfDir();
599
Gunnar Mills57d9c502018-09-14 14:42:34 -0500600 std::string fileName = systemd::config::networkFilePrefix +
601 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530602 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530603
Ratan Gupta497c0c92017-08-22 19:15:59 +0530604 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530605 config::Parser parser(confPath.string());
606 auto rc = config::ReturnCode::SUCCESS;
607
608 std::tie(rc, servers) = parser.getValues("Network", "NTP");
609 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530610 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530611 log<level::DEBUG>("Unable to get the value for Network[NTP]",
612 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530613 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530614
Ratan Gupta497c0c92017-08-22 19:15:59 +0530615 return servers;
616}
617
618ServerList EthernetInterface::nTPServers(ServerList servers)
619{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500620 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530621
622 writeConfigurationFile();
623 // timesynchd reads the NTP server configuration from the
624 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530625 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530626 return ntpServers;
627}
Ratan Gupta2b106532017-07-25 16:05:02 +0530628// Need to merge the below function with the code which writes the
629// config file during factory reset.
630// TODO openbmc/openbmc#1751
631
632void EthernetInterface::writeConfigurationFile()
633{
634 // write all the static ip address in the systemd-network conf file
635
636 using namespace std::string_literals;
637 using AddressOrigin =
638 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
639 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530640
641 // if there is vlan interafce then write the configuration file
642 // for vlan also.
643
Gunnar Mills57d9c502018-09-14 14:42:34 -0500644 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530645 {
646 intf.second->writeConfigurationFile();
647 }
648
Ratan Gupta2b106532017-07-25 16:05:02 +0530649 fs::path confPath = manager.getConfDir();
650
Gunnar Mills57d9c502018-09-14 14:42:34 -0500651 std::string fileName = systemd::config::networkFilePrefix +
652 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530653 confPath /= fileName;
654 std::fstream stream;
655
656 stream.open(confPath.c_str(), std::fstream::out);
657 if (!stream.is_open())
658 {
659 log<level::ERR>("Unable to open the file",
660 entry("FILE=%s", confPath.c_str()));
661 elog<InternalFailure>();
662 }
663
664 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400665 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530666 stream << "Name=" << interfaceName() << "\n";
667
668 auto addrs = getAddresses();
669
William A. Kennington III15787212019-04-23 19:18:01 -0700670 // Write the link section
671 stream << "[Link]\n";
672 auto mac = MacAddressIntf::mACAddress();
673 if (!mac.empty())
674 {
675 stream << "MACAddress=" << mac << "\n";
676 }
677
Ratan Gupta2b106532017-07-25 16:05:02 +0530678 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400679 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400680#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500681 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400682#else
683 stream << "LinkLocalAddressing=no\n";
684#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700685 stream << std::boolalpha
686 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530687
688 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500689 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530690 {
691 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500692 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530693 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530694 // Add the NTP server
695 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
696 {
697 stream << "NTP=" << ntp << "\n";
698 }
699
700 // Add the DNS entry
701 for (const auto& dns : EthernetInterfaceIntf::nameservers())
702 {
703 stream << "DNS=" << dns << "\n";
704 }
705
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500706 // Add the DHCP entry
707 auto value = dHCPEnabled() ? "true"s : "false"s;
708 stream << "DHCP="s + value + "\n";
709
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600710 // When the interface configured as dhcp, we don't need below given entries
711 // in config file.
712 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530713 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600714 // Static
715 for (const auto& addr : addrs)
716 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400717 if (addr.second->origin() == AddressOrigin::Static
718#ifndef LINK_LOCAL_AUTOCONFIGURATION
719 || addr.second->origin() == AddressOrigin::LinkLocal
720#endif
721 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530722 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500723 std::string address =
724 addr.second->address() + "/" +
725 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530726
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600727 stream << "Address=" << address << "\n";
728 }
729 }
730
731 if (manager.getSystemConf())
732 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800733 const auto& gateway = manager.getSystemConf()->defaultGateway();
734 if (!gateway.empty())
735 {
736 stream << "Gateway=" << gateway << "\n";
737 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800738 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
739 if (!gateway6.empty())
740 {
741 stream << "Gateway=" << gateway6 << "\n";
742 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600743 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530744 }
745
William A. Kennington III08505792019-01-30 16:00:04 -0800746 // Write the neighbor sections
747 for (const auto& neighbor : staticNeighbors)
748 {
749 stream << "[Neighbor]"
750 << "\n";
751 stream << "Address=" << neighbor.second->iPAddress() << "\n";
752 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
753 }
754
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600755 // Write the dhcp section irrespective of whether DHCP is enabled or not
756 writeDHCPSection(stream);
757
Ratan Gupta2b106532017-07-25 16:05:02 +0530758 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530759}
760
761void EthernetInterface::writeDHCPSection(std::fstream& stream)
762{
763 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530764 // write the dhcp section
765 stream << "[DHCP]\n";
766
767 // Hardcoding the client identifier to mac, to address below issue
768 // https://github.com/openbmc/openbmc/issues/1280
769 stream << "ClientIdentifier=mac\n";
770 if (manager.getDHCPConf())
771 {
772 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
773 stream << "UseDNS="s + value + "\n";
774
775 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
776 stream << "UseNTP="s + value + "\n";
777
778 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
779 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600780
781 value =
782 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
783 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530784 }
785}
786
Ratan Guptabd303b12017-08-18 17:10:07 +0530787std::string EthernetInterface::mACAddress(std::string value)
788{
William A. Kennington III1137a972019-04-20 20:49:58 -0700789 ether_addr newMAC = mac_address::fromString(value);
790 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530791 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500792 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500793 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500794 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
795 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530796 }
797
William A. Kennington III1137a972019-04-20 20:49:58 -0700798 // We don't need to update the system if the address is unchanged
799 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
800 if (!equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530801 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700802 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530803 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700804 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530805 {
Alvin Wang38a63c32019-08-29 22:56:46 +0800806 auto inventoryMAC =
807 mac_address::getfromInventory(bus, interfaceName());
William A. Kennington III1137a972019-04-20 20:49:58 -0700808 if (!equal(newMAC, inventoryMAC))
809 {
810 log<level::ERR>(
811 "Given MAC address is neither a local Admin "
812 "type nor is same as in inventory");
813 elog<InvalidArgument>(
814 Argument::ARGUMENT_NAME("MACAddress"),
815 Argument::ARGUMENT_VALUE(value.c_str()));
816 }
817 }
818 catch (const std::exception& e)
819 {
820 log<level::ERR>("Exception occurred during getting of MAC "
821 "address from Inventory");
822 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530823 }
824 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700825
826 // Update everything that depends on the MAC value
827 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530828 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700829 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530830 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700831 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530832
William A. Kennington III1137a972019-04-20 20:49:58 -0700833 auto interface = interfaceName();
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700834 auto envVar = interfaceToUbootEthAddr(interface.c_str());
835 if (envVar)
836 {
837 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
838 value.c_str());
839 }
William A. Kennington III15787212019-04-23 19:18:01 -0700840 // TODO: would remove the call below and
841 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -0700842 // through https://github.com/systemd/systemd/issues/6696
843 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
844 "down");
William A. Kennington III15787212019-04-23 19:18:01 -0700845 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +0530846 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700847
848 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530849}
850
Ratan Guptae9c9b812017-09-22 17:15:37 +0530851void EthernetInterface::deleteAll()
852{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500853 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530854 {
855 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500856 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530857 }
858
859 // clear all the ip on the interface
860 addrs.clear();
861 manager.writeToConfigurationFile();
862}
863
Gunnar Mills57d9c502018-09-14 14:42:34 -0500864} // namespace network
865} // namespace phosphor