blob: f7343adcfbf546a3cd6afc3a6d346abfcfa3ffad [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>
27#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070028#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070029#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta82549cc2017-04-21 08:45:23 +053030
Ratan Gupta91a99cc2017-04-14 16:32:09 +053031namespace phosphor
32{
33namespace network
34{
35
36using namespace phosphor::logging;
Ratan Gupta2b106532017-07-25 16:05:02 +053037using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053038using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
39using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -050040using Argument = xyz::openbmc_project::Common::InvalidArgument;
Manojkiran Edaacd6dd52019-10-15 15:00:51 +053041constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
42constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
43constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
44constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
45constexpr auto METHOD_GET = "Get";
Ratan Gupta2b106532017-07-25 16:05:02 +053046
Johnathan Manteyfaa72e52020-01-08 10:38:58 -080047struct EthernetIntfSocket
48{
49 EthernetIntfSocket(int domain, int type, int protocol)
50 {
51 if ((sock = socket(domain, type, protocol)) < 0)
52 {
53 log<level::ERR>("socket creation failed:",
54 entry("ERROR=%s", strerror(errno)));
55 }
56 }
57
58 ~EthernetIntfSocket()
59 {
60 if (sock >= 0)
61 {
62 close(sock);
63 }
64 }
65
66 int sock{-1};
67};
68
Ratan Gupta91a99cc2017-04-14 16:32:09 +053069EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
70 const std::string& objPath,
Gunnar Mills57d9c502018-09-14 14:42:34 -050071 bool dhcpEnabled, Manager& parent,
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +053072 bool emitSignal) :
Gunnar Mills57d9c502018-09-14 14:42:34 -050073 Ifaces(bus, objPath.c_str(), true),
74 bus(bus), manager(parent), objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053075{
76 auto intfName = objPath.substr(objPath.rfind("/") + 1);
Ratan Gupta5978dd12017-07-25 13:47:13 +053077 std::replace(intfName.begin(), intfName.end(), '_', '.');
Ratan Gupta91a99cc2017-04-14 16:32:09 +053078 interfaceName(intfName);
Ratan Guptac35481d2017-08-18 06:12:26 +053079 EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
Johnathan Mantey5b023f52019-06-24 16:06:37 -070080 EthernetInterfaceIntf::iPv6AcceptRA(getIPv6AcceptRAFromConf());
Ratan Gupta99801ce2020-01-09 18:37:16 +053081 // Don't get the mac address from the system as the mac address
82 // would be same as parent interface.
83 if (intfName.find(".") == std::string::npos)
84 {
85 MacAddressIntf::mACAddress(getMACAddress(intfName));
86 }
Ratan Gupta497c0c92017-08-22 19:15:59 +053087 EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
Ratan Gupta613a0122020-04-24 15:18:53 +053088
89 EthernetInterfaceIntf::linkUp(linkUp());
90 EthernetInterfaceIntf::nICEnabled(nICEnabled());
91
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -080092#if NIC_SUPPORTS_ETHTOOL
Johnathan Manteycb42fe22019-08-01 13:35:29 -070093 InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
94
95 EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
96 EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -080097#endif
Ratan Gupta6dec3902017-08-20 15:28:12 +053098
Ratan Gupta29b0e432017-05-25 12:51:40 +053099 // Emit deferred signal.
Ratan Gupta3d3e4fc2017-07-25 13:38:19 +0530100 if (emitSignal)
101 {
102 this->emit_object_added();
103 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530104}
105
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800106static IP::Protocol convertFamily(int family)
107{
108 switch (family)
109 {
110 case AF_INET:
111 return IP::Protocol::IPv4;
112 case AF_INET6:
113 return IP::Protocol::IPv6;
114 }
115
116 throw std::invalid_argument("Bad address family");
117}
118
Ratan Gupta87c13982017-06-15 09:27:27 +0530119void EthernetInterface::createIPAddressObjects()
Ratan Gupta29b0e432017-05-25 12:51:40 +0530120{
Ratan Gupta87c13982017-06-15 09:27:27 +0530121 addrs.clear();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530122
Ratan Gupta87c13982017-06-15 09:27:27 +0530123 auto addrs = getInterfaceAddrs()[interfaceName()];
Ratan Gupta5978dd12017-07-25 13:47:13 +0530124
Ratan Gupta6a387c12017-08-03 13:26:19 +0530125 for (auto& addr : addrs)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530126 {
William A. Kennington IIIfbafa252018-11-30 16:53:52 -0800127 IP::Protocol addressType = convertFamily(addr.addrType);
128 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +0530129 if (dHCPEnabled())
130 {
131 origin = IP::AddressOrigin::DHCP;
132 }
William A. Kennington III16893802019-01-30 16:01:01 -0800133 if (isLinkLocalIP(addr.ipaddress))
Ratan Guptafc2c7242017-05-29 08:46:06 +0530134 {
135 origin = IP::AddressOrigin::LinkLocal;
136 }
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700137 // Obsolete parameter
138 std::string gateway = "";
Ratan Gupta82549cc2017-04-21 08:45:23 +0530139
Gunnar Mills57d9c502018-09-14 14:42:34 -0500140 std::string ipAddressObjectPath = generateObjectPath(
141 addressType, addr.ipaddress, addr.prefix, gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530142
Gunnar Mills57d9c502018-09-14 14:42:34 -0500143 this->addrs.emplace(addr.ipaddress,
144 std::make_shared<phosphor::network::IPAddress>(
145 bus, ipAddressObjectPath.c_str(), *this,
146 addressType, addr.ipaddress, origin,
147 addr.prefix, gateway));
Ratan Gupta82549cc2017-04-21 08:45:23 +0530148 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530149}
150
William A. Kennington III08505792019-01-30 16:00:04 -0800151void EthernetInterface::createStaticNeighborObjects()
152{
153 staticNeighbors.clear();
154
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700155 NeighborFilter filter;
156 filter.interface = ifIndex();
157 filter.state = NUD_PERMANENT;
158 auto neighbors = getCurrentNeighbors(filter);
William A. Kennington III08505792019-01-30 16:00:04 -0800159 for (const auto& neighbor : neighbors)
160 {
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700161 if (!neighbor.mac)
William A. Kennington III08505792019-01-30 16:00:04 -0800162 {
163 continue;
164 }
165 std::string ip = toString(neighbor.address);
166 std::string mac = mac_address::toString(*neighbor.mac);
167 std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
168 staticNeighbors.emplace(ip,
169 std::make_shared<phosphor::network::Neighbor>(
170 bus, objectPath.c_str(), *this, ip, mac,
171 Neighbor::State::Permanent));
172 }
173}
174
William A. Kennington IIId7946a72019-04-19 14:24:09 -0700175unsigned EthernetInterface::ifIndex() const
176{
177 unsigned idx = if_nametoindex(interfaceName().c_str());
178 if (idx == 0)
179 {
180 throw std::system_error(errno, std::generic_category(),
181 "if_nametoindex");
182 }
183 return idx;
184}
185
raviteja-bce379562019-03-28 05:59:36 -0500186ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
187 uint8_t prefixLength, std::string gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530188{
Ratan Guptafc2c7242017-05-29 08:46:06 +0530189
190 if (dHCPEnabled())
191 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530192 log<level::INFO>("DHCP enabled on the interface"),
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500193 entry("INTERFACE=%s", interfaceName().c_str());
194 dHCPEnabled(false);
195 }
196
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500197 IP::AddressOrigin origin = IP::AddressOrigin::Static;
198
199 int addressFamily = (protType == IP::Protocol::IPv4) ? AF_INET : AF_INET6;
200
201 if (!isValidIP(addressFamily, ipaddress))
202 {
203 log<level::ERR>("Not a valid IP address"),
204 entry("ADDRESS=%s", ipaddress.c_str());
205 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"),
206 Argument::ARGUMENT_VALUE(ipaddress.c_str()));
207 }
208
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700209 // Gateway is an obsolete parameter
210 gateway = "";
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500211
212 if (!isValidPrefix(addressFamily, prefixLength))
213 {
214 log<level::ERR>("PrefixLength is not correct "),
William A. Kennington IIIf8c78f22019-04-20 20:32:59 -0700215 entry("PREFIXLENGTH=%" PRIu8, prefixLength);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500216 elog<InvalidArgument>(
217 Argument::ARGUMENT_NAME("prefixLength"),
218 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str()));
Ratan Guptafc2c7242017-05-29 08:46:06 +0530219 }
220
Gunnar Mills57d9c502018-09-14 14:42:34 -0500221 std::string objectPath =
222 generateObjectPath(protType, ipaddress, prefixLength, gateway);
223 this->addrs.emplace(ipaddress,
224 std::make_shared<phosphor::network::IPAddress>(
225 bus, objectPath.c_str(), *this, protType, ipaddress,
226 origin, prefixLength, gateway));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530227
Ratan Guptae05083a2017-09-16 07:12:11 +0530228 manager.writeToConfigurationFile();
raviteja-bce379562019-03-28 05:59:36 -0500229 return objectPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530230}
231
William A. Kennington III08505792019-01-30 16:00:04 -0800232ObjectPath EthernetInterface::neighbor(std::string iPAddress,
233 std::string mACAddress)
234{
235 if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
236 {
237 log<level::ERR>("Not a valid IP address",
238 entry("ADDRESS=%s", iPAddress.c_str()));
239 elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
240 Argument::ARGUMENT_VALUE(iPAddress.c_str()));
241 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700242 if (!mac_address::isUnicast(mac_address::fromString(mACAddress)))
William A. Kennington III08505792019-01-30 16:00:04 -0800243 {
244 log<level::ERR>("Not a valid MAC address",
245 entry("MACADDRESS=%s", iPAddress.c_str()));
246 elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
247 Argument::ARGUMENT_VALUE(mACAddress.c_str()));
248 }
249
250 std::string objectPath =
251 generateStaticNeighborObjectPath(iPAddress, mACAddress);
252 staticNeighbors.emplace(iPAddress,
253 std::make_shared<phosphor::network::Neighbor>(
254 bus, objectPath.c_str(), *this, iPAddress,
255 mACAddress, Neighbor::State::Permanent));
256 manager.writeToConfigurationFile();
257 return objectPath;
258}
259
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800260#if NIC_SUPPORTS_ETHTOOL
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530261/*
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800262 Enable this code if your NIC driver supports the ETHTOOL features.
263 Do this by adding the following to your phosphor-network*.bbappend file.
264 EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
265 The default compile mode is to omit getInterfaceInfo()
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530266*/
267InterfaceInfo EthernetInterface::getInterfaceInfo() const
268{
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400269 ifreq ifr{0};
270 ethtool_cmd edata{0};
Gunnar Mills57d9c502018-09-14 14:42:34 -0500271 LinkSpeed speed{0};
272 Autoneg autoneg{0};
273 DuplexMode duplex{0};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800274 LinkUp linkState{false};
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700275 NICEnabled nicEnabled{false};
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800276 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
277
278 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530279 {
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700280 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800281 }
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530282
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800283 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
284 ifr.ifr_data = reinterpret_cast<char*>(&edata);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530285
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800286 edata.cmd = ETHTOOL_GSET;
287 if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0)
288 {
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530289 speed = edata.speed;
290 duplex = edata.duplex;
291 autoneg = edata.autoneg;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530292 }
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800293
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700294 nicEnabled = nICEnabled();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800295 linkState = linkUp();
296
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700297 return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530298}
Johnathan Manteyad4bf5c2020-01-24 13:30:39 -0800299#endif
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530300
301/** @brief get the mac address of the interface.
302 * @return macaddress on success
303 */
304
Gunnar Mills57d9c502018-09-14 14:42:34 -0500305std::string
306 EthernetInterface::getMACAddress(const std::string& interfaceName) const
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530307{
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800308 std::string activeMACAddr = MacAddressIntf::mACAddress();
309 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
310
311 if (eifSocket.sock < 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530312 {
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800313 return activeMACAddr;
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530314 }
315
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800316 ifreq ifr{0};
317 std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
318 if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0)
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530319 {
Ratan Guptada7d3af2017-08-13 17:49:56 +0530320 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500321 entry("ERROR=%s", strerror(errno)));
William A. Kennington III7ed1b282019-04-21 23:38:42 -0700322 elog<InternalFailure>();
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530323 }
324
William A. Kennington III1137a972019-04-20 20:49:58 -0700325 static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
326 std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data),
327 sizeof(ifr.ifr_hwaddr.sa_data));
328 return mac_address::toString(copyFrom<ether_addr>(hwaddr));
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530329}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530330
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530331std::string EthernetInterface::generateId(const std::string& ipaddress,
332 uint8_t prefixLength,
333 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530334{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530335 std::stringstream hexId;
336 std::string hashString = ipaddress;
337 hashString += std::to_string(prefixLength);
338 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530339
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530340 // Only want 8 hex digits.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500341 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530342 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530343}
344
William A. Kennington III08505792019-01-30 16:00:04 -0800345std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
346 const std::string& mACAddress)
347{
348 std::stringstream hexId;
349 std::string hashString = iPAddress + mACAddress;
350
351 // Only want 8 hex digits.
352 hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
353 return hexId.str();
354}
355
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530356void EthernetInterface::deleteObject(const std::string& ipaddress)
357{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530358 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530359 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530360 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530361 log<level::ERR>("DeleteObject:Unable to find the object.");
362 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530363 }
364 this->addrs.erase(it);
Ratan Guptae05083a2017-09-16 07:12:11 +0530365 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530366}
367
William A. Kennington III08505792019-01-30 16:00:04 -0800368void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
369{
370 auto it = staticNeighbors.find(iPAddress);
371 if (it == staticNeighbors.end())
372 {
373 log<level::ERR>(
374 "DeleteStaticNeighborObject:Unable to find the object.");
375 return;
376 }
377 staticNeighbors.erase(it);
378 manager.writeToConfigurationFile();
379}
380
Ratan Guptae9c9b812017-09-22 17:15:37 +0530381void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
Ratan Guptabc886292017-07-25 18:29:57 +0530382{
Ratan Guptabc886292017-07-25 18:29:57 +0530383 auto confDir = manager.getConfDir();
384 fs::path networkFile = confDir;
385 networkFile /= systemd::config::networkFilePrefix + interface +
386 systemd::config::networkFileSuffix;
387
388 fs::path deviceFile = confDir;
389 deviceFile /= interface + systemd::config::deviceFileSuffix;
390
391 // delete the vlan network file
392 if (fs::is_regular_file(networkFile))
393 {
394 fs::remove(networkFile);
395 }
396
397 // delete the vlan device file
398 if (fs::is_regular_file(deviceFile))
399 {
400 fs::remove(deviceFile);
401 }
Ratan Guptabc886292017-07-25 18:29:57 +0530402
403 // TODO systemd doesn't delete the virtual network interface
404 // even after deleting all the related configuartion.
405 // https://github.com/systemd/systemd/issues/6600
406 try
407 {
408 deleteInterface(interface);
409 }
410 catch (InternalFailure& e)
411 {
412 commit<InternalFailure>();
413 }
Ratan Guptae9c9b812017-09-22 17:15:37 +0530414}
415
416void EthernetInterface::deleteVLANObject(const std::string& interface)
417{
418 auto it = vlanInterfaces.find(interface);
419 if (it == vlanInterfaces.end())
420 {
421 log<level::ERR>("DeleteVLANObject:Unable to find the object",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500422 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptae9c9b812017-09-22 17:15:37 +0530423 return;
424 }
425
426 deleteVLANFromSystem(interface);
427 // delete the interface
428 vlanInterfaces.erase(it);
429
Ratan Guptae05083a2017-09-16 07:12:11 +0530430 manager.writeToConfigurationFile();
Ratan Guptabc886292017-07-25 18:29:57 +0530431}
432
Gunnar Mills57d9c502018-09-14 14:42:34 -0500433std::string EthernetInterface::generateObjectPath(
434 IP::Protocol addressType, const std::string& ipaddress,
435 uint8_t prefixLength, const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530436{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530437 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530438 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530439 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
440
441 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530442 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530443 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530444 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530445 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530446}
447
William A. Kennington III08505792019-01-30 16:00:04 -0800448std::string EthernetInterface::generateStaticNeighborObjectPath(
449 const std::string& iPAddress, const std::string& mACAddress) const
450{
451 std::experimental::filesystem::path objectPath;
452 objectPath /= objPath;
453 objectPath /= "static_neighbor";
454 objectPath /= generateNeighborId(iPAddress, mACAddress);
455 return objectPath.string();
456}
457
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700458bool EthernetInterface::iPv6AcceptRA(bool value)
459{
460 if (value == EthernetInterfaceIntf::iPv6AcceptRA())
461 {
462 return value;
463 }
464 EthernetInterfaceIntf::iPv6AcceptRA(value);
465 manager.writeToConfigurationFile();
466 return value;
467}
468
Ratan Gupta87c13982017-06-15 09:27:27 +0530469bool EthernetInterface::dHCPEnabled(bool value)
470{
Ratan Gupta5978dd12017-07-25 13:47:13 +0530471 if (value == EthernetInterfaceIntf::dHCPEnabled())
472 {
473 return value;
474 }
475
Ratan Gupta87c13982017-06-15 09:27:27 +0530476 EthernetInterfaceIntf::dHCPEnabled(value);
Ratan Guptae05083a2017-09-16 07:12:11 +0530477 manager.writeToConfigurationFile();
Ratan Gupta87c13982017-06-15 09:27:27 +0530478 return value;
479}
480
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800481bool EthernetInterface::linkUp() const
482{
483 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
484 bool value = EthernetInterfaceIntf::linkUp();
485
486 if (eifSocket.sock < 0)
487 {
488 return value;
489 }
490
491 ifreq ifr{0};
492 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
493 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
494 {
495 value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING);
496 }
497 else
498 {
499 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
500 entry("ERROR=%s", strerror(errno)));
501 }
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700502 return value;
503}
504
505bool EthernetInterface::nICEnabled() const
506{
507 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
508 bool value = EthernetInterfaceIntf::nICEnabled();
509
510 if (eifSocket.sock < 0)
511 {
512 return value;
513 }
514
515 ifreq ifr{0};
516 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
517 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
518 {
519 value = static_cast<bool>(ifr.ifr_flags & IFF_UP);
520 }
521 else
522 {
523 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
524 entry("ERROR=%s", strerror(errno)));
525 }
526 return value;
527}
528
529bool EthernetInterface::nICEnabled(bool value)
530{
531 if (value == EthernetInterfaceIntf::nICEnabled())
532 {
533 return value;
534 }
535
536 EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
537 if (eifSocket.sock < 0)
538 {
539 return EthernetInterfaceIntf::nICEnabled();
540 }
541
542 ifreq ifr{0};
543 std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
544 if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) != 0)
545 {
546 log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
547 entry("ERROR=%s", strerror(errno)));
548 return EthernetInterfaceIntf::nICEnabled();
549 }
550
551 ifr.ifr_flags &= ~IFF_UP;
552 ifr.ifr_flags |= value ? IFF_UP : 0;
553
554 if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
555 {
556 log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
557 entry("ERROR=%s", strerror(errno)));
558 return EthernetInterfaceIntf::nICEnabled();
559 }
560 EthernetInterfaceIntf::nICEnabled(value);
561 writeConfigurationFile();
Johnathan Manteyfaa72e52020-01-08 10:38:58 -0800562
563 return value;
564}
565
Ratan Gupta6dec3902017-08-20 15:28:12 +0530566ServerList EthernetInterface::nameservers(ServerList value)
567{
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530568 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
569 return EthernetInterfaceIntf::nameservers();
570}
571
572ServerList EthernetInterface::staticNameServers(ServerList value)
573{
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530574 for (const auto& nameserverip : value)
575 {
576 if (!isValidIP(AF_INET, nameserverip) &&
577 !isValidIP(AF_INET6, nameserverip))
578 {
579 log<level::ERR>("Not a valid IP address"),
580 entry("ADDRESS=%s", nameserverip.c_str());
581 elog<InvalidArgument>(
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530582 Argument::ARGUMENT_NAME("StaticNameserver"),
Manojkiran Eda5fb6c332019-08-21 16:37:29 +0530583 Argument::ARGUMENT_VALUE(nameserverip.c_str()));
584 }
585 }
Ratan Gupta6dec3902017-08-20 15:28:12 +0530586 try
587 {
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530588 EthernetInterfaceIntf::staticNameServers(value);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530589 writeConfigurationFile();
Ratan Guptab4005972019-09-19 06:19:16 +0530590 // resolved reads the DNS server configuration from the
591 // network file.
592 manager.restartSystemdUnit(networkdService);
Ratan Gupta6dec3902017-08-20 15:28:12 +0530593 }
594 catch (InternalFailure& e)
595 {
596 log<level::ERR>("Exception processing DNS entries");
597 }
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530598 return EthernetInterfaceIntf::staticNameServers();
Ratan Gupta6dec3902017-08-20 15:28:12 +0530599}
600
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530601void EthernetInterface::loadNameServers()
602{
603 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
604 EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
605}
606
607ServerList EthernetInterface::getstaticNameServerFromConf()
Ratan Gupta6dec3902017-08-20 15:28:12 +0530608{
609 fs::path confPath = manager.getConfDir();
610
611 std::string fileName = systemd::config::networkFilePrefix +
Gunnar Mills57d9c502018-09-14 14:42:34 -0500612 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta6dec3902017-08-20 15:28:12 +0530613 confPath /= fileName;
614 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530615 config::Parser parser(confPath.string());
616 auto rc = config::ReturnCode::SUCCESS;
617
618 std::tie(rc, servers) = parser.getValues("Network", "DNS");
619 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta6dec3902017-08-20 15:28:12 +0530620 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530621 log<level::DEBUG>("Unable to get the value for network[DNS]",
622 entry("RC=%d", rc));
Ratan Gupta6dec3902017-08-20 15:28:12 +0530623 }
624 return servers;
625}
626
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530627ServerList EthernetInterface::getNameServerFromResolvd()
628{
629 ServerList servers;
630 std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
631
632 /*
633 The DNS property under org.freedesktop.resolve1.Link interface contains
634 an array containing all DNS servers currently used by resolved. It
635 contains similar information as the DNS server data written to
636 /run/systemd/resolve/resolv.conf.
637
638 Each structure in the array consists of a numeric network interface index,
639 an address family, and a byte array containing the DNS server address
640 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
641 The array contains DNS servers configured system-wide, including those
642 possibly read from a foreign /etc/resolv.conf or the DNS= setting in
643 /etc/systemd/resolved.conf, as well as per-interface DNS server
644 information either retrieved from systemd-networkd or configured by
645 external software via SetLinkDNS().
646 */
647
648 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
649 std::variant<type> name; // Variable to capture the DNS property
650 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
651 PROPERTY_INTERFACE, METHOD_GET);
652
653 method.append(RESOLVED_INTERFACE, "DNS");
654 auto reply = bus.call(method);
655
656 try
657 {
658 reply.read(name);
659 }
660 catch (const sdbusplus::exception::SdBusError& e)
661 {
662 log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
663 }
664 auto tupleVector = std::get_if<type>(&name);
665 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
666 {
667 std::vector<uint8_t> ipaddress = std::get<1>(*i);
668 std::string address;
669 for (auto byte : ipaddress)
670 {
671 address += std::to_string(byte) + ".";
672 }
673 address.pop_back();
674 servers.push_back(address);
675 }
676 return servers;
677}
678
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530679void EthernetInterface::loadVLAN(VlanId id)
680{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500681 std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
Ratan Gupta92bc2fe2017-07-26 22:40:21 +0530682 std::string path = objPath;
683 path += "_" + std::to_string(id);
684
Gunnar Mills57d9c502018-09-14 14:42:34 -0500685 auto dhcpEnabled =
686 getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
Ratan Gupta6e8df632017-08-13 09:41:58 +0530687
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
Ratan Gupta5978dd12017-07-25 13:47:13 +0530706 auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500707 bus, path.c_str(), false, id, *this, manager);
Ratan Gupta5978dd12017-07-25 13:47:13 +0530708
709 // write the device file for the vlan interface.
710 vlanIntf->writeDeviceFile();
711
Gunnar Mills57d9c502018-09-14 14:42:34 -0500712 this->vlanInterfaces.emplace(vlanInterfaceName, std::move(vlanIntf));
Ratan Gupta5978dd12017-07-25 13:47:13 +0530713 // write the new vlan device entry to the configuration(network) file.
Ratan Guptae05083a2017-09-16 07:12:11 +0530714 manager.writeToConfigurationFile();
William A. Kennington IIIf4b4ff82019-04-09 19:06:52 -0700715
716 return path;
Ratan Gupta5978dd12017-07-25 13:47:13 +0530717}
Ratan Gupta2b106532017-07-25 16:05:02 +0530718
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700719bool EthernetInterface::getIPv6AcceptRAFromConf()
720{
721 fs::path confPath = manager.getConfDir();
722
723 std::string fileName = systemd::config::networkFilePrefix +
724 interfaceName() + systemd::config::networkFileSuffix;
725 confPath /= fileName;
726 config::ValueList values;
727 config::Parser parser(confPath.string());
728 auto rc = config::ReturnCode::SUCCESS;
729 std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
730 if (rc != config::ReturnCode::SUCCESS)
731 {
732 log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
733 entry("rc=%d", rc));
734 return false;
735 }
736 return (values[0] == "true");
737}
738
Ratan Gupta497c0c92017-08-22 19:15:59 +0530739ServerList EthernetInterface::getNTPServersFromConf()
740{
741 fs::path confPath = manager.getConfDir();
742
Gunnar Mills57d9c502018-09-14 14:42:34 -0500743 std::string fileName = systemd::config::networkFilePrefix +
744 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta497c0c92017-08-22 19:15:59 +0530745 confPath /= fileName;
Ratan Guptac27170a2017-11-22 15:44:42 +0530746
Ratan Gupta497c0c92017-08-22 19:15:59 +0530747 ServerList servers;
Ratan Guptac27170a2017-11-22 15:44:42 +0530748 config::Parser parser(confPath.string());
749 auto rc = config::ReturnCode::SUCCESS;
750
751 std::tie(rc, servers) = parser.getValues("Network", "NTP");
752 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta497c0c92017-08-22 19:15:59 +0530753 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530754 log<level::DEBUG>("Unable to get the value for Network[NTP]",
755 entry("rc=%d", rc));
Ratan Gupta497c0c92017-08-22 19:15:59 +0530756 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530757
Ratan Gupta497c0c92017-08-22 19:15:59 +0530758 return servers;
759}
760
761ServerList EthernetInterface::nTPServers(ServerList servers)
762{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500763 auto ntpServers = EthernetInterfaceIntf::nTPServers(servers);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530764
765 writeConfigurationFile();
766 // timesynchd reads the NTP server configuration from the
767 // network file.
Ratan Gupta895f9e52018-11-26 20:57:34 +0530768 manager.restartSystemdUnit(networkdService);
Ratan Gupta497c0c92017-08-22 19:15:59 +0530769 return ntpServers;
770}
Ratan Gupta2b106532017-07-25 16:05:02 +0530771// Need to merge the below function with the code which writes the
772// config file during factory reset.
773// TODO openbmc/openbmc#1751
774
775void EthernetInterface::writeConfigurationFile()
776{
777 // write all the static ip address in the systemd-network conf file
778
779 using namespace std::string_literals;
780 using AddressOrigin =
781 sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
782 namespace fs = std::experimental::filesystem;
Ratan Guptae05083a2017-09-16 07:12:11 +0530783
784 // if there is vlan interafce then write the configuration file
785 // for vlan also.
786
Gunnar Mills57d9c502018-09-14 14:42:34 -0500787 for (const auto& intf : vlanInterfaces)
Ratan Guptae05083a2017-09-16 07:12:11 +0530788 {
789 intf.second->writeConfigurationFile();
790 }
791
Ratan Gupta2b106532017-07-25 16:05:02 +0530792 fs::path confPath = manager.getConfDir();
793
Gunnar Mills57d9c502018-09-14 14:42:34 -0500794 std::string fileName = systemd::config::networkFilePrefix +
795 interfaceName() + systemd::config::networkFileSuffix;
Ratan Gupta2b106532017-07-25 16:05:02 +0530796 confPath /= fileName;
797 std::fstream stream;
798
799 stream.open(confPath.c_str(), std::fstream::out);
800 if (!stream.is_open())
801 {
802 log<level::ERR>("Unable to open the file",
803 entry("FILE=%s", confPath.c_str()));
804 elog<InternalFailure>();
805 }
806
807 // Write the device
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400808 stream << "[Match]\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530809 stream << "Name=" << interfaceName() << "\n";
810
811 auto addrs = getAddresses();
812
William A. Kennington III15787212019-04-23 19:18:01 -0700813 // Write the link section
814 stream << "[Link]\n";
815 auto mac = MacAddressIntf::mACAddress();
816 if (!mac.empty())
817 {
818 stream << "MACAddress=" << mac << "\n";
819 }
820
Ratan Gupta40a51df2020-04-24 15:11:05 +0530821 if (!EthernetInterfaceIntf::nICEnabled())
Johnathan Manteyd0679f92019-10-29 16:20:28 -0700822 {
823 stream << "Unmanaged=yes\n";
824 }
825
Ratan Gupta2b106532017-07-25 16:05:02 +0530826 // write the network section
Ratan K Gupta1a054ae2018-09-15 00:49:51 -0400827 stream << "[Network]\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400828#ifdef LINK_LOCAL_AUTOCONFIGURATION
Nagaraju Goruganti24afe362017-09-21 07:40:26 -0500829 stream << "LinkLocalAddressing=yes\n";
Oskar Senftad21fc22018-07-26 16:32:23 -0400830#else
831 stream << "LinkLocalAddressing=no\n";
832#endif
Johnathan Mantey5b023f52019-06-24 16:06:37 -0700833 stream << std::boolalpha
834 << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530835
836 // Add the VLAN entry
Gunnar Mills57d9c502018-09-14 14:42:34 -0500837 for (const auto& intf : vlanInterfaces)
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530838 {
839 stream << "VLAN=" << intf.second->EthernetInterface::interfaceName()
Gunnar Mills57d9c502018-09-14 14:42:34 -0500840 << "\n";
Ratan Gupta4f67dac2017-08-28 22:18:21 +0530841 }
Ratan Gupta046b2a02019-09-20 15:49:51 +0530842 // Add the NTP server
843 for (const auto& ntp : EthernetInterfaceIntf::nTPServers())
844 {
845 stream << "NTP=" << ntp << "\n";
846 }
847
848 // Add the DNS entry
Manojkiran Edaacd6dd52019-10-15 15:00:51 +0530849 for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
Ratan Gupta046b2a02019-09-20 15:49:51 +0530850 {
851 stream << "DNS=" << dns << "\n";
852 }
853
Nagaraju Gorugantie8b83ec2018-03-26 05:21:45 -0500854 // Add the DHCP entry
855 auto value = dHCPEnabled() ? "true"s : "false"s;
856 stream << "DHCP="s + value + "\n";
857
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600858 // When the interface configured as dhcp, we don't need below given entries
859 // in config file.
860 if (dHCPEnabled() == false)
Ratan Gupta2b106532017-07-25 16:05:02 +0530861 {
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600862 // Static
863 for (const auto& addr : addrs)
864 {
Oskar Senftad21fc22018-07-26 16:32:23 -0400865 if (addr.second->origin() == AddressOrigin::Static
866#ifndef LINK_LOCAL_AUTOCONFIGURATION
867 || addr.second->origin() == AddressOrigin::LinkLocal
868#endif
869 )
Ratan Gupta2b106532017-07-25 16:05:02 +0530870 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500871 std::string address =
872 addr.second->address() + "/" +
873 std::to_string(addr.second->prefixLength());
Ratan Gupta2b106532017-07-25 16:05:02 +0530874
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600875 stream << "Address=" << address << "\n";
876 }
877 }
878
879 if (manager.getSystemConf())
880 {
William A. Kennington III781f3352019-02-01 21:07:10 -0800881 const auto& gateway = manager.getSystemConf()->defaultGateway();
882 if (!gateway.empty())
883 {
884 stream << "Gateway=" << gateway << "\n";
885 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800886 const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
887 if (!gateway6.empty())
888 {
889 stream << "Gateway=" << gateway6 << "\n";
890 }
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600891 }
Ratan Gupta2b106532017-07-25 16:05:02 +0530892 }
893
William A. Kennington III08505792019-01-30 16:00:04 -0800894 // Write the neighbor sections
895 for (const auto& neighbor : staticNeighbors)
896 {
897 stream << "[Neighbor]"
898 << "\n";
899 stream << "Address=" << neighbor.second->iPAddress() << "\n";
900 stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
901 }
902
Nagaraju Goruganti210420a2018-03-07 09:22:28 -0600903 // Write the dhcp section irrespective of whether DHCP is enabled or not
904 writeDHCPSection(stream);
905
Ratan Gupta2b106532017-07-25 16:05:02 +0530906 stream.close();
Ratan Gupta2b106532017-07-25 16:05:02 +0530907}
908
909void EthernetInterface::writeDHCPSection(std::fstream& stream)
910{
911 using namespace std::string_literals;
Ratan Gupta2b106532017-07-25 16:05:02 +0530912 // write the dhcp section
913 stream << "[DHCP]\n";
914
915 // Hardcoding the client identifier to mac, to address below issue
916 // https://github.com/openbmc/openbmc/issues/1280
917 stream << "ClientIdentifier=mac\n";
918 if (manager.getDHCPConf())
919 {
920 auto value = manager.getDHCPConf()->dNSEnabled() ? "true"s : "false"s;
921 stream << "UseDNS="s + value + "\n";
922
923 value = manager.getDHCPConf()->nTPEnabled() ? "true"s : "false"s;
924 stream << "UseNTP="s + value + "\n";
925
926 value = manager.getDHCPConf()->hostNameEnabled() ? "true"s : "false"s;
927 stream << "UseHostname="s + value + "\n";
Nagaraju Gorugantie8fca1d2018-02-05 20:32:45 -0600928
929 value =
930 manager.getDHCPConf()->sendHostNameEnabled() ? "true"s : "false"s;
931 stream << "SendHostname="s + value + "\n";
Ratan Gupta2b106532017-07-25 16:05:02 +0530932 }
933}
934
Ratan Guptabd303b12017-08-18 17:10:07 +0530935std::string EthernetInterface::mACAddress(std::string value)
936{
William A. Kennington III1137a972019-04-20 20:49:58 -0700937 ether_addr newMAC = mac_address::fromString(value);
938 if (!mac_address::isUnicast(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530939 {
Gunnar Mills90480c42018-06-19 16:02:17 -0500940 log<level::ERR>("MACAddress is not valid.",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500941 entry("MAC=%s", value.c_str()));
Gunnar Mills90480c42018-06-19 16:02:17 -0500942 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"),
943 Argument::ARGUMENT_VALUE(value.c_str()));
Ratan Guptabd303b12017-08-18 17:10:07 +0530944 }
945
William A. Kennington III1137a972019-04-20 20:49:58 -0700946 // We don't need to update the system if the address is unchanged
947 ether_addr oldMAC = mac_address::fromString(MacAddressIntf::mACAddress());
948 if (!equal(newMAC, oldMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530949 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700950 if (!mac_address::isLocalAdmin(newMAC))
Ratan Guptabd303b12017-08-18 17:10:07 +0530951 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700952 try
Ratan Guptabd303b12017-08-18 17:10:07 +0530953 {
Alvin Wang38a63c32019-08-29 22:56:46 +0800954 auto inventoryMAC =
955 mac_address::getfromInventory(bus, interfaceName());
William A. Kennington III1137a972019-04-20 20:49:58 -0700956 if (!equal(newMAC, inventoryMAC))
957 {
958 log<level::ERR>(
959 "Given MAC address is neither a local Admin "
960 "type nor is same as in inventory");
961 elog<InvalidArgument>(
962 Argument::ARGUMENT_NAME("MACAddress"),
963 Argument::ARGUMENT_VALUE(value.c_str()));
964 }
965 }
966 catch (const std::exception& e)
967 {
968 log<level::ERR>("Exception occurred during getting of MAC "
969 "address from Inventory");
970 elog<InternalFailure>();
Ratan Guptabd303b12017-08-18 17:10:07 +0530971 }
972 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700973
974 // Update everything that depends on the MAC value
975 for (const auto& [name, intf] : vlanInterfaces)
Ratan Guptabd303b12017-08-18 17:10:07 +0530976 {
William A. Kennington III1137a972019-04-20 20:49:58 -0700977 intf->MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530978 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700979 MacAddressIntf::mACAddress(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530980
William A. Kennington III1137a972019-04-20 20:49:58 -0700981 auto interface = interfaceName();
Benjamin Fair06345732020-04-15 16:06:32 -0700982
983#ifdef HAVE_UBOOT_ENV
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700984 auto envVar = interfaceToUbootEthAddr(interface.c_str());
985 if (envVar)
986 {
987 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(),
988 value.c_str());
989 }
Benjamin Fair06345732020-04-15 16:06:32 -0700990#endif // HAVE_UBOOT_ENV
991
William A. Kennington III15787212019-04-23 19:18:01 -0700992 // TODO: would remove the call below and
993 // just restart systemd-netwokd
William A. Kennington III1137a972019-04-20 20:49:58 -0700994 // through https://github.com/systemd/systemd/issues/6696
995 execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(),
996 "down");
William A. Kennington III15787212019-04-23 19:18:01 -0700997 manager.writeToConfigurationFile();
Ratan Gupta677ae122017-09-18 16:28:50 +0530998 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700999
1000 return value;
Ratan Guptabd303b12017-08-18 17:10:07 +05301001}
1002
Ratan Guptae9c9b812017-09-22 17:15:37 +05301003void EthernetInterface::deleteAll()
1004{
Gunnar Mills57d9c502018-09-14 14:42:34 -05001005 if (EthernetInterfaceIntf::dHCPEnabled())
Ratan Guptae9c9b812017-09-22 17:15:37 +05301006 {
1007 log<level::INFO>("DHCP enabled on the interface"),
Gunnar Mills57d9c502018-09-14 14:42:34 -05001008 entry("INTERFACE=%s", interfaceName().c_str());
Ratan Guptae9c9b812017-09-22 17:15:37 +05301009 }
1010
1011 // clear all the ip on the interface
1012 addrs.clear();
1013 manager.writeToConfigurationFile();
1014}
1015
Gunnar Mills57d9c502018-09-14 14:42:34 -05001016} // namespace network
1017} // namespace phosphor