blob: e517f069db12996b8cd6596c8e87b883971da0b7 [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{
40 uint8_t pos = 0;
41 uint8_t prevPos = 0;
42 uint8_t cidr = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050043 uint16_t buff{};
Ratan Gupta8804feb2017-05-25 10:49:57 +053044 do
45 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050046 // subnet mask look like ffff:ffff::
Ratan Gupta8804feb2017-05-25 10:49:57 +053047 // or ffff:c000::
Gunnar Mills57d9c502018-09-14 14:42:34 -050048 pos = subnetMask.find(":", prevPos);
Ratan Gupta8804feb2017-05-25 10:49:57 +053049 if (pos == std::string::npos)
50 {
51 break;
52 }
53
54 auto str = subnetMask.substr(prevPos, (pos - prevPos));
55 prevPos = pos + 1;
56
57 // String length is 0
58 if (!str.length())
59 {
60 return cidr;
61 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050062 // converts it into number.
Ratan Gupta8804feb2017-05-25 10:49:57 +053063 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
64 {
65 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050066 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053067
68 return 0;
69 }
70
71 // convert the number into bitset
72 // and check for how many ones are there.
73 // if we don't have all the ones then make
74 // sure that all the ones should be left justify.
75
76 if (__builtin_popcount(buff) != 16)
77 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050078 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
79 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053080 {
81 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050082 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053083
84 return 0;
85 }
86 cidr += __builtin_popcount(buff);
87 return cidr;
88 }
89
90 cidr += 16;
Gunnar Mills57d9c502018-09-14 14:42:34 -050091 } while (1);
Ratan Gupta8804feb2017-05-25 10:49:57 +053092
93 return cidr;
94}
Gunnar Mills57d9c502018-09-14 14:42:34 -050095} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053096
97uint8_t toCidr(int addressFamily, const std::string& subnetMask)
98{
99 if (addressFamily == AF_INET6)
100 {
101 return toV6Cidr(subnetMask);
102 }
103
104 uint32_t buff;
105
106 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
107 if (rc <= 0)
108 {
109 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500110 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530111 return 0;
112 }
113
114 buff = be32toh(buff);
115 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -0500116 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
117 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +0530118 {
119 return __builtin_popcount(buff);
120 }
121 else
122 {
123 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500124 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530125 return 0;
126 }
127}
128
129std::string toMask(int addressFamily, uint8_t prefix)
130{
131 if (addressFamily == AF_INET6)
132 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500133 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530134 return "";
135 }
136
137 if (prefix < 1 || prefix > 30)
138 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500139 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530140 return "";
141 }
142 /* Create the netmask from the number of bits */
143 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500144 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530145 {
146 mask |= 1 << (31 - i);
147 }
148 struct in_addr netmask;
149 netmask.s_addr = htonl(mask);
150 return inet_ntoa(netmask);
151}
152
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800153InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
154{
155 if (addressFamily == AF_INET)
156 {
157 struct in_addr ret;
158 if (buf.size() != sizeof(ret))
159 {
160 throw std::runtime_error("Buf not in_addr sized");
161 }
162 memcpy(&ret, buf.data(), sizeof(ret));
163 return ret;
164 }
165 else if (addressFamily == AF_INET6)
166 {
167 struct in6_addr ret;
168 if (buf.size() != sizeof(ret))
169 {
170 throw std::runtime_error("Buf not in6_addr sized");
171 }
172 memcpy(&ret, buf.data(), sizeof(ret));
173 return ret;
174 }
175
176 throw std::runtime_error("Unsupported address family");
177}
178
Alexander Filippov983da552021-02-08 15:26:54 +0300179std::string toString(const struct in_addr& addr)
180{
181 std::string ip(INET_ADDRSTRLEN, '\0');
182 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
183 {
184 throw std::runtime_error("Failed to convert IP4 to string");
185 }
186
187 ip.resize(strlen(ip.c_str()));
188 return ip;
189}
190
191std::string toString(const struct in6_addr& addr)
192{
193 std::string ip(INET6_ADDRSTRLEN, '\0');
194 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
195 {
196 throw std::runtime_error("Failed to convert IP6 to string");
197 }
198
199 ip.resize(strlen(ip.c_str()));
200 return ip;
201}
202
William A. Kennington III5058f572019-01-30 17:18:14 -0800203std::string toString(const InAddrAny& addr)
204{
William A. Kennington III5058f572019-01-30 17:18:14 -0800205 if (std::holds_alternative<struct in_addr>(addr))
206 {
207 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300208 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800209 }
210 else if (std::holds_alternative<struct in6_addr>(addr))
211 {
212 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300213 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800214 }
Alexander Filippov983da552021-02-08 15:26:54 +0300215
216 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800217}
218
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500219bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530220{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500221 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
222}
223
224bool isValidIP(int addressFamily, const std::string& address)
225{
226 unsigned char buf[sizeof(struct in6_addr)];
227
228 return inet_pton(addressFamily, address.c_str(), buf) > 0;
229}
230
231bool isValidPrefix(int addressFamily, uint8_t prefixLength)
232{
233 if (addressFamily == AF_INET)
234 {
235 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
236 prefixLength > IPV4_MAX_PREFIX_LENGTH)
237 {
238 return false;
239 }
240 }
241
242 if (addressFamily == AF_INET6)
243 {
244 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
245 prefixLength > IPV6_MAX_PREFIX_LENGTH)
246 {
247 return false;
248 }
249 }
250
251 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530252}
253
Ratan Gupta3681a502017-06-17 19:20:04 +0530254IntfAddrMap getInterfaceAddrs()
255{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500256 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530257 struct ifaddrs* ifaddr = nullptr;
258
259 // attempt to fill struct with ifaddrs
260 if (getifaddrs(&ifaddr) == -1)
261 {
262 auto error = errno;
263 log<level::ERR>("Error occurred during the getifaddrs call",
264 entry("ERRNO=%s", strerror(error)));
265 elog<InternalFailure>();
266 }
267
268 AddrPtr ifaddrPtr(ifaddr);
269 ifaddr = nullptr;
270
Gunnar Mills57d9c502018-09-14 14:42:34 -0500271 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530272
273 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
274 {
275 // walk interfaces
276 if (ifa->ifa_addr == nullptr)
277 {
278 continue;
279 }
280
281 // get only INET interfaces not ipv6
282 if (ifa->ifa_addr->sa_family == AF_INET ||
283 ifa->ifa_addr->sa_family == AF_INET6)
284 {
285 // if loopback, or not running ignore
286 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
287 !(ifa->ifa_flags & IFF_RUNNING))
288 {
289 continue;
290 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530291 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500292 AddrInfo info{};
293 char ip[INET6_ADDRSTRLEN] = {0};
294 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530295
296 if (ifa->ifa_addr->sa_family == AF_INET)
297 {
298
299 inet_ntop(ifa->ifa_addr->sa_family,
300 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500301 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530302
Gunnar Mills57d9c502018-09-14 14:42:34 -0500303 inet_ntop(
304 ifa->ifa_addr->sa_family,
305 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
306 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530307 }
308 else
309 {
310 inet_ntop(ifa->ifa_addr->sa_family,
311 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500312 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530313
Gunnar Mills57d9c502018-09-14 14:42:34 -0500314 inet_ntop(
315 ifa->ifa_addr->sa_family,
316 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
317 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530318 }
319
320 info.addrType = ifa->ifa_addr->sa_family;
321 info.ipaddress = ip;
322 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700323 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530324 }
325 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530326 return intfMap;
327}
328
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530329InterfaceList getInterfaces()
330{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500331 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530332 struct ifaddrs* ifaddr = nullptr;
333
334 // attempt to fill struct with ifaddrs
335 if (getifaddrs(&ifaddr) == -1)
336 {
337 auto error = errno;
338 log<level::ERR>("Error occurred during the getifaddrs call",
339 entry("ERRNO=%d", error));
340 elog<InternalFailure>();
341 }
342
343 AddrPtr ifaddrPtr(ifaddr);
344 ifaddr = nullptr;
345
346 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
347 {
348 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700349 // if loopback ignore
350 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530351 {
352 continue;
353 }
354 interfaces.emplace(ifa->ifa_name);
355 }
356 return interfaces;
357}
358
Ratan Guptabc886292017-07-25 18:29:57 +0530359void deleteInterface(const std::string& intf)
360{
361 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500362 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530363
364 if (pid == 0)
365 {
366
367 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
368 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500369 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530370 entry("INTF=%s", intf.c_str()));
371 elog<InternalFailure>();
372 }
373 else if (pid < 0)
374 {
375 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500376 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530377 elog<InternalFailure>();
378 }
379 else if (pid > 0)
380 {
381 while (waitpid(pid, &status, 0) == -1)
382 {
383 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500384 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530385 status = -1;
386 break;
387 }
388 }
389
Gunnar Mills57d9c502018-09-14 14:42:34 -0500390 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530391 {
392 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500393 entry("INTF=%s", intf.c_str()),
394 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530395 elog<InternalFailure>();
396 }
397 }
398}
399
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700400std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
401{
402 constexpr char ethPrefix[] = "eth";
403 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
404 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
405 {
406 return std::nullopt;
407 }
408 const auto intfSuffix = intf + ethPrefixLen;
409 if (intfSuffix[0] == '\0')
410 {
411 return std::nullopt;
412 }
413 char* end;
414 unsigned long idx = strtoul(intfSuffix, &end, 10);
415 if (end[0] != '\0')
416 {
417 return std::nullopt;
418 }
419 if (idx == 0)
420 {
421 return "ethaddr";
422 }
423 return "eth" + std::to_string(idx) + "addr";
424}
425
Johnathan Mantey817012a2020-01-30 15:07:39 -0800426EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
427 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530428{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800429 EthernetInterfaceIntf::DHCPConf dhcp =
430 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530431 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500432 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530433 fs::path confPath = confDir;
434 std::string fileName = systemd::config::networkFilePrefix + intf +
435 systemd::config::networkFileSuffix;
436 confPath /= fileName;
437
Ratan Guptac27170a2017-11-22 15:44:42 +0530438 auto rc = config::ReturnCode::SUCCESS;
439 config::ValueList values;
440 config::Parser parser(confPath.string());
441
442 std::tie(rc, values) = parser.getValues("Network", "DHCP");
443 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530444 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530445 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500446 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530447 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530448 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530449 // There will be only single value for DHCP key.
450 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530451 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800452 dhcp = EthernetInterfaceIntf::DHCPConf::both;
453 }
454 else if (values[0] == "ipv4")
455 {
456 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
457 }
458 else if (values[0] == "ipv6")
459 {
460 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530461 }
462 return dhcp;
463}
464
Ratan Guptabd303b12017-08-18 17:10:07 +0530465namespace internal
466{
Ratan Gupta56187e72017-08-13 09:40:14 +0530467
Ratan Guptabd303b12017-08-18 17:10:07 +0530468void executeCommandinChildProcess(const char* path, char** args)
469{
470 using namespace std::string_literals;
471 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500472 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530473
474 if (pid == 0)
475 {
476 execv(path, args);
477 auto error = errno;
478 // create the command from var args.
479 std::string command = path + " "s;
480
Gunnar Mills57d9c502018-09-14 14:42:34 -0500481 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530482 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500483 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530484 }
485
486 log<level::ERR>("Couldn't exceute the command",
487 entry("ERRNO=%d", error),
488 entry("CMD=%s", command.c_str()));
489 elog<InternalFailure>();
490 }
491 else if (pid < 0)
492 {
493 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500494 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530495 elog<InternalFailure>();
496 }
497 else if (pid > 0)
498 {
499 while (waitpid(pid, &status, 0) == -1)
500 {
501 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500502 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530503 status = -1;
504 break;
505 }
506 }
507
Gunnar Mills57d9c502018-09-14 14:42:34 -0500508 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530509 {
510 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500511 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530512 {
513 command += args[i] + " "s;
514 }
515
516 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500517 entry("CMD=%s", command.c_str()),
518 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530519 elog<InternalFailure>();
520 }
521 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530522}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500523} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530524
525namespace mac_address
526{
527
528constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
529constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
530constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
531constexpr auto propIntf = "org.freedesktop.DBus.Properties";
532constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530533constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530534
535using DbusObjectPath = std::string;
536using DbusService = std::string;
537using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500538using ObjectTree =
539 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530540
541constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
542constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500543 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530544constexpr auto invRoot = "/xyz/openbmc_project/inventory";
545
Alvin Wang38a63c32019-08-29 22:56:46 +0800546ether_addr getfromInventory(sdbusplus::bus::bus& bus,
547 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530548{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530549
550 std::string interfaceName = intfName;
551
552#if SYNC_MAC_FROM_INVENTORY
553 // load the config JSON from the Read Only Path
554 std::ifstream in(configFile);
555 nlohmann::json configJson;
556 in >> configJson;
557 interfaceName = configJson[intfName];
558#endif
559
Ratan Guptabd303b12017-08-18 17:10:07 +0530560 std::vector<DbusInterface> interfaces;
561 interfaces.emplace_back(invNetworkIntf);
562
563 auto depth = 0;
564
Gunnar Mills57d9c502018-09-14 14:42:34 -0500565 auto mapperCall =
566 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530567
568 mapperCall.append(invRoot, depth, interfaces);
569
570 auto mapperReply = bus.call(mapperCall);
571 if (mapperReply.is_method_error())
572 {
573 log<level::ERR>("Error in mapper call");
574 elog<InternalFailure>();
575 }
576
577 ObjectTree objectTree;
578 mapperReply.read(objectTree);
579
580 if (objectTree.empty())
581 {
582 log<level::ERR>("No Object has implemented the interface",
583 entry("INTERFACE=%s", invNetworkIntf));
584 elog<InternalFailure>();
585 }
586
Alvin Wang38a63c32019-08-29 22:56:46 +0800587 DbusObjectPath objPath;
588 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530589
Alvin Wang38a63c32019-08-29 22:56:46 +0800590 if (1 == objectTree.size())
591 {
592 objPath = objectTree.begin()->first;
593 service = objectTree.begin()->second.begin()->first;
594 }
595 else
596 {
597 // If there are more than 2 objects, object path must contain the
598 // interface name
599 for (auto const& object : objectTree)
600 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530601 log<level::INFO>("interface",
602 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800603 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530604
605 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800606 {
607 objPath = object.first;
608 service = object.second.begin()->first;
609 break;
610 }
611 }
612
613 if (objPath.empty())
614 {
615 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530616 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800617 elog<InternalFailure>();
618 }
619 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530620
Gunnar Mills57d9c502018-09-14 14:42:34 -0500621 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
622 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530623
624 method.append(invNetworkIntf, "MACAddress");
625
626 auto reply = bus.call(method);
627 if (reply.is_method_error())
628 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500629 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530630 entry("PATH=%s", objPath.c_str()),
631 entry("INTERFACE=%s", invNetworkIntf));
632 elog<InternalFailure>();
633 }
634
William A. Kennington III1137a972019-04-20 20:49:58 -0700635 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530636 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700637 return fromString(std::get<std::string>(value));
638}
639
640ether_addr fromString(const char* str)
641{
642 struct ether_addr* mac = ether_aton(str);
643 if (mac == nullptr)
644 {
Asmitha Karunanithi86f659e2021-01-05 00:16:03 -0600645 throw std::invalid_argument("Invalid MAC Address");
William A. Kennington III1137a972019-04-20 20:49:58 -0700646 }
647 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530648}
649
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700650std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800651{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800652 char buf[18] = {0};
653 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
654 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
655 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
656 mac.ether_addr_octet[5]);
657 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800658}
659
William A. Kennington III1137a972019-04-20 20:49:58 -0700660bool isEmpty(const ether_addr& mac)
661{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700662 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700663}
664
665bool isMulticast(const ether_addr& mac)
666{
667 return mac.ether_addr_octet[0] & 0b1;
668}
669
670bool isUnicast(const ether_addr& mac)
671{
672 return !isEmpty(mac) && !isMulticast(mac);
673}
674
Gunnar Mills57d9c502018-09-14 14:42:34 -0500675} // namespace mac_address
676} // namespace network
677} // namespace phosphor