blob: d1bcc71a5d0ae57808c34ab0d19c17464eebc1af [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>
19#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053020
21namespace phosphor
22{
23namespace network
24{
Ratan Guptabc886292017-07-25 18:29:57 +053025
Ratan Gupta8804feb2017-05-25 10:49:57 +053026namespace
27{
28
29using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053030using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta56187e72017-08-13 09:40:14 +053031namespace fs = std::experimental::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053032
33uint8_t toV6Cidr(const std::string& subnetMask)
34{
35 uint8_t pos = 0;
36 uint8_t prevPos = 0;
37 uint8_t cidr = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050038 uint16_t buff{};
Ratan Gupta8804feb2017-05-25 10:49:57 +053039 do
40 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050041 // subnet mask look like ffff:ffff::
Ratan Gupta8804feb2017-05-25 10:49:57 +053042 // or ffff:c000::
Gunnar Mills57d9c502018-09-14 14:42:34 -050043 pos = subnetMask.find(":", prevPos);
Ratan Gupta8804feb2017-05-25 10:49:57 +053044 if (pos == std::string::npos)
45 {
46 break;
47 }
48
49 auto str = subnetMask.substr(prevPos, (pos - prevPos));
50 prevPos = pos + 1;
51
52 // String length is 0
53 if (!str.length())
54 {
55 return cidr;
56 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050057 // converts it into number.
Ratan Gupta8804feb2017-05-25 10:49:57 +053058 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
59 {
60 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050061 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053062
63 return 0;
64 }
65
66 // convert the number into bitset
67 // and check for how many ones are there.
68 // if we don't have all the ones then make
69 // sure that all the ones should be left justify.
70
71 if (__builtin_popcount(buff) != 16)
72 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050073 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
74 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053075 {
76 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050077 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053078
79 return 0;
80 }
81 cidr += __builtin_popcount(buff);
82 return cidr;
83 }
84
85 cidr += 16;
Gunnar Mills57d9c502018-09-14 14:42:34 -050086 } while (1);
Ratan Gupta8804feb2017-05-25 10:49:57 +053087
88 return cidr;
89}
Gunnar Mills57d9c502018-09-14 14:42:34 -050090} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053091
92uint8_t toCidr(int addressFamily, const std::string& subnetMask)
93{
94 if (addressFamily == AF_INET6)
95 {
96 return toV6Cidr(subnetMask);
97 }
98
99 uint32_t buff;
100
101 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
102 if (rc <= 0)
103 {
104 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500105 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530106 return 0;
107 }
108
109 buff = be32toh(buff);
110 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -0500111 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
112 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +0530113 {
114 return __builtin_popcount(buff);
115 }
116 else
117 {
118 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500119 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530120 return 0;
121 }
122}
123
124std::string toMask(int addressFamily, uint8_t prefix)
125{
126 if (addressFamily == AF_INET6)
127 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500128 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530129 return "";
130 }
131
132 if (prefix < 1 || prefix > 30)
133 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500134 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530135 return "";
136 }
137 /* Create the netmask from the number of bits */
138 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500139 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530140 {
141 mask |= 1 << (31 - i);
142 }
143 struct in_addr netmask;
144 netmask.s_addr = htonl(mask);
145 return inet_ntoa(netmask);
146}
147
Ratan Gupta11cef802017-05-29 08:41:48 +0530148std::string getNetworkID(int addressFamily, const std::string& ipaddress,
Ratan Guptabc886292017-07-25 18:29:57 +0530149 uint8_t prefix)
Ratan Gupta11cef802017-05-29 08:41:48 +0530150{
151 unsigned char* pntMask = nullptr;
152 unsigned char* pntNetwork = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500153 int bit{};
154 int offset{};
155 struct in6_addr netmask
156 {
157 };
Ratan Gupta11cef802017-05-29 08:41:48 +0530158 const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
Gunnar Mills57d9c502018-09-14 14:42:34 -0500159 0xf8, 0xfc, 0xfe, 0xff};
Ratan Gupta11cef802017-05-29 08:41:48 +0530160
161 pntMask = reinterpret_cast<unsigned char*>(&netmask);
162
163 offset = prefix / 8;
164 bit = prefix % 8;
165
166 while (offset--)
167 {
168 *pntMask++ = 0xff;
169 }
170
171 if (bit)
172 {
173 *pntMask = maskbit[bit];
174 }
175
176 // convert ipaddres string into network address
177 struct in6_addr ipaddressNetwork;
178 if (inet_pton(addressFamily, ipaddress.c_str(), &ipaddressNetwork) <= 0)
179 {
180 log<level::ERR>("inet_pton failure",
Ratan Guptabc886292017-07-25 18:29:57 +0530181 entry("IPADDRESS=%s", ipaddress.c_str()));
Ratan Gupta450b3462018-11-27 15:05:54 +0530182 elog<InternalFailure>();
Ratan Gupta11cef802017-05-29 08:41:48 +0530183
184 return "";
185 }
186
187 // Now bit wise and gets you the network address
188 pntMask = reinterpret_cast<unsigned char*>(&netmask);
189 pntNetwork = reinterpret_cast<unsigned char*>(&ipaddressNetwork);
190
Gunnar Mills57d9c502018-09-14 14:42:34 -0500191 for (int i = 0; i < 16; i++)
Ratan Gupta11cef802017-05-29 08:41:48 +0530192 {
193 pntNetwork[i] = pntNetwork[i] & pntMask[i];
194 }
195
Gunnar Mills57d9c502018-09-14 14:42:34 -0500196 // convert the network address into string fomat.
197 char networkString[INET6_ADDRSTRLEN] = {0};
Ratan Gupta11cef802017-05-29 08:41:48 +0530198 if (inet_ntop(addressFamily, &ipaddressNetwork, networkString,
199 INET6_ADDRSTRLEN) == NULL)
200 {
201 log<level::ERR>("inet_ntop failure");
Ratan Gupta450b3462018-11-27 15:05:54 +0530202 elog<InternalFailure>();
Ratan Gupta11cef802017-05-29 08:41:48 +0530203 }
204 return networkString;
205}
206
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800207InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
208{
209 if (addressFamily == AF_INET)
210 {
211 struct in_addr ret;
212 if (buf.size() != sizeof(ret))
213 {
214 throw std::runtime_error("Buf not in_addr sized");
215 }
216 memcpy(&ret, buf.data(), sizeof(ret));
217 return ret;
218 }
219 else if (addressFamily == AF_INET6)
220 {
221 struct in6_addr ret;
222 if (buf.size() != sizeof(ret))
223 {
224 throw std::runtime_error("Buf not in6_addr sized");
225 }
226 memcpy(&ret, buf.data(), sizeof(ret));
227 return ret;
228 }
229
230 throw std::runtime_error("Unsupported address family");
231}
232
William A. Kennington III5058f572019-01-30 17:18:14 -0800233std::string toString(const InAddrAny& addr)
234{
235 std::string ip;
236 if (std::holds_alternative<struct in_addr>(addr))
237 {
238 const auto& v = std::get<struct in_addr>(addr);
239 ip.resize(INET_ADDRSTRLEN);
240 if (inet_ntop(AF_INET, &v, ip.data(), ip.size()) == NULL)
241 {
242 throw std::runtime_error("Failed to convert IP4 to string");
243 }
244 }
245 else if (std::holds_alternative<struct in6_addr>(addr))
246 {
247 const auto& v = std::get<struct in6_addr>(addr);
248 ip.resize(INET6_ADDRSTRLEN);
249 if (inet_ntop(AF_INET6, &v, ip.data(), ip.size()) == NULL)
250 {
251 throw std::runtime_error("Failed to convert IP6 to string");
252 }
253 }
254 else
255 {
256 throw std::runtime_error("Invalid addr type");
257 }
258 ip.resize(strlen(ip.c_str()));
259 return ip;
260}
261
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500262bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530263{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500264 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
265}
266
267bool isValidIP(int addressFamily, const std::string& address)
268{
269 unsigned char buf[sizeof(struct in6_addr)];
270
271 return inet_pton(addressFamily, address.c_str(), buf) > 0;
272}
273
274bool isValidPrefix(int addressFamily, uint8_t prefixLength)
275{
276 if (addressFamily == AF_INET)
277 {
278 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
279 prefixLength > IPV4_MAX_PREFIX_LENGTH)
280 {
281 return false;
282 }
283 }
284
285 if (addressFamily == AF_INET6)
286 {
287 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
288 prefixLength > IPV6_MAX_PREFIX_LENGTH)
289 {
290 return false;
291 }
292 }
293
294 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530295}
296
Ratan Gupta3681a502017-06-17 19:20:04 +0530297IntfAddrMap getInterfaceAddrs()
298{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500299 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530300 struct ifaddrs* ifaddr = nullptr;
301
302 // attempt to fill struct with ifaddrs
303 if (getifaddrs(&ifaddr) == -1)
304 {
305 auto error = errno;
306 log<level::ERR>("Error occurred during the getifaddrs call",
307 entry("ERRNO=%s", strerror(error)));
308 elog<InternalFailure>();
309 }
310
311 AddrPtr ifaddrPtr(ifaddr);
312 ifaddr = nullptr;
313
Gunnar Mills57d9c502018-09-14 14:42:34 -0500314 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530315
316 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
317 {
318 // walk interfaces
319 if (ifa->ifa_addr == nullptr)
320 {
321 continue;
322 }
323
324 // get only INET interfaces not ipv6
325 if (ifa->ifa_addr->sa_family == AF_INET ||
326 ifa->ifa_addr->sa_family == AF_INET6)
327 {
328 // if loopback, or not running ignore
329 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
330 !(ifa->ifa_flags & IFF_RUNNING))
331 {
332 continue;
333 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530334 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500335 AddrInfo info{};
336 char ip[INET6_ADDRSTRLEN] = {0};
337 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530338
339 if (ifa->ifa_addr->sa_family == AF_INET)
340 {
341
342 inet_ntop(ifa->ifa_addr->sa_family,
343 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500344 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530345
Gunnar Mills57d9c502018-09-14 14:42:34 -0500346 inet_ntop(
347 ifa->ifa_addr->sa_family,
348 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
349 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530350 }
351 else
352 {
353 inet_ntop(ifa->ifa_addr->sa_family,
354 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500355 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530356
Gunnar Mills57d9c502018-09-14 14:42:34 -0500357 inet_ntop(
358 ifa->ifa_addr->sa_family,
359 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
360 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530361 }
362
363 info.addrType = ifa->ifa_addr->sa_family;
364 info.ipaddress = ip;
365 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700366 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530367 }
368 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530369 return intfMap;
370}
371
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530372InterfaceList getInterfaces()
373{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500374 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530375 struct ifaddrs* ifaddr = nullptr;
376
377 // attempt to fill struct with ifaddrs
378 if (getifaddrs(&ifaddr) == -1)
379 {
380 auto error = errno;
381 log<level::ERR>("Error occurred during the getifaddrs call",
382 entry("ERRNO=%d", error));
383 elog<InternalFailure>();
384 }
385
386 AddrPtr ifaddrPtr(ifaddr);
387 ifaddr = nullptr;
388
389 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
390 {
391 // walk interfaces
392 // if loopback, or not running ignore
Gunnar Mills57d9c502018-09-14 14:42:34 -0500393 if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_RUNNING))
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530394 {
395 continue;
396 }
397 interfaces.emplace(ifa->ifa_name);
398 }
399 return interfaces;
400}
401
Ratan Guptabc886292017-07-25 18:29:57 +0530402void deleteInterface(const std::string& intf)
403{
404 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500405 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530406
407 if (pid == 0)
408 {
409
410 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
411 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500412 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530413 entry("INTF=%s", intf.c_str()));
414 elog<InternalFailure>();
415 }
416 else if (pid < 0)
417 {
418 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500419 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530420 elog<InternalFailure>();
421 }
422 else if (pid > 0)
423 {
424 while (waitpid(pid, &status, 0) == -1)
425 {
426 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530428 status = -1;
429 break;
430 }
431 }
432
Gunnar Mills57d9c502018-09-14 14:42:34 -0500433 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530434 {
435 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500436 entry("INTF=%s", intf.c_str()),
437 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530438 elog<InternalFailure>();
439 }
440 }
441}
442
Ratan Gupta56187e72017-08-13 09:40:14 +0530443bool getDHCPValue(const std::string& confDir, const std::string& intf)
444{
445 bool dhcp = false;
446 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500447 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530448 fs::path confPath = confDir;
449 std::string fileName = systemd::config::networkFilePrefix + intf +
450 systemd::config::networkFileSuffix;
451 confPath /= fileName;
452
Ratan Guptac27170a2017-11-22 15:44:42 +0530453 auto rc = config::ReturnCode::SUCCESS;
454 config::ValueList values;
455 config::Parser parser(confPath.string());
456
457 std::tie(rc, values) = parser.getValues("Network", "DHCP");
458 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530459 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530460 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500461 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530462 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530463 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530464 // There will be only single value for DHCP key.
465 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530466 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530467 dhcp = true;
Ratan Gupta56187e72017-08-13 09:40:14 +0530468 }
469 return dhcp;
470}
471
Ratan Guptabd303b12017-08-18 17:10:07 +0530472namespace internal
473{
Ratan Gupta56187e72017-08-13 09:40:14 +0530474
Ratan Guptabd303b12017-08-18 17:10:07 +0530475void executeCommandinChildProcess(const char* path, char** args)
476{
477 using namespace std::string_literals;
478 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500479 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530480
481 if (pid == 0)
482 {
483 execv(path, args);
484 auto error = errno;
485 // create the command from var args.
486 std::string command = path + " "s;
487
Gunnar Mills57d9c502018-09-14 14:42:34 -0500488 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530489 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500490 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530491 }
492
493 log<level::ERR>("Couldn't exceute the command",
494 entry("ERRNO=%d", error),
495 entry("CMD=%s", command.c_str()));
496 elog<InternalFailure>();
497 }
498 else if (pid < 0)
499 {
500 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500501 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530502 elog<InternalFailure>();
503 }
504 else if (pid > 0)
505 {
506 while (waitpid(pid, &status, 0) == -1)
507 {
508 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500509 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530510 status = -1;
511 break;
512 }
513 }
514
Gunnar Mills57d9c502018-09-14 14:42:34 -0500515 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530516 {
517 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500518 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530519 {
520 command += args[i] + " "s;
521 }
522
523 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500524 entry("CMD=%s", command.c_str()),
525 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530526 elog<InternalFailure>();
527 }
528 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530529}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500530} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530531
532namespace mac_address
533{
534
535constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
536constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
537constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
538constexpr auto propIntf = "org.freedesktop.DBus.Properties";
539constexpr auto methodGet = "Get";
540
541using DbusObjectPath = std::string;
542using DbusService = std::string;
543using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500544using ObjectTree =
545 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530546
547constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
548constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500549 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530550constexpr auto invRoot = "/xyz/openbmc_project/inventory";
551
552std::string getfromInventory(sdbusplus::bus::bus& bus)
553{
554 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
Gunnar Millsa251a782017-09-26 16:49:08 -0500581 // It is expected that only one object has implemented this interface.
Ratan Guptabd303b12017-08-18 17:10:07 +0530582
583 auto objPath = objectTree.begin()->first;
584 auto service = objectTree.begin()->second.begin()->first;
585
586 sdbusplus::message::variant<std::string> value;
587
Gunnar Mills57d9c502018-09-14 14:42:34 -0500588 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
589 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530590
591 method.append(invNetworkIntf, "MACAddress");
592
593 auto reply = bus.call(method);
594 if (reply.is_method_error())
595 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500596 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530597 entry("PATH=%s", objPath.c_str()),
598 entry("INTERFACE=%s", invNetworkIntf));
599 elog<InternalFailure>();
600 }
601
602 reply.read(value);
William A. Kennington III79e44152018-11-06 16:46:01 -0800603 return sdbusplus::message::variant_ns::get<std::string>(value);
Ratan Guptabd303b12017-08-18 17:10:07 +0530604}
605
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800606MacAddr fromBuf(std::string_view buf)
607{
608 MacAddr ret;
609 if (buf.size() != ret.size())
610 {
611 throw std::runtime_error("Invalid MacAddr size");
612 }
613 memcpy(ret.data(), buf.data(), ret.size());
614 return ret;
615}
616
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800617std::string toString(const MacAddr& mac)
618{
619 std::string str;
620 str.reserve(mac.size() * 3);
621 for (size_t i = 0; i < mac.size(); ++i)
622 {
623 str.push_back(internal::toHex(mac[i] >> 4));
624 str.push_back(internal::toHex(mac[i]));
625 str.push_back(':');
626 }
627 // Remove trailing semicolon
628 str.pop_back();
629 return str;
630}
631
Gunnar Mills57d9c502018-09-14 14:42:34 -0500632} // namespace mac_address
633} // namespace network
634} // namespace phosphor