blob: a1438deaa15fed402f3fdda03a6bc704fdcde226 [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>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070014#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053015#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053016#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053017#include <netinet/in.h>
18#include <sys/ioctl.h>
19#include <sys/socket.h>
20#include <unistd.h>
21
Ratan Gupta82549cc2017-04-21 08:45:23 +053022#include <algorithm>
23#include <experimental/filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053024#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070025#include <phosphor-logging/elog-errors.hpp>
26#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053027#include <sstream>
28#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070029#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070030#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053031
Ratan Gupta91a99cc2017-04-14 16:32:09 +053032namespace phosphor
33{
34namespace network
35{
36
37using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053038using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050039using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta2b106532017-07-25 16:05:02 +053040
Ratan Gupta91a99cc2017-04-14 16:32:09 +053041EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
42 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050043 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053044 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050045 Ifaces(bus, objPath.c_str(), true),
46 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053047{
48 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053049 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053050 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053051 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Ratan Guptabd303b12017-08-18 17:10:07 +053052 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053053 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec390f2017-08-20 15:28:12 +053054 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
55
Ratan Gupta29b0e432017-05-25 12:51:40 +053056 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053057 if (emitSignal)
58 {
59 this->emit_object_added();
60 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053061}
62
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080063static IP::Protocol convertFamily(int family)
64{
65 switch (family)
66 {
67 case AF_INET:
68 return IP::Protocol::IPv4;
69 case AF_INET6:
70 return IP::Protocol::IPv6;
71 }
72
73 throw std::invalid_argument("Bad address family");
74}
75
Ratan Gupta87c13982017-06-15 09:27:27 +053076void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053077{
Ratan Gupta87c13982017-06-15 09:27:27 +053078 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053079
Ratan Gupta87c13982017-06-15 09:27:27 +053080 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053081
Ratan Guptafc2c7242017-05-29 08:46:06 +053082 route::Table routingTable;
Ratan Gupta5978dd12017-07-25 13:47:13 +053083
Ratan Gupta6a387c12017-08-03 13:26:19 +053084 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053085 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080086 IP::Protocol addressType = convertFamily(addr.addrType);
87 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053088 if (dHCPEnabled())
89 {
90 origin = IP::AddressOrigin::DHCP;
91 }
William A. Kennington III16893802019-01-30 16:01:01 -080092 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053093 {
94 origin = IP::AddressOrigin::LinkLocal;
95 }
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080096 std::string gateway =
Gunnar Mills57d9c502018-09-14 14:42:34 -050097 routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
Ratan Gupta82549cc2017-04-21 08:45:23 +053098
Gunnar Mills57d9c502018-09-14 14:42:34 -050099 std::string ipAddressObjectPath = generateObjectPath(
100 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530101
Gunnar Mills57d9c502018-09-14 14:42:34 -0500102 this->addrs.emplace(addr.ipaddress,
103 std::make_shared<phosphor::network::IPAddress>(
104 bus, ipAddressObjectPath.c_str(), *this,
105 addressType, addr.ipaddress, origin,
106 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530107 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530108}
109
William A. Kennington III08505792019-01-30 16:00:04 -0800110void EthernetInterface::createStaticNeighborObjects()
111{
112 staticNeighbors.clear();
113
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700114 NeighborFilter filter;
115 filter.interface = ifIndex();
116 filter.state = NUD_PERMANENT;
117 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800118 for (const auto& neighbor : neighbors)
119 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700120 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800121 {
122 continue;
123 }
124 std::string ip = toString(neighbor.address);
125 std::string mac = mac_address::toString(*neighbor.mac);
126 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
127 staticNeighbors.emplace(ip,
128 std::make_shared<phosphor::network::Neighbor>(
129 bus, objectPath.c_str(), *this, ip, mac,
130 Neighbor::State::Permanent));
131 }
132}
133
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700134unsigned EthernetInterface::ifIndex() const
135{
136 unsigned idx = if_nametoindex(interfaceName().c_str());
137 if (idx == 0)
138 {
139 throw std::system_error(errno, std::generic_category(),
140 "if_nametoindex");
141 }
142 return idx;
143}
144
raviteja-bce379562019-03-28 05:59:36 -0500145ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
146 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530147{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530148
149 if (dHCPEnabled())
150 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530151 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500152 entry("INTERFACE=%s", interfaceName().c_str());
153 dHCPEnabled(false);
154 }
155
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500156 IP::AddressOrigin origin = IP::AddressOrigin::Static;
157
158 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
159
160 if (!isValidIP(addressFamily, ipaddress))
161 {
162 log<level::ERR>("Not a valid IP address"),
163 entry("ADDRESS=%s", ipaddress.c_str());
164 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
165 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
166 }
167
168 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
169 {
170 log<level::ERR>("Not a valid Gateway"),
171 entry("GATEWAY=%s", gateway.c_str());
172 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
173 Argument::ARGUMENT_VALUE(gateway.c_str()));
174 }
175
176 if (!isValidPrefix(addressFamily, prefixLength))
177 {
178 log<level::ERR>("PrefixLength is not correct "),
179 entry("PREFIXLENGTH=%d", gateway.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500180 elog<InvalidArgument>(
181 Argument::ARGUMENT_NAME("prefixLength"),
182 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530183 }
184
Gunnar Mills57d9c502018-09-14 14:42:34 -0500185 std::string objectPath =
186 generateObjectPath(protType, ipaddress, prefixLength, gateway);
187 this->addrs.emplace(ipaddress,
188 std::make_shared<phosphor::network::IPAddress>(
189 bus, objectPath.c_str(), *this, protType, ipaddress,
190 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530191
Ratan Guptae05083a2017-09-16 07:12:11 +0530192 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500193 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530194}
195
William A. Kennington III08505792019-01-30 16:00:04 -0800196ObjectPath EthernetInterface::neighbor(std::string iPAddress,
197 std::string mACAddress)
198{
199 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
200 {
201 log<level::ERR>("Not a valid IP address",
202 entry("ADDRESS=%s", iPAddress.c_str()));
203 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
204 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
205 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700206 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800207 {
208 log<level::ERR>("Not a valid MAC address",
209 entry("MACADDRESS=%s", iPAddress.c_str()));
210 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
211 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
212 }
213
214 std::string objectPath =
215 generateStaticNeighborObjectPath(iPAddress, mACAddress);
216 staticNeighbors.emplace(iPAddress,
217 std::make_shared<phosphor::network::Neighbor>(
218 bus, objectPath.c_str(), *this, iPAddress,
219 mACAddress, Neighbor::State::Permanent));
220 manager.writeToConfigurationFile();
221 return objectPath;
222}
223
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530224/*
225Note: We don't have support for ethtool now
226will enable this code once we bring the ethtool
227in the image.
228TODO: https://github.com/openbmc/openbmc/issues/1484
229*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530230
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530231InterfaceInfo EthernetInterface::getInterfaceInfo() const
232{
233 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400234 ifreq ifr{0};
235 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500236 LinkSpeed speed{0};
237 Autoneg autoneg{0};
238 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530239 do
240 {
241 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
242 if (sock < 0)
243 {
244 log<level::ERR>("socket creation failed:",
245 entry("ERROR=%s", strerror(errno)));
246 break;
247 }
248
William A. Kennington III0420c6a2019-06-27 14:38:17 -0700249 strcpy(ifr.ifr_name, interfaceName().c_str());
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530250 ifr.ifr_data = reinterpret_cast<char*>(&edata);
251
252 edata.cmd = ETHTOOL_GSET;
253
254 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
255 {
256 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
257 entry("ERROR=%s", strerror(errno)));
258 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530259 }
260 speed = edata.speed;
261 duplex = edata.duplex;
262 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500263 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530264
265 if (sock)
266 {
267 close(sock);
268 }
269 return std::make_tuple(speed, duplex, autoneg);
270}
271
272/** @brief get the mac address of the interface.
273 * @return macaddress on success
274 */
275
Gunnar Mills57d9c502018-09-14 14:42:34 -0500276std::string
277 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530278{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400279 ifreq ifr{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530280 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
281 if (sock < 0)
282 {
283 log<level::ERR>("socket creation failed:",
284 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700285 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530286 }
287
Patrick Venture836c91d2018-09-11 17:36:03 -0700288 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530289 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530290 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530291 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500292 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700293 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530294 }
295
William A. Kennington III1137a972019-04-20 20:49:58 -0700296 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
297 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
298 sizeof(ifr.ifr_hwaddr.sa_data));
299 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530300}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530301
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530302std::string EthernetInterface::generateId(const std::string& ipaddress,
303 uint8_t prefixLength,
304 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530305{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530306 std::stringstream hexId;
307 std::string hashString = ipaddress;
308 hashString += std::to_string(prefixLength);
309 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530310
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530311 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500312 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530313 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530314}
315
William A. Kennington III08505792019-01-30 16:00:04 -0800316std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
317 const std::string& mACAddress)
318{
319 std::stringstream hexId;
320 std::string hashString = iPAddress + mACAddress;
321
322 // Only want 8 hex digits.
323 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
324 return hexId.str();
325}
326
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530327void EthernetInterface::deleteObject(const std::string& ipaddress)
328{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530329 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530330 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530331 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530332 log<level::ERR>("DeleteObject:Unable to find the object.");
333 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530334 }
335 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530336 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530337}
338
William A. Kennington III08505792019-01-30 16:00:04 -0800339void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
340{
341 auto it = staticNeighbors.find(iPAddress);
342 if (it == staticNeighbors.end())
343 {
344 log<level::ERR>(
345 "DeleteStaticNeighborObject:Unable to find the object.");
346 return;
347 }
348 staticNeighbors.erase(it);
349 manager.writeToConfigurationFile();
350}
351
Ratan Guptae9c9b812017-09-22 17:15:37 +0530352void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530353{
Ratan Guptabc886292017-07-25 18:29:57 +0530354 auto confDir = manager.getConfDir();
355 fs::path networkFile = confDir;
356 networkFile /= systemd::config::networkFilePrefix + interface +
357 systemd::config::networkFileSuffix;
358
359 fs::path deviceFile = confDir;
360 deviceFile /= interface + systemd::config::deviceFileSuffix;
361
362 // delete the vlan network file
363 if (fs::is_regular_file(networkFile))
364 {
365 fs::remove(networkFile);
366 }
367
368 // delete the vlan device file
369 if (fs::is_regular_file(deviceFile))
370 {
371 fs::remove(deviceFile);
372 }
Ratan Guptabc886292017-07-25 18:29:57 +0530373
374 // TODO systemd doesn't delete the virtual network interface
375 // even after deleting all the related configuartion.
376 // https://github.com/systemd/systemd/issues/6600
377 try
378 {
379 deleteInterface(interface);
380 }
381 catch (InternalFailure& e)
382 {
383 commit<InternalFailure>();
384 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530385}
386
387void EthernetInterface::deleteVLANObject(const std::string& interface)
388{
389 auto it = vlanInterfaces.find(interface);
390 if (it == vlanInterfaces.end())
391 {
392 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500393 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530394 return;
395 }
396
397 deleteVLANFromSystem(interface);
398 // delete the interface
399 vlanInterfaces.erase(it);
400
Ratan Guptae05083a2017-09-16 07:12:11 +0530401 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530402}
403
Gunnar Mills57d9c502018-09-14 14:42:34 -0500404std::string EthernetInterface::generateObjectPath(
405 IP::Protocol addressType, const std::string& ipaddress,
406 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530407{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530408 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530409 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530410 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
411
412 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530413 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530414 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530415 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530416 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530417}
418
William A. Kennington III08505792019-01-30 16:00:04 -0800419std::string EthernetInterface::generateStaticNeighborObjectPath(
420 const std::string& iPAddress, const std::string& mACAddress) const
421{
422 std::experimental::filesystem::path objectPath;
423 objectPath /= objPath;
424 objectPath /= "static_neighbor";
425 objectPath /= generateNeighborId(iPAddress, mACAddress);
426 return objectPath.string();
427}
428
Ratan Gupta87c13982017-06-15 09:27:27 +0530429bool EthernetInterface::dHCPEnabled(bool value)
430{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530431 if (value == EthernetInterfaceIntf::dHCPEnabled())
432 {
433 return value;
434 }
435
Ratan Gupta87c13982017-06-15 09:27:27 +0530436 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530437 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530438 return value;
439}
440
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530441ServerList EthernetInterface::nameservers(ServerList value)
442{
443 try
444 {
445 EthernetInterfaceIntf::nameservers(value);
446
447 writeConfigurationFile();
448
449 // Currently we don't have systemd-resolved enabled
450 // in the openbmc. Once we update the network conf file,
451 // it should be read by systemd-resolved.service.
452
453 // The other reason to write the resolv conf is,
454 // we don't want to restart the networkd for nameserver change.
455 // as restarting of systemd-networkd takes more then 2 secs
456 writeDNSEntries(value, resolvConfFile);
457 }
458 catch (InternalFailure& e)
459 {
460 log<level::ERR>("Exception processing DNS entries");
461 }
462 return EthernetInterfaceIntf::nameservers();
463}
464
465ServerList EthernetInterface::getNameServerFromConf()
466{
467 fs::path confPath = manager.getConfDir();
468
469 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500470 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530471 confPath /= fileName;
472 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530473 config::Parser parser(confPath.string());
474 auto rc = config::ReturnCode::SUCCESS;
475
476 std::tie(rc, servers) = parser.getValues("Network", "DNS");
477 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530478 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530479 log<level::DEBUG>("Unable to get the value for network[DNS]",
480 entry("RC=%d", rc));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530481 }
482 return servers;
483}
484
485void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
486 const std::string& file)
487{
488 std::fstream outStream(file, std::fstream::out);
489 if (!outStream.is_open())
490 {
491 log<level::ERR>("Unable to open the file",
492 entry("FILE=%s", file.c_str()));
493 elog<InternalFailure>();
494 }
495
Ratan Guptafe116912017-11-10 16:00:59 +0530496 outStream << "### Generated manually via dbus settings ###\n";
Gunnar Mills57d9c502018-09-14 14:42:34 -0500497 for (const auto& server : dnsList)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530498 {
499 outStream << "nameserver " << server << "\n";
500 }
501}
502
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530503void EthernetInterface::loadVLAN(VlanId id)
504{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500505 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530506 std::string path = objPath;
507 path += "_" + std::to_string(id);
508
Gunnar Mills57d9c502018-09-14 14:42:34 -0500509 auto dhcpEnabled =
510 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530511
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530512 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500513 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530514
Gunnar Mills57d9c502018-09-14 14:42:34 -0500515 // Fetch the ip address from the system
516 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530517 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800518 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530519
520 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
521 std::move(vlanIntf));
522}
523
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700524ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530525{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500526 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530527 std::string path = objPath;
528 path += "_" + std::to_string(id);
529
Ratan Gupta5978dd12017-07-25 13:47:13 +0530530 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500531 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530532
533 // write the device file for the vlan interface.
534 vlanIntf->writeDeviceFile();
535
Gunnar Mills57d9c502018-09-14 14:42:34 -0500536 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530537 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530538 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700539
540 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530541}
Ratan Gupta2b106532017-07-25 16:05:02 +0530542
Ratan Gupta497c0c92017-08-22 19:15:59 +0530543ServerList EthernetInterface::getNTPServersFromConf()
544{
545 fs::path confPath = manager.getConfDir();
546
Gunnar Mills57d9c502018-09-14 14:42:34 -0500547 std::string fileName = systemd::config::networkFilePrefix +
548 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530549 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530550
Ratan Gupta497c0c92017-08-22 19:15:59 +0530551 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530552 config::Parser parser(confPath.string());
553 auto rc = config::ReturnCode::SUCCESS;
554
555 std::tie(rc, servers) = parser.getValues("Network", "NTP");
556 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530557 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530558 log<level::DEBUG>("Unable to get the value for Network[NTP]",
559 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530560 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530561
Ratan Gupta497c0c92017-08-22 19:15:59 +0530562 return servers;
563}
564
565ServerList EthernetInterface::nTPServers(ServerList servers)
566{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500567 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530568
569 writeConfigurationFile();
570 // timesynchd reads the NTP server configuration from the
571 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530572 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530573 return ntpServers;
574}
Ratan Gupta2b106532017-07-25 16:05:02 +0530575// Need to merge the below function with the code which writes the
576// config file during factory reset.
577// TODO openbmc/openbmc#1751
578
579void EthernetInterface::writeConfigurationFile()
580{
581 // write all the static ip address in the systemd-network conf file
582
583 using namespace std::string_literals;
584 using AddressOrigin =
585 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
586 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530587
588 // if there is vlan interafce then write the configuration file
589 // for vlan also.
590
Gunnar Mills57d9c502018-09-14 14:42:34 -0500591 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530592 {
593 intf.second->writeConfigurationFile();
594 }
595
Ratan Gupta2b106532017-07-25 16:05:02 +0530596 fs::path confPath = manager.getConfDir();
597
Gunnar Mills57d9c502018-09-14 14:42:34 -0500598 std::string fileName = systemd::config::networkFilePrefix +
599 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530600 confPath /= fileName;
601 std::fstream stream;
602
603 stream.open(confPath.c_str(), std::fstream::out);
604 if (!stream.is_open())
605 {
606 log<level::ERR>("Unable to open the file",
607 entry("FILE=%s", confPath.c_str()));
608 elog<InternalFailure>();
609 }
610
611 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400612 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530613 stream << "Name=" << interfaceName() << "\n";
614
615 auto addrs = getAddresses();
616
617 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400618 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400619#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500620 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400621#else
622 stream << "LinkLocalAddressing=no\n";
623#endif
Ratan Guptae9629412017-12-21 08:20:25 +0530624 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530625
626 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500627 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530628 {
629 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500630 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530631 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500632 // Add the DHCP entry
633 auto value = dHCPEnabled() ? "true"s : "false"s;
634 stream << "DHCP="s + value + "\n";
635
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600636 // When the interface configured as dhcp, we don't need below given entries
637 // in config file.
638 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530639 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500640 // Add the NTP server
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600641 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530642 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600643 stream << "NTP=" << ntp << "\n";
644 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530645
Gunnar Mills57d9c502018-09-14 14:42:34 -0500646 // Add the DNS entry
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600647 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530648 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600649 stream << "DNS=" << dns << "\n";
650 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530651
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600652 // Static
653 for (const auto& addr : addrs)
654 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400655 if (addr.second->origin() == AddressOrigin::Static
656#ifndef LINK_LOCAL_AUTOCONFIGURATION
657 || addr.second->origin() == AddressOrigin::LinkLocal
658#endif
659 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530660 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500661 std::string address =
662 addr.second->address() + "/" +
663 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530664
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600665 stream << "Address=" << address << "\n";
666 }
667 }
668
669 if (manager.getSystemConf())
670 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800671 const auto& gateway = manager.getSystemConf()->defaultGateway();
672 if (!gateway.empty())
673 {
674 stream << "Gateway=" << gateway << "\n";
675 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800676 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
677 if (!gateway6.empty())
678 {
679 stream << "Gateway=" << gateway6 << "\n";
680 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600681 }
682
683 // write the route section
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600684 for (const auto& addr : addrs)
685 {
686 if (addr.second->origin() == AddressOrigin::Static)
687 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500688 int addressFamily = addr.second->type() == IP::Protocol::IPv4
689 ? AF_INET
690 : AF_INET6;
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600691
Gunnar Mills57d9c502018-09-14 14:42:34 -0500692 std::string destination =
693 getNetworkID(addressFamily, addr.second->address(),
694 addr.second->prefixLength());
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600695
696 if (addr.second->gateway() != "0.0.0.0" &&
Gunnar Mills57d9c502018-09-14 14:42:34 -0500697 addr.second->gateway() != "" && destination != "0.0.0.0" &&
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600698 destination != "")
699 {
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400700 stream << "[Route]\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600701 stream << "Gateway=" << addr.second->gateway() << "\n";
702 stream << "Destination=" << destination << "\n";
703 }
704 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530705 }
706 }
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 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700768 auto inventoryMAC = mac_address::getfromInventory(bus);
769 if (!equal(newMAC, inventoryMAC))
770 {
771 log<level::ERR>(
772 "Given MAC address is neither a local Admin "
773 "type nor is same as in inventory");
774 elog<InvalidArgument>(
775 Argument::ARGUMENT_NAME("MACAddress"),
776 Argument::ARGUMENT_VALUE(value.c_str()));
777 }
778 }
779 catch (const std::exception& e)
780 {
781 log<level::ERR>("Exception occurred during getting of MAC "
782 "address from Inventory");
783 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530784 }
785 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700786
787 // Update everything that depends on the MAC value
788 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530789 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700790 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530791 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700792 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530793
William A. Kennington III1137a972019-04-20 20:49:58 -0700794 auto interface = interfaceName();
795 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
796 // TODO: would replace below three calls
797 // 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(),
800 "down");
801 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
802 "address", value.c_str());
803 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
804 "up");
Ratan Gupta895f9e52018-11-26 20:57:34 +0530805 manager.restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530806 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700807
808 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530809}
810
Ratan Guptae9c9b812017-09-22 17:15:37 +0530811void EthernetInterface::deleteAll()
812{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500813 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530814 {
815 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500816 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530817 }
818
819 // clear all the ip on the interface
820 addrs.clear();
821 manager.writeToConfigurationFile();
822}
823
Gunnar Mills57d9c502018-09-14 14:42:34 -0500824} // namespace network
825} // namespace phosphor