blob: c6aeddeccaceba7ba3114503dde302819bd3fe0d [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 III1137a972019-04-20 20:49:58 -070030#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070031#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053032
33namespace phosphor
34{
35namespace network
36{
Ratan Guptabc886292017-07-25 18:29:57 +053037
William A. Kennington III69f45542022-09-24 23:28:14 -070038using std::literals::string_view_literals::operator""sv;
Ratan Gupta8804feb2017-05-25 10:49:57 +053039using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053040using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta8804feb2017-05-25 10:49:57 +053041
Lei YU3894ce72021-03-18 14:53:42 +080042namespace internal
43{
44
William A. Kennington III69f45542022-09-24 23:28:14 -070045void executeCommandinChildProcess(stdplus::const_zstring path, char** args)
Lei YU3894ce72021-03-18 14:53:42 +080046{
47 using namespace std::string_literals;
48 pid_t pid = fork();
Lei YU3894ce72021-03-18 14:53:42 +080049
50 if (pid == 0)
51 {
William A. Kennington III69f45542022-09-24 23:28:14 -070052 execv(path.c_str(), args);
53 exit(255);
Lei YU3894ce72021-03-18 14:53:42 +080054 }
55 else if (pid < 0)
56 {
57 auto error = errno;
58 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
59 elog<InternalFailure>();
60 }
61 else if (pid > 0)
62 {
William A. Kennington III69f45542022-09-24 23:28:14 -070063 int status;
Lei YU3894ce72021-03-18 14:53:42 +080064 while (waitpid(pid, &status, 0) == -1)
65 {
66 if (errno != EINTR)
William A. Kennington III69f45542022-09-24 23:28:14 -070067 {
Lei YU3894ce72021-03-18 14:53:42 +080068 status = -1;
69 break;
70 }
71 }
72
73 if (status < 0)
74 {
William A. Kennington III69f45542022-09-24 23:28:14 -070075 fmt::memory_buffer buf;
76 fmt::format_to(fmt::appender(buf), "`{}`", path);
77 for (size_t i = 0; args[i] != nullptr; ++i)
Lei YU3894ce72021-03-18 14:53:42 +080078 {
William A. Kennington III69f45542022-09-24 23:28:14 -070079 fmt::format_to(fmt::appender(buf), " `{}`", args[i]);
Lei YU3894ce72021-03-18 14:53:42 +080080 }
William A. Kennington III69f45542022-09-24 23:28:14 -070081 buf.push_back('\0');
Lei YU3894ce72021-03-18 14:53:42 +080082 log<level::ERR>("Unable to execute the command",
William A. Kennington III69f45542022-09-24 23:28:14 -070083 entry("CMD=%s", buf.data()),
Lei YU3894ce72021-03-18 14:53:42 +080084 entry("STATUS=%d", status));
85 elog<InternalFailure>();
86 }
87 }
88}
89
Lei YU307554e2021-03-18 14:56:50 +080090/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070091std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +080092{
93 auto r = std::getenv("IGNORED_INTERFACES");
94 if (r == nullptr)
95 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -070096 return "";
Lei YU307554e2021-03-18 14:56:50 +080097 }
98 return r;
99}
100
101/** @brief Parse the comma separated interface names */
William A. Kennington III95530ec2022-08-19 01:44:39 -0700102std::unordered_set<std::string_view>
103 parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800104{
William A. Kennington III95530ec2022-08-19 01:44:39 -0700105 std::unordered_set<std::string_view> result;
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700106 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800107 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700108 auto sep = interfaces.find(',');
109 auto interface = interfaces.substr(0, sep);
110 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800111 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700112 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800113 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700114 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800115 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700116 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800117 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700118 if (!interface.empty())
119 {
120 result.insert(interface);
121 }
122 if (sep == interfaces.npos)
123 {
124 break;
125 }
126 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800127 }
128 return result;
129}
130
131/** @brief Get the ignored interfaces */
William A. Kennington III95530ec2022-08-19 01:44:39 -0700132const std::unordered_set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800133{
134 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
135 return ignoredInterfaces;
136}
137
Lei YU3894ce72021-03-18 14:53:42 +0800138} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530139
Ratan Gupta8804feb2017-05-25 10:49:57 +0530140std::string toMask(int addressFamily, uint8_t prefix)
141{
142 if (addressFamily == AF_INET6)
143 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500144 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530145 return "";
146 }
147
148 if (prefix < 1 || prefix > 30)
149 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500150 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530151 return "";
152 }
153 /* Create the netmask from the number of bits */
154 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500155 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530156 {
157 mask |= 1 << (31 - i);
158 }
159 struct in_addr netmask;
160 netmask.s_addr = htonl(mask);
161 return inet_ntoa(netmask);
162}
163
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800164InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
165{
166 if (addressFamily == AF_INET)
167 {
168 struct in_addr ret;
169 if (buf.size() != sizeof(ret))
170 {
171 throw std::runtime_error("Buf not in_addr sized");
172 }
173 memcpy(&ret, buf.data(), sizeof(ret));
174 return ret;
175 }
176 else if (addressFamily == AF_INET6)
177 {
178 struct in6_addr ret;
179 if (buf.size() != sizeof(ret))
180 {
181 throw std::runtime_error("Buf not in6_addr sized");
182 }
183 memcpy(&ret, buf.data(), sizeof(ret));
184 return ret;
185 }
186
187 throw std::runtime_error("Unsupported address family");
188}
189
Alexander Filippov983da552021-02-08 15:26:54 +0300190std::string toString(const struct in_addr& addr)
191{
192 std::string ip(INET_ADDRSTRLEN, '\0');
193 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
194 {
195 throw std::runtime_error("Failed to convert IP4 to string");
196 }
197
198 ip.resize(strlen(ip.c_str()));
199 return ip;
200}
201
202std::string toString(const struct in6_addr& addr)
203{
204 std::string ip(INET6_ADDRSTRLEN, '\0');
205 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
206 {
207 throw std::runtime_error("Failed to convert IP6 to string");
208 }
209
210 ip.resize(strlen(ip.c_str()));
211 return ip;
212}
213
William A. Kennington III5058f572019-01-30 17:18:14 -0800214std::string toString(const InAddrAny& addr)
215{
William A. Kennington III5058f572019-01-30 17:18:14 -0800216 if (std::holds_alternative<struct in_addr>(addr))
217 {
218 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300219 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800220 }
221 else if (std::holds_alternative<struct in6_addr>(addr))
222 {
223 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300224 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800225 }
Alexander Filippov983da552021-02-08 15:26:54 +0300226
227 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800228}
229
William A. Kennington III69f45542022-09-24 23:28:14 -0700230bool isValidIP(int addressFamily, stdplus::const_zstring address)
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500231{
232 unsigned char buf[sizeof(struct in6_addr)];
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500233 return inet_pton(addressFamily, address.c_str(), buf) > 0;
234}
235
236bool isValidPrefix(int addressFamily, uint8_t prefixLength)
237{
238 if (addressFamily == AF_INET)
239 {
240 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
241 prefixLength > IPV4_MAX_PREFIX_LENGTH)
242 {
243 return false;
244 }
245 }
246
247 if (addressFamily == AF_INET6)
248 {
249 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
250 prefixLength > IPV6_MAX_PREFIX_LENGTH)
251 {
252 return false;
253 }
254 }
255
256 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530257}
258
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530259InterfaceList getInterfaces()
260{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500261 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530262 struct ifaddrs* ifaddr = nullptr;
263
264 // attempt to fill struct with ifaddrs
265 if (getifaddrs(&ifaddr) == -1)
266 {
267 auto error = errno;
268 log<level::ERR>("Error occurred during the getifaddrs call",
269 entry("ERRNO=%d", error));
270 elog<InternalFailure>();
271 }
272
273 AddrPtr ifaddrPtr(ifaddr);
274 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800275 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530276
277 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
278 {
279 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700280 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800281 if (ifa->ifa_flags & IFF_LOOPBACK ||
282 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530283 {
284 continue;
285 }
Willy Tuf7dce2e2022-10-07 05:48:08 +0000286 interfaces.emplace(ifa->ifa_name);
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530287 }
288 return interfaces;
289}
290
William A. Kennington III69f45542022-09-24 23:28:14 -0700291void deleteInterface(stdplus::const_zstring intf)
Ratan Guptabc886292017-07-25 18:29:57 +0530292{
293 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500294 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530295
296 if (pid == 0)
297 {
298
299 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
300 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500301 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530302 entry("INTF=%s", intf.c_str()));
303 elog<InternalFailure>();
304 }
305 else if (pid < 0)
306 {
307 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500308 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530309 elog<InternalFailure>();
310 }
311 else if (pid > 0)
312 {
313 while (waitpid(pid, &status, 0) == -1)
314 {
315 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500316 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530317 status = -1;
318 break;
319 }
320 }
321
Gunnar Mills57d9c502018-09-14 14:42:34 -0500322 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530323 {
324 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500325 entry("INTF=%s", intf.c_str()),
326 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530327 elog<InternalFailure>();
328 }
329 }
330}
331
William A. Kennington III69f45542022-09-24 23:28:14 -0700332std::optional<std::string> interfaceToUbootEthAddr(std::string_view intf)
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700333{
William A. Kennington III69f45542022-09-24 23:28:14 -0700334 constexpr auto pfx = "eth"sv;
335 if (!intf.starts_with(pfx))
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700336 {
337 return std::nullopt;
338 }
William A. Kennington III69f45542022-09-24 23:28:14 -0700339 intf.remove_prefix(pfx.size());
340 auto last = intf.data() + intf.size();
341 unsigned long idx;
342 auto res = std::from_chars(intf.data(), last, idx);
343 if (res.ec != std::errc() || res.ptr != last)
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700344 {
345 return std::nullopt;
346 }
347 if (idx == 0)
348 {
349 return "ethaddr";
350 }
William A. Kennington III69f45542022-09-24 23:28:14 -0700351 return fmt::format(FMT_COMPILE("eth{}addr"), idx);
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700352}
353
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700354static std::optional<DHCPVal> systemdParseDHCP(std::string_view str)
355{
356 if (config::icaseeq(str, "ipv4"))
357 {
358 return DHCPVal{.v4 = true, .v6 = false};
359 }
360 if (config::icaseeq(str, "ipv6"))
361 {
362 return DHCPVal{.v4 = false, .v6 = true};
363 }
364 if (auto b = config::parseBool(str); b)
365 {
366 return DHCPVal{.v4 = *b, .v6 = *b};
367 }
368 return std::nullopt;
369}
370
371inline auto systemdParseLast(const config::Parser& config,
372 std::string_view section, std::string_view key,
373 auto&& fun)
374{
375 if (auto str = config.map.getLastValueString(section, key); str == nullptr)
376 {
377 auto err = fmt::format("Unable to get the value of {}[{}] from {}",
378 section, key, config.getFilename().native());
379 log<level::NOTICE>(err.c_str(),
380 entry("FILE=%s", config.getFilename().c_str()));
381 }
382 else if (auto val = fun(*str); !val)
383 {
384 auto err = fmt::format("Invalid value of {}[{}] from {}: {}", section,
385 key, config.getFilename().native(), *str);
386 log<level::NOTICE>(err.c_str(), entry("VALUE=%s", str->c_str()),
387 entry("FILE=%s", config.getFilename().c_str()));
388 }
389 else
390 {
391 return val;
392 }
393 return decltype(fun(std::string_view{}))(std::nullopt);
394}
395
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700396bool getIPv6AcceptRA(const config::Parser& config)
Ratan Gupta56187e72017-08-13 09:40:14 +0530397{
William A. Kennington III324d2602022-08-18 18:32:56 -0700398#ifdef ENABLE_IPV6_ACCEPT_RA
399 constexpr bool def = true;
400#else
401 constexpr bool def = false;
402#endif
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700403 return systemdParseLast(config, "Network", "IPv6AcceptRA",
404 config::parseBool)
405 .value_or(def);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700406}
407
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700408DHCPVal getDHCPValue(const config::Parser& config)
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700409{
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700410 return systemdParseLast(config, "Network", "DHCP", systemdParseDHCP)
411 .value_or(DHCPVal{.v4 = true, .v6 = true});
412}
William A. Kennington III324d2602022-08-18 18:32:56 -0700413
William A. Kennington IIIe94c9ff2022-08-18 20:12:27 -0700414bool getDHCPProp(const config::Parser& config, std::string_view key)
415{
416 return systemdParseLast(config, "DHCP", key, config::parseBool)
417 .value_or(true);
Ratan Gupta56187e72017-08-13 09:40:14 +0530418}
419
Ratan Guptabd303b12017-08-18 17:10:07 +0530420namespace mac_address
421{
422
423constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
424constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
425constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
426constexpr auto propIntf = "org.freedesktop.DBus.Properties";
427constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530428constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530429
430using DbusObjectPath = std::string;
431using DbusService = std::string;
432using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500433using ObjectTree =
434 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530435
436constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
437constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500438 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530439constexpr auto invRoot = "/xyz/openbmc_project/inventory";
440
Patrick Williamsc38b0712022-07-22 19:26:54 -0500441ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530442{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530443
444 std::string interfaceName = intfName;
445
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700446#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530447 // load the config JSON from the Read Only Path
448 std::ifstream in(configFile);
449 nlohmann::json configJson;
450 in >> configJson;
451 interfaceName = configJson[intfName];
452#endif
453
Ratan Guptabd303b12017-08-18 17:10:07 +0530454 std::vector<DbusInterface> interfaces;
455 interfaces.emplace_back(invNetworkIntf);
456
457 auto depth = 0;
458
Gunnar Mills57d9c502018-09-14 14:42:34 -0500459 auto mapperCall =
460 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530461
462 mapperCall.append(invRoot, depth, interfaces);
463
464 auto mapperReply = bus.call(mapperCall);
465 if (mapperReply.is_method_error())
466 {
467 log<level::ERR>("Error in mapper call");
468 elog<InternalFailure>();
469 }
470
471 ObjectTree objectTree;
472 mapperReply.read(objectTree);
473
474 if (objectTree.empty())
475 {
476 log<level::ERR>("No Object has implemented the interface",
477 entry("INTERFACE=%s", invNetworkIntf));
478 elog<InternalFailure>();
479 }
480
Alvin Wang38a63c32019-08-29 22:56:46 +0800481 DbusObjectPath objPath;
482 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530483
Alvin Wang38a63c32019-08-29 22:56:46 +0800484 if (1 == objectTree.size())
485 {
486 objPath = objectTree.begin()->first;
487 service = objectTree.begin()->second.begin()->first;
488 }
489 else
490 {
491 // If there are more than 2 objects, object path must contain the
492 // interface name
493 for (auto const& object : objectTree)
494 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530495 log<level::INFO>("interface",
496 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800497 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530498
499 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800500 {
501 objPath = object.first;
502 service = object.second.begin()->first;
503 break;
504 }
505 }
506
507 if (objPath.empty())
508 {
509 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530510 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800511 elog<InternalFailure>();
512 }
513 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530514
Gunnar Mills57d9c502018-09-14 14:42:34 -0500515 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
516 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530517
518 method.append(invNetworkIntf, "MACAddress");
519
520 auto reply = bus.call(method);
521 if (reply.is_method_error())
522 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500523 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530524 entry("PATH=%s", objPath.c_str()),
525 entry("INTERFACE=%s", invNetworkIntf));
526 elog<InternalFailure>();
527 }
528
William A. Kennington III1137a972019-04-20 20:49:58 -0700529 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530530 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700531 return fromString(std::get<std::string>(value));
532}
533
William A. Kennington III69f45542022-09-24 23:28:14 -0700534ether_addr fromString(stdplus::zstring_view str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700535{
William A. Kennington III1c776022022-01-05 14:12:16 -0800536 std::string genstr;
Potin Laida0b1d42021-12-26 20:08:20 +0800537
538 // MAC address without colons
William A. Kennington III69f45542022-09-24 23:28:14 -0700539 if (str.size() == 12 && str.find(":") == str.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700540 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800541 genstr =
William A. Kennington III69f45542022-09-24 23:28:14 -0700542 fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), str.substr(0, 2),
543 str.substr(2, 2), str.substr(4, 2), str.substr(6, 2),
544 str.substr(8, 2), str.substr(10, 2));
545 str = genstr;
William A. Kennington III1137a972019-04-20 20:49:58 -0700546 }
Potin Laida0b1d42021-12-26 20:08:20 +0800547
William A. Kennington III1c776022022-01-05 14:12:16 -0800548 ether_addr addr;
William A. Kennington III69f45542022-09-24 23:28:14 -0700549 if (ether_aton_r(str.c_str(), &addr) == nullptr)
Potin Laida0b1d42021-12-26 20:08:20 +0800550 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800551 throw std::invalid_argument("Invalid MAC Address");
Potin Laida0b1d42021-12-26 20:08:20 +0800552 }
William A. Kennington III1c776022022-01-05 14:12:16 -0800553 return addr;
Ratan Guptabd303b12017-08-18 17:10:07 +0530554}
555
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700556std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800557{
William A. Kennington III69f45542022-09-24 23:28:14 -0700558 return fmt::format(FMT_COMPILE("{:02x}"),
559 fmt::join(mac.ether_addr_octet, ":"));
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800560}
561
William A. Kennington III1137a972019-04-20 20:49:58 -0700562bool isEmpty(const ether_addr& mac)
563{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700564 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700565}
566
567bool isMulticast(const ether_addr& mac)
568{
569 return mac.ether_addr_octet[0] & 0b1;
570}
571
572bool isUnicast(const ether_addr& mac)
573{
574 return !isEmpty(mac) && !isMulticast(mac);
575}
576
Gunnar Mills57d9c502018-09-14 14:42:34 -0500577} // namespace mac_address
578} // namespace network
579} // namespace phosphor