blob: 5c5e42732151089237a781c2b3860b7dd52a838b [file] [log] [blame]
Ratan Gupta3681a502017-06-17 19:20:04 +05301#include "util.hpp"
Ratan Gupta11cef802017-05-29 08:41:48 +05302
Patrick Venture189d44e2018-07-09 12:30:59 -07003#include "config_parser.hpp"
4#include "types.hpp"
Ratan Gupta8804feb2017-05-25 10:49:57 +05305
Ratan Gupta3681a502017-06-17 19:20:04 +05306#include <arpa/inet.h>
7#include <dirent.h>
8#include <net/if.h>
Ratan Guptabc886292017-07-25 18:29:57 +05309#include <sys/wait.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053010
Ratan Gupta8804feb2017-05-25 10:49:57 +053011#include <algorithm>
Lei YU307554e2021-03-18 14:56:50 +080012#include <cctype>
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -070013#include <cstdlib>
14#include <cstring>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053015#include <filesystem>
Manojkiran Edacc099a82020-05-11 14:25:16 +053016#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070017#include <list>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070018#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053019#include <nlohmann/json.hpp>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070020#endif
Patrick Venture189d44e2018-07-09 12:30:59 -070021#include <phosphor-logging/elog-errors.hpp>
22#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080023#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070024#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070025#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070026#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070027#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053028
29namespace phosphor
30{
31namespace network
32{
Ratan Guptabc886292017-07-25 18:29:57 +053033
Ratan Gupta8804feb2017-05-25 10:49:57 +053034using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053035using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053036namespace fs = std::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053037
Lei YU3894ce72021-03-18 14:53:42 +080038namespace internal
39{
40
41void executeCommandinChildProcess(const char* path, char** args)
42{
43 using namespace std::string_literals;
44 pid_t pid = fork();
45 int status{};
46
47 if (pid == 0)
48 {
49 execv(path, args);
50 auto error = errno;
51 // create the command from var args.
52 std::string command = path + " "s;
53
54 for (int i = 0; args[i]; i++)
55 {
56 command += args[i] + " "s;
57 }
58
59 log<level::ERR>("Couldn't exceute the command",
60 entry("ERRNO=%d", error),
61 entry("CMD=%s", command.c_str()));
62 elog<InternalFailure>();
63 }
64 else if (pid < 0)
65 {
66 auto error = errno;
67 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
68 elog<InternalFailure>();
69 }
70 else if (pid > 0)
71 {
72 while (waitpid(pid, &status, 0) == -1)
73 {
74 if (errno != EINTR)
75 { // Error other than EINTR
76 status = -1;
77 break;
78 }
79 }
80
81 if (status < 0)
82 {
83 std::string command = path + " "s;
84 for (int i = 0; args[i]; i++)
85 {
86 command += args[i] + " "s;
87 }
88
89 log<level::ERR>("Unable to execute the command",
90 entry("CMD=%s", command.c_str()),
91 entry("STATUS=%d", status));
92 elog<InternalFailure>();
93 }
94 }
95}
96
Lei YU307554e2021-03-18 14:56:50 +080097/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070098std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +080099{
100 auto r = std::getenv("IGNORED_INTERFACES");
101 if (r == nullptr)
102 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700103 return "";
Lei YU307554e2021-03-18 14:56:50 +0800104 }
105 return r;
106}
107
108/** @brief Parse the comma separated interface names */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700109std::set<std::string_view> parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800110{
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700111 std::set<std::string_view> result;
112 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800113 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700114 auto sep = interfaces.find(',');
115 auto interface = interfaces.substr(0, sep);
116 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800117 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700118 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800119 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700120 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800121 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700122 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800123 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700124 if (!interface.empty())
125 {
126 result.insert(interface);
127 }
128 if (sep == interfaces.npos)
129 {
130 break;
131 }
132 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800133 }
134 return result;
135}
136
137/** @brief Get the ignored interfaces */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700138const std::set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800139{
140 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
141 return ignoredInterfaces;
142}
143
Lei YU3894ce72021-03-18 14:53:42 +0800144} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530145
146uint8_t toCidr(int addressFamily, const std::string& subnetMask)
147{
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700148 uint32_t subnet[sizeof(in6_addr) / sizeof(uint32_t)];
149 if (inet_pton(addressFamily, subnetMask.c_str(), &subnet) != 1)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530150 {
151 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500152 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530153 return 0;
154 }
155
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700156 static_assert(sizeof(in6_addr) % sizeof(uint32_t) == 0);
157 static_assert(sizeof(in_addr) % sizeof(uint32_t) == 0);
158 auto i = (addressFamily == AF_INET ? sizeof(in_addr) : sizeof(in6_addr)) /
159 sizeof(uint32_t);
160 while (i > 0)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530161 {
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700162 if (subnet[--i] != 0)
163 {
164 auto v = be32toh(subnet[i]);
165 static_assert(sizeof(unsigned) == sizeof(uint32_t));
166 auto trailing = __builtin_ctz(v);
167 auto ret = (i + 1) * 32 - trailing;
168 bool valid = ~v == 0 || 32 == trailing + __builtin_clz(~v);
169 while (i > 0 && (valid = (~subnet[--i] == 0) && valid))
170 ;
171 if (!valid)
172 {
173 log<level::ERR>("Invalid netmask",
174 entry("SUBNETMASK=%s", subnetMask.c_str()));
175 return 0;
176 }
177 return ret;
178 }
Ratan Gupta8804feb2017-05-25 10:49:57 +0530179 }
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700180 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530181}
182
183std::string toMask(int addressFamily, uint8_t prefix)
184{
185 if (addressFamily == AF_INET6)
186 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500187 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530188 return "";
189 }
190
191 if (prefix < 1 || prefix > 30)
192 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500193 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530194 return "";
195 }
196 /* Create the netmask from the number of bits */
197 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500198 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530199 {
200 mask |= 1 << (31 - i);
201 }
202 struct in_addr netmask;
203 netmask.s_addr = htonl(mask);
204 return inet_ntoa(netmask);
205}
206
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800207InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
208{
209 if (addressFamily == AF_INET)
210 {
211 struct in_addr ret;
212 if (buf.size() != sizeof(ret))
213 {
214 throw std::runtime_error("Buf not in_addr sized");
215 }
216 memcpy(&ret, buf.data(), sizeof(ret));
217 return ret;
218 }
219 else if (addressFamily == AF_INET6)
220 {
221 struct in6_addr ret;
222 if (buf.size() != sizeof(ret))
223 {
224 throw std::runtime_error("Buf not in6_addr sized");
225 }
226 memcpy(&ret, buf.data(), sizeof(ret));
227 return ret;
228 }
229
230 throw std::runtime_error("Unsupported address family");
231}
232
Alexander Filippov983da552021-02-08 15:26:54 +0300233std::string toString(const struct in_addr& addr)
234{
235 std::string ip(INET_ADDRSTRLEN, '\0');
236 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
237 {
238 throw std::runtime_error("Failed to convert IP4 to string");
239 }
240
241 ip.resize(strlen(ip.c_str()));
242 return ip;
243}
244
245std::string toString(const struct in6_addr& addr)
246{
247 std::string ip(INET6_ADDRSTRLEN, '\0');
248 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
249 {
250 throw std::runtime_error("Failed to convert IP6 to string");
251 }
252
253 ip.resize(strlen(ip.c_str()));
254 return ip;
255}
256
William A. Kennington III5058f572019-01-30 17:18:14 -0800257std::string toString(const InAddrAny& addr)
258{
William A. Kennington III5058f572019-01-30 17:18:14 -0800259 if (std::holds_alternative<struct in_addr>(addr))
260 {
261 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300262 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800263 }
264 else if (std::holds_alternative<struct in6_addr>(addr))
265 {
266 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300267 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800268 }
Alexander Filippov983da552021-02-08 15:26:54 +0300269
270 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800271}
272
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500273bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530274{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500275 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
276}
277
278bool isValidIP(int addressFamily, const std::string& address)
279{
280 unsigned char buf[sizeof(struct in6_addr)];
281
282 return inet_pton(addressFamily, address.c_str(), buf) > 0;
283}
284
285bool isValidPrefix(int addressFamily, uint8_t prefixLength)
286{
287 if (addressFamily == AF_INET)
288 {
289 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
290 prefixLength > IPV4_MAX_PREFIX_LENGTH)
291 {
292 return false;
293 }
294 }
295
296 if (addressFamily == AF_INET6)
297 {
298 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
299 prefixLength > IPV6_MAX_PREFIX_LENGTH)
300 {
301 return false;
302 }
303 }
304
305 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530306}
307
Ratan Gupta3681a502017-06-17 19:20:04 +0530308IntfAddrMap getInterfaceAddrs()
309{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500310 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530311 struct ifaddrs* ifaddr = nullptr;
312
313 // attempt to fill struct with ifaddrs
314 if (getifaddrs(&ifaddr) == -1)
315 {
316 auto error = errno;
317 log<level::ERR>("Error occurred during the getifaddrs call",
318 entry("ERRNO=%s", strerror(error)));
319 elog<InternalFailure>();
320 }
321
322 AddrPtr ifaddrPtr(ifaddr);
323 ifaddr = nullptr;
324
Gunnar Mills57d9c502018-09-14 14:42:34 -0500325 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530326
327 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
328 {
329 // walk interfaces
330 if (ifa->ifa_addr == nullptr)
331 {
332 continue;
333 }
334
335 // get only INET interfaces not ipv6
336 if (ifa->ifa_addr->sa_family == AF_INET ||
337 ifa->ifa_addr->sa_family == AF_INET6)
338 {
339 // if loopback, or not running ignore
340 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
341 !(ifa->ifa_flags & IFF_RUNNING))
342 {
343 continue;
344 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530345 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500346 AddrInfo info{};
347 char ip[INET6_ADDRSTRLEN] = {0};
348 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530349
350 if (ifa->ifa_addr->sa_family == AF_INET)
351 {
352
353 inet_ntop(ifa->ifa_addr->sa_family,
354 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500355 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530356
Gunnar Mills57d9c502018-09-14 14:42:34 -0500357 inet_ntop(
358 ifa->ifa_addr->sa_family,
359 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
360 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530361 }
362 else
363 {
364 inet_ntop(ifa->ifa_addr->sa_family,
365 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500366 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530367
Gunnar Mills57d9c502018-09-14 14:42:34 -0500368 inet_ntop(
369 ifa->ifa_addr->sa_family,
370 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
371 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530372 }
373
374 info.addrType = ifa->ifa_addr->sa_family;
375 info.ipaddress = ip;
376 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700377 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530378 }
379 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530380 return intfMap;
381}
382
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530383InterfaceList getInterfaces()
384{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500385 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530386 struct ifaddrs* ifaddr = nullptr;
387
388 // attempt to fill struct with ifaddrs
389 if (getifaddrs(&ifaddr) == -1)
390 {
391 auto error = errno;
392 log<level::ERR>("Error occurred during the getifaddrs call",
393 entry("ERRNO=%d", error));
394 elog<InternalFailure>();
395 }
396
397 AddrPtr ifaddrPtr(ifaddr);
398 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800399 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530400
401 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
402 {
403 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700404 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800405 if (ifa->ifa_flags & IFF_LOOPBACK ||
406 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530407 {
408 continue;
409 }
410 interfaces.emplace(ifa->ifa_name);
411 }
412 return interfaces;
413}
414
Ratan Guptabc886292017-07-25 18:29:57 +0530415void deleteInterface(const std::string& intf)
416{
417 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500418 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530419
420 if (pid == 0)
421 {
422
423 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
424 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500425 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530426 entry("INTF=%s", intf.c_str()));
427 elog<InternalFailure>();
428 }
429 else if (pid < 0)
430 {
431 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500432 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530433 elog<InternalFailure>();
434 }
435 else if (pid > 0)
436 {
437 while (waitpid(pid, &status, 0) == -1)
438 {
439 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500440 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530441 status = -1;
442 break;
443 }
444 }
445
Gunnar Mills57d9c502018-09-14 14:42:34 -0500446 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530447 {
448 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500449 entry("INTF=%s", intf.c_str()),
450 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530451 elog<InternalFailure>();
452 }
453 }
454}
455
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700456std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
457{
458 constexpr char ethPrefix[] = "eth";
459 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
460 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
461 {
462 return std::nullopt;
463 }
464 const auto intfSuffix = intf + ethPrefixLen;
465 if (intfSuffix[0] == '\0')
466 {
467 return std::nullopt;
468 }
469 char* end;
470 unsigned long idx = strtoul(intfSuffix, &end, 10);
471 if (end[0] != '\0')
472 {
473 return std::nullopt;
474 }
475 if (idx == 0)
476 {
477 return "ethaddr";
478 }
479 return "eth" + std::to_string(idx) + "addr";
480}
481
Johnathan Mantey817012a2020-01-30 15:07:39 -0800482EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
483 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530484{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800485 EthernetInterfaceIntf::DHCPConf dhcp =
486 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530487 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500488 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530489 fs::path confPath = confDir;
490 std::string fileName = systemd::config::networkFilePrefix + intf +
491 systemd::config::networkFileSuffix;
492 confPath /= fileName;
493
Ratan Guptac27170a2017-11-22 15:44:42 +0530494 auto rc = config::ReturnCode::SUCCESS;
495 config::ValueList values;
496 config::Parser parser(confPath.string());
497
498 std::tie(rc, values) = parser.getValues("Network", "DHCP");
499 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530500 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530501 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500502 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530503 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530504 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530505 // There will be only single value for DHCP key.
506 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530507 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800508 dhcp = EthernetInterfaceIntf::DHCPConf::both;
509 }
510 else if (values[0] == "ipv4")
511 {
512 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
513 }
514 else if (values[0] == "ipv6")
515 {
516 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530517 }
518 return dhcp;
519}
520
Ratan Guptabd303b12017-08-18 17:10:07 +0530521namespace mac_address
522{
523
524constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
525constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
526constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
527constexpr auto propIntf = "org.freedesktop.DBus.Properties";
528constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530529constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530530
531using DbusObjectPath = std::string;
532using DbusService = std::string;
533using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500534using ObjectTree =
535 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530536
537constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
538constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500539 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530540constexpr auto invRoot = "/xyz/openbmc_project/inventory";
541
Alvin Wang38a63c32019-08-29 22:56:46 +0800542ether_addr getfromInventory(sdbusplus::bus::bus& bus,
543 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530544{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530545
546 std::string interfaceName = intfName;
547
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700548#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530549 // load the config JSON from the Read Only Path
550 std::ifstream in(configFile);
551 nlohmann::json configJson;
552 in >> configJson;
553 interfaceName = configJson[intfName];
554#endif
555
Ratan Guptabd303b12017-08-18 17:10:07 +0530556 std::vector<DbusInterface> interfaces;
557 interfaces.emplace_back(invNetworkIntf);
558
559 auto depth = 0;
560
Gunnar Mills57d9c502018-09-14 14:42:34 -0500561 auto mapperCall =
562 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530563
564 mapperCall.append(invRoot, depth, interfaces);
565
566 auto mapperReply = bus.call(mapperCall);
567 if (mapperReply.is_method_error())
568 {
569 log<level::ERR>("Error in mapper call");
570 elog<InternalFailure>();
571 }
572
573 ObjectTree objectTree;
574 mapperReply.read(objectTree);
575
576 if (objectTree.empty())
577 {
578 log<level::ERR>("No Object has implemented the interface",
579 entry("INTERFACE=%s", invNetworkIntf));
580 elog<InternalFailure>();
581 }
582
Alvin Wang38a63c32019-08-29 22:56:46 +0800583 DbusObjectPath objPath;
584 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530585
Alvin Wang38a63c32019-08-29 22:56:46 +0800586 if (1 == objectTree.size())
587 {
588 objPath = objectTree.begin()->first;
589 service = objectTree.begin()->second.begin()->first;
590 }
591 else
592 {
593 // If there are more than 2 objects, object path must contain the
594 // interface name
595 for (auto const& object : objectTree)
596 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530597 log<level::INFO>("interface",
598 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800599 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530600
601 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800602 {
603 objPath = object.first;
604 service = object.second.begin()->first;
605 break;
606 }
607 }
608
609 if (objPath.empty())
610 {
611 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530612 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800613 elog<InternalFailure>();
614 }
615 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530616
Gunnar Mills57d9c502018-09-14 14:42:34 -0500617 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
618 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530619
620 method.append(invNetworkIntf, "MACAddress");
621
622 auto reply = bus.call(method);
623 if (reply.is_method_error())
624 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500625 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530626 entry("PATH=%s", objPath.c_str()),
627 entry("INTERFACE=%s", invNetworkIntf));
628 elog<InternalFailure>();
629 }
630
William A. Kennington III1137a972019-04-20 20:49:58 -0700631 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530632 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700633 return fromString(std::get<std::string>(value));
634}
635
636ether_addr fromString(const char* str)
637{
638 struct ether_addr* mac = ether_aton(str);
639 if (mac == nullptr)
640 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600641 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700642 }
643 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530644}
645
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700646std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800647{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800648 char buf[18] = {0};
649 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
650 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
651 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
652 mac.ether_addr_octet[5]);
653 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800654}
655
William A. Kennington III1137a972019-04-20 20:49:58 -0700656bool isEmpty(const ether_addr& mac)
657{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700658 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700659}
660
661bool isMulticast(const ether_addr& mac)
662{
663 return mac.ether_addr_octet[0] & 0b1;
664}
665
666bool isUnicast(const ether_addr& mac)
667{
668 return !isEmpty(mac) && !isMulticast(mac);
669}
670
Gunnar Mills57d9c502018-09-14 14:42:34 -0500671} // namespace mac_address
672} // namespace network
673} // namespace phosphor