blob: bf6bf7f1d0f232e70e665f683bd30f1022be720a [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 +053031namespace
32{
33
34using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053035using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053036namespace fs = std::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053037
Gunnar Mills57d9c502018-09-14 14:42:34 -050038} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053039
40uint8_t toCidr(int addressFamily, const std::string& subnetMask)
41{
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -070042 uint32_t subnet[sizeof(in6_addr) / sizeof(uint32_t)];
43 if (inet_pton(addressFamily, subnetMask.c_str(), &subnet) != 1)
Ratan Gupta8804feb2017-05-25 10:49:57 +053044 {
45 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050046 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053047 return 0;
48 }
49
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -070050 static_assert(sizeof(in6_addr) % sizeof(uint32_t) == 0);
51 static_assert(sizeof(in_addr) % sizeof(uint32_t) == 0);
52 auto i = (addressFamily == AF_INET ? sizeof(in_addr) : sizeof(in6_addr)) /
53 sizeof(uint32_t);
54 while (i > 0)
Ratan Gupta8804feb2017-05-25 10:49:57 +053055 {
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -070056 if (subnet[--i] != 0)
57 {
58 auto v = be32toh(subnet[i]);
59 static_assert(sizeof(unsigned) == sizeof(uint32_t));
60 auto trailing = __builtin_ctz(v);
61 auto ret = (i + 1) * 32 - trailing;
62 bool valid = ~v == 0 || 32 == trailing + __builtin_clz(~v);
63 while (i > 0 && (valid = (~subnet[--i] == 0) && valid))
64 ;
65 if (!valid)
66 {
67 log<level::ERR>("Invalid netmask",
68 entry("SUBNETMASK=%s", subnetMask.c_str()));
69 return 0;
70 }
71 return ret;
72 }
Ratan Gupta8804feb2017-05-25 10:49:57 +053073 }
William A. Kennington IIIa1b897e2021-03-31 13:27:11 -070074 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +053075}
76
77std::string toMask(int addressFamily, uint8_t prefix)
78{
79 if (addressFamily == AF_INET6)
80 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050081 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +053082 return "";
83 }
84
85 if (prefix < 1 || prefix > 30)
86 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050087 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +053088 return "";
89 }
90 /* Create the netmask from the number of bits */
91 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050092 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +053093 {
94 mask |= 1 << (31 - i);
95 }
96 struct in_addr netmask;
97 netmask.s_addr = htonl(mask);
98 return inet_ntoa(netmask);
99}
100
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800101InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
102{
103 if (addressFamily == AF_INET)
104 {
105 struct in_addr ret;
106 if (buf.size() != sizeof(ret))
107 {
108 throw std::runtime_error("Buf not in_addr sized");
109 }
110 memcpy(&ret, buf.data(), sizeof(ret));
111 return ret;
112 }
113 else if (addressFamily == AF_INET6)
114 {
115 struct in6_addr ret;
116 if (buf.size() != sizeof(ret))
117 {
118 throw std::runtime_error("Buf not in6_addr sized");
119 }
120 memcpy(&ret, buf.data(), sizeof(ret));
121 return ret;
122 }
123
124 throw std::runtime_error("Unsupported address family");
125}
126
Alexander Filippov983da552021-02-08 15:26:54 +0300127std::string toString(const struct in_addr& addr)
128{
129 std::string ip(INET_ADDRSTRLEN, '\0');
130 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
131 {
132 throw std::runtime_error("Failed to convert IP4 to string");
133 }
134
135 ip.resize(strlen(ip.c_str()));
136 return ip;
137}
138
139std::string toString(const struct in6_addr& addr)
140{
141 std::string ip(INET6_ADDRSTRLEN, '\0');
142 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
143 {
144 throw std::runtime_error("Failed to convert IP6 to string");
145 }
146
147 ip.resize(strlen(ip.c_str()));
148 return ip;
149}
150
William A. Kennington III5058f572019-01-30 17:18:14 -0800151std::string toString(const InAddrAny& addr)
152{
William A. Kennington III5058f572019-01-30 17:18:14 -0800153 if (std::holds_alternative<struct in_addr>(addr))
154 {
155 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300156 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800157 }
158 else if (std::holds_alternative<struct in6_addr>(addr))
159 {
160 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300161 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800162 }
Alexander Filippov983da552021-02-08 15:26:54 +0300163
164 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800165}
166
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500167bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530168{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500169 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
170}
171
172bool isValidIP(int addressFamily, const std::string& address)
173{
174 unsigned char buf[sizeof(struct in6_addr)];
175
176 return inet_pton(addressFamily, address.c_str(), buf) > 0;
177}
178
179bool isValidPrefix(int addressFamily, uint8_t prefixLength)
180{
181 if (addressFamily == AF_INET)
182 {
183 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
184 prefixLength > IPV4_MAX_PREFIX_LENGTH)
185 {
186 return false;
187 }
188 }
189
190 if (addressFamily == AF_INET6)
191 {
192 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
193 prefixLength > IPV6_MAX_PREFIX_LENGTH)
194 {
195 return false;
196 }
197 }
198
199 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530200}
201
Ratan Gupta3681a502017-06-17 19:20:04 +0530202IntfAddrMap getInterfaceAddrs()
203{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500204 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530205 struct ifaddrs* ifaddr = nullptr;
206
207 // attempt to fill struct with ifaddrs
208 if (getifaddrs(&ifaddr) == -1)
209 {
210 auto error = errno;
211 log<level::ERR>("Error occurred during the getifaddrs call",
212 entry("ERRNO=%s", strerror(error)));
213 elog<InternalFailure>();
214 }
215
216 AddrPtr ifaddrPtr(ifaddr);
217 ifaddr = nullptr;
218
Gunnar Mills57d9c502018-09-14 14:42:34 -0500219 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530220
221 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
222 {
223 // walk interfaces
224 if (ifa->ifa_addr == nullptr)
225 {
226 continue;
227 }
228
229 // get only INET interfaces not ipv6
230 if (ifa->ifa_addr->sa_family == AF_INET ||
231 ifa->ifa_addr->sa_family == AF_INET6)
232 {
233 // if loopback, or not running ignore
234 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
235 !(ifa->ifa_flags & IFF_RUNNING))
236 {
237 continue;
238 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530239 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500240 AddrInfo info{};
241 char ip[INET6_ADDRSTRLEN] = {0};
242 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530243
244 if (ifa->ifa_addr->sa_family == AF_INET)
245 {
246
247 inet_ntop(ifa->ifa_addr->sa_family,
248 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500249 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530250
Gunnar Mills57d9c502018-09-14 14:42:34 -0500251 inet_ntop(
252 ifa->ifa_addr->sa_family,
253 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
254 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530255 }
256 else
257 {
258 inet_ntop(ifa->ifa_addr->sa_family,
259 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500260 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530261
Gunnar Mills57d9c502018-09-14 14:42:34 -0500262 inet_ntop(
263 ifa->ifa_addr->sa_family,
264 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
265 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530266 }
267
268 info.addrType = ifa->ifa_addr->sa_family;
269 info.ipaddress = ip;
270 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700271 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530272 }
273 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530274 return intfMap;
275}
276
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530277InterfaceList getInterfaces()
278{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500279 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530280 struct ifaddrs* ifaddr = nullptr;
281
282 // attempt to fill struct with ifaddrs
283 if (getifaddrs(&ifaddr) == -1)
284 {
285 auto error = errno;
286 log<level::ERR>("Error occurred during the getifaddrs call",
287 entry("ERRNO=%d", error));
288 elog<InternalFailure>();
289 }
290
291 AddrPtr ifaddrPtr(ifaddr);
292 ifaddr = nullptr;
293
294 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
295 {
296 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700297 // if loopback ignore
298 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530299 {
300 continue;
301 }
302 interfaces.emplace(ifa->ifa_name);
303 }
304 return interfaces;
305}
306
Ratan Guptabc886292017-07-25 18:29:57 +0530307void deleteInterface(const std::string& intf)
308{
309 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500310 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530311
312 if (pid == 0)
313 {
314
315 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
316 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500317 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530318 entry("INTF=%s", intf.c_str()));
319 elog<InternalFailure>();
320 }
321 else if (pid < 0)
322 {
323 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500324 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530325 elog<InternalFailure>();
326 }
327 else if (pid > 0)
328 {
329 while (waitpid(pid, &status, 0) == -1)
330 {
331 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500332 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530333 status = -1;
334 break;
335 }
336 }
337
Gunnar Mills57d9c502018-09-14 14:42:34 -0500338 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530339 {
340 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500341 entry("INTF=%s", intf.c_str()),
342 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530343 elog<InternalFailure>();
344 }
345 }
346}
347
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700348std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
349{
350 constexpr char ethPrefix[] = "eth";
351 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
352 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
353 {
354 return std::nullopt;
355 }
356 const auto intfSuffix = intf + ethPrefixLen;
357 if (intfSuffix[0] == '\0')
358 {
359 return std::nullopt;
360 }
361 char* end;
362 unsigned long idx = strtoul(intfSuffix, &end, 10);
363 if (end[0] != '\0')
364 {
365 return std::nullopt;
366 }
367 if (idx == 0)
368 {
369 return "ethaddr";
370 }
371 return "eth" + std::to_string(idx) + "addr";
372}
373
Johnathan Mantey817012a2020-01-30 15:07:39 -0800374EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
375 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530376{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800377 EthernetInterfaceIntf::DHCPConf dhcp =
378 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530379 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500380 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530381 fs::path confPath = confDir;
382 std::string fileName = systemd::config::networkFilePrefix + intf +
383 systemd::config::networkFileSuffix;
384 confPath /= fileName;
385
Ratan Guptac27170a2017-11-22 15:44:42 +0530386 auto rc = config::ReturnCode::SUCCESS;
387 config::ValueList values;
388 config::Parser parser(confPath.string());
389
390 std::tie(rc, values) = parser.getValues("Network", "DHCP");
391 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530392 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530393 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500394 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530395 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530396 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530397 // There will be only single value for DHCP key.
398 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530399 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800400 dhcp = EthernetInterfaceIntf::DHCPConf::both;
401 }
402 else if (values[0] == "ipv4")
403 {
404 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
405 }
406 else if (values[0] == "ipv6")
407 {
408 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530409 }
410 return dhcp;
411}
412
Ratan Guptabd303b12017-08-18 17:10:07 +0530413namespace internal
414{
Ratan Gupta56187e72017-08-13 09:40:14 +0530415
Ratan Guptabd303b12017-08-18 17:10:07 +0530416void executeCommandinChildProcess(const char* path, char** args)
417{
418 using namespace std::string_literals;
419 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500420 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530421
422 if (pid == 0)
423 {
424 execv(path, args);
425 auto error = errno;
426 // create the command from var args.
427 std::string command = path + " "s;
428
Gunnar Mills57d9c502018-09-14 14:42:34 -0500429 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530430 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500431 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530432 }
433
434 log<level::ERR>("Couldn't exceute the command",
435 entry("ERRNO=%d", error),
436 entry("CMD=%s", command.c_str()));
437 elog<InternalFailure>();
438 }
439 else if (pid < 0)
440 {
441 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500442 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530443 elog<InternalFailure>();
444 }
445 else if (pid > 0)
446 {
447 while (waitpid(pid, &status, 0) == -1)
448 {
449 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500450 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530451 status = -1;
452 break;
453 }
454 }
455
Gunnar Mills57d9c502018-09-14 14:42:34 -0500456 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530457 {
458 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500459 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530460 {
461 command += args[i] + " "s;
462 }
463
464 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500465 entry("CMD=%s", command.c_str()),
466 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530467 elog<InternalFailure>();
468 }
469 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530470}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500471} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530472
473namespace mac_address
474{
475
476constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
477constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
478constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
479constexpr auto propIntf = "org.freedesktop.DBus.Properties";
480constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530481constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530482
483using DbusObjectPath = std::string;
484using DbusService = std::string;
485using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500486using ObjectTree =
487 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530488
489constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
490constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500491 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530492constexpr auto invRoot = "/xyz/openbmc_project/inventory";
493
Alvin Wang38a63c32019-08-29 22:56:46 +0800494ether_addr getfromInventory(sdbusplus::bus::bus& bus,
495 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530496{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530497
498 std::string interfaceName = intfName;
499
500#if SYNC_MAC_FROM_INVENTORY
501 // load the config JSON from the Read Only Path
502 std::ifstream in(configFile);
503 nlohmann::json configJson;
504 in >> configJson;
505 interfaceName = configJson[intfName];
506#endif
507
Ratan Guptabd303b12017-08-18 17:10:07 +0530508 std::vector<DbusInterface> interfaces;
509 interfaces.emplace_back(invNetworkIntf);
510
511 auto depth = 0;
512
Gunnar Mills57d9c502018-09-14 14:42:34 -0500513 auto mapperCall =
514 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530515
516 mapperCall.append(invRoot, depth, interfaces);
517
518 auto mapperReply = bus.call(mapperCall);
519 if (mapperReply.is_method_error())
520 {
521 log<level::ERR>("Error in mapper call");
522 elog<InternalFailure>();
523 }
524
525 ObjectTree objectTree;
526 mapperReply.read(objectTree);
527
528 if (objectTree.empty())
529 {
530 log<level::ERR>("No Object has implemented the interface",
531 entry("INTERFACE=%s", invNetworkIntf));
532 elog<InternalFailure>();
533 }
534
Alvin Wang38a63c32019-08-29 22:56:46 +0800535 DbusObjectPath objPath;
536 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530537
Alvin Wang38a63c32019-08-29 22:56:46 +0800538 if (1 == objectTree.size())
539 {
540 objPath = objectTree.begin()->first;
541 service = objectTree.begin()->second.begin()->first;
542 }
543 else
544 {
545 // If there are more than 2 objects, object path must contain the
546 // interface name
547 for (auto const& object : objectTree)
548 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530549 log<level::INFO>("interface",
550 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800551 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530552
553 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800554 {
555 objPath = object.first;
556 service = object.second.begin()->first;
557 break;
558 }
559 }
560
561 if (objPath.empty())
562 {
563 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530564 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800565 elog<InternalFailure>();
566 }
567 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530568
Gunnar Mills57d9c502018-09-14 14:42:34 -0500569 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
570 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530571
572 method.append(invNetworkIntf, "MACAddress");
573
574 auto reply = bus.call(method);
575 if (reply.is_method_error())
576 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500577 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530578 entry("PATH=%s", objPath.c_str()),
579 entry("INTERFACE=%s", invNetworkIntf));
580 elog<InternalFailure>();
581 }
582
William A. Kennington III1137a972019-04-20 20:49:58 -0700583 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530584 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700585 return fromString(std::get<std::string>(value));
586}
587
588ether_addr fromString(const char* str)
589{
590 struct ether_addr* mac = ether_aton(str);
591 if (mac == nullptr)
592 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600593 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700594 }
595 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530596}
597
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700598std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800599{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800600 char buf[18] = {0};
601 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
602 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
603 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
604 mac.ether_addr_octet[5]);
605 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800606}
607
William A. Kennington III1137a972019-04-20 20:49:58 -0700608bool isEmpty(const ether_addr& mac)
609{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700610 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700611}
612
613bool isMulticast(const ether_addr& mac)
614{
615 return mac.ether_addr_octet[0] & 0b1;
616}
617
618bool isUnicast(const ether_addr& mac)
619{
620 return !isEmpty(mac) && !isMulticast(mac);
621}
622
Gunnar Mills57d9c502018-09-14 14:42:34 -0500623} // namespace mac_address
624} // namespace network
625} // namespace phosphor