blob: c9bf123c221b70c9730d7cfbfef5f1789369a0ff [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 Gupta29b0e432017-05-25 12:51:40 +053054 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053055 if (emitSignal)
56 {
57 this->emit_object_added();
58 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053059}
60
Ratan Gupta87c13982017-06-15 09:27:27 +053061void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053062{
Ratan Gupta82549cc2017-04-21 08:45:23 +053063 std::string gateway;
Ratan Gupta87c13982017-06-15 09:27:27 +053064 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053065
Ratan Gupta87c13982017-06-15 09:27:27 +053066 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053067
Ratan Gupta82549cc2017-04-21 08:45:23 +053068 IP::Protocol addressType = IP::Protocol::IPv4;
Ratan Gupta29b0e432017-05-25 12:51:40 +053069 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053070 route::Table routingTable;
Ratan Gupta5978dd12017-07-25 13:47:13 +053071
Ratan Gupta6a387c12017-08-03 13:26:19 +053072 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053073 {
74 if (addr.addrType == AF_INET6)
75 {
76 addressType = IP::Protocol::IPv6;
77 }
Ratan Guptafc2c7242017-05-29 08:46:06 +053078 if (dHCPEnabled())
79 {
80 origin = IP::AddressOrigin::DHCP;
81 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050082 else if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053083 {
84 origin = IP::AddressOrigin::LinkLocal;
85 }
86 gateway = routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
Ratan Gupta82549cc2017-04-21 08:45:23 +053087
Ratan Gupta65e5abe2017-05-23 13:20:44 +053088 std::string ipAddressObjectPath = generateObjectPath(addressType,
89 addr.ipaddress,
90 addr.prefix,
91 gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +053092
Ratan Gupta82549cc2017-04-21 08:45:23 +053093 this->addrs.emplace(
Ratan Guptae578d562017-08-02 07:04:16 +053094 std::move(addr.ipaddress),
95 std::make_shared<phosphor::network::IPAddress>(
Ratan Gupta719f83a2017-06-02 11:54:53 +053096 bus,
97 ipAddressObjectPath.c_str(),
98 *this,
99 addressType,
Ratan Gupta82549cc2017-04-21 08:45:23 +0530100 addr.ipaddress,
Ratan Gupta29b0e432017-05-25 12:51:40 +0530101 origin,
Ratan Gupta719f83a2017-06-02 11:54:53 +0530102 addr.prefix,
Ratan Guptae578d562017-08-02 07:04:16 +0530103 gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530104 }
Ratan Guptafc2c7242017-05-29 08:46:06 +0530105
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530106}
107
Ratan Gupta82549cc2017-04-21 08:45:23 +0530108void EthernetInterface::iP(IP::Protocol protType,
109 std::string ipaddress,
110 uint8_t prefixLength,
111 std::string gateway)
112{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530113
114 if (dHCPEnabled())
115 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530116 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500117 entry("INTERFACE=%s", interfaceName().c_str());
118 dHCPEnabled(false);
119 }
120
121
122 IP::AddressOrigin origin = IP::AddressOrigin::Static;
123
124 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
125
126 if (!isValidIP(addressFamily, ipaddress))
127 {
128 log<level::ERR>("Not a valid IP address"),
129 entry("ADDRESS=%s", ipaddress.c_str());
130 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
131 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
132 }
133
134 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
135 {
136 log<level::ERR>("Not a valid Gateway"),
137 entry("GATEWAY=%s", gateway.c_str());
138 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
139 Argument::ARGUMENT_VALUE(gateway.c_str()));
140 }
141
142 if (!isValidPrefix(addressFamily, prefixLength))
143 {
144 log<level::ERR>("PrefixLength is not correct "),
145 entry("PREFIXLENGTH=%d", gateway.c_str());
146 elog<InvalidArgument>(Argument::ARGUMENT_NAME("prefixLength"),
147 Argument::ARGUMENT_VALUE(std::to_string(
148 prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530149 return;
150 }
151
Ratan Gupta29b0e432017-05-25 12:51:40 +0530152
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530153 std::string objectPath = generateObjectPath(protType,
154 ipaddress,
155 prefixLength,
156 gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530157 this->addrs.emplace(
Ratan Guptae578d562017-08-02 07:04:16 +0530158 std::move(ipaddress),
159 std::make_shared<phosphor::network::IPAddress>(
160 bus,
161 objectPath.c_str(),
162 *this,
163 protType,
164 ipaddress,
165 origin,
166 prefixLength,
167 gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530168
Ratan Guptae05083a2017-09-16 07:12:11 +0530169 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530170}
171
172
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530173/*
174Note: We don't have support for ethtool now
175will enable this code once we bring the ethtool
176in the image.
177TODO: https://github.com/openbmc/openbmc/issues/1484
178*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530179
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530180InterfaceInfo EthernetInterface::getInterfaceInfo() const
181{
182 int sock{-1};
183 struct ifreq ifr{0};
184 struct ethtool_cmd edata{0};
185 LinkSpeed speed {0};
186 Autoneg autoneg {0};
187 DuplexMode duplex {0};
188 do
189 {
190 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
191 if (sock < 0)
192 {
193 log<level::ERR>("socket creation failed:",
194 entry("ERROR=%s", strerror(errno)));
195 break;
196 }
197
198 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
199 ifr.ifr_data = reinterpret_cast<char*>(&edata);
200
201 edata.cmd = ETHTOOL_GSET;
202
203 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
204 {
205 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
206 entry("ERROR=%s", strerror(errno)));
207 break;
208
209 }
210 speed = edata.speed;
211 duplex = edata.duplex;
212 autoneg = edata.autoneg;
213 }
214 while (0);
215
216 if (sock)
217 {
218 close(sock);
219 }
220 return std::make_tuple(speed, duplex, autoneg);
221}
222
223/** @brief get the mac address of the interface.
224 * @return macaddress on success
225 */
226
Ratan Guptada7d3af2017-08-13 17:49:56 +0530227std::string EthernetInterface::getMACAddress(
228 const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530229{
Ratan Guptada7d3af2017-08-13 17:49:56 +0530230 struct ifreq ifr{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530231 char macAddress[mac_address::size] {};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530232
233 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
234 if (sock < 0)
235 {
236 log<level::ERR>("socket creation failed:",
237 entry("ERROR=%s", strerror(errno)));
238 return macAddress;
239 }
240
Ratan Guptada7d3af2017-08-13 17:49:56 +0530241 strcpy(ifr.ifr_name, interfaceName.c_str());
242 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530243 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530244 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
245 entry("ERROR=%s", strerror(errno)));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530246 return macAddress;
247 }
248
Ratan Guptabd303b12017-08-18 17:10:07 +0530249 snprintf(macAddress, mac_address::size, mac_address::format,
Ratan Guptada7d3af2017-08-13 17:49:56 +0530250 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
251 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
252 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530253
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530254 return macAddress;
255}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530256
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530257std::string EthernetInterface::generateId(const std::string& ipaddress,
258 uint8_t prefixLength,
259 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530260{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530261 std::stringstream hexId;
262 std::string hashString = ipaddress;
263 hashString += std::to_string(prefixLength);
264 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530265
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530266 // Only want 8 hex digits.
267 hexId << std::hex << ((std::hash<std::string> {}(
Ratan Guptafc2c7242017-05-29 08:46:06 +0530268 hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530269 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530270}
271
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530272void EthernetInterface::deleteObject(const std::string& ipaddress)
273{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530274 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530275 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530276 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530277 log<level::ERR>("DeleteObject:Unable to find the object.");
278 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530279 }
280 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530281 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530282}
283
Ratan Guptae9c9b812017-09-22 17:15:37 +0530284void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530285{
Ratan Guptabc886292017-07-25 18:29:57 +0530286 auto confDir = manager.getConfDir();
287 fs::path networkFile = confDir;
288 networkFile /= systemd::config::networkFilePrefix + interface +
289 systemd::config::networkFileSuffix;
290
291 fs::path deviceFile = confDir;
292 deviceFile /= interface + systemd::config::deviceFileSuffix;
293
294 // delete the vlan network file
295 if (fs::is_regular_file(networkFile))
296 {
297 fs::remove(networkFile);
298 }
299
300 // delete the vlan device file
301 if (fs::is_regular_file(deviceFile))
302 {
303 fs::remove(deviceFile);
304 }
Ratan Guptabc886292017-07-25 18:29:57 +0530305
306 // TODO systemd doesn't delete the virtual network interface
307 // even after deleting all the related configuartion.
308 // https://github.com/systemd/systemd/issues/6600
309 try
310 {
311 deleteInterface(interface);
312 }
313 catch (InternalFailure& e)
314 {
315 commit<InternalFailure>();
316 }
Ratan Guptae05083a2017-09-16 07:12:11 +0530317
Ratan Guptae9c9b812017-09-22 17:15:37 +0530318}
319
320void EthernetInterface::deleteVLANObject(const std::string& interface)
321{
322 auto it = vlanInterfaces.find(interface);
323 if (it == vlanInterfaces.end())
324 {
325 log<level::ERR>("DeleteVLANObject:Unable to find the object",
326 entry("INTERFACE=%s",interface.c_str()));
327 return;
328 }
329
330 deleteVLANFromSystem(interface);
331 // delete the interface
332 vlanInterfaces.erase(it);
333
Ratan Guptae05083a2017-09-16 07:12:11 +0530334 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530335}
336
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530337std::string EthernetInterface::generateObjectPath(IP::Protocol addressType,
338 const std::string& ipaddress,
339 uint8_t prefixLength,
340 const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530341{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530342 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530343 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530344 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
345
346 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530347 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530348 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530349 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530350 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530351}
352
Ratan Gupta87c13982017-06-15 09:27:27 +0530353bool EthernetInterface::dHCPEnabled(bool value)
354{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530355 if (value == EthernetInterfaceIntf::dHCPEnabled())
356 {
357 return value;
358 }
359
Ratan Gupta87c13982017-06-15 09:27:27 +0530360 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530361 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530362 return value;
363}
364
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530365void EthernetInterface::loadVLAN(VlanId id)
366{
367 std::string vlanInterfaceName = interfaceName() + "." +
368 std::to_string(id);
369 std::string path = objPath;
370 path += "_" + std::to_string(id);
371
Ratan Gupta6e8df632017-08-13 09:41:58 +0530372 auto dhcpEnabled = getDHCPValue(manager.getConfDir().string(),
373 vlanInterfaceName);
374
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530375 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
376 bus,
377 path.c_str(),
Ratan Gupta6e8df632017-08-13 09:41:58 +0530378 dhcpEnabled,
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530379 id,
380 *this,
381 manager);
382
383 // Fetch the ip address from the system
384 // and create the dbus object.
385 vlanIntf->createIPAddressObjects();
386
387 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
388 std::move(vlanIntf));
389}
390
Ratan Gupta5978dd12017-07-25 13:47:13 +0530391void EthernetInterface::createVLAN(VlanId id)
392{
393 std::string vlanInterfaceName = interfaceName() + "." +
394 std::to_string(id);
395 std::string path = objPath;
396 path += "_" + std::to_string(id);
397
398
399 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
400 bus,
401 path.c_str(),
Ratan Guptae05083a2017-09-16 07:12:11 +0530402 false,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530403 id,
404 *this,
405 manager);
406
407 // write the device file for the vlan interface.
408 vlanIntf->writeDeviceFile();
409
Ratan Gupta6e8df632017-08-13 09:41:58 +0530410 this->vlanInterfaces.emplace(vlanInterfaceName,
Ratan Gupta5978dd12017-07-25 13:47:13 +0530411 std::move(vlanIntf));
412 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530413 manager.writeToConfigurationFile();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530414}
Ratan Gupta2b106532017-07-25 16:05:02 +0530415
Ratan Gupta497c0c92017-08-22 19:15:59 +0530416ServerList EthernetInterface::getNTPServersFromConf()
417{
418 fs::path confPath = manager.getConfDir();
419
420 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
421 systemd::config::networkFileSuffix;
422 confPath /= fileName;
423 ServerList servers;
424 try
425 {
426 config::Parser parser(confPath.string());
427 servers = parser.getValues("Network", "NTP");
428 }
429 catch (InternalFailure& e)
430 {
431 log<level::INFO>("Unable to find the NTP server configuration.");
432 }
433 return servers;
434}
435
436ServerList EthernetInterface::nTPServers(ServerList servers)
437{
438 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
439
440 writeConfigurationFile();
441 // timesynchd reads the NTP server configuration from the
442 // network file.
443 restartSystemdUnit(timeSynchdService);
444 return ntpServers;
445}
Ratan Gupta2b106532017-07-25 16:05:02 +0530446// Need to merge the below function with the code which writes the
447// config file during factory reset.
448// TODO openbmc/openbmc#1751
449
450void EthernetInterface::writeConfigurationFile()
451{
452 // write all the static ip address in the systemd-network conf file
453
454 using namespace std::string_literals;
455 using AddressOrigin =
456 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
457 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530458
459 // if there is vlan interafce then write the configuration file
460 // for vlan also.
461
462 for (const auto& intf: vlanInterfaces)
463 {
464 intf.second->writeConfigurationFile();
465 }
466
Ratan Gupta2b106532017-07-25 16:05:02 +0530467 fs::path confPath = manager.getConfDir();
468
Ratan Guptabc886292017-07-25 18:29:57 +0530469 std::string fileName = systemd::config::networkFilePrefix + interfaceName() +
470 systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530471 confPath /= fileName;
472 std::fstream stream;
473
474 stream.open(confPath.c_str(), std::fstream::out);
475 if (!stream.is_open())
476 {
477 log<level::ERR>("Unable to open the file",
478 entry("FILE=%s", confPath.c_str()));
479 elog<InternalFailure>();
480 }
481
482 // Write the device
483 stream << "[" << "Match" << "]\n";
484 stream << "Name=" << interfaceName() << "\n";
485
486 auto addrs = getAddresses();
487
488 // write the network section
489 stream << "[" << "Network" << "]\n";
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500490 stream << "LinkLocalAddressing=yes\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530491
492 // Add the VLAN entry
493 for (const auto& intf: vlanInterfaces)
494 {
495 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
496 << "\n";
497 }
498
Ratan Gupta2b106532017-07-25 16:05:02 +0530499 // DHCP
500 if (dHCPEnabled() == true)
501 {
502 // write the dhcp section if interface is
503 // configured as dhcp.
504 writeDHCPSection(stream);
505 stream.close();
506 return;
507 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530508
Ratan Gupta497c0c92017-08-22 19:15:59 +0530509 //Add the NTP server
510 for(const auto& ntp: EthernetInterfaceIntf::nTPServers())
511 {
512 stream << "NTP=" << ntp << "\n";
513 }
514
Ratan Gupta2b106532017-07-25 16:05:02 +0530515 // Static
516 for (const auto& addr : addrs)
517 {
518 if (addr.second->origin() == AddressOrigin::Static)
519 {
520 std::string address = addr.second->address() + "/" + std::to_string(
521 addr.second->prefixLength());
522
523 stream << "Address=" << address << "\n";
524 }
525 }
526
527 if (manager.getSystemConf())
528 {
529 stream << "Gateway=" << manager.getSystemConf()->defaultGateway()
530 << "\n";
531 }
532 // write the route section
533 stream << "[" << "Route" << "]\n";
534 for(const auto& addr : addrs)
535 {
536 if (addr.second->origin() == AddressOrigin::Static)
537 {
538 int addressFamily = addr.second->type() == IP::Protocol::IPv4 ? AF_INET : AF_INET6;
539 std::string destination = getNetworkID(
540 addressFamily,
541 addr.second->address(),
542 addr.second->prefixLength());
543
544 if (addr.second->gateway() != "0.0.0.0" &&
545 addr.second->gateway() != "" &&
546 destination != "0.0.0.0" &&
547 destination != "")
548 {
549 stream << "Gateway=" << addr.second->gateway() << "\n";
550 stream << "Destination=" << destination << "\n";
551 }
552
553 }
554 }
555
556 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530557}
558
559void EthernetInterface::writeDHCPSection(std::fstream& stream)
560{
561 using namespace std::string_literals;
562 stream << "DHCP=true\n";
563 // write the dhcp section
564 stream << "[DHCP]\n";
565
566 // Hardcoding the client identifier to mac, to address below issue
567 // https://github.com/openbmc/openbmc/issues/1280
568 stream << "ClientIdentifier=mac\n";
569 if (manager.getDHCPConf())
570 {
571 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
572 stream << "UseDNS="s + value + "\n";
573
574 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
575 stream << "UseNTP="s + value + "\n";
576
577 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
578 stream << "UseHostname="s + value + "\n";
579 }
580}
581
Ratan Guptabd303b12017-08-18 17:10:07 +0530582std::string EthernetInterface::mACAddress(std::string value)
583{
584 if (!mac_address::validate(value))
585 {
586 log<level::DEBUG>("MACAddress is not valid.",
587 entry("MAC=%s", value.c_str()));
588 return MacAddressIntf::mACAddress();
589 }
590
591 // check whether MAC is broadcast mac.
592 auto intMac = mac_address::internal::convertToInt(value);
593
594 if (!(intMac ^ mac_address::broadcastMac))
595 {
596 log<level::DEBUG>("MACAddress is a broadcast mac.",
597 entry("MAC=%s", value.c_str()));
598 return MacAddressIntf::mACAddress();
599 }
600
601 // Allow the mac to be set if one of the condition is true.
602 // 1) Incoming Mac is of local admin type.
603 // or
604 // 2) Incoming mac is same as eeprom Mac.
605
606 if (!(intMac & mac_address::localAdminMask))
607 {
608 try
609 {
610 auto inventoryMac = mac_address::getfromInventory(bus);
611 auto intInventoryMac = mac_address::internal::convertToInt(inventoryMac);
612
613 if (intInventoryMac != intMac)
614 {
615 log<level::DEBUG>("Given MAC address is neither a local Admin \
616 type nor is same as in inventory");
617 return MacAddressIntf::mACAddress();
618 }
619 }
620 catch(InternalFailure& e)
621 {
Gunnar Millsd75f0492017-10-25 20:33:32 -0500622 log<level::ERR>("Exception occurred during getting of MAC \
Ratan Guptabd303b12017-08-18 17:10:07 +0530623 address from Inventory");
624 return MacAddressIntf::mACAddress();
625 }
626 }
627 auto interface = interfaceName();
628 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
629 //TODO: would replace below three calls
630 // with restarting of systemd-netwokd
631 // through https://github.com/systemd/systemd/issues/6696
632 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
633 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "address",
634 value.c_str());
635
636 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
637
638 auto mac = MacAddressIntf::mACAddress(std::move(value));
639 //update all the vlan interfaces
640 for(const auto& intf: vlanInterfaces)
641 {
642 intf.second->updateMacAddress();
643 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530644
645 // restart the systemd networkd so that dhcp client gets the
646 // ip for the changed mac address.
647 if (dHCPEnabled())
648 {
649 restartSystemdUnit("systemd-networkd.service");
650 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530651 return mac;
652
653}
654
Ratan Guptae9c9b812017-09-22 17:15:37 +0530655void EthernetInterface::deleteAll()
656{
657 if(EthernetInterfaceIntf::dHCPEnabled())
658 {
659 log<level::INFO>("DHCP enabled on the interface"),
660 entry("INTERFACE=%s", interfaceName().c_str());
661
662 }
663
664 // clear all the ip on the interface
665 addrs.clear();
666 manager.writeToConfigurationFile();
667}
668
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530669}//namespace network
670}//namespace phosphor