blob: 34df649114687d4160b8b360bf3e7747cac3d10f [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>
Manojkiran Edacc099a82020-05-11 14:25:16 +053018#include <nlohmann/json.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070019#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080021#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070022#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070023#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070024#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070025#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053026
27namespace phosphor
28{
29namespace network
30{
Ratan Guptabc886292017-07-25 18:29:57 +053031
Ratan Gupta8804feb2017-05-25 10:49:57 +053032using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053033using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053034namespace fs = std::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053035
Lei YU3894ce72021-03-18 14:53:42 +080036namespace internal
37{
38
39void executeCommandinChildProcess(const char* path, char** args)
40{
41 using namespace std::string_literals;
42 pid_t pid = fork();
43 int status{};
44
45 if (pid == 0)
46 {
47 execv(path, args);
48 auto error = errno;
49 // create the command from var args.
50 std::string command = path + " "s;
51
52 for (int i = 0; args[i]; i++)
53 {
54 command += args[i] + " "s;
55 }
56
57 log<level::ERR>("Couldn't exceute the command",
58 entry("ERRNO=%d", error),
59 entry("CMD=%s", command.c_str()));
60 elog<InternalFailure>();
61 }
62 else if (pid < 0)
63 {
64 auto error = errno;
65 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
66 elog<InternalFailure>();
67 }
68 else if (pid > 0)
69 {
70 while (waitpid(pid, &status, 0) == -1)
71 {
72 if (errno != EINTR)
73 { // Error other than EINTR
74 status = -1;
75 break;
76 }
77 }
78
79 if (status < 0)
80 {
81 std::string command = path + " "s;
82 for (int i = 0; args[i]; i++)
83 {
84 command += args[i] + " "s;
85 }
86
87 log<level::ERR>("Unable to execute the command",
88 entry("CMD=%s", command.c_str()),
89 entry("STATUS=%d", status));
90 elog<InternalFailure>();
91 }
92 }
93}
94
Lei YU307554e2021-03-18 14:56:50 +080095/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070096std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +080097{
98 auto r = std::getenv("IGNORED_INTERFACES");
99 if (r == nullptr)
100 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700101 return "";
Lei YU307554e2021-03-18 14:56:50 +0800102 }
103 return r;
104}
105
106/** @brief Parse the comma separated interface names */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700107std::set<std::string_view> parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800108{
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700109 std::set<std::string_view> result;
110 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800111 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700112 auto sep = interfaces.find(',');
113 auto interface = interfaces.substr(0, sep);
114 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800115 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700116 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800117 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700118 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800119 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700120 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800121 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700122 if (!interface.empty())
123 {
124 result.insert(interface);
125 }
126 if (sep == interfaces.npos)
127 {
128 break;
129 }
130 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800131 }
132 return result;
133}
134
135/** @brief Get the ignored interfaces */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700136const std::set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800137{
138 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
139 return ignoredInterfaces;
140}
141
Lei YU3894ce72021-03-18 14:53:42 +0800142} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530143
144uint8_t toCidr(int addressFamily, const std::string& subnetMask)
145{
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700146 uint32_t subnet[sizeof(in6_addr) / sizeof(uint32_t)];
147 if (inet_pton(addressFamily, subnetMask.c_str(), &subnet) != 1)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530148 {
149 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500150 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530151 return 0;
152 }
153
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700154 static_assert(sizeof(in6_addr) % sizeof(uint32_t) == 0);
155 static_assert(sizeof(in_addr) % sizeof(uint32_t) == 0);
156 auto i = (addressFamily == AF_INET ? sizeof(in_addr) : sizeof(in6_addr)) /
157 sizeof(uint32_t);
158 while (i > 0)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530159 {
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700160 if (subnet[--i] != 0)
161 {
162 auto v = be32toh(subnet[i]);
163 static_assert(sizeof(unsigned) == sizeof(uint32_t));
164 auto trailing = __builtin_ctz(v);
165 auto ret = (i + 1) * 32 - trailing;
166 bool valid = ~v == 0 || 32 == trailing + __builtin_clz(~v);
167 while (i > 0 && (valid = (~subnet[--i] == 0) && valid))
168 ;
169 if (!valid)
170 {
171 log<level::ERR>("Invalid netmask",
172 entry("SUBNETMASK=%s", subnetMask.c_str()));
173 return 0;
174 }
175 return ret;
176 }
Ratan Gupta8804feb2017-05-25 10:49:57 +0530177 }
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700178 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530179}
180
181std::string toMask(int addressFamily, uint8_t prefix)
182{
183 if (addressFamily == AF_INET6)
184 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500185 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530186 return "";
187 }
188
189 if (prefix < 1 || prefix > 30)
190 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500191 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530192 return "";
193 }
194 /* Create the netmask from the number of bits */
195 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500196 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530197 {
198 mask |= 1 << (31 - i);
199 }
200 struct in_addr netmask;
201 netmask.s_addr = htonl(mask);
202 return inet_ntoa(netmask);
203}
204
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800205InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
206{
207 if (addressFamily == AF_INET)
208 {
209 struct in_addr ret;
210 if (buf.size() != sizeof(ret))
211 {
212 throw std::runtime_error("Buf not in_addr sized");
213 }
214 memcpy(&ret, buf.data(), sizeof(ret));
215 return ret;
216 }
217 else if (addressFamily == AF_INET6)
218 {
219 struct in6_addr ret;
220 if (buf.size() != sizeof(ret))
221 {
222 throw std::runtime_error("Buf not in6_addr sized");
223 }
224 memcpy(&ret, buf.data(), sizeof(ret));
225 return ret;
226 }
227
228 throw std::runtime_error("Unsupported address family");
229}
230
Alexander Filippov983da552021-02-08 15:26:54 +0300231std::string toString(const struct in_addr& addr)
232{
233 std::string ip(INET_ADDRSTRLEN, '\0');
234 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
235 {
236 throw std::runtime_error("Failed to convert IP4 to string");
237 }
238
239 ip.resize(strlen(ip.c_str()));
240 return ip;
241}
242
243std::string toString(const struct in6_addr& addr)
244{
245 std::string ip(INET6_ADDRSTRLEN, '\0');
246 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
247 {
248 throw std::runtime_error("Failed to convert IP6 to string");
249 }
250
251 ip.resize(strlen(ip.c_str()));
252 return ip;
253}
254
William A. Kennington III5058f572019-01-30 17:18:14 -0800255std::string toString(const InAddrAny& addr)
256{
William A. Kennington III5058f572019-01-30 17:18:14 -0800257 if (std::holds_alternative<struct in_addr>(addr))
258 {
259 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300260 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800261 }
262 else if (std::holds_alternative<struct in6_addr>(addr))
263 {
264 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300265 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800266 }
Alexander Filippov983da552021-02-08 15:26:54 +0300267
268 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800269}
270
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500271bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530272{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500273 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
274}
275
276bool isValidIP(int addressFamily, const std::string& address)
277{
278 unsigned char buf[sizeof(struct in6_addr)];
279
280 return inet_pton(addressFamily, address.c_str(), buf) > 0;
281}
282
283bool isValidPrefix(int addressFamily, uint8_t prefixLength)
284{
285 if (addressFamily == AF_INET)
286 {
287 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
288 prefixLength > IPV4_MAX_PREFIX_LENGTH)
289 {
290 return false;
291 }
292 }
293
294 if (addressFamily == AF_INET6)
295 {
296 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
297 prefixLength > IPV6_MAX_PREFIX_LENGTH)
298 {
299 return false;
300 }
301 }
302
303 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530304}
305
Ratan Gupta3681a502017-06-17 19:20:04 +0530306IntfAddrMap getInterfaceAddrs()
307{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500308 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530309 struct ifaddrs* ifaddr = nullptr;
310
311 // attempt to fill struct with ifaddrs
312 if (getifaddrs(&ifaddr) == -1)
313 {
314 auto error = errno;
315 log<level::ERR>("Error occurred during the getifaddrs call",
316 entry("ERRNO=%s", strerror(error)));
317 elog<InternalFailure>();
318 }
319
320 AddrPtr ifaddrPtr(ifaddr);
321 ifaddr = nullptr;
322
Gunnar Mills57d9c502018-09-14 14:42:34 -0500323 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530324
325 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
326 {
327 // walk interfaces
328 if (ifa->ifa_addr == nullptr)
329 {
330 continue;
331 }
332
333 // get only INET interfaces not ipv6
334 if (ifa->ifa_addr->sa_family == AF_INET ||
335 ifa->ifa_addr->sa_family == AF_INET6)
336 {
337 // if loopback, or not running ignore
338 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
339 !(ifa->ifa_flags & IFF_RUNNING))
340 {
341 continue;
342 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530343 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500344 AddrInfo info{};
345 char ip[INET6_ADDRSTRLEN] = {0};
346 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530347
348 if (ifa->ifa_addr->sa_family == AF_INET)
349 {
350
351 inet_ntop(ifa->ifa_addr->sa_family,
352 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500353 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530354
Gunnar Mills57d9c502018-09-14 14:42:34 -0500355 inet_ntop(
356 ifa->ifa_addr->sa_family,
357 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
358 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530359 }
360 else
361 {
362 inet_ntop(ifa->ifa_addr->sa_family,
363 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500364 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530365
Gunnar Mills57d9c502018-09-14 14:42:34 -0500366 inet_ntop(
367 ifa->ifa_addr->sa_family,
368 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
369 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530370 }
371
372 info.addrType = ifa->ifa_addr->sa_family;
373 info.ipaddress = ip;
374 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700375 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530376 }
377 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530378 return intfMap;
379}
380
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530381InterfaceList getInterfaces()
382{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500383 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530384 struct ifaddrs* ifaddr = nullptr;
385
386 // attempt to fill struct with ifaddrs
387 if (getifaddrs(&ifaddr) == -1)
388 {
389 auto error = errno;
390 log<level::ERR>("Error occurred during the getifaddrs call",
391 entry("ERRNO=%d", error));
392 elog<InternalFailure>();
393 }
394
395 AddrPtr ifaddrPtr(ifaddr);
396 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800397 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530398
399 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
400 {
401 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700402 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800403 if (ifa->ifa_flags & IFF_LOOPBACK ||
404 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530405 {
406 continue;
407 }
408 interfaces.emplace(ifa->ifa_name);
409 }
410 return interfaces;
411}
412
Ratan Guptabc886292017-07-25 18:29:57 +0530413void deleteInterface(const std::string& intf)
414{
415 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500416 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530417
418 if (pid == 0)
419 {
420
421 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
422 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500423 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530424 entry("INTF=%s", intf.c_str()));
425 elog<InternalFailure>();
426 }
427 else if (pid < 0)
428 {
429 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500430 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530431 elog<InternalFailure>();
432 }
433 else if (pid > 0)
434 {
435 while (waitpid(pid, &status, 0) == -1)
436 {
437 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500438 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530439 status = -1;
440 break;
441 }
442 }
443
Gunnar Mills57d9c502018-09-14 14:42:34 -0500444 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530445 {
446 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500447 entry("INTF=%s", intf.c_str()),
448 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530449 elog<InternalFailure>();
450 }
451 }
452}
453
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700454std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
455{
456 constexpr char ethPrefix[] = "eth";
457 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
458 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
459 {
460 return std::nullopt;
461 }
462 const auto intfSuffix = intf + ethPrefixLen;
463 if (intfSuffix[0] == '\0')
464 {
465 return std::nullopt;
466 }
467 char* end;
468 unsigned long idx = strtoul(intfSuffix, &end, 10);
469 if (end[0] != '\0')
470 {
471 return std::nullopt;
472 }
473 if (idx == 0)
474 {
475 return "ethaddr";
476 }
477 return "eth" + std::to_string(idx) + "addr";
478}
479
Johnathan Mantey817012a2020-01-30 15:07:39 -0800480EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
481 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530482{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800483 EthernetInterfaceIntf::DHCPConf dhcp =
484 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530485 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500486 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530487 fs::path confPath = confDir;
488 std::string fileName = systemd::config::networkFilePrefix + intf +
489 systemd::config::networkFileSuffix;
490 confPath /= fileName;
491
Ratan Guptac27170a2017-11-22 15:44:42 +0530492 auto rc = config::ReturnCode::SUCCESS;
493 config::ValueList values;
494 config::Parser parser(confPath.string());
495
496 std::tie(rc, values) = parser.getValues("Network", "DHCP");
497 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530498 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530499 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500500 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530501 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530502 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530503 // There will be only single value for DHCP key.
504 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530505 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800506 dhcp = EthernetInterfaceIntf::DHCPConf::both;
507 }
508 else if (values[0] == "ipv4")
509 {
510 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
511 }
512 else if (values[0] == "ipv6")
513 {
514 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530515 }
516 return dhcp;
517}
518
Ratan Guptabd303b12017-08-18 17:10:07 +0530519namespace mac_address
520{
521
522constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
523constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
524constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
525constexpr auto propIntf = "org.freedesktop.DBus.Properties";
526constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530527constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530528
529using DbusObjectPath = std::string;
530using DbusService = std::string;
531using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500532using ObjectTree =
533 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530534
535constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
536constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500537 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530538constexpr auto invRoot = "/xyz/openbmc_project/inventory";
539
Alvin Wang38a63c32019-08-29 22:56:46 +0800540ether_addr getfromInventory(sdbusplus::bus::bus& bus,
541 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530542{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530543
544 std::string interfaceName = intfName;
545
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700546#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530547 // load the config JSON from the Read Only Path
548 std::ifstream in(configFile);
549 nlohmann::json configJson;
550 in >> configJson;
551 interfaceName = configJson[intfName];
552#endif
553
Ratan Guptabd303b12017-08-18 17:10:07 +0530554 std::vector<DbusInterface> interfaces;
555 interfaces.emplace_back(invNetworkIntf);
556
557 auto depth = 0;
558
Gunnar Mills57d9c502018-09-14 14:42:34 -0500559 auto mapperCall =
560 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530561
562 mapperCall.append(invRoot, depth, interfaces);
563
564 auto mapperReply = bus.call(mapperCall);
565 if (mapperReply.is_method_error())
566 {
567 log<level::ERR>("Error in mapper call");
568 elog<InternalFailure>();
569 }
570
571 ObjectTree objectTree;
572 mapperReply.read(objectTree);
573
574 if (objectTree.empty())
575 {
576 log<level::ERR>("No Object has implemented the interface",
577 entry("INTERFACE=%s", invNetworkIntf));
578 elog<InternalFailure>();
579 }
580
Alvin Wang38a63c32019-08-29 22:56:46 +0800581 DbusObjectPath objPath;
582 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530583
Alvin Wang38a63c32019-08-29 22:56:46 +0800584 if (1 == objectTree.size())
585 {
586 objPath = objectTree.begin()->first;
587 service = objectTree.begin()->second.begin()->first;
588 }
589 else
590 {
591 // If there are more than 2 objects, object path must contain the
592 // interface name
593 for (auto const& object : objectTree)
594 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530595 log<level::INFO>("interface",
596 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800597 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530598
599 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800600 {
601 objPath = object.first;
602 service = object.second.begin()->first;
603 break;
604 }
605 }
606
607 if (objPath.empty())
608 {
609 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530610 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800611 elog<InternalFailure>();
612 }
613 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530614
Gunnar Mills57d9c502018-09-14 14:42:34 -0500615 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
616 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530617
618 method.append(invNetworkIntf, "MACAddress");
619
620 auto reply = bus.call(method);
621 if (reply.is_method_error())
622 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500623 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530624 entry("PATH=%s", objPath.c_str()),
625 entry("INTERFACE=%s", invNetworkIntf));
626 elog<InternalFailure>();
627 }
628
William A. Kennington III1137a972019-04-20 20:49:58 -0700629 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530630 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700631 return fromString(std::get<std::string>(value));
632}
633
634ether_addr fromString(const char* str)
635{
636 struct ether_addr* mac = ether_aton(str);
637 if (mac == nullptr)
638 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600639 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700640 }
641 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530642}
643
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700644std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800645{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800646 char buf[18] = {0};
647 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
648 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
649 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
650 mac.ether_addr_octet[5]);
651 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800652}
653
William A. Kennington III1137a972019-04-20 20:49:58 -0700654bool isEmpty(const ether_addr& mac)
655{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700656 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700657}
658
659bool isMulticast(const ether_addr& mac)
660{
661 return mac.ether_addr_octet[0] & 0b1;
662}
663
664bool isUnicast(const ether_addr& mac)
665{
666 return !isEmpty(mac) && !isMulticast(mac);
667}
668
Gunnar Mills57d9c502018-09-14 14:42:34 -0500669} // namespace mac_address
670} // namespace network
671} // namespace phosphor