blob: fb5934812bc21d12fc1dfb002fbfcf3046a84ef2 [file] [log] [blame]
William A. Kennington III324d2602022-08-18 18:32:56 -07001#include "config.h"
2
Ratan Gupta3681a502017-06-17 19:20:04 +05303#include "util.hpp"
Ratan Gupta11cef802017-05-29 08:41:48 +05304
Patrick Venture189d44e2018-07-09 12:30:59 -07005#include "config_parser.hpp"
6#include "types.hpp"
Ratan Gupta8804feb2017-05-25 10:49:57 +05307
Ratan Gupta3681a502017-06-17 19:20:04 +05308#include <arpa/inet.h>
9#include <dirent.h>
William A. Kennington III1c776022022-01-05 14:12:16 -080010#include <fmt/compile.h>
11#include <fmt/format.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053012#include <net/if.h>
Ratan Guptabc886292017-07-25 18:29:57 +053013#include <sys/wait.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053014
Ratan Gupta8804feb2017-05-25 10:49:57 +053015#include <algorithm>
Lei YU307554e2021-03-18 14:56:50 +080016#include <cctype>
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -070017#include <cstdlib>
18#include <cstring>
Manojkiran Edacc099a82020-05-11 14:25:16 +053019#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070020#include <list>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070021#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053022#include <nlohmann/json.hpp>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070023#endif
Patrick Venture189d44e2018-07-09 12:30:59 -070024#include <phosphor-logging/elog-errors.hpp>
25#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080026#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070027#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070028#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070029#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070030#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053031
32namespace phosphor
33{
34namespace network
35{
Ratan Guptabc886292017-07-25 18:29:57 +053036
Ratan Gupta8804feb2017-05-25 10:49:57 +053037using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053038using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta8804feb2017-05-25 10:49:57 +053039
Lei YU3894ce72021-03-18 14:53:42 +080040namespace internal
41{
42
43void executeCommandinChildProcess(const char* path, char** args)
44{
45 using namespace std::string_literals;
46 pid_t pid = fork();
47 int status{};
48
49 if (pid == 0)
50 {
51 execv(path, args);
52 auto error = errno;
53 // create the command from var args.
54 std::string command = path + " "s;
55
56 for (int i = 0; args[i]; i++)
57 {
58 command += args[i] + " "s;
59 }
60
61 log<level::ERR>("Couldn't exceute the command",
62 entry("ERRNO=%d", error),
63 entry("CMD=%s", command.c_str()));
64 elog<InternalFailure>();
65 }
66 else if (pid < 0)
67 {
68 auto error = errno;
69 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
70 elog<InternalFailure>();
71 }
72 else if (pid > 0)
73 {
74 while (waitpid(pid, &status, 0) == -1)
75 {
76 if (errno != EINTR)
77 { // Error other than EINTR
78 status = -1;
79 break;
80 }
81 }
82
83 if (status < 0)
84 {
85 std::string command = path + " "s;
86 for (int i = 0; args[i]; i++)
87 {
88 command += args[i] + " "s;
89 }
90
91 log<level::ERR>("Unable to execute the command",
92 entry("CMD=%s", command.c_str()),
93 entry("STATUS=%d", status));
94 elog<InternalFailure>();
95 }
96 }
97}
98
Lei YU307554e2021-03-18 14:56:50 +080099/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700100std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +0800101{
102 auto r = std::getenv("IGNORED_INTERFACES");
103 if (r == nullptr)
104 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700105 return "";
Lei YU307554e2021-03-18 14:56:50 +0800106 }
107 return r;
108}
109
110/** @brief Parse the comma separated interface names */
William A. Kennington III95530ec2022-08-19 01:44:39 -0700111std::unordered_set<std::string_view>
112 parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800113{
William A. Kennington III95530ec2022-08-19 01:44:39 -0700114 std::unordered_set<std::string_view> result;
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700115 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800116 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700117 auto sep = interfaces.find(',');
118 auto interface = interfaces.substr(0, sep);
119 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800120 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700121 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800122 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700123 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800124 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700125 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800126 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700127 if (!interface.empty())
128 {
129 result.insert(interface);
130 }
131 if (sep == interfaces.npos)
132 {
133 break;
134 }
135 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800136 }
137 return result;
138}
139
140/** @brief Get the ignored interfaces */
William A. Kennington III95530ec2022-08-19 01:44:39 -0700141const std::unordered_set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800142{
143 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
144 return ignoredInterfaces;
145}
146
Lei YU3894ce72021-03-18 14:53:42 +0800147} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530148
Ratan Gupta8804feb2017-05-25 10:49:57 +0530149std::string toMask(int addressFamily, uint8_t prefix)
150{
151 if (addressFamily == AF_INET6)
152 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500153 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530154 return "";
155 }
156
157 if (prefix < 1 || prefix > 30)
158 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500159 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530160 return "";
161 }
162 /* Create the netmask from the number of bits */
163 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500164 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530165 {
166 mask |= 1 << (31 - i);
167 }
168 struct in_addr netmask;
169 netmask.s_addr = htonl(mask);
170 return inet_ntoa(netmask);
171}
172
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800173InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
174{
175 if (addressFamily == AF_INET)
176 {
177 struct in_addr ret;
178 if (buf.size() != sizeof(ret))
179 {
180 throw std::runtime_error("Buf not in_addr sized");
181 }
182 memcpy(&ret, buf.data(), sizeof(ret));
183 return ret;
184 }
185 else if (addressFamily == AF_INET6)
186 {
187 struct in6_addr ret;
188 if (buf.size() != sizeof(ret))
189 {
190 throw std::runtime_error("Buf not in6_addr sized");
191 }
192 memcpy(&ret, buf.data(), sizeof(ret));
193 return ret;
194 }
195
196 throw std::runtime_error("Unsupported address family");
197}
198
Alexander Filippov983da552021-02-08 15:26:54 +0300199std::string toString(const struct in_addr& addr)
200{
201 std::string ip(INET_ADDRSTRLEN, '\0');
202 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
203 {
204 throw std::runtime_error("Failed to convert IP4 to string");
205 }
206
207 ip.resize(strlen(ip.c_str()));
208 return ip;
209}
210
211std::string toString(const struct in6_addr& addr)
212{
213 std::string ip(INET6_ADDRSTRLEN, '\0');
214 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
215 {
216 throw std::runtime_error("Failed to convert IP6 to string");
217 }
218
219 ip.resize(strlen(ip.c_str()));
220 return ip;
221}
222
William A. Kennington III5058f572019-01-30 17:18:14 -0800223std::string toString(const InAddrAny& addr)
224{
William A. Kennington III5058f572019-01-30 17:18:14 -0800225 if (std::holds_alternative<struct in_addr>(addr))
226 {
227 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300228 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800229 }
230 else if (std::holds_alternative<struct in6_addr>(addr))
231 {
232 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300233 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800234 }
Alexander Filippov983da552021-02-08 15:26:54 +0300235
236 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800237}
238
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500239bool isValidIP(int addressFamily, const std::string& address)
240{
241 unsigned char buf[sizeof(struct in6_addr)];
242
243 return inet_pton(addressFamily, address.c_str(), buf) > 0;
244}
245
246bool isValidPrefix(int addressFamily, uint8_t prefixLength)
247{
248 if (addressFamily == AF_INET)
249 {
250 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
251 prefixLength > IPV4_MAX_PREFIX_LENGTH)
252 {
253 return false;
254 }
255 }
256
257 if (addressFamily == AF_INET6)
258 {
259 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
260 prefixLength > IPV6_MAX_PREFIX_LENGTH)
261 {
262 return false;
263 }
264 }
265
266 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530267}
268
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530269InterfaceList getInterfaces()
270{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500271 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530272 struct ifaddrs* ifaddr = nullptr;
273
274 // attempt to fill struct with ifaddrs
275 if (getifaddrs(&ifaddr) == -1)
276 {
277 auto error = errno;
278 log<level::ERR>("Error occurred during the getifaddrs call",
279 entry("ERRNO=%d", error));
280 elog<InternalFailure>();
281 }
282
283 AddrPtr ifaddrPtr(ifaddr);
284 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800285 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530286
287 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
288 {
289 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700290 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800291 if (ifa->ifa_flags & IFF_LOOPBACK ||
292 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530293 {
294 continue;
295 }
William A. Kennington III95530ec2022-08-19 01:44:39 -0700296 interfaces.emplace_back(ifa->ifa_name);
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530297 }
298 return interfaces;
299}
300
Ratan Guptabc886292017-07-25 18:29:57 +0530301void deleteInterface(const std::string& intf)
302{
303 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500304 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530305
306 if (pid == 0)
307 {
308
309 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
310 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500311 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530312 entry("INTF=%s", intf.c_str()));
313 elog<InternalFailure>();
314 }
315 else if (pid < 0)
316 {
317 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500318 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530319 elog<InternalFailure>();
320 }
321 else if (pid > 0)
322 {
323 while (waitpid(pid, &status, 0) == -1)
324 {
325 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500326 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530327 status = -1;
328 break;
329 }
330 }
331
Gunnar Mills57d9c502018-09-14 14:42:34 -0500332 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530333 {
334 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500335 entry("INTF=%s", intf.c_str()),
336 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530337 elog<InternalFailure>();
338 }
339 }
340}
341
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700342std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
343{
344 constexpr char ethPrefix[] = "eth";
345 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
346 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
347 {
348 return std::nullopt;
349 }
350 const auto intfSuffix = intf + ethPrefixLen;
351 if (intfSuffix[0] == '\0')
352 {
353 return std::nullopt;
354 }
355 char* end;
356 unsigned long idx = strtoul(intfSuffix, &end, 10);
357 if (end[0] != '\0')
358 {
359 return std::nullopt;
360 }
361 if (idx == 0)
362 {
363 return "ethaddr";
364 }
365 return "eth" + std::to_string(idx) + "addr";
366}
367
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700368static std::optional<DHCPVal> systemdParseDHCP(std::string_view str)
369{
370 if (config::icaseeq(str, "ipv4"))
371 {
372 return DHCPVal{.v4 = true, .v6 = false};
373 }
374 if (config::icaseeq(str, "ipv6"))
375 {
376 return DHCPVal{.v4 = false, .v6 = true};
377 }
378 if (auto b = config::parseBool(str); b)
379 {
380 return DHCPVal{.v4 = *b, .v6 = *b};
381 }
382 return std::nullopt;
383}
384
385inline auto systemdParseLast(const config::Parser& config,
386 std::string_view section, std::string_view key,
387 auto&& fun)
388{
389 if (auto str = config.map.getLastValueString(section, key); str == nullptr)
390 {
391 auto err = fmt::format("Unable to get the value of {}[{}] from {}",
392 section, key, config.getFilename().native());
393 log<level::NOTICE>(err.c_str(),
394 entry("FILE=%s", config.getFilename().c_str()));
395 }
396 else if (auto val = fun(*str); !val)
397 {
398 auto err = fmt::format("Invalid value of {}[{}] from {}: {}", section,
399 key, config.getFilename().native(), *str);
400 log<level::NOTICE>(err.c_str(), entry("VALUE=%s", str->c_str()),
401 entry("FILE=%s", config.getFilename().c_str()));
402 }
403 else
404 {
405 return val;
406 }
407 return decltype(fun(std::string_view{}))(std::nullopt);
408}
409
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700410bool getIPv6AcceptRA(const config::Parser& config)
Ratan Gupta56187e72017-08-13 09:40:14 +0530411{
William A. Kennington III324d2602022-08-18 18:32:56 -0700412#ifdef ENABLE_IPV6_ACCEPT_RA
413 constexpr bool def = true;
414#else
415 constexpr bool def = false;
416#endif
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700417 return systemdParseLast(config, "Network", "IPv6AcceptRA",
418 config::parseBool)
419 .value_or(def);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700420}
421
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700422DHCPVal getDHCPValue(const config::Parser& config)
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700423{
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700424 return systemdParseLast(config, "Network", "DHCP", systemdParseDHCP)
425 .value_or(DHCPVal{.v4 = true, .v6 = true});
426}
William A. Kennington III324d2602022-08-18 18:32:56 -0700427
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700428bool getDHCPProp(const config::Parser& config, std::string_view key)
429{
430 return systemdParseLast(config, "DHCP", key, config::parseBool)
431 .value_or(true);
Ratan Gupta56187e72017-08-13 09:40:14 +0530432}
433
Ratan Guptabd303b12017-08-18 17:10:07 +0530434namespace mac_address
435{
436
437constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
438constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
439constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
440constexpr auto propIntf = "org.freedesktop.DBus.Properties";
441constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530442constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530443
444using DbusObjectPath = std::string;
445using DbusService = std::string;
446using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500447using ObjectTree =
448 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530449
450constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
451constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500452 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530453constexpr auto invRoot = "/xyz/openbmc_project/inventory";
454
Patrick Williamsc38b0712022-07-22 19:26:54 -0500455ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530456{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530457
458 std::string interfaceName = intfName;
459
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700460#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530461 // load the config JSON from the Read Only Path
462 std::ifstream in(configFile);
463 nlohmann::json configJson;
464 in >> configJson;
465 interfaceName = configJson[intfName];
466#endif
467
Ratan Guptabd303b12017-08-18 17:10:07 +0530468 std::vector<DbusInterface> interfaces;
469 interfaces.emplace_back(invNetworkIntf);
470
471 auto depth = 0;
472
Gunnar Mills57d9c502018-09-14 14:42:34 -0500473 auto mapperCall =
474 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530475
476 mapperCall.append(invRoot, depth, interfaces);
477
478 auto mapperReply = bus.call(mapperCall);
479 if (mapperReply.is_method_error())
480 {
481 log<level::ERR>("Error in mapper call");
482 elog<InternalFailure>();
483 }
484
485 ObjectTree objectTree;
486 mapperReply.read(objectTree);
487
488 if (objectTree.empty())
489 {
490 log<level::ERR>("No Object has implemented the interface",
491 entry("INTERFACE=%s", invNetworkIntf));
492 elog<InternalFailure>();
493 }
494
Alvin Wang38a63c32019-08-29 22:56:46 +0800495 DbusObjectPath objPath;
496 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530497
Alvin Wang38a63c32019-08-29 22:56:46 +0800498 if (1 == objectTree.size())
499 {
500 objPath = objectTree.begin()->first;
501 service = objectTree.begin()->second.begin()->first;
502 }
503 else
504 {
505 // If there are more than 2 objects, object path must contain the
506 // interface name
507 for (auto const& object : objectTree)
508 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530509 log<level::INFO>("interface",
510 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800511 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530512
513 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800514 {
515 objPath = object.first;
516 service = object.second.begin()->first;
517 break;
518 }
519 }
520
521 if (objPath.empty())
522 {
523 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530524 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800525 elog<InternalFailure>();
526 }
527 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530528
Gunnar Mills57d9c502018-09-14 14:42:34 -0500529 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
530 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530531
532 method.append(invNetworkIntf, "MACAddress");
533
534 auto reply = bus.call(method);
535 if (reply.is_method_error())
536 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500537 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530538 entry("PATH=%s", objPath.c_str()),
539 entry("INTERFACE=%s", invNetworkIntf));
540 elog<InternalFailure>();
541 }
542
William A. Kennington III1137a972019-04-20 20:49:58 -0700543 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530544 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700545 return fromString(std::get<std::string>(value));
546}
547
William A. Kennington III1c776022022-01-05 14:12:16 -0800548ether_addr fromString(const char* str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700549{
William A. Kennington III1c776022022-01-05 14:12:16 -0800550 std::string genstr;
Potin Laida0b1d42021-12-26 20:08:20 +0800551
552 // MAC address without colons
William A. Kennington III1c776022022-01-05 14:12:16 -0800553 std::string_view strv = str;
554 if (strv.size() == 12 && strv.find(":") == strv.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700555 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800556 genstr =
557 fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), strv.substr(0, 2),
558 strv.substr(2, 2), strv.substr(4, 2), strv.substr(6, 2),
559 strv.substr(8, 2), strv.substr(10, 2));
560 str = genstr.c_str();
William A. Kennington III1137a972019-04-20 20:49:58 -0700561 }
Potin Laida0b1d42021-12-26 20:08:20 +0800562
William A. Kennington III1c776022022-01-05 14:12:16 -0800563 ether_addr addr;
564 if (ether_aton_r(str, &addr) == nullptr)
Potin Laida0b1d42021-12-26 20:08:20 +0800565 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800566 throw std::invalid_argument("Invalid MAC Address");
Potin Laida0b1d42021-12-26 20:08:20 +0800567 }
William A. Kennington III1c776022022-01-05 14:12:16 -0800568 return addr;
Ratan Guptabd303b12017-08-18 17:10:07 +0530569}
570
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700571std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800572{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800573 char buf[18] = {0};
574 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
575 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
576 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
577 mac.ether_addr_octet[5]);
578 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800579}
580
William A. Kennington III1137a972019-04-20 20:49:58 -0700581bool isEmpty(const ether_addr& mac)
582{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700583 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700584}
585
586bool isMulticast(const ether_addr& mac)
587{
588 return mac.ether_addr_octet[0] & 0b1;
589}
590
591bool isUnicast(const ether_addr& mac)
592{
593 return !isEmpty(mac) && !isMulticast(mac);
594}
595
Gunnar Mills57d9c502018-09-14 14:42:34 -0500596} // namespace mac_address
597} // namespace network
598} // namespace phosphor