blob: 154efcbfa592e332d2b2ea3a2f57fd1e1b851b34 [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"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05307#include "network_manager.hpp"
Ratan Guptafc2c7242017-05-29 08:46:06 +05308#include "routing_table.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>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053013#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053014#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053015#include <netinet/in.h>
16#include <sys/ioctl.h>
17#include <sys/socket.h>
18#include <unistd.h>
19
Ratan Gupta82549cc2017-04-21 08:45:23 +053020#include <algorithm>
21#include <experimental/filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053022#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070023#include <phosphor-logging/elog-errors.hpp>
24#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053025#include <sstream>
26#include <string>
Patrick Venture189d44e2018-07-09 12:30:59 -070027#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053028
Ratan Gupta91a99cc2017-04-14 16:32:09 +053029namespace phosphor
30{
31namespace network
32{
33
34using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053035using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050036using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta2b106532017-07-25 16:05:02 +053037
Ratan Gupta91a99cc2017-04-14 16:32:09 +053038EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
39 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050040 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053041 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 Ifaces(bus, objPath.c_str(), true),
43 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053044{
45 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053046 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053047 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053048 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Ratan Guptabd303b12017-08-18 17:10:07 +053049 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053050 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec3902017-08-20 15:28:12 +053051 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
52
Ratan Gupta29b0e432017-05-25 12:51:40 +053053 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053054 if (emitSignal)
55 {
56 this->emit_object_added();
57 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053058}
59
William A. Kennington IIIfbafa252018-11-30 16:53:52 -080060static IP::Protocol convertFamily(int family)
61{
62 switch (family)
63 {
64 case AF_INET:
65 return IP::Protocol::IPv4;
66 case AF_INET6:
67 return IP::Protocol::IPv6;
68 }
69
70 throw std::invalid_argument("Bad address family");
71}
72
Ratan Gupta87c13982017-06-15 09:27:27 +053073void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053074{
Ratan Gupta87c13982017-06-15 09:27:27 +053075 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053076
Ratan Gupta87c13982017-06-15 09:27:27 +053077 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053078
Ratan Guptafc2c7242017-05-29 08:46:06 +053079 route::Table routingTable;
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 IIIfbafa252018-11-30 16:53:52 -080093 std::string gateway =
Gunnar Mills57d9c502018-09-14 14:42:34 -050094 routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
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
raviteja-bce379562019-03-28 05:59:36 -0500107ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
108 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530109{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530110
111 if (dHCPEnabled())
112 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530113 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500114 entry("INTERFACE=%s", interfaceName().c_str());
115 dHCPEnabled(false);
116 }
117
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500118 IP::AddressOrigin origin = IP::AddressOrigin::Static;
119
120 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
121
122 if (!isValidIP(addressFamily, ipaddress))
123 {
124 log<level::ERR>("Not a valid IP address"),
125 entry("ADDRESS=%s", ipaddress.c_str());
126 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
127 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
128 }
129
130 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
131 {
132 log<level::ERR>("Not a valid Gateway"),
133 entry("GATEWAY=%s", gateway.c_str());
134 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
135 Argument::ARGUMENT_VALUE(gateway.c_str()));
136 }
137
138 if (!isValidPrefix(addressFamily, prefixLength))
139 {
140 log<level::ERR>("PrefixLength is not correct "),
141 entry("PREFIXLENGTH=%d", gateway.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500142 elog<InvalidArgument>(
143 Argument::ARGUMENT_NAME("prefixLength"),
144 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530145 }
146
Gunnar Mills57d9c502018-09-14 14:42:34 -0500147 std::string objectPath =
148 generateObjectPath(protType, ipaddress, prefixLength, gateway);
149 this->addrs.emplace(ipaddress,
150 std::make_shared<phosphor::network::IPAddress>(
151 bus, objectPath.c_str(), *this, protType, ipaddress,
152 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530153
Ratan Guptae05083a2017-09-16 07:12:11 +0530154 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500155 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530156}
157
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530158/*
159Note: We don't have support for ethtool now
160will enable this code once we bring the ethtool
161in the image.
162TODO: https://github.com/openbmc/openbmc/issues/1484
163*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530164
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530165InterfaceInfo EthernetInterface::getInterfaceInfo() const
166{
167 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400168 ifreq ifr{0};
169 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500170 LinkSpeed speed{0};
171 Autoneg autoneg{0};
172 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530173 do
174 {
175 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
176 if (sock < 0)
177 {
178 log<level::ERR>("socket creation failed:",
179 entry("ERROR=%s", strerror(errno)));
180 break;
181 }
182
183 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
184 ifr.ifr_data = reinterpret_cast<char*>(&edata);
185
186 edata.cmd = ETHTOOL_GSET;
187
188 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
189 {
190 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
191 entry("ERROR=%s", strerror(errno)));
192 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530193 }
194 speed = edata.speed;
195 duplex = edata.duplex;
196 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500197 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530198
199 if (sock)
200 {
201 close(sock);
202 }
203 return std::make_tuple(speed, duplex, autoneg);
204}
205
206/** @brief get the mac address of the interface.
207 * @return macaddress on success
208 */
209
Gunnar Mills57d9c502018-09-14 14:42:34 -0500210std::string
211 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530212{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400213 ifreq ifr{};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500214 char macAddress[mac_address::size]{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530215
216 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
217 if (sock < 0)
218 {
219 log<level::ERR>("socket creation failed:",
220 entry("ERROR=%s", strerror(errno)));
221 return macAddress;
222 }
223
Patrick Venture836c91d2018-09-11 17:36:03 -0700224 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530225 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530226 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530227 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500228 entry("ERROR=%s", strerror(errno)));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530229 return macAddress;
230 }
231
Patrick Venture836c91d2018-09-11 17:36:03 -0700232 std::snprintf(macAddress, mac_address::size, mac_address::format,
233 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
234 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
235 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530236
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530237 return macAddress;
238}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530239
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530240std::string EthernetInterface::generateId(const std::string& ipaddress,
241 uint8_t prefixLength,
242 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530243{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530244 std::stringstream hexId;
245 std::string hashString = ipaddress;
246 hashString += std::to_string(prefixLength);
247 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530248
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530249 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500250 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530251 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530252}
253
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530254void EthernetInterface::deleteObject(const std::string& ipaddress)
255{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530256 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530257 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530258 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530259 log<level::ERR>("DeleteObject:Unable to find the object.");
260 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530261 }
262 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530263 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530264}
265
Ratan Guptae9c9b812017-09-22 17:15:37 +0530266void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530267{
Ratan Guptabc886292017-07-25 18:29:57 +0530268 auto confDir = manager.getConfDir();
269 fs::path networkFile = confDir;
270 networkFile /= systemd::config::networkFilePrefix + interface +
271 systemd::config::networkFileSuffix;
272
273 fs::path deviceFile = confDir;
274 deviceFile /= interface + systemd::config::deviceFileSuffix;
275
276 // delete the vlan network file
277 if (fs::is_regular_file(networkFile))
278 {
279 fs::remove(networkFile);
280 }
281
282 // delete the vlan device file
283 if (fs::is_regular_file(deviceFile))
284 {
285 fs::remove(deviceFile);
286 }
Ratan Guptabc886292017-07-25 18:29:57 +0530287
288 // TODO systemd doesn't delete the virtual network interface
289 // even after deleting all the related configuartion.
290 // https://github.com/systemd/systemd/issues/6600
291 try
292 {
293 deleteInterface(interface);
294 }
295 catch (InternalFailure& e)
296 {
297 commit<InternalFailure>();
298 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530299}
300
301void EthernetInterface::deleteVLANObject(const std::string& interface)
302{
303 auto it = vlanInterfaces.find(interface);
304 if (it == vlanInterfaces.end())
305 {
306 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500307 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530308 return;
309 }
310
311 deleteVLANFromSystem(interface);
312 // delete the interface
313 vlanInterfaces.erase(it);
314
Ratan Guptae05083a2017-09-16 07:12:11 +0530315 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530316}
317
Gunnar Mills57d9c502018-09-14 14:42:34 -0500318std::string EthernetInterface::generateObjectPath(
319 IP::Protocol addressType, const std::string& ipaddress,
320 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530321{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530322 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530323 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530324 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
325
326 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530327 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530328 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530329 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530330 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530331}
332
Ratan Gupta87c13982017-06-15 09:27:27 +0530333bool EthernetInterface::dHCPEnabled(bool value)
334{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530335 if (value == EthernetInterfaceIntf::dHCPEnabled())
336 {
337 return value;
338 }
339
Ratan Gupta87c13982017-06-15 09:27:27 +0530340 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530341 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530342 return value;
343}
344
Ratan Gupta6dec3902017-08-20 15:28:12 +0530345ServerList EthernetInterface::nameservers(ServerList value)
346{
347 try
348 {
349 EthernetInterfaceIntf::nameservers(value);
350
351 writeConfigurationFile();
352
353 // Currently we don't have systemd-resolved enabled
354 // in the openbmc. Once we update the network conf file,
355 // it should be read by systemd-resolved.service.
356
357 // The other reason to write the resolv conf is,
358 // we don't want to restart the networkd for nameserver change.
359 // as restarting of systemd-networkd takes more then 2 secs
360 writeDNSEntries(value, resolvConfFile);
361 }
362 catch (InternalFailure& e)
363 {
364 log<level::ERR>("Exception processing DNS entries");
365 }
366 return EthernetInterfaceIntf::nameservers();
367}
368
369ServerList EthernetInterface::getNameServerFromConf()
370{
371 fs::path confPath = manager.getConfDir();
372
373 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500374 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530375 confPath /= fileName;
376 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530377 config::Parser parser(confPath.string());
378 auto rc = config::ReturnCode::SUCCESS;
379
380 std::tie(rc, servers) = parser.getValues("Network", "DNS");
381 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530382 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530383 log<level::DEBUG>("Unable to get the value for network[DNS]",
384 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530385 }
386 return servers;
387}
388
389void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
390 const std::string& file)
391{
392 std::fstream outStream(file, std::fstream::out);
393 if (!outStream.is_open())
394 {
395 log<level::ERR>("Unable to open the file",
396 entry("FILE=%s", file.c_str()));
397 elog<InternalFailure>();
398 }
399
Ratan Guptafe116912017-11-10 16:00:59 +0530400 outStream << "### Generated manually via dbus settings ###\n";
Gunnar Mills57d9c502018-09-14 14:42:34 -0500401 for (const auto& server : dnsList)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530402 {
403 outStream << "nameserver " << server << "\n";
404 }
405}
406
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530407void EthernetInterface::loadVLAN(VlanId id)
408{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500409 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530410 std::string path = objPath;
411 path += "_" + std::to_string(id);
412
Gunnar Mills57d9c502018-09-14 14:42:34 -0500413 auto dhcpEnabled =
414 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530415
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530416 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500417 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530418
Gunnar Mills57d9c502018-09-14 14:42:34 -0500419 // Fetch the ip address from the system
420 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530421 vlanIntf->createIPAddressObjects();
422
423 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
424 std::move(vlanIntf));
425}
426
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700427ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530428{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500429 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530430 std::string path = objPath;
431 path += "_" + std::to_string(id);
432
Ratan Gupta5978dd12017-07-25 13:47:13 +0530433 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500434 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530435
436 // write the device file for the vlan interface.
437 vlanIntf->writeDeviceFile();
438
Gunnar Mills57d9c502018-09-14 14:42:34 -0500439 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530440 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530441 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700442
443 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530444}
Ratan Gupta2b106532017-07-25 16:05:02 +0530445
Ratan Gupta497c0c92017-08-22 19:15:59 +0530446ServerList EthernetInterface::getNTPServersFromConf()
447{
448 fs::path confPath = manager.getConfDir();
449
Gunnar Mills57d9c502018-09-14 14:42:34 -0500450 std::string fileName = systemd::config::networkFilePrefix +
451 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530452 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530453
Ratan Gupta497c0c92017-08-22 19:15:59 +0530454 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530455 config::Parser parser(confPath.string());
456 auto rc = config::ReturnCode::SUCCESS;
457
458 std::tie(rc, servers) = parser.getValues("Network", "NTP");
459 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530460 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530461 log<level::DEBUG>("Unable to get the value for Network[NTP]",
462 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530463 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530464
Ratan Gupta497c0c92017-08-22 19:15:59 +0530465 return servers;
466}
467
468ServerList EthernetInterface::nTPServers(ServerList servers)
469{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500470 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530471
472 writeConfigurationFile();
473 // timesynchd reads the NTP server configuration from the
474 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530475 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530476 return ntpServers;
477}
Ratan Gupta2b106532017-07-25 16:05:02 +0530478// Need to merge the below function with the code which writes the
479// config file during factory reset.
480// TODO openbmc/openbmc#1751
481
482void EthernetInterface::writeConfigurationFile()
483{
484 // write all the static ip address in the systemd-network conf file
485
486 using namespace std::string_literals;
487 using AddressOrigin =
488 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
489 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530490
491 // if there is vlan interafce then write the configuration file
492 // for vlan also.
493
Gunnar Mills57d9c502018-09-14 14:42:34 -0500494 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530495 {
496 intf.second->writeConfigurationFile();
497 }
498
Ratan Gupta2b106532017-07-25 16:05:02 +0530499 fs::path confPath = manager.getConfDir();
500
Gunnar Mills57d9c502018-09-14 14:42:34 -0500501 std::string fileName = systemd::config::networkFilePrefix +
502 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530503 confPath /= fileName;
504 std::fstream stream;
505
506 stream.open(confPath.c_str(), std::fstream::out);
507 if (!stream.is_open())
508 {
509 log<level::ERR>("Unable to open the file",
510 entry("FILE=%s", confPath.c_str()));
511 elog<InternalFailure>();
512 }
513
514 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400515 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530516 stream << "Name=" << interfaceName() << "\n";
517
518 auto addrs = getAddresses();
519
520 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400521 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400522#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500523 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400524#else
525 stream << "LinkLocalAddressing=no\n";
526#endif
Ratan Guptae9629412017-12-21 08:20:25 +0530527 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530528
529 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500530 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530531 {
532 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500533 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530534 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500535 // Add the DHCP entry
536 auto value = dHCPEnabled() ? "true"s : "false"s;
537 stream << "DHCP="s + value + "\n";
538
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600539 // When the interface configured as dhcp, we don't need below given entries
540 // in config file.
541 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530542 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500543 // Add the NTP server
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600544 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530545 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600546 stream << "NTP=" << ntp << "\n";
547 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530548
Gunnar Mills57d9c502018-09-14 14:42:34 -0500549 // Add the DNS entry
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600550 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530551 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600552 stream << "DNS=" << dns << "\n";
553 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530554
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600555 // Static
556 for (const auto& addr : addrs)
557 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400558 if (addr.second->origin() == AddressOrigin::Static
559#ifndef LINK_LOCAL_AUTOCONFIGURATION
560 || addr.second->origin() == AddressOrigin::LinkLocal
561#endif
562 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530563 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500564 std::string address =
565 addr.second->address() + "/" +
566 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530567
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600568 stream << "Address=" << address << "\n";
569 }
570 }
571
572 if (manager.getSystemConf())
573 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800574 const auto& gateway = manager.getSystemConf()->defaultGateway();
575 if (!gateway.empty())
576 {
577 stream << "Gateway=" << gateway << "\n";
578 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800579 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
580 if (!gateway6.empty())
581 {
582 stream << "Gateway=" << gateway6 << "\n";
583 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600584 }
585
586 // write the route section
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600587 for (const auto& addr : addrs)
588 {
589 if (addr.second->origin() == AddressOrigin::Static)
590 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500591 int addressFamily = addr.second->type() == IP::Protocol::IPv4
592 ? AF_INET
593 : AF_INET6;
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600594
Gunnar Mills57d9c502018-09-14 14:42:34 -0500595 std::string destination =
596 getNetworkID(addressFamily, addr.second->address(),
597 addr.second->prefixLength());
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600598
599 if (addr.second->gateway() != "0.0.0.0" &&
Gunnar Mills57d9c502018-09-14 14:42:34 -0500600 addr.second->gateway() != "" && destination != "0.0.0.0" &&
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600601 destination != "")
602 {
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400603 stream << "[Route]\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600604 stream << "Gateway=" << addr.second->gateway() << "\n";
605 stream << "Destination=" << destination << "\n";
606 }
607 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530608 }
609 }
610
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600611 // Write the dhcp section irrespective of whether DHCP is enabled or not
612 writeDHCPSection(stream);
613
Ratan Gupta2b106532017-07-25 16:05:02 +0530614 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530615}
616
617void EthernetInterface::writeDHCPSection(std::fstream& stream)
618{
619 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530620 // write the dhcp section
621 stream << "[DHCP]\n";
622
623 // Hardcoding the client identifier to mac, to address below issue
624 // https://github.com/openbmc/openbmc/issues/1280
625 stream << "ClientIdentifier=mac\n";
626 if (manager.getDHCPConf())
627 {
628 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
629 stream << "UseDNS="s + value + "\n";
630
631 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
632 stream << "UseNTP="s + value + "\n";
633
634 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
635 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600636
637 value =
638 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
639 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530640 }
641}
642
Ratan Guptabd303b12017-08-18 17:10:07 +0530643std::string EthernetInterface::mACAddress(std::string value)
644{
645 if (!mac_address::validate(value))
646 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500647 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500648 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500649 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
650 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530651 }
652
653 // check whether MAC is broadcast mac.
654 auto intMac = mac_address::internal::convertToInt(value);
655
656 if (!(intMac ^ mac_address::broadcastMac))
657 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500658 log<level::ERR>("MACAddress is a broadcast mac.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500659 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500660 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
661 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530662 }
663
Patrick Ventured475cd62018-02-26 17:07:41 -0800664 // Check if the MAC changed.
665 auto pmac = MacAddressIntf::mACAddress();
666 if (strcasecmp(pmac.c_str(), value.c_str()) == 0)
667 {
668 return MacAddressIntf::mACAddress();
669 }
670
Ratan Guptabd303b12017-08-18 17:10:07 +0530671 // Allow the mac to be set if one of the condition is true.
672 // 1) Incoming Mac is of local admin type.
673 // or
674 // 2) Incoming mac is same as eeprom Mac.
675
676 if (!(intMac & mac_address::localAdminMask))
677 {
678 try
679 {
680 auto inventoryMac = mac_address::getfromInventory(bus);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500681 auto intInventoryMac =
682 mac_address::internal::convertToInt(inventoryMac);
Ratan Guptabd303b12017-08-18 17:10:07 +0530683
684 if (intInventoryMac != intMac)
685 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500686 log<level::ERR>("Given MAC address is neither a local Admin "
Gunnar Mills57d9c502018-09-14 14:42:34 -0500687 "type nor is same as in inventory");
Gunnar Mills90480c42018-06-19 16:02:17 -0500688 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
689 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530690 }
691 }
Gunnar Mills57d9c502018-09-14 14:42:34 -0500692 catch (InternalFailure& e)
Ratan Guptabd303b12017-08-18 17:10:07 +0530693 {
Patrick Venturee0ad43a2017-11-29 18:19:54 -0800694 log<level::ERR>("Exception occurred during getting of MAC "
695 "address from Inventory");
Gunnar Millsce262822018-06-19 16:21:34 -0500696 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530697 }
698 }
699 auto interface = interfaceName();
700 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500701 // TODO: would replace below three calls
Ratan Guptabd303b12017-08-18 17:10:07 +0530702 // with restarting of systemd-netwokd
703 // through https://github.com/systemd/systemd/issues/6696
704 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
Gunnar Mills57d9c502018-09-14 14:42:34 -0500705 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
706 "address", value.c_str());
Ratan Guptabd303b12017-08-18 17:10:07 +0530707
708 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
709
710 auto mac = MacAddressIntf::mACAddress(std::move(value));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500711 // update all the vlan interfaces
712 for (const auto& intf : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530713 {
714 intf.second->updateMacAddress();
715 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530716
717 // restart the systemd networkd so that dhcp client gets the
718 // ip for the changed mac address.
719 if (dHCPEnabled())
720 {
Ratan Gupta895f9e52018-11-26 20:57:34 +0530721 manager.restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530722 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530723 return mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530724}
725
Ratan Guptae9c9b812017-09-22 17:15:37 +0530726void EthernetInterface::deleteAll()
727{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500728 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530729 {
730 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500731 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530732 }
733
734 // clear all the ip on the interface
735 addrs.clear();
736 manager.writeToConfigurationFile();
737}
738
Gunnar Mills57d9c502018-09-14 14:42:34 -0500739} // namespace network
740} // namespace phosphor