blob: d7e0baa0ee0fe986045e1c368399e9f125fd1240 [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>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053022#include <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
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530442 std::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{
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530452 std::filesystem::path objectPath;
William A. Kennington III08505792019-01-30 16:00:04 -0800453 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
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530567ServerList EthernetInterface::nameservers(ServerList /*value*/)
Ratan Gupta6dec390f2017-08-20 15:28:12 +0530568{
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 Gupta92bc2fe2017-07-26 22:40:21 +0530688 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500689 bus, path.c_str(), dhcpEnabled, id, *this, manager);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530690
Gunnar Mills57d9c502018-09-14 14:42:34 -0500691 // Fetch the ip address from the system
692 // and create the dbus object.
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530693 vlanIntf->createIPAddressObjects();
William A. Kennington III08505792019-01-30 16:00:04 -0800694 vlanIntf->createStaticNeighborObjects();
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530695
696 this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
697 std::move(vlanIntf));
698}
699
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700700ObjectPath EthernetInterface::createVLAN(VlanId id)
Ratan Gupta5978dd12017-07-25 13:47:13 +0530701{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500702 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530703 std::string path = objPath;
704 path += "_" + std::to_string(id);
705
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530706 // Pass the parents nICEnabled property, so that the child
707 // VLAN interface can inherit.
708
Ratan Gupta5978dd12017-07-25 13:47:13 +0530709 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Manojkiran Edaca8b91b2020-05-28 09:28:42 +0530710 bus, path.c_str(), false, EthernetInterfaceIntf::nICEnabled(), id,
711 *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530712
713 // write the device file for the vlan interface.
714 vlanIntf->writeDeviceFile();
715
Gunnar Mills57d9c502018-09-14 14:42:34 -0500716 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530717 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530718 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700719
720 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530721}
Ratan Gupta2b106532017-07-25 16:05:02 +0530722
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700723bool EthernetInterface::getIPv6AcceptRAFromConf()
724{
725 fs::path confPath = manager.getConfDir();
726
727 std::string fileName = systemd::config::networkFilePrefix +
728 interfaceName() + systemd::config::networkFileSuffix;
729 confPath /= fileName;
730 config::ValueList values;
731 config::Parser parser(confPath.string());
732 auto rc = config::ReturnCode::SUCCESS;
733 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
734 if (rc != config::ReturnCode::SUCCESS)
735 {
736 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
737 entry("rc=%d", rc));
738 return false;
739 }
740 return (values[0] == "true");
741}
742
Ratan Gupta497c0c92017-08-22 19:15:59 +0530743ServerList EthernetInterface::getNTPServersFromConf()
744{
745 fs::path confPath = manager.getConfDir();
746
Gunnar Mills57d9c502018-09-14 14:42:34 -0500747 std::string fileName = systemd::config::networkFilePrefix +
748 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530749 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530750
Ratan Gupta497c0c92017-08-22 19:15:59 +0530751 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530752 config::Parser parser(confPath.string());
753 auto rc = config::ReturnCode::SUCCESS;
754
755 std::tie(rc, servers) = parser.getValues("Network", "NTP");
756 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530757 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530758 log<level::DEBUG>("Unable to get the value for Network[NTP]",
759 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530760 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530761
Ratan Gupta497c0c92017-08-22 19:15:59 +0530762 return servers;
763}
764
765ServerList EthernetInterface::nTPServers(ServerList servers)
766{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500767 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530768
769 writeConfigurationFile();
770 // timesynchd reads the NTP server configuration from the
771 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530772 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530773 return ntpServers;
774}
Ratan Gupta2b106532017-07-25 16:05:02 +0530775// Need to merge the below function with the code which writes the
776// config file during factory reset.
777// TODO openbmc/openbmc#1751
778
779void EthernetInterface::writeConfigurationFile()
780{
781 // write all the static ip address in the systemd-network conf file
782
783 using namespace std::string_literals;
784 using AddressOrigin =
785 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
Manojkiran Edaa879baa2020-06-13 14:39:08 +0530786 namespace fs = std::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530787
788 // if there is vlan interafce then write the configuration file
789 // for vlan also.
790
Gunnar Mills57d9c502018-09-14 14:42:34 -0500791 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530792 {
793 intf.second->writeConfigurationFile();
794 }
795
Ratan Gupta2b106532017-07-25 16:05:02 +0530796 fs::path confPath = manager.getConfDir();
797
Gunnar Mills57d9c502018-09-14 14:42:34 -0500798 std::string fileName = systemd::config::networkFilePrefix +
799 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530800 confPath /= fileName;
801 std::fstream stream;
802
803 stream.open(confPath.c_str(), std::fstream::out);
804 if (!stream.is_open())
805 {
806 log<level::ERR>("Unable to open the file",
807 entry("FILE=%s", confPath.c_str()));
808 elog<InternalFailure>();
809 }
810
811 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400812 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530813 stream << "Name=" << interfaceName() << "\n";
814
815 auto addrs = getAddresses();
816
William A. Kennington III15787212019-04-23 19:18:01 -0700817 // Write the link section
818 stream << "[Link]\n";
819 auto mac = MacAddressIntf::mACAddress();
820 if (!mac.empty())
821 {
822 stream << "MACAddress=" << mac << "\n";
823 }
824
Ratan Gupta40a51df2020-04-24 15:11:05 +0530825 if (!EthernetInterfaceIntf::nICEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700826 {
827 stream << "Unmanaged=yes\n";
828 }
829
Ratan Gupta2b106532017-07-25 16:05:02 +0530830 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400831 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400832#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500833 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400834#else
835 stream << "LinkLocalAddressing=no\n";
836#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700837 stream << std::boolalpha
838 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530839
840 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500841 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530842 {
843 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500844 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530845 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530846 // Add the NTP server
847 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
848 {
849 stream << "NTP=" << ntp << "\n";
850 }
851
852 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530853 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530854 {
855 stream << "DNS=" << dns << "\n";
856 }
857
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500858 // Add the DHCP entry
859 auto value = dHCPEnabled() ? "true"s : "false"s;
860 stream << "DHCP="s + value + "\n";
861
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600862 // When the interface configured as dhcp, we don't need below given entries
863 // in config file.
864 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530865 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600866 // Static
867 for (const auto& addr : addrs)
868 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400869 if (addr.second->origin() == AddressOrigin::Static
870#ifndef LINK_LOCAL_AUTOCONFIGURATION
871 || addr.second->origin() == AddressOrigin::LinkLocal
872#endif
873 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530874 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500875 std::string address =
876 addr.second->address() + "/" +
877 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530878
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600879 stream << "Address=" << address << "\n";
880 }
881 }
882
883 if (manager.getSystemConf())
884 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800885 const auto& gateway = manager.getSystemConf()->defaultGateway();
886 if (!gateway.empty())
887 {
888 stream << "Gateway=" << gateway << "\n";
889 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800890 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
891 if (!gateway6.empty())
892 {
893 stream << "Gateway=" << gateway6 << "\n";
894 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600895 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530896 }
897
William A. Kennington III08505792019-01-30 16:00:04 -0800898 // Write the neighbor sections
899 for (const auto& neighbor : staticNeighbors)
900 {
901 stream << "[Neighbor]"
902 << "\n";
903 stream << "Address=" << neighbor.second->iPAddress() << "\n";
904 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
905 }
906
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600907 // Write the dhcp section irrespective of whether DHCP is enabled or not
908 writeDHCPSection(stream);
909
Ratan Gupta2b106532017-07-25 16:05:02 +0530910 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530911}
912
913void EthernetInterface::writeDHCPSection(std::fstream& stream)
914{
915 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530916 // write the dhcp section
917 stream << "[DHCP]\n";
918
919 // Hardcoding the client identifier to mac, to address below issue
920 // https://github.com/openbmc/openbmc/issues/1280
921 stream << "ClientIdentifier=mac\n";
922 if (manager.getDHCPConf())
923 {
924 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
925 stream << "UseDNS="s + value + "\n";
926
927 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
928 stream << "UseNTP="s + value + "\n";
929
930 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
931 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600932
933 value =
934 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
935 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530936 }
937}
938
Ratan Guptabd303b12017-08-18 17:10:07 +0530939std::string EthernetInterface::mACAddress(std::string value)
940{
William A. Kennington III1137a972019-04-20 20:49:58 -0700941 ether_addr newMAC = mac_address::fromString(value);
942 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530943 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500944 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500945 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500946 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
947 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530948 }
949
William A. Kennington III1137a972019-04-20 20:49:58 -0700950 // We don't need to update the system if the address is unchanged
951 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
William A. Kennington III12beaad2020-06-13 19:30:41 -0700952 if (!stdplus::raw::equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530953 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700954 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530955 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700956 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530957 {
Alvin Wang38a63c32019-08-29 22:56:46 +0800958 auto inventoryMAC =
959 mac_address::getfromInventory(bus, interfaceName());
William A. Kennington III12beaad2020-06-13 19:30:41 -0700960 if (!stdplus::raw::equal(newMAC, inventoryMAC))
William A. Kennington III1137a972019-04-20 20:49:58 -0700961 {
962 log<level::ERR>(
963 "Given MAC address is neither a local Admin "
964 "type nor is same as in inventory");
965 elog<InvalidArgument>(
966 Argument::ARGUMENT_NAME("MACAddress"),
967 Argument::ARGUMENT_VALUE(value.c_str()));
968 }
969 }
970 catch (const std::exception& e)
971 {
972 log<level::ERR>("Exception occurred during getting of MAC "
973 "address from Inventory");
974 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530975 }
976 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700977
978 // Update everything that depends on the MAC value
979 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530980 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700981 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530982 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700983 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530984
William A. Kennington III1137a972019-04-20 20:49:58 -0700985 auto interface = interfaceName();
Benjamin Fair06345732020-04-15 16:06:32 -0700986
987#ifdef HAVE_UBOOT_ENV
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700988 auto envVar = interfaceToUbootEthAddr(interface.c_str());
989 if (envVar)
990 {
991 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
992 value.c_str());
993 }
Benjamin Fair06345732020-04-15 16:06:32 -0700994#endif // HAVE_UBOOT_ENV
995
William A. Kennington III15787212019-04-23 19:18:01 -0700996 // TODO: would remove the call below and
997 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -0700998 // through https://github.com/systemd/systemd/issues/6696
999 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
1000 "down");
William A. Kennington III15787212019-04-23 19:18:01 -07001001 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +05301002 }
William A. Kennington III1137a972019-04-20 20:49:58 -07001003
1004 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301005}
1006
Ratan Guptae9c9b812017-09-22 17:15:37 +05301007void EthernetInterface::deleteAll()
1008{
Gunnar Mills57d9c502018-09-14 14:42:34 -05001009 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +05301010 {
1011 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001012 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301013 }
1014
1015 // clear all the ip on the interface
1016 addrs.clear();
1017 manager.writeToConfigurationFile();
1018}
1019
Gunnar Mills57d9c502018-09-14 14:42:34 -05001020} // namespace network
1021} // namespace phosphor