blob: c00e4f481329f54724330bdc516d07414cb024f6 [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 Gupta99801ce2020-01-09 18:37:16 +053074 // Don't get the mac address from the system as the mac address
75 // would be same as parent interface.
76 if (intfName.find(".") == std::string::npos)
77 {
78 MacAddressIntf::mACAddress(getMACAddress(intfName));
79 }
Ratan Gupta497c0c92017-08-22 19:15:59 +053080 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec3902017-08-20 15:28:12 +053081 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
Johnathan Manteycb42fe22019-08-01 13:35:29 -070082 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
83
84 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
85 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080086 EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo));
Ratan Gupta6dec3902017-08-20 15:28:12 +053087
Ratan Gupta29b0e432017-05-25 12:51:40 +053088 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053089 if (emitSignal)
90 {
91 this->emit_object_added();
92 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053093}
94
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080095static IP::Protocol convertFamily(int family)
96{
97 switch (family)
98 {
99 case AF_INET:
100 return IP::Protocol::IPv4;
101 case AF_INET6:
102 return IP::Protocol::IPv6;
103 }
104
105 throw std::invalid_argument("Bad address family");
106}
107
Ratan Gupta87c13982017-06-15 09:27:27 +0530108void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530109{
Ratan Gupta87c13982017-06-15 09:27:27 +0530110 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530111
Ratan Gupta87c13982017-06-15 09:27:27 +0530112 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530113
Ratan Gupta6a387c12017-08-03 13:26:19 +0530114 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530115 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800116 IP::Protocol addressType = convertFamily(addr.addrType);
117 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +0530118 if (dHCPEnabled())
119 {
120 origin = IP::AddressOrigin::DHCP;
121 }
William A. Kennington III16893802019-01-30 16:01:01 -0800122 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530123 {
124 origin = IP::AddressOrigin::LinkLocal;
125 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700126 // Obsolete parameter
127 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530128
Gunnar Mills57d9c502018-09-14 14:42:34 -0500129 std::string ipAddressObjectPath = generateObjectPath(
130 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530131
Gunnar Mills57d9c502018-09-14 14:42:34 -0500132 this->addrs.emplace(addr.ipaddress,
133 std::make_shared<phosphor::network::IPAddress>(
134 bus, ipAddressObjectPath.c_str(), *this,
135 addressType, addr.ipaddress, origin,
136 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530137 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530138}
139
William A. Kennington III08505792019-01-30 16:00:04 -0800140void EthernetInterface::createStaticNeighborObjects()
141{
142 staticNeighbors.clear();
143
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700144 NeighborFilter filter;
145 filter.interface = ifIndex();
146 filter.state = NUD_PERMANENT;
147 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800148 for (const auto& neighbor : neighbors)
149 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700150 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800151 {
152 continue;
153 }
154 std::string ip = toString(neighbor.address);
155 std::string mac = mac_address::toString(*neighbor.mac);
156 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
157 staticNeighbors.emplace(ip,
158 std::make_shared<phosphor::network::Neighbor>(
159 bus, objectPath.c_str(), *this, ip, mac,
160 Neighbor::State::Permanent));
161 }
162}
163
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700164unsigned EthernetInterface::ifIndex() const
165{
166 unsigned idx = if_nametoindex(interfaceName().c_str());
167 if (idx == 0)
168 {
169 throw std::system_error(errno, std::generic_category(),
170 "if_nametoindex");
171 }
172 return idx;
173}
174
raviteja-bce379562019-03-28 05:59:36 -0500175ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
176 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530177{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530178
179 if (dHCPEnabled())
180 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530181 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500182 entry("INTERFACE=%s", interfaceName().c_str());
183 dHCPEnabled(false);
184 }
185
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500186 IP::AddressOrigin origin = IP::AddressOrigin::Static;
187
188 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
189
190 if (!isValidIP(addressFamily, ipaddress))
191 {
192 log<level::ERR>("Not a valid IP address"),
193 entry("ADDRESS=%s", ipaddress.c_str());
194 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
195 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
196 }
197
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700198 // Gateway is an obsolete parameter
199 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500200
201 if (!isValidPrefix(addressFamily, prefixLength))
202 {
203 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700204 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500205 elog<InvalidArgument>(
206 Argument::ARGUMENT_NAME("prefixLength"),
207 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530208 }
209
Gunnar Mills57d9c502018-09-14 14:42:34 -0500210 std::string objectPath =
211 generateObjectPath(protType, ipaddress, prefixLength, gateway);
212 this->addrs.emplace(ipaddress,
213 std::make_shared<phosphor::network::IPAddress>(
214 bus, objectPath.c_str(), *this, protType, ipaddress,
215 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530216
Ratan Guptae05083a2017-09-16 07:12:11 +0530217 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500218 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530219}
220
William A. Kennington III08505792019-01-30 16:00:04 -0800221ObjectPath EthernetInterface::neighbor(std::string iPAddress,
222 std::string mACAddress)
223{
224 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
225 {
226 log<level::ERR>("Not a valid IP address",
227 entry("ADDRESS=%s", iPAddress.c_str()));
228 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
229 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
230 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700231 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800232 {
233 log<level::ERR>("Not a valid MAC address",
234 entry("MACADDRESS=%s", iPAddress.c_str()));
235 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
236 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
237 }
238
239 std::string objectPath =
240 generateStaticNeighborObjectPath(iPAddress, mACAddress);
241 staticNeighbors.emplace(iPAddress,
242 std::make_shared<phosphor::network::Neighbor>(
243 bus, objectPath.c_str(), *this, iPAddress,
244 mACAddress, Neighbor::State::Permanent));
245 manager.writeToConfigurationFile();
246 return objectPath;
247}
248
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530249/*
250Note: We don't have support for ethtool now
251will enable this code once we bring the ethtool
252in the image.
253TODO: https://github.com/openbmc/openbmc/issues/1484
254*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530255
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530256InterfaceInfo EthernetInterface::getInterfaceInfo() const
257{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400258 ifreq ifr{0};
259 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500260 LinkSpeed speed{0};
261 Autoneg autoneg{0};
262 DuplexMode duplex{0};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800263 LinkUp linkState{false};
264 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
265
266 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530267 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800268 return std::make_tuple(speed, duplex, autoneg, linkState);
269 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530270
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800271 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
272 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530273
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800274 edata.cmd = ETHTOOL_GSET;
275 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
276 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530277 speed = edata.speed;
278 duplex = edata.duplex;
279 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530280 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800281
282 linkState = linkUp();
283
284 return std::make_tuple(speed, duplex, autoneg, linkState);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530285}
286
287/** @brief get the mac address of the interface.
288 * @return macaddress on success
289 */
290
Gunnar Mills57d9c502018-09-14 14:42:34 -0500291std::string
292 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530293{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800294 std::string activeMACAddr = MacAddressIntf::mACAddress();
295 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
296
297 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530298 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800299 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530300 }
301
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800302 ifreq ifr{0};
303 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
304 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530305 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530306 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500307 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700308 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530309 }
310
William A. Kennington III1137a972019-04-20 20:49:58 -0700311 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
312 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
313 sizeof(ifr.ifr_hwaddr.sa_data));
314 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530315}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530316
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530317std::string EthernetInterface::generateId(const std::string& ipaddress,
318 uint8_t prefixLength,
319 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530320{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530321 std::stringstream hexId;
322 std::string hashString = ipaddress;
323 hashString += std::to_string(prefixLength);
324 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530325
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530326 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500327 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530328 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530329}
330
William A. Kennington III08505792019-01-30 16:00:04 -0800331std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
332 const std::string& mACAddress)
333{
334 std::stringstream hexId;
335 std::string hashString = iPAddress + mACAddress;
336
337 // Only want 8 hex digits.
338 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
339 return hexId.str();
340}
341
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530342void EthernetInterface::deleteObject(const std::string& ipaddress)
343{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530344 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530345 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530346 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530347 log<level::ERR>("DeleteObject:Unable to find the object.");
348 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530349 }
350 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530351 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530352}
353
William A. Kennington III08505792019-01-30 16:00:04 -0800354void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
355{
356 auto it = staticNeighbors.find(iPAddress);
357 if (it == staticNeighbors.end())
358 {
359 log<level::ERR>(
360 "DeleteStaticNeighborObject:Unable to find the object.");
361 return;
362 }
363 staticNeighbors.erase(it);
364 manager.writeToConfigurationFile();
365}
366
Ratan Guptae9c9b812017-09-22 17:15:37 +0530367void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530368{
Ratan Guptabc886292017-07-25 18:29:57 +0530369 auto confDir = manager.getConfDir();
370 fs::path networkFile = confDir;
371 networkFile /= systemd::config::networkFilePrefix + interface +
372 systemd::config::networkFileSuffix;
373
374 fs::path deviceFile = confDir;
375 deviceFile /= interface + systemd::config::deviceFileSuffix;
376
377 // delete the vlan network file
378 if (fs::is_regular_file(networkFile))
379 {
380 fs::remove(networkFile);
381 }
382
383 // delete the vlan device file
384 if (fs::is_regular_file(deviceFile))
385 {
386 fs::remove(deviceFile);
387 }
Ratan Guptabc886292017-07-25 18:29:57 +0530388
389 // TODO systemd doesn't delete the virtual network interface
390 // even after deleting all the related configuartion.
391 // https://github.com/systemd/systemd/issues/6600
392 try
393 {
394 deleteInterface(interface);
395 }
396 catch (InternalFailure& e)
397 {
398 commit<InternalFailure>();
399 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530400}
401
402void EthernetInterface::deleteVLANObject(const std::string& interface)
403{
404 auto it = vlanInterfaces.find(interface);
405 if (it == vlanInterfaces.end())
406 {
407 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500408 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530409 return;
410 }
411
412 deleteVLANFromSystem(interface);
413 // delete the interface
414 vlanInterfaces.erase(it);
415
Ratan Guptae05083a2017-09-16 07:12:11 +0530416 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530417}
418
Gunnar Mills57d9c502018-09-14 14:42:34 -0500419std::string EthernetInterface::generateObjectPath(
420 IP::Protocol addressType, const std::string& ipaddress,
421 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530422{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530423 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530424 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530425 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
426
427 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530428 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530429 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530430 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530431 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530432}
433
William A. Kennington III08505792019-01-30 16:00:04 -0800434std::string EthernetInterface::generateStaticNeighborObjectPath(
435 const std::string& iPAddress, const std::string& mACAddress) const
436{
437 std::experimental::filesystem::path objectPath;
438 objectPath /= objPath;
439 objectPath /= "static_neighbor";
440 objectPath /= generateNeighborId(iPAddress, mACAddress);
441 return objectPath.string();
442}
443
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700444bool EthernetInterface::iPv6AcceptRA(bool value)
445{
446 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
447 {
448 return value;
449 }
450 EthernetInterfaceIntf::iPv6AcceptRA(value);
451 manager.writeToConfigurationFile();
452 return value;
453}
454
Ratan Gupta87c13982017-06-15 09:27:27 +0530455bool EthernetInterface::dHCPEnabled(bool value)
456{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530457 if (value == EthernetInterfaceIntf::dHCPEnabled())
458 {
459 return value;
460 }
461
Ratan Gupta87c13982017-06-15 09:27:27 +0530462 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530463 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530464 return value;
465}
466
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800467bool EthernetInterface::linkUp() const
468{
469 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
470 bool value = EthernetInterfaceIntf::linkUp();
471
472 if (eifSocket.sock < 0)
473 {
474 return value;
475 }
476
477 ifreq ifr{0};
478 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
479 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
480 {
481 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
482 }
483 else
484 {
485 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
486 entry("ERROR=%s", strerror(errno)));
487 }
488
489 return value;
490}
491
Ratan Gupta6dec3902017-08-20 15:28:12 +0530492ServerList EthernetInterface::nameservers(ServerList value)
493{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530494 for (const auto& nameserverip : value)
495 {
496 if (!isValidIP(AF_INET, nameserverip) &&
497 !isValidIP(AF_INET6, nameserverip))
498 {
499 log<level::ERR>("Not a valid IP address"),
500 entry("ADDRESS=%s", nameserverip.c_str());
501 elog<InvalidArgument>(
502 Argument::ARGUMENT_NAME("Nameserver"),
503 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
504 }
505 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530506 try
507 {
508 EthernetInterfaceIntf::nameservers(value);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530509 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530510 // resolved reads the DNS server configuration from the
511 // network file.
512 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530513 }
514 catch (InternalFailure& e)
515 {
516 log<level::ERR>("Exception processing DNS entries");
517 }
518 return EthernetInterfaceIntf::nameservers();
519}
520
521ServerList EthernetInterface::getNameServerFromConf()
522{
523 fs::path confPath = manager.getConfDir();
524
525 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500526 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530527 confPath /= fileName;
528 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530529 config::Parser parser(confPath.string());
530 auto rc = config::ReturnCode::SUCCESS;
531
532 std::tie(rc, servers) = parser.getValues("Network", "DNS");
533 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530534 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530535 log<level::DEBUG>("Unable to get the value for network[DNS]",
536 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530537 }
538 return servers;
539}
540
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530541void EthernetInterface::loadVLAN(VlanId id)
542{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500543 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530544 std::string path = objPath;
545 path += "_" + std::to_string(id);
546
Gunnar Mills57d9c502018-09-14 14:42:34 -0500547 auto dhcpEnabled =
548 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530549
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530550 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500551 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530552
Gunnar Mills57d9c502018-09-14 14:42:34 -0500553 // Fetch the ip address from the system
554 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530555 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800556 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530557
558 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
559 std::move(vlanIntf));
560}
561
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700562ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530563{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500564 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530565 std::string path = objPath;
566 path += "_" + std::to_string(id);
567
Ratan Gupta5978dd12017-07-25 13:47:13 +0530568 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500569 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530570
571 // write the device file for the vlan interface.
572 vlanIntf->writeDeviceFile();
573
Gunnar Mills57d9c502018-09-14 14:42:34 -0500574 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530575 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530576 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700577
578 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530579}
Ratan Gupta2b106532017-07-25 16:05:02 +0530580
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700581bool EthernetInterface::getIPv6AcceptRAFromConf()
582{
583 fs::path confPath = manager.getConfDir();
584
585 std::string fileName = systemd::config::networkFilePrefix +
586 interfaceName() + systemd::config::networkFileSuffix;
587 confPath /= fileName;
588 config::ValueList values;
589 config::Parser parser(confPath.string());
590 auto rc = config::ReturnCode::SUCCESS;
591 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
592 if (rc != config::ReturnCode::SUCCESS)
593 {
594 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
595 entry("rc=%d", rc));
596 return false;
597 }
598 return (values[0] == "true");
599}
600
Ratan Gupta497c0c92017-08-22 19:15:59 +0530601ServerList EthernetInterface::getNTPServersFromConf()
602{
603 fs::path confPath = manager.getConfDir();
604
Gunnar Mills57d9c502018-09-14 14:42:34 -0500605 std::string fileName = systemd::config::networkFilePrefix +
606 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530607 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530608
Ratan Gupta497c0c92017-08-22 19:15:59 +0530609 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530610 config::Parser parser(confPath.string());
611 auto rc = config::ReturnCode::SUCCESS;
612
613 std::tie(rc, servers) = parser.getValues("Network", "NTP");
614 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530615 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530616 log<level::DEBUG>("Unable to get the value for Network[NTP]",
617 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530618 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530619
Ratan Gupta497c0c92017-08-22 19:15:59 +0530620 return servers;
621}
622
623ServerList EthernetInterface::nTPServers(ServerList servers)
624{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500625 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530626
627 writeConfigurationFile();
628 // timesynchd reads the NTP server configuration from the
629 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530630 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530631 return ntpServers;
632}
Ratan Gupta2b106532017-07-25 16:05:02 +0530633// Need to merge the below function with the code which writes the
634// config file during factory reset.
635// TODO openbmc/openbmc#1751
636
637void EthernetInterface::writeConfigurationFile()
638{
639 // write all the static ip address in the systemd-network conf file
640
641 using namespace std::string_literals;
642 using AddressOrigin =
643 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
644 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530645
646 // if there is vlan interafce then write the configuration file
647 // for vlan also.
648
Gunnar Mills57d9c502018-09-14 14:42:34 -0500649 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530650 {
651 intf.second->writeConfigurationFile();
652 }
653
Ratan Gupta2b106532017-07-25 16:05:02 +0530654 fs::path confPath = manager.getConfDir();
655
Gunnar Mills57d9c502018-09-14 14:42:34 -0500656 std::string fileName = systemd::config::networkFilePrefix +
657 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530658 confPath /= fileName;
659 std::fstream stream;
660
661 stream.open(confPath.c_str(), std::fstream::out);
662 if (!stream.is_open())
663 {
664 log<level::ERR>("Unable to open the file",
665 entry("FILE=%s", confPath.c_str()));
666 elog<InternalFailure>();
667 }
668
669 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400670 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530671 stream << "Name=" << interfaceName() << "\n";
672
673 auto addrs = getAddresses();
674
William A. Kennington III15787212019-04-23 19:18:01 -0700675 // Write the link section
676 stream << "[Link]\n";
677 auto mac = MacAddressIntf::mACAddress();
678 if (!mac.empty())
679 {
680 stream << "MACAddress=" << mac << "\n";
681 }
682
Ratan Gupta2b106532017-07-25 16:05:02 +0530683 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400684 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400685#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500686 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400687#else
688 stream << "LinkLocalAddressing=no\n";
689#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700690 stream << std::boolalpha
691 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530692
693 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500694 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530695 {
696 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500697 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530698 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530699 // Add the NTP server
700 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
701 {
702 stream << "NTP=" << ntp << "\n";
703 }
704
705 // Add the DNS entry
706 for (const auto& dns : EthernetInterfaceIntf::nameservers())
707 {
708 stream << "DNS=" << dns << "\n";
709 }
710
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500711 // Add the DHCP entry
712 auto value = dHCPEnabled() ? "true"s : "false"s;
713 stream << "DHCP="s + value + "\n";
714
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600715 // When the interface configured as dhcp, we don't need below given entries
716 // in config file.
717 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530718 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600719 // Static
720 for (const auto& addr : addrs)
721 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400722 if (addr.second->origin() == AddressOrigin::Static
723#ifndef LINK_LOCAL_AUTOCONFIGURATION
724 || addr.second->origin() == AddressOrigin::LinkLocal
725#endif
726 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530727 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500728 std::string address =
729 addr.second->address() + "/" +
730 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530731
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600732 stream << "Address=" << address << "\n";
733 }
734 }
735
736 if (manager.getSystemConf())
737 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800738 const auto& gateway = manager.getSystemConf()->defaultGateway();
739 if (!gateway.empty())
740 {
741 stream << "Gateway=" << gateway << "\n";
742 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800743 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
744 if (!gateway6.empty())
745 {
746 stream << "Gateway=" << gateway6 << "\n";
747 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600748 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530749 }
750
William A. Kennington III08505792019-01-30 16:00:04 -0800751 // Write the neighbor sections
752 for (const auto& neighbor : staticNeighbors)
753 {
754 stream << "[Neighbor]"
755 << "\n";
756 stream << "Address=" << neighbor.second->iPAddress() << "\n";
757 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
758 }
759
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600760 // Write the dhcp section irrespective of whether DHCP is enabled or not
761 writeDHCPSection(stream);
762
Ratan Gupta2b106532017-07-25 16:05:02 +0530763 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530764}
765
766void EthernetInterface::writeDHCPSection(std::fstream& stream)
767{
768 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530769 // write the dhcp section
770 stream << "[DHCP]\n";
771
772 // Hardcoding the client identifier to mac, to address below issue
773 // https://github.com/openbmc/openbmc/issues/1280
774 stream << "ClientIdentifier=mac\n";
775 if (manager.getDHCPConf())
776 {
777 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
778 stream << "UseDNS="s + value + "\n";
779
780 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
781 stream << "UseNTP="s + value + "\n";
782
783 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
784 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600785
786 value =
787 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
788 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530789 }
790}
791
Ratan Guptabd303b12017-08-18 17:10:07 +0530792std::string EthernetInterface::mACAddress(std::string value)
793{
William A. Kennington III1137a972019-04-20 20:49:58 -0700794 ether_addr newMAC = mac_address::fromString(value);
795 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530796 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500797 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500798 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500799 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
800 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530801 }
802
William A. Kennington III1137a972019-04-20 20:49:58 -0700803 // We don't need to update the system if the address is unchanged
804 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
805 if (!equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530806 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700807 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530808 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700809 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530810 {
Alvin Wang38a63c32019-08-29 22:56:46 +0800811 auto inventoryMAC =
812 mac_address::getfromInventory(bus, interfaceName());
William A. Kennington III1137a972019-04-20 20:49:58 -0700813 if (!equal(newMAC, inventoryMAC))
814 {
815 log<level::ERR>(
816 "Given MAC address is neither a local Admin "
817 "type nor is same as in inventory");
818 elog<InvalidArgument>(
819 Argument::ARGUMENT_NAME("MACAddress"),
820 Argument::ARGUMENT_VALUE(value.c_str()));
821 }
822 }
823 catch (const std::exception& e)
824 {
825 log<level::ERR>("Exception occurred during getting of MAC "
826 "address from Inventory");
827 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530828 }
829 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700830
831 // Update everything that depends on the MAC value
832 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530833 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700834 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530835 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700836 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530837
William A. Kennington III1137a972019-04-20 20:49:58 -0700838 auto interface = interfaceName();
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700839 auto envVar = interfaceToUbootEthAddr(interface.c_str());
840 if (envVar)
841 {
842 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
843 value.c_str());
844 }
William A. Kennington III15787212019-04-23 19:18:01 -0700845 // TODO: would remove the call below and
846 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -0700847 // through https://github.com/systemd/systemd/issues/6696
848 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
849 "down");
William A. Kennington III15787212019-04-23 19:18:01 -0700850 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +0530851 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700852
853 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530854}
855
Ratan Guptae9c9b812017-09-22 17:15:37 +0530856void EthernetInterface::deleteAll()
857{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500858 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530859 {
860 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500861 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530862 }
863
864 // clear all the ip on the interface
865 addrs.clear();
866 manager.writeToConfigurationFile();
867}
868
Gunnar Mills57d9c502018-09-14 14:42:34 -0500869} // namespace network
870} // namespace phosphor