blob: 6cc42d1fb18c3c1b1598446adb2622a860fb8349 [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>
Lei YU307554e2021-03-18 14:56:50 +080021#include <sstream>
William A. Kennington III5058f572019-01-30 17:18:14 -080022#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070023#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070024#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070025#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070026#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053027
28namespace phosphor
29{
30namespace network
31{
Ratan Guptabc886292017-07-25 18:29:57 +053032
Ratan Gupta8804feb2017-05-25 10:49:57 +053033using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053034using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053035namespace fs = std::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053036
Lei YU3894ce72021-03-18 14:53:42 +080037namespace internal
38{
39
40void executeCommandinChildProcess(const char* path, char** args)
41{
42 using namespace std::string_literals;
43 pid_t pid = fork();
44 int status{};
45
46 if (pid == 0)
47 {
48 execv(path, args);
49 auto error = errno;
50 // create the command from var args.
51 std::string command = path + " "s;
52
53 for (int i = 0; args[i]; i++)
54 {
55 command += args[i] + " "s;
56 }
57
58 log<level::ERR>("Couldn't exceute the command",
59 entry("ERRNO=%d", error),
60 entry("CMD=%s", command.c_str()));
61 elog<InternalFailure>();
62 }
63 else if (pid < 0)
64 {
65 auto error = errno;
66 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
67 elog<InternalFailure>();
68 }
69 else if (pid > 0)
70 {
71 while (waitpid(pid, &status, 0) == -1)
72 {
73 if (errno != EINTR)
74 { // Error other than EINTR
75 status = -1;
76 break;
77 }
78 }
79
80 if (status < 0)
81 {
82 std::string command = path + " "s;
83 for (int i = 0; args[i]; i++)
84 {
85 command += args[i] + " "s;
86 }
87
88 log<level::ERR>("Unable to execute the command",
89 entry("CMD=%s", command.c_str()),
90 entry("STATUS=%d", status));
91 elog<InternalFailure>();
92 }
93 }
94}
95
Lei YU307554e2021-03-18 14:56:50 +080096/** @brief Get ignored interfaces from environment */
97std::string getIgnoredInterfacesEnv()
98{
99 auto r = std::getenv("IGNORED_INTERFACES");
100 if (r == nullptr)
101 {
102 return {};
103 }
104 return r;
105}
106
107/** @brief Parse the comma separated interface names */
108std::set<std::string> parseInterfaces(const std::string& interfaces)
109{
110 std::set<std::string> result;
111 std::stringstream ss(interfaces);
112 while (ss.good())
113 {
114 std::string str;
115 std::getline(ss, str, ',');
116 // Trim str
117 if (!str.empty())
118 {
119 str.erase(
120 std::remove_if(str.begin(), str.end(),
121 [](unsigned char c) { return std::isspace(c); }),
122 str.end());
123 }
124 if (!str.empty())
125 {
126 result.insert(str);
127 }
128 }
129 return result;
130}
131
132/** @brief Get the ignored interfaces */
133const std::set<std::string>& getIgnoredInterfaces()
134{
135 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
136 return ignoredInterfaces;
137}
138
Lei YU3894ce72021-03-18 14:53:42 +0800139} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530140
141uint8_t toCidr(int addressFamily, const std::string& subnetMask)
142{
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700143 uint32_t subnet[sizeof(in6_addr) / sizeof(uint32_t)];
144 if (inet_pton(addressFamily, subnetMask.c_str(), &subnet) != 1)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530145 {
146 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500147 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530148 return 0;
149 }
150
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700151 static_assert(sizeof(in6_addr) % sizeof(uint32_t) == 0);
152 static_assert(sizeof(in_addr) % sizeof(uint32_t) == 0);
153 auto i = (addressFamily == AF_INET ? sizeof(in_addr) : sizeof(in6_addr)) /
154 sizeof(uint32_t);
155 while (i > 0)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530156 {
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700157 if (subnet[--i] != 0)
158 {
159 auto v = be32toh(subnet[i]);
160 static_assert(sizeof(unsigned) == sizeof(uint32_t));
161 auto trailing = __builtin_ctz(v);
162 auto ret = (i + 1) * 32 - trailing;
163 bool valid = ~v == 0 || 32 == trailing + __builtin_clz(~v);
164 while (i > 0 && (valid = (~subnet[--i] == 0) && valid))
165 ;
166 if (!valid)
167 {
168 log<level::ERR>("Invalid netmask",
169 entry("SUBNETMASK=%s", subnetMask.c_str()));
170 return 0;
171 }
172 return ret;
173 }
Ratan Gupta8804feb2017-05-25 10:49:57 +0530174 }
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700175 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530176}
177
178std::string toMask(int addressFamily, uint8_t prefix)
179{
180 if (addressFamily == AF_INET6)
181 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500182 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530183 return "";
184 }
185
186 if (prefix < 1 || prefix > 30)
187 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500188 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530189 return "";
190 }
191 /* Create the netmask from the number of bits */
192 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500193 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530194 {
195 mask |= 1 << (31 - i);
196 }
197 struct in_addr netmask;
198 netmask.s_addr = htonl(mask);
199 return inet_ntoa(netmask);
200}
201
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800202InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
203{
204 if (addressFamily == AF_INET)
205 {
206 struct in_addr ret;
207 if (buf.size() != sizeof(ret))
208 {
209 throw std::runtime_error("Buf not in_addr sized");
210 }
211 memcpy(&ret, buf.data(), sizeof(ret));
212 return ret;
213 }
214 else if (addressFamily == AF_INET6)
215 {
216 struct in6_addr ret;
217 if (buf.size() != sizeof(ret))
218 {
219 throw std::runtime_error("Buf not in6_addr sized");
220 }
221 memcpy(&ret, buf.data(), sizeof(ret));
222 return ret;
223 }
224
225 throw std::runtime_error("Unsupported address family");
226}
227
Alexander Filippov983da552021-02-08 15:26:54 +0300228std::string toString(const struct in_addr& addr)
229{
230 std::string ip(INET_ADDRSTRLEN, '\0');
231 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
232 {
233 throw std::runtime_error("Failed to convert IP4 to string");
234 }
235
236 ip.resize(strlen(ip.c_str()));
237 return ip;
238}
239
240std::string toString(const struct in6_addr& addr)
241{
242 std::string ip(INET6_ADDRSTRLEN, '\0');
243 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
244 {
245 throw std::runtime_error("Failed to convert IP6 to string");
246 }
247
248 ip.resize(strlen(ip.c_str()));
249 return ip;
250}
251
William A. Kennington III5058f572019-01-30 17:18:14 -0800252std::string toString(const InAddrAny& addr)
253{
William A. Kennington III5058f572019-01-30 17:18:14 -0800254 if (std::holds_alternative<struct in_addr>(addr))
255 {
256 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300257 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800258 }
259 else if (std::holds_alternative<struct in6_addr>(addr))
260 {
261 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300262 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800263 }
Alexander Filippov983da552021-02-08 15:26:54 +0300264
265 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800266}
267
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500268bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530269{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500270 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
271}
272
273bool isValidIP(int addressFamily, const std::string& address)
274{
275 unsigned char buf[sizeof(struct in6_addr)];
276
277 return inet_pton(addressFamily, address.c_str(), buf) > 0;
278}
279
280bool isValidPrefix(int addressFamily, uint8_t prefixLength)
281{
282 if (addressFamily == AF_INET)
283 {
284 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
285 prefixLength > IPV4_MAX_PREFIX_LENGTH)
286 {
287 return false;
288 }
289 }
290
291 if (addressFamily == AF_INET6)
292 {
293 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
294 prefixLength > IPV6_MAX_PREFIX_LENGTH)
295 {
296 return false;
297 }
298 }
299
300 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530301}
302
Ratan Gupta3681a502017-06-17 19:20:04 +0530303IntfAddrMap getInterfaceAddrs()
304{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500305 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530306 struct ifaddrs* ifaddr = nullptr;
307
308 // attempt to fill struct with ifaddrs
309 if (getifaddrs(&ifaddr) == -1)
310 {
311 auto error = errno;
312 log<level::ERR>("Error occurred during the getifaddrs call",
313 entry("ERRNO=%s", strerror(error)));
314 elog<InternalFailure>();
315 }
316
317 AddrPtr ifaddrPtr(ifaddr);
318 ifaddr = nullptr;
319
Gunnar Mills57d9c502018-09-14 14:42:34 -0500320 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530321
322 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
323 {
324 // walk interfaces
325 if (ifa->ifa_addr == nullptr)
326 {
327 continue;
328 }
329
330 // get only INET interfaces not ipv6
331 if (ifa->ifa_addr->sa_family == AF_INET ||
332 ifa->ifa_addr->sa_family == AF_INET6)
333 {
334 // if loopback, or not running ignore
335 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
336 !(ifa->ifa_flags & IFF_RUNNING))
337 {
338 continue;
339 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530340 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500341 AddrInfo info{};
342 char ip[INET6_ADDRSTRLEN] = {0};
343 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530344
345 if (ifa->ifa_addr->sa_family == AF_INET)
346 {
347
348 inet_ntop(ifa->ifa_addr->sa_family,
349 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500350 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530351
Gunnar Mills57d9c502018-09-14 14:42:34 -0500352 inet_ntop(
353 ifa->ifa_addr->sa_family,
354 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
355 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530356 }
357 else
358 {
359 inet_ntop(ifa->ifa_addr->sa_family,
360 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500361 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530362
Gunnar Mills57d9c502018-09-14 14:42:34 -0500363 inet_ntop(
364 ifa->ifa_addr->sa_family,
365 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
366 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530367 }
368
369 info.addrType = ifa->ifa_addr->sa_family;
370 info.ipaddress = ip;
371 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700372 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530373 }
374 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530375 return intfMap;
376}
377
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530378InterfaceList getInterfaces()
379{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500380 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530381 struct ifaddrs* ifaddr = nullptr;
382
383 // attempt to fill struct with ifaddrs
384 if (getifaddrs(&ifaddr) == -1)
385 {
386 auto error = errno;
387 log<level::ERR>("Error occurred during the getifaddrs call",
388 entry("ERRNO=%d", error));
389 elog<InternalFailure>();
390 }
391
392 AddrPtr ifaddrPtr(ifaddr);
393 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800394 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530395
396 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
397 {
398 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700399 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800400 if (ifa->ifa_flags & IFF_LOOPBACK ||
401 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530402 {
403 continue;
404 }
405 interfaces.emplace(ifa->ifa_name);
406 }
407 return interfaces;
408}
409
Ratan Guptabc886292017-07-25 18:29:57 +0530410void deleteInterface(const std::string& intf)
411{
412 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500413 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530414
415 if (pid == 0)
416 {
417
418 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
419 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500420 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530421 entry("INTF=%s", intf.c_str()));
422 elog<InternalFailure>();
423 }
424 else if (pid < 0)
425 {
426 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530428 elog<InternalFailure>();
429 }
430 else if (pid > 0)
431 {
432 while (waitpid(pid, &status, 0) == -1)
433 {
434 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500435 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530436 status = -1;
437 break;
438 }
439 }
440
Gunnar Mills57d9c502018-09-14 14:42:34 -0500441 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530442 {
443 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500444 entry("INTF=%s", intf.c_str()),
445 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530446 elog<InternalFailure>();
447 }
448 }
449}
450
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700451std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
452{
453 constexpr char ethPrefix[] = "eth";
454 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
455 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
456 {
457 return std::nullopt;
458 }
459 const auto intfSuffix = intf + ethPrefixLen;
460 if (intfSuffix[0] == '\0')
461 {
462 return std::nullopt;
463 }
464 char* end;
465 unsigned long idx = strtoul(intfSuffix, &end, 10);
466 if (end[0] != '\0')
467 {
468 return std::nullopt;
469 }
470 if (idx == 0)
471 {
472 return "ethaddr";
473 }
474 return "eth" + std::to_string(idx) + "addr";
475}
476
Johnathan Mantey817012a2020-01-30 15:07:39 -0800477EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
478 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530479{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800480 EthernetInterfaceIntf::DHCPConf dhcp =
481 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530482 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500483 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530484 fs::path confPath = confDir;
485 std::string fileName = systemd::config::networkFilePrefix + intf +
486 systemd::config::networkFileSuffix;
487 confPath /= fileName;
488
Ratan Guptac27170a2017-11-22 15:44:42 +0530489 auto rc = config::ReturnCode::SUCCESS;
490 config::ValueList values;
491 config::Parser parser(confPath.string());
492
493 std::tie(rc, values) = parser.getValues("Network", "DHCP");
494 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530495 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530496 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500497 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530498 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530499 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530500 // There will be only single value for DHCP key.
501 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530502 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800503 dhcp = EthernetInterfaceIntf::DHCPConf::both;
504 }
505 else if (values[0] == "ipv4")
506 {
507 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
508 }
509 else if (values[0] == "ipv6")
510 {
511 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530512 }
513 return dhcp;
514}
515
Ratan Guptabd303b12017-08-18 17:10:07 +0530516namespace mac_address
517{
518
519constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
520constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
521constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
522constexpr auto propIntf = "org.freedesktop.DBus.Properties";
523constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530524constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530525
526using DbusObjectPath = std::string;
527using DbusService = std::string;
528using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500529using ObjectTree =
530 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530531
532constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
533constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500534 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530535constexpr auto invRoot = "/xyz/openbmc_project/inventory";
536
Alvin Wang38a63c32019-08-29 22:56:46 +0800537ether_addr getfromInventory(sdbusplus::bus::bus& bus,
538 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530539{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530540
541 std::string interfaceName = intfName;
542
543#if SYNC_MAC_FROM_INVENTORY
544 // load the config JSON from the Read Only Path
545 std::ifstream in(configFile);
546 nlohmann::json configJson;
547 in >> configJson;
548 interfaceName = configJson[intfName];
549#endif
550
Ratan Guptabd303b12017-08-18 17:10:07 +0530551 std::vector<DbusInterface> interfaces;
552 interfaces.emplace_back(invNetworkIntf);
553
554 auto depth = 0;
555
Gunnar Mills57d9c502018-09-14 14:42:34 -0500556 auto mapperCall =
557 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530558
559 mapperCall.append(invRoot, depth, interfaces);
560
561 auto mapperReply = bus.call(mapperCall);
562 if (mapperReply.is_method_error())
563 {
564 log<level::ERR>("Error in mapper call");
565 elog<InternalFailure>();
566 }
567
568 ObjectTree objectTree;
569 mapperReply.read(objectTree);
570
571 if (objectTree.empty())
572 {
573 log<level::ERR>("No Object has implemented the interface",
574 entry("INTERFACE=%s", invNetworkIntf));
575 elog<InternalFailure>();
576 }
577
Alvin Wang38a63c32019-08-29 22:56:46 +0800578 DbusObjectPath objPath;
579 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530580
Alvin Wang38a63c32019-08-29 22:56:46 +0800581 if (1 == objectTree.size())
582 {
583 objPath = objectTree.begin()->first;
584 service = objectTree.begin()->second.begin()->first;
585 }
586 else
587 {
588 // If there are more than 2 objects, object path must contain the
589 // interface name
590 for (auto const& object : objectTree)
591 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530592 log<level::INFO>("interface",
593 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800594 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530595
596 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800597 {
598 objPath = object.first;
599 service = object.second.begin()->first;
600 break;
601 }
602 }
603
604 if (objPath.empty())
605 {
606 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530607 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800608 elog<InternalFailure>();
609 }
610 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530611
Gunnar Mills57d9c502018-09-14 14:42:34 -0500612 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
613 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530614
615 method.append(invNetworkIntf, "MACAddress");
616
617 auto reply = bus.call(method);
618 if (reply.is_method_error())
619 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500620 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530621 entry("PATH=%s", objPath.c_str()),
622 entry("INTERFACE=%s", invNetworkIntf));
623 elog<InternalFailure>();
624 }
625
William A. Kennington III1137a972019-04-20 20:49:58 -0700626 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530627 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700628 return fromString(std::get<std::string>(value));
629}
630
631ether_addr fromString(const char* str)
632{
633 struct ether_addr* mac = ether_aton(str);
634 if (mac == nullptr)
635 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600636 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700637 }
638 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530639}
640
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700641std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800642{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800643 char buf[18] = {0};
644 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
645 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
646 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
647 mac.ether_addr_octet[5]);
648 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800649}
650
William A. Kennington III1137a972019-04-20 20:49:58 -0700651bool isEmpty(const ether_addr& mac)
652{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700653 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700654}
655
656bool isMulticast(const ether_addr& mac)
657{
658 return mac.ether_addr_octet[0] & 0b1;
659}
660
661bool isUnicast(const ether_addr& mac)
662{
663 return !isEmpty(mac) && !isMulticast(mac);
664}
665
Gunnar Mills57d9c502018-09-14 14:42:34 -0500666} // namespace mac_address
667} // namespace network
668} // namespace phosphor