blob: 2c8bbd42b98fad40c60526c06262adf097bdf4ca [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"
William A. Kennington III08505792019-01-30 16:00:04 -08007#include "neighbor.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05308#include "network_manager.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>
William A. Kennington IIId7946a72019-04-19 14:24:09 -070013#include <linux/rtnetlink.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053014#include <linux/sockios.h>
Ratan Gupta2b106532017-07-25 16:05:02 +053015#include <net/if.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053016#include <netinet/in.h>
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <unistd.h>
20
Ratan Gupta82549cc2017-04-21 08:45:23 +053021#include <algorithm>
22#include <experimental/filesystem>
Ratan Gupta2b106532017-07-25 16:05:02 +053023#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070024#include <phosphor-logging/elog-errors.hpp>
25#include <phosphor-logging/log.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053026#include <sstream>
William A. Kennington III12beaad2020-06-13 19:30:41 -070027#include <stdplus/raw.hpp>
Ratan Gupta2b106532017-07-25 16:05:02 +053028#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070029#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070030#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053031
Ratan Gupta91a99cc2017-04-14 16:32:09 +053032namespace phosphor
33{
34namespace network
35{
36
37using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053038using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053039using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
40using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050041using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053042constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
43constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
44constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
45constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
46constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053047
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080048struct EthernetIntfSocket
49{
50 EthernetIntfSocket(int domain, int type, int protocol)
51 {
52 if ((sock = socket(domain, type, protocol)) < 0)
53 {
54 log<level::ERR>("socket creation failed:",
55 entry("ERROR=%s", strerror(errno)));
56 }
57 }
58
59 ~EthernetIntfSocket()
60 {
61 if (sock >= 0)
62 {
63 close(sock);
64 }
65 }
66
67 int sock{-1};
68};
69
Ratan Gupta91a99cc2017-04-14 16:32:09 +053070EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
71 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050072 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053073 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050074 Ifaces(bus, objPath.c_str(), true),
75 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053076{
77 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053078 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053079 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053080 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Johnathan Mantey5b023f52019-06-24 16:06:37 -070081 EthernetInterfaceIntf::iPv6AcceptRA(getIPv6AcceptRAFromConf());
Ratan Gupta99801ce2020-01-09 18:37:16 +053082 // Don't get the mac address from the system as the mac address
83 // would be same as parent interface.
84 if (intfName.find(".") == std::string::npos)
85 {
86 MacAddressIntf::mACAddress(getMACAddress(intfName));
87 }
Ratan Gupta497c0c92017-08-22 19:15:59 +053088 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +053089
90 EthernetInterfaceIntf::linkUp(linkUp());
91 EthernetInterfaceIntf::nICEnabled(nICEnabled());
92
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -080093#if NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -070094 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
95
96 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
97 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -080098#endif
Ratan Gupta6dec390f2017-08-20 15:28:12 +053099
Ratan Gupta29b0e432017-05-25 12:51:40 +0530100 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530101 if (emitSignal)
102 {
103 this->emit_object_added();
104 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530105}
106
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800107static IP::Protocol convertFamily(int family)
108{
109 switch (family)
110 {
111 case AF_INET:
112 return IP::Protocol::IPv4;
113 case AF_INET6:
114 return IP::Protocol::IPv6;
115 }
116
117 throw std::invalid_argument("Bad address family");
118}
119
Ratan Gupta87c13982017-06-15 09:27:27 +0530120void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530121{
Ratan Gupta87c13982017-06-15 09:27:27 +0530122 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530123
Ratan Gupta87c13982017-06-15 09:27:27 +0530124 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530125
Ratan Gupta6a387c12017-08-03 13:26:19 +0530126 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530127 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800128 IP::Protocol addressType = convertFamily(addr.addrType);
129 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +0530130 if (dHCPEnabled())
131 {
132 origin = IP::AddressOrigin::DHCP;
133 }
William A. Kennington III16893802019-01-30 16:01:01 -0800134 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530135 {
136 origin = IP::AddressOrigin::LinkLocal;
137 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700138 // Obsolete parameter
139 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530140
Gunnar Mills57d9c502018-09-14 14:42:34 -0500141 std::string ipAddressObjectPath = generateObjectPath(
142 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530143
Gunnar Mills57d9c502018-09-14 14:42:34 -0500144 this->addrs.emplace(addr.ipaddress,
145 std::make_shared<phosphor::network::IPAddress>(
146 bus, ipAddressObjectPath.c_str(), *this,
147 addressType, addr.ipaddress, origin,
148 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530149 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530150}
151
William A. Kennington III08505792019-01-30 16:00:04 -0800152void EthernetInterface::createStaticNeighborObjects()
153{
154 staticNeighbors.clear();
155
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700156 NeighborFilter filter;
157 filter.interface = ifIndex();
158 filter.state = NUD_PERMANENT;
159 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800160 for (const auto& neighbor : neighbors)
161 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700162 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800163 {
164 continue;
165 }
166 std::string ip = toString(neighbor.address);
167 std::string mac = mac_address::toString(*neighbor.mac);
168 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
169 staticNeighbors.emplace(ip,
170 std::make_shared<phosphor::network::Neighbor>(
171 bus, objectPath.c_str(), *this, ip, mac,
172 Neighbor::State::Permanent));
173 }
174}
175
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700176unsigned EthernetInterface::ifIndex() const
177{
178 unsigned idx = if_nametoindex(interfaceName().c_str());
179 if (idx == 0)
180 {
181 throw std::system_error(errno, std::generic_category(),
182 "if_nametoindex");
183 }
184 return idx;
185}
186
raviteja-bce379562019-03-28 05:59:36 -0500187ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
188 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530189{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530190
191 if (dHCPEnabled())
192 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530193 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500194 entry("INTERFACE=%s", interfaceName().c_str());
195 dHCPEnabled(false);
196 }
197
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500198 IP::AddressOrigin origin = IP::AddressOrigin::Static;
199
200 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
201
202 if (!isValidIP(addressFamily, ipaddress))
203 {
204 log<level::ERR>("Not a valid IP address"),
205 entry("ADDRESS=%s", ipaddress.c_str());
206 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
207 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
208 }
209
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700210 // Gateway is an obsolete parameter
211 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500212
213 if (!isValidPrefix(addressFamily, prefixLength))
214 {
215 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700216 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500217 elog<InvalidArgument>(
218 Argument::ARGUMENT_NAME("prefixLength"),
219 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530220 }
221
Gunnar Mills57d9c502018-09-14 14:42:34 -0500222 std::string objectPath =
223 generateObjectPath(protType, ipaddress, prefixLength, gateway);
224 this->addrs.emplace(ipaddress,
225 std::make_shared<phosphor::network::IPAddress>(
226 bus, objectPath.c_str(), *this, protType, ipaddress,
227 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530228
Ratan Guptae05083a2017-09-16 07:12:11 +0530229 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500230 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530231}
232
William A. Kennington III08505792019-01-30 16:00:04 -0800233ObjectPath EthernetInterface::neighbor(std::string iPAddress,
234 std::string mACAddress)
235{
236 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
237 {
238 log<level::ERR>("Not a valid IP address",
239 entry("ADDRESS=%s", iPAddress.c_str()));
240 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
241 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
242 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700243 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800244 {
245 log<level::ERR>("Not a valid MAC address",
246 entry("MACADDRESS=%s", iPAddress.c_str()));
247 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
248 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
249 }
250
251 std::string objectPath =
252 generateStaticNeighborObjectPath(iPAddress, mACAddress);
253 staticNeighbors.emplace(iPAddress,
254 std::make_shared<phosphor::network::Neighbor>(
255 bus, objectPath.c_str(), *this, iPAddress,
256 mACAddress, Neighbor::State::Permanent));
257 manager.writeToConfigurationFile();
258 return objectPath;
259}
260
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800261#if NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530262/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800263 Enable this code if your NIC driver supports the ETHTOOL features.
264 Do this by adding the following to your phosphor-network*.bbappend file.
265 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
266 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530267*/
268InterfaceInfo EthernetInterface::getInterfaceInfo() const
269{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400270 ifreq ifr{0};
271 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500272 LinkSpeed speed{0};
273 Autoneg autoneg{0};
274 DuplexMode duplex{0};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800275 LinkUp linkState{false};
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700276 NICEnabled nicEnabled{false};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800277 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
278
279 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530280 {
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700281 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800282 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530283
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800284 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
285 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530286
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800287 edata.cmd = ETHTOOL_GSET;
288 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
289 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530290 speed = edata.speed;
291 duplex = edata.duplex;
292 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530293 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800294
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700295 nicEnabled = nICEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800296 linkState = linkUp();
297
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700298 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530299}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800300#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530301
302/** @brief get the mac address of the interface.
303 * @return macaddress on success
304 */
305
Gunnar Mills57d9c502018-09-14 14:42:34 -0500306std::string
307 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530308{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800309 std::string activeMACAddr = MacAddressIntf::mACAddress();
310 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
311
312 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530313 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800314 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530315 }
316
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800317 ifreq ifr{0};
318 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
319 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530320 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530321 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500322 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700323 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530324 }
325
William A. Kennington III1137a972019-04-20 20:49:58 -0700326 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
327 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
328 sizeof(ifr.ifr_hwaddr.sa_data));
William A. Kennington III12beaad2020-06-13 19:30:41 -0700329 return mac_address::toString(stdplus::raw::copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530330}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530331
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530332std::string EthernetInterface::generateId(const std::string& ipaddress,
333 uint8_t prefixLength,
334 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530335{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530336 std::stringstream hexId;
337 std::string hashString = ipaddress;
338 hashString += std::to_string(prefixLength);
339 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530340
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530341 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500342 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530343 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530344}
345
William A. Kennington III08505792019-01-30 16:00:04 -0800346std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
347 const std::string& mACAddress)
348{
349 std::stringstream hexId;
350 std::string hashString = iPAddress + mACAddress;
351
352 // Only want 8 hex digits.
353 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
354 return hexId.str();
355}
356
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530357void EthernetInterface::deleteObject(const std::string& ipaddress)
358{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530359 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530360 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530361 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530362 log<level::ERR>("DeleteObject:Unable to find the object.");
363 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530364 }
365 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530366 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530367}
368
William A. Kennington III08505792019-01-30 16:00:04 -0800369void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
370{
371 auto it = staticNeighbors.find(iPAddress);
372 if (it == staticNeighbors.end())
373 {
374 log<level::ERR>(
375 "DeleteStaticNeighborObject:Unable to find the object.");
376 return;
377 }
378 staticNeighbors.erase(it);
379 manager.writeToConfigurationFile();
380}
381
Ratan Guptae9c9b812017-09-22 17:15:37 +0530382void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530383{
Ratan Guptabc886292017-07-25 18:29:57 +0530384 auto confDir = manager.getConfDir();
385 fs::path networkFile = confDir;
386 networkFile /= systemd::config::networkFilePrefix + interface +
387 systemd::config::networkFileSuffix;
388
389 fs::path deviceFile = confDir;
390 deviceFile /= interface + systemd::config::deviceFileSuffix;
391
392 // delete the vlan network file
393 if (fs::is_regular_file(networkFile))
394 {
395 fs::remove(networkFile);
396 }
397
398 // delete the vlan device file
399 if (fs::is_regular_file(deviceFile))
400 {
401 fs::remove(deviceFile);
402 }
Ratan Guptabc886292017-07-25 18:29:57 +0530403
404 // TODO systemd doesn't delete the virtual network interface
405 // even after deleting all the related configuartion.
406 // https://github.com/systemd/systemd/issues/6600
407 try
408 {
409 deleteInterface(interface);
410 }
411 catch (InternalFailure& e)
412 {
413 commit<InternalFailure>();
414 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530415}
416
417void EthernetInterface::deleteVLANObject(const std::string& interface)
418{
419 auto it = vlanInterfaces.find(interface);
420 if (it == vlanInterfaces.end())
421 {
422 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500423 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530424 return;
425 }
426
427 deleteVLANFromSystem(interface);
428 // delete the interface
429 vlanInterfaces.erase(it);
430
Ratan Guptae05083a2017-09-16 07:12:11 +0530431 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530432}
433
Gunnar Mills57d9c502018-09-14 14:42:34 -0500434std::string EthernetInterface::generateObjectPath(
435 IP::Protocol addressType, const std::string& ipaddress,
436 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530437{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530438 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530439 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530440 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
441
442 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530443 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530444 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530445 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530446 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530447}
448
William A. Kennington III08505792019-01-30 16:00:04 -0800449std::string EthernetInterface::generateStaticNeighborObjectPath(
450 const std::string& iPAddress, const std::string& mACAddress) const
451{
452 std::experimental::filesystem::path objectPath;
453 objectPath /= objPath;
454 objectPath /= "static_neighbor";
455 objectPath /= generateNeighborId(iPAddress, mACAddress);
456 return objectPath.string();
457}
458
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700459bool EthernetInterface::iPv6AcceptRA(bool value)
460{
461 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
462 {
463 return value;
464 }
465 EthernetInterfaceIntf::iPv6AcceptRA(value);
466 manager.writeToConfigurationFile();
467 return value;
468}
469
Ratan Gupta87c13982017-06-15 09:27:27 +0530470bool EthernetInterface::dHCPEnabled(bool value)
471{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530472 if (value == EthernetInterfaceIntf::dHCPEnabled())
473 {
474 return value;
475 }
476
Ratan Gupta87c13982017-06-15 09:27:27 +0530477 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530478 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530479 return value;
480}
481
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800482bool EthernetInterface::linkUp() const
483{
484 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
485 bool value = EthernetInterfaceIntf::linkUp();
486
487 if (eifSocket.sock < 0)
488 {
489 return value;
490 }
491
492 ifreq ifr{0};
493 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
494 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
495 {
496 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
497 }
498 else
499 {
500 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
501 entry("ERROR=%s", strerror(errno)));
502 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700503 return value;
504}
505
506bool EthernetInterface::nICEnabled() const
507{
508 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
509 bool value = EthernetInterfaceIntf::nICEnabled();
510
511 if (eifSocket.sock < 0)
512 {
513 return value;
514 }
515
516 ifreq ifr{0};
517 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
518 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
519 {
520 value = static_cast<bool>(ifr.ifr_flags & IFF_UP);
521 }
522 else
523 {
524 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
525 entry("ERROR=%s", strerror(errno)));
526 }
527 return value;
528}
529
530bool EthernetInterface::nICEnabled(bool value)
531{
532 if (value == EthernetInterfaceIntf::nICEnabled())
533 {
534 return value;
535 }
536
537 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
538 if (eifSocket.sock < 0)
539 {
540 return EthernetInterfaceIntf::nICEnabled();
541 }
542
543 ifreq ifr{0};
544 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
545 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) != 0)
546 {
547 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
548 entry("ERROR=%s", strerror(errno)));
549 return EthernetInterfaceIntf::nICEnabled();
550 }
551
552 ifr.ifr_flags &= ~IFF_UP;
553 ifr.ifr_flags |= value ? IFF_UP : 0;
554
555 if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
556 {
557 log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
558 entry("ERROR=%s", strerror(errno)));
559 return EthernetInterfaceIntf::nICEnabled();
560 }
561 EthernetInterfaceIntf::nICEnabled(value);
562 writeConfigurationFile();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800563
564 return value;
565}
566
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530567ServerList EthernetInterface::nameservers(ServerList value)
568{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530569 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
570 return EthernetInterfaceIntf::nameservers();
571}
572
573ServerList EthernetInterface::staticNameServers(ServerList value)
574{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530575 for (const auto& nameserverip : value)
576 {
577 if (!isValidIP(AF_INET, nameserverip) &&
578 !isValidIP(AF_INET6, nameserverip))
579 {
580 log<level::ERR>("Not a valid IP address"),
581 entry("ADDRESS=%s", nameserverip.c_str());
582 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530583 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530584 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
585 }
586 }
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530587 try
588 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530589 EthernetInterfaceIntf::staticNameServers(value);
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530590 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530591 // resolved reads the DNS server configuration from the
592 // network file.
593 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530594 }
595 catch (InternalFailure& e)
596 {
597 log<level::ERR>("Exception processing DNS entries");
598 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530599 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530600}
601
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530602void EthernetInterface::loadNameServers()
603{
604 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
605 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
606}
607
608ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530609{
610 fs::path confPath = manager.getConfDir();
611
612 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500613 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530614 confPath /= fileName;
615 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530616 config::Parser parser(confPath.string());
617 auto rc = config::ReturnCode::SUCCESS;
618
619 std::tie(rc, servers) = parser.getValues("Network", "DNS");
620 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530621 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530622 log<level::DEBUG>("Unable to get the value for network[DNS]",
623 entry("RC=%d", rc));
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530624 }
625 return servers;
626}
627
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530628ServerList EthernetInterface::getNameServerFromResolvd()
629{
630 ServerList servers;
631 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
632
633 /*
634 The DNS property under org.freedesktop.resolve1.Link interface contains
635 an array containing all DNS servers currently used by resolved. It
636 contains similar information as the DNS server data written to
637 /run/systemd/resolve/resolv.conf.
638
639 Each structure in the array consists of a numeric network interface index,
640 an address family, and a byte array containing the DNS server address
641 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
642 The array contains DNS servers configured system-wide, including those
643 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
644 /etc/systemd/resolved.conf, as well as per-interface DNS server
645 information either retrieved from systemd-networkd or configured by
646 external software via SetLinkDNS().
647 */
648
649 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
650 std::variant<type> name; // Variable to capture the DNS property
651 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
652 PROPERTY_INTERFACE, METHOD_GET);
653
654 method.append(RESOLVED_INTERFACE, "DNS");
655 auto reply = bus.call(method);
656
657 try
658 {
659 reply.read(name);
660 }
661 catch (const sdbusplus::exception::SdBusError& e)
662 {
663 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
664 }
665 auto tupleVector = std::get_if<type>(&name);
666 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
667 {
668 std::vector<uint8_t> ipaddress = std::get<1>(*i);
669 std::string address;
670 for (auto byte : ipaddress)
671 {
672 address += std::to_string(byte) + ".";
673 }
674 address.pop_back();
675 servers.push_back(address);
676 }
677 return servers;
678}
679
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530680void EthernetInterface::loadVLAN(VlanId id)
681{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500682 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530683 std::string path = objPath;
684 path += "_" + std::to_string(id);
685
Gunnar Mills57d9c502018-09-14 14:42:34 -0500686 auto dhcpEnabled =
687 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530688
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530689 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500690 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530691
Gunnar Mills57d9c502018-09-14 14:42:34 -0500692 // Fetch the ip address from the system
693 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530694 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800695 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530696
697 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
698 std::move(vlanIntf));
699}
700
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700701ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530702{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500703 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530704 std::string path = objPath;
705 path += "_" + std::to_string(id);
706
Ratan Gupta5978dd12017-07-25 13:47:13 +0530707 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500708 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530709
710 // write the device file for the vlan interface.
711 vlanIntf->writeDeviceFile();
712
Gunnar Mills57d9c502018-09-14 14:42:34 -0500713 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530714 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530715 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700716
717 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530718}
Ratan Gupta2b106532017-07-25 16:05:02 +0530719
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700720bool EthernetInterface::getIPv6AcceptRAFromConf()
721{
722 fs::path confPath = manager.getConfDir();
723
724 std::string fileName = systemd::config::networkFilePrefix +
725 interfaceName() + systemd::config::networkFileSuffix;
726 confPath /= fileName;
727 config::ValueList values;
728 config::Parser parser(confPath.string());
729 auto rc = config::ReturnCode::SUCCESS;
730 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
731 if (rc != config::ReturnCode::SUCCESS)
732 {
733 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
734 entry("rc=%d", rc));
735 return false;
736 }
737 return (values[0] == "true");
738}
739
Ratan Gupta497c0c92017-08-22 19:15:59 +0530740ServerList EthernetInterface::getNTPServersFromConf()
741{
742 fs::path confPath = manager.getConfDir();
743
Gunnar Mills57d9c502018-09-14 14:42:34 -0500744 std::string fileName = systemd::config::networkFilePrefix +
745 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530746 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530747
Ratan Gupta497c0c92017-08-22 19:15:59 +0530748 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530749 config::Parser parser(confPath.string());
750 auto rc = config::ReturnCode::SUCCESS;
751
752 std::tie(rc, servers) = parser.getValues("Network", "NTP");
753 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530754 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530755 log<level::DEBUG>("Unable to get the value for Network[NTP]",
756 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530757 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530758
Ratan Gupta497c0c92017-08-22 19:15:59 +0530759 return servers;
760}
761
762ServerList EthernetInterface::nTPServers(ServerList servers)
763{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500764 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530765
766 writeConfigurationFile();
767 // timesynchd reads the NTP server configuration from the
768 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530769 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530770 return ntpServers;
771}
Ratan Gupta2b106532017-07-25 16:05:02 +0530772// Need to merge the below function with the code which writes the
773// config file during factory reset.
774// TODO openbmc/openbmc#1751
775
776void EthernetInterface::writeConfigurationFile()
777{
778 // write all the static ip address in the systemd-network conf file
779
780 using namespace std::string_literals;
781 using AddressOrigin =
782 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
783 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530784
785 // if there is vlan interafce then write the configuration file
786 // for vlan also.
787
Gunnar Mills57d9c502018-09-14 14:42:34 -0500788 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530789 {
790 intf.second->writeConfigurationFile();
791 }
792
Ratan Gupta2b106532017-07-25 16:05:02 +0530793 fs::path confPath = manager.getConfDir();
794
Gunnar Mills57d9c502018-09-14 14:42:34 -0500795 std::string fileName = systemd::config::networkFilePrefix +
796 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530797 confPath /= fileName;
798 std::fstream stream;
799
800 stream.open(confPath.c_str(), std::fstream::out);
801 if (!stream.is_open())
802 {
803 log<level::ERR>("Unable to open the file",
804 entry("FILE=%s", confPath.c_str()));
805 elog<InternalFailure>();
806 }
807
808 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400809 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530810 stream << "Name=" << interfaceName() << "\n";
811
812 auto addrs = getAddresses();
813
William A. Kennington III15787212019-04-23 19:18:01 -0700814 // Write the link section
815 stream << "[Link]\n";
816 auto mac = MacAddressIntf::mACAddress();
817 if (!mac.empty())
818 {
819 stream << "MACAddress=" << mac << "\n";
820 }
821
Ratan Gupta40a51df2020-04-24 15:11:05 +0530822 if (!EthernetInterfaceIntf::nICEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700823 {
824 stream << "Unmanaged=yes\n";
825 }
826
Ratan Gupta2b106532017-07-25 16:05:02 +0530827 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400828 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400829#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500830 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400831#else
832 stream << "LinkLocalAddressing=no\n";
833#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700834 stream << std::boolalpha
835 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530836
837 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500838 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530839 {
840 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500841 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530842 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530843 // Add the NTP server
844 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
845 {
846 stream << "NTP=" << ntp << "\n";
847 }
848
849 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530850 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530851 {
852 stream << "DNS=" << dns << "\n";
853 }
854
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500855 // Add the DHCP entry
856 auto value = dHCPEnabled() ? "true"s : "false"s;
857 stream << "DHCP="s + value + "\n";
858
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600859 // When the interface configured as dhcp, we don't need below given entries
860 // in config file.
861 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530862 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600863 // Static
864 for (const auto& addr : addrs)
865 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400866 if (addr.second->origin() == AddressOrigin::Static
867#ifndef LINK_LOCAL_AUTOCONFIGURATION
868 || addr.second->origin() == AddressOrigin::LinkLocal
869#endif
870 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530871 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500872 std::string address =
873 addr.second->address() + "/" +
874 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530875
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600876 stream << "Address=" << address << "\n";
877 }
878 }
879
880 if (manager.getSystemConf())
881 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800882 const auto& gateway = manager.getSystemConf()->defaultGateway();
883 if (!gateway.empty())
884 {
885 stream << "Gateway=" << gateway << "\n";
886 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800887 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
888 if (!gateway6.empty())
889 {
890 stream << "Gateway=" << gateway6 << "\n";
891 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600892 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530893 }
894
William A. Kennington III08505792019-01-30 16:00:04 -0800895 // Write the neighbor sections
896 for (const auto& neighbor : staticNeighbors)
897 {
898 stream << "[Neighbor]"
899 << "\n";
900 stream << "Address=" << neighbor.second->iPAddress() << "\n";
901 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
902 }
903
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600904 // Write the dhcp section irrespective of whether DHCP is enabled or not
905 writeDHCPSection(stream);
906
Ratan Gupta2b106532017-07-25 16:05:02 +0530907 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530908}
909
910void EthernetInterface::writeDHCPSection(std::fstream& stream)
911{
912 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530913 // write the dhcp section
914 stream << "[DHCP]\n";
915
916 // Hardcoding the client identifier to mac, to address below issue
917 // https://github.com/openbmc/openbmc/issues/1280
918 stream << "ClientIdentifier=mac\n";
919 if (manager.getDHCPConf())
920 {
921 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
922 stream << "UseDNS="s + value + "\n";
923
924 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
925 stream << "UseNTP="s + value + "\n";
926
927 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
928 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600929
930 value =
931 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
932 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530933 }
934}
935
Ratan Guptabd303b12017-08-18 17:10:07 +0530936std::string EthernetInterface::mACAddress(std::string value)
937{
William A. Kennington III1137a972019-04-20 20:49:58 -0700938 ether_addr newMAC = mac_address::fromString(value);
939 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530940 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500941 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500942 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500943 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
944 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530945 }
946
William A. Kennington III1137a972019-04-20 20:49:58 -0700947 // We don't need to update the system if the address is unchanged
948 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -0700949 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530950 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700951 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530952 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700953 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530954 {
Alvin Wang38a63c32019-08-29 22:56:46 +0800955 auto inventoryMAC =
956 mac_address::getfromInventory(bus, interfaceName());
William A. Kennington III12beaad2020-06-13 19:30:41 -0700957 if (!stdplus::raw::equal(newMAC, inventoryMAC))
William A. Kennington III1137a972019-04-20 20:49:58 -0700958 {
959 log<level::ERR>(
960 "Given MAC address is neither a local Admin "
961 "type nor is same as in inventory");
962 elog<InvalidArgument>(
963 Argument::ARGUMENT_NAME("MACAddress"),
964 Argument::ARGUMENT_VALUE(value.c_str()));
965 }
966 }
967 catch (const std::exception& e)
968 {
969 log<level::ERR>("Exception occurred during getting of MAC "
970 "address from Inventory");
971 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530972 }
973 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700974
975 // Update everything that depends on the MAC value
976 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530977 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700978 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530979 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700980 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530981
William A. Kennington III1137a972019-04-20 20:49:58 -0700982 auto interface = interfaceName();
Benjamin Fair06345732020-04-15 16:06:32 -0700983
984#ifdef HAVE_UBOOT_ENV
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700985 auto envVar = interfaceToUbootEthAddr(interface.c_str());
986 if (envVar)
987 {
988 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
989 value.c_str());
990 }
Benjamin Fair06345732020-04-15 16:06:32 -0700991#endif // HAVE_UBOOT_ENV
992
William A. Kennington III15787212019-04-23 19:18:01 -0700993 // TODO: would remove the call below and
994 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -0700995 // through https://github.com/systemd/systemd/issues/6696
996 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
997 "down");
William A. Kennington III15787212019-04-23 19:18:01 -0700998 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +0530999 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001000
1001 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301002}
1003
Ratan Guptae9c9b812017-09-22 17:15:37 +05301004void EthernetInterface::deleteAll()
1005{
Gunnar Mills57d9c502018-09-14 14:42:34 -05001006 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +05301007 {
1008 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001009 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301010 }
1011
1012 // clear all the ip on the interface
1013 addrs.clear();
1014 manager.writeToConfigurationFile();
1015}
1016
Gunnar Mills57d9c502018-09-14 14:42:34 -05001017} // namespace network
1018} // namespace phosphor