blob: f2ad37275b7b1aa0236d50d8278dae4c804e0c52 [file] [log] [blame]
Gunnar Mills57d9c502018-09-14 14:42:34 -05001#include "config.h"
2
Patrick Venture189d44e2018-07-09 12:30:59 -07003#include "ethernet_interface.hpp"
4
Ratan Gupta497c0c92017-08-22 19:15:59 +05305#include "config_parser.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05306#include "ipaddress.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05307#include "network_manager.hpp"
Ratan Guptafc2c7242017-05-29 08:46:06 +05308#include "routing_table.hpp"
Ratan Gupta2b106532017-07-25 16:05:02 +05309#include "vlan_interface.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +053010
Ratan Gupta82549cc2017-04-21 08:45:23 +053011#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053012#include <linux/ethtool.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053013#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053014#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053015#include <netinet/in.h>
16#include <sys/ioctl.h>
17#include <sys/socket.h>
18#include <unistd.h>
19
Ratan Gupta82549cc2017-04-21 08:45:23 +053020#include <algorithm>
21#include <experimental/filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053022#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070023#include <phosphor-logging/elog-errors.hpp>
24#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053025#include <sstream>
26#include <string>
Patrick Venture189d44e2018-07-09 12:30:59 -070027#include <xyz/openbmc_project/Common/error.hpp>
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,
Gunnar Mills57d9c502018-09-14 14:42:34 -050040 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053041 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 Ifaces(bus, objPath.c_str(), true),
43 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053044{
45 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053046 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053047 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053048 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Ratan Guptabd303b12017-08-18 17:10:07 +053049 MacAddressIntf::mACAddress(getMACAddress(intfName));
Ratan Gupta497c0c92017-08-22 19:15:59 +053050 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta6dec390f2017-08-20 15:28:12 +053051 EthernetInterfaceIntf::nameservers(getNameServerFromConf());
52
Ratan Gupta29b0e432017-05-25 12:51:40 +053053 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053054 if (emitSignal)
55 {
56 this->emit_object_added();
57 }
Ratan Gupta29b0e432017-05-25 12:51:40 +053058}
59
Ratan Gupta87c13982017-06-15 09:27:27 +053060void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +053061{
Ratan Gupta82549cc2017-04-21 08:45:23 +053062 std::string gateway;
Ratan Gupta87c13982017-06-15 09:27:27 +053063 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +053064
Ratan Gupta87c13982017-06-15 09:27:27 +053065 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +053066
Ratan Gupta82549cc2017-04-21 08:45:23 +053067 IP::Protocol addressType = IP::Protocol::IPv4;
Ratan Gupta29b0e432017-05-25 12:51:40 +053068 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053069 route::Table routingTable;
Ratan Gupta5978dd12017-07-25 13:47:13 +053070
Ratan Gupta6a387c12017-08-03 13:26:19 +053071 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +053072 {
73 if (addr.addrType == AF_INET6)
74 {
75 addressType = IP::Protocol::IPv6;
76 }
Ratan Guptafc2c7242017-05-29 08:46:06 +053077 if (dHCPEnabled())
78 {
79 origin = IP::AddressOrigin::DHCP;
80 }
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050081 else if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +053082 {
83 origin = IP::AddressOrigin::LinkLocal;
84 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050085 gateway =
86 routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
Ratan Gupta82549cc2017-04-21 08:45:23 +053087
Gunnar Mills57d9c502018-09-14 14:42:34 -050088 std::string ipAddressObjectPath = generateObjectPath(
89 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +053090
Gunnar Mills57d9c502018-09-14 14:42:34 -050091 this->addrs.emplace(addr.ipaddress,
92 std::make_shared<phosphor::network::IPAddress>(
93 bus, ipAddressObjectPath.c_str(), *this,
94 addressType, addr.ipaddress, origin,
95 addr.prefix, gateway));
Ratan Gupta603598d2017-11-14 20:58:38 +053096
97 origin = IP::AddressOrigin::Static;
Ratan Gupta82549cc2017-04-21 08:45:23 +053098 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +053099}
100
Gunnar Mills57d9c502018-09-14 14:42:34 -0500101void EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
102 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530103{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530104
105 if (dHCPEnabled())
106 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530107 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500108 entry("INTERFACE=%s", interfaceName().c_str());
109 dHCPEnabled(false);
110 }
111
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500112 IP::AddressOrigin origin = IP::AddressOrigin::Static;
113
114 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
115
116 if (!isValidIP(addressFamily, ipaddress))
117 {
118 log<level::ERR>("Not a valid IP address"),
119 entry("ADDRESS=%s", ipaddress.c_str());
120 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
121 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
122 }
123
124 if (!gateway.empty() && (!isValidIP(addressFamily, gateway)))
125 {
126 log<level::ERR>("Not a valid Gateway"),
127 entry("GATEWAY=%s", gateway.c_str());
128 elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
129 Argument::ARGUMENT_VALUE(gateway.c_str()));
130 }
131
132 if (!isValidPrefix(addressFamily, prefixLength))
133 {
134 log<level::ERR>("PrefixLength is not correct "),
135 entry("PREFIXLENGTH=%d", gateway.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500136 elog<InvalidArgument>(
137 Argument::ARGUMENT_NAME("prefixLength"),
138 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530139 }
140
Gunnar Mills57d9c502018-09-14 14:42:34 -0500141 std::string objectPath =
142 generateObjectPath(protType, ipaddress, prefixLength, gateway);
143 this->addrs.emplace(ipaddress,
144 std::make_shared<phosphor::network::IPAddress>(
145 bus, objectPath.c_str(), *this, protType, ipaddress,
146 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530147
Ratan Guptae05083a2017-09-16 07:12:11 +0530148 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530149}
150
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530151/*
152Note: We don't have support for ethtool now
153will enable this code once we bring the ethtool
154in the image.
155TODO: https://github.com/openbmc/openbmc/issues/1484
156*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530157
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530158InterfaceInfo EthernetInterface::getInterfaceInfo() const
159{
160 int sock{-1};
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400161 ifreq ifr{0};
162 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500163 LinkSpeed speed{0};
164 Autoneg autoneg{0};
165 DuplexMode duplex{0};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530166 do
167 {
168 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
169 if (sock < 0)
170 {
171 log<level::ERR>("socket creation failed:",
172 entry("ERROR=%s", strerror(errno)));
173 break;
174 }
175
176 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
177 ifr.ifr_data = reinterpret_cast<char*>(&edata);
178
179 edata.cmd = ETHTOOL_GSET;
180
181 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
182 {
183 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
184 entry("ERROR=%s", strerror(errno)));
185 break;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530186 }
187 speed = edata.speed;
188 duplex = edata.duplex;
189 autoneg = edata.autoneg;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500190 } while (0);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530191
192 if (sock)
193 {
194 close(sock);
195 }
196 return std::make_tuple(speed, duplex, autoneg);
197}
198
199/** @brief get the mac address of the interface.
200 * @return macaddress on success
201 */
202
Gunnar Mills57d9c502018-09-14 14:42:34 -0500203std::string
204 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530205{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400206 ifreq ifr{};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500207 char macAddress[mac_address::size]{};
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530208
209 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
210 if (sock < 0)
211 {
212 log<level::ERR>("socket creation failed:",
213 entry("ERROR=%s", strerror(errno)));
214 return macAddress;
215 }
216
Patrick Venture836c91d2018-09-11 17:36:03 -0700217 std::strcpy(ifr.ifr_name, interfaceName.c_str());
Ratan Guptada7d3af2017-08-13 17:49:56 +0530218 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530219 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530220 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500221 entry("ERROR=%s", strerror(errno)));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530222 return macAddress;
223 }
224
Patrick Venture836c91d2018-09-11 17:36:03 -0700225 std::snprintf(macAddress, mac_address::size, mac_address::format,
226 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
227 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
228 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530229
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530230 return macAddress;
231}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530232
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530233std::string EthernetInterface::generateId(const std::string& ipaddress,
234 uint8_t prefixLength,
235 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530236{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530237 std::stringstream hexId;
238 std::string hashString = ipaddress;
239 hashString += std::to_string(prefixLength);
240 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530241
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530242 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500243 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530244 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530245}
246
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530247void EthernetInterface::deleteObject(const std::string& ipaddress)
248{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530249 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530250 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530251 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530252 log<level::ERR>("DeleteObject:Unable to find the object.");
253 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530254 }
255 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530256 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530257}
258
Ratan Guptae9c9b812017-09-22 17:15:37 +0530259void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530260{
Ratan Guptabc886292017-07-25 18:29:57 +0530261 auto confDir = manager.getConfDir();
262 fs::path networkFile = confDir;
263 networkFile /= systemd::config::networkFilePrefix + interface +
264 systemd::config::networkFileSuffix;
265
266 fs::path deviceFile = confDir;
267 deviceFile /= interface + systemd::config::deviceFileSuffix;
268
269 // delete the vlan network file
270 if (fs::is_regular_file(networkFile))
271 {
272 fs::remove(networkFile);
273 }
274
275 // delete the vlan device file
276 if (fs::is_regular_file(deviceFile))
277 {
278 fs::remove(deviceFile);
279 }
Ratan Guptabc886292017-07-25 18:29:57 +0530280
281 // TODO systemd doesn't delete the virtual network interface
282 // even after deleting all the related configuartion.
283 // https://github.com/systemd/systemd/issues/6600
284 try
285 {
286 deleteInterface(interface);
287 }
288 catch (InternalFailure& e)
289 {
290 commit<InternalFailure>();
291 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530292}
293
294void EthernetInterface::deleteVLANObject(const std::string& interface)
295{
296 auto it = vlanInterfaces.find(interface);
297 if (it == vlanInterfaces.end())
298 {
299 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500300 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530301 return;
302 }
303
304 deleteVLANFromSystem(interface);
305 // delete the interface
306 vlanInterfaces.erase(it);
307
Ratan Guptae05083a2017-09-16 07:12:11 +0530308 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530309}
310
Gunnar Mills57d9c502018-09-14 14:42:34 -0500311std::string EthernetInterface::generateObjectPath(
312 IP::Protocol addressType, const std::string& ipaddress,
313 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530314{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530315 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530316 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530317 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
318
319 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530320 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530321 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530322 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530323 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530324}
325
Ratan Gupta87c13982017-06-15 09:27:27 +0530326bool EthernetInterface::dHCPEnabled(bool value)
327{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530328 if (value == EthernetInterfaceIntf::dHCPEnabled())
329 {
330 return value;
331 }
332
Ratan Gupta87c13982017-06-15 09:27:27 +0530333 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530334 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530335 return value;
336}
337
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530338ServerList EthernetInterface::nameservers(ServerList value)
339{
340 try
341 {
342 EthernetInterfaceIntf::nameservers(value);
343
344 writeConfigurationFile();
345
346 // Currently we don't have systemd-resolved enabled
347 // in the openbmc. Once we update the network conf file,
348 // it should be read by systemd-resolved.service.
349
350 // The other reason to write the resolv conf is,
351 // we don't want to restart the networkd for nameserver change.
352 // as restarting of systemd-networkd takes more then 2 secs
353 writeDNSEntries(value, resolvConfFile);
354 }
355 catch (InternalFailure& e)
356 {
357 log<level::ERR>("Exception processing DNS entries");
358 }
359 return EthernetInterfaceIntf::nameservers();
360}
361
362ServerList EthernetInterface::getNameServerFromConf()
363{
364 fs::path confPath = manager.getConfDir();
365
366 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500367 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530368 confPath /= fileName;
369 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530370 config::Parser parser(confPath.string());
371 auto rc = config::ReturnCode::SUCCESS;
372
373 std::tie(rc, servers) = parser.getValues("Network", "DNS");
374 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530375 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530376 log<level::DEBUG>("Unable to get the value for network[DNS]",
377 entry("RC=%d", rc));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530378 }
379 return servers;
380}
381
382void EthernetInterface::writeDNSEntries(const ServerList& dnsList,
383 const std::string& file)
384{
385 std::fstream outStream(file, std::fstream::out);
386 if (!outStream.is_open())
387 {
388 log<level::ERR>("Unable to open the file",
389 entry("FILE=%s", file.c_str()));
390 elog<InternalFailure>();
391 }
392
Ratan Guptafe116912017-11-10 16:00:59 +0530393 outStream << "### Generated manually via dbus settings ###\n";
Gunnar Mills57d9c502018-09-14 14:42:34 -0500394 for (const auto& server : dnsList)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530395 {
396 outStream << "nameserver " << server << "\n";
397 }
398}
399
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530400void EthernetInterface::loadVLAN(VlanId id)
401{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500402 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530403 std::string path = objPath;
404 path += "_" + std::to_string(id);
405
Gunnar Mills57d9c502018-09-14 14:42:34 -0500406 auto dhcpEnabled =
407 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530408
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530409 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500410 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530411
Gunnar Mills57d9c502018-09-14 14:42:34 -0500412 // Fetch the ip address from the system
413 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530414 vlanIntf->createIPAddressObjects();
415
416 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
417 std::move(vlanIntf));
418}
419
Ratan Gupta5978dd12017-07-25 13:47:13 +0530420void EthernetInterface::createVLAN(VlanId id)
421{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500422 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530423 std::string path = objPath;
424 path += "_" + std::to_string(id);
425
Ratan Gupta5978dd12017-07-25 13:47:13 +0530426 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530428
429 // write the device file for the vlan interface.
430 vlanIntf->writeDeviceFile();
431
Gunnar Mills57d9c502018-09-14 14:42:34 -0500432 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530433 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530434 manager.writeToConfigurationFile();
Ratan Gupta5978dd12017-07-25 13:47:13 +0530435}
Ratan Gupta2b106532017-07-25 16:05:02 +0530436
Ratan Gupta497c0c92017-08-22 19:15:59 +0530437ServerList EthernetInterface::getNTPServersFromConf()
438{
439 fs::path confPath = manager.getConfDir();
440
Gunnar Mills57d9c502018-09-14 14:42:34 -0500441 std::string fileName = systemd::config::networkFilePrefix +
442 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530443 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530444
Ratan Gupta497c0c92017-08-22 19:15:59 +0530445 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530446 config::Parser parser(confPath.string());
447 auto rc = config::ReturnCode::SUCCESS;
448
449 std::tie(rc, servers) = parser.getValues("Network", "NTP");
450 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530451 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530452 log<level::DEBUG>("Unable to get the value for Network[NTP]",
453 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530454 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530455
Ratan Gupta497c0c92017-08-22 19:15:59 +0530456 return servers;
457}
458
459ServerList EthernetInterface::nTPServers(ServerList servers)
460{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500461 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530462
463 writeConfigurationFile();
464 // timesynchd reads the NTP server configuration from the
465 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530466 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530467 return ntpServers;
468}
Ratan Gupta2b106532017-07-25 16:05:02 +0530469// Need to merge the below function with the code which writes the
470// config file during factory reset.
471// TODO openbmc/openbmc#1751
472
473void EthernetInterface::writeConfigurationFile()
474{
475 // write all the static ip address in the systemd-network conf file
476
477 using namespace std::string_literals;
478 using AddressOrigin =
479 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
480 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530481
482 // if there is vlan interafce then write the configuration file
483 // for vlan also.
484
Gunnar Mills57d9c502018-09-14 14:42:34 -0500485 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530486 {
487 intf.second->writeConfigurationFile();
488 }
489
Ratan Gupta2b106532017-07-25 16:05:02 +0530490 fs::path confPath = manager.getConfDir();
491
Gunnar Mills57d9c502018-09-14 14:42:34 -0500492 std::string fileName = systemd::config::networkFilePrefix +
493 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530494 confPath /= fileName;
495 std::fstream stream;
496
497 stream.open(confPath.c_str(), std::fstream::out);
498 if (!stream.is_open())
499 {
500 log<level::ERR>("Unable to open the file",
501 entry("FILE=%s", confPath.c_str()));
502 elog<InternalFailure>();
503 }
504
505 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400506 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530507 stream << "Name=" << interfaceName() << "\n";
508
509 auto addrs = getAddresses();
510
511 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400512 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400513#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500514 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400515#else
516 stream << "LinkLocalAddressing=no\n";
517#endif
Ratan Guptae9629412017-12-21 08:20:25 +0530518 stream << "IPv6AcceptRA=false\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530519
520 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500521 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530522 {
523 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500524 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530525 }
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500526 // Add the DHCP entry
527 auto value = dHCPEnabled() ? "true"s : "false"s;
528 stream << "DHCP="s + value + "\n";
529
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600530 // When the interface configured as dhcp, we don't need below given entries
531 // in config file.
532 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530533 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500534 // Add the NTP server
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600535 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530536 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600537 stream << "NTP=" << ntp << "\n";
538 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530539
Gunnar Mills57d9c502018-09-14 14:42:34 -0500540 // Add the DNS entry
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600541 for (const auto& dns : EthernetInterfaceIntf::nameservers())
Ratan Gupta2b106532017-07-25 16:05:02 +0530542 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600543 stream << "DNS=" << dns << "\n";
544 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530545
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600546 // Static
547 for (const auto& addr : addrs)
548 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400549 if (addr.second->origin() == AddressOrigin::Static
550#ifndef LINK_LOCAL_AUTOCONFIGURATION
551 || addr.second->origin() == AddressOrigin::LinkLocal
552#endif
553 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530554 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500555 std::string address =
556 addr.second->address() + "/" +
557 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530558
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600559 stream << "Address=" << address << "\n";
560 }
561 }
562
563 if (manager.getSystemConf())
564 {
565 stream << "Gateway=" << manager.getSystemConf()->defaultGateway()
566 << "\n";
567 }
568
569 // write the route section
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600570 for (const auto& addr : addrs)
571 {
572 if (addr.second->origin() == AddressOrigin::Static)
573 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500574 int addressFamily = addr.second->type() == IP::Protocol::IPv4
575 ? AF_INET
576 : AF_INET6;
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600577
Gunnar Mills57d9c502018-09-14 14:42:34 -0500578 std::string destination =
579 getNetworkID(addressFamily, addr.second->address(),
580 addr.second->prefixLength());
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600581
582 if (addr.second->gateway() != "0.0.0.0" &&
Gunnar Mills57d9c502018-09-14 14:42:34 -0500583 addr.second->gateway() != "" && destination != "0.0.0.0" &&
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600584 destination != "")
585 {
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400586 stream << "[Route]\n";
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600587 stream << "Gateway=" << addr.second->gateway() << "\n";
588 stream << "Destination=" << destination << "\n";
589 }
590 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530591 }
592 }
593
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600594 // Write the dhcp section irrespective of whether DHCP is enabled or not
595 writeDHCPSection(stream);
596
Ratan Gupta2b106532017-07-25 16:05:02 +0530597 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530598}
599
600void EthernetInterface::writeDHCPSection(std::fstream& stream)
601{
602 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530603 // write the dhcp section
604 stream << "[DHCP]\n";
605
606 // Hardcoding the client identifier to mac, to address below issue
607 // https://github.com/openbmc/openbmc/issues/1280
608 stream << "ClientIdentifier=mac\n";
609 if (manager.getDHCPConf())
610 {
611 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
612 stream << "UseDNS="s + value + "\n";
613
614 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
615 stream << "UseNTP="s + value + "\n";
616
617 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
618 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600619
620 value =
621 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
622 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530623 }
624}
625
Ratan Guptabd303b12017-08-18 17:10:07 +0530626std::string EthernetInterface::mACAddress(std::string value)
627{
628 if (!mac_address::validate(value))
629 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500630 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500631 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500632 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
633 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530634 }
635
636 // check whether MAC is broadcast mac.
637 auto intMac = mac_address::internal::convertToInt(value);
638
639 if (!(intMac ^ mac_address::broadcastMac))
640 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500641 log<level::ERR>("MACAddress is a broadcast mac.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500642 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500643 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
644 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530645 }
646
Patrick Ventured475cd62018-02-26 17:07:41 -0800647 // Check if the MAC changed.
648 auto pmac = MacAddressIntf::mACAddress();
649 if (strcasecmp(pmac.c_str(), value.c_str()) == 0)
650 {
651 return MacAddressIntf::mACAddress();
652 }
653
Ratan Guptabd303b12017-08-18 17:10:07 +0530654 // Allow the mac to be set if one of the condition is true.
655 // 1) Incoming Mac is of local admin type.
656 // or
657 // 2) Incoming mac is same as eeprom Mac.
658
659 if (!(intMac & mac_address::localAdminMask))
660 {
661 try
662 {
663 auto inventoryMac = mac_address::getfromInventory(bus);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500664 auto intInventoryMac =
665 mac_address::internal::convertToInt(inventoryMac);
Ratan Guptabd303b12017-08-18 17:10:07 +0530666
667 if (intInventoryMac != intMac)
668 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500669 log<level::ERR>("Given MAC address is neither a local Admin "
Gunnar Mills57d9c502018-09-14 14:42:34 -0500670 "type nor is same as in inventory");
Gunnar Mills90480c42018-06-19 16:02:17 -0500671 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
672 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530673 }
674 }
Gunnar Mills57d9c502018-09-14 14:42:34 -0500675 catch (InternalFailure& e)
Ratan Guptabd303b12017-08-18 17:10:07 +0530676 {
Patrick Venturee0ad43a2017-11-29 18:19:54 -0800677 log<level::ERR>("Exception occurred during getting of MAC "
678 "address from Inventory");
Gunnar Millsce262822018-06-19 16:21:34 -0500679 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530680 }
681 }
682 auto interface = interfaceName();
683 execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
Gunnar Mills57d9c502018-09-14 14:42:34 -0500684 // TODO: would replace below three calls
Ratan Guptabd303b12017-08-18 17:10:07 +0530685 // with restarting of systemd-netwokd
686 // through https://github.com/systemd/systemd/issues/6696
687 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
Gunnar Mills57d9c502018-09-14 14:42:34 -0500688 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
689 "address", value.c_str());
Ratan Guptabd303b12017-08-18 17:10:07 +0530690
691 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
692
693 auto mac = MacAddressIntf::mACAddress(std::move(value));
Gunnar Mills57d9c502018-09-14 14:42:34 -0500694 // update all the vlan interfaces
695 for (const auto& intf : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530696 {
697 intf.second->updateMacAddress();
698 }
Ratan Gupta677ae122017-09-18 16:28:50 +0530699
700 // restart the systemd networkd so that dhcp client gets the
701 // ip for the changed mac address.
702 if (dHCPEnabled())
703 {
Ratan Gupta895f9e52018-11-26 20:57:34 +0530704 manager.restartSystemdUnit(networkdService);
Ratan Gupta677ae122017-09-18 16:28:50 +0530705 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530706 return mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530707}
708
Ratan Guptae9c9b812017-09-22 17:15:37 +0530709void EthernetInterface::deleteAll()
710{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500711 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +0530712 {
713 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500714 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +0530715 }
716
717 // clear all the ip on the interface
718 addrs.clear();
719 manager.writeToConfigurationFile();
720}
721
Gunnar Mills57d9c502018-09-14 14:42:34 -0500722} // namespace network
723} // namespace phosphor