blob: 92ba2cc6407e77b2a1129e0a6f3b9b8767865612 [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>
Patrick Venture189d44e2018-07-09 12:30:59 -070028#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053029
Ratan Gupta91a99cc2017-04-14 16:32:09 +053030namespace phosphor
31{
32namespace network
33{
34
35using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053036using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050037using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta2b106532017-07-25 16:05:02 +053038
Ratan Gupta91a99cc2017-04-14 16:32:09 +053039EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
40 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050041 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053042 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050043 Ifaces(bus, objPath.c_str(), true),
44 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053045{
46 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053047 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053048 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053049 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Ratan Guptabd303b12017-08-18 17:10:07 +053050 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053051 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec3902017-08-20 15:28:12 +053052 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
53
Ratan Gupta29b0e432017-05-25 12:51:40 +053054 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053055 if (emitSignal)
56 {
57 this->emit_object_added();
58 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053059}
60
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080061static IP::Protocol convertFamily(int family)
62{
63 switch (family)
64 {
65 case AF_INET:
66 return IP::Protocol::IPv4;
67 case AF_INET6:
68 return IP::Protocol::IPv6;
69 }
70
71 throw std::invalid_argument("Bad address family");
72}
73
Ratan Gupta87c13982017-06-15 09:27:27 +053074void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053075{
Ratan Gupta87c13982017-06-15 09:27:27 +053076 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053077
Ratan Gupta87c13982017-06-15 09:27:27 +053078 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053079
Ratan Guptafc2c7242017-05-29 08:46:06 +053080 route::Table routingTable;
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 IIIfbafa252018-11-30 16:53:52 -080094 std::string gateway =
Gunnar Mills57d9c502018-09-14 14:42:34 -050095 routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
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
112 auto neighbors = getCurrentNeighbors();
113 for (const auto& neighbor : neighbors)
114 {
115 if (!neighbor.permanent || !neighbor.mac ||
116 neighbor.interface != interfaceName())
117 {
118 continue;
119 }
120 std::string ip = toString(neighbor.address);
121 std::string mac = mac_address::toString(*neighbor.mac);
122 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
123 staticNeighbors.emplace(ip,
124 std::make_shared<phosphor::network::Neighbor>(
125 bus, objectPath.c_str(), *this, ip, mac,
126 Neighbor::State::Permanent));
127 }
128}
129
raviteja-bce379562019-03-28 05:59:36 -0500130ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
131 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530132{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530133
134 if (dHCPEnabled())
135 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530136 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500137 entry("INTERFACE=%s", interfaceName().c_str());
138 dHCPEnabled(false);
139 }
140
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500141 IP::AddressOrigin origin = IP::AddressOrigin::Static;
142
143 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
144
145 if (!isValidIP(addressFamily, ipaddress))
146 {
147 log<level::ERR>("Not a valid IP address"),
148 entry("ADDRESS=%s", ipaddress.c_str());
149 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
150 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
151 }
152
153 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
154 {
155 log<level::ERR>("Not a valid Gateway"),
156 entry("GATEWAY=%s", gateway.c_str());
157 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
158 Argument::ARGUMENT_VALUE(gateway.c_str()));
159 }
160
161 if (!isValidPrefix(addressFamily, prefixLength))
162 {
163 log<level::ERR>("PrefixLength is not correct "),
164 entry("PREFIXLENGTH=%d", gateway.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500165 elog<InvalidArgument>(
166 Argument::ARGUMENT_NAME("prefixLength"),
167 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530168 }
169
Gunnar Mills57d9c502018-09-14 14:42:34 -0500170 std::string objectPath =
171 generateObjectPath(protType, ipaddress, prefixLength, gateway);
172 this->addrs.emplace(ipaddress,
173 std::make_shared<phosphor::network::IPAddress>(
174 bus, objectPath.c_str(), *this, protType, ipaddress,
175 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530176
Ratan Guptae05083a2017-09-16 07:12:11 +0530177 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500178 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530179}
180
William A. Kennington III08505792019-01-30 16:00:04 -0800181ObjectPath EthernetInterface::neighbor(std::string iPAddress,
182 std::string mACAddress)
183{
184 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
185 {
186 log<level::ERR>("Not a valid IP address",
187 entry("ADDRESS=%s", iPAddress.c_str()));
188 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
189 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
190 }
191 if (!mac_address::validate(mACAddress))
192 {
193 log<level::ERR>("Not a valid MAC address",
194 entry("MACADDRESS=%s", iPAddress.c_str()));
195 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
196 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
197 }
198
199 std::string objectPath =
200 generateStaticNeighborObjectPath(iPAddress, mACAddress);
201 staticNeighbors.emplace(iPAddress,
202 std::make_shared<phosphor::network::Neighbor>(
203 bus, objectPath.c_str(), *this, iPAddress,
204 mACAddress, Neighbor::State::Permanent));
205 manager.writeToConfigurationFile();
206 return objectPath;
207}
208
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530209/*
210Note: We don't have support for ethtool now
211will enable this code once we bring the ethtool
212in the image.
213TODO: https://github.com/openbmc/openbmc/issues/1484
214*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530215
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530216InterfaceInfo EthernetInterface::getInterfaceInfo() const
217{
218 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400219 ifreq ifr{0};
220 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500221 LinkSpeed speed{0};
222 Autoneg autoneg{0};
223 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530224 do
225 {
226 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
227 if (sock < 0)
228 {
229 log<level::ERR>("socket creation failed:",
230 entry("ERROR=%s", strerror(errno)));
231 break;
232 }
233
234 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
235 ifr.ifr_data = reinterpret_cast<char*>(&edata);
236
237 edata.cmd = ETHTOOL_GSET;
238
239 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
240 {
241 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
242 entry("ERROR=%s", strerror(errno)));
243 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530244 }
245 speed = edata.speed;
246 duplex = edata.duplex;
247 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500248 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530249
250 if (sock)
251 {
252 close(sock);
253 }
254 return std::make_tuple(speed, duplex, autoneg);
255}
256
257/** @brief get the mac address of the interface.
258 * @return macaddress on success
259 */
260
Gunnar Mills57d9c502018-09-14 14:42:34 -0500261std::string
262 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530263{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400264 ifreq ifr{};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500265 char macAddress[mac_address::size]{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530266
267 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
268 if (sock < 0)
269 {
270 log<level::ERR>("socket creation failed:",
271 entry("ERROR=%s", strerror(errno)));
272 return macAddress;
273 }
274
Patrick Venture836c91d2018-09-11 17:36:03 -0700275 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530276 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530277 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530278 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500279 entry("ERROR=%s", strerror(errno)));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530280 return macAddress;
281 }
282
Patrick Venture836c91d2018-09-11 17:36:03 -0700283 std::snprintf(macAddress, mac_address::size, mac_address::format,
284 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
285 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
286 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530287
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530288 return macAddress;
289}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530290
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530291std::string EthernetInterface::generateId(const std::string& ipaddress,
292 uint8_t prefixLength,
293 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530294{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530295 std::stringstream hexId;
296 std::string hashString = ipaddress;
297 hashString += std::to_string(prefixLength);
298 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530299
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530300 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500301 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530302 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530303}
304
William A. Kennington III08505792019-01-30 16:00:04 -0800305std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
306 const std::string& mACAddress)
307{
308 std::stringstream hexId;
309 std::string hashString = iPAddress + mACAddress;
310
311 // Only want 8 hex digits.
312 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
313 return hexId.str();
314}
315
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530316void EthernetInterface::deleteObject(const std::string& ipaddress)
317{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530318 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530319 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530320 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530321 log<level::ERR>("DeleteObject:Unable to find the object.");
322 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530323 }
324 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530325 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530326}
327
William A. Kennington III08505792019-01-30 16:00:04 -0800328void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
329{
330 auto it = staticNeighbors.find(iPAddress);
331 if (it == staticNeighbors.end())
332 {
333 log<level::ERR>(
334 "DeleteStaticNeighborObject:Unable to find the object.");
335 return;
336 }
337 staticNeighbors.erase(it);
338 manager.writeToConfigurationFile();
339}
340
Ratan Guptae9c9b812017-09-22 17:15:37 +0530341void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530342{
Ratan Guptabc886292017-07-25 18:29:57 +0530343 auto confDir = manager.getConfDir();
344 fs::path networkFile = confDir;
345 networkFile /= systemd::config::networkFilePrefix + interface +
346 systemd::config::networkFileSuffix;
347
348 fs::path deviceFile = confDir;
349 deviceFile /= interface + systemd::config::deviceFileSuffix;
350
351 // delete the vlan network file
352 if (fs::is_regular_file(networkFile))
353 {
354 fs::remove(networkFile);
355 }
356
357 // delete the vlan device file
358 if (fs::is_regular_file(deviceFile))
359 {
360 fs::remove(deviceFile);
361 }
Ratan Guptabc886292017-07-25 18:29:57 +0530362
363 // TODO systemd doesn't delete the virtual network interface
364 // even after deleting all the related configuartion.
365 // https://github.com/systemd/systemd/issues/6600
366 try
367 {
368 deleteInterface(interface);
369 }
370 catch (InternalFailure& e)
371 {
372 commit<InternalFailure>();
373 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530374}
375
376void EthernetInterface::deleteVLANObject(const std::string& interface)
377{
378 auto it = vlanInterfaces.find(interface);
379 if (it == vlanInterfaces.end())
380 {
381 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500382 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530383 return;
384 }
385
386 deleteVLANFromSystem(interface);
387 // delete the interface
388 vlanInterfaces.erase(it);
389
Ratan Guptae05083a2017-09-16 07:12:11 +0530390 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530391}
392
Gunnar Mills57d9c502018-09-14 14:42:34 -0500393std::string EthernetInterface::generateObjectPath(
394 IP::Protocol addressType, const std::string& ipaddress,
395 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530396{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530397 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530398 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530399 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
400
401 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530402 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530403 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530404 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530405 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530406}
407
William A. Kennington III08505792019-01-30 16:00:04 -0800408std::string EthernetInterface::generateStaticNeighborObjectPath(
409 const std::string& iPAddress, const std::string& mACAddress) const
410{
411 std::experimental::filesystem::path objectPath;
412 objectPath /= objPath;
413 objectPath /= "static_neighbor";
414 objectPath /= generateNeighborId(iPAddress, mACAddress);
415 return objectPath.string();
416}
417
Ratan Gupta87c13982017-06-15 09:27:27 +0530418bool EthernetInterface::dHCPEnabled(bool value)
419{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530420 if (value == EthernetInterfaceIntf::dHCPEnabled())
421 {
422 return value;
423 }
424
Ratan Gupta87c13982017-06-15 09:27:27 +0530425 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530426 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530427 return value;
428}
429
Ratan Gupta6dec3902017-08-20 15:28:12 +0530430ServerList EthernetInterface::nameservers(ServerList value)
431{
432 try
433 {
434 EthernetInterfaceIntf::nameservers(value);
435
436 writeConfigurationFile();
437
438 // Currently we don't have systemd-resolved enabled
439 // in the openbmc. Once we update the network conf file,
440 // it should be read by systemd-resolved.service.
441
442 // The other reason to write the resolv conf is,
443 // we don't want to restart the networkd for nameserver change.
444 // as restarting of systemd-networkd takes more then 2 secs
445 writeDNSEntries(value, resolvConfFile);
446 }
447 catch (InternalFailure& e)
448 {
449 log<level::ERR>("Exception processing DNS entries");
450 }
451 return EthernetInterfaceIntf::nameservers();
452}
453
454ServerList EthernetInterface::getNameServerFromConf()
455{
456 fs::path confPath = manager.getConfDir();
457
458 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500459 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530460 confPath /= fileName;
461 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530462 config::Parser parser(confPath.string());
463 auto rc = config::ReturnCode::SUCCESS;
464
465 std::tie(rc, servers) = parser.getValues("Network", "DNS");
466 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530467 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530468 log<level::DEBUG>("Unable to get the value for network[DNS]",
469 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530470 }
471 return servers;
472}
473
474void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
475 const std::string& file)
476{
477 std::fstream outStream(file, std::fstream::out);
478 if (!outStream.is_open())
479 {
480 log<level::ERR>("Unable to open the file",
481 entry("FILE=%s", file.c_str()));
482 elog<InternalFailure>();
483 }
484
Ratan Guptafe116912017-11-10 16:00:59 +0530485 outStream << "### Generated manually via dbus settings ###\n";
Gunnar Mills57d9c502018-09-14 14:42:34 -0500486 for (const auto& server : dnsList)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530487 {
488 outStream << "nameserver " << server << "\n";
489 }
490}
491
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530492void EthernetInterface::loadVLAN(VlanId id)
493{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500494 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530495 std::string path = objPath;
496 path += "_" + std::to_string(id);
497
Gunnar Mills57d9c502018-09-14 14:42:34 -0500498 auto dhcpEnabled =
499 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530500
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530501 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500502 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530503
Gunnar Mills57d9c502018-09-14 14:42:34 -0500504 // Fetch the ip address from the system
505 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530506 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800507 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530508
509 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
510 std::move(vlanIntf));
511}
512
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700513ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530514{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500515 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530516 std::string path = objPath;
517 path += "_" + std::to_string(id);
518
Ratan Gupta5978dd12017-07-25 13:47:13 +0530519 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500520 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530521
522 // write the device file for the vlan interface.
523 vlanIntf->writeDeviceFile();
524
Gunnar Mills57d9c502018-09-14 14:42:34 -0500525 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530526 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530527 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700528
529 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530530}
Ratan Gupta2b106532017-07-25 16:05:02 +0530531
Ratan Gupta497c0c92017-08-22 19:15:59 +0530532ServerList EthernetInterface::getNTPServersFromConf()
533{
534 fs::path confPath = manager.getConfDir();
535
Gunnar Mills57d9c502018-09-14 14:42:34 -0500536 std::string fileName = systemd::config::networkFilePrefix +
537 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530538 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530539
Ratan Gupta497c0c92017-08-22 19:15:59 +0530540 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530541 config::Parser parser(confPath.string());
542 auto rc = config::ReturnCode::SUCCESS;
543
544 std::tie(rc, servers) = parser.getValues("Network", "NTP");
545 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530546 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530547 log<level::DEBUG>("Unable to get the value for Network[NTP]",
548 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530549 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530550
Ratan Gupta497c0c92017-08-22 19:15:59 +0530551 return servers;
552}
553
554ServerList EthernetInterface::nTPServers(ServerList servers)
555{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500556 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530557
558 writeConfigurationFile();
559 // timesynchd reads the NTP server configuration from the
560 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530561 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530562 return ntpServers;
563}
Ratan Gupta2b106532017-07-25 16:05:02 +0530564// Need to merge the below function with the code which writes the
565// config file during factory reset.
566// TODO openbmc/openbmc#1751
567
568void EthernetInterface::writeConfigurationFile()
569{
570 // write all the static ip address in the systemd-network conf file
571
572 using namespace std::string_literals;
573 using AddressOrigin =
574 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
575 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530576
577 // if there is vlan interafce then write the configuration file
578 // for vlan also.
579
Gunnar Mills57d9c502018-09-14 14:42:34 -0500580 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530581 {
582 intf.second->writeConfigurationFile();
583 }
584
Ratan Gupta2b106532017-07-25 16:05:02 +0530585 fs::path confPath = manager.getConfDir();
586
Gunnar Mills57d9c502018-09-14 14:42:34 -0500587 std::string fileName = systemd::config::networkFilePrefix +
588 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530589 confPath /= fileName;
590 std::fstream stream;
591
592 stream.open(confPath.c_str(), std::fstream::out);
593 if (!stream.is_open())
594 {
595 log<level::ERR>("Unable to open the file",
596 entry("FILE=%s", confPath.c_str()));
597 elog<InternalFailure>();
598 }
599
600 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400601 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530602 stream << "Name=" << interfaceName() << "\n";
603
604 auto addrs = getAddresses();
605
606 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400607 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400608#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500609 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400610#else
611 stream << "LinkLocalAddressing=no\n";
612#endif
Ratan Guptae9629412017-12-21 08:20:25 +0530613 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530614
615 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500616 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530617 {
618 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500619 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530620 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500621 // Add the DHCP entry
622 auto value = dHCPEnabled() ? "true"s : "false"s;
623 stream << "DHCP="s + value + "\n";
624
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600625 // When the interface configured as dhcp, we don't need below given entries
626 // in config file.
627 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530628 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500629 // Add the NTP server
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600630 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530631 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600632 stream << "NTP=" << ntp << "\n";
633 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530634
Gunnar Mills57d9c502018-09-14 14:42:34 -0500635 // Add the DNS entry
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600636 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530637 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600638 stream << "DNS=" << dns << "\n";
639 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530640
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600641 // Static
642 for (const auto& addr : addrs)
643 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400644 if (addr.second->origin() == AddressOrigin::Static
645#ifndef LINK_LOCAL_AUTOCONFIGURATION
646 || addr.second->origin() == AddressOrigin::LinkLocal
647#endif
648 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530649 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500650 std::string address =
651 addr.second->address() + "/" +
652 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530653
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600654 stream << "Address=" << address << "\n";
655 }
656 }
657
658 if (manager.getSystemConf())
659 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800660 const auto& gateway = manager.getSystemConf()->defaultGateway();
661 if (!gateway.empty())
662 {
663 stream << "Gateway=" << gateway << "\n";
664 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800665 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
666 if (!gateway6.empty())
667 {
668 stream << "Gateway=" << gateway6 << "\n";
669 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600670 }
671
672 // write the route section
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600673 for (const auto& addr : addrs)
674 {
675 if (addr.second->origin() == AddressOrigin::Static)
676 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500677 int addressFamily = addr.second->type() == IP::Protocol::IPv4
678 ? AF_INET
679 : AF_INET6;
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600680
Gunnar Mills57d9c502018-09-14 14:42:34 -0500681 std::string destination =
682 getNetworkID(addressFamily, addr.second->address(),
683 addr.second->prefixLength());
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600684
685 if (addr.second->gateway() != "0.0.0.0" &&
Gunnar Mills57d9c502018-09-14 14:42:34 -0500686 addr.second->gateway() != "" && destination != "0.0.0.0" &&
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600687 destination != "")
688 {
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400689 stream << "[Route]\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600690 stream << "Gateway=" << addr.second->gateway() << "\n";
691 stream << "Destination=" << destination << "\n";
692 }
693 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530694 }
695 }
696
William A. Kennington III08505792019-01-30 16:00:04 -0800697 // Write the neighbor sections
698 for (const auto& neighbor : staticNeighbors)
699 {
700 stream << "[Neighbor]"
701 << "\n";
702 stream << "Address=" << neighbor.second->iPAddress() << "\n";
703 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
704 }
705
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600706 // Write the dhcp section irrespective of whether DHCP is enabled or not
707 writeDHCPSection(stream);
708
Ratan Gupta2b106532017-07-25 16:05:02 +0530709 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530710}
711
712void EthernetInterface::writeDHCPSection(std::fstream& stream)
713{
714 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530715 // write the dhcp section
716 stream << "[DHCP]\n";
717
718 // Hardcoding the client identifier to mac, to address below issue
719 // https://github.com/openbmc/openbmc/issues/1280
720 stream << "ClientIdentifier=mac\n";
721 if (manager.getDHCPConf())
722 {
723 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
724 stream << "UseDNS="s + value + "\n";
725
726 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
727 stream << "UseNTP="s + value + "\n";
728
729 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
730 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600731
732 value =
733 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
734 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530735 }
736}
737
Ratan Guptabd303b12017-08-18 17:10:07 +0530738std::string EthernetInterface::mACAddress(std::string value)
739{
740 if (!mac_address::validate(value))
741 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500742 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500743 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500744 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
745 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530746 }
747
748 // check whether MAC is broadcast mac.
749 auto intMac = mac_address::internal::convertToInt(value);
750
751 if (!(intMac ^ mac_address::broadcastMac))
752 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500753 log<level::ERR>("MACAddress is a broadcast mac.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500754 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500755 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
756 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530757 }
758
Patrick Ventured475cd62018-02-26 17:07:41 -0800759 // Check if the MAC changed.
760 auto pmac = MacAddressIntf::mACAddress();
761 if (strcasecmp(pmac.c_str(), value.c_str()) == 0)
762 {
763 return MacAddressIntf::mACAddress();
764 }
765
Ratan Guptabd303b12017-08-18 17:10:07 +0530766 // Allow the mac to be set if one of the condition is true.
767 // 1) Incoming Mac is of local admin type.
768 // or
769 // 2) Incoming mac is same as eeprom Mac.
770
771 if (!(intMac & mac_address::localAdminMask))
772 {
773 try
774 {
775 auto inventoryMac = mac_address::getfromInventory(bus);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500776 auto intInventoryMac =
777 mac_address::internal::convertToInt(inventoryMac);
Ratan Guptabd303b12017-08-18 17:10:07 +0530778
779 if (intInventoryMac != intMac)
780 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500781 log<level::ERR>("Given MAC address is neither a local Admin "
Gunnar Mills57d9c502018-09-14 14:42:34 -0500782 "type nor is same as in inventory");
Gunnar Mills90480c42018-06-19 16:02:17 -0500783 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
784 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530785 }
786 }
Gunnar Mills57d9c502018-09-14 14:42:34 -0500787 catch (InternalFailure& e)
Ratan Guptabd303b12017-08-18 17:10:07 +0530788 {
Patrick Venturee0ad43a2017-11-29 18:19:54 -0800789 log<level::ERR>("Exception occurred during getting of MAC "
790 "address from Inventory");
Gunnar Millsce262822018-06-19 16:21:34 -0500791 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530792 }
793 }
794 auto interface = interfaceName();
795 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500796 // TODO: would replace below three calls
Ratan Guptabd303b12017-08-18 17:10:07 +0530797 // with restarting of systemd-netwokd
798 // through https://github.com/systemd/systemd/issues/6696
799 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
Gunnar Mills57d9c502018-09-14 14:42:34 -0500800 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
801 "address", value.c_str());
Ratan Guptabd303b12017-08-18 17:10:07 +0530802
803 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
804
805 auto mac = MacAddressIntf::mACAddress(std::move(value));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500806 // update all the vlan interfaces
807 for (const auto& intf : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530808 {
809 intf.second->updateMacAddress();
810 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530811
812 // restart the systemd networkd so that dhcp client gets the
813 // ip for the changed mac address.
814 if (dHCPEnabled())
815 {
Ratan Gupta895f9e52018-11-26 20:57:34 +0530816 manager.restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530817 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530818 return mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530819}
820
Ratan Guptae9c9b812017-09-22 17:15:37 +0530821void EthernetInterface::deleteAll()
822{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500823 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530824 {
825 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500826 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530827 }
828
829 // clear all the ip on the interface
830 addrs.clear();
831 manager.writeToConfigurationFile();
832}
833
Gunnar Mills57d9c502018-09-14 14:42:34 -0500834} // namespace network
835} // namespace phosphor