blob: 82be20ec7340d4e3f18c2ab60f37a4b545e4462d [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 Guptafc2c7242017-05-29 08:46:06 +05309#include "routing_table.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +053010#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +053011
Ratan Gupta82549cc2017-04-21 08:45:23 +053012#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053013#include <linux/ethtool.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);
Ratan Guptabd303b12017-08-18 17:10:07 +053051 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053052 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec3902017-08-20 15:28:12 +053053 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
54
Ratan Gupta29b0e432017-05-25 12:51:40 +053055 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053056 if (emitSignal)
57 {
58 this->emit_object_added();
59 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053060}
61
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080062static IP::Protocol convertFamily(int family)
63{
64 switch (family)
65 {
66 case AF_INET:
67 return IP::Protocol::IPv4;
68 case AF_INET6:
69 return IP::Protocol::IPv6;
70 }
71
72 throw std::invalid_argument("Bad address family");
73}
74
Ratan Gupta87c13982017-06-15 09:27:27 +053075void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053076{
Ratan Gupta87c13982017-06-15 09:27:27 +053077 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053078
Ratan Gupta87c13982017-06-15 09:27:27 +053079 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053080
Ratan Guptafc2c7242017-05-29 08:46:06 +053081 route::Table routingTable;
Ratan Gupta5978dd12017-07-25 13:47:13 +053082
Ratan Gupta6a387c12017-08-03 13:26:19 +053083 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053084 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080085 IP::Protocol addressType = convertFamily(addr.addrType);
86 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053087 if (dHCPEnabled())
88 {
89 origin = IP::AddressOrigin::DHCP;
90 }
William A. Kennington III16893802019-01-30 16:01:01 -080091 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053092 {
93 origin = IP::AddressOrigin::LinkLocal;
94 }
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080095 std::string gateway =
Gunnar Mills57d9c502018-09-14 14:42:34 -050096 routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
Ratan Gupta82549cc2017-04-21 08:45:23 +053097
Gunnar Mills57d9c502018-09-14 14:42:34 -050098 std::string ipAddressObjectPath = generateObjectPath(
99 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530100
Gunnar Mills57d9c502018-09-14 14:42:34 -0500101 this->addrs.emplace(addr.ipaddress,
102 std::make_shared<phosphor::network::IPAddress>(
103 bus, ipAddressObjectPath.c_str(), *this,
104 addressType, addr.ipaddress, origin,
105 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530106 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530107}
108
William A. Kennington III08505792019-01-30 16:00:04 -0800109void EthernetInterface::createStaticNeighborObjects()
110{
111 staticNeighbors.clear();
112
113 auto neighbors = getCurrentNeighbors();
114 for (const auto& neighbor : neighbors)
115 {
116 if (!neighbor.permanent || !neighbor.mac ||
117 neighbor.interface != interfaceName())
118 {
119 continue;
120 }
121 std::string ip = toString(neighbor.address);
122 std::string mac = mac_address::toString(*neighbor.mac);
123 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
124 staticNeighbors.emplace(ip,
125 std::make_shared<phosphor::network::Neighbor>(
126 bus, objectPath.c_str(), *this, ip, mac,
127 Neighbor::State::Permanent));
128 }
129}
130
raviteja-bce379562019-03-28 05:59:36 -0500131ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
132 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530133{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530134
135 if (dHCPEnabled())
136 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530137 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500138 entry("INTERFACE=%s", interfaceName().c_str());
139 dHCPEnabled(false);
140 }
141
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500142 IP::AddressOrigin origin = IP::AddressOrigin::Static;
143
144 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
145
146 if (!isValidIP(addressFamily, ipaddress))
147 {
148 log<level::ERR>("Not a valid IP address"),
149 entry("ADDRESS=%s", ipaddress.c_str());
150 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
151 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
152 }
153
154 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
155 {
156 log<level::ERR>("Not a valid Gateway"),
157 entry("GATEWAY=%s", gateway.c_str());
158 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
159 Argument::ARGUMENT_VALUE(gateway.c_str()));
160 }
161
162 if (!isValidPrefix(addressFamily, prefixLength))
163 {
164 log<level::ERR>("PrefixLength is not correct "),
165 entry("PREFIXLENGTH=%d", gateway.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500166 elog<InvalidArgument>(
167 Argument::ARGUMENT_NAME("prefixLength"),
168 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530169 }
170
Gunnar Mills57d9c502018-09-14 14:42:34 -0500171 std::string objectPath =
172 generateObjectPath(protType, ipaddress, prefixLength, gateway);
173 this->addrs.emplace(ipaddress,
174 std::make_shared<phosphor::network::IPAddress>(
175 bus, objectPath.c_str(), *this, protType, ipaddress,
176 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530177
Ratan Guptae05083a2017-09-16 07:12:11 +0530178 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500179 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530180}
181
William A. Kennington III08505792019-01-30 16:00:04 -0800182ObjectPath EthernetInterface::neighbor(std::string iPAddress,
183 std::string mACAddress)
184{
185 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
186 {
187 log<level::ERR>("Not a valid IP address",
188 entry("ADDRESS=%s", iPAddress.c_str()));
189 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
190 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
191 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700192 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800193 {
194 log<level::ERR>("Not a valid MAC address",
195 entry("MACADDRESS=%s", iPAddress.c_str()));
196 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
197 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
198 }
199
200 std::string objectPath =
201 generateStaticNeighborObjectPath(iPAddress, mACAddress);
202 staticNeighbors.emplace(iPAddress,
203 std::make_shared<phosphor::network::Neighbor>(
204 bus, objectPath.c_str(), *this, iPAddress,
205 mACAddress, Neighbor::State::Permanent));
206 manager.writeToConfigurationFile();
207 return objectPath;
208}
209
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530210/*
211Note: We don't have support for ethtool now
212will enable this code once we bring the ethtool
213in the image.
214TODO: https://github.com/openbmc/openbmc/issues/1484
215*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530216
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530217InterfaceInfo EthernetInterface::getInterfaceInfo() const
218{
219 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400220 ifreq ifr{0};
221 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500222 LinkSpeed speed{0};
223 Autoneg autoneg{0};
224 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530225 do
226 {
227 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
228 if (sock < 0)
229 {
230 log<level::ERR>("socket creation failed:",
231 entry("ERROR=%s", strerror(errno)));
232 break;
233 }
234
William A. Kennington III0420c6a2019-06-27 14:38:17 -0700235 strcpy(ifr.ifr_name, interfaceName().c_str());
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530236 ifr.ifr_data = reinterpret_cast<char*>(&edata);
237
238 edata.cmd = ETHTOOL_GSET;
239
240 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
241 {
242 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
243 entry("ERROR=%s", strerror(errno)));
244 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530245 }
246 speed = edata.speed;
247 duplex = edata.duplex;
248 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500249 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530250
251 if (sock)
252 {
253 close(sock);
254 }
255 return std::make_tuple(speed, duplex, autoneg);
256}
257
258/** @brief get the mac address of the interface.
259 * @return macaddress on success
260 */
261
Gunnar Mills57d9c502018-09-14 14:42:34 -0500262std::string
263 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530264{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400265 ifreq ifr{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530266 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
267 if (sock < 0)
268 {
269 log<level::ERR>("socket creation failed:",
270 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700271 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530272 }
273
Patrick Venture836c91d2018-09-11 17:36:03 -0700274 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530275 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530276 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530277 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500278 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700279 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530280 }
281
William A. Kennington III1137a972019-04-20 20:49:58 -0700282 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
283 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
284 sizeof(ifr.ifr_hwaddr.sa_data));
285 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530286}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530287
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530288std::string EthernetInterface::generateId(const std::string& ipaddress,
289 uint8_t prefixLength,
290 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530291{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530292 std::stringstream hexId;
293 std::string hashString = ipaddress;
294 hashString += std::to_string(prefixLength);
295 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530296
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530297 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500298 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530299 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530300}
301
William A. Kennington III08505792019-01-30 16:00:04 -0800302std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
303 const std::string& mACAddress)
304{
305 std::stringstream hexId;
306 std::string hashString = iPAddress + mACAddress;
307
308 // Only want 8 hex digits.
309 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
310 return hexId.str();
311}
312
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530313void EthernetInterface::deleteObject(const std::string& ipaddress)
314{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530315 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530316 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530317 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530318 log<level::ERR>("DeleteObject:Unable to find the object.");
319 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530320 }
321 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530322 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530323}
324
William A. Kennington III08505792019-01-30 16:00:04 -0800325void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
326{
327 auto it = staticNeighbors.find(iPAddress);
328 if (it == staticNeighbors.end())
329 {
330 log<level::ERR>(
331 "DeleteStaticNeighborObject:Unable to find the object.");
332 return;
333 }
334 staticNeighbors.erase(it);
335 manager.writeToConfigurationFile();
336}
337
Ratan Guptae9c9b812017-09-22 17:15:37 +0530338void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530339{
Ratan Guptabc886292017-07-25 18:29:57 +0530340 auto confDir = manager.getConfDir();
341 fs::path networkFile = confDir;
342 networkFile /= systemd::config::networkFilePrefix + interface +
343 systemd::config::networkFileSuffix;
344
345 fs::path deviceFile = confDir;
346 deviceFile /= interface + systemd::config::deviceFileSuffix;
347
348 // delete the vlan network file
349 if (fs::is_regular_file(networkFile))
350 {
351 fs::remove(networkFile);
352 }
353
354 // delete the vlan device file
355 if (fs::is_regular_file(deviceFile))
356 {
357 fs::remove(deviceFile);
358 }
Ratan Guptabc886292017-07-25 18:29:57 +0530359
360 // TODO systemd doesn't delete the virtual network interface
361 // even after deleting all the related configuartion.
362 // https://github.com/systemd/systemd/issues/6600
363 try
364 {
365 deleteInterface(interface);
366 }
367 catch (InternalFailure& e)
368 {
369 commit<InternalFailure>();
370 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530371}
372
373void EthernetInterface::deleteVLANObject(const std::string& interface)
374{
375 auto it = vlanInterfaces.find(interface);
376 if (it == vlanInterfaces.end())
377 {
378 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500379 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530380 return;
381 }
382
383 deleteVLANFromSystem(interface);
384 // delete the interface
385 vlanInterfaces.erase(it);
386
Ratan Guptae05083a2017-09-16 07:12:11 +0530387 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530388}
389
Gunnar Mills57d9c502018-09-14 14:42:34 -0500390std::string EthernetInterface::generateObjectPath(
391 IP::Protocol addressType, const std::string& ipaddress,
392 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530393{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530394 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530395 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530396 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
397
398 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530399 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530400 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530401 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530402 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530403}
404
William A. Kennington III08505792019-01-30 16:00:04 -0800405std::string EthernetInterface::generateStaticNeighborObjectPath(
406 const std::string& iPAddress, const std::string& mACAddress) const
407{
408 std::experimental::filesystem::path objectPath;
409 objectPath /= objPath;
410 objectPath /= "static_neighbor";
411 objectPath /= generateNeighborId(iPAddress, mACAddress);
412 return objectPath.string();
413}
414
Ratan Gupta87c13982017-06-15 09:27:27 +0530415bool EthernetInterface::dHCPEnabled(bool value)
416{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530417 if (value == EthernetInterfaceIntf::dHCPEnabled())
418 {
419 return value;
420 }
421
Ratan Gupta87c13982017-06-15 09:27:27 +0530422 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530423 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530424 return value;
425}
426
Ratan Gupta6dec3902017-08-20 15:28:12 +0530427ServerList EthernetInterface::nameservers(ServerList value)
428{
429 try
430 {
431 EthernetInterfaceIntf::nameservers(value);
432
433 writeConfigurationFile();
434
435 // Currently we don't have systemd-resolved enabled
436 // in the openbmc. Once we update the network conf file,
437 // it should be read by systemd-resolved.service.
438
439 // The other reason to write the resolv conf is,
440 // we don't want to restart the networkd for nameserver change.
441 // as restarting of systemd-networkd takes more then 2 secs
442 writeDNSEntries(value, resolvConfFile);
443 }
444 catch (InternalFailure& e)
445 {
446 log<level::ERR>("Exception processing DNS entries");
447 }
448 return EthernetInterfaceIntf::nameservers();
449}
450
451ServerList EthernetInterface::getNameServerFromConf()
452{
453 fs::path confPath = manager.getConfDir();
454
455 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500456 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530457 confPath /= fileName;
458 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530459 config::Parser parser(confPath.string());
460 auto rc = config::ReturnCode::SUCCESS;
461
462 std::tie(rc, servers) = parser.getValues("Network", "DNS");
463 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530464 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530465 log<level::DEBUG>("Unable to get the value for network[DNS]",
466 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530467 }
468 return servers;
469}
470
471void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
472 const std::string& file)
473{
474 std::fstream outStream(file, std::fstream::out);
475 if (!outStream.is_open())
476 {
477 log<level::ERR>("Unable to open the file",
478 entry("FILE=%s", file.c_str()));
479 elog<InternalFailure>();
480 }
481
Ratan Guptafe116912017-11-10 16:00:59 +0530482 outStream << "### Generated manually via dbus settings ###\n";
Gunnar Mills57d9c502018-09-14 14:42:34 -0500483 for (const auto& server : dnsList)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530484 {
485 outStream << "nameserver " << server << "\n";
486 }
487}
488
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530489void EthernetInterface::loadVLAN(VlanId id)
490{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500491 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530492 std::string path = objPath;
493 path += "_" + std::to_string(id);
494
Gunnar Mills57d9c502018-09-14 14:42:34 -0500495 auto dhcpEnabled =
496 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530497
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530498 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500499 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530500
Gunnar Mills57d9c502018-09-14 14:42:34 -0500501 // Fetch the ip address from the system
502 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530503 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800504 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530505
506 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
507 std::move(vlanIntf));
508}
509
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700510ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530511{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500512 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530513 std::string path = objPath;
514 path += "_" + std::to_string(id);
515
Ratan Gupta5978dd12017-07-25 13:47:13 +0530516 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500517 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530518
519 // write the device file for the vlan interface.
520 vlanIntf->writeDeviceFile();
521
Gunnar Mills57d9c502018-09-14 14:42:34 -0500522 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530523 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530524 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700525
526 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530527}
Ratan Gupta2b106532017-07-25 16:05:02 +0530528
Ratan Gupta497c0c92017-08-22 19:15:59 +0530529ServerList EthernetInterface::getNTPServersFromConf()
530{
531 fs::path confPath = manager.getConfDir();
532
Gunnar Mills57d9c502018-09-14 14:42:34 -0500533 std::string fileName = systemd::config::networkFilePrefix +
534 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530535 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530536
Ratan Gupta497c0c92017-08-22 19:15:59 +0530537 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530538 config::Parser parser(confPath.string());
539 auto rc = config::ReturnCode::SUCCESS;
540
541 std::tie(rc, servers) = parser.getValues("Network", "NTP");
542 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530543 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530544 log<level::DEBUG>("Unable to get the value for Network[NTP]",
545 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530546 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530547
Ratan Gupta497c0c92017-08-22 19:15:59 +0530548 return servers;
549}
550
551ServerList EthernetInterface::nTPServers(ServerList servers)
552{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500553 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530554
555 writeConfigurationFile();
556 // timesynchd reads the NTP server configuration from the
557 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530558 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530559 return ntpServers;
560}
Ratan Gupta2b106532017-07-25 16:05:02 +0530561// Need to merge the below function with the code which writes the
562// config file during factory reset.
563// TODO openbmc/openbmc#1751
564
565void EthernetInterface::writeConfigurationFile()
566{
567 // write all the static ip address in the systemd-network conf file
568
569 using namespace std::string_literals;
570 using AddressOrigin =
571 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
572 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530573
574 // if there is vlan interafce then write the configuration file
575 // for vlan also.
576
Gunnar Mills57d9c502018-09-14 14:42:34 -0500577 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530578 {
579 intf.second->writeConfigurationFile();
580 }
581
Ratan Gupta2b106532017-07-25 16:05:02 +0530582 fs::path confPath = manager.getConfDir();
583
Gunnar Mills57d9c502018-09-14 14:42:34 -0500584 std::string fileName = systemd::config::networkFilePrefix +
585 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530586 confPath /= fileName;
587 std::fstream stream;
588
589 stream.open(confPath.c_str(), std::fstream::out);
590 if (!stream.is_open())
591 {
592 log<level::ERR>("Unable to open the file",
593 entry("FILE=%s", confPath.c_str()));
594 elog<InternalFailure>();
595 }
596
597 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400598 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530599 stream << "Name=" << interfaceName() << "\n";
600
601 auto addrs = getAddresses();
602
603 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400604 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400605#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500606 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400607#else
608 stream << "LinkLocalAddressing=no\n";
609#endif
Ratan Guptae9629412017-12-21 08:20:25 +0530610 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530611
612 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500613 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530614 {
615 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500616 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530617 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500618 // Add the DHCP entry
619 auto value = dHCPEnabled() ? "true"s : "false"s;
620 stream << "DHCP="s + value + "\n";
621
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600622 // When the interface configured as dhcp, we don't need below given entries
623 // in config file.
624 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530625 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500626 // Add the NTP server
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600627 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530628 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600629 stream << "NTP=" << ntp << "\n";
630 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530631
Gunnar Mills57d9c502018-09-14 14:42:34 -0500632 // Add the DNS entry
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600633 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530634 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600635 stream << "DNS=" << dns << "\n";
636 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530637
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600638 // Static
639 for (const auto& addr : addrs)
640 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400641 if (addr.second->origin() == AddressOrigin::Static
642#ifndef LINK_LOCAL_AUTOCONFIGURATION
643 || addr.second->origin() == AddressOrigin::LinkLocal
644#endif
645 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530646 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500647 std::string address =
648 addr.second->address() + "/" +
649 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530650
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600651 stream << "Address=" << address << "\n";
652 }
653 }
654
655 if (manager.getSystemConf())
656 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800657 const auto& gateway = manager.getSystemConf()->defaultGateway();
658 if (!gateway.empty())
659 {
660 stream << "Gateway=" << gateway << "\n";
661 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800662 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
663 if (!gateway6.empty())
664 {
665 stream << "Gateway=" << gateway6 << "\n";
666 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600667 }
668
669 // write the route section
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600670 for (const auto& addr : addrs)
671 {
672 if (addr.second->origin() == AddressOrigin::Static)
673 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500674 int addressFamily = addr.second->type() == IP::Protocol::IPv4
675 ? AF_INET
676 : AF_INET6;
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600677
Gunnar Mills57d9c502018-09-14 14:42:34 -0500678 std::string destination =
679 getNetworkID(addressFamily, addr.second->address(),
680 addr.second->prefixLength());
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600681
682 if (addr.second->gateway() != "0.0.0.0" &&
Gunnar Mills57d9c502018-09-14 14:42:34 -0500683 addr.second->gateway() != "" && destination != "0.0.0.0" &&
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600684 destination != "")
685 {
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400686 stream << "[Route]\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600687 stream << "Gateway=" << addr.second->gateway() << "\n";
688 stream << "Destination=" << destination << "\n";
689 }
690 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530691 }
692 }
693
William A. Kennington III08505792019-01-30 16:00:04 -0800694 // Write the neighbor sections
695 for (const auto& neighbor : staticNeighbors)
696 {
697 stream << "[Neighbor]"
698 << "\n";
699 stream << "Address=" << neighbor.second->iPAddress() << "\n";
700 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
701 }
702
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600703 // Write the dhcp section irrespective of whether DHCP is enabled or not
704 writeDHCPSection(stream);
705
Ratan Gupta2b106532017-07-25 16:05:02 +0530706 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530707}
708
709void EthernetInterface::writeDHCPSection(std::fstream& stream)
710{
711 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530712 // write the dhcp section
713 stream << "[DHCP]\n";
714
715 // Hardcoding the client identifier to mac, to address below issue
716 // https://github.com/openbmc/openbmc/issues/1280
717 stream << "ClientIdentifier=mac\n";
718 if (manager.getDHCPConf())
719 {
720 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
721 stream << "UseDNS="s + value + "\n";
722
723 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
724 stream << "UseNTP="s + value + "\n";
725
726 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
727 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600728
729 value =
730 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
731 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530732 }
733}
734
Ratan Guptabd303b12017-08-18 17:10:07 +0530735std::string EthernetInterface::mACAddress(std::string value)
736{
William A. Kennington III1137a972019-04-20 20:49:58 -0700737 ether_addr newMAC = mac_address::fromString(value);
738 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530739 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500740 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500741 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500742 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
743 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530744 }
745
William A. Kennington III1137a972019-04-20 20:49:58 -0700746 // We don't need to update the system if the address is unchanged
747 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
748 if (!equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530749 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700750 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530751 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700752 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530753 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700754 auto inventoryMAC = mac_address::getfromInventory(bus);
755 if (!equal(newMAC, inventoryMAC))
756 {
757 log<level::ERR>(
758 "Given MAC address is neither a local Admin "
759 "type nor is same as in inventory");
760 elog<InvalidArgument>(
761 Argument::ARGUMENT_NAME("MACAddress"),
762 Argument::ARGUMENT_VALUE(value.c_str()));
763 }
764 }
765 catch (const std::exception& e)
766 {
767 log<level::ERR>("Exception occurred during getting of MAC "
768 "address from Inventory");
769 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530770 }
771 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700772
773 // Update everything that depends on the MAC value
774 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530775 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700776 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530777 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700778 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530779
William A. Kennington III1137a972019-04-20 20:49:58 -0700780 auto interface = interfaceName();
781 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
782 // TODO: would replace below three calls
783 // with restarting of systemd-netwokd
784 // through https://github.com/systemd/systemd/issues/6696
785 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
786 "down");
787 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
788 "address", value.c_str());
789 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
790 "up");
Ratan Gupta895f9e52018-11-26 20:57:34 +0530791 manager.restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530792 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700793
794 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530795}
796
Ratan Guptae9c9b812017-09-22 17:15:37 +0530797void EthernetInterface::deleteAll()
798{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500799 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530800 {
801 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500802 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530803 }
804
805 // clear all the ip on the interface
806 addrs.clear();
807 manager.writeToConfigurationFile();
808}
809
Gunnar Mills57d9c502018-09-14 14:42:34 -0500810} // namespace network
811} // namespace phosphor