blob: 3bd3806cfc6bdcafae76711abef10111d20e9529 [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>
William A. Kennington III1c776022022-01-05 14:12:16 -08008#include <fmt/compile.h>
9#include <fmt/format.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053010#include <net/if.h>
Ratan Guptabc886292017-07-25 18:29:57 +053011#include <sys/wait.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053012
Ratan Gupta8804feb2017-05-25 10:49:57 +053013#include <algorithm>
Lei YU307554e2021-03-18 14:56:50 +080014#include <cctype>
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -070015#include <cstdlib>
16#include <cstring>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053017#include <filesystem>
Manojkiran Edacc099a82020-05-11 14:25:16 +053018#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070019#include <list>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070020#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053021#include <nlohmann/json.hpp>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070022#endif
Patrick Venture189d44e2018-07-09 12:30:59 -070023#include <phosphor-logging/elog-errors.hpp>
24#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080025#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070026#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070027#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070028#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070029#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053030
31namespace phosphor
32{
33namespace network
34{
Ratan Guptabc886292017-07-25 18:29:57 +053035
Ratan Gupta8804feb2017-05-25 10:49:57 +053036using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053037using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053038namespace fs = std::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053039
Lei YU3894ce72021-03-18 14:53:42 +080040namespace internal
41{
42
43void executeCommandinChildProcess(const char* path, char** args)
44{
45 using namespace std::string_literals;
46 pid_t pid = fork();
47 int status{};
48
49 if (pid == 0)
50 {
51 execv(path, args);
52 auto error = errno;
53 // create the command from var args.
54 std::string command = path + " "s;
55
56 for (int i = 0; args[i]; i++)
57 {
58 command += args[i] + " "s;
59 }
60
61 log<level::ERR>("Couldn't exceute the command",
62 entry("ERRNO=%d", error),
63 entry("CMD=%s", command.c_str()));
64 elog<InternalFailure>();
65 }
66 else if (pid < 0)
67 {
68 auto error = errno;
69 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
70 elog<InternalFailure>();
71 }
72 else if (pid > 0)
73 {
74 while (waitpid(pid, &status, 0) == -1)
75 {
76 if (errno != EINTR)
77 { // Error other than EINTR
78 status = -1;
79 break;
80 }
81 }
82
83 if (status < 0)
84 {
85 std::string command = path + " "s;
86 for (int i = 0; args[i]; i++)
87 {
88 command += args[i] + " "s;
89 }
90
91 log<level::ERR>("Unable to execute the command",
92 entry("CMD=%s", command.c_str()),
93 entry("STATUS=%d", status));
94 elog<InternalFailure>();
95 }
96 }
97}
98
Lei YU307554e2021-03-18 14:56:50 +080099/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700100std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +0800101{
102 auto r = std::getenv("IGNORED_INTERFACES");
103 if (r == nullptr)
104 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700105 return "";
Lei YU307554e2021-03-18 14:56:50 +0800106 }
107 return r;
108}
109
110/** @brief Parse the comma separated interface names */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700111std::set<std::string_view> parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800112{
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700113 std::set<std::string_view> result;
114 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800115 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700116 auto sep = interfaces.find(',');
117 auto interface = interfaces.substr(0, sep);
118 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800119 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700120 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800121 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700122 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800123 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700124 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800125 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700126 if (!interface.empty())
127 {
128 result.insert(interface);
129 }
130 if (sep == interfaces.npos)
131 {
132 break;
133 }
134 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800135 }
136 return result;
137}
138
139/** @brief Get the ignored interfaces */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700140const std::set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800141{
142 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
143 return ignoredInterfaces;
144}
145
Lei YU3894ce72021-03-18 14:53:42 +0800146} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530147
148uint8_t toCidr(int addressFamily, const std::string& subnetMask)
149{
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700150 uint32_t subnet[sizeof(in6_addr) / sizeof(uint32_t)];
151 if (inet_pton(addressFamily, subnetMask.c_str(), &subnet) != 1)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530152 {
153 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500154 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530155 return 0;
156 }
157
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700158 static_assert(sizeof(in6_addr) % sizeof(uint32_t) == 0);
159 static_assert(sizeof(in_addr) % sizeof(uint32_t) == 0);
160 auto i = (addressFamily == AF_INET ? sizeof(in_addr) : sizeof(in6_addr)) /
161 sizeof(uint32_t);
162 while (i > 0)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530163 {
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700164 if (subnet[--i] != 0)
165 {
166 auto v = be32toh(subnet[i]);
167 static_assert(sizeof(unsigned) == sizeof(uint32_t));
168 auto trailing = __builtin_ctz(v);
169 auto ret = (i + 1) * 32 - trailing;
170 bool valid = ~v == 0 || 32 == trailing + __builtin_clz(~v);
171 while (i > 0 && (valid = (~subnet[--i] == 0) && valid))
172 ;
173 if (!valid)
174 {
175 log<level::ERR>("Invalid netmask",
176 entry("SUBNETMASK=%s", subnetMask.c_str()));
177 return 0;
178 }
179 return ret;
180 }
Ratan Gupta8804feb2017-05-25 10:49:57 +0530181 }
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700182 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530183}
184
185std::string toMask(int addressFamily, uint8_t prefix)
186{
187 if (addressFamily == AF_INET6)
188 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500189 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530190 return "";
191 }
192
193 if (prefix < 1 || prefix > 30)
194 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500195 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530196 return "";
197 }
198 /* Create the netmask from the number of bits */
199 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500200 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530201 {
202 mask |= 1 << (31 - i);
203 }
204 struct in_addr netmask;
205 netmask.s_addr = htonl(mask);
206 return inet_ntoa(netmask);
207}
208
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800209InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
210{
211 if (addressFamily == AF_INET)
212 {
213 struct in_addr ret;
214 if (buf.size() != sizeof(ret))
215 {
216 throw std::runtime_error("Buf not in_addr sized");
217 }
218 memcpy(&ret, buf.data(), sizeof(ret));
219 return ret;
220 }
221 else if (addressFamily == AF_INET6)
222 {
223 struct in6_addr ret;
224 if (buf.size() != sizeof(ret))
225 {
226 throw std::runtime_error("Buf not in6_addr sized");
227 }
228 memcpy(&ret, buf.data(), sizeof(ret));
229 return ret;
230 }
231
232 throw std::runtime_error("Unsupported address family");
233}
234
Alexander Filippov983da552021-02-08 15:26:54 +0300235std::string toString(const struct in_addr& addr)
236{
237 std::string ip(INET_ADDRSTRLEN, '\0');
238 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
239 {
240 throw std::runtime_error("Failed to convert IP4 to string");
241 }
242
243 ip.resize(strlen(ip.c_str()));
244 return ip;
245}
246
247std::string toString(const struct in6_addr& addr)
248{
249 std::string ip(INET6_ADDRSTRLEN, '\0');
250 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
251 {
252 throw std::runtime_error("Failed to convert IP6 to string");
253 }
254
255 ip.resize(strlen(ip.c_str()));
256 return ip;
257}
258
William A. Kennington III5058f572019-01-30 17:18:14 -0800259std::string toString(const InAddrAny& addr)
260{
William A. Kennington III5058f572019-01-30 17:18:14 -0800261 if (std::holds_alternative<struct in_addr>(addr))
262 {
263 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300264 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800265 }
266 else if (std::holds_alternative<struct in6_addr>(addr))
267 {
268 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300269 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800270 }
Alexander Filippov983da552021-02-08 15:26:54 +0300271
272 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800273}
274
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500275bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530276{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500277 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
278}
279
280bool isValidIP(int addressFamily, const std::string& address)
281{
282 unsigned char buf[sizeof(struct in6_addr)];
283
284 return inet_pton(addressFamily, address.c_str(), buf) > 0;
285}
286
287bool isValidPrefix(int addressFamily, uint8_t prefixLength)
288{
289 if (addressFamily == AF_INET)
290 {
291 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
292 prefixLength > IPV4_MAX_PREFIX_LENGTH)
293 {
294 return false;
295 }
296 }
297
298 if (addressFamily == AF_INET6)
299 {
300 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
301 prefixLength > IPV6_MAX_PREFIX_LENGTH)
302 {
303 return false;
304 }
305 }
306
307 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530308}
309
Ratan Gupta3681a502017-06-17 19:20:04 +0530310IntfAddrMap getInterfaceAddrs()
311{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500312 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530313 struct ifaddrs* ifaddr = nullptr;
314
315 // attempt to fill struct with ifaddrs
316 if (getifaddrs(&ifaddr) == -1)
317 {
318 auto error = errno;
319 log<level::ERR>("Error occurred during the getifaddrs call",
320 entry("ERRNO=%s", strerror(error)));
321 elog<InternalFailure>();
322 }
323
324 AddrPtr ifaddrPtr(ifaddr);
325 ifaddr = nullptr;
326
Gunnar Mills57d9c502018-09-14 14:42:34 -0500327 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530328
329 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
330 {
331 // walk interfaces
332 if (ifa->ifa_addr == nullptr)
333 {
334 continue;
335 }
336
337 // get only INET interfaces not ipv6
338 if (ifa->ifa_addr->sa_family == AF_INET ||
339 ifa->ifa_addr->sa_family == AF_INET6)
340 {
341 // if loopback, or not running ignore
342 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
343 !(ifa->ifa_flags & IFF_RUNNING))
344 {
345 continue;
346 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530347 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500348 AddrInfo info{};
349 char ip[INET6_ADDRSTRLEN] = {0};
350 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530351
352 if (ifa->ifa_addr->sa_family == AF_INET)
353 {
354
355 inet_ntop(ifa->ifa_addr->sa_family,
356 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500357 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530358
Gunnar Mills57d9c502018-09-14 14:42:34 -0500359 inet_ntop(
360 ifa->ifa_addr->sa_family,
361 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
362 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530363 }
364 else
365 {
366 inet_ntop(ifa->ifa_addr->sa_family,
367 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500368 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530369
Gunnar Mills57d9c502018-09-14 14:42:34 -0500370 inet_ntop(
371 ifa->ifa_addr->sa_family,
372 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
373 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530374 }
375
376 info.addrType = ifa->ifa_addr->sa_family;
377 info.ipaddress = ip;
378 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700379 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530380 }
381 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530382 return intfMap;
383}
384
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530385InterfaceList getInterfaces()
386{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500387 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530388 struct ifaddrs* ifaddr = nullptr;
389
390 // attempt to fill struct with ifaddrs
391 if (getifaddrs(&ifaddr) == -1)
392 {
393 auto error = errno;
394 log<level::ERR>("Error occurred during the getifaddrs call",
395 entry("ERRNO=%d", error));
396 elog<InternalFailure>();
397 }
398
399 AddrPtr ifaddrPtr(ifaddr);
400 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800401 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530402
403 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
404 {
405 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700406 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800407 if (ifa->ifa_flags & IFF_LOOPBACK ||
408 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530409 {
410 continue;
411 }
412 interfaces.emplace(ifa->ifa_name);
413 }
414 return interfaces;
415}
416
Ratan Guptabc886292017-07-25 18:29:57 +0530417void deleteInterface(const std::string& intf)
418{
419 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500420 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530421
422 if (pid == 0)
423 {
424
425 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
426 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530428 entry("INTF=%s", intf.c_str()));
429 elog<InternalFailure>();
430 }
431 else if (pid < 0)
432 {
433 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500434 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530435 elog<InternalFailure>();
436 }
437 else if (pid > 0)
438 {
439 while (waitpid(pid, &status, 0) == -1)
440 {
441 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500442 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530443 status = -1;
444 break;
445 }
446 }
447
Gunnar Mills57d9c502018-09-14 14:42:34 -0500448 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530449 {
450 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500451 entry("INTF=%s", intf.c_str()),
452 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530453 elog<InternalFailure>();
454 }
455 }
456}
457
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700458std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
459{
460 constexpr char ethPrefix[] = "eth";
461 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
462 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
463 {
464 return std::nullopt;
465 }
466 const auto intfSuffix = intf + ethPrefixLen;
467 if (intfSuffix[0] == '\0')
468 {
469 return std::nullopt;
470 }
471 char* end;
472 unsigned long idx = strtoul(intfSuffix, &end, 10);
473 if (end[0] != '\0')
474 {
475 return std::nullopt;
476 }
477 if (idx == 0)
478 {
479 return "ethaddr";
480 }
481 return "eth" + std::to_string(idx) + "addr";
482}
483
Johnathan Mantey817012a2020-01-30 15:07:39 -0800484EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
485 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530486{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800487 EthernetInterfaceIntf::DHCPConf dhcp =
488 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530489 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500490 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530491 fs::path confPath = confDir;
492 std::string fileName = systemd::config::networkFilePrefix + intf +
493 systemd::config::networkFileSuffix;
494 confPath /= fileName;
495
Ratan Guptac27170a2017-11-22 15:44:42 +0530496 auto rc = config::ReturnCode::SUCCESS;
497 config::ValueList values;
498 config::Parser parser(confPath.string());
499
500 std::tie(rc, values) = parser.getValues("Network", "DHCP");
501 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530502 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530503 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500504 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530505 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530506 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530507 // There will be only single value for DHCP key.
508 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530509 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800510 dhcp = EthernetInterfaceIntf::DHCPConf::both;
511 }
512 else if (values[0] == "ipv4")
513 {
514 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
515 }
516 else if (values[0] == "ipv6")
517 {
518 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530519 }
520 return dhcp;
521}
522
Ratan Guptabd303b12017-08-18 17:10:07 +0530523namespace mac_address
524{
525
526constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
527constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
528constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
529constexpr auto propIntf = "org.freedesktop.DBus.Properties";
530constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530531constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530532
533using DbusObjectPath = std::string;
534using DbusService = std::string;
535using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500536using ObjectTree =
537 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530538
539constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
540constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500541 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530542constexpr auto invRoot = "/xyz/openbmc_project/inventory";
543
Patrick Williamsc38b0712022-07-22 19:26:54 -0500544ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530545{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530546
547 std::string interfaceName = intfName;
548
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700549#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530550 // load the config JSON from the Read Only Path
551 std::ifstream in(configFile);
552 nlohmann::json configJson;
553 in >> configJson;
554 interfaceName = configJson[intfName];
555#endif
556
Ratan Guptabd303b12017-08-18 17:10:07 +0530557 std::vector<DbusInterface> interfaces;
558 interfaces.emplace_back(invNetworkIntf);
559
560 auto depth = 0;
561
Gunnar Mills57d9c502018-09-14 14:42:34 -0500562 auto mapperCall =
563 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530564
565 mapperCall.append(invRoot, depth, interfaces);
566
567 auto mapperReply = bus.call(mapperCall);
568 if (mapperReply.is_method_error())
569 {
570 log<level::ERR>("Error in mapper call");
571 elog<InternalFailure>();
572 }
573
574 ObjectTree objectTree;
575 mapperReply.read(objectTree);
576
577 if (objectTree.empty())
578 {
579 log<level::ERR>("No Object has implemented the interface",
580 entry("INTERFACE=%s", invNetworkIntf));
581 elog<InternalFailure>();
582 }
583
Alvin Wang38a63c32019-08-29 22:56:46 +0800584 DbusObjectPath objPath;
585 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530586
Alvin Wang38a63c32019-08-29 22:56:46 +0800587 if (1 == objectTree.size())
588 {
589 objPath = objectTree.begin()->first;
590 service = objectTree.begin()->second.begin()->first;
591 }
592 else
593 {
594 // If there are more than 2 objects, object path must contain the
595 // interface name
596 for (auto const& object : objectTree)
597 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530598 log<level::INFO>("interface",
599 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800600 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530601
602 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800603 {
604 objPath = object.first;
605 service = object.second.begin()->first;
606 break;
607 }
608 }
609
610 if (objPath.empty())
611 {
612 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530613 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800614 elog<InternalFailure>();
615 }
616 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530617
Gunnar Mills57d9c502018-09-14 14:42:34 -0500618 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
619 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530620
621 method.append(invNetworkIntf, "MACAddress");
622
623 auto reply = bus.call(method);
624 if (reply.is_method_error())
625 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500626 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530627 entry("PATH=%s", objPath.c_str()),
628 entry("INTERFACE=%s", invNetworkIntf));
629 elog<InternalFailure>();
630 }
631
William A. Kennington III1137a972019-04-20 20:49:58 -0700632 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530633 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700634 return fromString(std::get<std::string>(value));
635}
636
William A. Kennington III1c776022022-01-05 14:12:16 -0800637ether_addr fromString(const char* str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700638{
William A. Kennington III1c776022022-01-05 14:12:16 -0800639 std::string genstr;
Potin Laida0b1d42021-12-26 20:08:20 +0800640
641 // MAC address without colons
William A. Kennington III1c776022022-01-05 14:12:16 -0800642 std::string_view strv = str;
643 if (strv.size() == 12 && strv.find(":") == strv.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700644 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800645 genstr =
646 fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), strv.substr(0, 2),
647 strv.substr(2, 2), strv.substr(4, 2), strv.substr(6, 2),
648 strv.substr(8, 2), strv.substr(10, 2));
649 str = genstr.c_str();
William A. Kennington III1137a972019-04-20 20:49:58 -0700650 }
Potin Laida0b1d42021-12-26 20:08:20 +0800651
William A. Kennington III1c776022022-01-05 14:12:16 -0800652 ether_addr addr;
653 if (ether_aton_r(str, &addr) == nullptr)
Potin Laida0b1d42021-12-26 20:08:20 +0800654 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800655 throw std::invalid_argument("Invalid MAC Address");
Potin Laida0b1d42021-12-26 20:08:20 +0800656 }
William A. Kennington III1c776022022-01-05 14:12:16 -0800657 return addr;
Ratan Guptabd303b12017-08-18 17:10:07 +0530658}
659
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700660std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800661{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800662 char buf[18] = {0};
663 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
664 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
665 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
666 mac.ether_addr_octet[5]);
667 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800668}
669
William A. Kennington III1137a972019-04-20 20:49:58 -0700670bool isEmpty(const ether_addr& mac)
671{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700672 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700673}
674
675bool isMulticast(const ether_addr& mac)
676{
677 return mac.ether_addr_octet[0] & 0b1;
678}
679
680bool isUnicast(const ether_addr& mac)
681{
682 return !isEmpty(mac) && !isMulticast(mac);
683}
684
Gunnar Mills57d9c502018-09-14 14:42:34 -0500685} // namespace mac_address
686} // namespace network
687} // namespace phosphor