blob: 237548270218c1f2561eaa4e9b331f17c3d9df34 [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());
Johnathan Manteycb42fe22019-08-01 13:35:29 -070055 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
56
57 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
58 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Ratan Gupta6dec3902017-08-20 15:28:12 +053059
Ratan Gupta29b0e432017-05-25 12:51:40 +053060 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053061 if (emitSignal)
62 {
63 this->emit_object_added();
64 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053065}
66
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080067static IP::Protocol convertFamily(int family)
68{
69 switch (family)
70 {
71 case AF_INET:
72 return IP::Protocol::IPv4;
73 case AF_INET6:
74 return IP::Protocol::IPv6;
75 }
76
77 throw std::invalid_argument("Bad address family");
78}
79
Ratan Gupta87c13982017-06-15 09:27:27 +053080void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053081{
Ratan Gupta87c13982017-06-15 09:27:27 +053082 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053083
Ratan Gupta87c13982017-06-15 09:27:27 +053084 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053085
Ratan Gupta6a387c12017-08-03 13:26:19 +053086 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053087 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080088 IP::Protocol addressType = convertFamily(addr.addrType);
89 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053090 if (dHCPEnabled())
91 {
92 origin = IP::AddressOrigin::DHCP;
93 }
William A. Kennington III16893802019-01-30 16:01:01 -080094 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053095 {
96 origin = IP::AddressOrigin::LinkLocal;
97 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -070098 // Obsolete parameter
99 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530100
Gunnar Mills57d9c502018-09-14 14:42:34 -0500101 std::string ipAddressObjectPath = generateObjectPath(
102 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530103
Gunnar Mills57d9c502018-09-14 14:42:34 -0500104 this->addrs.emplace(addr.ipaddress,
105 std::make_shared<phosphor::network::IPAddress>(
106 bus, ipAddressObjectPath.c_str(), *this,
107 addressType, addr.ipaddress, origin,
108 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530109 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530110}
111
William A. Kennington III08505792019-01-30 16:00:04 -0800112void EthernetInterface::createStaticNeighborObjects()
113{
114 staticNeighbors.clear();
115
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700116 NeighborFilter filter;
117 filter.interface = ifIndex();
118 filter.state = NUD_PERMANENT;
119 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800120 for (const auto& neighbor : neighbors)
121 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700122 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800123 {
124 continue;
125 }
126 std::string ip = toString(neighbor.address);
127 std::string mac = mac_address::toString(*neighbor.mac);
128 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
129 staticNeighbors.emplace(ip,
130 std::make_shared<phosphor::network::Neighbor>(
131 bus, objectPath.c_str(), *this, ip, mac,
132 Neighbor::State::Permanent));
133 }
134}
135
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700136unsigned EthernetInterface::ifIndex() const
137{
138 unsigned idx = if_nametoindex(interfaceName().c_str());
139 if (idx == 0)
140 {
141 throw std::system_error(errno, std::generic_category(),
142 "if_nametoindex");
143 }
144 return idx;
145}
146
raviteja-bce379562019-03-28 05:59:36 -0500147ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
148 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530149{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530150
151 if (dHCPEnabled())
152 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530153 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500154 entry("INTERFACE=%s", interfaceName().c_str());
155 dHCPEnabled(false);
156 }
157
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500158 IP::AddressOrigin origin = IP::AddressOrigin::Static;
159
160 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
161
162 if (!isValidIP(addressFamily, ipaddress))
163 {
164 log<level::ERR>("Not a valid IP address"),
165 entry("ADDRESS=%s", ipaddress.c_str());
166 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
167 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
168 }
169
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700170 // Gateway is an obsolete parameter
171 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500172
173 if (!isValidPrefix(addressFamily, prefixLength))
174 {
175 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700176 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500177 elog<InvalidArgument>(
178 Argument::ARGUMENT_NAME("prefixLength"),
179 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530180 }
181
Gunnar Mills57d9c502018-09-14 14:42:34 -0500182 std::string objectPath =
183 generateObjectPath(protType, ipaddress, prefixLength, gateway);
184 this->addrs.emplace(ipaddress,
185 std::make_shared<phosphor::network::IPAddress>(
186 bus, objectPath.c_str(), *this, protType, ipaddress,
187 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530188
Ratan Guptae05083a2017-09-16 07:12:11 +0530189 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500190 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530191}
192
William A. Kennington III08505792019-01-30 16:00:04 -0800193ObjectPath EthernetInterface::neighbor(std::string iPAddress,
194 std::string mACAddress)
195{
196 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
197 {
198 log<level::ERR>("Not a valid IP address",
199 entry("ADDRESS=%s", iPAddress.c_str()));
200 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
201 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
202 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700203 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800204 {
205 log<level::ERR>("Not a valid MAC address",
206 entry("MACADDRESS=%s", iPAddress.c_str()));
207 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
208 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
209 }
210
211 std::string objectPath =
212 generateStaticNeighborObjectPath(iPAddress, mACAddress);
213 staticNeighbors.emplace(iPAddress,
214 std::make_shared<phosphor::network::Neighbor>(
215 bus, objectPath.c_str(), *this, iPAddress,
216 mACAddress, Neighbor::State::Permanent));
217 manager.writeToConfigurationFile();
218 return objectPath;
219}
220
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530221/*
222Note: We don't have support for ethtool now
223will enable this code once we bring the ethtool
224in the image.
225TODO: https://github.com/openbmc/openbmc/issues/1484
226*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530227
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530228InterfaceInfo EthernetInterface::getInterfaceInfo() const
229{
230 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400231 ifreq ifr{0};
232 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500233 LinkSpeed speed{0};
234 Autoneg autoneg{0};
235 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530236 do
237 {
238 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
239 if (sock < 0)
240 {
241 log<level::ERR>("socket creation failed:",
242 entry("ERROR=%s", strerror(errno)));
243 break;
244 }
245
William A. Kennington III0420c6a2019-06-27 14:38:17 -0700246 strcpy(ifr.ifr_name, interfaceName().c_str());
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530247 ifr.ifr_data = reinterpret_cast<char*>(&edata);
248
249 edata.cmd = ETHTOOL_GSET;
250
251 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
252 {
253 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
254 entry("ERROR=%s", strerror(errno)));
255 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530256 }
257 speed = edata.speed;
258 duplex = edata.duplex;
259 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500260 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530261
262 if (sock)
263 {
264 close(sock);
265 }
266 return std::make_tuple(speed, duplex, autoneg);
267}
268
269/** @brief get the mac address of the interface.
270 * @return macaddress on success
271 */
272
Gunnar Mills57d9c502018-09-14 14:42:34 -0500273std::string
274 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530275{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400276 ifreq ifr{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530277 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
278 if (sock < 0)
279 {
280 log<level::ERR>("socket creation failed:",
281 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700282 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530283 }
284
Patrick Venture836c91d2018-09-11 17:36:03 -0700285 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530286 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530287 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530288 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500289 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700290 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530291 }
292
William A. Kennington III1137a972019-04-20 20:49:58 -0700293 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
294 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
295 sizeof(ifr.ifr_hwaddr.sa_data));
296 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530297}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530298
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530299std::string EthernetInterface::generateId(const std::string& ipaddress,
300 uint8_t prefixLength,
301 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530302{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530303 std::stringstream hexId;
304 std::string hashString = ipaddress;
305 hashString += std::to_string(prefixLength);
306 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530307
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530308 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500309 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530310 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530311}
312
William A. Kennington III08505792019-01-30 16:00:04 -0800313std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
314 const std::string& mACAddress)
315{
316 std::stringstream hexId;
317 std::string hashString = iPAddress + mACAddress;
318
319 // Only want 8 hex digits.
320 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
321 return hexId.str();
322}
323
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530324void EthernetInterface::deleteObject(const std::string& ipaddress)
325{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530326 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530327 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530328 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530329 log<level::ERR>("DeleteObject:Unable to find the object.");
330 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530331 }
332 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530333 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530334}
335
William A. Kennington III08505792019-01-30 16:00:04 -0800336void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
337{
338 auto it = staticNeighbors.find(iPAddress);
339 if (it == staticNeighbors.end())
340 {
341 log<level::ERR>(
342 "DeleteStaticNeighborObject:Unable to find the object.");
343 return;
344 }
345 staticNeighbors.erase(it);
346 manager.writeToConfigurationFile();
347}
348
Ratan Guptae9c9b812017-09-22 17:15:37 +0530349void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530350{
Ratan Guptabc886292017-07-25 18:29:57 +0530351 auto confDir = manager.getConfDir();
352 fs::path networkFile = confDir;
353 networkFile /= systemd::config::networkFilePrefix + interface +
354 systemd::config::networkFileSuffix;
355
356 fs::path deviceFile = confDir;
357 deviceFile /= interface + systemd::config::deviceFileSuffix;
358
359 // delete the vlan network file
360 if (fs::is_regular_file(networkFile))
361 {
362 fs::remove(networkFile);
363 }
364
365 // delete the vlan device file
366 if (fs::is_regular_file(deviceFile))
367 {
368 fs::remove(deviceFile);
369 }
Ratan Guptabc886292017-07-25 18:29:57 +0530370
371 // TODO systemd doesn't delete the virtual network interface
372 // even after deleting all the related configuartion.
373 // https://github.com/systemd/systemd/issues/6600
374 try
375 {
376 deleteInterface(interface);
377 }
378 catch (InternalFailure& e)
379 {
380 commit<InternalFailure>();
381 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530382}
383
384void EthernetInterface::deleteVLANObject(const std::string& interface)
385{
386 auto it = vlanInterfaces.find(interface);
387 if (it == vlanInterfaces.end())
388 {
389 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500390 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530391 return;
392 }
393
394 deleteVLANFromSystem(interface);
395 // delete the interface
396 vlanInterfaces.erase(it);
397
Ratan Guptae05083a2017-09-16 07:12:11 +0530398 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530399}
400
Gunnar Mills57d9c502018-09-14 14:42:34 -0500401std::string EthernetInterface::generateObjectPath(
402 IP::Protocol addressType, const std::string& ipaddress,
403 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530404{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530405 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530406 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530407 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
408
409 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530410 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530411 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530412 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530413 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530414}
415
William A. Kennington III08505792019-01-30 16:00:04 -0800416std::string EthernetInterface::generateStaticNeighborObjectPath(
417 const std::string& iPAddress, const std::string& mACAddress) const
418{
419 std::experimental::filesystem::path objectPath;
420 objectPath /= objPath;
421 objectPath /= "static_neighbor";
422 objectPath /= generateNeighborId(iPAddress, mACAddress);
423 return objectPath.string();
424}
425
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700426bool EthernetInterface::iPv6AcceptRA(bool value)
427{
428 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
429 {
430 return value;
431 }
432 EthernetInterfaceIntf::iPv6AcceptRA(value);
433 manager.writeToConfigurationFile();
434 return value;
435}
436
Ratan Gupta87c13982017-06-15 09:27:27 +0530437bool EthernetInterface::dHCPEnabled(bool value)
438{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530439 if (value == EthernetInterfaceIntf::dHCPEnabled())
440 {
441 return value;
442 }
443
Ratan Gupta87c13982017-06-15 09:27:27 +0530444 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530445 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530446 return value;
447}
448
Ratan Gupta6dec3902017-08-20 15:28:12 +0530449ServerList EthernetInterface::nameservers(ServerList value)
450{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530451 for (const auto& nameserverip : value)
452 {
453 if (!isValidIP(AF_INET, nameserverip) &&
454 !isValidIP(AF_INET6, nameserverip))
455 {
456 log<level::ERR>("Not a valid IP address"),
457 entry("ADDRESS=%s", nameserverip.c_str());
458 elog<InvalidArgument>(
459 Argument::ARGUMENT_NAME("Nameserver"),
460 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
461 }
462 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530463 try
464 {
465 EthernetInterfaceIntf::nameservers(value);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530466 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530467 // resolved reads the DNS server configuration from the
468 // network file.
469 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530470 }
471 catch (InternalFailure& e)
472 {
473 log<level::ERR>("Exception processing DNS entries");
474 }
475 return EthernetInterfaceIntf::nameservers();
476}
477
478ServerList EthernetInterface::getNameServerFromConf()
479{
480 fs::path confPath = manager.getConfDir();
481
482 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500483 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530484 confPath /= fileName;
485 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530486 config::Parser parser(confPath.string());
487 auto rc = config::ReturnCode::SUCCESS;
488
489 std::tie(rc, servers) = parser.getValues("Network", "DNS");
490 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530491 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530492 log<level::DEBUG>("Unable to get the value for network[DNS]",
493 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530494 }
495 return servers;
496}
497
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530498void EthernetInterface::loadVLAN(VlanId id)
499{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500500 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530501 std::string path = objPath;
502 path += "_" + std::to_string(id);
503
Gunnar Mills57d9c502018-09-14 14:42:34 -0500504 auto dhcpEnabled =
505 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530506
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530507 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500508 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530509
Gunnar Mills57d9c502018-09-14 14:42:34 -0500510 // Fetch the ip address from the system
511 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530512 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800513 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530514
515 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
516 std::move(vlanIntf));
517}
518
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700519ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530520{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500521 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530522 std::string path = objPath;
523 path += "_" + std::to_string(id);
524
Ratan Gupta5978dd12017-07-25 13:47:13 +0530525 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500526 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530527
528 // write the device file for the vlan interface.
529 vlanIntf->writeDeviceFile();
530
Gunnar Mills57d9c502018-09-14 14:42:34 -0500531 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530532 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530533 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700534
535 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530536}
Ratan Gupta2b106532017-07-25 16:05:02 +0530537
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700538bool EthernetInterface::getIPv6AcceptRAFromConf()
539{
540 fs::path confPath = manager.getConfDir();
541
542 std::string fileName = systemd::config::networkFilePrefix +
543 interfaceName() + systemd::config::networkFileSuffix;
544 confPath /= fileName;
545 config::ValueList values;
546 config::Parser parser(confPath.string());
547 auto rc = config::ReturnCode::SUCCESS;
548 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
549 if (rc != config::ReturnCode::SUCCESS)
550 {
551 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
552 entry("rc=%d", rc));
553 return false;
554 }
555 return (values[0] == "true");
556}
557
Ratan Gupta497c0c92017-08-22 19:15:59 +0530558ServerList EthernetInterface::getNTPServersFromConf()
559{
560 fs::path confPath = manager.getConfDir();
561
Gunnar Mills57d9c502018-09-14 14:42:34 -0500562 std::string fileName = systemd::config::networkFilePrefix +
563 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530564 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530565
Ratan Gupta497c0c92017-08-22 19:15:59 +0530566 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530567 config::Parser parser(confPath.string());
568 auto rc = config::ReturnCode::SUCCESS;
569
570 std::tie(rc, servers) = parser.getValues("Network", "NTP");
571 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530572 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530573 log<level::DEBUG>("Unable to get the value for Network[NTP]",
574 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530575 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530576
Ratan Gupta497c0c92017-08-22 19:15:59 +0530577 return servers;
578}
579
580ServerList EthernetInterface::nTPServers(ServerList servers)
581{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500582 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530583
584 writeConfigurationFile();
585 // timesynchd reads the NTP server configuration from the
586 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530587 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530588 return ntpServers;
589}
Ratan Gupta2b106532017-07-25 16:05:02 +0530590// Need to merge the below function with the code which writes the
591// config file during factory reset.
592// TODO openbmc/openbmc#1751
593
594void EthernetInterface::writeConfigurationFile()
595{
596 // write all the static ip address in the systemd-network conf file
597
598 using namespace std::string_literals;
599 using AddressOrigin =
600 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
601 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530602
603 // if there is vlan interafce then write the configuration file
604 // for vlan also.
605
Gunnar Mills57d9c502018-09-14 14:42:34 -0500606 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530607 {
608 intf.second->writeConfigurationFile();
609 }
610
Ratan Gupta2b106532017-07-25 16:05:02 +0530611 fs::path confPath = manager.getConfDir();
612
Gunnar Mills57d9c502018-09-14 14:42:34 -0500613 std::string fileName = systemd::config::networkFilePrefix +
614 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530615 confPath /= fileName;
616 std::fstream stream;
617
618 stream.open(confPath.c_str(), std::fstream::out);
619 if (!stream.is_open())
620 {
621 log<level::ERR>("Unable to open the file",
622 entry("FILE=%s", confPath.c_str()));
623 elog<InternalFailure>();
624 }
625
626 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400627 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530628 stream << "Name=" << interfaceName() << "\n";
629
630 auto addrs = getAddresses();
631
William A. Kennington III15787212019-04-23 19:18:01 -0700632 // Write the link section
633 stream << "[Link]\n";
634 auto mac = MacAddressIntf::mACAddress();
635 if (!mac.empty())
636 {
637 stream << "MACAddress=" << mac << "\n";
638 }
639
Ratan Gupta2b106532017-07-25 16:05:02 +0530640 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400641 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400642#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500643 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400644#else
645 stream << "LinkLocalAddressing=no\n";
646#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700647 stream << std::boolalpha
648 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530649
650 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500651 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530652 {
653 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500654 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530655 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530656 // Add the NTP server
657 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
658 {
659 stream << "NTP=" << ntp << "\n";
660 }
661
662 // Add the DNS entry
663 for (const auto& dns : EthernetInterfaceIntf::nameservers())
664 {
665 stream << "DNS=" << dns << "\n";
666 }
667
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500668 // Add the DHCP entry
669 auto value = dHCPEnabled() ? "true"s : "false"s;
670 stream << "DHCP="s + value + "\n";
671
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600672 // When the interface configured as dhcp, we don't need below given entries
673 // in config file.
674 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530675 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600676 // Static
677 for (const auto& addr : addrs)
678 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400679 if (addr.second->origin() == AddressOrigin::Static
680#ifndef LINK_LOCAL_AUTOCONFIGURATION
681 || addr.second->origin() == AddressOrigin::LinkLocal
682#endif
683 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530684 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500685 std::string address =
686 addr.second->address() + "/" +
687 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530688
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600689 stream << "Address=" << address << "\n";
690 }
691 }
692
693 if (manager.getSystemConf())
694 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800695 const auto& gateway = manager.getSystemConf()->defaultGateway();
696 if (!gateway.empty())
697 {
698 stream << "Gateway=" << gateway << "\n";
699 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800700 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
701 if (!gateway6.empty())
702 {
703 stream << "Gateway=" << gateway6 << "\n";
704 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600705 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530706 }
707
William A. Kennington III08505792019-01-30 16:00:04 -0800708 // Write the neighbor sections
709 for (const auto& neighbor : staticNeighbors)
710 {
711 stream << "[Neighbor]"
712 << "\n";
713 stream << "Address=" << neighbor.second->iPAddress() << "\n";
714 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
715 }
716
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600717 // Write the dhcp section irrespective of whether DHCP is enabled or not
718 writeDHCPSection(stream);
719
Ratan Gupta2b106532017-07-25 16:05:02 +0530720 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530721}
722
723void EthernetInterface::writeDHCPSection(std::fstream& stream)
724{
725 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530726 // write the dhcp section
727 stream << "[DHCP]\n";
728
729 // Hardcoding the client identifier to mac, to address below issue
730 // https://github.com/openbmc/openbmc/issues/1280
731 stream << "ClientIdentifier=mac\n";
732 if (manager.getDHCPConf())
733 {
734 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
735 stream << "UseDNS="s + value + "\n";
736
737 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
738 stream << "UseNTP="s + value + "\n";
739
740 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
741 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600742
743 value =
744 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
745 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530746 }
747}
748
Ratan Guptabd303b12017-08-18 17:10:07 +0530749std::string EthernetInterface::mACAddress(std::string value)
750{
William A. Kennington III1137a972019-04-20 20:49:58 -0700751 ether_addr newMAC = mac_address::fromString(value);
752 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530753 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500754 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500755 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500756 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
757 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530758 }
759
William A. Kennington III1137a972019-04-20 20:49:58 -0700760 // We don't need to update the system if the address is unchanged
761 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
762 if (!equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530763 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700764 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530765 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700766 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530767 {
Alvin Wang38a63c32019-08-29 22:56:46 +0800768 auto inventoryMAC =
769 mac_address::getfromInventory(bus, interfaceName());
William A. Kennington III1137a972019-04-20 20:49:58 -0700770 if (!equal(newMAC, inventoryMAC))
771 {
772 log<level::ERR>(
773 "Given MAC address is neither a local Admin "
774 "type nor is same as in inventory");
775 elog<InvalidArgument>(
776 Argument::ARGUMENT_NAME("MACAddress"),
777 Argument::ARGUMENT_VALUE(value.c_str()));
778 }
779 }
780 catch (const std::exception& e)
781 {
782 log<level::ERR>("Exception occurred during getting of MAC "
783 "address from Inventory");
784 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530785 }
786 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700787
788 // Update everything that depends on the MAC value
789 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530790 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700791 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530792 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700793 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530794
William A. Kennington III1137a972019-04-20 20:49:58 -0700795 auto interface = interfaceName();
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700796 auto envVar = interfaceToUbootEthAddr(interface.c_str());
797 if (envVar)
798 {
799 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
800 value.c_str());
801 }
William A. Kennington III15787212019-04-23 19:18:01 -0700802 // TODO: would remove the call below and
803 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -0700804 // through https://github.com/systemd/systemd/issues/6696
805 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
806 "down");
William A. Kennington III15787212019-04-23 19:18:01 -0700807 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +0530808 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700809
810 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530811}
812
Ratan Guptae9c9b812017-09-22 17:15:37 +0530813void EthernetInterface::deleteAll()
814{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500815 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530816 {
817 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500818 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530819 }
820
821 // clear all the ip on the interface
822 addrs.clear();
823 manager.writeToConfigurationFile();
824}
825
Gunnar Mills57d9c502018-09-14 14:42:34 -0500826} // namespace network
827} // namespace phosphor