blob: f9cc4e40764ad477134b21df58dab03423c5279c [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 Gupta82549cc2017-04-21 08:45:23 +0530106 }
Ratan Guptafc2c7242017-05-29 08:46:06 +0530107
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530108}
109
Ratan Gupta82549cc2017-04-21 08:45:23 +0530110void EthernetInterface::iP(IP::Protocol protType,
111 std::string ipaddress,
112 uint8_t prefixLength,
113 std::string gateway)
114{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530115
116 if (dHCPEnabled())
117 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530118 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500119 entry("INTERFACE=%s", interfaceName().c_str());
120 dHCPEnabled(false);
121 }
122
123
124 IP::AddressOrigin origin = IP::AddressOrigin::Static;
125
126 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
127
128 if (!isValidIP(addressFamily, ipaddress))
129 {
130 log<level::ERR>("Not a valid IP address"),
131 entry("ADDRESS=%s", ipaddress.c_str());
132 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
133 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
134 }
135
136 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
137 {
138 log<level::ERR>("Not a valid Gateway"),
139 entry("GATEWAY=%s", gateway.c_str());
140 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
141 Argument::ARGUMENT_VALUE(gateway.c_str()));
142 }
143
144 if (!isValidPrefix(addressFamily, prefixLength))
145 {
146 log<level::ERR>("PrefixLength is not correct "),
147 entry("PREFIXLENGTH=%d", gateway.c_str());
148 elog<InvalidArgument>(Argument::ARGUMENT_NAME("prefixLength"),
149 Argument::ARGUMENT_VALUE(std::to_string(
150 prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530151 return;
152 }
153
Ratan Gupta29b0e432017-05-25 12:51:40 +0530154
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530155 std::string objectPath = generateObjectPath(protType,
156 ipaddress,
157 prefixLength,
158 gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530159 this->addrs.emplace(
Ratan Guptae578d562017-08-02 07:04:16 +0530160 std::move(ipaddress),
161 std::make_shared<phosphor::network::IPAddress>(
162 bus,
163 objectPath.c_str(),
164 *this,
165 protType,
166 ipaddress,
167 origin,
168 prefixLength,
169 gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530170
Ratan Guptae05083a2017-09-16 07:12:11 +0530171 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530172}
173
174
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530175/*
176Note: We don't have support for ethtool now
177will enable this code once we bring the ethtool
178in the image.
179TODO: https://github.com/openbmc/openbmc/issues/1484
180*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530181
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530182InterfaceInfo EthernetInterface::getInterfaceInfo() const
183{
184 int sock{-1};
185 struct ifreq ifr{0};
186 struct ethtool_cmd edata{0};
187 LinkSpeed speed {0};
188 Autoneg autoneg {0};
189 DuplexMode duplex {0};
190 do
191 {
192 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
193 if (sock < 0)
194 {
195 log<level::ERR>("socket creation failed:",
196 entry("ERROR=%s", strerror(errno)));
197 break;
198 }
199
200 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
201 ifr.ifr_data = reinterpret_cast<char*>(&edata);
202
203 edata.cmd = ETHTOOL_GSET;
204
205 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
206 {
207 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
208 entry("ERROR=%s", strerror(errno)));
209 break;
210
211 }
212 speed = edata.speed;
213 duplex = edata.duplex;
214 autoneg = edata.autoneg;
215 }
216 while (0);
217
218 if (sock)
219 {
220 close(sock);
221 }
222 return std::make_tuple(speed, duplex, autoneg);
223}
224
225/** @brief get the mac address of the interface.
226 * @return macaddress on success
227 */
228
Ratan Guptada7d3af2017-08-13 17:49:56 +0530229std::string EthernetInterface::getMACAddress(
230 const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530231{
Ratan Guptada7d3af2017-08-13 17:49:56 +0530232 struct ifreq ifr{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530233 char macAddress[mac_address::size] {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530234
235 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
236 if (sock < 0)
237 {
238 log<level::ERR>("socket creation failed:",
239 entry("ERROR=%s", strerror(errno)));
240 return macAddress;
241 }
242
Ratan Guptada7d3af2017-08-13 17:49:56 +0530243 strcpy(ifr.ifr_name, interfaceName.c_str());
244 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530245 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530246 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
247 entry("ERROR=%s", strerror(errno)));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530248 return macAddress;
249 }
250
Ratan Guptabd303b12017-08-18 17:10:07 +0530251 snprintf(macAddress, mac_address::size, mac_address::format,
Ratan Guptada7d3af2017-08-13 17:49:56 +0530252 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
253 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
254 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530255
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530256 return macAddress;
257}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530258
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530259std::string EthernetInterface::generateId(const std::string& ipaddress,
260 uint8_t prefixLength,
261 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530262{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530263 std::stringstream hexId;
264 std::string hashString = ipaddress;
265 hashString += std::to_string(prefixLength);
266 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530267
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530268 // Only want 8 hex digits.
269 hexId << std::hex << ((std::hash<std::string> {}(
Ratan Guptafc2c7242017-05-29 08:46:06 +0530270 hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530271 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530272}
273
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530274void EthernetInterface::deleteObject(const std::string& ipaddress)
275{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530276 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530277 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530278 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530279 log<level::ERR>("DeleteObject:Unable to find the object.");
280 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530281 }
282 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530283 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530284}
285
Ratan Guptae9c9b812017-09-22 17:15:37 +0530286void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530287{
Ratan Guptabc886292017-07-25 18:29:57 +0530288 auto confDir = manager.getConfDir();
289 fs::path networkFile = confDir;
290 networkFile /= systemd::config::networkFilePrefix + interface +
291 systemd::config::networkFileSuffix;
292
293 fs::path deviceFile = confDir;
294 deviceFile /= interface + systemd::config::deviceFileSuffix;
295
296 // delete the vlan network file
297 if (fs::is_regular_file(networkFile))
298 {
299 fs::remove(networkFile);
300 }
301
302 // delete the vlan device file
303 if (fs::is_regular_file(deviceFile))
304 {
305 fs::remove(deviceFile);
306 }
Ratan Guptabc886292017-07-25 18:29:57 +0530307
308 // TODO systemd doesn't delete the virtual network interface
309 // even after deleting all the related configuartion.
310 // https://github.com/systemd/systemd/issues/6600
311 try
312 {
313 deleteInterface(interface);
314 }
315 catch (InternalFailure& e)
316 {
317 commit<InternalFailure>();
318 }
Ratan Guptae05083a2017-09-16 07:12:11 +0530319
Ratan Guptae9c9b812017-09-22 17:15:37 +0530320}
321
322void EthernetInterface::deleteVLANObject(const std::string& interface)
323{
324 auto it = vlanInterfaces.find(interface);
325 if (it == vlanInterfaces.end())
326 {
327 log<level::ERR>("DeleteVLANObject:Unable to find the object",
328 entry("INTERFACE=%s",interface.c_str()));
329 return;
330 }
331
332 deleteVLANFromSystem(interface);
333 // delete the interface
334 vlanInterfaces.erase(it);
335
Ratan Guptae05083a2017-09-16 07:12:11 +0530336 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530337}
338
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530339std::string EthernetInterface::generateObjectPath(IP::Protocol addressType,
340 const std::string& ipaddress,
341 uint8_t prefixLength,
342 const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530343{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530344 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530345 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530346 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
347
348 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530349 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530350 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530351 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530352 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530353}
354
Ratan Gupta87c13982017-06-15 09:27:27 +0530355bool EthernetInterface::dHCPEnabled(bool value)
356{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530357 if (value == EthernetInterfaceIntf::dHCPEnabled())
358 {
359 return value;
360 }
361
Ratan Gupta87c13982017-06-15 09:27:27 +0530362 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530363 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530364 return value;
365}
366
Ratan Gupta6dec3902017-08-20 15:28:12 +0530367ServerList EthernetInterface::nameservers(ServerList value)
368{
369 try
370 {
371 EthernetInterfaceIntf::nameservers(value);
372
373 writeConfigurationFile();
374
375 // Currently we don't have systemd-resolved enabled
376 // in the openbmc. Once we update the network conf file,
377 // it should be read by systemd-resolved.service.
378
379 // The other reason to write the resolv conf is,
380 // we don't want to restart the networkd for nameserver change.
381 // as restarting of systemd-networkd takes more then 2 secs
382 writeDNSEntries(value, resolvConfFile);
383 }
384 catch (InternalFailure& e)
385 {
386 log<level::ERR>("Exception processing DNS entries");
387 }
388 return EthernetInterfaceIntf::nameservers();
389}
390
391ServerList EthernetInterface::getNameServerFromConf()
392{
393 fs::path confPath = manager.getConfDir();
394
395 std::string fileName = systemd::config::networkFilePrefix +
396 interfaceName() +
397 systemd::config::networkFileSuffix;
398 confPath /= fileName;
399 ServerList servers;
400 try
401 {
402 config::Parser parser(confPath.string());
403 servers = parser.getValues("Network", "DNS");
404 }
405 catch (InternalFailure& e)
406 {
407 log<level::INFO>("Exception getting DNS value from conf file");
408 }
409 return servers;
410}
411
412void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
413 const std::string& file)
414{
415 std::fstream outStream(file, std::fstream::out);
416 if (!outStream.is_open())
417 {
418 log<level::ERR>("Unable to open the file",
419 entry("FILE=%s", file.c_str()));
420 elog<InternalFailure>();
421 }
422
423 outStream << "### Generated manually via dbus settings ###";
424 for(const auto& server : dnsList)
425 {
426 outStream << "nameserver " << server << "\n";
427 }
428}
429
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530430void EthernetInterface::loadVLAN(VlanId id)
431{
432 std::string vlanInterfaceName = interfaceName() + "." +
433 std::to_string(id);
434 std::string path = objPath;
435 path += "_" + std::to_string(id);
436
Ratan Gupta6e8df632017-08-13 09:41:58 +0530437 auto dhcpEnabled = getDHCPValue(manager.getConfDir().string(),
438 vlanInterfaceName);
439
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530440 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
441 bus,
442 path.c_str(),
Ratan Gupta6e8df632017-08-13 09:41:58 +0530443 dhcpEnabled,
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530444 id,
445 *this,
446 manager);
447
448 // Fetch the ip address from the system
449 // and create the dbus object.
450 vlanIntf->createIPAddressObjects();
451
452 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
453 std::move(vlanIntf));
454}
455
Ratan Gupta5978dd12017-07-25 13:47:13 +0530456void EthernetInterface::createVLAN(VlanId id)
457{
458 std::string vlanInterfaceName = interfaceName() + "." +
459 std::to_string(id);
460 std::string path = objPath;
461 path += "_" + std::to_string(id);
462
463
464 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
465 bus,
466 path.c_str(),
Ratan Guptae05083a2017-09-16 07:12:11 +0530467 false,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530468 id,
469 *this,
470 manager);
471
472 // write the device file for the vlan interface.
473 vlanIntf->writeDeviceFile();
474
Ratan Gupta6e8df632017-08-13 09:41:58 +0530475 this->vlanInterfaces.emplace(vlanInterfaceName,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530476 std::move(vlanIntf));
477 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530478 manager.writeToConfigurationFile();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530479}
Ratan Gupta2b106532017-07-25 16:05:02 +0530480
Ratan Gupta497c0c92017-08-22 19:15:59 +0530481ServerList EthernetInterface::getNTPServersFromConf()
482{
483 fs::path confPath = manager.getConfDir();
484
485 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
486 systemd::config::networkFileSuffix;
487 confPath /= fileName;
488 ServerList servers;
489 try
490 {
491 config::Parser parser(confPath.string());
492 servers = parser.getValues("Network", "NTP");
493 }
494 catch (InternalFailure& e)
495 {
496 log<level::INFO>("Unable to find the NTP server configuration.");
497 }
498 return servers;
499}
500
501ServerList EthernetInterface::nTPServers(ServerList servers)
502{
503 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
504
505 writeConfigurationFile();
506 // timesynchd reads the NTP server configuration from the
507 // network file.
508 restartSystemdUnit(timeSynchdService);
509 return ntpServers;
510}
Ratan Gupta2b106532017-07-25 16:05:02 +0530511// Need to merge the below function with the code which writes the
512// config file during factory reset.
513// TODO openbmc/openbmc#1751
514
515void EthernetInterface::writeConfigurationFile()
516{
517 // write all the static ip address in the systemd-network conf file
518
519 using namespace std::string_literals;
520 using AddressOrigin =
521 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
522 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530523
524 // if there is vlan interafce then write the configuration file
525 // for vlan also.
526
527 for (const auto& intf: vlanInterfaces)
528 {
529 intf.second->writeConfigurationFile();
530 }
531
Ratan Gupta2b106532017-07-25 16:05:02 +0530532 fs::path confPath = manager.getConfDir();
533
Ratan Guptabc886292017-07-25 18:29:57 +0530534 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
535 systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530536 confPath /= fileName;
537 std::fstream stream;
538
539 stream.open(confPath.c_str(), std::fstream::out);
540 if (!stream.is_open())
541 {
542 log<level::ERR>("Unable to open the file",
543 entry("FILE=%s", confPath.c_str()));
544 elog<InternalFailure>();
545 }
546
547 // Write the device
548 stream << "[" << "Match" << "]\n";
549 stream << "Name=" << interfaceName() << "\n";
550
551 auto addrs = getAddresses();
552
553 // write the network section
554 stream << "[" << "Network" << "]\n";
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500555 stream << "LinkLocalAddressing=yes\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530556
557 // Add the VLAN entry
558 for (const auto& intf: vlanInterfaces)
559 {
560 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
561 << "\n";
562 }
563
Ratan Gupta2b106532017-07-25 16:05:02 +0530564 // DHCP
565 if (dHCPEnabled() == true)
566 {
567 // write the dhcp section if interface is
568 // configured as dhcp.
569 writeDHCPSection(stream);
570 stream.close();
571 return;
572 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530573
Ratan Gupta497c0c92017-08-22 19:15:59 +0530574 //Add the NTP server
575 for(const auto& ntp: EthernetInterfaceIntf::nTPServers())
576 {
577 stream << "NTP=" << ntp << "\n";
578 }
579
Ratan Gupta6dec3902017-08-20 15:28:12 +0530580 //Add the DNS entry
581 for(const auto& dns: EthernetInterfaceIntf::nameservers())
582 {
583 stream << "DNS=" << dns << "\n";
584 }
585
Ratan Gupta2b106532017-07-25 16:05:02 +0530586 // Static
587 for (const auto& addr : addrs)
588 {
589 if (addr.second->origin() == AddressOrigin::Static)
590 {
591 std::string address = addr.second->address() + "/" + std::to_string(
592 addr.second->prefixLength());
593
594 stream << "Address=" << address << "\n";
595 }
596 }
597
598 if (manager.getSystemConf())
599 {
600 stream << "Gateway=" << manager.getSystemConf()->defaultGateway()
601 << "\n";
602 }
603 // write the route section
604 stream << "[" << "Route" << "]\n";
605 for(const auto& addr : addrs)
606 {
607 if (addr.second->origin() == AddressOrigin::Static)
608 {
609 int addressFamily = addr.second->type() == IP::Protocol::IPv4 ? AF_INET : AF_INET6;
610 std::string destination = getNetworkID(
611 addressFamily,
612 addr.second->address(),
613 addr.second->prefixLength());
614
615 if (addr.second->gateway() != "0.0.0.0" &&
616 addr.second->gateway() != "" &&
617 destination != "0.0.0.0" &&
618 destination != "")
619 {
620 stream << "Gateway=" << addr.second->gateway() << "\n";
621 stream << "Destination=" << destination << "\n";
622 }
623
624 }
625 }
626
627 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530628}
629
630void EthernetInterface::writeDHCPSection(std::fstream& stream)
631{
632 using namespace std::string_literals;
633 stream << "DHCP=true\n";
634 // write the dhcp section
635 stream << "[DHCP]\n";
636
637 // Hardcoding the client identifier to mac, to address below issue
638 // https://github.com/openbmc/openbmc/issues/1280
639 stream << "ClientIdentifier=mac\n";
640 if (manager.getDHCPConf())
641 {
642 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
643 stream << "UseDNS="s + value + "\n";
644
645 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
646 stream << "UseNTP="s + value + "\n";
647
648 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
649 stream << "UseHostname="s + value + "\n";
650 }
651}
652
Ratan Guptabd303b12017-08-18 17:10:07 +0530653std::string EthernetInterface::mACAddress(std::string value)
654{
655 if (!mac_address::validate(value))
656 {
657 log<level::DEBUG>("MACAddress is not valid.",
658 entry("MAC=%s", value.c_str()));
659 return MacAddressIntf::mACAddress();
660 }
661
662 // check whether MAC is broadcast mac.
663 auto intMac = mac_address::internal::convertToInt(value);
664
665 if (!(intMac ^ mac_address::broadcastMac))
666 {
667 log<level::DEBUG>("MACAddress is a broadcast mac.",
668 entry("MAC=%s", value.c_str()));
669 return MacAddressIntf::mACAddress();
670 }
671
672 // Allow the mac to be set if one of the condition is true.
673 // 1) Incoming Mac is of local admin type.
674 // or
675 // 2) Incoming mac is same as eeprom Mac.
676
677 if (!(intMac & mac_address::localAdminMask))
678 {
679 try
680 {
681 auto inventoryMac = mac_address::getfromInventory(bus);
682 auto intInventoryMac = mac_address::internal::convertToInt(inventoryMac);
683
684 if (intInventoryMac != intMac)
685 {
686 log<level::DEBUG>("Given MAC address is neither a local Admin \
687 type nor is same as in inventory");
688 return MacAddressIntf::mACAddress();
689 }
690 }
691 catch(InternalFailure& e)
692 {
Gunnar Millsd75f0492017-10-25 20:33:32 -0500693 log<level::ERR>("Exception occurred during getting of MAC \
Ratan Guptabd303b12017-08-18 17:10:07 +0530694 address from Inventory");
695 return MacAddressIntf::mACAddress();
696 }
697 }
698 auto interface = interfaceName();
699 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
700 //TODO: would replace below three calls
701 // with restarting of systemd-netwokd
702 // through https://github.com/systemd/systemd/issues/6696
703 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
704 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "address",
705 value.c_str());
706
707 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
708
709 auto mac = MacAddressIntf::mACAddress(std::move(value));
710 //update all the vlan interfaces
711 for(const auto& intf: vlanInterfaces)
712 {
713 intf.second->updateMacAddress();
714 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530715
716 // restart the systemd networkd so that dhcp client gets the
717 // ip for the changed mac address.
718 if (dHCPEnabled())
719 {
720 restartSystemdUnit("systemd-networkd.service");
721 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530722 return mac;
723
724}
725
Ratan Guptae9c9b812017-09-22 17:15:37 +0530726void EthernetInterface::deleteAll()
727{
728 if(EthernetInterfaceIntf::dHCPEnabled())
729 {
730 log<level::INFO>("DHCP enabled on the interface"),
731 entry("INTERFACE=%s", interfaceName().c_str());
732
733 }
734
735 // clear all the ip on the interface
736 addrs.clear();
737 manager.writeToConfigurationFile();
738}
739
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530740}//namespace network
741}//namespace phosphor