blob: 13be8d0c431a2d4b7ad62c8b414897f0c4cf293f [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{
Ratan Gupta56187e72017-08-13 09:40:14 +0530370 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500371 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530372 fs::path confPath = confDir;
373 std::string fileName = systemd::config::networkFilePrefix + intf +
374 systemd::config::networkFileSuffix;
375 confPath /= fileName;
376
Ratan Guptac27170a2017-11-22 15:44:42 +0530377 config::Parser parser(confPath.string());
William A. Kennington III25511a12022-08-04 16:32:28 -0700378 const auto& values = parser.getValues("Network", "DHCP");
379 if (values.empty())
Ratan Gupta56187e72017-08-13 09:40:14 +0530380 {
William A. Kennington III25511a12022-08-04 16:32:28 -0700381 log<level::NOTICE>("Unable to get the value for Network[DHCP]");
William A. Kennington III150753f2022-08-05 15:20:54 -0700382 return EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530383 }
William A. Kennington III150753f2022-08-05 15:20:54 -0700384 if (config::icaseeq(values.back(), "ipv4"))
Ratan Gupta56187e72017-08-13 09:40:14 +0530385 {
William A. Kennington III150753f2022-08-05 15:20:54 -0700386 return EthernetInterfaceIntf::DHCPConf::v4;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800387 }
William A. Kennington III150753f2022-08-05 15:20:54 -0700388 if (config::icaseeq(values.back(), "ipv6"))
Johnathan Mantey817012a2020-01-30 15:07:39 -0800389 {
William A. Kennington III150753f2022-08-05 15:20:54 -0700390 return EthernetInterfaceIntf::DHCPConf::v6;
Johnathan Mantey817012a2020-01-30 15:07:39 -0800391 }
William A. Kennington III150753f2022-08-05 15:20:54 -0700392 auto ret = config::parseBool(values.back());
393 if (!ret.has_value())
Johnathan Mantey817012a2020-01-30 15:07:39 -0800394 {
William A. Kennington III150753f2022-08-05 15:20:54 -0700395 auto str =
396 fmt::format("Unable to parse Network[DHCP]: `{}`", values.back());
397 log<level::NOTICE>(str.c_str());
Ratan Gupta56187e72017-08-13 09:40:14 +0530398 }
William A. Kennington III150753f2022-08-05 15:20:54 -0700399 return ret.value_or(false) ? EthernetInterfaceIntf::DHCPConf::both
400 : EthernetInterfaceIntf::DHCPConf::none;
Ratan Gupta56187e72017-08-13 09:40:14 +0530401}
402
Ratan Guptabd303b12017-08-18 17:10:07 +0530403namespace mac_address
404{
405
406constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
407constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
408constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
409constexpr auto propIntf = "org.freedesktop.DBus.Properties";
410constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530411constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530412
413using DbusObjectPath = std::string;
414using DbusService = std::string;
415using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500416using ObjectTree =
417 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530418
419constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
420constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500421 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530422constexpr auto invRoot = "/xyz/openbmc_project/inventory";
423
Patrick Williamsc38b0712022-07-22 19:26:54 -0500424ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530425{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530426
427 std::string interfaceName = intfName;
428
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700429#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530430 // load the config JSON from the Read Only Path
431 std::ifstream in(configFile);
432 nlohmann::json configJson;
433 in >> configJson;
434 interfaceName = configJson[intfName];
435#endif
436
Ratan Guptabd303b12017-08-18 17:10:07 +0530437 std::vector<DbusInterface> interfaces;
438 interfaces.emplace_back(invNetworkIntf);
439
440 auto depth = 0;
441
Gunnar Mills57d9c502018-09-14 14:42:34 -0500442 auto mapperCall =
443 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530444
445 mapperCall.append(invRoot, depth, interfaces);
446
447 auto mapperReply = bus.call(mapperCall);
448 if (mapperReply.is_method_error())
449 {
450 log<level::ERR>("Error in mapper call");
451 elog<InternalFailure>();
452 }
453
454 ObjectTree objectTree;
455 mapperReply.read(objectTree);
456
457 if (objectTree.empty())
458 {
459 log<level::ERR>("No Object has implemented the interface",
460 entry("INTERFACE=%s", invNetworkIntf));
461 elog<InternalFailure>();
462 }
463
Alvin Wang38a63c32019-08-29 22:56:46 +0800464 DbusObjectPath objPath;
465 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530466
Alvin Wang38a63c32019-08-29 22:56:46 +0800467 if (1 == objectTree.size())
468 {
469 objPath = objectTree.begin()->first;
470 service = objectTree.begin()->second.begin()->first;
471 }
472 else
473 {
474 // If there are more than 2 objects, object path must contain the
475 // interface name
476 for (auto const& object : objectTree)
477 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530478 log<level::INFO>("interface",
479 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800480 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530481
482 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800483 {
484 objPath = object.first;
485 service = object.second.begin()->first;
486 break;
487 }
488 }
489
490 if (objPath.empty())
491 {
492 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530493 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800494 elog<InternalFailure>();
495 }
496 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530497
Gunnar Mills57d9c502018-09-14 14:42:34 -0500498 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
499 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530500
501 method.append(invNetworkIntf, "MACAddress");
502
503 auto reply = bus.call(method);
504 if (reply.is_method_error())
505 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500506 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530507 entry("PATH=%s", objPath.c_str()),
508 entry("INTERFACE=%s", invNetworkIntf));
509 elog<InternalFailure>();
510 }
511
William A. Kennington III1137a972019-04-20 20:49:58 -0700512 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530513 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700514 return fromString(std::get<std::string>(value));
515}
516
William A. Kennington III1c776022022-01-05 14:12:16 -0800517ether_addr fromString(const char* str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700518{
William A. Kennington III1c776022022-01-05 14:12:16 -0800519 std::string genstr;
Potin Laida0b1d42021-12-26 20:08:20 +0800520
521 // MAC address without colons
William A. Kennington III1c776022022-01-05 14:12:16 -0800522 std::string_view strv = str;
523 if (strv.size() == 12 && strv.find(":") == strv.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700524 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800525 genstr =
526 fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), strv.substr(0, 2),
527 strv.substr(2, 2), strv.substr(4, 2), strv.substr(6, 2),
528 strv.substr(8, 2), strv.substr(10, 2));
529 str = genstr.c_str();
William A. Kennington III1137a972019-04-20 20:49:58 -0700530 }
Potin Laida0b1d42021-12-26 20:08:20 +0800531
William A. Kennington III1c776022022-01-05 14:12:16 -0800532 ether_addr addr;
533 if (ether_aton_r(str, &addr) == nullptr)
Potin Laida0b1d42021-12-26 20:08:20 +0800534 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800535 throw std::invalid_argument("Invalid MAC Address");
Potin Laida0b1d42021-12-26 20:08:20 +0800536 }
William A. Kennington III1c776022022-01-05 14:12:16 -0800537 return addr;
Ratan Guptabd303b12017-08-18 17:10:07 +0530538}
539
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700540std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800541{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800542 char buf[18] = {0};
543 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
544 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
545 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
546 mac.ether_addr_octet[5]);
547 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800548}
549
William A. Kennington III1137a972019-04-20 20:49:58 -0700550bool isEmpty(const ether_addr& mac)
551{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700552 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700553}
554
555bool isMulticast(const ether_addr& mac)
556{
557 return mac.ether_addr_octet[0] & 0b1;
558}
559
560bool isUnicast(const ether_addr& mac)
561{
562 return !isEmpty(mac) && !isMulticast(mac);
563}
564
Gunnar Mills57d9c502018-09-14 14:42:34 -0500565} // namespace mac_address
566} // namespace network
567} // namespace phosphor