blob: b66f908831533ace3bffeda2f11c00fa27296fe5 [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>
17#include <string>
18#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053019
20namespace phosphor
21{
22namespace network
23{
Ratan Guptabc886292017-07-25 18:29:57 +053024
Ratan Gupta8804feb2017-05-25 10:49:57 +053025namespace
26{
27
28using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053029using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta56187e72017-08-13 09:40:14 +053030namespace fs = std::experimental::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053031
32uint8_t toV6Cidr(const std::string& subnetMask)
33{
34 uint8_t pos = 0;
35 uint8_t prevPos = 0;
36 uint8_t cidr = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050037 uint16_t buff{};
Ratan Gupta8804feb2017-05-25 10:49:57 +053038 do
39 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050040 // subnet mask look like ffff:ffff::
Ratan Gupta8804feb2017-05-25 10:49:57 +053041 // or ffff:c000::
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 pos = subnetMask.find(":", prevPos);
Ratan Gupta8804feb2017-05-25 10:49:57 +053043 if (pos == std::string::npos)
44 {
45 break;
46 }
47
48 auto str = subnetMask.substr(prevPos, (pos - prevPos));
49 prevPos = pos + 1;
50
51 // String length is 0
52 if (!str.length())
53 {
54 return cidr;
55 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050056 // converts it into number.
Ratan Gupta8804feb2017-05-25 10:49:57 +053057 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
58 {
59 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050060 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053061
62 return 0;
63 }
64
65 // convert the number into bitset
66 // and check for how many ones are there.
67 // if we don't have all the ones then make
68 // sure that all the ones should be left justify.
69
70 if (__builtin_popcount(buff) != 16)
71 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050072 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
73 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053074 {
75 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050076 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053077
78 return 0;
79 }
80 cidr += __builtin_popcount(buff);
81 return cidr;
82 }
83
84 cidr += 16;
Gunnar Mills57d9c502018-09-14 14:42:34 -050085 } while (1);
Ratan Gupta8804feb2017-05-25 10:49:57 +053086
87 return cidr;
88}
Gunnar Mills57d9c502018-09-14 14:42:34 -050089} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053090
91uint8_t toCidr(int addressFamily, const std::string& subnetMask)
92{
93 if (addressFamily == AF_INET6)
94 {
95 return toV6Cidr(subnetMask);
96 }
97
98 uint32_t buff;
99
100 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
101 if (rc <= 0)
102 {
103 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500104 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530105 return 0;
106 }
107
108 buff = be32toh(buff);
109 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -0500110 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
111 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +0530112 {
113 return __builtin_popcount(buff);
114 }
115 else
116 {
117 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500118 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530119 return 0;
120 }
121}
122
123std::string toMask(int addressFamily, uint8_t prefix)
124{
125 if (addressFamily == AF_INET6)
126 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500127 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530128 return "";
129 }
130
131 if (prefix < 1 || prefix > 30)
132 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500133 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530134 return "";
135 }
136 /* Create the netmask from the number of bits */
137 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500138 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530139 {
140 mask |= 1 << (31 - i);
141 }
142 struct in_addr netmask;
143 netmask.s_addr = htonl(mask);
144 return inet_ntoa(netmask);
145}
146
Ratan Gupta11cef802017-05-29 08:41:48 +0530147std::string getNetworkID(int addressFamily, const std::string& ipaddress,
Ratan Guptabc886292017-07-25 18:29:57 +0530148 uint8_t prefix)
Ratan Gupta11cef802017-05-29 08:41:48 +0530149{
150 unsigned char* pntMask = nullptr;
151 unsigned char* pntNetwork = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500152 int bit{};
153 int offset{};
154 struct in6_addr netmask
155 {
156 };
Ratan Gupta11cef802017-05-29 08:41:48 +0530157 const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
Gunnar Mills57d9c502018-09-14 14:42:34 -0500158 0xf8, 0xfc, 0xfe, 0xff};
Ratan Gupta11cef802017-05-29 08:41:48 +0530159
160 pntMask = reinterpret_cast<unsigned char*>(&netmask);
161
162 offset = prefix / 8;
163 bit = prefix % 8;
164
165 while (offset--)
166 {
167 *pntMask++ = 0xff;
168 }
169
170 if (bit)
171 {
172 *pntMask = maskbit[bit];
173 }
174
175 // convert ipaddres string into network address
176 struct in6_addr ipaddressNetwork;
177 if (inet_pton(addressFamily, ipaddress.c_str(), &ipaddressNetwork) <= 0)
178 {
179 log<level::ERR>("inet_pton failure",
Ratan Guptabc886292017-07-25 18:29:57 +0530180 entry("IPADDRESS=%s", ipaddress.c_str()));
Ratan Gupta11cef802017-05-29 08:41:48 +0530181 report<InternalFailure>();
182
183 return "";
184 }
185
186 // Now bit wise and gets you the network address
187 pntMask = reinterpret_cast<unsigned char*>(&netmask);
188 pntNetwork = reinterpret_cast<unsigned char*>(&ipaddressNetwork);
189
Gunnar Mills57d9c502018-09-14 14:42:34 -0500190 for (int i = 0; i < 16; i++)
Ratan Gupta11cef802017-05-29 08:41:48 +0530191 {
192 pntNetwork[i] = pntNetwork[i] & pntMask[i];
193 }
194
Gunnar Mills57d9c502018-09-14 14:42:34 -0500195 // convert the network address into string fomat.
196 char networkString[INET6_ADDRSTRLEN] = {0};
Ratan Gupta11cef802017-05-29 08:41:48 +0530197 if (inet_ntop(addressFamily, &ipaddressNetwork, networkString,
198 INET6_ADDRSTRLEN) == NULL)
199 {
200 log<level::ERR>("inet_ntop failure");
201 report<InternalFailure>();
202 }
203 return networkString;
204}
205
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500206bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530207{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500208 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
209}
210
211bool isValidIP(int addressFamily, const std::string& address)
212{
213 unsigned char buf[sizeof(struct in6_addr)];
214
215 return inet_pton(addressFamily, address.c_str(), buf) > 0;
216}
217
218bool isValidPrefix(int addressFamily, uint8_t prefixLength)
219{
220 if (addressFamily == AF_INET)
221 {
222 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
223 prefixLength > IPV4_MAX_PREFIX_LENGTH)
224 {
225 return false;
226 }
227 }
228
229 if (addressFamily == AF_INET6)
230 {
231 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
232 prefixLength > IPV6_MAX_PREFIX_LENGTH)
233 {
234 return false;
235 }
236 }
237
238 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530239}
240
Ratan Gupta3681a502017-06-17 19:20:04 +0530241IntfAddrMap getInterfaceAddrs()
242{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500243 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530244 struct ifaddrs* ifaddr = nullptr;
245
246 // attempt to fill struct with ifaddrs
247 if (getifaddrs(&ifaddr) == -1)
248 {
249 auto error = errno;
250 log<level::ERR>("Error occurred during the getifaddrs call",
251 entry("ERRNO=%s", strerror(error)));
252 elog<InternalFailure>();
253 }
254
255 AddrPtr ifaddrPtr(ifaddr);
256 ifaddr = nullptr;
257
Gunnar Mills57d9c502018-09-14 14:42:34 -0500258 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530259
260 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
261 {
262 // walk interfaces
263 if (ifa->ifa_addr == nullptr)
264 {
265 continue;
266 }
267
268 // get only INET interfaces not ipv6
269 if (ifa->ifa_addr->sa_family == AF_INET ||
270 ifa->ifa_addr->sa_family == AF_INET6)
271 {
272 // if loopback, or not running ignore
273 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
274 !(ifa->ifa_flags & IFF_RUNNING))
275 {
276 continue;
277 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530278 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500279 AddrInfo info{};
280 char ip[INET6_ADDRSTRLEN] = {0};
281 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530282
283 if (ifa->ifa_addr->sa_family == AF_INET)
284 {
285
286 inet_ntop(ifa->ifa_addr->sa_family,
287 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500288 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530289
Gunnar Mills57d9c502018-09-14 14:42:34 -0500290 inet_ntop(
291 ifa->ifa_addr->sa_family,
292 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
293 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530294 }
295 else
296 {
297 inet_ntop(ifa->ifa_addr->sa_family,
298 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500299 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530300
Gunnar Mills57d9c502018-09-14 14:42:34 -0500301 inet_ntop(
302 ifa->ifa_addr->sa_family,
303 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
304 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530305 }
306
307 info.addrType = ifa->ifa_addr->sa_family;
308 info.ipaddress = ip;
309 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700310 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530311 }
312 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530313 return intfMap;
314}
315
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530316InterfaceList getInterfaces()
317{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500318 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530319 struct ifaddrs* ifaddr = nullptr;
320
321 // attempt to fill struct with ifaddrs
322 if (getifaddrs(&ifaddr) == -1)
323 {
324 auto error = errno;
325 log<level::ERR>("Error occurred during the getifaddrs call",
326 entry("ERRNO=%d", error));
327 elog<InternalFailure>();
328 }
329
330 AddrPtr ifaddrPtr(ifaddr);
331 ifaddr = nullptr;
332
333 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
334 {
335 // walk interfaces
336 // if loopback, or not running ignore
Gunnar Mills57d9c502018-09-14 14:42:34 -0500337 if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_RUNNING))
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530338 {
339 continue;
340 }
341 interfaces.emplace(ifa->ifa_name);
342 }
343 return interfaces;
344}
345
Ratan Guptabc886292017-07-25 18:29:57 +0530346void deleteInterface(const std::string& intf)
347{
348 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500349 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530350
351 if (pid == 0)
352 {
353
354 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
355 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500356 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530357 entry("INTF=%s", intf.c_str()));
358 elog<InternalFailure>();
359 }
360 else if (pid < 0)
361 {
362 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500363 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530364 elog<InternalFailure>();
365 }
366 else if (pid > 0)
367 {
368 while (waitpid(pid, &status, 0) == -1)
369 {
370 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500371 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530372 status = -1;
373 break;
374 }
375 }
376
Gunnar Mills57d9c502018-09-14 14:42:34 -0500377 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530378 {
379 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500380 entry("INTF=%s", intf.c_str()),
381 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530382 elog<InternalFailure>();
383 }
384 }
385}
386
Ratan Gupta56187e72017-08-13 09:40:14 +0530387bool getDHCPValue(const std::string& confDir, const std::string& intf)
388{
389 bool dhcp = false;
390 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500391 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530392 fs::path confPath = confDir;
393 std::string fileName = systemd::config::networkFilePrefix + intf +
394 systemd::config::networkFileSuffix;
395 confPath /= fileName;
396
Ratan Guptac27170a2017-11-22 15:44:42 +0530397 auto rc = config::ReturnCode::SUCCESS;
398 config::ValueList values;
399 config::Parser parser(confPath.string());
400
401 std::tie(rc, values) = parser.getValues("Network", "DHCP");
402 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530403 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530404 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500405 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530406 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530407 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530408 // There will be only single value for DHCP key.
409 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530410 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530411 dhcp = true;
Ratan Gupta56187e72017-08-13 09:40:14 +0530412 }
413 return dhcp;
414}
415
Ratan Guptabd303b12017-08-18 17:10:07 +0530416namespace internal
417{
Ratan Gupta56187e72017-08-13 09:40:14 +0530418
Ratan Guptabd303b12017-08-18 17:10:07 +0530419void executeCommandinChildProcess(const char* path, char** args)
420{
421 using namespace std::string_literals;
422 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500423 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530424
425 if (pid == 0)
426 {
427 execv(path, args);
428 auto error = errno;
429 // create the command from var args.
430 std::string command = path + " "s;
431
Gunnar Mills57d9c502018-09-14 14:42:34 -0500432 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530433 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500434 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530435 }
436
437 log<level::ERR>("Couldn't exceute the command",
438 entry("ERRNO=%d", error),
439 entry("CMD=%s", command.c_str()));
440 elog<InternalFailure>();
441 }
442 else if (pid < 0)
443 {
444 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500445 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530446 elog<InternalFailure>();
447 }
448 else if (pid > 0)
449 {
450 while (waitpid(pid, &status, 0) == -1)
451 {
452 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500453 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530454 status = -1;
455 break;
456 }
457 }
458
Gunnar Mills57d9c502018-09-14 14:42:34 -0500459 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530460 {
461 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500462 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530463 {
464 command += args[i] + " "s;
465 }
466
467 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500468 entry("CMD=%s", command.c_str()),
469 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530470 elog<InternalFailure>();
471 }
472 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530473}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500474} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530475
476namespace mac_address
477{
478
479constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
480constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
481constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
482constexpr auto propIntf = "org.freedesktop.DBus.Properties";
483constexpr auto methodGet = "Get";
484
485using DbusObjectPath = std::string;
486using DbusService = std::string;
487using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500488using ObjectTree =
489 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530490
491constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
492constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500493 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530494constexpr auto invRoot = "/xyz/openbmc_project/inventory";
495
496std::string getfromInventory(sdbusplus::bus::bus& bus)
497{
498 std::vector<DbusInterface> interfaces;
499 interfaces.emplace_back(invNetworkIntf);
500
501 auto depth = 0;
502
Gunnar Mills57d9c502018-09-14 14:42:34 -0500503 auto mapperCall =
504 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530505
506 mapperCall.append(invRoot, depth, interfaces);
507
508 auto mapperReply = bus.call(mapperCall);
509 if (mapperReply.is_method_error())
510 {
511 log<level::ERR>("Error in mapper call");
512 elog<InternalFailure>();
513 }
514
515 ObjectTree objectTree;
516 mapperReply.read(objectTree);
517
518 if (objectTree.empty())
519 {
520 log<level::ERR>("No Object has implemented the interface",
521 entry("INTERFACE=%s", invNetworkIntf));
522 elog<InternalFailure>();
523 }
524
Gunnar Millsa251a782017-09-26 16:49:08 -0500525 // It is expected that only one object has implemented this interface.
Ratan Guptabd303b12017-08-18 17:10:07 +0530526
527 auto objPath = objectTree.begin()->first;
528 auto service = objectTree.begin()->second.begin()->first;
529
530 sdbusplus::message::variant<std::string> value;
531
Gunnar Mills57d9c502018-09-14 14:42:34 -0500532 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
533 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530534
535 method.append(invNetworkIntf, "MACAddress");
536
537 auto reply = bus.call(method);
538 if (reply.is_method_error())
539 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500540 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530541 entry("PATH=%s", objPath.c_str()),
542 entry("INTERFACE=%s", invNetworkIntf));
543 elog<InternalFailure>();
544 }
545
546 reply.read(value);
547 return value.get<std::string>();
548}
549
Gunnar Mills57d9c502018-09-14 14:42:34 -0500550} // namespace mac_address
551} // namespace network
552} // namespace phosphor