blob: 25d2838265f84c0f263ffa238a00265b6b17a6fd [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
38uint8_t toV6Cidr(const std::string& subnetMask)
39{
Johnathan Mantey359623e2021-01-26 15:02:54 -080040 struct in6_addr subnet;
41 int ret = inet_pton(AF_INET6, subnetMask.c_str(), &subnet);
42 if (ret != 1)
Ratan Gupta8804feb2017-05-25 10:49:57 +053043 {
Johnathan Mantey359623e2021-01-26 15:02:54 -080044 log<level::ERR>("Invalid Mask",
45 entry("SUBNETMASK=%s", subnetMask.c_str()));
46 return 0;
47 }
Ratan Gupta8804feb2017-05-25 10:49:57 +053048
Johnathan Mantey359623e2021-01-26 15:02:54 -080049 uint8_t cidr = 0;
50 bool zeroesFound = false;
51 int bitsSet, trailingZeroes;
52 for (int lv = 0; lv < 4; lv++)
53 {
54 subnet.s6_addr32[lv] = be32toh(subnet.s6_addr32[lv]);
55 bitsSet = __builtin_popcount(subnet.s6_addr32[lv]);
56 if (zeroesFound && bitsSet)
Ratan Gupta8804feb2017-05-25 10:49:57 +053057 {
58 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050059 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053060 return 0;
61 }
Lei YUa3b14dc2021-04-06 11:42:10 +080062
63 // The __builtin_ctz function returns -1 when the value is 0 on arm.
64 // GCC's doc specifies that:
65 // If x is 0, the result is undefined.
66 // https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Other-Builtins.html
67 // So we could not rely on the undefined behavior.
68 // Handling the 0 case specifically fixes the issue.
69 if (subnet.s6_addr32[lv] == 0)
70 {
71 trailingZeroes = 32;
72 }
73 else
74 {
75 trailingZeroes = __builtin_ctz(subnet.s6_addr32[lv]);
76 }
Johnathan Mantey359623e2021-01-26 15:02:54 -080077 zeroesFound |= trailingZeroes;
Ratan Gupta8804feb2017-05-25 10:49:57 +053078
Johnathan Mantey359623e2021-01-26 15:02:54 -080079 if (bitsSet + trailingZeroes != 32)
Ratan Gupta8804feb2017-05-25 10:49:57 +053080 {
Johnathan Mantey359623e2021-01-26 15:02:54 -080081 // There are '1' bits interspersed with '0' bits
82 log<level::ERR>("Invalid Mask",
83 entry("SUBNETMASK=%s", subnetMask.c_str()));
84 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +053085 }
Johnathan Mantey359623e2021-01-26 15:02:54 -080086 cidr += bitsSet;
87 }
Ratan Gupta8804feb2017-05-25 10:49:57 +053088 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
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800148InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
149{
150 if (addressFamily == AF_INET)
151 {
152 struct in_addr ret;
153 if (buf.size() != sizeof(ret))
154 {
155 throw std::runtime_error("Buf not in_addr sized");
156 }
157 memcpy(&ret, buf.data(), sizeof(ret));
158 return ret;
159 }
160 else if (addressFamily == AF_INET6)
161 {
162 struct in6_addr ret;
163 if (buf.size() != sizeof(ret))
164 {
165 throw std::runtime_error("Buf not in6_addr sized");
166 }
167 memcpy(&ret, buf.data(), sizeof(ret));
168 return ret;
169 }
170
171 throw std::runtime_error("Unsupported address family");
172}
173
Alexander Filippov983da552021-02-08 15:26:54 +0300174std::string toString(const struct in_addr& addr)
175{
176 std::string ip(INET_ADDRSTRLEN, '\0');
177 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
178 {
179 throw std::runtime_error("Failed to convert IP4 to string");
180 }
181
182 ip.resize(strlen(ip.c_str()));
183 return ip;
184}
185
186std::string toString(const struct in6_addr& addr)
187{
188 std::string ip(INET6_ADDRSTRLEN, '\0');
189 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
190 {
191 throw std::runtime_error("Failed to convert IP6 to string");
192 }
193
194 ip.resize(strlen(ip.c_str()));
195 return ip;
196}
197
William A. Kennington III5058f572019-01-30 17:18:14 -0800198std::string toString(const InAddrAny& addr)
199{
William A. Kennington III5058f572019-01-30 17:18:14 -0800200 if (std::holds_alternative<struct in_addr>(addr))
201 {
202 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300203 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800204 }
205 else if (std::holds_alternative<struct in6_addr>(addr))
206 {
207 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300208 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800209 }
Alexander Filippov983da552021-02-08 15:26:54 +0300210
211 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800212}
213
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500214bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530215{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500216 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
217}
218
219bool isValidIP(int addressFamily, const std::string& address)
220{
221 unsigned char buf[sizeof(struct in6_addr)];
222
223 return inet_pton(addressFamily, address.c_str(), buf) > 0;
224}
225
226bool isValidPrefix(int addressFamily, uint8_t prefixLength)
227{
228 if (addressFamily == AF_INET)
229 {
230 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
231 prefixLength > IPV4_MAX_PREFIX_LENGTH)
232 {
233 return false;
234 }
235 }
236
237 if (addressFamily == AF_INET6)
238 {
239 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
240 prefixLength > IPV6_MAX_PREFIX_LENGTH)
241 {
242 return false;
243 }
244 }
245
246 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530247}
248
Ratan Gupta3681a502017-06-17 19:20:04 +0530249IntfAddrMap getInterfaceAddrs()
250{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500251 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530252 struct ifaddrs* ifaddr = nullptr;
253
254 // attempt to fill struct with ifaddrs
255 if (getifaddrs(&ifaddr) == -1)
256 {
257 auto error = errno;
258 log<level::ERR>("Error occurred during the getifaddrs call",
259 entry("ERRNO=%s", strerror(error)));
260 elog<InternalFailure>();
261 }
262
263 AddrPtr ifaddrPtr(ifaddr);
264 ifaddr = nullptr;
265
Gunnar Mills57d9c502018-09-14 14:42:34 -0500266 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530267
268 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
269 {
270 // walk interfaces
271 if (ifa->ifa_addr == nullptr)
272 {
273 continue;
274 }
275
276 // get only INET interfaces not ipv6
277 if (ifa->ifa_addr->sa_family == AF_INET ||
278 ifa->ifa_addr->sa_family == AF_INET6)
279 {
280 // if loopback, or not running ignore
281 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
282 !(ifa->ifa_flags & IFF_RUNNING))
283 {
284 continue;
285 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530286 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500287 AddrInfo info{};
288 char ip[INET6_ADDRSTRLEN] = {0};
289 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530290
291 if (ifa->ifa_addr->sa_family == AF_INET)
292 {
293
294 inet_ntop(ifa->ifa_addr->sa_family,
295 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500296 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530297
Gunnar Mills57d9c502018-09-14 14:42:34 -0500298 inet_ntop(
299 ifa->ifa_addr->sa_family,
300 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
301 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530302 }
303 else
304 {
305 inet_ntop(ifa->ifa_addr->sa_family,
306 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500307 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530308
Gunnar Mills57d9c502018-09-14 14:42:34 -0500309 inet_ntop(
310 ifa->ifa_addr->sa_family,
311 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
312 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530313 }
314
315 info.addrType = ifa->ifa_addr->sa_family;
316 info.ipaddress = ip;
317 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700318 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530319 }
320 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530321 return intfMap;
322}
323
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530324InterfaceList getInterfaces()
325{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500326 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530327 struct ifaddrs* ifaddr = nullptr;
328
329 // attempt to fill struct with ifaddrs
330 if (getifaddrs(&ifaddr) == -1)
331 {
332 auto error = errno;
333 log<level::ERR>("Error occurred during the getifaddrs call",
334 entry("ERRNO=%d", error));
335 elog<InternalFailure>();
336 }
337
338 AddrPtr ifaddrPtr(ifaddr);
339 ifaddr = nullptr;
340
341 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
342 {
343 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700344 // if loopback ignore
345 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530346 {
347 continue;
348 }
349 interfaces.emplace(ifa->ifa_name);
350 }
351 return interfaces;
352}
353
Ratan Guptabc886292017-07-25 18:29:57 +0530354void deleteInterface(const std::string& intf)
355{
356 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500357 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530358
359 if (pid == 0)
360 {
361
362 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
363 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500364 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530365 entry("INTF=%s", intf.c_str()));
366 elog<InternalFailure>();
367 }
368 else if (pid < 0)
369 {
370 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500371 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530372 elog<InternalFailure>();
373 }
374 else if (pid > 0)
375 {
376 while (waitpid(pid, &status, 0) == -1)
377 {
378 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500379 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530380 status = -1;
381 break;
382 }
383 }
384
Gunnar Mills57d9c502018-09-14 14:42:34 -0500385 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530386 {
387 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500388 entry("INTF=%s", intf.c_str()),
389 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530390 elog<InternalFailure>();
391 }
392 }
393}
394
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700395std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
396{
397 constexpr char ethPrefix[] = "eth";
398 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
399 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
400 {
401 return std::nullopt;
402 }
403 const auto intfSuffix = intf + ethPrefixLen;
404 if (intfSuffix[0] == '\0')
405 {
406 return std::nullopt;
407 }
408 char* end;
409 unsigned long idx = strtoul(intfSuffix, &end, 10);
410 if (end[0] != '\0')
411 {
412 return std::nullopt;
413 }
414 if (idx == 0)
415 {
416 return "ethaddr";
417 }
418 return "eth" + std::to_string(idx) + "addr";
419}
420
Johnathan Mantey817012a2020-01-30 15:07:39 -0800421EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
422 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530423{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800424 EthernetInterfaceIntf::DHCPConf dhcp =
425 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530426 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530428 fs::path confPath = confDir;
429 std::string fileName = systemd::config::networkFilePrefix + intf +
430 systemd::config::networkFileSuffix;
431 confPath /= fileName;
432
Ratan Guptac27170a2017-11-22 15:44:42 +0530433 auto rc = config::ReturnCode::SUCCESS;
434 config::ValueList values;
435 config::Parser parser(confPath.string());
436
437 std::tie(rc, values) = parser.getValues("Network", "DHCP");
438 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530439 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530440 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500441 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530442 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530443 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530444 // There will be only single value for DHCP key.
445 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530446 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800447 dhcp = EthernetInterfaceIntf::DHCPConf::both;
448 }
449 else if (values[0] == "ipv4")
450 {
451 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
452 }
453 else if (values[0] == "ipv6")
454 {
455 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530456 }
457 return dhcp;
458}
459
Ratan Guptabd303b12017-08-18 17:10:07 +0530460namespace internal
461{
Ratan Gupta56187e72017-08-13 09:40:14 +0530462
Ratan Guptabd303b12017-08-18 17:10:07 +0530463void executeCommandinChildProcess(const char* path, char** args)
464{
465 using namespace std::string_literals;
466 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500467 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530468
469 if (pid == 0)
470 {
471 execv(path, args);
472 auto error = errno;
473 // create the command from var args.
474 std::string command = path + " "s;
475
Gunnar Mills57d9c502018-09-14 14:42:34 -0500476 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530477 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500478 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530479 }
480
481 log<level::ERR>("Couldn't exceute the command",
482 entry("ERRNO=%d", error),
483 entry("CMD=%s", command.c_str()));
484 elog<InternalFailure>();
485 }
486 else if (pid < 0)
487 {
488 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500489 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530490 elog<InternalFailure>();
491 }
492 else if (pid > 0)
493 {
494 while (waitpid(pid, &status, 0) == -1)
495 {
496 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500497 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530498 status = -1;
499 break;
500 }
501 }
502
Gunnar Mills57d9c502018-09-14 14:42:34 -0500503 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530504 {
505 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500506 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530507 {
508 command += args[i] + " "s;
509 }
510
511 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500512 entry("CMD=%s", command.c_str()),
513 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530514 elog<InternalFailure>();
515 }
516 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530517}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500518} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530519
520namespace mac_address
521{
522
523constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
524constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
525constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
526constexpr auto propIntf = "org.freedesktop.DBus.Properties";
527constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530528constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530529
530using DbusObjectPath = std::string;
531using DbusService = std::string;
532using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500533using ObjectTree =
534 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530535
536constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
537constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500538 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530539constexpr auto invRoot = "/xyz/openbmc_project/inventory";
540
Alvin Wang38a63c32019-08-29 22:56:46 +0800541ether_addr getfromInventory(sdbusplus::bus::bus& bus,
542 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530543{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530544
545 std::string interfaceName = intfName;
546
547#if SYNC_MAC_FROM_INVENTORY
548 // load the config JSON from the Read Only Path
549 std::ifstream in(configFile);
550 nlohmann::json configJson;
551 in >> configJson;
552 interfaceName = configJson[intfName];
553#endif
554
Ratan Guptabd303b12017-08-18 17:10:07 +0530555 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
Alvin Wang38a63c32019-08-29 22:56:46 +0800582 DbusObjectPath objPath;
583 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530584
Alvin Wang38a63c32019-08-29 22:56:46 +0800585 if (1 == objectTree.size())
586 {
587 objPath = objectTree.begin()->first;
588 service = objectTree.begin()->second.begin()->first;
589 }
590 else
591 {
592 // If there are more than 2 objects, object path must contain the
593 // interface name
594 for (auto const& object : objectTree)
595 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530596 log<level::INFO>("interface",
597 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800598 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530599
600 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800601 {
602 objPath = object.first;
603 service = object.second.begin()->first;
604 break;
605 }
606 }
607
608 if (objPath.empty())
609 {
610 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530611 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800612 elog<InternalFailure>();
613 }
614 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530615
Gunnar Mills57d9c502018-09-14 14:42:34 -0500616 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
617 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530618
619 method.append(invNetworkIntf, "MACAddress");
620
621 auto reply = bus.call(method);
622 if (reply.is_method_error())
623 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500624 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530625 entry("PATH=%s", objPath.c_str()),
626 entry("INTERFACE=%s", invNetworkIntf));
627 elog<InternalFailure>();
628 }
629
William A. Kennington III1137a972019-04-20 20:49:58 -0700630 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530631 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700632 return fromString(std::get<std::string>(value));
633}
634
635ether_addr fromString(const char* str)
636{
637 struct ether_addr* mac = ether_aton(str);
638 if (mac == nullptr)
639 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600640 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700641 }
642 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530643}
644
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700645std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800646{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800647 char buf[18] = {0};
648 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
649 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
650 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
651 mac.ether_addr_octet[5]);
652 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800653}
654
William A. Kennington III1137a972019-04-20 20:49:58 -0700655bool isEmpty(const ether_addr& mac)
656{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700657 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700658}
659
660bool isMulticast(const ether_addr& mac)
661{
662 return mac.ether_addr_octet[0] & 0b1;
663}
664
665bool isUnicast(const ether_addr& mac)
666{
667 return !isEmpty(mac) && !isMulticast(mac);
668}
669
Gunnar Mills57d9c502018-09-14 14:42:34 -0500670} // namespace mac_address
671} // namespace network
672} // namespace phosphor