blob: 803d26e4901abb58840fe2555e60756b6861613c [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 auto rc = config::ReturnCode::SUCCESS;
380 config::ValueList values;
381 config::Parser parser(confPath.string());
382
383 std::tie(rc, values) = parser.getValues("Network", "DHCP");
384 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530385 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530386 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500387 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530388 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530389 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530390 // There will be only single value for DHCP key.
391 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530392 {
Johnathan Mantey817012a2020-01-30 15:07:39 -0800393 dhcp = EthernetInterfaceIntf::DHCPConf::both;
394 }
395 else if (values[0] == "ipv4")
396 {
397 dhcp = EthernetInterfaceIntf::DHCPConf::v4;
398 }
399 else if (values[0] == "ipv6")
400 {
401 dhcp = EthernetInterfaceIntf::DHCPConf::v6;
Ratan Gupta56187e72017-08-13 09:40:14 +0530402 }
403 return dhcp;
404}
405
Ratan Guptabd303b12017-08-18 17:10:07 +0530406namespace mac_address
407{
408
409constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
410constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
411constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
412constexpr auto propIntf = "org.freedesktop.DBus.Properties";
413constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530414constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530415
416using DbusObjectPath = std::string;
417using DbusService = std::string;
418using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500419using ObjectTree =
420 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530421
422constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
423constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500424 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530425constexpr auto invRoot = "/xyz/openbmc_project/inventory";
426
Patrick Williamsc38b0712022-07-22 19:26:54 -0500427ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530428{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530429
430 std::string interfaceName = intfName;
431
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700432#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530433 // load the config JSON from the Read Only Path
434 std::ifstream in(configFile);
435 nlohmann::json configJson;
436 in >> configJson;
437 interfaceName = configJson[intfName];
438#endif
439
Ratan Guptabd303b12017-08-18 17:10:07 +0530440 std::vector<DbusInterface> interfaces;
441 interfaces.emplace_back(invNetworkIntf);
442
443 auto depth = 0;
444
Gunnar Mills57d9c502018-09-14 14:42:34 -0500445 auto mapperCall =
446 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530447
448 mapperCall.append(invRoot, depth, interfaces);
449
450 auto mapperReply = bus.call(mapperCall);
451 if (mapperReply.is_method_error())
452 {
453 log<level::ERR>("Error in mapper call");
454 elog<InternalFailure>();
455 }
456
457 ObjectTree objectTree;
458 mapperReply.read(objectTree);
459
460 if (objectTree.empty())
461 {
462 log<level::ERR>("No Object has implemented the interface",
463 entry("INTERFACE=%s", invNetworkIntf));
464 elog<InternalFailure>();
465 }
466
Alvin Wang38a63c32019-08-29 22:56:46 +0800467 DbusObjectPath objPath;
468 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530469
Alvin Wang38a63c32019-08-29 22:56:46 +0800470 if (1 == objectTree.size())
471 {
472 objPath = objectTree.begin()->first;
473 service = objectTree.begin()->second.begin()->first;
474 }
475 else
476 {
477 // If there are more than 2 objects, object path must contain the
478 // interface name
479 for (auto const& object : objectTree)
480 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530481 log<level::INFO>("interface",
482 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800483 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530484
485 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800486 {
487 objPath = object.first;
488 service = object.second.begin()->first;
489 break;
490 }
491 }
492
493 if (objPath.empty())
494 {
495 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530496 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800497 elog<InternalFailure>();
498 }
499 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530500
Gunnar Mills57d9c502018-09-14 14:42:34 -0500501 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
502 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530503
504 method.append(invNetworkIntf, "MACAddress");
505
506 auto reply = bus.call(method);
507 if (reply.is_method_error())
508 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500509 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530510 entry("PATH=%s", objPath.c_str()),
511 entry("INTERFACE=%s", invNetworkIntf));
512 elog<InternalFailure>();
513 }
514
William A. Kennington III1137a972019-04-20 20:49:58 -0700515 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530516 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700517 return fromString(std::get<std::string>(value));
518}
519
William A. Kennington III1c776022022-01-05 14:12:16 -0800520ether_addr fromString(const char* str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700521{
William A. Kennington III1c776022022-01-05 14:12:16 -0800522 std::string genstr;
Potin Laida0b1d42021-12-26 20:08:20 +0800523
524 // MAC address without colons
William A. Kennington III1c776022022-01-05 14:12:16 -0800525 std::string_view strv = str;
526 if (strv.size() == 12 && strv.find(":") == strv.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700527 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800528 genstr =
529 fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), strv.substr(0, 2),
530 strv.substr(2, 2), strv.substr(4, 2), strv.substr(6, 2),
531 strv.substr(8, 2), strv.substr(10, 2));
532 str = genstr.c_str();
William A. Kennington III1137a972019-04-20 20:49:58 -0700533 }
Potin Laida0b1d42021-12-26 20:08:20 +0800534
William A. Kennington III1c776022022-01-05 14:12:16 -0800535 ether_addr addr;
536 if (ether_aton_r(str, &addr) == nullptr)
Potin Laida0b1d42021-12-26 20:08:20 +0800537 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800538 throw std::invalid_argument("Invalid MAC Address");
Potin Laida0b1d42021-12-26 20:08:20 +0800539 }
William A. Kennington III1c776022022-01-05 14:12:16 -0800540 return addr;
Ratan Guptabd303b12017-08-18 17:10:07 +0530541}
542
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700543std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800544{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800545 char buf[18] = {0};
546 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
547 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
548 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
549 mac.ether_addr_octet[5]);
550 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800551}
552
William A. Kennington III1137a972019-04-20 20:49:58 -0700553bool isEmpty(const ether_addr& mac)
554{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700555 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700556}
557
558bool isMulticast(const ether_addr& mac)
559{
560 return mac.ether_addr_octet[0] & 0b1;
561}
562
563bool isUnicast(const ether_addr& mac)
564{
565 return !isEmpty(mac) && !isMulticast(mac);
566}
567
Gunnar Mills57d9c502018-09-14 14:42:34 -0500568} // namespace mac_address
569} // namespace network
570} // namespace phosphor