blob: 186d0c20a3013f6ea8b9008344a762bf7b8b7d32 [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>
William A. Kennington III1c776022022-01-05 14:12:16 -08009#include <fmt/compile.h>
10#include <fmt/format.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 III69f45542022-09-24 23:28:14 -070015#include <charconv>
Manojkiran Edacc099a82020-05-11 14:25:16 +053016#include <fstream>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070017#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053018#include <nlohmann/json.hpp>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070019#endif
Patrick Venture189d44e2018-07-09 12:30:59 -070020#include <phosphor-logging/elog-errors.hpp>
21#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080022#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070023#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070024#include <string>
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -070025#include <string_view>
William A. Kennington III1137a972019-04-20 20:49:58 -070026#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070027#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053028
29namespace phosphor
30{
31namespace network
32{
Ratan Guptabc886292017-07-25 18:29:57 +053033
William A. Kennington III69f45542022-09-24 23:28:14 -070034using std::literals::string_view_literals::operator""sv;
Ratan Gupta8804feb2017-05-25 10:49:57 +053035using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053036using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta8804feb2017-05-25 10:49:57 +053037
Lei YU3894ce72021-03-18 14:53:42 +080038namespace internal
39{
40
William A. Kennington III69f45542022-09-24 23:28:14 -070041void executeCommandinChildProcess(stdplus::const_zstring path, char** args)
Lei YU3894ce72021-03-18 14:53:42 +080042{
43 using namespace std::string_literals;
44 pid_t pid = fork();
Lei YU3894ce72021-03-18 14:53:42 +080045
46 if (pid == 0)
47 {
William A. Kennington III69f45542022-09-24 23:28:14 -070048 execv(path.c_str(), args);
49 exit(255);
Lei YU3894ce72021-03-18 14:53:42 +080050 }
51 else if (pid < 0)
52 {
53 auto error = errno;
54 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
55 elog<InternalFailure>();
56 }
57 else if (pid > 0)
58 {
William A. Kennington III69f45542022-09-24 23:28:14 -070059 int status;
Lei YU3894ce72021-03-18 14:53:42 +080060 while (waitpid(pid, &status, 0) == -1)
61 {
62 if (errno != EINTR)
William A. Kennington III69f45542022-09-24 23:28:14 -070063 {
Lei YU3894ce72021-03-18 14:53:42 +080064 status = -1;
65 break;
66 }
67 }
68
69 if (status < 0)
70 {
William A. Kennington III69f45542022-09-24 23:28:14 -070071 fmt::memory_buffer buf;
72 fmt::format_to(fmt::appender(buf), "`{}`", path);
73 for (size_t i = 0; args[i] != nullptr; ++i)
Lei YU3894ce72021-03-18 14:53:42 +080074 {
William A. Kennington III69f45542022-09-24 23:28:14 -070075 fmt::format_to(fmt::appender(buf), " `{}`", args[i]);
Lei YU3894ce72021-03-18 14:53:42 +080076 }
William A. Kennington III69f45542022-09-24 23:28:14 -070077 buf.push_back('\0');
Lei YU3894ce72021-03-18 14:53:42 +080078 log<level::ERR>("Unable to execute the command",
William A. Kennington III69f45542022-09-24 23:28:14 -070079 entry("CMD=%s", buf.data()),
Lei YU3894ce72021-03-18 14:53:42 +080080 entry("STATUS=%d", status));
81 elog<InternalFailure>();
82 }
83 }
84}
85
Lei YU307554e2021-03-18 14:56:50 +080086/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070087std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +080088{
89 auto r = std::getenv("IGNORED_INTERFACES");
90 if (r == nullptr)
91 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070092 return "";
Lei YU307554e2021-03-18 14:56:50 +080093 }
94 return r;
95}
96
97/** @brief Parse the comma separated interface names */
William A. Kennington III95530ec2022-08-19 01:44:39 -070098std::unordered_set<std::string_view>
99 parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800100{
William A. Kennington III95530ec2022-08-19 01:44:39 -0700101 std::unordered_set<std::string_view> result;
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700102 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800103 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700104 auto sep = interfaces.find(',');
105 auto interface = interfaces.substr(0, sep);
106 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800107 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700108 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800109 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700110 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800111 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700112 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800113 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700114 if (!interface.empty())
115 {
116 result.insert(interface);
117 }
118 if (sep == interfaces.npos)
119 {
120 break;
121 }
122 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800123 }
124 return result;
125}
126
127/** @brief Get the ignored interfaces */
William A. Kennington III95530ec2022-08-19 01:44:39 -0700128const std::unordered_set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800129{
130 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
131 return ignoredInterfaces;
132}
133
Lei YU3894ce72021-03-18 14:53:42 +0800134} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530135
William A. Kennington IIIe5a48ab2019-04-22 03:55:23 -0700136constexpr auto familyVisit(auto&& visitor, int family)
137{
138 if (family == AF_INET)
139 {
140 return visitor.template operator()<AF_INET>();
141 }
142 else if (family == AF_INET6)
143 {
144 return visitor.template operator()<AF_INET6>();
145 }
146 throw std::invalid_argument("Invalid addr family");
147}
148
William A. Kennington III97b5dc62022-10-07 14:01:29 -0700149template <int family>
150typename FamilyTraits<family>::addr addrFromBuf(std::string_view buf)
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800151{
William A. Kennington III97b5dc62022-10-07 14:01:29 -0700152 return stdplus::raw::copyFromStrict<typename FamilyTraits<family>::addr>(
153 buf);
154}
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800155
William A. Kennington III97b5dc62022-10-07 14:01:29 -0700156InAddrAny addrFromBuf(int family, std::string_view buf)
157{
158 return familyVisit(
159 [=]<int f>() -> InAddrAny { return addrFromBuf<f>(buf); }, family);
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800160}
161
William A. Kennington IIId07c0862022-10-07 14:17:05 -0700162template <typename Addr>
163std::string toString(const Addr& addr)
Alexander Filippov983da552021-02-08 15:26:54 +0300164{
William A. Kennington IIId07c0862022-10-07 14:17:05 -0700165 static constexpr int family = AddrToFamily<Addr>::value;
166 std::string ret(FamilyTraits<family>::strlen, '\0');
167 if (inet_ntop(family, &addr, ret.data(), ret.size()) == nullptr)
Alexander Filippov983da552021-02-08 15:26:54 +0300168 {
William A. Kennington IIId07c0862022-10-07 14:17:05 -0700169 throw std::runtime_error("Failed to convert IP to string");
Alexander Filippov983da552021-02-08 15:26:54 +0300170 }
171
William A. Kennington IIId07c0862022-10-07 14:17:05 -0700172 ret.resize(strlen(ret.c_str()));
173 return ret;
Alexander Filippov983da552021-02-08 15:26:54 +0300174}
175
William A. Kennington III5058f572019-01-30 17:18:14 -0800176std::string toString(const InAddrAny& addr)
177{
William A. Kennington IIId07c0862022-10-07 14:17:05 -0700178 return std::visit([](auto&& a) { return toString(a); }, addr);
William A. Kennington III5058f572019-01-30 17:18:14 -0800179}
180
William A. Kennington III9f228302022-10-07 14:02:49 -0700181bool isValidIP(int family, stdplus::const_zstring address) noexcept
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500182{
183 unsigned char buf[sizeof(struct in6_addr)];
William A. Kennington III9f228302022-10-07 14:02:49 -0700184 return inet_pton(family, address.c_str(), buf) > 0;
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500185}
186
William A. Kennington IIIff12acb2022-10-07 19:06:56 -0700187bool isValidIP(stdplus::const_zstring address) noexcept
188{
189 return isValidIP(AF_INET, address) || isValidIP(AF_INET6, address);
190}
191
William A. Kennington IIIe5a48ab2019-04-22 03:55:23 -0700192bool isValidPrefix(int family, uint8_t prefix)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500193{
William A. Kennington IIIe5a48ab2019-04-22 03:55:23 -0700194 return familyVisit(
195 [=]<int f>() noexcept { return isValidPrefix<f>(prefix); }, family);
Ratan Gupta8804feb2017-05-25 10:49:57 +0530196}
197
William A. Kennington III69f45542022-09-24 23:28:14 -0700198void deleteInterface(stdplus::const_zstring intf)
Ratan Guptabc886292017-07-25 18:29:57 +0530199{
200 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500201 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530202
203 if (pid == 0)
204 {
205
206 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
207 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500208 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530209 entry("INTF=%s", intf.c_str()));
210 elog<InternalFailure>();
211 }
212 else if (pid < 0)
213 {
214 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500215 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530216 elog<InternalFailure>();
217 }
218 else if (pid > 0)
219 {
220 while (waitpid(pid, &status, 0) == -1)
221 {
222 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500223 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530224 status = -1;
225 break;
226 }
227 }
228
Gunnar Mills57d9c502018-09-14 14:42:34 -0500229 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530230 {
231 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500232 entry("INTF=%s", intf.c_str()),
233 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530234 elog<InternalFailure>();
235 }
236 }
237}
238
William A. Kennington III69f45542022-09-24 23:28:14 -0700239std::optional<std::string> interfaceToUbootEthAddr(std::string_view intf)
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700240{
William A. Kennington III69f45542022-09-24 23:28:14 -0700241 constexpr auto pfx = "eth"sv;
242 if (!intf.starts_with(pfx))
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700243 {
244 return std::nullopt;
245 }
William A. Kennington III69f45542022-09-24 23:28:14 -0700246 intf.remove_prefix(pfx.size());
247 auto last = intf.data() + intf.size();
248 unsigned long idx;
249 auto res = std::from_chars(intf.data(), last, idx);
250 if (res.ec != std::errc() || res.ptr != last)
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700251 {
252 return std::nullopt;
253 }
254 if (idx == 0)
255 {
256 return "ethaddr";
257 }
William A. Kennington III69f45542022-09-24 23:28:14 -0700258 return fmt::format(FMT_COMPILE("eth{}addr"), idx);
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700259}
260
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700261static std::optional<DHCPVal> systemdParseDHCP(std::string_view str)
262{
263 if (config::icaseeq(str, "ipv4"))
264 {
265 return DHCPVal{.v4 = true, .v6 = false};
266 }
267 if (config::icaseeq(str, "ipv6"))
268 {
269 return DHCPVal{.v4 = false, .v6 = true};
270 }
271 if (auto b = config::parseBool(str); b)
272 {
273 return DHCPVal{.v4 = *b, .v6 = *b};
274 }
275 return std::nullopt;
276}
277
278inline auto systemdParseLast(const config::Parser& config,
279 std::string_view section, std::string_view key,
280 auto&& fun)
281{
282 if (auto str = config.map.getLastValueString(section, key); str == nullptr)
283 {
284 auto err = fmt::format("Unable to get the value of {}[{}] from {}",
285 section, key, config.getFilename().native());
286 log<level::NOTICE>(err.c_str(),
287 entry("FILE=%s", config.getFilename().c_str()));
288 }
289 else if (auto val = fun(*str); !val)
290 {
291 auto err = fmt::format("Invalid value of {}[{}] from {}: {}", section,
292 key, config.getFilename().native(), *str);
293 log<level::NOTICE>(err.c_str(), entry("VALUE=%s", str->c_str()),
294 entry("FILE=%s", config.getFilename().c_str()));
295 }
296 else
297 {
298 return val;
299 }
300 return decltype(fun(std::string_view{}))(std::nullopt);
301}
302
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700303bool getIPv6AcceptRA(const config::Parser& config)
Ratan Gupta56187e72017-08-13 09:40:14 +0530304{
William A. Kennington III324d2602022-08-18 18:32:56 -0700305#ifdef ENABLE_IPV6_ACCEPT_RA
306 constexpr bool def = true;
307#else
308 constexpr bool def = false;
309#endif
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700310 return systemdParseLast(config, "Network", "IPv6AcceptRA",
311 config::parseBool)
312 .value_or(def);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700313}
314
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700315DHCPVal getDHCPValue(const config::Parser& config)
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700316{
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700317 return systemdParseLast(config, "Network", "DHCP", systemdParseDHCP)
318 .value_or(DHCPVal{.v4 = true, .v6 = true});
319}
William A. Kennington III324d2602022-08-18 18:32:56 -0700320
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700321bool getDHCPProp(const config::Parser& config, std::string_view key)
322{
323 return systemdParseLast(config, "DHCP", key, config::parseBool)
324 .value_or(true);
Ratan Gupta56187e72017-08-13 09:40:14 +0530325}
326
Ratan Guptabd303b12017-08-18 17:10:07 +0530327namespace mac_address
328{
329
330constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
331constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
332constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
333constexpr auto propIntf = "org.freedesktop.DBus.Properties";
334constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530335constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530336
337using DbusObjectPath = std::string;
338using DbusService = std::string;
339using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500340using ObjectTree =
341 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530342
343constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
344constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500345 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530346constexpr auto invRoot = "/xyz/openbmc_project/inventory";
347
Patrick Williamsc38b0712022-07-22 19:26:54 -0500348ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530349{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530350
351 std::string interfaceName = intfName;
352
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700353#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530354 // load the config JSON from the Read Only Path
355 std::ifstream in(configFile);
356 nlohmann::json configJson;
357 in >> configJson;
358 interfaceName = configJson[intfName];
359#endif
360
Ratan Guptabd303b12017-08-18 17:10:07 +0530361 std::vector<DbusInterface> interfaces;
362 interfaces.emplace_back(invNetworkIntf);
363
364 auto depth = 0;
365
Gunnar Mills57d9c502018-09-14 14:42:34 -0500366 auto mapperCall =
367 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530368
369 mapperCall.append(invRoot, depth, interfaces);
370
371 auto mapperReply = bus.call(mapperCall);
372 if (mapperReply.is_method_error())
373 {
374 log<level::ERR>("Error in mapper call");
375 elog<InternalFailure>();
376 }
377
378 ObjectTree objectTree;
379 mapperReply.read(objectTree);
380
381 if (objectTree.empty())
382 {
383 log<level::ERR>("No Object has implemented the interface",
384 entry("INTERFACE=%s", invNetworkIntf));
385 elog<InternalFailure>();
386 }
387
Alvin Wang38a63c32019-08-29 22:56:46 +0800388 DbusObjectPath objPath;
389 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530390
Alvin Wang38a63c32019-08-29 22:56:46 +0800391 if (1 == objectTree.size())
392 {
393 objPath = objectTree.begin()->first;
394 service = objectTree.begin()->second.begin()->first;
395 }
396 else
397 {
398 // If there are more than 2 objects, object path must contain the
399 // interface name
400 for (auto const& object : objectTree)
401 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530402 log<level::INFO>("interface",
403 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800404 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530405
406 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800407 {
408 objPath = object.first;
409 service = object.second.begin()->first;
410 break;
411 }
412 }
413
414 if (objPath.empty())
415 {
416 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530417 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800418 elog<InternalFailure>();
419 }
420 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530421
Gunnar Mills57d9c502018-09-14 14:42:34 -0500422 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
423 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530424
425 method.append(invNetworkIntf, "MACAddress");
426
427 auto reply = bus.call(method);
428 if (reply.is_method_error())
429 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500430 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530431 entry("PATH=%s", objPath.c_str()),
432 entry("INTERFACE=%s", invNetworkIntf));
433 elog<InternalFailure>();
434 }
435
William A. Kennington III1137a972019-04-20 20:49:58 -0700436 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530437 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700438 return fromString(std::get<std::string>(value));
439}
440
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700441static uint8_t decodeHex(std::string_view str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700442{
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700443 uint8_t ret;
444 auto res = std::from_chars(str.begin(), str.end(), ret, 16);
445 if (res.ptr != str.end() || res.ec != std::errc())
446 {
447 throw std::invalid_argument("Not hex");
448 }
449 return ret;
450}
Potin Laida0b1d42021-12-26 20:08:20 +0800451
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700452ether_addr fromString(std::string_view str)
453{
454 ether_addr ret;
William A. Kennington III69f45542022-09-24 23:28:14 -0700455 if (str.size() == 12 && str.find(":") == str.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700456 {
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700457 for (size_t i = 0; i < 6; ++i)
458 {
459 ret.ether_addr_octet[i] = decodeHex(str.substr(i * 2, 2));
460 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700461 }
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700462 else
Potin Laida0b1d42021-12-26 20:08:20 +0800463 {
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700464 for (size_t i = 0; i < 5; ++i)
465 {
466 auto loc = str.find(":");
467 ret.ether_addr_octet[i] = decodeHex(str.substr(0, loc));
468 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
469 if (str.empty())
470 {
471 throw std::invalid_argument("Missing mac data");
472 }
473 }
474 ret.ether_addr_octet[5] = decodeHex(str);
Potin Laida0b1d42021-12-26 20:08:20 +0800475 }
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700476 return ret;
Ratan Guptabd303b12017-08-18 17:10:07 +0530477}
478
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700479std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800480{
William A. Kennington III69f45542022-09-24 23:28:14 -0700481 return fmt::format(FMT_COMPILE("{:02x}"),
482 fmt::join(mac.ether_addr_octet, ":"));
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800483}
484
William A. Kennington III1137a972019-04-20 20:49:58 -0700485bool isEmpty(const ether_addr& mac)
486{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700487 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700488}
489
490bool isMulticast(const ether_addr& mac)
491{
492 return mac.ether_addr_octet[0] & 0b1;
493}
494
495bool isUnicast(const ether_addr& mac)
496{
497 return !isEmpty(mac) && !isMulticast(mac);
498}
499
Gunnar Mills57d9c502018-09-14 14:42:34 -0500500} // namespace mac_address
501} // namespace network
502} // namespace phosphor