blob: 8781494d019efd12f37bcd0afadb9dde7e699747 [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
Ratan Gupta91a99cc2017-04-14 16:32:09 +053040EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
41 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053043 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050044 Ifaces(bus, objPath.c_str(), true),
45 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053046{
47 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053048 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053049 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053050 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Johnathan Mantey5b023f52019-06-24 16:06:37 -070051 EthernetInterfaceIntf::iPv6AcceptRA(getIPv6AcceptRAFromConf());
Ratan Guptabd303b12017-08-18 17:10:07 +053052 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053053 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec3902017-08-20 15:28:12 +053054 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
55
Ratan Gupta29b0e432017-05-25 12:51:40 +053056 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053057 if (emitSignal)
58 {
59 this->emit_object_added();
60 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053061}
62
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080063static IP::Protocol convertFamily(int family)
64{
65 switch (family)
66 {
67 case AF_INET:
68 return IP::Protocol::IPv4;
69 case AF_INET6:
70 return IP::Protocol::IPv6;
71 }
72
73 throw std::invalid_argument("Bad address family");
74}
75
Ratan Gupta87c13982017-06-15 09:27:27 +053076void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053077{
Ratan Gupta87c13982017-06-15 09:27:27 +053078 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053079
Ratan Gupta87c13982017-06-15 09:27:27 +053080 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053081
Ratan Gupta6a387c12017-08-03 13:26:19 +053082 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053083 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080084 IP::Protocol addressType = convertFamily(addr.addrType);
85 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053086 if (dHCPEnabled())
87 {
88 origin = IP::AddressOrigin::DHCP;
89 }
William A. Kennington III16893802019-01-30 16:01:01 -080090 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053091 {
92 origin = IP::AddressOrigin::LinkLocal;
93 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -070094 // Obsolete parameter
95 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +053096
Gunnar Mills57d9c502018-09-14 14:42:34 -050097 std::string ipAddressObjectPath = generateObjectPath(
98 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +053099
Gunnar Mills57d9c502018-09-14 14:42:34 -0500100 this->addrs.emplace(addr.ipaddress,
101 std::make_shared<phosphor::network::IPAddress>(
102 bus, ipAddressObjectPath.c_str(), *this,
103 addressType, addr.ipaddress, origin,
104 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530105 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530106}
107
William A. Kennington III08505792019-01-30 16:00:04 -0800108void EthernetInterface::createStaticNeighborObjects()
109{
110 staticNeighbors.clear();
111
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700112 NeighborFilter filter;
113 filter.interface = ifIndex();
114 filter.state = NUD_PERMANENT;
115 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800116 for (const auto& neighbor : neighbors)
117 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700118 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800119 {
120 continue;
121 }
122 std::string ip = toString(neighbor.address);
123 std::string mac = mac_address::toString(*neighbor.mac);
124 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
125 staticNeighbors.emplace(ip,
126 std::make_shared<phosphor::network::Neighbor>(
127 bus, objectPath.c_str(), *this, ip, mac,
128 Neighbor::State::Permanent));
129 }
130}
131
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700132unsigned EthernetInterface::ifIndex() const
133{
134 unsigned idx = if_nametoindex(interfaceName().c_str());
135 if (idx == 0)
136 {
137 throw std::system_error(errno, std::generic_category(),
138 "if_nametoindex");
139 }
140 return idx;
141}
142
raviteja-bce379562019-03-28 05:59:36 -0500143ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
144 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530145{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530146
147 if (dHCPEnabled())
148 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530149 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500150 entry("INTERFACE=%s", interfaceName().c_str());
151 dHCPEnabled(false);
152 }
153
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500154 IP::AddressOrigin origin = IP::AddressOrigin::Static;
155
156 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
157
158 if (!isValidIP(addressFamily, ipaddress))
159 {
160 log<level::ERR>("Not a valid IP address"),
161 entry("ADDRESS=%s", ipaddress.c_str());
162 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
163 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
164 }
165
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700166 // Gateway is an obsolete parameter
167 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500168
169 if (!isValidPrefix(addressFamily, prefixLength))
170 {
171 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700172 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500173 elog<InvalidArgument>(
174 Argument::ARGUMENT_NAME("prefixLength"),
175 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530176 }
177
Gunnar Mills57d9c502018-09-14 14:42:34 -0500178 std::string objectPath =
179 generateObjectPath(protType, ipaddress, prefixLength, gateway);
180 this->addrs.emplace(ipaddress,
181 std::make_shared<phosphor::network::IPAddress>(
182 bus, objectPath.c_str(), *this, protType, ipaddress,
183 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530184
Ratan Guptae05083a2017-09-16 07:12:11 +0530185 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500186 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530187}
188
William A. Kennington III08505792019-01-30 16:00:04 -0800189ObjectPath EthernetInterface::neighbor(std::string iPAddress,
190 std::string mACAddress)
191{
192 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
193 {
194 log<level::ERR>("Not a valid IP address",
195 entry("ADDRESS=%s", iPAddress.c_str()));
196 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
197 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
198 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700199 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800200 {
201 log<level::ERR>("Not a valid MAC address",
202 entry("MACADDRESS=%s", iPAddress.c_str()));
203 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
204 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
205 }
206
207 std::string objectPath =
208 generateStaticNeighborObjectPath(iPAddress, mACAddress);
209 staticNeighbors.emplace(iPAddress,
210 std::make_shared<phosphor::network::Neighbor>(
211 bus, objectPath.c_str(), *this, iPAddress,
212 mACAddress, Neighbor::State::Permanent));
213 manager.writeToConfigurationFile();
214 return objectPath;
215}
216
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530217/*
218Note: We don't have support for ethtool now
219will enable this code once we bring the ethtool
220in the image.
221TODO: https://github.com/openbmc/openbmc/issues/1484
222*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530223
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530224InterfaceInfo EthernetInterface::getInterfaceInfo() const
225{
226 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400227 ifreq ifr{0};
228 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500229 LinkSpeed speed{0};
230 Autoneg autoneg{0};
231 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530232 do
233 {
234 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
235 if (sock < 0)
236 {
237 log<level::ERR>("socket creation failed:",
238 entry("ERROR=%s", strerror(errno)));
239 break;
240 }
241
William A. Kennington III0420c6a2019-06-27 14:38:17 -0700242 strcpy(ifr.ifr_name, interfaceName().c_str());
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530243 ifr.ifr_data = reinterpret_cast<char*>(&edata);
244
245 edata.cmd = ETHTOOL_GSET;
246
247 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
248 {
249 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
250 entry("ERROR=%s", strerror(errno)));
251 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530252 }
253 speed = edata.speed;
254 duplex = edata.duplex;
255 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500256 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530257
258 if (sock)
259 {
260 close(sock);
261 }
262 return std::make_tuple(speed, duplex, autoneg);
263}
264
265/** @brief get the mac address of the interface.
266 * @return macaddress on success
267 */
268
Gunnar Mills57d9c502018-09-14 14:42:34 -0500269std::string
270 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530271{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400272 ifreq ifr{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530273 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
274 if (sock < 0)
275 {
276 log<level::ERR>("socket creation failed:",
277 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700278 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530279 }
280
Patrick Venture836c91d2018-09-11 17:36:03 -0700281 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530282 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530283 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530284 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500285 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700286 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530287 }
288
William A. Kennington III1137a972019-04-20 20:49:58 -0700289 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
290 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
291 sizeof(ifr.ifr_hwaddr.sa_data));
292 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530293}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530294
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530295std::string EthernetInterface::generateId(const std::string& ipaddress,
296 uint8_t prefixLength,
297 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530298{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530299 std::stringstream hexId;
300 std::string hashString = ipaddress;
301 hashString += std::to_string(prefixLength);
302 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530303
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530304 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500305 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530306 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530307}
308
William A. Kennington III08505792019-01-30 16:00:04 -0800309std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
310 const std::string& mACAddress)
311{
312 std::stringstream hexId;
313 std::string hashString = iPAddress + mACAddress;
314
315 // Only want 8 hex digits.
316 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
317 return hexId.str();
318}
319
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530320void EthernetInterface::deleteObject(const std::string& ipaddress)
321{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530322 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530323 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530324 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530325 log<level::ERR>("DeleteObject:Unable to find the object.");
326 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530327 }
328 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530329 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530330}
331
William A. Kennington III08505792019-01-30 16:00:04 -0800332void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
333{
334 auto it = staticNeighbors.find(iPAddress);
335 if (it == staticNeighbors.end())
336 {
337 log<level::ERR>(
338 "DeleteStaticNeighborObject:Unable to find the object.");
339 return;
340 }
341 staticNeighbors.erase(it);
342 manager.writeToConfigurationFile();
343}
344
Ratan Guptae9c9b812017-09-22 17:15:37 +0530345void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530346{
Ratan Guptabc886292017-07-25 18:29:57 +0530347 auto confDir = manager.getConfDir();
348 fs::path networkFile = confDir;
349 networkFile /= systemd::config::networkFilePrefix + interface +
350 systemd::config::networkFileSuffix;
351
352 fs::path deviceFile = confDir;
353 deviceFile /= interface + systemd::config::deviceFileSuffix;
354
355 // delete the vlan network file
356 if (fs::is_regular_file(networkFile))
357 {
358 fs::remove(networkFile);
359 }
360
361 // delete the vlan device file
362 if (fs::is_regular_file(deviceFile))
363 {
364 fs::remove(deviceFile);
365 }
Ratan Guptabc886292017-07-25 18:29:57 +0530366
367 // TODO systemd doesn't delete the virtual network interface
368 // even after deleting all the related configuartion.
369 // https://github.com/systemd/systemd/issues/6600
370 try
371 {
372 deleteInterface(interface);
373 }
374 catch (InternalFailure& e)
375 {
376 commit<InternalFailure>();
377 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530378}
379
380void EthernetInterface::deleteVLANObject(const std::string& interface)
381{
382 auto it = vlanInterfaces.find(interface);
383 if (it == vlanInterfaces.end())
384 {
385 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500386 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530387 return;
388 }
389
390 deleteVLANFromSystem(interface);
391 // delete the interface
392 vlanInterfaces.erase(it);
393
Ratan Guptae05083a2017-09-16 07:12:11 +0530394 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530395}
396
Gunnar Mills57d9c502018-09-14 14:42:34 -0500397std::string EthernetInterface::generateObjectPath(
398 IP::Protocol addressType, const std::string& ipaddress,
399 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530400{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530401 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530402 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530403 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
404
405 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530406 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530407 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530408 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530409 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530410}
411
William A. Kennington III08505792019-01-30 16:00:04 -0800412std::string EthernetInterface::generateStaticNeighborObjectPath(
413 const std::string& iPAddress, const std::string& mACAddress) const
414{
415 std::experimental::filesystem::path objectPath;
416 objectPath /= objPath;
417 objectPath /= "static_neighbor";
418 objectPath /= generateNeighborId(iPAddress, mACAddress);
419 return objectPath.string();
420}
421
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700422bool EthernetInterface::iPv6AcceptRA(bool value)
423{
424 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
425 {
426 return value;
427 }
428 EthernetInterfaceIntf::iPv6AcceptRA(value);
429 manager.writeToConfigurationFile();
430 return value;
431}
432
Ratan Gupta87c13982017-06-15 09:27:27 +0530433bool EthernetInterface::dHCPEnabled(bool value)
434{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530435 if (value == EthernetInterfaceIntf::dHCPEnabled())
436 {
437 return value;
438 }
439
Ratan Gupta87c13982017-06-15 09:27:27 +0530440 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530441 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530442 return value;
443}
444
Ratan Gupta6dec3902017-08-20 15:28:12 +0530445ServerList EthernetInterface::nameservers(ServerList value)
446{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530447 for (const auto& nameserverip : value)
448 {
449 if (!isValidIP(AF_INET, nameserverip) &&
450 !isValidIP(AF_INET6, nameserverip))
451 {
452 log<level::ERR>("Not a valid IP address"),
453 entry("ADDRESS=%s", nameserverip.c_str());
454 elog<InvalidArgument>(
455 Argument::ARGUMENT_NAME("Nameserver"),
456 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
457 }
458 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530459 try
460 {
461 EthernetInterfaceIntf::nameservers(value);
462
463 writeConfigurationFile();
464
465 // Currently we don't have systemd-resolved enabled
466 // in the openbmc. Once we update the network conf file,
467 // it should be read by systemd-resolved.service.
468
469 // The other reason to write the resolv conf is,
470 // we don't want to restart the networkd for nameserver change.
471 // as restarting of systemd-networkd takes more then 2 secs
472 writeDNSEntries(value, resolvConfFile);
473 }
474 catch (InternalFailure& e)
475 {
476 log<level::ERR>("Exception processing DNS entries");
477 }
478 return EthernetInterfaceIntf::nameservers();
479}
480
481ServerList EthernetInterface::getNameServerFromConf()
482{
483 fs::path confPath = manager.getConfDir();
484
485 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500486 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530487 confPath /= fileName;
488 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530489 config::Parser parser(confPath.string());
490 auto rc = config::ReturnCode::SUCCESS;
491
492 std::tie(rc, servers) = parser.getValues("Network", "DNS");
493 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530494 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530495 log<level::DEBUG>("Unable to get the value for network[DNS]",
496 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530497 }
498 return servers;
499}
500
501void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
502 const std::string& file)
503{
504 std::fstream outStream(file, std::fstream::out);
505 if (!outStream.is_open())
506 {
507 log<level::ERR>("Unable to open the file",
508 entry("FILE=%s", file.c_str()));
509 elog<InternalFailure>();
510 }
511
Ratan Guptafe116912017-11-10 16:00:59 +0530512 outStream << "### Generated manually via dbus settings ###\n";
Gunnar Mills57d9c502018-09-14 14:42:34 -0500513 for (const auto& server : dnsList)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530514 {
515 outStream << "nameserver " << server << "\n";
516 }
517}
518
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530519void EthernetInterface::loadVLAN(VlanId id)
520{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500521 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530522 std::string path = objPath;
523 path += "_" + std::to_string(id);
524
Gunnar Mills57d9c502018-09-14 14:42:34 -0500525 auto dhcpEnabled =
526 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530527
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530528 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500529 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530530
Gunnar Mills57d9c502018-09-14 14:42:34 -0500531 // Fetch the ip address from the system
532 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530533 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800534 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530535
536 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
537 std::move(vlanIntf));
538}
539
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700540ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530541{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500542 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530543 std::string path = objPath;
544 path += "_" + std::to_string(id);
545
Ratan Gupta5978dd12017-07-25 13:47:13 +0530546 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500547 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530548
549 // write the device file for the vlan interface.
550 vlanIntf->writeDeviceFile();
551
Gunnar Mills57d9c502018-09-14 14:42:34 -0500552 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530553 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530554 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700555
556 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530557}
Ratan Gupta2b106532017-07-25 16:05:02 +0530558
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700559bool EthernetInterface::getIPv6AcceptRAFromConf()
560{
561 fs::path confPath = manager.getConfDir();
562
563 std::string fileName = systemd::config::networkFilePrefix +
564 interfaceName() + systemd::config::networkFileSuffix;
565 confPath /= fileName;
566 config::ValueList values;
567 config::Parser parser(confPath.string());
568 auto rc = config::ReturnCode::SUCCESS;
569 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
570 if (rc != config::ReturnCode::SUCCESS)
571 {
572 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
573 entry("rc=%d", rc));
574 return false;
575 }
576 return (values[0] == "true");
577}
578
Ratan Gupta497c0c92017-08-22 19:15:59 +0530579ServerList EthernetInterface::getNTPServersFromConf()
580{
581 fs::path confPath = manager.getConfDir();
582
Gunnar Mills57d9c502018-09-14 14:42:34 -0500583 std::string fileName = systemd::config::networkFilePrefix +
584 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530585 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530586
Ratan Gupta497c0c92017-08-22 19:15:59 +0530587 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530588 config::Parser parser(confPath.string());
589 auto rc = config::ReturnCode::SUCCESS;
590
591 std::tie(rc, servers) = parser.getValues("Network", "NTP");
592 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530593 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530594 log<level::DEBUG>("Unable to get the value for Network[NTP]",
595 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530596 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530597
Ratan Gupta497c0c92017-08-22 19:15:59 +0530598 return servers;
599}
600
601ServerList EthernetInterface::nTPServers(ServerList servers)
602{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500603 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530604
605 writeConfigurationFile();
606 // timesynchd reads the NTP server configuration from the
607 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530608 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530609 return ntpServers;
610}
Ratan Gupta2b106532017-07-25 16:05:02 +0530611// Need to merge the below function with the code which writes the
612// config file during factory reset.
613// TODO openbmc/openbmc#1751
614
615void EthernetInterface::writeConfigurationFile()
616{
617 // write all the static ip address in the systemd-network conf file
618
619 using namespace std::string_literals;
620 using AddressOrigin =
621 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
622 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530623
624 // if there is vlan interafce then write the configuration file
625 // for vlan also.
626
Gunnar Mills57d9c502018-09-14 14:42:34 -0500627 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530628 {
629 intf.second->writeConfigurationFile();
630 }
631
Ratan Gupta2b106532017-07-25 16:05:02 +0530632 fs::path confPath = manager.getConfDir();
633
Gunnar Mills57d9c502018-09-14 14:42:34 -0500634 std::string fileName = systemd::config::networkFilePrefix +
635 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530636 confPath /= fileName;
637 std::fstream stream;
638
639 stream.open(confPath.c_str(), std::fstream::out);
640 if (!stream.is_open())
641 {
642 log<level::ERR>("Unable to open the file",
643 entry("FILE=%s", confPath.c_str()));
644 elog<InternalFailure>();
645 }
646
647 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400648 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530649 stream << "Name=" << interfaceName() << "\n";
650
651 auto addrs = getAddresses();
652
William A. Kennington III15787212019-04-23 19:18:01 -0700653 // Write the link section
654 stream << "[Link]\n";
655 auto mac = MacAddressIntf::mACAddress();
656 if (!mac.empty())
657 {
658 stream << "MACAddress=" << mac << "\n";
659 }
660
Ratan Gupta2b106532017-07-25 16:05:02 +0530661 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400662 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400663#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500664 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400665#else
666 stream << "LinkLocalAddressing=no\n";
667#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700668 stream << std::boolalpha
669 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530670
671 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500672 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530673 {
674 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500675 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530676 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500677 // Add the DHCP entry
678 auto value = dHCPEnabled() ? "true"s : "false"s;
679 stream << "DHCP="s + value + "\n";
680
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600681 // When the interface configured as dhcp, we don't need below given entries
682 // in config file.
683 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530684 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500685 // Add the NTP server
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600686 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530687 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600688 stream << "NTP=" << ntp << "\n";
689 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530690
Gunnar Mills57d9c502018-09-14 14:42:34 -0500691 // Add the DNS entry
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600692 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530693 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600694 stream << "DNS=" << dns << "\n";
695 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530696
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600697 // Static
698 for (const auto& addr : addrs)
699 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400700 if (addr.second->origin() == AddressOrigin::Static
701#ifndef LINK_LOCAL_AUTOCONFIGURATION
702 || addr.second->origin() == AddressOrigin::LinkLocal
703#endif
704 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530705 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500706 std::string address =
707 addr.second->address() + "/" +
708 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530709
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600710 stream << "Address=" << address << "\n";
711 }
712 }
713
714 if (manager.getSystemConf())
715 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800716 const auto& gateway = manager.getSystemConf()->defaultGateway();
717 if (!gateway.empty())
718 {
719 stream << "Gateway=" << gateway << "\n";
720 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800721 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
722 if (!gateway6.empty())
723 {
724 stream << "Gateway=" << gateway6 << "\n";
725 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600726 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530727 }
728
William A. Kennington III08505792019-01-30 16:00:04 -0800729 // Write the neighbor sections
730 for (const auto& neighbor : staticNeighbors)
731 {
732 stream << "[Neighbor]"
733 << "\n";
734 stream << "Address=" << neighbor.second->iPAddress() << "\n";
735 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
736 }
737
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600738 // Write the dhcp section irrespective of whether DHCP is enabled or not
739 writeDHCPSection(stream);
740
Ratan Gupta2b106532017-07-25 16:05:02 +0530741 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530742}
743
744void EthernetInterface::writeDHCPSection(std::fstream& stream)
745{
746 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530747 // write the dhcp section
748 stream << "[DHCP]\n";
749
750 // Hardcoding the client identifier to mac, to address below issue
751 // https://github.com/openbmc/openbmc/issues/1280
752 stream << "ClientIdentifier=mac\n";
753 if (manager.getDHCPConf())
754 {
755 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
756 stream << "UseDNS="s + value + "\n";
757
758 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
759 stream << "UseNTP="s + value + "\n";
760
761 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
762 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600763
764 value =
765 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
766 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530767 }
768}
769
Ratan Guptabd303b12017-08-18 17:10:07 +0530770std::string EthernetInterface::mACAddress(std::string value)
771{
William A. Kennington III1137a972019-04-20 20:49:58 -0700772 ether_addr newMAC = mac_address::fromString(value);
773 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530774 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500775 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500776 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500777 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
778 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530779 }
780
William A. Kennington III1137a972019-04-20 20:49:58 -0700781 // We don't need to update the system if the address is unchanged
782 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
783 if (!equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530784 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700785 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530786 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700787 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530788 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700789 auto inventoryMAC = mac_address::getfromInventory(bus);
790 if (!equal(newMAC, inventoryMAC))
791 {
792 log<level::ERR>(
793 "Given MAC address is neither a local Admin "
794 "type nor is same as in inventory");
795 elog<InvalidArgument>(
796 Argument::ARGUMENT_NAME("MACAddress"),
797 Argument::ARGUMENT_VALUE(value.c_str()));
798 }
799 }
800 catch (const std::exception& e)
801 {
802 log<level::ERR>("Exception occurred during getting of MAC "
803 "address from Inventory");
804 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530805 }
806 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700807
808 // Update everything that depends on the MAC value
809 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530810 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700811 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530812 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700813 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530814
William A. Kennington III1137a972019-04-20 20:49:58 -0700815 auto interface = interfaceName();
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700816 auto envVar = interfaceToUbootEthAddr(interface.c_str());
817 if (envVar)
818 {
819 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
820 value.c_str());
821 }
William A. Kennington III15787212019-04-23 19:18:01 -0700822 // TODO: would remove the call below and
823 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -0700824 // through https://github.com/systemd/systemd/issues/6696
825 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
826 "down");
William A. Kennington III15787212019-04-23 19:18:01 -0700827 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +0530828 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700829
830 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530831}
832
Ratan Guptae9c9b812017-09-22 17:15:37 +0530833void EthernetInterface::deleteAll()
834{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500835 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530836 {
837 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500838 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530839 }
840
841 // clear all the ip on the interface
842 addrs.clear();
843 manager.writeToConfigurationFile();
844}
845
Gunnar Mills57d9c502018-09-14 14:42:34 -0500846} // namespace network
847} // namespace phosphor