blob: a17bc5d71fa7b394af3ea9c94f9b438481359ec4 [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>
Ratan Gupta56187e72017-08-13 09:40:14 +053012#include <experimental/filesystem>
Patrick Venture189d44e2018-07-09 12:30:59 -070013#include <iostream>
14#include <list>
15#include <phosphor-logging/elog-errors.hpp>
16#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080017#include <stdexcept>
Patrick Venture189d44e2018-07-09 12:30:59 -070018#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070019#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070020#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053021
22namespace phosphor
23{
24namespace network
25{
Ratan Guptabc886292017-07-25 18:29:57 +053026
Ratan Gupta8804feb2017-05-25 10:49:57 +053027namespace
28{
29
30using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053031using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta56187e72017-08-13 09:40:14 +053032namespace fs = std::experimental::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053033
34uint8_t toV6Cidr(const std::string& subnetMask)
35{
36 uint8_t pos = 0;
37 uint8_t prevPos = 0;
38 uint8_t cidr = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050039 uint16_t buff{};
Ratan Gupta8804feb2017-05-25 10:49:57 +053040 do
41 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 // subnet mask look like ffff:ffff::
Ratan Gupta8804feb2017-05-25 10:49:57 +053043 // or ffff:c000::
Gunnar Mills57d9c502018-09-14 14:42:34 -050044 pos = subnetMask.find(":", prevPos);
Ratan Gupta8804feb2017-05-25 10:49:57 +053045 if (pos == std::string::npos)
46 {
47 break;
48 }
49
50 auto str = subnetMask.substr(prevPos, (pos - prevPos));
51 prevPos = pos + 1;
52
53 // String length is 0
54 if (!str.length())
55 {
56 return cidr;
57 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050058 // converts it into number.
Ratan Gupta8804feb2017-05-25 10:49:57 +053059 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
60 {
61 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050062 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053063
64 return 0;
65 }
66
67 // convert the number into bitset
68 // and check for how many ones are there.
69 // if we don't have all the ones then make
70 // sure that all the ones should be left justify.
71
72 if (__builtin_popcount(buff) != 16)
73 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050074 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
75 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053076 {
77 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050078 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053079
80 return 0;
81 }
82 cidr += __builtin_popcount(buff);
83 return cidr;
84 }
85
86 cidr += 16;
Gunnar Mills57d9c502018-09-14 14:42:34 -050087 } while (1);
Ratan Gupta8804feb2017-05-25 10:49:57 +053088
89 return cidr;
90}
Gunnar Mills57d9c502018-09-14 14:42:34 -050091} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053092
93uint8_t toCidr(int addressFamily, const std::string& subnetMask)
94{
95 if (addressFamily == AF_INET6)
96 {
97 return toV6Cidr(subnetMask);
98 }
99
100 uint32_t buff;
101
102 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
103 if (rc <= 0)
104 {
105 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500106 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530107 return 0;
108 }
109
110 buff = be32toh(buff);
111 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -0500112 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
113 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +0530114 {
115 return __builtin_popcount(buff);
116 }
117 else
118 {
119 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500120 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530121 return 0;
122 }
123}
124
125std::string toMask(int addressFamily, uint8_t prefix)
126{
127 if (addressFamily == AF_INET6)
128 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500129 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530130 return "";
131 }
132
133 if (prefix < 1 || prefix > 30)
134 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500135 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530136 return "";
137 }
138 /* Create the netmask from the number of bits */
139 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500140 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530141 {
142 mask |= 1 << (31 - i);
143 }
144 struct in_addr netmask;
145 netmask.s_addr = htonl(mask);
146 return inet_ntoa(netmask);
147}
148
Ratan Gupta11cef802017-05-29 08:41:48 +0530149std::string getNetworkID(int addressFamily, const std::string& ipaddress,
Ratan Guptabc886292017-07-25 18:29:57 +0530150 uint8_t prefix)
Ratan Gupta11cef802017-05-29 08:41:48 +0530151{
152 unsigned char* pntMask = nullptr;
153 unsigned char* pntNetwork = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500154 int bit{};
155 int offset{};
156 struct in6_addr netmask
157 {
158 };
Ratan Gupta11cef802017-05-29 08:41:48 +0530159 const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
Gunnar Mills57d9c502018-09-14 14:42:34 -0500160 0xf8, 0xfc, 0xfe, 0xff};
Ratan Gupta11cef802017-05-29 08:41:48 +0530161
162 pntMask = reinterpret_cast<unsigned char*>(&netmask);
163
164 offset = prefix / 8;
165 bit = prefix % 8;
166
167 while (offset--)
168 {
169 *pntMask++ = 0xff;
170 }
171
172 if (bit)
173 {
174 *pntMask = maskbit[bit];
175 }
176
177 // convert ipaddres string into network address
178 struct in6_addr ipaddressNetwork;
179 if (inet_pton(addressFamily, ipaddress.c_str(), &ipaddressNetwork) <= 0)
180 {
181 log<level::ERR>("inet_pton failure",
Ratan Guptabc886292017-07-25 18:29:57 +0530182 entry("IPADDRESS=%s", ipaddress.c_str()));
Ratan Gupta450b3462018-11-27 15:05:54 +0530183 elog<InternalFailure>();
Ratan Gupta11cef802017-05-29 08:41:48 +0530184
185 return "";
186 }
187
188 // Now bit wise and gets you the network address
189 pntMask = reinterpret_cast<unsigned char*>(&netmask);
190 pntNetwork = reinterpret_cast<unsigned char*>(&ipaddressNetwork);
191
Gunnar Mills57d9c502018-09-14 14:42:34 -0500192 for (int i = 0; i < 16; i++)
Ratan Gupta11cef802017-05-29 08:41:48 +0530193 {
194 pntNetwork[i] = pntNetwork[i] & pntMask[i];
195 }
196
Gunnar Mills57d9c502018-09-14 14:42:34 -0500197 // convert the network address into string fomat.
198 char networkString[INET6_ADDRSTRLEN] = {0};
Ratan Gupta11cef802017-05-29 08:41:48 +0530199 if (inet_ntop(addressFamily, &ipaddressNetwork, networkString,
200 INET6_ADDRSTRLEN) == NULL)
201 {
202 log<level::ERR>("inet_ntop failure");
Ratan Gupta450b3462018-11-27 15:05:54 +0530203 elog<InternalFailure>();
Ratan Gupta11cef802017-05-29 08:41:48 +0530204 }
205 return networkString;
206}
207
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800208InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
209{
210 if (addressFamily == AF_INET)
211 {
212 struct in_addr ret;
213 if (buf.size() != sizeof(ret))
214 {
215 throw std::runtime_error("Buf not in_addr sized");
216 }
217 memcpy(&ret, buf.data(), sizeof(ret));
218 return ret;
219 }
220 else if (addressFamily == AF_INET6)
221 {
222 struct in6_addr ret;
223 if (buf.size() != sizeof(ret))
224 {
225 throw std::runtime_error("Buf not in6_addr sized");
226 }
227 memcpy(&ret, buf.data(), sizeof(ret));
228 return ret;
229 }
230
231 throw std::runtime_error("Unsupported address family");
232}
233
William A. Kennington III5058f572019-01-30 17:18:14 -0800234std::string toString(const InAddrAny& addr)
235{
236 std::string ip;
237 if (std::holds_alternative<struct in_addr>(addr))
238 {
239 const auto& v = std::get<struct in_addr>(addr);
240 ip.resize(INET_ADDRSTRLEN);
241 if (inet_ntop(AF_INET, &v, ip.data(), ip.size()) == NULL)
242 {
243 throw std::runtime_error("Failed to convert IP4 to string");
244 }
245 }
246 else if (std::holds_alternative<struct in6_addr>(addr))
247 {
248 const auto& v = std::get<struct in6_addr>(addr);
249 ip.resize(INET6_ADDRSTRLEN);
250 if (inet_ntop(AF_INET6, &v, ip.data(), ip.size()) == NULL)
251 {
252 throw std::runtime_error("Failed to convert IP6 to string");
253 }
254 }
255 else
256 {
257 throw std::runtime_error("Invalid addr type");
258 }
259 ip.resize(strlen(ip.c_str()));
260 return ip;
261}
262
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500263bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530264{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500265 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
266}
267
268bool isValidIP(int addressFamily, const std::string& address)
269{
270 unsigned char buf[sizeof(struct in6_addr)];
271
272 return inet_pton(addressFamily, address.c_str(), buf) > 0;
273}
274
275bool isValidPrefix(int addressFamily, uint8_t prefixLength)
276{
277 if (addressFamily == AF_INET)
278 {
279 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
280 prefixLength > IPV4_MAX_PREFIX_LENGTH)
281 {
282 return false;
283 }
284 }
285
286 if (addressFamily == AF_INET6)
287 {
288 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
289 prefixLength > IPV6_MAX_PREFIX_LENGTH)
290 {
291 return false;
292 }
293 }
294
295 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530296}
297
Ratan Gupta3681a502017-06-17 19:20:04 +0530298IntfAddrMap getInterfaceAddrs()
299{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500300 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530301 struct ifaddrs* ifaddr = nullptr;
302
303 // attempt to fill struct with ifaddrs
304 if (getifaddrs(&ifaddr) == -1)
305 {
306 auto error = errno;
307 log<level::ERR>("Error occurred during the getifaddrs call",
308 entry("ERRNO=%s", strerror(error)));
309 elog<InternalFailure>();
310 }
311
312 AddrPtr ifaddrPtr(ifaddr);
313 ifaddr = nullptr;
314
Gunnar Mills57d9c502018-09-14 14:42:34 -0500315 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530316
317 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
318 {
319 // walk interfaces
320 if (ifa->ifa_addr == nullptr)
321 {
322 continue;
323 }
324
325 // get only INET interfaces not ipv6
326 if (ifa->ifa_addr->sa_family == AF_INET ||
327 ifa->ifa_addr->sa_family == AF_INET6)
328 {
329 // if loopback, or not running ignore
330 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
331 !(ifa->ifa_flags & IFF_RUNNING))
332 {
333 continue;
334 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530335 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500336 AddrInfo info{};
337 char ip[INET6_ADDRSTRLEN] = {0};
338 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530339
340 if (ifa->ifa_addr->sa_family == AF_INET)
341 {
342
343 inet_ntop(ifa->ifa_addr->sa_family,
344 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500345 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530346
Gunnar Mills57d9c502018-09-14 14:42:34 -0500347 inet_ntop(
348 ifa->ifa_addr->sa_family,
349 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
350 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530351 }
352 else
353 {
354 inet_ntop(ifa->ifa_addr->sa_family,
355 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500356 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530357
Gunnar Mills57d9c502018-09-14 14:42:34 -0500358 inet_ntop(
359 ifa->ifa_addr->sa_family,
360 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
361 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530362 }
363
364 info.addrType = ifa->ifa_addr->sa_family;
365 info.ipaddress = ip;
366 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700367 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530368 }
369 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530370 return intfMap;
371}
372
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530373InterfaceList getInterfaces()
374{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500375 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530376 struct ifaddrs* ifaddr = nullptr;
377
378 // attempt to fill struct with ifaddrs
379 if (getifaddrs(&ifaddr) == -1)
380 {
381 auto error = errno;
382 log<level::ERR>("Error occurred during the getifaddrs call",
383 entry("ERRNO=%d", error));
384 elog<InternalFailure>();
385 }
386
387 AddrPtr ifaddrPtr(ifaddr);
388 ifaddr = nullptr;
389
390 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
391 {
392 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700393 // if loopback ignore
394 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530395 {
396 continue;
397 }
398 interfaces.emplace(ifa->ifa_name);
399 }
400 return interfaces;
401}
402
Ratan Guptabc886292017-07-25 18:29:57 +0530403void deleteInterface(const std::string& intf)
404{
405 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500406 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530407
408 if (pid == 0)
409 {
410
411 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
412 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500413 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530414 entry("INTF=%s", intf.c_str()));
415 elog<InternalFailure>();
416 }
417 else if (pid < 0)
418 {
419 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500420 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530421 elog<InternalFailure>();
422 }
423 else if (pid > 0)
424 {
425 while (waitpid(pid, &status, 0) == -1)
426 {
427 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500428 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530429 status = -1;
430 break;
431 }
432 }
433
Gunnar Mills57d9c502018-09-14 14:42:34 -0500434 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530435 {
436 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500437 entry("INTF=%s", intf.c_str()),
438 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530439 elog<InternalFailure>();
440 }
441 }
442}
443
Ratan Gupta56187e72017-08-13 09:40:14 +0530444bool getDHCPValue(const std::string& confDir, const std::string& intf)
445{
446 bool dhcp = false;
447 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500448 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530449 fs::path confPath = confDir;
450 std::string fileName = systemd::config::networkFilePrefix + intf +
451 systemd::config::networkFileSuffix;
452 confPath /= fileName;
453
Ratan Guptac27170a2017-11-22 15:44:42 +0530454 auto rc = config::ReturnCode::SUCCESS;
455 config::ValueList values;
456 config::Parser parser(confPath.string());
457
458 std::tie(rc, values) = parser.getValues("Network", "DHCP");
459 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530460 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530461 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500462 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530463 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530464 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530465 // There will be only single value for DHCP key.
466 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530467 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530468 dhcp = true;
Ratan Gupta56187e72017-08-13 09:40:14 +0530469 }
470 return dhcp;
471}
472
Ratan Guptabd303b12017-08-18 17:10:07 +0530473namespace internal
474{
Ratan Gupta56187e72017-08-13 09:40:14 +0530475
Ratan Guptabd303b12017-08-18 17:10:07 +0530476void executeCommandinChildProcess(const char* path, char** args)
477{
478 using namespace std::string_literals;
479 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500480 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530481
482 if (pid == 0)
483 {
484 execv(path, args);
485 auto error = errno;
486 // create the command from var args.
487 std::string command = path + " "s;
488
Gunnar Mills57d9c502018-09-14 14:42:34 -0500489 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530490 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500491 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530492 }
493
494 log<level::ERR>("Couldn't exceute the command",
495 entry("ERRNO=%d", error),
496 entry("CMD=%s", command.c_str()));
497 elog<InternalFailure>();
498 }
499 else if (pid < 0)
500 {
501 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500502 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530503 elog<InternalFailure>();
504 }
505 else if (pid > 0)
506 {
507 while (waitpid(pid, &status, 0) == -1)
508 {
509 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500510 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530511 status = -1;
512 break;
513 }
514 }
515
Gunnar Mills57d9c502018-09-14 14:42:34 -0500516 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530517 {
518 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500519 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530520 {
521 command += args[i] + " "s;
522 }
523
524 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500525 entry("CMD=%s", command.c_str()),
526 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530527 elog<InternalFailure>();
528 }
529 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530530}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500531} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530532
533namespace mac_address
534{
535
536constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
537constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
538constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
539constexpr auto propIntf = "org.freedesktop.DBus.Properties";
540constexpr auto methodGet = "Get";
541
542using DbusObjectPath = std::string;
543using DbusService = std::string;
544using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500545using ObjectTree =
546 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530547
548constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
549constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500550 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530551constexpr auto invRoot = "/xyz/openbmc_project/inventory";
552
William A. Kennington III1137a972019-04-20 20:49:58 -0700553ether_addr getfromInventory(sdbusplus::bus::bus& bus)
Ratan Guptabd303b12017-08-18 17:10:07 +0530554{
555 std::vector<DbusInterface> interfaces;
556 interfaces.emplace_back(invNetworkIntf);
557
558 auto depth = 0;
559
Gunnar Mills57d9c502018-09-14 14:42:34 -0500560 auto mapperCall =
561 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530562
563 mapperCall.append(invRoot, depth, interfaces);
564
565 auto mapperReply = bus.call(mapperCall);
566 if (mapperReply.is_method_error())
567 {
568 log<level::ERR>("Error in mapper call");
569 elog<InternalFailure>();
570 }
571
572 ObjectTree objectTree;
573 mapperReply.read(objectTree);
574
575 if (objectTree.empty())
576 {
577 log<level::ERR>("No Object has implemented the interface",
578 entry("INTERFACE=%s", invNetworkIntf));
579 elog<InternalFailure>();
580 }
581
Gunnar Millsa251a782017-09-26 16:49:08 -0500582 // It is expected that only one object has implemented this interface.
Ratan Guptabd303b12017-08-18 17:10:07 +0530583
584 auto objPath = objectTree.begin()->first;
585 auto service = objectTree.begin()->second.begin()->first;
586
Gunnar Mills57d9c502018-09-14 14:42:34 -0500587 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
588 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530589
590 method.append(invNetworkIntf, "MACAddress");
591
592 auto reply = bus.call(method);
593 if (reply.is_method_error())
594 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500595 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530596 entry("PATH=%s", objPath.c_str()),
597 entry("INTERFACE=%s", invNetworkIntf));
598 elog<InternalFailure>();
599 }
600
William A. Kennington III1137a972019-04-20 20:49:58 -0700601 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530602 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700603 return fromString(std::get<std::string>(value));
604}
605
606ether_addr fromString(const char* str)
607{
608 struct ether_addr* mac = ether_aton(str);
609 if (mac == nullptr)
610 {
611 throw std::runtime_error("Invalid mac address string");
612 }
613 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530614}
615
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700616std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800617{
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700618 return ether_ntoa(&mac);
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800619}
620
William A. Kennington III1137a972019-04-20 20:49:58 -0700621bool isEmpty(const ether_addr& mac)
622{
623 return equal(mac, ether_addr{});
624}
625
626bool isMulticast(const ether_addr& mac)
627{
628 return mac.ether_addr_octet[0] & 0b1;
629}
630
631bool isUnicast(const ether_addr& mac)
632{
633 return !isEmpty(mac) && !isMulticast(mac);
634}
635
636bool isLocalAdmin(const ether_addr& mac)
637{
638 return mac.ether_addr_octet[0] & 0b10;
639}
640
Gunnar Mills57d9c502018-09-14 14:42:34 -0500641} // namespace mac_address
642} // namespace network
643} // namespace phosphor