blob: af8efc91d6d7d755ee94b5be466c9f804983e9bf [file] [log] [blame]
Patrick Venture189d44e2018-07-09 12:30:59 -07001#include "ethernet_interface.hpp"
2
Ratan Gupta82549cc2017-04-21 08:45:23 +05303#include "config.h"
Ratan Gupta497c0c92017-08-22 19:15:59 +05304#include "config_parser.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05305#include "ipaddress.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05306#include "network_manager.hpp"
Ratan Guptafc2c7242017-05-29 08:46:06 +05307#include "routing_table.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05308#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05309
Ratan Gupta82549cc2017-04-21 08:45:23 +053010#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053011#include <linux/ethtool.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053012#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053013#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <netinet/in.h>
15#include <sys/ioctl.h>
16#include <sys/socket.h>
17#include <unistd.h>
18
Ratan Gupta82549cc2017-04-21 08:45:23 +053019#include <algorithm>
20#include <experimental/filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053021#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070022#include <phosphor-logging/elog-errors.hpp>
23#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053024#include <sstream>
25#include <string>
Patrick Venture189d44e2018-07-09 12:30:59 -070026#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053027
Ratan Gupta91a99cc2017-04-14 16:32:09 +053028namespace phosphor
29{
30namespace network
31{
32
33using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053034using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050035using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta2b106532017-07-25 16:05:02 +053036
Ratan Gupta91a99cc2017-04-14 16:32:09 +053037EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
38 const std::string& objPath,
Ratan Gupta4f1c18b2017-05-25 12:59:35 +053039 bool dhcpEnabled,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053040 Manager& parent,
41 bool emitSignal) :
Ratan Gupta82549cc2017-04-21 08:45:23 +053042 Ifaces(bus, objPath.c_str(), true),
Ratan Gupta4f1c18b2017-05-25 12:59:35 +053043 bus(bus),
Ratan Gupta47722dc2017-05-26 18:32:23 +053044 manager(parent),
45 objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053046{
47 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053048 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053049 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053050 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Ratan Guptabd303b12017-08-18 17:10:07 +053051 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053052 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec390f2017-08-20 15:28:12 +053053 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
54
Ratan Gupta29b0e432017-05-25 12:51:40 +053055 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053056 if (emitSignal)
57 {
58 this->emit_object_added();
59 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053060}
61
Ratan Gupta87c13982017-06-15 09:27:27 +053062void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053063{
Ratan Gupta82549cc2017-04-21 08:45:23 +053064 std::string gateway;
Ratan Gupta87c13982017-06-15 09:27:27 +053065 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053066
Ratan Gupta87c13982017-06-15 09:27:27 +053067 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053068
Ratan Gupta82549cc2017-04-21 08:45:23 +053069 IP::Protocol addressType = IP::Protocol::IPv4;
Ratan Gupta29b0e432017-05-25 12:51:40 +053070 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053071 route::Table routingTable;
Ratan Gupta5978dd12017-07-25 13:47:13 +053072
Ratan Gupta6a387c12017-08-03 13:26:19 +053073 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053074 {
75 if (addr.addrType == AF_INET6)
76 {
77 addressType = IP::Protocol::IPv6;
78 }
Ratan Guptafc2c7242017-05-29 08:46:06 +053079 if (dHCPEnabled())
80 {
81 origin = IP::AddressOrigin::DHCP;
82 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050083 else if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053084 {
85 origin = IP::AddressOrigin::LinkLocal;
86 }
87 gateway = routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
Ratan Gupta82549cc2017-04-21 08:45:23 +053088
Ratan Gupta65e5abe2017-05-23 13:20:44 +053089 std::string ipAddressObjectPath = generateObjectPath(addressType,
90 addr.ipaddress,
91 addr.prefix,
92 gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +053093
Ratan Gupta82549cc2017-04-21 08:45:23 +053094 this->addrs.emplace(
Ratan Gupta057ff0d2018-05-04 16:59:55 +053095 addr.ipaddress,
Ratan Guptae578d562017-08-02 07:04:16 +053096 std::make_shared<phosphor::network::IPAddress>(
Ratan Gupta719f83a2017-06-02 11:54:53 +053097 bus,
98 ipAddressObjectPath.c_str(),
99 *this,
100 addressType,
Ratan Gupta82549cc2017-04-21 08:45:23 +0530101 addr.ipaddress,
Ratan Gupta29b0e432017-05-25 12:51:40 +0530102 origin,
Ratan Gupta719f83a2017-06-02 11:54:53 +0530103 addr.prefix,
Ratan Guptae578d562017-08-02 07:04:16 +0530104 gateway));
Ratan Gupta603598d2017-11-14 20:58:38 +0530105
106 origin = IP::AddressOrigin::Static;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530107 }
Ratan Guptafc2c7242017-05-29 08:46:06 +0530108
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530109}
110
Ratan Gupta82549cc2017-04-21 08:45:23 +0530111void EthernetInterface::iP(IP::Protocol protType,
112 std::string ipaddress,
113 uint8_t prefixLength,
114 std::string gateway)
115{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530116
117 if (dHCPEnabled())
118 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530119 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500120 entry("INTERFACE=%s", interfaceName().c_str());
121 dHCPEnabled(false);
122 }
123
124
125 IP::AddressOrigin origin = IP::AddressOrigin::Static;
126
127 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
128
129 if (!isValidIP(addressFamily, ipaddress))
130 {
131 log<level::ERR>("Not a valid IP address"),
132 entry("ADDRESS=%s", ipaddress.c_str());
133 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
134 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
135 }
136
137 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
138 {
139 log<level::ERR>("Not a valid Gateway"),
140 entry("GATEWAY=%s", gateway.c_str());
141 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
142 Argument::ARGUMENT_VALUE(gateway.c_str()));
143 }
144
145 if (!isValidPrefix(addressFamily, prefixLength))
146 {
147 log<level::ERR>("PrefixLength is not correct "),
148 entry("PREFIXLENGTH=%d", gateway.c_str());
149 elog<InvalidArgument>(Argument::ARGUMENT_NAME("prefixLength"),
150 Argument::ARGUMENT_VALUE(std::to_string(
151 prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530152 }
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 Gupta057ff0d2018-05-04 16:59:55 +0530160 ipaddress,
Ratan Guptae578d562017-08-02 07:04:16 +0530161 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 Gupta6dec390f2017-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;
Ratan Guptac27170a2017-11-22 15:44:42 +0530400 config::Parser parser(confPath.string());
401 auto rc = config::ReturnCode::SUCCESS;
402
403 std::tie(rc, servers) = parser.getValues("Network", "DNS");
404 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530405 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530406 log<level::DEBUG>("Unable to get the value for network[DNS]",
407 entry("RC=%d", rc));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530408 }
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
Ratan Guptafe116912017-11-10 16:00:59 +0530423 outStream << "### Generated manually via dbus settings ###\n";
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530424 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() +
Ratan Guptac27170a2017-11-22 15:44:42 +0530486 systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530487 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530488
Ratan Gupta497c0c92017-08-22 19:15:59 +0530489 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530490 config::Parser parser(confPath.string());
491 auto rc = config::ReturnCode::SUCCESS;
492
493 std::tie(rc, servers) = parser.getValues("Network", "NTP");
494 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530495 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530496 log<level::DEBUG>("Unable to get the value for Network[NTP]",
497 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530498 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530499
Ratan Gupta497c0c92017-08-22 19:15:59 +0530500 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.
Lei YU250011e2018-02-01 14:07:06 +0800510 restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530511 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";
Oskar Senftad21fc22018-07-26 16:32:23 -0400557#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500558 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400559#else
560 stream << "LinkLocalAddressing=no\n";
561#endif
Ratan Guptae9629412017-12-21 08:20:25 +0530562 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530563
564 // Add the VLAN entry
565 for (const auto& intf: vlanInterfaces)
566 {
567 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
568 << "\n";
569 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500570 // Add the DHCP entry
571 auto value = dHCPEnabled() ? "true"s : "false"s;
572 stream << "DHCP="s + value + "\n";
573
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600574 // When the interface configured as dhcp, we don't need below given entries
575 // in config file.
576 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530577 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600578 //Add the NTP server
579 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530580 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600581 stream << "NTP=" << ntp << "\n";
582 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530583
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600584 //Add the DNS entry
585 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530586 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600587 stream << "DNS=" << dns << "\n";
588 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530589
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600590 // Static
591 for (const auto& addr : addrs)
592 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400593 if (addr.second->origin() == AddressOrigin::Static
594#ifndef LINK_LOCAL_AUTOCONFIGURATION
595 || addr.second->origin() == AddressOrigin::LinkLocal
596#endif
597 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530598 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600599 std::string address = addr.second->address() + "/" +
600 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530601
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600602 stream << "Address=" << address << "\n";
603 }
604 }
605
606 if (manager.getSystemConf())
607 {
608 stream << "Gateway=" << manager.getSystemConf()->defaultGateway()
609 << "\n";
610 }
611
612 // write the route section
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600613 for (const auto& addr : addrs)
614 {
615 if (addr.second->origin() == AddressOrigin::Static)
616 {
617 int addressFamily = addr.second->type() == IP::Protocol::IPv4 ?
618 AF_INET : AF_INET6;
619
620 std::string destination = getNetworkID(
621 addressFamily,
622 addr.second->address(),
623 addr.second->prefixLength());
624
625 if (addr.second->gateway() != "0.0.0.0" &&
626 addr.second->gateway() != "" &&
627 destination != "0.0.0.0" &&
628 destination != "")
629 {
Ratan Gupta3e60e072018-05-04 16:53:47 +0530630 stream << "[" << "Route" << "]\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600631 stream << "Gateway=" << addr.second->gateway() << "\n";
632 stream << "Destination=" << destination << "\n";
633 }
634 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530635 }
636 }
637
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600638 // Write the dhcp section irrespective of whether DHCP is enabled or not
639 writeDHCPSection(stream);
640
Ratan Gupta2b106532017-07-25 16:05:02 +0530641 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530642}
643
644void EthernetInterface::writeDHCPSection(std::fstream& stream)
645{
646 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530647 // write the dhcp section
648 stream << "[DHCP]\n";
649
650 // Hardcoding the client identifier to mac, to address below issue
651 // https://github.com/openbmc/openbmc/issues/1280
652 stream << "ClientIdentifier=mac\n";
653 if (manager.getDHCPConf())
654 {
655 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
656 stream << "UseDNS="s + value + "\n";
657
658 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
659 stream << "UseNTP="s + value + "\n";
660
661 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
662 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600663
664 value =
665 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
666 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530667 }
668}
669
Ratan Guptabd303b12017-08-18 17:10:07 +0530670std::string EthernetInterface::mACAddress(std::string value)
671{
672 if (!mac_address::validate(value))
673 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500674 log<level::ERR>("MACAddress is not valid.",
Ratan Guptabd303b12017-08-18 17:10:07 +0530675 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500676 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
677 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530678 }
679
680 // check whether MAC is broadcast mac.
681 auto intMac = mac_address::internal::convertToInt(value);
682
683 if (!(intMac ^ mac_address::broadcastMac))
684 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500685 log<level::ERR>("MACAddress is a broadcast mac.",
Ratan Guptabd303b12017-08-18 17:10:07 +0530686 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500687 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
688 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530689 }
690
Patrick Ventured475cd62018-02-26 17:07:41 -0800691 // Check if the MAC changed.
692 auto pmac = MacAddressIntf::mACAddress();
693 if (strcasecmp(pmac.c_str(), value.c_str()) == 0)
694 {
695 return MacAddressIntf::mACAddress();
696 }
697
Ratan Guptabd303b12017-08-18 17:10:07 +0530698 // Allow the mac to be set if one of the condition is true.
699 // 1) Incoming Mac is of local admin type.
700 // or
701 // 2) Incoming mac is same as eeprom Mac.
702
703 if (!(intMac & mac_address::localAdminMask))
704 {
705 try
706 {
707 auto inventoryMac = mac_address::getfromInventory(bus);
708 auto intInventoryMac = mac_address::internal::convertToInt(inventoryMac);
709
710 if (intInventoryMac != intMac)
711 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500712 log<level::ERR>("Given MAC address is neither a local Admin "
Patrick Venturee0ad43a2017-11-29 18:19:54 -0800713 "type nor is same as in inventory");
Gunnar Mills90480c42018-06-19 16:02:17 -0500714 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
715 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530716 }
717 }
718 catch(InternalFailure& e)
719 {
Patrick Venturee0ad43a2017-11-29 18:19:54 -0800720 log<level::ERR>("Exception occurred during getting of MAC "
721 "address from Inventory");
Ratan Guptabd303b12017-08-18 17:10:07 +0530722 return MacAddressIntf::mACAddress();
723 }
724 }
725 auto interface = interfaceName();
726 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
727 //TODO: would replace below three calls
728 // with restarting of systemd-netwokd
729 // through https://github.com/systemd/systemd/issues/6696
730 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
731 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "address",
732 value.c_str());
733
734 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
735
736 auto mac = MacAddressIntf::mACAddress(std::move(value));
737 //update all the vlan interfaces
738 for(const auto& intf: vlanInterfaces)
739 {
740 intf.second->updateMacAddress();
741 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530742
743 // restart the systemd networkd so that dhcp client gets the
744 // ip for the changed mac address.
745 if (dHCPEnabled())
746 {
Lei YU250011e2018-02-01 14:07:06 +0800747 restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530748 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530749 return mac;
750
751}
752
Ratan Guptae9c9b812017-09-22 17:15:37 +0530753void EthernetInterface::deleteAll()
754{
755 if(EthernetInterfaceIntf::dHCPEnabled())
756 {
757 log<level::INFO>("DHCP enabled on the interface"),
758 entry("INTERFACE=%s", interfaceName().c_str());
759
760 }
761
762 // clear all the ip on the interface
763 addrs.clear();
764 manager.writeToConfigurationFile();
765}
766
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530767}//namespace network
768}//namespace phosphor