blob: eb3bf5fee70bea932c5f518d468063f4efce3b80 [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 }
Johnathan Mantey359623e2021-01-26 15:02:54 -080062 trailingZeroes = __builtin_ctz(subnet.s6_addr32[lv]);
63 zeroesFound |= trailingZeroes;
Ratan Gupta8804feb2017-05-25 10:49:57 +053064
Johnathan Mantey359623e2021-01-26 15:02:54 -080065 if (bitsSet + trailingZeroes != 32)
Ratan Gupta8804feb2017-05-25 10:49:57 +053066 {
Johnathan Mantey359623e2021-01-26 15:02:54 -080067 // There are '1' bits interspersed with '0' bits
68 log<level::ERR>("Invalid Mask",
69 entry("SUBNETMASK=%s", subnetMask.c_str()));
70 return 0;
Ratan Gupta8804feb2017-05-25 10:49:57 +053071 }
Johnathan Mantey359623e2021-01-26 15:02:54 -080072 cidr += bitsSet;
73 }
Ratan Gupta8804feb2017-05-25 10:49:57 +053074 return cidr;
75}
Gunnar Mills57d9c502018-09-14 14:42:34 -050076} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053077
78uint8_t toCidr(int addressFamily, const std::string& subnetMask)
79{
80 if (addressFamily == AF_INET6)
81 {
82 return toV6Cidr(subnetMask);
83 }
84
85 uint32_t buff;
86
87 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
88 if (rc <= 0)
89 {
90 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050091 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053092 return 0;
93 }
94
95 buff = be32toh(buff);
96 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -050097 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
98 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053099 {
100 return __builtin_popcount(buff);
101 }
102 else
103 {
104 log<level::ERR>("Invalid Mask",
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
110std::string toMask(int addressFamily, uint8_t prefix)
111{
112 if (addressFamily == AF_INET6)
113 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500114 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530115 return "";
116 }
117
118 if (prefix < 1 || prefix > 30)
119 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500120 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530121 return "";
122 }
123 /* Create the netmask from the number of bits */
124 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500125 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530126 {
127 mask |= 1 << (31 - i);
128 }
129 struct in_addr netmask;
130 netmask.s_addr = htonl(mask);
131 return inet_ntoa(netmask);
132}
133
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800134InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
135{
136 if (addressFamily == AF_INET)
137 {
138 struct in_addr ret;
139 if (buf.size() != sizeof(ret))
140 {
141 throw std::runtime_error("Buf not in_addr sized");
142 }
143 memcpy(&ret, buf.data(), sizeof(ret));
144 return ret;
145 }
146 else if (addressFamily == AF_INET6)
147 {
148 struct in6_addr ret;
149 if (buf.size() != sizeof(ret))
150 {
151 throw std::runtime_error("Buf not in6_addr sized");
152 }
153 memcpy(&ret, buf.data(), sizeof(ret));
154 return ret;
155 }
156
157 throw std::runtime_error("Unsupported address family");
158}
159
Alexander Filippov983da552021-02-08 15:26:54 +0300160std::string toString(const struct in_addr& addr)
161{
162 std::string ip(INET_ADDRSTRLEN, '\0');
163 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
164 {
165 throw std::runtime_error("Failed to convert IP4 to string");
166 }
167
168 ip.resize(strlen(ip.c_str()));
169 return ip;
170}
171
172std::string toString(const struct in6_addr& addr)
173{
174 std::string ip(INET6_ADDRSTRLEN, '\0');
175 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
176 {
177 throw std::runtime_error("Failed to convert IP6 to string");
178 }
179
180 ip.resize(strlen(ip.c_str()));
181 return ip;
182}
183
William A. Kennington III5058f572019-01-30 17:18:14 -0800184std::string toString(const InAddrAny& addr)
185{
William A. Kennington III5058f572019-01-30 17:18:14 -0800186 if (std::holds_alternative<struct in_addr>(addr))
187 {
188 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300189 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800190 }
191 else if (std::holds_alternative<struct in6_addr>(addr))
192 {
193 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300194 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800195 }
Alexander Filippov983da552021-02-08 15:26:54 +0300196
197 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800198}
199
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500200bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530201{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500202 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
203}
204
205bool isValidIP(int addressFamily, const std::string& address)
206{
207 unsigned char buf[sizeof(struct in6_addr)];
208
209 return inet_pton(addressFamily, address.c_str(), buf) > 0;
210}
211
212bool isValidPrefix(int addressFamily, uint8_t prefixLength)
213{
214 if (addressFamily == AF_INET)
215 {
216 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
217 prefixLength > IPV4_MAX_PREFIX_LENGTH)
218 {
219 return false;
220 }
221 }
222
223 if (addressFamily == AF_INET6)
224 {
225 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
226 prefixLength > IPV6_MAX_PREFIX_LENGTH)
227 {
228 return false;
229 }
230 }
231
232 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530233}
234
Ratan Gupta3681a502017-06-17 19:20:04 +0530235IntfAddrMap getInterfaceAddrs()
236{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500237 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530238 struct ifaddrs* ifaddr = nullptr;
239
240 // attempt to fill struct with ifaddrs
241 if (getifaddrs(&ifaddr) == -1)
242 {
243 auto error = errno;
244 log<level::ERR>("Error occurred during the getifaddrs call",
245 entry("ERRNO=%s", strerror(error)));
246 elog<InternalFailure>();
247 }
248
249 AddrPtr ifaddrPtr(ifaddr);
250 ifaddr = nullptr;
251
Gunnar Mills57d9c502018-09-14 14:42:34 -0500252 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530253
254 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
255 {
256 // walk interfaces
257 if (ifa->ifa_addr == nullptr)
258 {
259 continue;
260 }
261
262 // get only INET interfaces not ipv6
263 if (ifa->ifa_addr->sa_family == AF_INET ||
264 ifa->ifa_addr->sa_family == AF_INET6)
265 {
266 // if loopback, or not running ignore
267 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
268 !(ifa->ifa_flags & IFF_RUNNING))
269 {
270 continue;
271 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530272 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500273 AddrInfo info{};
274 char ip[INET6_ADDRSTRLEN] = {0};
275 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530276
277 if (ifa->ifa_addr->sa_family == AF_INET)
278 {
279
280 inet_ntop(ifa->ifa_addr->sa_family,
281 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500282 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530283
Gunnar Mills57d9c502018-09-14 14:42:34 -0500284 inet_ntop(
285 ifa->ifa_addr->sa_family,
286 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
287 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530288 }
289 else
290 {
291 inet_ntop(ifa->ifa_addr->sa_family,
292 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500293 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530294
Gunnar Mills57d9c502018-09-14 14:42:34 -0500295 inet_ntop(
296 ifa->ifa_addr->sa_family,
297 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
298 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530299 }
300
301 info.addrType = ifa->ifa_addr->sa_family;
302 info.ipaddress = ip;
303 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700304 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530305 }
306 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530307 return intfMap;
308}
309
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530310InterfaceList getInterfaces()
311{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500312 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530313 struct ifaddrs* ifaddr = nullptr;
314
315 // attempt to fill struct with ifaddrs
316 if (getifaddrs(&ifaddr) == -1)
317 {
318 auto error = errno;
319 log<level::ERR>("Error occurred during the getifaddrs call",
320 entry("ERRNO=%d", error));
321 elog<InternalFailure>();
322 }
323
324 AddrPtr ifaddrPtr(ifaddr);
325 ifaddr = nullptr;
326
327 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
328 {
329 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700330 // if loopback ignore
331 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530332 {
333 continue;
334 }
335 interfaces.emplace(ifa->ifa_name);
336 }
337 return interfaces;
338}
339
Ratan Guptabc886292017-07-25 18:29:57 +0530340void deleteInterface(const std::string& intf)
341{
342 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500343 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530344
345 if (pid == 0)
346 {
347
348 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
349 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500350 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530351 entry("INTF=%s", intf.c_str()));
352 elog<InternalFailure>();
353 }
354 else if (pid < 0)
355 {
356 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500357 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530358 elog<InternalFailure>();
359 }
360 else if (pid > 0)
361 {
362 while (waitpid(pid, &status, 0) == -1)
363 {
364 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500365 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530366 status = -1;
367 break;
368 }
369 }
370
Gunnar Mills57d9c502018-09-14 14:42:34 -0500371 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530372 {
373 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500374 entry("INTF=%s", intf.c_str()),
375 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530376 elog<InternalFailure>();
377 }
378 }
379}
380
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700381std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
382{
383 constexpr char ethPrefix[] = "eth";
384 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
385 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
386 {
387 return std::nullopt;
388 }
389 const auto intfSuffix = intf + ethPrefixLen;
390 if (intfSuffix[0] == '\0')
391 {
392 return std::nullopt;
393 }
394 char* end;
395 unsigned long idx = strtoul(intfSuffix, &end, 10);
396 if (end[0] != '\0')
397 {
398 return std::nullopt;
399 }
400 if (idx == 0)
401 {
402 return "ethaddr";
403 }
404 return "eth" + std::to_string(idx) + "addr";
405}
406
Johnathan Mantey817012a2020-01-30 15:07:39 -0800407EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
408 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530409{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800410 EthernetInterfaceIntf::DHCPConf dhcp =
411 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530412 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500413 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530414 fs::path confPath = confDir;
415 std::string fileName = systemd::config::networkFilePrefix + intf +
416 systemd::config::networkFileSuffix;
417 confPath /= fileName;
418
Ratan Guptac27170a2017-11-22 15:44:42 +0530419 auto rc = config::ReturnCode::SUCCESS;
420 config::ValueList values;
421 config::Parser parser(confPath.string());
422
423 std::tie(rc, values) = parser.getValues("Network", "DHCP");
424 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530425 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530426 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500427 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530428 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530429 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530430 // There will be only single value for DHCP key.
431 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530432 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800433 dhcp = EthernetInterfaceIntf::DHCPConf::both;
434 }
435 else if (values[0] == "ipv4")
436 {
437 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
438 }
439 else if (values[0] == "ipv6")
440 {
441 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530442 }
443 return dhcp;
444}
445
Ratan Guptabd303b12017-08-18 17:10:07 +0530446namespace internal
447{
Ratan Gupta56187e72017-08-13 09:40:14 +0530448
Ratan Guptabd303b12017-08-18 17:10:07 +0530449void executeCommandinChildProcess(const char* path, char** args)
450{
451 using namespace std::string_literals;
452 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500453 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530454
455 if (pid == 0)
456 {
457 execv(path, args);
458 auto error = errno;
459 // create the command from var args.
460 std::string command = path + " "s;
461
Gunnar Mills57d9c502018-09-14 14:42:34 -0500462 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530463 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500464 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530465 }
466
467 log<level::ERR>("Couldn't exceute the command",
468 entry("ERRNO=%d", error),
469 entry("CMD=%s", command.c_str()));
470 elog<InternalFailure>();
471 }
472 else if (pid < 0)
473 {
474 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500475 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530476 elog<InternalFailure>();
477 }
478 else if (pid > 0)
479 {
480 while (waitpid(pid, &status, 0) == -1)
481 {
482 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500483 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530484 status = -1;
485 break;
486 }
487 }
488
Gunnar Mills57d9c502018-09-14 14:42:34 -0500489 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530490 {
491 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500492 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530493 {
494 command += args[i] + " "s;
495 }
496
497 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500498 entry("CMD=%s", command.c_str()),
499 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530500 elog<InternalFailure>();
501 }
502 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530503}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500504} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530505
506namespace mac_address
507{
508
509constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
510constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
511constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
512constexpr auto propIntf = "org.freedesktop.DBus.Properties";
513constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530514constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530515
516using DbusObjectPath = std::string;
517using DbusService = std::string;
518using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500519using ObjectTree =
520 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530521
522constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
523constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500524 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530525constexpr auto invRoot = "/xyz/openbmc_project/inventory";
526
Alvin Wang38a63c32019-08-29 22:56:46 +0800527ether_addr getfromInventory(sdbusplus::bus::bus& bus,
528 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530529{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530530
531 std::string interfaceName = intfName;
532
533#if SYNC_MAC_FROM_INVENTORY
534 // load the config JSON from the Read Only Path
535 std::ifstream in(configFile);
536 nlohmann::json configJson;
537 in >> configJson;
538 interfaceName = configJson[intfName];
539#endif
540
Ratan Guptabd303b12017-08-18 17:10:07 +0530541 std::vector<DbusInterface> interfaces;
542 interfaces.emplace_back(invNetworkIntf);
543
544 auto depth = 0;
545
Gunnar Mills57d9c502018-09-14 14:42:34 -0500546 auto mapperCall =
547 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530548
549 mapperCall.append(invRoot, depth, interfaces);
550
551 auto mapperReply = bus.call(mapperCall);
552 if (mapperReply.is_method_error())
553 {
554 log<level::ERR>("Error in mapper call");
555 elog<InternalFailure>();
556 }
557
558 ObjectTree objectTree;
559 mapperReply.read(objectTree);
560
561 if (objectTree.empty())
562 {
563 log<level::ERR>("No Object has implemented the interface",
564 entry("INTERFACE=%s", invNetworkIntf));
565 elog<InternalFailure>();
566 }
567
Alvin Wang38a63c32019-08-29 22:56:46 +0800568 DbusObjectPath objPath;
569 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530570
Alvin Wang38a63c32019-08-29 22:56:46 +0800571 if (1 == objectTree.size())
572 {
573 objPath = objectTree.begin()->first;
574 service = objectTree.begin()->second.begin()->first;
575 }
576 else
577 {
578 // If there are more than 2 objects, object path must contain the
579 // interface name
580 for (auto const& object : objectTree)
581 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530582 log<level::INFO>("interface",
583 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800584 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530585
586 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800587 {
588 objPath = object.first;
589 service = object.second.begin()->first;
590 break;
591 }
592 }
593
594 if (objPath.empty())
595 {
596 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530597 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800598 elog<InternalFailure>();
599 }
600 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530601
Gunnar Mills57d9c502018-09-14 14:42:34 -0500602 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
603 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530604
605 method.append(invNetworkIntf, "MACAddress");
606
607 auto reply = bus.call(method);
608 if (reply.is_method_error())
609 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500610 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530611 entry("PATH=%s", objPath.c_str()),
612 entry("INTERFACE=%s", invNetworkIntf));
613 elog<InternalFailure>();
614 }
615
William A. Kennington III1137a972019-04-20 20:49:58 -0700616 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530617 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700618 return fromString(std::get<std::string>(value));
619}
620
621ether_addr fromString(const char* str)
622{
623 struct ether_addr* mac = ether_aton(str);
624 if (mac == nullptr)
625 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600626 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700627 }
628 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530629}
630
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700631std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800632{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800633 char buf[18] = {0};
634 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
635 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
636 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
637 mac.ether_addr_octet[5]);
638 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800639}
640
William A. Kennington III1137a972019-04-20 20:49:58 -0700641bool isEmpty(const ether_addr& mac)
642{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700643 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700644}
645
646bool isMulticast(const ether_addr& mac)
647{
648 return mac.ether_addr_octet[0] & 0b1;
649}
650
651bool isUnicast(const ether_addr& mac)
652{
653 return !isEmpty(mac) && !isMulticast(mac);
654}
655
Gunnar Mills57d9c502018-09-14 14:42:34 -0500656} // namespace mac_address
657} // namespace network
658} // namespace phosphor