blob: de0bc9dd1259049af0086cb2529c66c157667520 [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>
William A. Kennington III1c776022022-01-05 14:12:16 -08008#include <fmt/compile.h>
9#include <fmt/format.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053010#include <net/if.h>
Ratan Guptabc886292017-07-25 18:29:57 +053011#include <sys/wait.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053012
Ratan Gupta8804feb2017-05-25 10:49:57 +053013#include <algorithm>
Lei YU307554e2021-03-18 14:56:50 +080014#include <cctype>
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -070015#include <cstdlib>
16#include <cstring>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053017#include <filesystem>
Manojkiran Edacc099a82020-05-11 14:25:16 +053018#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070019#include <list>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070020#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053021#include <nlohmann/json.hpp>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070022#endif
Patrick Venture189d44e2018-07-09 12:30:59 -070023#include <phosphor-logging/elog-errors.hpp>
24#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080025#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070026#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070027#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070028#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070029#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053030
31namespace phosphor
32{
33namespace network
34{
Ratan Guptabc886292017-07-25 18:29:57 +053035
Ratan Gupta8804feb2017-05-25 10:49:57 +053036using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053037using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053038namespace fs = std::filesystem;
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 IIIee5b2c92021-04-28 02:31:28 -0700111std::set<std::string_view> parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800112{
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700113 std::set<std::string_view> result;
114 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800115 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700116 auto sep = interfaces.find(',');
117 auto interface = interfaces.substr(0, sep);
118 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800119 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700120 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800121 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700122 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800123 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700124 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800125 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700126 if (!interface.empty())
127 {
128 result.insert(interface);
129 }
130 if (sep == interfaces.npos)
131 {
132 break;
133 }
134 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800135 }
136 return result;
137}
138
139/** @brief Get the ignored interfaces */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700140const std::set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800141{
142 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
143 return ignoredInterfaces;
144}
145
Lei YU3894ce72021-03-18 14:53:42 +0800146} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530147
Ratan Gupta8804feb2017-05-25 10:49:57 +0530148std::string toMask(int addressFamily, uint8_t prefix)
149{
150 if (addressFamily == AF_INET6)
151 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500152 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530153 return "";
154 }
155
156 if (prefix < 1 || prefix > 30)
157 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500158 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530159 return "";
160 }
161 /* Create the netmask from the number of bits */
162 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500163 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530164 {
165 mask |= 1 << (31 - i);
166 }
167 struct in_addr netmask;
168 netmask.s_addr = htonl(mask);
169 return inet_ntoa(netmask);
170}
171
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800172InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
173{
174 if (addressFamily == AF_INET)
175 {
176 struct in_addr ret;
177 if (buf.size() != sizeof(ret))
178 {
179 throw std::runtime_error("Buf not in_addr sized");
180 }
181 memcpy(&ret, buf.data(), sizeof(ret));
182 return ret;
183 }
184 else if (addressFamily == AF_INET6)
185 {
186 struct in6_addr ret;
187 if (buf.size() != sizeof(ret))
188 {
189 throw std::runtime_error("Buf not in6_addr sized");
190 }
191 memcpy(&ret, buf.data(), sizeof(ret));
192 return ret;
193 }
194
195 throw std::runtime_error("Unsupported address family");
196}
197
Alexander Filippov983da552021-02-08 15:26:54 +0300198std::string toString(const struct in_addr& addr)
199{
200 std::string ip(INET_ADDRSTRLEN, '\0');
201 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
202 {
203 throw std::runtime_error("Failed to convert IP4 to string");
204 }
205
206 ip.resize(strlen(ip.c_str()));
207 return ip;
208}
209
210std::string toString(const struct in6_addr& addr)
211{
212 std::string ip(INET6_ADDRSTRLEN, '\0');
213 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
214 {
215 throw std::runtime_error("Failed to convert IP6 to string");
216 }
217
218 ip.resize(strlen(ip.c_str()));
219 return ip;
220}
221
William A. Kennington III5058f572019-01-30 17:18:14 -0800222std::string toString(const InAddrAny& addr)
223{
William A. Kennington III5058f572019-01-30 17:18:14 -0800224 if (std::holds_alternative<struct in_addr>(addr))
225 {
226 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300227 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800228 }
229 else if (std::holds_alternative<struct in6_addr>(addr))
230 {
231 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300232 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800233 }
Alexander Filippov983da552021-02-08 15:26:54 +0300234
235 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800236}
237
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500238bool isValidIP(int addressFamily, const std::string& address)
239{
240 unsigned char buf[sizeof(struct in6_addr)];
241
242 return inet_pton(addressFamily, address.c_str(), buf) > 0;
243}
244
245bool isValidPrefix(int addressFamily, uint8_t prefixLength)
246{
247 if (addressFamily == AF_INET)
248 {
249 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
250 prefixLength > IPV4_MAX_PREFIX_LENGTH)
251 {
252 return false;
253 }
254 }
255
256 if (addressFamily == AF_INET6)
257 {
258 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
259 prefixLength > IPV6_MAX_PREFIX_LENGTH)
260 {
261 return false;
262 }
263 }
264
265 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530266}
267
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530268InterfaceList getInterfaces()
269{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500270 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530271 struct ifaddrs* ifaddr = nullptr;
272
273 // attempt to fill struct with ifaddrs
274 if (getifaddrs(&ifaddr) == -1)
275 {
276 auto error = errno;
277 log<level::ERR>("Error occurred during the getifaddrs call",
278 entry("ERRNO=%d", error));
279 elog<InternalFailure>();
280 }
281
282 AddrPtr ifaddrPtr(ifaddr);
283 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800284 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530285
286 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
287 {
288 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700289 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800290 if (ifa->ifa_flags & IFF_LOOPBACK ||
291 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530292 {
293 continue;
294 }
295 interfaces.emplace(ifa->ifa_name);
296 }
297 return interfaces;
298}
299
Ratan Guptabc886292017-07-25 18:29:57 +0530300void deleteInterface(const std::string& intf)
301{
302 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500303 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530304
305 if (pid == 0)
306 {
307
308 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
309 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500310 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530311 entry("INTF=%s", intf.c_str()));
312 elog<InternalFailure>();
313 }
314 else if (pid < 0)
315 {
316 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500317 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530318 elog<InternalFailure>();
319 }
320 else if (pid > 0)
321 {
322 while (waitpid(pid, &status, 0) == -1)
323 {
324 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500325 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530326 status = -1;
327 break;
328 }
329 }
330
Gunnar Mills57d9c502018-09-14 14:42:34 -0500331 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530332 {
333 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500334 entry("INTF=%s", intf.c_str()),
335 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530336 elog<InternalFailure>();
337 }
338 }
339}
340
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700341std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
342{
343 constexpr char ethPrefix[] = "eth";
344 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
345 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
346 {
347 return std::nullopt;
348 }
349 const auto intfSuffix = intf + ethPrefixLen;
350 if (intfSuffix[0] == '\0')
351 {
352 return std::nullopt;
353 }
354 char* end;
355 unsigned long idx = strtoul(intfSuffix, &end, 10);
356 if (end[0] != '\0')
357 {
358 return std::nullopt;
359 }
360 if (idx == 0)
361 {
362 return "ethaddr";
363 }
364 return "eth" + std::to_string(idx) + "addr";
365}
366
Johnathan Mantey817012a2020-01-30 15:07:39 -0800367EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
368 const std::string& intf)
Ratan Gupta56187e72017-08-13 09:40:14 +0530369{
Johnathan Mantey817012a2020-01-30 15:07:39 -0800370 EthernetInterfaceIntf::DHCPConf dhcp =
371 EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530372 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500373 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530374 fs::path confPath = confDir;
375 std::string fileName = systemd::config::networkFilePrefix + intf +
376 systemd::config::networkFileSuffix;
377 confPath /= fileName;
378
Ratan Guptac27170a2017-11-22 15:44:42 +0530379 config::Parser parser(confPath.string());
William A. Kennington III25511a12022-08-04 16:32:28 -0700380 const auto& values = parser.getValues("Network", "DHCP");
381 if (values.empty())
Ratan Gupta56187e72017-08-13 09:40:14 +0530382 {
William A. Kennington III25511a12022-08-04 16:32:28 -0700383 log<level::NOTICE>("Unable to get the value for Network[DHCP]");
Ratan Guptac27170a2017-11-22 15:44:42 +0530384 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530385 }
William A. Kennington III25511a12022-08-04 16:32:28 -0700386 if (values.back() == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530387 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800388 dhcp = EthernetInterfaceIntf::DHCPConf::both;
389 }
William A. Kennington III25511a12022-08-04 16:32:28 -0700390 else if (values.back() == "ipv4")
Johnathan Mantey817012a2020-01-30 15:07:39 -0800391 {
392 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
393 }
William A. Kennington III25511a12022-08-04 16:32:28 -0700394 else if (values.back() == "ipv6")
Johnathan Mantey817012a2020-01-30 15:07:39 -0800395 {
396 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530397 }
398 return dhcp;
399}
400
Ratan Guptabd303b12017-08-18 17:10:07 +0530401namespace mac_address
402{
403
404constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
405constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
406constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
407constexpr auto propIntf = "org.freedesktop.DBus.Properties";
408constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530409constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530410
411using DbusObjectPath = std::string;
412using DbusService = std::string;
413using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500414using ObjectTree =
415 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530416
417constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
418constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500419 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530420constexpr auto invRoot = "/xyz/openbmc_project/inventory";
421
Patrick Williamsc38b0712022-07-22 19:26:54 -0500422ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530423{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530424
425 std::string interfaceName = intfName;
426
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700427#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530428 // load the config JSON from the Read Only Path
429 std::ifstream in(configFile);
430 nlohmann::json configJson;
431 in >> configJson;
432 interfaceName = configJson[intfName];
433#endif
434
Ratan Guptabd303b12017-08-18 17:10:07 +0530435 std::vector<DbusInterface> interfaces;
436 interfaces.emplace_back(invNetworkIntf);
437
438 auto depth = 0;
439
Gunnar Mills57d9c502018-09-14 14:42:34 -0500440 auto mapperCall =
441 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530442
443 mapperCall.append(invRoot, depth, interfaces);
444
445 auto mapperReply = bus.call(mapperCall);
446 if (mapperReply.is_method_error())
447 {
448 log<level::ERR>("Error in mapper call");
449 elog<InternalFailure>();
450 }
451
452 ObjectTree objectTree;
453 mapperReply.read(objectTree);
454
455 if (objectTree.empty())
456 {
457 log<level::ERR>("No Object has implemented the interface",
458 entry("INTERFACE=%s", invNetworkIntf));
459 elog<InternalFailure>();
460 }
461
Alvin Wang38a63c32019-08-29 22:56:46 +0800462 DbusObjectPath objPath;
463 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530464
Alvin Wang38a63c32019-08-29 22:56:46 +0800465 if (1 == objectTree.size())
466 {
467 objPath = objectTree.begin()->first;
468 service = objectTree.begin()->second.begin()->first;
469 }
470 else
471 {
472 // If there are more than 2 objects, object path must contain the
473 // interface name
474 for (auto const& object : objectTree)
475 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530476 log<level::INFO>("interface",
477 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800478 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530479
480 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800481 {
482 objPath = object.first;
483 service = object.second.begin()->first;
484 break;
485 }
486 }
487
488 if (objPath.empty())
489 {
490 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530491 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800492 elog<InternalFailure>();
493 }
494 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530495
Gunnar Mills57d9c502018-09-14 14:42:34 -0500496 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
497 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530498
499 method.append(invNetworkIntf, "MACAddress");
500
501 auto reply = bus.call(method);
502 if (reply.is_method_error())
503 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500504 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530505 entry("PATH=%s", objPath.c_str()),
506 entry("INTERFACE=%s", invNetworkIntf));
507 elog<InternalFailure>();
508 }
509
William A. Kennington III1137a972019-04-20 20:49:58 -0700510 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530511 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700512 return fromString(std::get<std::string>(value));
513}
514
William A. Kennington III1c776022022-01-05 14:12:16 -0800515ether_addr fromString(const char* str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700516{
William A. Kennington III1c776022022-01-05 14:12:16 -0800517 std::string genstr;
Potin Laida0b1d42021-12-26 20:08:20 +0800518
519 // MAC address without colons
William A. Kennington III1c776022022-01-05 14:12:16 -0800520 std::string_view strv = str;
521 if (strv.size() == 12 && strv.find(":") == strv.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700522 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800523 genstr =
524 fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), strv.substr(0, 2),
525 strv.substr(2, 2), strv.substr(4, 2), strv.substr(6, 2),
526 strv.substr(8, 2), strv.substr(10, 2));
527 str = genstr.c_str();
William A. Kennington III1137a972019-04-20 20:49:58 -0700528 }
Potin Laida0b1d42021-12-26 20:08:20 +0800529
William A. Kennington III1c776022022-01-05 14:12:16 -0800530 ether_addr addr;
531 if (ether_aton_r(str, &addr) == nullptr)
Potin Laida0b1d42021-12-26 20:08:20 +0800532 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800533 throw std::invalid_argument("Invalid MAC Address");
Potin Laida0b1d42021-12-26 20:08:20 +0800534 }
William A. Kennington III1c776022022-01-05 14:12:16 -0800535 return addr;
Ratan Guptabd303b12017-08-18 17:10:07 +0530536}
537
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700538std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800539{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800540 char buf[18] = {0};
541 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
542 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
543 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
544 mac.ether_addr_octet[5]);
545 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800546}
547
William A. Kennington III1137a972019-04-20 20:49:58 -0700548bool isEmpty(const ether_addr& mac)
549{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700550 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700551}
552
553bool isMulticast(const ether_addr& mac)
554{
555 return mac.ether_addr_octet[0] & 0b1;
556}
557
558bool isUnicast(const ether_addr& mac)
559{
560 return !isEmpty(mac) && !isMulticast(mac);
561}
562
Gunnar Mills57d9c502018-09-14 14:42:34 -0500563} // namespace mac_address
564} // namespace network
565} // namespace phosphor