blob: e388fa8f2ab0ddaa719e61f46e0cbcb676e1490c [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 Gupta6dec390f2017-08-20 15:28:12 +053054 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
55
Ratan Gupta29b0e432017-05-25 12:51:40 +053056 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053057 if (emitSignal)
58 {
59 this->emit_object_added();
60 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053061}
62
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 }
154
Ratan Gupta29b0e432017-05-25 12:51:40 +0530155
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530156 std::string objectPath = generateObjectPath(protType,
157 ipaddress,
158 prefixLength,
159 gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530160 this->addrs.emplace(
Ratan Guptae578d562017-08-02 07:04:16 +0530161 std::move(ipaddress),
162 std::make_shared<phosphor::network::IPAddress>(
163 bus,
164 objectPath.c_str(),
165 *this,
166 protType,
167 ipaddress,
168 origin,
169 prefixLength,
170 gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530171
Ratan Guptae05083a2017-09-16 07:12:11 +0530172 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530173}
174
175
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530176/*
177Note: We don't have support for ethtool now
178will enable this code once we bring the ethtool
179in the image.
180TODO: https://github.com/openbmc/openbmc/issues/1484
181*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530182
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530183InterfaceInfo EthernetInterface::getInterfaceInfo() const
184{
185 int sock{-1};
186 struct ifreq ifr{0};
187 struct ethtool_cmd edata{0};
188 LinkSpeed speed {0};
189 Autoneg autoneg {0};
190 DuplexMode duplex {0};
191 do
192 {
193 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
194 if (sock < 0)
195 {
196 log<level::ERR>("socket creation failed:",
197 entry("ERROR=%s", strerror(errno)));
198 break;
199 }
200
201 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
202 ifr.ifr_data = reinterpret_cast<char*>(&edata);
203
204 edata.cmd = ETHTOOL_GSET;
205
206 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
207 {
208 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
209 entry("ERROR=%s", strerror(errno)));
210 break;
211
212 }
213 speed = edata.speed;
214 duplex = edata.duplex;
215 autoneg = edata.autoneg;
216 }
217 while (0);
218
219 if (sock)
220 {
221 close(sock);
222 }
223 return std::make_tuple(speed, duplex, autoneg);
224}
225
226/** @brief get the mac address of the interface.
227 * @return macaddress on success
228 */
229
Ratan Guptada7d3af2017-08-13 17:49:56 +0530230std::string EthernetInterface::getMACAddress(
231 const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530232{
Ratan Guptada7d3af2017-08-13 17:49:56 +0530233 struct ifreq ifr{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530234 char macAddress[mac_address::size] {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530235
236 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
237 if (sock < 0)
238 {
239 log<level::ERR>("socket creation failed:",
240 entry("ERROR=%s", strerror(errno)));
241 return macAddress;
242 }
243
Ratan Guptada7d3af2017-08-13 17:49:56 +0530244 strcpy(ifr.ifr_name, interfaceName.c_str());
245 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530246 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530247 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
248 entry("ERROR=%s", strerror(errno)));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530249 return macAddress;
250 }
251
Ratan Guptabd303b12017-08-18 17:10:07 +0530252 snprintf(macAddress, mac_address::size, mac_address::format,
Ratan Guptada7d3af2017-08-13 17:49:56 +0530253 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
254 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
255 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530256
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530257 return macAddress;
258}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530259
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530260std::string EthernetInterface::generateId(const std::string& ipaddress,
261 uint8_t prefixLength,
262 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530263{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530264 std::stringstream hexId;
265 std::string hashString = ipaddress;
266 hashString += std::to_string(prefixLength);
267 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530268
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530269 // Only want 8 hex digits.
270 hexId << std::hex << ((std::hash<std::string> {}(
Ratan Guptafc2c7242017-05-29 08:46:06 +0530271 hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530272 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530273}
274
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530275void EthernetInterface::deleteObject(const std::string& ipaddress)
276{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530277 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530278 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530279 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530280 log<level::ERR>("DeleteObject:Unable to find the object.");
281 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530282 }
283 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530284 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530285}
286
Ratan Guptae9c9b812017-09-22 17:15:37 +0530287void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530288{
Ratan Guptabc886292017-07-25 18:29:57 +0530289 auto confDir = manager.getConfDir();
290 fs::path networkFile = confDir;
291 networkFile /= systemd::config::networkFilePrefix + interface +
292 systemd::config::networkFileSuffix;
293
294 fs::path deviceFile = confDir;
295 deviceFile /= interface + systemd::config::deviceFileSuffix;
296
297 // delete the vlan network file
298 if (fs::is_regular_file(networkFile))
299 {
300 fs::remove(networkFile);
301 }
302
303 // delete the vlan device file
304 if (fs::is_regular_file(deviceFile))
305 {
306 fs::remove(deviceFile);
307 }
Ratan Guptabc886292017-07-25 18:29:57 +0530308
309 // TODO systemd doesn't delete the virtual network interface
310 // even after deleting all the related configuartion.
311 // https://github.com/systemd/systemd/issues/6600
312 try
313 {
314 deleteInterface(interface);
315 }
316 catch (InternalFailure& e)
317 {
318 commit<InternalFailure>();
319 }
Ratan Guptae05083a2017-09-16 07:12:11 +0530320
Ratan Guptae9c9b812017-09-22 17:15:37 +0530321}
322
323void EthernetInterface::deleteVLANObject(const std::string& interface)
324{
325 auto it = vlanInterfaces.find(interface);
326 if (it == vlanInterfaces.end())
327 {
328 log<level::ERR>("DeleteVLANObject:Unable to find the object",
329 entry("INTERFACE=%s",interface.c_str()));
330 return;
331 }
332
333 deleteVLANFromSystem(interface);
334 // delete the interface
335 vlanInterfaces.erase(it);
336
Ratan Guptae05083a2017-09-16 07:12:11 +0530337 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530338}
339
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530340std::string EthernetInterface::generateObjectPath(IP::Protocol addressType,
341 const std::string& ipaddress,
342 uint8_t prefixLength,
343 const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530344{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530345 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530346 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530347 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
348
349 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530350 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530351 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530352 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530353 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530354}
355
Ratan Gupta87c13982017-06-15 09:27:27 +0530356bool EthernetInterface::dHCPEnabled(bool value)
357{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530358 if (value == EthernetInterfaceIntf::dHCPEnabled())
359 {
360 return value;
361 }
362
Ratan Gupta87c13982017-06-15 09:27:27 +0530363 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530364 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530365 return value;
366}
367
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530368ServerList EthernetInterface::nameservers(ServerList value)
369{
370 try
371 {
372 EthernetInterfaceIntf::nameservers(value);
373
374 writeConfigurationFile();
375
376 // Currently we don't have systemd-resolved enabled
377 // in the openbmc. Once we update the network conf file,
378 // it should be read by systemd-resolved.service.
379
380 // The other reason to write the resolv conf is,
381 // we don't want to restart the networkd for nameserver change.
382 // as restarting of systemd-networkd takes more then 2 secs
383 writeDNSEntries(value, resolvConfFile);
384 }
385 catch (InternalFailure& e)
386 {
387 log<level::ERR>("Exception processing DNS entries");
388 }
389 return EthernetInterfaceIntf::nameservers();
390}
391
392ServerList EthernetInterface::getNameServerFromConf()
393{
394 fs::path confPath = manager.getConfDir();
395
396 std::string fileName = systemd::config::networkFilePrefix +
397 interfaceName() +
398 systemd::config::networkFileSuffix;
399 confPath /= fileName;
400 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530401 config::Parser parser(confPath.string());
402 auto rc = config::ReturnCode::SUCCESS;
403
404 std::tie(rc, servers) = parser.getValues("Network", "DNS");
405 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530406 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530407 log<level::DEBUG>("Unable to get the value for network[DNS]",
408 entry("RC=%d", rc));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530409 }
410 return servers;
411}
412
413void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
414 const std::string& file)
415{
416 std::fstream outStream(file, std::fstream::out);
417 if (!outStream.is_open())
418 {
419 log<level::ERR>("Unable to open the file",
420 entry("FILE=%s", file.c_str()));
421 elog<InternalFailure>();
422 }
423
Ratan Guptafe116912017-11-10 16:00:59 +0530424 outStream << "### Generated manually via dbus settings ###\n";
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530425 for(const auto& server : dnsList)
426 {
427 outStream << "nameserver " << server << "\n";
428 }
429}
430
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530431void EthernetInterface::loadVLAN(VlanId id)
432{
433 std::string vlanInterfaceName = interfaceName() + "." +
434 std::to_string(id);
435 std::string path = objPath;
436 path += "_" + std::to_string(id);
437
Ratan Gupta6e8df632017-08-13 09:41:58 +0530438 auto dhcpEnabled = getDHCPValue(manager.getConfDir().string(),
439 vlanInterfaceName);
440
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530441 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
442 bus,
443 path.c_str(),
Ratan Gupta6e8df632017-08-13 09:41:58 +0530444 dhcpEnabled,
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530445 id,
446 *this,
447 manager);
448
449 // Fetch the ip address from the system
450 // and create the dbus object.
451 vlanIntf->createIPAddressObjects();
452
453 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
454 std::move(vlanIntf));
455}
456
Ratan Gupta5978dd12017-07-25 13:47:13 +0530457void EthernetInterface::createVLAN(VlanId id)
458{
459 std::string vlanInterfaceName = interfaceName() + "." +
460 std::to_string(id);
461 std::string path = objPath;
462 path += "_" + std::to_string(id);
463
464
465 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
466 bus,
467 path.c_str(),
Ratan Guptae05083a2017-09-16 07:12:11 +0530468 false,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530469 id,
470 *this,
471 manager);
472
473 // write the device file for the vlan interface.
474 vlanIntf->writeDeviceFile();
475
Ratan Gupta6e8df632017-08-13 09:41:58 +0530476 this->vlanInterfaces.emplace(vlanInterfaceName,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530477 std::move(vlanIntf));
478 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530479 manager.writeToConfigurationFile();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530480}
Ratan Gupta2b106532017-07-25 16:05:02 +0530481
Ratan Gupta497c0c92017-08-22 19:15:59 +0530482ServerList EthernetInterface::getNTPServersFromConf()
483{
484 fs::path confPath = manager.getConfDir();
485
486 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
Ratan Guptac27170a2017-11-22 15:44:42 +0530487 systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530488 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530489
Ratan Gupta497c0c92017-08-22 19:15:59 +0530490 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530491 config::Parser parser(confPath.string());
492 auto rc = config::ReturnCode::SUCCESS;
493
494 std::tie(rc, servers) = parser.getValues("Network", "NTP");
495 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530496 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530497 log<level::DEBUG>("Unable to get the value for Network[NTP]",
498 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530499 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530500
Ratan Gupta497c0c92017-08-22 19:15:59 +0530501 return servers;
502}
503
504ServerList EthernetInterface::nTPServers(ServerList servers)
505{
506 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
507
508 writeConfigurationFile();
509 // timesynchd reads the NTP server configuration from the
510 // network file.
Lei YU250011e2018-02-01 14:07:06 +0800511 restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530512 return ntpServers;
513}
Ratan Gupta2b106532017-07-25 16:05:02 +0530514// Need to merge the below function with the code which writes the
515// config file during factory reset.
516// TODO openbmc/openbmc#1751
517
518void EthernetInterface::writeConfigurationFile()
519{
520 // write all the static ip address in the systemd-network conf file
521
522 using namespace std::string_literals;
523 using AddressOrigin =
524 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
525 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530526
527 // if there is vlan interafce then write the configuration file
528 // for vlan also.
529
530 for (const auto& intf: vlanInterfaces)
531 {
532 intf.second->writeConfigurationFile();
533 }
534
Ratan Gupta2b106532017-07-25 16:05:02 +0530535 fs::path confPath = manager.getConfDir();
536
Ratan Guptabc886292017-07-25 18:29:57 +0530537 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
538 systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530539 confPath /= fileName;
540 std::fstream stream;
541
542 stream.open(confPath.c_str(), std::fstream::out);
543 if (!stream.is_open())
544 {
545 log<level::ERR>("Unable to open the file",
546 entry("FILE=%s", confPath.c_str()));
547 elog<InternalFailure>();
548 }
549
550 // Write the device
551 stream << "[" << "Match" << "]\n";
552 stream << "Name=" << interfaceName() << "\n";
553
554 auto addrs = getAddresses();
555
556 // write the network section
557 stream << "[" << "Network" << "]\n";
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500558 stream << "LinkLocalAddressing=yes\n";
Ratan Guptae9629412017-12-21 08:20:25 +0530559 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530560
561 // Add the VLAN entry
562 for (const auto& intf: vlanInterfaces)
563 {
564 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
565 << "\n";
566 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500567 // Add the DHCP entry
568 auto value = dHCPEnabled() ? "true"s : "false"s;
569 stream << "DHCP="s + value + "\n";
570
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600571 // When the interface configured as dhcp, we don't need below given entries
572 // in config file.
573 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530574 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600575 //Add the NTP server
576 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530577 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600578 stream << "NTP=" << ntp << "\n";
579 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530580
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600581 //Add the DNS entry
582 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530583 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600584 stream << "DNS=" << dns << "\n";
585 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530586
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600587 // Static
588 for (const auto& addr : addrs)
589 {
590 if (addr.second->origin() == AddressOrigin::Static)
Ratan Gupta2b106532017-07-25 16:05:02 +0530591 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600592 std::string address = addr.second->address() + "/" +
593 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530594
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600595 stream << "Address=" << address << "\n";
596 }
597 }
598
599 if (manager.getSystemConf())
600 {
601 stream << "Gateway=" << manager.getSystemConf()->defaultGateway()
602 << "\n";
603 }
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 ?
612 AF_INET : AF_INET6;
613
614 std::string destination = getNetworkID(
615 addressFamily,
616 addr.second->address(),
617 addr.second->prefixLength());
618
619 if (addr.second->gateway() != "0.0.0.0" &&
620 addr.second->gateway() != "" &&
621 destination != "0.0.0.0" &&
622 destination != "")
623 {
624 stream << "Gateway=" << addr.second->gateway() << "\n";
625 stream << "Destination=" << destination << "\n";
626 }
627 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530628 }
629 }
630
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600631 // Write the dhcp section irrespective of whether DHCP is enabled or not
632 writeDHCPSection(stream);
633
Ratan Gupta2b106532017-07-25 16:05:02 +0530634 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530635}
636
637void EthernetInterface::writeDHCPSection(std::fstream& stream)
638{
639 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530640 // write the dhcp section
641 stream << "[DHCP]\n";
642
643 // Hardcoding the client identifier to mac, to address below issue
644 // https://github.com/openbmc/openbmc/issues/1280
645 stream << "ClientIdentifier=mac\n";
646 if (manager.getDHCPConf())
647 {
648 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
649 stream << "UseDNS="s + value + "\n";
650
651 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
652 stream << "UseNTP="s + value + "\n";
653
654 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
655 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600656
657 value =
658 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
659 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530660 }
661}
662
Ratan Guptabd303b12017-08-18 17:10:07 +0530663std::string EthernetInterface::mACAddress(std::string value)
664{
665 if (!mac_address::validate(value))
666 {
667 log<level::DEBUG>("MACAddress is not valid.",
668 entry("MAC=%s", value.c_str()));
669 return MacAddressIntf::mACAddress();
670 }
671
672 // check whether MAC is broadcast mac.
673 auto intMac = mac_address::internal::convertToInt(value);
674
675 if (!(intMac ^ mac_address::broadcastMac))
676 {
677 log<level::DEBUG>("MACAddress is a broadcast mac.",
678 entry("MAC=%s", value.c_str()));
679 return MacAddressIntf::mACAddress();
680 }
681
Patrick Ventured475cd62018-02-26 17:07:41 -0800682 // Check if the MAC changed.
683 auto pmac = MacAddressIntf::mACAddress();
684 if (strcasecmp(pmac.c_str(), value.c_str()) == 0)
685 {
686 return MacAddressIntf::mACAddress();
687 }
688
Ratan Guptabd303b12017-08-18 17:10:07 +0530689 // Allow the mac to be set if one of the condition is true.
690 // 1) Incoming Mac is of local admin type.
691 // or
692 // 2) Incoming mac is same as eeprom Mac.
693
694 if (!(intMac & mac_address::localAdminMask))
695 {
696 try
697 {
698 auto inventoryMac = mac_address::getfromInventory(bus);
699 auto intInventoryMac = mac_address::internal::convertToInt(inventoryMac);
700
701 if (intInventoryMac != intMac)
702 {
Patrick Venturee0ad43a2017-11-29 18:19:54 -0800703 log<level::DEBUG>("Given MAC address is neither a local Admin "
704 "type nor is same as in inventory");
Ratan Guptabd303b12017-08-18 17:10:07 +0530705 return MacAddressIntf::mACAddress();
706 }
707 }
708 catch(InternalFailure& e)
709 {
Patrick Venturee0ad43a2017-11-29 18:19:54 -0800710 log<level::ERR>("Exception occurred during getting of MAC "
711 "address from Inventory");
Ratan Guptabd303b12017-08-18 17:10:07 +0530712 return MacAddressIntf::mACAddress();
713 }
714 }
715 auto interface = interfaceName();
716 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
717 //TODO: would replace below three calls
718 // with restarting of systemd-netwokd
719 // through https://github.com/systemd/systemd/issues/6696
720 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
721 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "address",
722 value.c_str());
723
724 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
725
726 auto mac = MacAddressIntf::mACAddress(std::move(value));
727 //update all the vlan interfaces
728 for(const auto& intf: vlanInterfaces)
729 {
730 intf.second->updateMacAddress();
731 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530732
733 // restart the systemd networkd so that dhcp client gets the
734 // ip for the changed mac address.
735 if (dHCPEnabled())
736 {
Lei YU250011e2018-02-01 14:07:06 +0800737 restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530738 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530739 return mac;
740
741}
742
Ratan Guptae9c9b812017-09-22 17:15:37 +0530743void EthernetInterface::deleteAll()
744{
745 if(EthernetInterfaceIntf::dHCPEnabled())
746 {
747 log<level::INFO>("DHCP enabled on the interface"),
748 entry("INTERFACE=%s", interfaceName().c_str());
749
750 }
751
752 // clear all the ip on the interface
753 addrs.clear();
754 manager.writeToConfigurationFile();
755}
756
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530757}//namespace network
758}//namespace phosphor