blob: a2cd1c87771505aceca52ea40ef1c24f63633e0a [file] [log] [blame]
Gunnar Mills57d9c502018-09-14 14:42:34 -05001#include "config.h"
2
Patrick Venture189d44e2018-07-09 12:30:59 -07003#include "ethernet_interface.hpp"
4
Ratan Gupta497c0c92017-08-22 19:15:59 +05305#include "config_parser.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05306#include "ipaddress.hpp"
William A. Kennington III08505792019-01-30 16:00:04 -08007#include "neighbor.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05308#include "network_manager.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05309#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +053010
Ratan Gupta82549cc2017-04-21 08:45:23 +053011#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053012#include <linux/ethtool.h>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070013#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053015#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053016#include <netinet/in.h>
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <unistd.h>
20
Ratan Gupta82549cc2017-04-21 08:45:23 +053021#include <algorithm>
22#include <experimental/filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053023#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070024#include <phosphor-logging/elog-errors.hpp>
25#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053026#include <sstream>
27#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070028#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070029#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053030
Ratan Gupta91a99cc2017-04-14 16:32:09 +053031namespace phosphor
32{
33namespace network
34{
35
36using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053037using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050038using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta2b106532017-07-25 16:05:02 +053039
Ratan Gupta91a99cc2017-04-14 16:32:09 +053040EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
41 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053043 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050044 Ifaces(bus, objPath.c_str(), true),
45 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053046{
47 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053048 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053049 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053050 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
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 Gupta6a387c12017-08-03 13:26:19 +053081 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053082 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080083 IP::Protocol addressType = convertFamily(addr.addrType);
84 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053085 if (dHCPEnabled())
86 {
87 origin = IP::AddressOrigin::DHCP;
88 }
William A. Kennington III16893802019-01-30 16:01:01 -080089 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053090 {
91 origin = IP::AddressOrigin::LinkLocal;
92 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -070093 // Obsolete parameter
94 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +053095
Gunnar Mills57d9c502018-09-14 14:42:34 -050096 std::string ipAddressObjectPath = generateObjectPath(
97 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +053098
Gunnar Mills57d9c502018-09-14 14:42:34 -050099 this->addrs.emplace(addr.ipaddress,
100 std::make_shared<phosphor::network::IPAddress>(
101 bus, ipAddressObjectPath.c_str(), *this,
102 addressType, addr.ipaddress, origin,
103 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530104 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530105}
106
William A. Kennington III08505792019-01-30 16:00:04 -0800107void EthernetInterface::createStaticNeighborObjects()
108{
109 staticNeighbors.clear();
110
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700111 NeighborFilter filter;
112 filter.interface = ifIndex();
113 filter.state = NUD_PERMANENT;
114 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800115 for (const auto& neighbor : neighbors)
116 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700117 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800118 {
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
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700131unsigned EthernetInterface::ifIndex() const
132{
133 unsigned idx = if_nametoindex(interfaceName().c_str());
134 if (idx == 0)
135 {
136 throw std::system_error(errno, std::generic_category(),
137 "if_nametoindex");
138 }
139 return idx;
140}
141
raviteja-bce379562019-03-28 05:59:36 -0500142ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
143 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530144{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530145
146 if (dHCPEnabled())
147 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530148 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500149 entry("INTERFACE=%s", interfaceName().c_str());
150 dHCPEnabled(false);
151 }
152
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500153 IP::AddressOrigin origin = IP::AddressOrigin::Static;
154
155 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
156
157 if (!isValidIP(addressFamily, ipaddress))
158 {
159 log<level::ERR>("Not a valid IP address"),
160 entry("ADDRESS=%s", ipaddress.c_str());
161 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
162 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
163 }
164
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700165 // Gateway is an obsolete parameter
166 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500167
168 if (!isValidPrefix(addressFamily, prefixLength))
169 {
170 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700171 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500172 elog<InvalidArgument>(
173 Argument::ARGUMENT_NAME("prefixLength"),
174 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530175 }
176
Gunnar Mills57d9c502018-09-14 14:42:34 -0500177 std::string objectPath =
178 generateObjectPath(protType, ipaddress, prefixLength, gateway);
179 this->addrs.emplace(ipaddress,
180 std::make_shared<phosphor::network::IPAddress>(
181 bus, objectPath.c_str(), *this, protType, ipaddress,
182 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530183
Ratan Guptae05083a2017-09-16 07:12:11 +0530184 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500185 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530186}
187
William A. Kennington III08505792019-01-30 16:00:04 -0800188ObjectPath EthernetInterface::neighbor(std::string iPAddress,
189 std::string mACAddress)
190{
191 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
192 {
193 log<level::ERR>("Not a valid IP address",
194 entry("ADDRESS=%s", iPAddress.c_str()));
195 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
196 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
197 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700198 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800199 {
200 log<level::ERR>("Not a valid MAC address",
201 entry("MACADDRESS=%s", iPAddress.c_str()));
202 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
203 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
204 }
205
206 std::string objectPath =
207 generateStaticNeighborObjectPath(iPAddress, mACAddress);
208 staticNeighbors.emplace(iPAddress,
209 std::make_shared<phosphor::network::Neighbor>(
210 bus, objectPath.c_str(), *this, iPAddress,
211 mACAddress, Neighbor::State::Permanent));
212 manager.writeToConfigurationFile();
213 return objectPath;
214}
215
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530216/*
217Note: We don't have support for ethtool now
218will enable this code once we bring the ethtool
219in the image.
220TODO: https://github.com/openbmc/openbmc/issues/1484
221*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530222
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530223InterfaceInfo EthernetInterface::getInterfaceInfo() const
224{
225 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400226 ifreq ifr{0};
227 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500228 LinkSpeed speed{0};
229 Autoneg autoneg{0};
230 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530231 do
232 {
233 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
234 if (sock < 0)
235 {
236 log<level::ERR>("socket creation failed:",
237 entry("ERROR=%s", strerror(errno)));
238 break;
239 }
240
William A. Kennington III0420c6a2019-06-27 14:38:17 -0700241 strcpy(ifr.ifr_name, interfaceName().c_str());
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530242 ifr.ifr_data = reinterpret_cast<char*>(&edata);
243
244 edata.cmd = ETHTOOL_GSET;
245
246 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
247 {
248 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
249 entry("ERROR=%s", strerror(errno)));
250 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530251 }
252 speed = edata.speed;
253 duplex = edata.duplex;
254 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500255 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530256
257 if (sock)
258 {
259 close(sock);
260 }
261 return std::make_tuple(speed, duplex, autoneg);
262}
263
264/** @brief get the mac address of the interface.
265 * @return macaddress on success
266 */
267
Gunnar Mills57d9c502018-09-14 14:42:34 -0500268std::string
269 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530270{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400271 ifreq ifr{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530272 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
273 if (sock < 0)
274 {
275 log<level::ERR>("socket creation failed:",
276 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700277 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530278 }
279
Patrick Venture836c91d2018-09-11 17:36:03 -0700280 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530281 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530282 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530283 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500284 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
William A. Kennington III1137a972019-04-20 20:49:58 -0700288 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
289 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
290 sizeof(ifr.ifr_hwaddr.sa_data));
291 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530292}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530293
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530294std::string EthernetInterface::generateId(const std::string& ipaddress,
295 uint8_t prefixLength,
296 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530297{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530298 std::stringstream hexId;
299 std::string hashString = ipaddress;
300 hashString += std::to_string(prefixLength);
301 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530302
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530303 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500304 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530305 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530306}
307
William A. Kennington III08505792019-01-30 16:00:04 -0800308std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
309 const std::string& mACAddress)
310{
311 std::stringstream hexId;
312 std::string hashString = iPAddress + mACAddress;
313
314 // Only want 8 hex digits.
315 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
316 return hexId.str();
317}
318
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530319void EthernetInterface::deleteObject(const std::string& ipaddress)
320{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530321 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530322 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530323 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530324 log<level::ERR>("DeleteObject:Unable to find the object.");
325 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530326 }
327 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530328 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530329}
330
William A. Kennington III08505792019-01-30 16:00:04 -0800331void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
332{
333 auto it = staticNeighbors.find(iPAddress);
334 if (it == staticNeighbors.end())
335 {
336 log<level::ERR>(
337 "DeleteStaticNeighborObject:Unable to find the object.");
338 return;
339 }
340 staticNeighbors.erase(it);
341 manager.writeToConfigurationFile();
342}
343
Ratan Guptae9c9b812017-09-22 17:15:37 +0530344void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530345{
Ratan Guptabc886292017-07-25 18:29:57 +0530346 auto confDir = manager.getConfDir();
347 fs::path networkFile = confDir;
348 networkFile /= systemd::config::networkFilePrefix + interface +
349 systemd::config::networkFileSuffix;
350
351 fs::path deviceFile = confDir;
352 deviceFile /= interface + systemd::config::deviceFileSuffix;
353
354 // delete the vlan network file
355 if (fs::is_regular_file(networkFile))
356 {
357 fs::remove(networkFile);
358 }
359
360 // delete the vlan device file
361 if (fs::is_regular_file(deviceFile))
362 {
363 fs::remove(deviceFile);
364 }
Ratan Guptabc886292017-07-25 18:29:57 +0530365
366 // TODO systemd doesn't delete the virtual network interface
367 // even after deleting all the related configuartion.
368 // https://github.com/systemd/systemd/issues/6600
369 try
370 {
371 deleteInterface(interface);
372 }
373 catch (InternalFailure& e)
374 {
375 commit<InternalFailure>();
376 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530377}
378
379void EthernetInterface::deleteVLANObject(const std::string& interface)
380{
381 auto it = vlanInterfaces.find(interface);
382 if (it == vlanInterfaces.end())
383 {
384 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500385 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530386 return;
387 }
388
389 deleteVLANFromSystem(interface);
390 // delete the interface
391 vlanInterfaces.erase(it);
392
Ratan Guptae05083a2017-09-16 07:12:11 +0530393 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530394}
395
Gunnar Mills57d9c502018-09-14 14:42:34 -0500396std::string EthernetInterface::generateObjectPath(
397 IP::Protocol addressType, const std::string& ipaddress,
398 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530399{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530400 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530401 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530402 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
403
404 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530405 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530406 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530407 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530408 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530409}
410
William A. Kennington III08505792019-01-30 16:00:04 -0800411std::string EthernetInterface::generateStaticNeighborObjectPath(
412 const std::string& iPAddress, const std::string& mACAddress) const
413{
414 std::experimental::filesystem::path objectPath;
415 objectPath /= objPath;
416 objectPath /= "static_neighbor";
417 objectPath /= generateNeighborId(iPAddress, mACAddress);
418 return objectPath.string();
419}
420
Ratan Gupta87c13982017-06-15 09:27:27 +0530421bool EthernetInterface::dHCPEnabled(bool value)
422{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530423 if (value == EthernetInterfaceIntf::dHCPEnabled())
424 {
425 return value;
426 }
427
Ratan Gupta87c13982017-06-15 09:27:27 +0530428 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530429 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530430 return value;
431}
432
Ratan Gupta6dec3902017-08-20 15:28:12 +0530433ServerList EthernetInterface::nameservers(ServerList value)
434{
435 try
436 {
437 EthernetInterfaceIntf::nameservers(value);
438
439 writeConfigurationFile();
440
441 // Currently we don't have systemd-resolved enabled
442 // in the openbmc. Once we update the network conf file,
443 // it should be read by systemd-resolved.service.
444
445 // The other reason to write the resolv conf is,
446 // we don't want to restart the networkd for nameserver change.
447 // as restarting of systemd-networkd takes more then 2 secs
448 writeDNSEntries(value, resolvConfFile);
449 }
450 catch (InternalFailure& e)
451 {
452 log<level::ERR>("Exception processing DNS entries");
453 }
454 return EthernetInterfaceIntf::nameservers();
455}
456
457ServerList EthernetInterface::getNameServerFromConf()
458{
459 fs::path confPath = manager.getConfDir();
460
461 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500462 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530463 confPath /= fileName;
464 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530465 config::Parser parser(confPath.string());
466 auto rc = config::ReturnCode::SUCCESS;
467
468 std::tie(rc, servers) = parser.getValues("Network", "DNS");
469 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530470 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530471 log<level::DEBUG>("Unable to get the value for network[DNS]",
472 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530473 }
474 return servers;
475}
476
477void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
478 const std::string& file)
479{
480 std::fstream outStream(file, std::fstream::out);
481 if (!outStream.is_open())
482 {
483 log<level::ERR>("Unable to open the file",
484 entry("FILE=%s", file.c_str()));
485 elog<InternalFailure>();
486 }
487
Ratan Guptafe116912017-11-10 16:00:59 +0530488 outStream << "### Generated manually via dbus settings ###\n";
Gunnar Mills57d9c502018-09-14 14:42:34 -0500489 for (const auto& server : dnsList)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530490 {
491 outStream << "nameserver " << server << "\n";
492 }
493}
494
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530495void EthernetInterface::loadVLAN(VlanId id)
496{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500497 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530498 std::string path = objPath;
499 path += "_" + std::to_string(id);
500
Gunnar Mills57d9c502018-09-14 14:42:34 -0500501 auto dhcpEnabled =
502 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530503
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530504 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500505 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530506
Gunnar Mills57d9c502018-09-14 14:42:34 -0500507 // Fetch the ip address from the system
508 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530509 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800510 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530511
512 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
513 std::move(vlanIntf));
514}
515
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700516ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530517{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500518 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530519 std::string path = objPath;
520 path += "_" + std::to_string(id);
521
Ratan Gupta5978dd12017-07-25 13:47:13 +0530522 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500523 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530524
525 // write the device file for the vlan interface.
526 vlanIntf->writeDeviceFile();
527
Gunnar Mills57d9c502018-09-14 14:42:34 -0500528 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530529 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530530 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700531
532 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530533}
Ratan Gupta2b106532017-07-25 16:05:02 +0530534
Ratan Gupta497c0c92017-08-22 19:15:59 +0530535ServerList EthernetInterface::getNTPServersFromConf()
536{
537 fs::path confPath = manager.getConfDir();
538
Gunnar Mills57d9c502018-09-14 14:42:34 -0500539 std::string fileName = systemd::config::networkFilePrefix +
540 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530541 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530542
Ratan Gupta497c0c92017-08-22 19:15:59 +0530543 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530544 config::Parser parser(confPath.string());
545 auto rc = config::ReturnCode::SUCCESS;
546
547 std::tie(rc, servers) = parser.getValues("Network", "NTP");
548 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530549 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530550 log<level::DEBUG>("Unable to get the value for Network[NTP]",
551 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530552 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530553
Ratan Gupta497c0c92017-08-22 19:15:59 +0530554 return servers;
555}
556
557ServerList EthernetInterface::nTPServers(ServerList servers)
558{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500559 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530560
561 writeConfigurationFile();
562 // timesynchd reads the NTP server configuration from the
563 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530564 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530565 return ntpServers;
566}
Ratan Gupta2b106532017-07-25 16:05:02 +0530567// Need to merge the below function with the code which writes the
568// config file during factory reset.
569// TODO openbmc/openbmc#1751
570
571void EthernetInterface::writeConfigurationFile()
572{
573 // write all the static ip address in the systemd-network conf file
574
575 using namespace std::string_literals;
576 using AddressOrigin =
577 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
578 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530579
580 // if there is vlan interafce then write the configuration file
581 // for vlan also.
582
Gunnar Mills57d9c502018-09-14 14:42:34 -0500583 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530584 {
585 intf.second->writeConfigurationFile();
586 }
587
Ratan Gupta2b106532017-07-25 16:05:02 +0530588 fs::path confPath = manager.getConfDir();
589
Gunnar Mills57d9c502018-09-14 14:42:34 -0500590 std::string fileName = systemd::config::networkFilePrefix +
591 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530592 confPath /= fileName;
593 std::fstream stream;
594
595 stream.open(confPath.c_str(), std::fstream::out);
596 if (!stream.is_open())
597 {
598 log<level::ERR>("Unable to open the file",
599 entry("FILE=%s", confPath.c_str()));
600 elog<InternalFailure>();
601 }
602
603 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400604 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530605 stream << "Name=" << interfaceName() << "\n";
606
607 auto addrs = getAddresses();
608
609 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400610 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400611#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500612 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400613#else
614 stream << "LinkLocalAddressing=no\n";
615#endif
Ratan Guptae9629412017-12-21 08:20:25 +0530616 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530617
618 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500619 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530620 {
621 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500622 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530623 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500624 // Add the DHCP entry
625 auto value = dHCPEnabled() ? "true"s : "false"s;
626 stream << "DHCP="s + value + "\n";
627
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600628 // When the interface configured as dhcp, we don't need below given entries
629 // in config file.
630 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530631 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500632 // Add the NTP server
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600633 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530634 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600635 stream << "NTP=" << ntp << "\n";
636 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530637
Gunnar Mills57d9c502018-09-14 14:42:34 -0500638 // Add the DNS entry
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600639 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530640 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600641 stream << "DNS=" << dns << "\n";
642 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530643
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600644 // Static
645 for (const auto& addr : addrs)
646 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400647 if (addr.second->origin() == AddressOrigin::Static
648#ifndef LINK_LOCAL_AUTOCONFIGURATION
649 || addr.second->origin() == AddressOrigin::LinkLocal
650#endif
651 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530652 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500653 std::string address =
654 addr.second->address() + "/" +
655 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530656
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600657 stream << "Address=" << address << "\n";
658 }
659 }
660
661 if (manager.getSystemConf())
662 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800663 const auto& gateway = manager.getSystemConf()->defaultGateway();
664 if (!gateway.empty())
665 {
666 stream << "Gateway=" << gateway << "\n";
667 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800668 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
669 if (!gateway6.empty())
670 {
671 stream << "Gateway=" << gateway6 << "\n";
672 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600673 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530674 }
675
William A. Kennington III08505792019-01-30 16:00:04 -0800676 // Write the neighbor sections
677 for (const auto& neighbor : staticNeighbors)
678 {
679 stream << "[Neighbor]"
680 << "\n";
681 stream << "Address=" << neighbor.second->iPAddress() << "\n";
682 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
683 }
684
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600685 // Write the dhcp section irrespective of whether DHCP is enabled or not
686 writeDHCPSection(stream);
687
Ratan Gupta2b106532017-07-25 16:05:02 +0530688 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530689}
690
691void EthernetInterface::writeDHCPSection(std::fstream& stream)
692{
693 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530694 // write the dhcp section
695 stream << "[DHCP]\n";
696
697 // Hardcoding the client identifier to mac, to address below issue
698 // https://github.com/openbmc/openbmc/issues/1280
699 stream << "ClientIdentifier=mac\n";
700 if (manager.getDHCPConf())
701 {
702 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
703 stream << "UseDNS="s + value + "\n";
704
705 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
706 stream << "UseNTP="s + value + "\n";
707
708 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
709 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600710
711 value =
712 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
713 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530714 }
715}
716
Ratan Guptabd303b12017-08-18 17:10:07 +0530717std::string EthernetInterface::mACAddress(std::string value)
718{
William A. Kennington III1137a972019-04-20 20:49:58 -0700719 ether_addr newMAC = mac_address::fromString(value);
720 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530721 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500722 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500723 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500724 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
725 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530726 }
727
William A. Kennington III1137a972019-04-20 20:49:58 -0700728 // We don't need to update the system if the address is unchanged
729 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
730 if (!equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530731 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700732 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530733 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700734 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530735 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700736 auto inventoryMAC = mac_address::getfromInventory(bus);
737 if (!equal(newMAC, inventoryMAC))
738 {
739 log<level::ERR>(
740 "Given MAC address is neither a local Admin "
741 "type nor is same as in inventory");
742 elog<InvalidArgument>(
743 Argument::ARGUMENT_NAME("MACAddress"),
744 Argument::ARGUMENT_VALUE(value.c_str()));
745 }
746 }
747 catch (const std::exception& e)
748 {
749 log<level::ERR>("Exception occurred during getting of MAC "
750 "address from Inventory");
751 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530752 }
753 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700754
755 // Update everything that depends on the MAC value
756 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530757 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700758 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530759 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700760 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530761
William A. Kennington III1137a972019-04-20 20:49:58 -0700762 auto interface = interfaceName();
763 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
764 // TODO: would replace below three calls
765 // with restarting of systemd-netwokd
766 // through https://github.com/systemd/systemd/issues/6696
767 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
768 "down");
769 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
770 "address", value.c_str());
771 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
772 "up");
Ratan Gupta895f9e52018-11-26 20:57:34 +0530773 manager.restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530774 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700775
776 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530777}
778
Ratan Guptae9c9b812017-09-22 17:15:37 +0530779void EthernetInterface::deleteAll()
780{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500781 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530782 {
783 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500784 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530785 }
786
787 // clear all the ip on the interface
788 addrs.clear();
789 manager.writeToConfigurationFile();
790}
791
Gunnar Mills57d9c502018-09-14 14:42:34 -0500792} // namespace network
793} // namespace phosphor