blob: 67a9345c675f56d422f05f9bb2691c44cb842863 [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>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053014#include <filesystem>
Manojkiran Edacc099a82020-05-11 14:25:16 +053015#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070016#include <list>
Manojkiran Edacc099a82020-05-11 14:25:16 +053017#include <nlohmann/json.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070018#include <phosphor-logging/elog-errors.hpp>
19#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080020#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070021#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070022#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070023#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070024#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053025
26namespace phosphor
27{
28namespace network
29{
Ratan Guptabc886292017-07-25 18:29:57 +053030
Ratan Gupta8804feb2017-05-25 10:49:57 +053031using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053032using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053033namespace fs = std::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053034
Lei YU3894ce72021-03-18 14:53:42 +080035namespace internal
36{
37
38void executeCommandinChildProcess(const char* path, char** args)
39{
40 using namespace std::string_literals;
41 pid_t pid = fork();
42 int status{};
43
44 if (pid == 0)
45 {
46 execv(path, args);
47 auto error = errno;
48 // create the command from var args.
49 std::string command = path + " "s;
50
51 for (int i = 0; args[i]; i++)
52 {
53 command += args[i] + " "s;
54 }
55
56 log<level::ERR>("Couldn't exceute the command",
57 entry("ERRNO=%d", error),
58 entry("CMD=%s", command.c_str()));
59 elog<InternalFailure>();
60 }
61 else if (pid < 0)
62 {
63 auto error = errno;
64 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
65 elog<InternalFailure>();
66 }
67 else if (pid > 0)
68 {
69 while (waitpid(pid, &status, 0) == -1)
70 {
71 if (errno != EINTR)
72 { // Error other than EINTR
73 status = -1;
74 break;
75 }
76 }
77
78 if (status < 0)
79 {
80 std::string command = path + " "s;
81 for (int i = 0; args[i]; i++)
82 {
83 command += args[i] + " "s;
84 }
85
86 log<level::ERR>("Unable to execute the command",
87 entry("CMD=%s", command.c_str()),
88 entry("STATUS=%d", status));
89 elog<InternalFailure>();
90 }
91 }
92}
93
94} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +053095
96uint8_t toCidr(int addressFamily, const std::string& subnetMask)
97{
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -070098 uint32_t subnet[sizeof(in6_addr) / sizeof(uint32_t)];
99 if (inet_pton(addressFamily, subnetMask.c_str(), &subnet) != 1)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530100 {
101 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500102 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530103 return 0;
104 }
105
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700106 static_assert(sizeof(in6_addr) % sizeof(uint32_t) == 0);
107 static_assert(sizeof(in_addr) % sizeof(uint32_t) == 0);
108 auto i = (addressFamily == AF_INET ? sizeof(in_addr) : sizeof(in6_addr)) /
109 sizeof(uint32_t);
110 while (i > 0)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530111 {
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700112 if (subnet[--i] != 0)
113 {
114 auto v = be32toh(subnet[i]);
115 static_assert(sizeof(unsigned) == sizeof(uint32_t));
116 auto trailing = __builtin_ctz(v);
117 auto ret = (i + 1) * 32 - trailing;
118 bool valid = ~v == 0 || 32 == trailing + __builtin_clz(~v);
119 while (i > 0 && (valid = (~subnet[--i] == 0) && valid))
120 ;
121 if (!valid)
122 {
123 log<level::ERR>("Invalid netmask",
124 entry("SUBNETMASK=%s", subnetMask.c_str()));
125 return 0;
126 }
127 return ret;
128 }
Ratan Gupta8804feb2017-05-25 10:49:57 +0530129 }
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -0700130 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530131}
132
133std::string toMask(int addressFamily, uint8_t prefix)
134{
135 if (addressFamily == AF_INET6)
136 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500137 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530138 return "";
139 }
140
141 if (prefix < 1 || prefix > 30)
142 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500143 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530144 return "";
145 }
146 /* Create the netmask from the number of bits */
147 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500148 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530149 {
150 mask |= 1 << (31 - i);
151 }
152 struct in_addr netmask;
153 netmask.s_addr = htonl(mask);
154 return inet_ntoa(netmask);
155}
156
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800157InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
158{
159 if (addressFamily == AF_INET)
160 {
161 struct in_addr ret;
162 if (buf.size() != sizeof(ret))
163 {
164 throw std::runtime_error("Buf not in_addr sized");
165 }
166 memcpy(&ret, buf.data(), sizeof(ret));
167 return ret;
168 }
169 else if (addressFamily == AF_INET6)
170 {
171 struct in6_addr ret;
172 if (buf.size() != sizeof(ret))
173 {
174 throw std::runtime_error("Buf not in6_addr sized");
175 }
176 memcpy(&ret, buf.data(), sizeof(ret));
177 return ret;
178 }
179
180 throw std::runtime_error("Unsupported address family");
181}
182
Alexander Filippov983da552021-02-08 15:26:54 +0300183std::string toString(const struct in_addr& addr)
184{
185 std::string ip(INET_ADDRSTRLEN, '\0');
186 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
187 {
188 throw std::runtime_error("Failed to convert IP4 to string");
189 }
190
191 ip.resize(strlen(ip.c_str()));
192 return ip;
193}
194
195std::string toString(const struct in6_addr& addr)
196{
197 std::string ip(INET6_ADDRSTRLEN, '\0');
198 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
199 {
200 throw std::runtime_error("Failed to convert IP6 to string");
201 }
202
203 ip.resize(strlen(ip.c_str()));
204 return ip;
205}
206
William A. Kennington III5058f572019-01-30 17:18:14 -0800207std::string toString(const InAddrAny& addr)
208{
William A. Kennington III5058f572019-01-30 17:18:14 -0800209 if (std::holds_alternative<struct in_addr>(addr))
210 {
211 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300212 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800213 }
214 else if (std::holds_alternative<struct in6_addr>(addr))
215 {
216 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300217 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800218 }
Alexander Filippov983da552021-02-08 15:26:54 +0300219
220 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800221}
222
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500223bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530224{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500225 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
226}
227
228bool isValidIP(int addressFamily, const std::string& address)
229{
230 unsigned char buf[sizeof(struct in6_addr)];
231
232 return inet_pton(addressFamily, address.c_str(), buf) > 0;
233}
234
235bool isValidPrefix(int addressFamily, uint8_t prefixLength)
236{
237 if (addressFamily == AF_INET)
238 {
239 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
240 prefixLength > IPV4_MAX_PREFIX_LENGTH)
241 {
242 return false;
243 }
244 }
245
246 if (addressFamily == AF_INET6)
247 {
248 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
249 prefixLength > IPV6_MAX_PREFIX_LENGTH)
250 {
251 return false;
252 }
253 }
254
255 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530256}
257
Ratan Gupta3681a502017-06-17 19:20:04 +0530258IntfAddrMap getInterfaceAddrs()
259{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500260 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530261 struct ifaddrs* ifaddr = nullptr;
262
263 // attempt to fill struct with ifaddrs
264 if (getifaddrs(&ifaddr) == -1)
265 {
266 auto error = errno;
267 log<level::ERR>("Error occurred during the getifaddrs call",
268 entry("ERRNO=%s", strerror(error)));
269 elog<InternalFailure>();
270 }
271
272 AddrPtr ifaddrPtr(ifaddr);
273 ifaddr = nullptr;
274
Gunnar Mills57d9c502018-09-14 14:42:34 -0500275 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530276
277 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
278 {
279 // walk interfaces
280 if (ifa->ifa_addr == nullptr)
281 {
282 continue;
283 }
284
285 // get only INET interfaces not ipv6
286 if (ifa->ifa_addr->sa_family == AF_INET ||
287 ifa->ifa_addr->sa_family == AF_INET6)
288 {
289 // if loopback, or not running ignore
290 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
291 !(ifa->ifa_flags & IFF_RUNNING))
292 {
293 continue;
294 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530295 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500296 AddrInfo info{};
297 char ip[INET6_ADDRSTRLEN] = {0};
298 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530299
300 if (ifa->ifa_addr->sa_family == AF_INET)
301 {
302
303 inet_ntop(ifa->ifa_addr->sa_family,
304 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500305 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530306
Gunnar Mills57d9c502018-09-14 14:42:34 -0500307 inet_ntop(
308 ifa->ifa_addr->sa_family,
309 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
310 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530311 }
312 else
313 {
314 inet_ntop(ifa->ifa_addr->sa_family,
315 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500316 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530317
Gunnar Mills57d9c502018-09-14 14:42:34 -0500318 inet_ntop(
319 ifa->ifa_addr->sa_family,
320 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
321 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530322 }
323
324 info.addrType = ifa->ifa_addr->sa_family;
325 info.ipaddress = ip;
326 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700327 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530328 }
329 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530330 return intfMap;
331}
332
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530333InterfaceList getInterfaces()
334{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500335 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530336 struct ifaddrs* ifaddr = nullptr;
337
338 // attempt to fill struct with ifaddrs
339 if (getifaddrs(&ifaddr) == -1)
340 {
341 auto error = errno;
342 log<level::ERR>("Error occurred during the getifaddrs call",
343 entry("ERRNO=%d", error));
344 elog<InternalFailure>();
345 }
346
347 AddrPtr ifaddrPtr(ifaddr);
348 ifaddr = nullptr;
349
350 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
351 {
352 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700353 // if loopback ignore
354 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530355 {
356 continue;
357 }
358 interfaces.emplace(ifa->ifa_name);
359 }
360 return interfaces;
361}
362
Ratan Guptabc886292017-07-25 18:29:57 +0530363void deleteInterface(const std::string& intf)
364{
365 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500366 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530367
368 if (pid == 0)
369 {
370
371 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
372 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500373 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530374 entry("INTF=%s", intf.c_str()));
375 elog<InternalFailure>();
376 }
377 else if (pid < 0)
378 {
379 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500380 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530381 elog<InternalFailure>();
382 }
383 else if (pid > 0)
384 {
385 while (waitpid(pid, &status, 0) == -1)
386 {
387 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500388 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530389 status = -1;
390 break;
391 }
392 }
393
Gunnar Mills57d9c502018-09-14 14:42:34 -0500394 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530395 {
396 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500397 entry("INTF=%s", intf.c_str()),
398 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530399 elog<InternalFailure>();
400 }
401 }
402}
403
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700404std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
405{
406 constexpr char ethPrefix[] = "eth";
407 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
408 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
409 {
410 return std::nullopt;
411 }
412 const auto intfSuffix = intf + ethPrefixLen;
413 if (intfSuffix[0] == '\0')
414 {
415 return std::nullopt;
416 }
417 char* end;
418 unsigned long idx = strtoul(intfSuffix, &end, 10);
419 if (end[0] != '\0')
420 {
421 return std::nullopt;
422 }
423 if (idx == 0)
424 {
425 return "ethaddr";
426 }
427 return "eth" + std::to_string(idx) + "addr";
428}
429
Johnathan Mantey817012a2020-01-30 15:07:39 -0800430EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
431 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530432{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800433 EthernetInterfaceIntf::DHCPConf dhcp =
434 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530435 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500436 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530437 fs::path confPath = confDir;
438 std::string fileName = systemd::config::networkFilePrefix + intf +
439 systemd::config::networkFileSuffix;
440 confPath /= fileName;
441
Ratan Guptac27170a2017-11-22 15:44:42 +0530442 auto rc = config::ReturnCode::SUCCESS;
443 config::ValueList values;
444 config::Parser parser(confPath.string());
445
446 std::tie(rc, values) = parser.getValues("Network", "DHCP");
447 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530448 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530449 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500450 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530451 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530452 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530453 // There will be only single value for DHCP key.
454 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530455 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800456 dhcp = EthernetInterfaceIntf::DHCPConf::both;
457 }
458 else if (values[0] == "ipv4")
459 {
460 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
461 }
462 else if (values[0] == "ipv6")
463 {
464 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530465 }
466 return dhcp;
467}
468
Ratan Guptabd303b12017-08-18 17:10:07 +0530469namespace mac_address
470{
471
472constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
473constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
474constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
475constexpr auto propIntf = "org.freedesktop.DBus.Properties";
476constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530477constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530478
479using DbusObjectPath = std::string;
480using DbusService = std::string;
481using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500482using ObjectTree =
483 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530484
485constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
486constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500487 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530488constexpr auto invRoot = "/xyz/openbmc_project/inventory";
489
Alvin Wang38a63c32019-08-29 22:56:46 +0800490ether_addr getfromInventory(sdbusplus::bus::bus& bus,
491 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530492{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530493
494 std::string interfaceName = intfName;
495
496#if SYNC_MAC_FROM_INVENTORY
497 // load the config JSON from the Read Only Path
498 std::ifstream in(configFile);
499 nlohmann::json configJson;
500 in >> configJson;
501 interfaceName = configJson[intfName];
502#endif
503
Ratan Guptabd303b12017-08-18 17:10:07 +0530504 std::vector<DbusInterface> interfaces;
505 interfaces.emplace_back(invNetworkIntf);
506
507 auto depth = 0;
508
Gunnar Mills57d9c502018-09-14 14:42:34 -0500509 auto mapperCall =
510 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530511
512 mapperCall.append(invRoot, depth, interfaces);
513
514 auto mapperReply = bus.call(mapperCall);
515 if (mapperReply.is_method_error())
516 {
517 log<level::ERR>("Error in mapper call");
518 elog<InternalFailure>();
519 }
520
521 ObjectTree objectTree;
522 mapperReply.read(objectTree);
523
524 if (objectTree.empty())
525 {
526 log<level::ERR>("No Object has implemented the interface",
527 entry("INTERFACE=%s", invNetworkIntf));
528 elog<InternalFailure>();
529 }
530
Alvin Wang38a63c32019-08-29 22:56:46 +0800531 DbusObjectPath objPath;
532 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530533
Alvin Wang38a63c32019-08-29 22:56:46 +0800534 if (1 == objectTree.size())
535 {
536 objPath = objectTree.begin()->first;
537 service = objectTree.begin()->second.begin()->first;
538 }
539 else
540 {
541 // If there are more than 2 objects, object path must contain the
542 // interface name
543 for (auto const& object : objectTree)
544 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530545 log<level::INFO>("interface",
546 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800547 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530548
549 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800550 {
551 objPath = object.first;
552 service = object.second.begin()->first;
553 break;
554 }
555 }
556
557 if (objPath.empty())
558 {
559 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530560 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800561 elog<InternalFailure>();
562 }
563 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530564
Gunnar Mills57d9c502018-09-14 14:42:34 -0500565 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
566 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530567
568 method.append(invNetworkIntf, "MACAddress");
569
570 auto reply = bus.call(method);
571 if (reply.is_method_error())
572 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500573 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530574 entry("PATH=%s", objPath.c_str()),
575 entry("INTERFACE=%s", invNetworkIntf));
576 elog<InternalFailure>();
577 }
578
William A. Kennington III1137a972019-04-20 20:49:58 -0700579 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530580 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700581 return fromString(std::get<std::string>(value));
582}
583
584ether_addr fromString(const char* str)
585{
586 struct ether_addr* mac = ether_aton(str);
587 if (mac == nullptr)
588 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600589 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700590 }
591 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530592}
593
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700594std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800595{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800596 char buf[18] = {0};
597 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
598 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
599 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
600 mac.ether_addr_octet[5]);
601 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800602}
603
William A. Kennington III1137a972019-04-20 20:49:58 -0700604bool isEmpty(const ether_addr& mac)
605{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700606 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700607}
608
609bool isMulticast(const ether_addr& mac)
610{
611 return mac.ether_addr_octet[0] & 0b1;
612}
613
614bool isUnicast(const ether_addr& mac)
615{
616 return !isEmpty(mac) && !isMulticast(mac);
617}
618
Gunnar Mills57d9c502018-09-14 14:42:34 -0500619} // namespace mac_address
620} // namespace network
621} // namespace phosphor