blob: 72307065026b2f1fe4e85285f8420f32fe0548d2 [file] [log] [blame]
Ratan Gupta82549cc2017-04-21 08:45:23 +05301#include "config.h"
Ratan Gupta497c0c92017-08-22 19:15:59 +05302#include "config_parser.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05303#include "ethernet_interface.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05304#include "ipaddress.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05305#include "network_manager.hpp"
Ratan Guptafc2c7242017-05-29 08:46:06 +05306#include "routing_table.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05307#include "vlan_interface.hpp"
8#include "xyz/openbmc_project/Common/error.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05309
Ratan Gupta2b106532017-07-25 16:05:02 +053010#include <phosphor-logging/elog-errors.hpp>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053011#include <phosphor-logging/log.hpp>
12
Ratan Gupta82549cc2017-04-21 08:45:23 +053013#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/ethtool.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 Gupta2b106532017-07-25 16:05:02 +053022
Ratan Gupta82549cc2017-04-21 08:45:23 +053023#include <algorithm>
24#include <experimental/filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053025#include <fstream>
26#include <sstream>
27#include <string>
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,
Ratan Gupta4f1c18b2017-05-25 12:59:35 +053040 bool dhcpEnabled,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053041 Manager& parent,
42 bool emitSignal) :
Ratan Gupta82549cc2017-04-21 08:45:23 +053043 Ifaces(bus, objPath.c_str(), true),
Ratan Gupta4f1c18b2017-05-25 12:59:35 +053044 bus(bus),
Ratan Gupta47722dc2017-05-26 18:32:23 +053045 manager(parent),
46 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 Gupta6dec3902017-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
Ratan Gupta87c13982017-06-15 09:27:27 +053063void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053064{
Ratan Gupta82549cc2017-04-21 08:45:23 +053065 std::string gateway;
Ratan Gupta87c13982017-06-15 09:27:27 +053066 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053067
Ratan Gupta87c13982017-06-15 09:27:27 +053068 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053069
Ratan Gupta82549cc2017-04-21 08:45:23 +053070 IP::Protocol addressType = IP::Protocol::IPv4;
Ratan Gupta29b0e432017-05-25 12:51:40 +053071 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053072 route::Table routingTable;
Ratan Gupta5978dd12017-07-25 13:47:13 +053073
Ratan Gupta6a387c12017-08-03 13:26:19 +053074 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053075 {
76 if (addr.addrType == AF_INET6)
77 {
78 addressType = IP::Protocol::IPv6;
79 }
Ratan Guptafc2c7242017-05-29 08:46:06 +053080 if (dHCPEnabled())
81 {
82 origin = IP::AddressOrigin::DHCP;
83 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050084 else if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053085 {
86 origin = IP::AddressOrigin::LinkLocal;
87 }
88 gateway = routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
Ratan Gupta82549cc2017-04-21 08:45:23 +053089
Ratan Gupta65e5abe2017-05-23 13:20:44 +053090 std::string ipAddressObjectPath = generateObjectPath(addressType,
91 addr.ipaddress,
92 addr.prefix,
93 gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +053094
Ratan Gupta82549cc2017-04-21 08:45:23 +053095 this->addrs.emplace(
Ratan Guptae578d562017-08-02 07:04:16 +053096 std::move(addr.ipaddress),
97 std::make_shared<phosphor::network::IPAddress>(
Ratan Gupta719f83a2017-06-02 11:54:53 +053098 bus,
99 ipAddressObjectPath.c_str(),
100 *this,
101 addressType,
Ratan Gupta82549cc2017-04-21 08:45:23 +0530102 addr.ipaddress,
Ratan Gupta29b0e432017-05-25 12:51:40 +0530103 origin,
Ratan Gupta719f83a2017-06-02 11:54:53 +0530104 addr.prefix,
Ratan Guptae578d562017-08-02 07:04:16 +0530105 gateway));
Ratan Gupta603598d2017-11-14 20:58:38 +0530106
107 origin = IP::AddressOrigin::Static;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530108 }
Ratan Guptafc2c7242017-05-29 08:46:06 +0530109
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530110}
111
Ratan Gupta82549cc2017-04-21 08:45:23 +0530112void EthernetInterface::iP(IP::Protocol protType,
113 std::string ipaddress,
114 uint8_t prefixLength,
115 std::string gateway)
116{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530117
118 if (dHCPEnabled())
119 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530120 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500121 entry("INTERFACE=%s", interfaceName().c_str());
122 dHCPEnabled(false);
123 }
124
125
126 IP::AddressOrigin origin = IP::AddressOrigin::Static;
127
128 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
129
130 if (!isValidIP(addressFamily, ipaddress))
131 {
132 log<level::ERR>("Not a valid IP address"),
133 entry("ADDRESS=%s", ipaddress.c_str());
134 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
135 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
136 }
137
138 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
139 {
140 log<level::ERR>("Not a valid Gateway"),
141 entry("GATEWAY=%s", gateway.c_str());
142 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
143 Argument::ARGUMENT_VALUE(gateway.c_str()));
144 }
145
146 if (!isValidPrefix(addressFamily, prefixLength))
147 {
148 log<level::ERR>("PrefixLength is not correct "),
149 entry("PREFIXLENGTH=%d", gateway.c_str());
150 elog<InvalidArgument>(Argument::ARGUMENT_NAME("prefixLength"),
151 Argument::ARGUMENT_VALUE(std::to_string(
152 prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530153 return;
154 }
155
Ratan Gupta29b0e432017-05-25 12:51:40 +0530156
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530157 std::string objectPath = generateObjectPath(protType,
158 ipaddress,
159 prefixLength,
160 gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530161 this->addrs.emplace(
Ratan Guptae578d562017-08-02 07:04:16 +0530162 std::move(ipaddress),
163 std::make_shared<phosphor::network::IPAddress>(
164 bus,
165 objectPath.c_str(),
166 *this,
167 protType,
168 ipaddress,
169 origin,
170 prefixLength,
171 gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530172
Ratan Guptae05083a2017-09-16 07:12:11 +0530173 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530174}
175
176
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530177/*
178Note: We don't have support for ethtool now
179will enable this code once we bring the ethtool
180in the image.
181TODO: https://github.com/openbmc/openbmc/issues/1484
182*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530183
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530184InterfaceInfo EthernetInterface::getInterfaceInfo() const
185{
186 int sock{-1};
187 struct ifreq ifr{0};
188 struct ethtool_cmd edata{0};
189 LinkSpeed speed {0};
190 Autoneg autoneg {0};
191 DuplexMode duplex {0};
192 do
193 {
194 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
195 if (sock < 0)
196 {
197 log<level::ERR>("socket creation failed:",
198 entry("ERROR=%s", strerror(errno)));
199 break;
200 }
201
202 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
203 ifr.ifr_data = reinterpret_cast<char*>(&edata);
204
205 edata.cmd = ETHTOOL_GSET;
206
207 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
208 {
209 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
210 entry("ERROR=%s", strerror(errno)));
211 break;
212
213 }
214 speed = edata.speed;
215 duplex = edata.duplex;
216 autoneg = edata.autoneg;
217 }
218 while (0);
219
220 if (sock)
221 {
222 close(sock);
223 }
224 return std::make_tuple(speed, duplex, autoneg);
225}
226
227/** @brief get the mac address of the interface.
228 * @return macaddress on success
229 */
230
Ratan Guptada7d3af2017-08-13 17:49:56 +0530231std::string EthernetInterface::getMACAddress(
232 const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530233{
Ratan Guptada7d3af2017-08-13 17:49:56 +0530234 struct ifreq ifr{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530235 char macAddress[mac_address::size] {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530236
237 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
238 if (sock < 0)
239 {
240 log<level::ERR>("socket creation failed:",
241 entry("ERROR=%s", strerror(errno)));
242 return macAddress;
243 }
244
Ratan Guptada7d3af2017-08-13 17:49:56 +0530245 strcpy(ifr.ifr_name, interfaceName.c_str());
246 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530247 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530248 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
249 entry("ERROR=%s", strerror(errno)));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530250 return macAddress;
251 }
252
Ratan Guptabd303b12017-08-18 17:10:07 +0530253 snprintf(macAddress, mac_address::size, mac_address::format,
Ratan Guptada7d3af2017-08-13 17:49:56 +0530254 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
255 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
256 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530257
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530258 return macAddress;
259}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530260
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530261std::string EthernetInterface::generateId(const std::string& ipaddress,
262 uint8_t prefixLength,
263 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530264{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530265 std::stringstream hexId;
266 std::string hashString = ipaddress;
267 hashString += std::to_string(prefixLength);
268 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530269
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530270 // Only want 8 hex digits.
271 hexId << std::hex << ((std::hash<std::string> {}(
Ratan Guptafc2c7242017-05-29 08:46:06 +0530272 hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530273 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530274}
275
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530276void EthernetInterface::deleteObject(const std::string& ipaddress)
277{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530278 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530279 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530280 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530281 log<level::ERR>("DeleteObject:Unable to find the object.");
282 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530283 }
284 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530285 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530286}
287
Ratan Guptae9c9b812017-09-22 17:15:37 +0530288void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530289{
Ratan Guptabc886292017-07-25 18:29:57 +0530290 auto confDir = manager.getConfDir();
291 fs::path networkFile = confDir;
292 networkFile /= systemd::config::networkFilePrefix + interface +
293 systemd::config::networkFileSuffix;
294
295 fs::path deviceFile = confDir;
296 deviceFile /= interface + systemd::config::deviceFileSuffix;
297
298 // delete the vlan network file
299 if (fs::is_regular_file(networkFile))
300 {
301 fs::remove(networkFile);
302 }
303
304 // delete the vlan device file
305 if (fs::is_regular_file(deviceFile))
306 {
307 fs::remove(deviceFile);
308 }
Ratan Guptabc886292017-07-25 18:29:57 +0530309
310 // TODO systemd doesn't delete the virtual network interface
311 // even after deleting all the related configuartion.
312 // https://github.com/systemd/systemd/issues/6600
313 try
314 {
315 deleteInterface(interface);
316 }
317 catch (InternalFailure& e)
318 {
319 commit<InternalFailure>();
320 }
Ratan Guptae05083a2017-09-16 07:12:11 +0530321
Ratan Guptae9c9b812017-09-22 17:15:37 +0530322}
323
324void EthernetInterface::deleteVLANObject(const std::string& interface)
325{
326 auto it = vlanInterfaces.find(interface);
327 if (it == vlanInterfaces.end())
328 {
329 log<level::ERR>("DeleteVLANObject:Unable to find the object",
330 entry("INTERFACE=%s",interface.c_str()));
331 return;
332 }
333
334 deleteVLANFromSystem(interface);
335 // delete the interface
336 vlanInterfaces.erase(it);
337
Ratan Guptae05083a2017-09-16 07:12:11 +0530338 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530339}
340
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530341std::string EthernetInterface::generateObjectPath(IP::Protocol addressType,
342 const std::string& ipaddress,
343 uint8_t prefixLength,
344 const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530345{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530346 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530347 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530348 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
349
350 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530351 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530352 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530353 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530354 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530355}
356
Ratan Gupta87c13982017-06-15 09:27:27 +0530357bool EthernetInterface::dHCPEnabled(bool value)
358{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530359 if (value == EthernetInterfaceIntf::dHCPEnabled())
360 {
361 return value;
362 }
363
Ratan Gupta87c13982017-06-15 09:27:27 +0530364 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530365 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530366 return value;
367}
368
Ratan Gupta6dec3902017-08-20 15:28:12 +0530369ServerList EthernetInterface::nameservers(ServerList value)
370{
371 try
372 {
373 EthernetInterfaceIntf::nameservers(value);
374
375 writeConfigurationFile();
376
377 // Currently we don't have systemd-resolved enabled
378 // in the openbmc. Once we update the network conf file,
379 // it should be read by systemd-resolved.service.
380
381 // The other reason to write the resolv conf is,
382 // we don't want to restart the networkd for nameserver change.
383 // as restarting of systemd-networkd takes more then 2 secs
384 writeDNSEntries(value, resolvConfFile);
385 }
386 catch (InternalFailure& e)
387 {
388 log<level::ERR>("Exception processing DNS entries");
389 }
390 return EthernetInterfaceIntf::nameservers();
391}
392
393ServerList EthernetInterface::getNameServerFromConf()
394{
395 fs::path confPath = manager.getConfDir();
396
397 std::string fileName = systemd::config::networkFilePrefix +
398 interfaceName() +
399 systemd::config::networkFileSuffix;
400 confPath /= fileName;
401 ServerList servers;
402 try
403 {
404 config::Parser parser(confPath.string());
405 servers = parser.getValues("Network", "DNS");
406 }
407 catch (InternalFailure& e)
408 {
409 log<level::INFO>("Exception getting DNS value from conf file");
410 }
411 return servers;
412}
413
414void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
415 const std::string& file)
416{
417 std::fstream outStream(file, std::fstream::out);
418 if (!outStream.is_open())
419 {
420 log<level::ERR>("Unable to open the file",
421 entry("FILE=%s", file.c_str()));
422 elog<InternalFailure>();
423 }
424
425 outStream << "### Generated manually via dbus settings ###";
426 for(const auto& server : dnsList)
427 {
428 outStream << "nameserver " << server << "\n";
429 }
430}
431
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530432void EthernetInterface::loadVLAN(VlanId id)
433{
434 std::string vlanInterfaceName = interfaceName() + "." +
435 std::to_string(id);
436 std::string path = objPath;
437 path += "_" + std::to_string(id);
438
Ratan Gupta6e8df632017-08-13 09:41:58 +0530439 auto dhcpEnabled = getDHCPValue(manager.getConfDir().string(),
440 vlanInterfaceName);
441
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530442 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
443 bus,
444 path.c_str(),
Ratan Gupta6e8df632017-08-13 09:41:58 +0530445 dhcpEnabled,
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530446 id,
447 *this,
448 manager);
449
450 // Fetch the ip address from the system
451 // and create the dbus object.
452 vlanIntf->createIPAddressObjects();
453
454 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
455 std::move(vlanIntf));
456}
457
Ratan Gupta5978dd12017-07-25 13:47:13 +0530458void EthernetInterface::createVLAN(VlanId id)
459{
460 std::string vlanInterfaceName = interfaceName() + "." +
461 std::to_string(id);
462 std::string path = objPath;
463 path += "_" + std::to_string(id);
464
465
466 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
467 bus,
468 path.c_str(),
Ratan Guptae05083a2017-09-16 07:12:11 +0530469 false,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530470 id,
471 *this,
472 manager);
473
474 // write the device file for the vlan interface.
475 vlanIntf->writeDeviceFile();
476
Ratan Gupta6e8df632017-08-13 09:41:58 +0530477 this->vlanInterfaces.emplace(vlanInterfaceName,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530478 std::move(vlanIntf));
479 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530480 manager.writeToConfigurationFile();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530481}
Ratan Gupta2b106532017-07-25 16:05:02 +0530482
Ratan Gupta497c0c92017-08-22 19:15:59 +0530483ServerList EthernetInterface::getNTPServersFromConf()
484{
485 fs::path confPath = manager.getConfDir();
486
487 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
488 systemd::config::networkFileSuffix;
489 confPath /= fileName;
490 ServerList servers;
491 try
492 {
493 config::Parser parser(confPath.string());
494 servers = parser.getValues("Network", "NTP");
495 }
496 catch (InternalFailure& e)
497 {
498 log<level::INFO>("Unable to find the NTP server configuration.");
499 }
500 return servers;
501}
502
503ServerList EthernetInterface::nTPServers(ServerList servers)
504{
505 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
506
507 writeConfigurationFile();
508 // timesynchd reads the NTP server configuration from the
509 // network file.
510 restartSystemdUnit(timeSynchdService);
511 return ntpServers;
512}
Ratan Gupta2b106532017-07-25 16:05:02 +0530513// Need to merge the below function with the code which writes the
514// config file during factory reset.
515// TODO openbmc/openbmc#1751
516
517void EthernetInterface::writeConfigurationFile()
518{
519 // write all the static ip address in the systemd-network conf file
520
521 using namespace std::string_literals;
522 using AddressOrigin =
523 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
524 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530525
526 // if there is vlan interafce then write the configuration file
527 // for vlan also.
528
529 for (const auto& intf: vlanInterfaces)
530 {
531 intf.second->writeConfigurationFile();
532 }
533
Ratan Gupta2b106532017-07-25 16:05:02 +0530534 fs::path confPath = manager.getConfDir();
535
Ratan Guptabc886292017-07-25 18:29:57 +0530536 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
537 systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530538 confPath /= fileName;
539 std::fstream stream;
540
541 stream.open(confPath.c_str(), std::fstream::out);
542 if (!stream.is_open())
543 {
544 log<level::ERR>("Unable to open the file",
545 entry("FILE=%s", confPath.c_str()));
546 elog<InternalFailure>();
547 }
548
549 // Write the device
550 stream << "[" << "Match" << "]\n";
551 stream << "Name=" << interfaceName() << "\n";
552
553 auto addrs = getAddresses();
554
555 // write the network section
556 stream << "[" << "Network" << "]\n";
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500557 stream << "LinkLocalAddressing=yes\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530558
559 // Add the VLAN entry
560 for (const auto& intf: vlanInterfaces)
561 {
562 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
563 << "\n";
564 }
565
Ratan Gupta2b106532017-07-25 16:05:02 +0530566 // DHCP
567 if (dHCPEnabled() == true)
568 {
569 // write the dhcp section if interface is
570 // configured as dhcp.
571 writeDHCPSection(stream);
572 stream.close();
573 return;
574 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530575
Ratan Gupta497c0c92017-08-22 19:15:59 +0530576 //Add the NTP server
577 for(const auto& ntp: EthernetInterfaceIntf::nTPServers())
578 {
579 stream << "NTP=" << ntp << "\n";
580 }
581
Ratan Gupta6dec3902017-08-20 15:28:12 +0530582 //Add the DNS entry
583 for(const auto& dns: EthernetInterfaceIntf::nameservers())
584 {
585 stream << "DNS=" << dns << "\n";
586 }
587
Ratan Gupta2b106532017-07-25 16:05:02 +0530588 // Static
589 for (const auto& addr : addrs)
590 {
591 if (addr.second->origin() == AddressOrigin::Static)
592 {
593 std::string address = addr.second->address() + "/" + std::to_string(
594 addr.second->prefixLength());
595
596 stream << "Address=" << address << "\n";
597 }
598 }
599
600 if (manager.getSystemConf())
601 {
602 stream << "Gateway=" << manager.getSystemConf()->defaultGateway()
603 << "\n";
604 }
605 // write the route section
606 stream << "[" << "Route" << "]\n";
607 for(const auto& addr : addrs)
608 {
609 if (addr.second->origin() == AddressOrigin::Static)
610 {
611 int addressFamily = addr.second->type() == IP::Protocol::IPv4 ? AF_INET : AF_INET6;
612 std::string destination = getNetworkID(
613 addressFamily,
614 addr.second->address(),
615 addr.second->prefixLength());
616
617 if (addr.second->gateway() != "0.0.0.0" &&
618 addr.second->gateway() != "" &&
619 destination != "0.0.0.0" &&
620 destination != "")
621 {
622 stream << "Gateway=" << addr.second->gateway() << "\n";
623 stream << "Destination=" << destination << "\n";
624 }
625
626 }
627 }
628
629 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530630}
631
632void EthernetInterface::writeDHCPSection(std::fstream& stream)
633{
634 using namespace std::string_literals;
635 stream << "DHCP=true\n";
636 // write the dhcp section
637 stream << "[DHCP]\n";
638
639 // Hardcoding the client identifier to mac, to address below issue
640 // https://github.com/openbmc/openbmc/issues/1280
641 stream << "ClientIdentifier=mac\n";
642 if (manager.getDHCPConf())
643 {
644 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
645 stream << "UseDNS="s + value + "\n";
646
647 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
648 stream << "UseNTP="s + value + "\n";
649
650 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
651 stream << "UseHostname="s + value + "\n";
652 }
653}
654
Ratan Guptabd303b12017-08-18 17:10:07 +0530655std::string EthernetInterface::mACAddress(std::string value)
656{
657 if (!mac_address::validate(value))
658 {
659 log<level::DEBUG>("MACAddress is not valid.",
660 entry("MAC=%s", value.c_str()));
661 return MacAddressIntf::mACAddress();
662 }
663
664 // check whether MAC is broadcast mac.
665 auto intMac = mac_address::internal::convertToInt(value);
666
667 if (!(intMac ^ mac_address::broadcastMac))
668 {
669 log<level::DEBUG>("MACAddress is a broadcast mac.",
670 entry("MAC=%s", value.c_str()));
671 return MacAddressIntf::mACAddress();
672 }
673
674 // Allow the mac to be set if one of the condition is true.
675 // 1) Incoming Mac is of local admin type.
676 // or
677 // 2) Incoming mac is same as eeprom Mac.
678
679 if (!(intMac & mac_address::localAdminMask))
680 {
681 try
682 {
683 auto inventoryMac = mac_address::getfromInventory(bus);
684 auto intInventoryMac = mac_address::internal::convertToInt(inventoryMac);
685
686 if (intInventoryMac != intMac)
687 {
688 log<level::DEBUG>("Given MAC address is neither a local Admin \
689 type nor is same as in inventory");
690 return MacAddressIntf::mACAddress();
691 }
692 }
693 catch(InternalFailure& e)
694 {
Gunnar Millsd75f0492017-10-25 20:33:32 -0500695 log<level::ERR>("Exception occurred during getting of MAC \
Ratan Guptabd303b12017-08-18 17:10:07 +0530696 address from Inventory");
697 return MacAddressIntf::mACAddress();
698 }
699 }
700 auto interface = interfaceName();
701 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
702 //TODO: would replace below three calls
703 // with restarting of systemd-netwokd
704 // through https://github.com/systemd/systemd/issues/6696
705 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
706 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "address",
707 value.c_str());
708
709 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
710
711 auto mac = MacAddressIntf::mACAddress(std::move(value));
712 //update all the vlan interfaces
713 for(const auto& intf: vlanInterfaces)
714 {
715 intf.second->updateMacAddress();
716 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530717
718 // restart the systemd networkd so that dhcp client gets the
719 // ip for the changed mac address.
720 if (dHCPEnabled())
721 {
722 restartSystemdUnit("systemd-networkd.service");
723 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530724 return mac;
725
726}
727
Ratan Guptae9c9b812017-09-22 17:15:37 +0530728void EthernetInterface::deleteAll()
729{
730 if(EthernetInterfaceIntf::dHCPEnabled())
731 {
732 log<level::INFO>("DHCP enabled on the interface"),
733 entry("INTERFACE=%s", interfaceName().c_str());
734
735 }
736
737 // clear all the ip on the interface
738 addrs.clear();
739 manager.writeToConfigurationFile();
740}
741
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530742}//namespace network
743}//namespace phosphor