blob: fbe576d20cc1705a0b40f7b9a24ee98bf43a2f86 [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>
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -070012#include <cstdlib>
13#include <cstring>
Ratan Gupta56187e72017-08-13 09:40:14 +053014#include <experimental/filesystem>
Patrick Venture189d44e2018-07-09 12:30:59 -070015#include <iostream>
16#include <list>
17#include <phosphor-logging/elog-errors.hpp>
18#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080019#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070020#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070021#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070022#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070023#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053024
25namespace phosphor
26{
27namespace network
28{
Ratan Guptabc886292017-07-25 18:29:57 +053029
Ratan Gupta8804feb2017-05-25 10:49:57 +053030namespace
31{
32
33using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053034using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta56187e72017-08-13 09:40:14 +053035namespace fs = std::experimental::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053036
37uint8_t toV6Cidr(const std::string& subnetMask)
38{
39 uint8_t pos = 0;
40 uint8_t prevPos = 0;
41 uint8_t cidr = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 uint16_t buff{};
Ratan Gupta8804feb2017-05-25 10:49:57 +053043 do
44 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050045 // subnet mask look like ffff:ffff::
Ratan Gupta8804feb2017-05-25 10:49:57 +053046 // or ffff:c000::
Gunnar Mills57d9c502018-09-14 14:42:34 -050047 pos = subnetMask.find(":", prevPos);
Ratan Gupta8804feb2017-05-25 10:49:57 +053048 if (pos == std::string::npos)
49 {
50 break;
51 }
52
53 auto str = subnetMask.substr(prevPos, (pos - prevPos));
54 prevPos = pos + 1;
55
56 // String length is 0
57 if (!str.length())
58 {
59 return cidr;
60 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050061 // converts it into number.
Ratan Gupta8804feb2017-05-25 10:49:57 +053062 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
63 {
64 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050065 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053066
67 return 0;
68 }
69
70 // convert the number into bitset
71 // and check for how many ones are there.
72 // if we don't have all the ones then make
73 // sure that all the ones should be left justify.
74
75 if (__builtin_popcount(buff) != 16)
76 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050077 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
78 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053079 {
80 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050081 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053082
83 return 0;
84 }
85 cidr += __builtin_popcount(buff);
86 return cidr;
87 }
88
89 cidr += 16;
Gunnar Mills57d9c502018-09-14 14:42:34 -050090 } while (1);
Ratan Gupta8804feb2017-05-25 10:49:57 +053091
92 return cidr;
93}
Gunnar Mills57d9c502018-09-14 14:42:34 -050094} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053095
96uint8_t toCidr(int addressFamily, const std::string& subnetMask)
97{
98 if (addressFamily == AF_INET6)
99 {
100 return toV6Cidr(subnetMask);
101 }
102
103 uint32_t buff;
104
105 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
106 if (rc <= 0)
107 {
108 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500109 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530110 return 0;
111 }
112
113 buff = be32toh(buff);
114 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -0500115 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
116 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +0530117 {
118 return __builtin_popcount(buff);
119 }
120 else
121 {
122 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500123 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530124 return 0;
125 }
126}
127
128std::string toMask(int addressFamily, uint8_t prefix)
129{
130 if (addressFamily == AF_INET6)
131 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500132 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530133 return "";
134 }
135
136 if (prefix < 1 || prefix > 30)
137 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500138 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530139 return "";
140 }
141 /* Create the netmask from the number of bits */
142 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500143 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530144 {
145 mask |= 1 << (31 - i);
146 }
147 struct in_addr netmask;
148 netmask.s_addr = htonl(mask);
149 return inet_ntoa(netmask);
150}
151
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800152InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
153{
154 if (addressFamily == AF_INET)
155 {
156 struct in_addr ret;
157 if (buf.size() != sizeof(ret))
158 {
159 throw std::runtime_error("Buf not in_addr sized");
160 }
161 memcpy(&ret, buf.data(), sizeof(ret));
162 return ret;
163 }
164 else if (addressFamily == AF_INET6)
165 {
166 struct in6_addr ret;
167 if (buf.size() != sizeof(ret))
168 {
169 throw std::runtime_error("Buf not in6_addr sized");
170 }
171 memcpy(&ret, buf.data(), sizeof(ret));
172 return ret;
173 }
174
175 throw std::runtime_error("Unsupported address family");
176}
177
William A. Kennington III5058f572019-01-30 17:18:14 -0800178std::string toString(const InAddrAny& addr)
179{
180 std::string ip;
181 if (std::holds_alternative<struct in_addr>(addr))
182 {
183 const auto& v = std::get<struct in_addr>(addr);
184 ip.resize(INET_ADDRSTRLEN);
185 if (inet_ntop(AF_INET, &v, ip.data(), ip.size()) == NULL)
186 {
187 throw std::runtime_error("Failed to convert IP4 to string");
188 }
189 }
190 else if (std::holds_alternative<struct in6_addr>(addr))
191 {
192 const auto& v = std::get<struct in6_addr>(addr);
193 ip.resize(INET6_ADDRSTRLEN);
194 if (inet_ntop(AF_INET6, &v, ip.data(), ip.size()) == NULL)
195 {
196 throw std::runtime_error("Failed to convert IP6 to string");
197 }
198 }
199 else
200 {
201 throw std::runtime_error("Invalid addr type");
202 }
203 ip.resize(strlen(ip.c_str()));
204 return ip;
205}
206
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500207bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530208{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500209 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
210}
211
212bool isValidIP(int addressFamily, const std::string& address)
213{
214 unsigned char buf[sizeof(struct in6_addr)];
215
216 return inet_pton(addressFamily, address.c_str(), buf) > 0;
217}
218
219bool isValidPrefix(int addressFamily, uint8_t prefixLength)
220{
221 if (addressFamily == AF_INET)
222 {
223 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
224 prefixLength > IPV4_MAX_PREFIX_LENGTH)
225 {
226 return false;
227 }
228 }
229
230 if (addressFamily == AF_INET6)
231 {
232 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
233 prefixLength > IPV6_MAX_PREFIX_LENGTH)
234 {
235 return false;
236 }
237 }
238
239 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530240}
241
Ratan Gupta3681a502017-06-17 19:20:04 +0530242IntfAddrMap getInterfaceAddrs()
243{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500244 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530245 struct ifaddrs* ifaddr = nullptr;
246
247 // attempt to fill struct with ifaddrs
248 if (getifaddrs(&ifaddr) == -1)
249 {
250 auto error = errno;
251 log<level::ERR>("Error occurred during the getifaddrs call",
252 entry("ERRNO=%s", strerror(error)));
253 elog<InternalFailure>();
254 }
255
256 AddrPtr ifaddrPtr(ifaddr);
257 ifaddr = nullptr;
258
Gunnar Mills57d9c502018-09-14 14:42:34 -0500259 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530260
261 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
262 {
263 // walk interfaces
264 if (ifa->ifa_addr == nullptr)
265 {
266 continue;
267 }
268
269 // get only INET interfaces not ipv6
270 if (ifa->ifa_addr->sa_family == AF_INET ||
271 ifa->ifa_addr->sa_family == AF_INET6)
272 {
273 // if loopback, or not running ignore
274 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
275 !(ifa->ifa_flags & IFF_RUNNING))
276 {
277 continue;
278 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530279 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500280 AddrInfo info{};
281 char ip[INET6_ADDRSTRLEN] = {0};
282 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530283
284 if (ifa->ifa_addr->sa_family == AF_INET)
285 {
286
287 inet_ntop(ifa->ifa_addr->sa_family,
288 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500289 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530290
Gunnar Mills57d9c502018-09-14 14:42:34 -0500291 inet_ntop(
292 ifa->ifa_addr->sa_family,
293 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
294 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530295 }
296 else
297 {
298 inet_ntop(ifa->ifa_addr->sa_family,
299 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500300 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530301
Gunnar Mills57d9c502018-09-14 14:42:34 -0500302 inet_ntop(
303 ifa->ifa_addr->sa_family,
304 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
305 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530306 }
307
308 info.addrType = ifa->ifa_addr->sa_family;
309 info.ipaddress = ip;
310 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700311 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530312 }
313 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530314 return intfMap;
315}
316
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530317InterfaceList getInterfaces()
318{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500319 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530320 struct ifaddrs* ifaddr = nullptr;
321
322 // attempt to fill struct with ifaddrs
323 if (getifaddrs(&ifaddr) == -1)
324 {
325 auto error = errno;
326 log<level::ERR>("Error occurred during the getifaddrs call",
327 entry("ERRNO=%d", error));
328 elog<InternalFailure>();
329 }
330
331 AddrPtr ifaddrPtr(ifaddr);
332 ifaddr = nullptr;
333
334 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
335 {
336 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700337 // if loopback ignore
338 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530339 {
340 continue;
341 }
342 interfaces.emplace(ifa->ifa_name);
343 }
344 return interfaces;
345}
346
Ratan Guptabc886292017-07-25 18:29:57 +0530347void deleteInterface(const std::string& intf)
348{
349 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500350 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530351
352 if (pid == 0)
353 {
354
355 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
356 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500357 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530358 entry("INTF=%s", intf.c_str()));
359 elog<InternalFailure>();
360 }
361 else if (pid < 0)
362 {
363 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500364 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530365 elog<InternalFailure>();
366 }
367 else if (pid > 0)
368 {
369 while (waitpid(pid, &status, 0) == -1)
370 {
371 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500372 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530373 status = -1;
374 break;
375 }
376 }
377
Gunnar Mills57d9c502018-09-14 14:42:34 -0500378 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530379 {
380 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500381 entry("INTF=%s", intf.c_str()),
382 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530383 elog<InternalFailure>();
384 }
385 }
386}
387
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700388std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
389{
390 constexpr char ethPrefix[] = "eth";
391 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
392 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
393 {
394 return std::nullopt;
395 }
396 const auto intfSuffix = intf + ethPrefixLen;
397 if (intfSuffix[0] == '\0')
398 {
399 return std::nullopt;
400 }
401 char* end;
402 unsigned long idx = strtoul(intfSuffix, &end, 10);
403 if (end[0] != '\0')
404 {
405 return std::nullopt;
406 }
407 if (idx == 0)
408 {
409 return "ethaddr";
410 }
411 return "eth" + std::to_string(idx) + "addr";
412}
413
Ratan Gupta56187e72017-08-13 09:40:14 +0530414bool getDHCPValue(const std::string& confDir, const std::string& intf)
415{
416 bool dhcp = false;
417 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500418 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530419 fs::path confPath = confDir;
420 std::string fileName = systemd::config::networkFilePrefix + intf +
421 systemd::config::networkFileSuffix;
422 confPath /= fileName;
423
Ratan Guptac27170a2017-11-22 15:44:42 +0530424 auto rc = config::ReturnCode::SUCCESS;
425 config::ValueList values;
426 config::Parser parser(confPath.string());
427
428 std::tie(rc, values) = parser.getValues("Network", "DHCP");
429 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530430 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530431 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500432 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530433 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530434 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530435 // There will be only single value for DHCP key.
436 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530437 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530438 dhcp = true;
Ratan Gupta56187e72017-08-13 09:40:14 +0530439 }
440 return dhcp;
441}
442
Ratan Guptabd303b12017-08-18 17:10:07 +0530443namespace internal
444{
Ratan Gupta56187e72017-08-13 09:40:14 +0530445
Ratan Guptabd303b12017-08-18 17:10:07 +0530446void executeCommandinChildProcess(const char* path, char** args)
447{
448 using namespace std::string_literals;
449 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500450 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530451
452 if (pid == 0)
453 {
454 execv(path, args);
455 auto error = errno;
456 // create the command from var args.
457 std::string command = path + " "s;
458
Gunnar Mills57d9c502018-09-14 14:42:34 -0500459 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530460 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500461 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530462 }
463
464 log<level::ERR>("Couldn't exceute the command",
465 entry("ERRNO=%d", error),
466 entry("CMD=%s", command.c_str()));
467 elog<InternalFailure>();
468 }
469 else if (pid < 0)
470 {
471 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500472 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530473 elog<InternalFailure>();
474 }
475 else if (pid > 0)
476 {
477 while (waitpid(pid, &status, 0) == -1)
478 {
479 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500480 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530481 status = -1;
482 break;
483 }
484 }
485
Gunnar Mills57d9c502018-09-14 14:42:34 -0500486 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530487 {
488 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500489 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530490 {
491 command += args[i] + " "s;
492 }
493
494 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500495 entry("CMD=%s", command.c_str()),
496 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530497 elog<InternalFailure>();
498 }
499 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530500}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500501} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530502
503namespace mac_address
504{
505
506constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
507constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
508constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
509constexpr auto propIntf = "org.freedesktop.DBus.Properties";
510constexpr auto methodGet = "Get";
511
512using DbusObjectPath = std::string;
513using DbusService = std::string;
514using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500515using ObjectTree =
516 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530517
518constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
519constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500520 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530521constexpr auto invRoot = "/xyz/openbmc_project/inventory";
522
Alvin Wang38a63c32019-08-29 22:56:46 +0800523ether_addr getfromInventory(sdbusplus::bus::bus& bus,
524 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530525{
526 std::vector<DbusInterface> interfaces;
527 interfaces.emplace_back(invNetworkIntf);
528
529 auto depth = 0;
530
Gunnar Mills57d9c502018-09-14 14:42:34 -0500531 auto mapperCall =
532 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530533
534 mapperCall.append(invRoot, depth, interfaces);
535
536 auto mapperReply = bus.call(mapperCall);
537 if (mapperReply.is_method_error())
538 {
539 log<level::ERR>("Error in mapper call");
540 elog<InternalFailure>();
541 }
542
543 ObjectTree objectTree;
544 mapperReply.read(objectTree);
545
546 if (objectTree.empty())
547 {
548 log<level::ERR>("No Object has implemented the interface",
549 entry("INTERFACE=%s", invNetworkIntf));
550 elog<InternalFailure>();
551 }
552
Alvin Wang38a63c32019-08-29 22:56:46 +0800553 DbusObjectPath objPath;
554 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530555
Alvin Wang38a63c32019-08-29 22:56:46 +0800556 if (1 == objectTree.size())
557 {
558 objPath = objectTree.begin()->first;
559 service = objectTree.begin()->second.begin()->first;
560 }
561 else
562 {
563 // If there are more than 2 objects, object path must contain the
564 // interface name
565 for (auto const& object : objectTree)
566 {
567 log<level::INFO>("interface", entry("INT=%s", intfName.c_str()));
568 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
569 if (std::string::npos != object.first.find(intfName))
570 {
571 objPath = object.first;
572 service = object.second.begin()->first;
573 break;
574 }
575 }
576
577 if (objPath.empty())
578 {
579 log<level::ERR>("Can't find the object for the interface",
580 entry("intfName=%s", intfName.c_str()));
581 elog<InternalFailure>();
582 }
583 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530584
Gunnar Mills57d9c502018-09-14 14:42:34 -0500585 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
586 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530587
588 method.append(invNetworkIntf, "MACAddress");
589
590 auto reply = bus.call(method);
591 if (reply.is_method_error())
592 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500593 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530594 entry("PATH=%s", objPath.c_str()),
595 entry("INTERFACE=%s", invNetworkIntf));
596 elog<InternalFailure>();
597 }
598
William A. Kennington III1137a972019-04-20 20:49:58 -0700599 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530600 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700601 return fromString(std::get<std::string>(value));
602}
603
604ether_addr fromString(const char* str)
605{
606 struct ether_addr* mac = ether_aton(str);
607 if (mac == nullptr)
608 {
609 throw std::runtime_error("Invalid mac address string");
610 }
611 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530612}
613
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700614std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800615{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800616 char buf[18] = {0};
617 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
618 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
619 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
620 mac.ether_addr_octet[5]);
621 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800622}
623
William A. Kennington III1137a972019-04-20 20:49:58 -0700624bool isEmpty(const ether_addr& mac)
625{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700626 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700627}
628
629bool isMulticast(const ether_addr& mac)
630{
631 return mac.ether_addr_octet[0] & 0b1;
632}
633
634bool isUnicast(const ether_addr& mac)
635{
636 return !isEmpty(mac) && !isMulticast(mac);
637}
638
639bool isLocalAdmin(const ether_addr& mac)
640{
641 return mac.ether_addr_octet[0] & 0b10;
642}
643
Gunnar Mills57d9c502018-09-14 14:42:34 -0500644} // namespace mac_address
645} // namespace network
646} // namespace phosphor