blob: cef29663c3842b666ee8780f53afe1e836ff91da [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 III69f45542022-09-24 23:28:14 -070017#include <charconv>
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -070018#include <cstdlib>
19#include <cstring>
Manojkiran Edacc099a82020-05-11 14:25:16 +053020#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070021#include <list>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070022#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053023#include <nlohmann/json.hpp>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070024#endif
Patrick Venture189d44e2018-07-09 12:30:59 -070025#include <phosphor-logging/elog-errors.hpp>
26#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080027#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070028#include <stdplus/raw.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070029#include <string>
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -070030#include <string_view>
William A. Kennington III1137a972019-04-20 20:49:58 -070031#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070032#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053033
34namespace phosphor
35{
36namespace network
37{
Ratan Guptabc886292017-07-25 18:29:57 +053038
William A. Kennington III69f45542022-09-24 23:28:14 -070039using std::literals::string_view_literals::operator""sv;
Ratan Gupta8804feb2017-05-25 10:49:57 +053040using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053041using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta8804feb2017-05-25 10:49:57 +053042
Lei YU3894ce72021-03-18 14:53:42 +080043namespace internal
44{
45
William A. Kennington III69f45542022-09-24 23:28:14 -070046void executeCommandinChildProcess(stdplus::const_zstring path, char** args)
Lei YU3894ce72021-03-18 14:53:42 +080047{
48 using namespace std::string_literals;
49 pid_t pid = fork();
Lei YU3894ce72021-03-18 14:53:42 +080050
51 if (pid == 0)
52 {
William A. Kennington III69f45542022-09-24 23:28:14 -070053 execv(path.c_str(), args);
54 exit(255);
Lei YU3894ce72021-03-18 14:53:42 +080055 }
56 else if (pid < 0)
57 {
58 auto error = errno;
59 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
60 elog<InternalFailure>();
61 }
62 else if (pid > 0)
63 {
William A. Kennington III69f45542022-09-24 23:28:14 -070064 int status;
Lei YU3894ce72021-03-18 14:53:42 +080065 while (waitpid(pid, &status, 0) == -1)
66 {
67 if (errno != EINTR)
William A. Kennington III69f45542022-09-24 23:28:14 -070068 {
Lei YU3894ce72021-03-18 14:53:42 +080069 status = -1;
70 break;
71 }
72 }
73
74 if (status < 0)
75 {
William A. Kennington III69f45542022-09-24 23:28:14 -070076 fmt::memory_buffer buf;
77 fmt::format_to(fmt::appender(buf), "`{}`", path);
78 for (size_t i = 0; args[i] != nullptr; ++i)
Lei YU3894ce72021-03-18 14:53:42 +080079 {
William A. Kennington III69f45542022-09-24 23:28:14 -070080 fmt::format_to(fmt::appender(buf), " `{}`", args[i]);
Lei YU3894ce72021-03-18 14:53:42 +080081 }
William A. Kennington III69f45542022-09-24 23:28:14 -070082 buf.push_back('\0');
Lei YU3894ce72021-03-18 14:53:42 +080083 log<level::ERR>("Unable to execute the command",
William A. Kennington III69f45542022-09-24 23:28:14 -070084 entry("CMD=%s", buf.data()),
Lei YU3894ce72021-03-18 14:53:42 +080085 entry("STATUS=%d", status));
86 elog<InternalFailure>();
87 }
88 }
89}
90
Lei YU307554e2021-03-18 14:56:50 +080091/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070092std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +080093{
94 auto r = std::getenv("IGNORED_INTERFACES");
95 if (r == nullptr)
96 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070097 return "";
Lei YU307554e2021-03-18 14:56:50 +080098 }
99 return r;
100}
101
102/** @brief Parse the comma separated interface names */
William A. Kennington III95530ec2022-08-19 01:44:39 -0700103std::unordered_set<std::string_view>
104 parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800105{
William A. Kennington III95530ec2022-08-19 01:44:39 -0700106 std::unordered_set<std::string_view> result;
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700107 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800108 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700109 auto sep = interfaces.find(',');
110 auto interface = interfaces.substr(0, sep);
111 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800112 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700113 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800114 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700115 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800116 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700117 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800118 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700119 if (!interface.empty())
120 {
121 result.insert(interface);
122 }
123 if (sep == interfaces.npos)
124 {
125 break;
126 }
127 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800128 }
129 return result;
130}
131
132/** @brief Get the ignored interfaces */
William A. Kennington III95530ec2022-08-19 01:44:39 -0700133const std::unordered_set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800134{
135 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
136 return ignoredInterfaces;
137}
138
Lei YU3894ce72021-03-18 14:53:42 +0800139} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530140
William A. Kennington IIIe5a48ab2019-04-22 03:55:23 -0700141constexpr auto familyVisit(auto&& visitor, int family)
142{
143 if (family == AF_INET)
144 {
145 return visitor.template operator()<AF_INET>();
146 }
147 else if (family == AF_INET6)
148 {
149 return visitor.template operator()<AF_INET6>();
150 }
151 throw std::invalid_argument("Invalid addr family");
152}
153
Ratan Gupta8804feb2017-05-25 10:49:57 +0530154std::string toMask(int addressFamily, uint8_t prefix)
155{
156 if (addressFamily == AF_INET6)
157 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500158 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530159 return "";
160 }
161
162 if (prefix < 1 || prefix > 30)
163 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500164 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530165 return "";
166 }
167 /* Create the netmask from the number of bits */
168 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500169 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530170 {
171 mask |= 1 << (31 - i);
172 }
173 struct in_addr netmask;
174 netmask.s_addr = htonl(mask);
175 return inet_ntoa(netmask);
176}
177
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800178InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
179{
180 if (addressFamily == AF_INET)
181 {
182 struct in_addr ret;
183 if (buf.size() != sizeof(ret))
184 {
185 throw std::runtime_error("Buf not in_addr sized");
186 }
187 memcpy(&ret, buf.data(), sizeof(ret));
188 return ret;
189 }
190 else if (addressFamily == AF_INET6)
191 {
192 struct in6_addr ret;
193 if (buf.size() != sizeof(ret))
194 {
195 throw std::runtime_error("Buf not in6_addr sized");
196 }
197 memcpy(&ret, buf.data(), sizeof(ret));
198 return ret;
199 }
200
201 throw std::runtime_error("Unsupported address family");
202}
203
Alexander Filippov983da552021-02-08 15:26:54 +0300204std::string toString(const struct in_addr& addr)
205{
206 std::string ip(INET_ADDRSTRLEN, '\0');
207 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
208 {
209 throw std::runtime_error("Failed to convert IP4 to string");
210 }
211
212 ip.resize(strlen(ip.c_str()));
213 return ip;
214}
215
216std::string toString(const struct in6_addr& addr)
217{
218 std::string ip(INET6_ADDRSTRLEN, '\0');
219 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
220 {
221 throw std::runtime_error("Failed to convert IP6 to string");
222 }
223
224 ip.resize(strlen(ip.c_str()));
225 return ip;
226}
227
William A. Kennington III5058f572019-01-30 17:18:14 -0800228std::string toString(const InAddrAny& addr)
229{
William A. Kennington III5058f572019-01-30 17:18:14 -0800230 if (std::holds_alternative<struct in_addr>(addr))
231 {
232 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300233 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800234 }
235 else if (std::holds_alternative<struct in6_addr>(addr))
236 {
237 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300238 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800239 }
Alexander Filippov983da552021-02-08 15:26:54 +0300240
241 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800242}
243
William A. Kennington III69f45542022-09-24 23:28:14 -0700244bool isValidIP(int addressFamily, stdplus::const_zstring address)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500245{
246 unsigned char buf[sizeof(struct in6_addr)];
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500247 return inet_pton(addressFamily, address.c_str(), buf) > 0;
248}
249
William A. Kennington IIIe5a48ab2019-04-22 03:55:23 -0700250bool isValidPrefix(int family, uint8_t prefix)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500251{
William A. Kennington IIIe5a48ab2019-04-22 03:55:23 -0700252 return familyVisit(
253 [=]<int f>() noexcept { return isValidPrefix<f>(prefix); }, family);
Ratan Gupta8804feb2017-05-25 10:49:57 +0530254}
255
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530256InterfaceList getInterfaces()
257{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500258 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530259 struct ifaddrs* ifaddr = nullptr;
260
261 // attempt to fill struct with ifaddrs
262 if (getifaddrs(&ifaddr) == -1)
263 {
264 auto error = errno;
265 log<level::ERR>("Error occurred during the getifaddrs call",
266 entry("ERRNO=%d", error));
267 elog<InternalFailure>();
268 }
269
270 AddrPtr ifaddrPtr(ifaddr);
271 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800272 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530273
274 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
275 {
276 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700277 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800278 if (ifa->ifa_flags & IFF_LOOPBACK ||
279 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530280 {
281 continue;
282 }
Willy Tuf7dce2e2022-10-07 05:48:08 +0000283 interfaces.emplace(ifa->ifa_name);
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530284 }
285 return interfaces;
286}
287
William A. Kennington III69f45542022-09-24 23:28:14 -0700288void deleteInterface(stdplus::const_zstring intf)
Ratan Guptabc886292017-07-25 18:29:57 +0530289{
290 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500291 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530292
293 if (pid == 0)
294 {
295
296 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
297 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500298 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530299 entry("INTF=%s", intf.c_str()));
300 elog<InternalFailure>();
301 }
302 else if (pid < 0)
303 {
304 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500305 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530306 elog<InternalFailure>();
307 }
308 else if (pid > 0)
309 {
310 while (waitpid(pid, &status, 0) == -1)
311 {
312 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500313 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530314 status = -1;
315 break;
316 }
317 }
318
Gunnar Mills57d9c502018-09-14 14:42:34 -0500319 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530320 {
321 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500322 entry("INTF=%s", intf.c_str()),
323 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530324 elog<InternalFailure>();
325 }
326 }
327}
328
William A. Kennington III69f45542022-09-24 23:28:14 -0700329std::optional<std::string> interfaceToUbootEthAddr(std::string_view intf)
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700330{
William A. Kennington III69f45542022-09-24 23:28:14 -0700331 constexpr auto pfx = "eth"sv;
332 if (!intf.starts_with(pfx))
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700333 {
334 return std::nullopt;
335 }
William A. Kennington III69f45542022-09-24 23:28:14 -0700336 intf.remove_prefix(pfx.size());
337 auto last = intf.data() + intf.size();
338 unsigned long idx;
339 auto res = std::from_chars(intf.data(), last, idx);
340 if (res.ec != std::errc() || res.ptr != last)
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700341 {
342 return std::nullopt;
343 }
344 if (idx == 0)
345 {
346 return "ethaddr";
347 }
William A. Kennington III69f45542022-09-24 23:28:14 -0700348 return fmt::format(FMT_COMPILE("eth{}addr"), idx);
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700349}
350
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700351static std::optional<DHCPVal> systemdParseDHCP(std::string_view str)
352{
353 if (config::icaseeq(str, "ipv4"))
354 {
355 return DHCPVal{.v4 = true, .v6 = false};
356 }
357 if (config::icaseeq(str, "ipv6"))
358 {
359 return DHCPVal{.v4 = false, .v6 = true};
360 }
361 if (auto b = config::parseBool(str); b)
362 {
363 return DHCPVal{.v4 = *b, .v6 = *b};
364 }
365 return std::nullopt;
366}
367
368inline auto systemdParseLast(const config::Parser& config,
369 std::string_view section, std::string_view key,
370 auto&& fun)
371{
372 if (auto str = config.map.getLastValueString(section, key); str == nullptr)
373 {
374 auto err = fmt::format("Unable to get the value of {}[{}] from {}",
375 section, key, config.getFilename().native());
376 log<level::NOTICE>(err.c_str(),
377 entry("FILE=%s", config.getFilename().c_str()));
378 }
379 else if (auto val = fun(*str); !val)
380 {
381 auto err = fmt::format("Invalid value of {}[{}] from {}: {}", section,
382 key, config.getFilename().native(), *str);
383 log<level::NOTICE>(err.c_str(), entry("VALUE=%s", str->c_str()),
384 entry("FILE=%s", config.getFilename().c_str()));
385 }
386 else
387 {
388 return val;
389 }
390 return decltype(fun(std::string_view{}))(std::nullopt);
391}
392
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700393bool getIPv6AcceptRA(const config::Parser& config)
Ratan Gupta56187e72017-08-13 09:40:14 +0530394{
William A. Kennington III324d2602022-08-18 18:32:56 -0700395#ifdef ENABLE_IPV6_ACCEPT_RA
396 constexpr bool def = true;
397#else
398 constexpr bool def = false;
399#endif
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700400 return systemdParseLast(config, "Network", "IPv6AcceptRA",
401 config::parseBool)
402 .value_or(def);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700403}
404
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700405DHCPVal getDHCPValue(const config::Parser& config)
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700406{
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700407 return systemdParseLast(config, "Network", "DHCP", systemdParseDHCP)
408 .value_or(DHCPVal{.v4 = true, .v6 = true});
409}
William A. Kennington III324d2602022-08-18 18:32:56 -0700410
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700411bool getDHCPProp(const config::Parser& config, std::string_view key)
412{
413 return systemdParseLast(config, "DHCP", key, config::parseBool)
414 .value_or(true);
Ratan Gupta56187e72017-08-13 09:40:14 +0530415}
416
Ratan Guptabd303b12017-08-18 17:10:07 +0530417namespace mac_address
418{
419
420constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
421constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
422constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
423constexpr auto propIntf = "org.freedesktop.DBus.Properties";
424constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530425constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530426
427using DbusObjectPath = std::string;
428using DbusService = std::string;
429using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500430using ObjectTree =
431 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530432
433constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
434constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500435 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530436constexpr auto invRoot = "/xyz/openbmc_project/inventory";
437
Patrick Williamsc38b0712022-07-22 19:26:54 -0500438ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530439{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530440
441 std::string interfaceName = intfName;
442
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700443#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530444 // load the config JSON from the Read Only Path
445 std::ifstream in(configFile);
446 nlohmann::json configJson;
447 in >> configJson;
448 interfaceName = configJson[intfName];
449#endif
450
Ratan Guptabd303b12017-08-18 17:10:07 +0530451 std::vector<DbusInterface> interfaces;
452 interfaces.emplace_back(invNetworkIntf);
453
454 auto depth = 0;
455
Gunnar Mills57d9c502018-09-14 14:42:34 -0500456 auto mapperCall =
457 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530458
459 mapperCall.append(invRoot, depth, interfaces);
460
461 auto mapperReply = bus.call(mapperCall);
462 if (mapperReply.is_method_error())
463 {
464 log<level::ERR>("Error in mapper call");
465 elog<InternalFailure>();
466 }
467
468 ObjectTree objectTree;
469 mapperReply.read(objectTree);
470
471 if (objectTree.empty())
472 {
473 log<level::ERR>("No Object has implemented the interface",
474 entry("INTERFACE=%s", invNetworkIntf));
475 elog<InternalFailure>();
476 }
477
Alvin Wang38a63c32019-08-29 22:56:46 +0800478 DbusObjectPath objPath;
479 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530480
Alvin Wang38a63c32019-08-29 22:56:46 +0800481 if (1 == objectTree.size())
482 {
483 objPath = objectTree.begin()->first;
484 service = objectTree.begin()->second.begin()->first;
485 }
486 else
487 {
488 // If there are more than 2 objects, object path must contain the
489 // interface name
490 for (auto const& object : objectTree)
491 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530492 log<level::INFO>("interface",
493 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800494 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530495
496 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800497 {
498 objPath = object.first;
499 service = object.second.begin()->first;
500 break;
501 }
502 }
503
504 if (objPath.empty())
505 {
506 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530507 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800508 elog<InternalFailure>();
509 }
510 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530511
Gunnar Mills57d9c502018-09-14 14:42:34 -0500512 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
513 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530514
515 method.append(invNetworkIntf, "MACAddress");
516
517 auto reply = bus.call(method);
518 if (reply.is_method_error())
519 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500520 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530521 entry("PATH=%s", objPath.c_str()),
522 entry("INTERFACE=%s", invNetworkIntf));
523 elog<InternalFailure>();
524 }
525
William A. Kennington III1137a972019-04-20 20:49:58 -0700526 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530527 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700528 return fromString(std::get<std::string>(value));
529}
530
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700531static uint8_t decodeHex(std::string_view str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700532{
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700533 uint8_t ret;
534 auto res = std::from_chars(str.begin(), str.end(), ret, 16);
535 if (res.ptr != str.end() || res.ec != std::errc())
536 {
537 throw std::invalid_argument("Not hex");
538 }
539 return ret;
540}
Potin Laida0b1d42021-12-26 20:08:20 +0800541
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700542ether_addr fromString(std::string_view str)
543{
544 ether_addr ret;
William A. Kennington III69f45542022-09-24 23:28:14 -0700545 if (str.size() == 12 && str.find(":") == str.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700546 {
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700547 for (size_t i = 0; i < 6; ++i)
548 {
549 ret.ether_addr_octet[i] = decodeHex(str.substr(i * 2, 2));
550 }
William A. Kennington III1137a972019-04-20 20:49:58 -0700551 }
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700552 else
Potin Laida0b1d42021-12-26 20:08:20 +0800553 {
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700554 for (size_t i = 0; i < 5; ++i)
555 {
556 auto loc = str.find(":");
557 ret.ether_addr_octet[i] = decodeHex(str.substr(0, loc));
558 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
559 if (str.empty())
560 {
561 throw std::invalid_argument("Missing mac data");
562 }
563 }
564 ret.ether_addr_octet[5] = decodeHex(str);
Potin Laida0b1d42021-12-26 20:08:20 +0800565 }
William A. Kennington IIIfeb7aab2022-10-03 17:21:44 -0700566 return ret;
Ratan Guptabd303b12017-08-18 17:10:07 +0530567}
568
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700569std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800570{
William A. Kennington III69f45542022-09-24 23:28:14 -0700571 return fmt::format(FMT_COMPILE("{:02x}"),
572 fmt::join(mac.ether_addr_octet, ":"));
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800573}
574
William A. Kennington III1137a972019-04-20 20:49:58 -0700575bool isEmpty(const ether_addr& mac)
576{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700577 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700578}
579
580bool isMulticast(const ether_addr& mac)
581{
582 return mac.ether_addr_octet[0] & 0b1;
583}
584
585bool isUnicast(const ether_addr& mac)
586{
587 return !isEmpty(mac) && !isMulticast(mac);
588}
589
Gunnar Mills57d9c502018-09-14 14:42:34 -0500590} // namespace mac_address
591} // namespace network
592} // namespace phosphor