blob: 54028aff47dfbee0dc1b080cda2db9541300763b [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 III7b9e8bd2019-04-23 19:31:31 -070017#include <cstdlib>
18#include <cstring>
Manojkiran Edaa879baa2020-06-13 14:39:08 +053019#include <filesystem>
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
Ratan Gupta8804feb2017-05-25 10:49:57 +053038using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053039using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Manojkiran Edaa879baa2020-06-13 14:39:08 +053040namespace fs = std::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053041
Lei YU3894ce72021-03-18 14:53:42 +080042namespace internal
43{
44
45void executeCommandinChildProcess(const char* path, char** args)
46{
47 using namespace std::string_literals;
48 pid_t pid = fork();
49 int status{};
50
51 if (pid == 0)
52 {
53 execv(path, args);
54 auto error = errno;
55 // create the command from var args.
56 std::string command = path + " "s;
57
58 for (int i = 0; args[i]; i++)
59 {
60 command += args[i] + " "s;
61 }
62
63 log<level::ERR>("Couldn't exceute the command",
64 entry("ERRNO=%d", error),
65 entry("CMD=%s", command.c_str()));
66 elog<InternalFailure>();
67 }
68 else if (pid < 0)
69 {
70 auto error = errno;
71 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
72 elog<InternalFailure>();
73 }
74 else if (pid > 0)
75 {
76 while (waitpid(pid, &status, 0) == -1)
77 {
78 if (errno != EINTR)
79 { // Error other than EINTR
80 status = -1;
81 break;
82 }
83 }
84
85 if (status < 0)
86 {
87 std::string command = path + " "s;
88 for (int i = 0; args[i]; i++)
89 {
90 command += args[i] + " "s;
91 }
92
93 log<level::ERR>("Unable to execute the command",
94 entry("CMD=%s", command.c_str()),
95 entry("STATUS=%d", status));
96 elog<InternalFailure>();
97 }
98 }
99}
100
Lei YU307554e2021-03-18 14:56:50 +0800101/** @brief Get ignored interfaces from environment */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700102std::string_view getIgnoredInterfacesEnv()
Lei YU307554e2021-03-18 14:56:50 +0800103{
104 auto r = std::getenv("IGNORED_INTERFACES");
105 if (r == nullptr)
106 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700107 return "";
Lei YU307554e2021-03-18 14:56:50 +0800108 }
109 return r;
110}
111
112/** @brief Parse the comma separated interface names */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700113std::set<std::string_view> parseInterfaces(std::string_view interfaces)
Lei YU307554e2021-03-18 14:56:50 +0800114{
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700115 std::set<std::string_view> result;
116 while (true)
Lei YU307554e2021-03-18 14:56:50 +0800117 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700118 auto sep = interfaces.find(',');
119 auto interface = interfaces.substr(0, sep);
120 while (!interface.empty() && std::isspace(interface.front()))
Lei YU307554e2021-03-18 14:56:50 +0800121 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700122 interface.remove_prefix(1);
Lei YU307554e2021-03-18 14:56:50 +0800123 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700124 while (!interface.empty() && std::isspace(interface.back()))
Lei YU307554e2021-03-18 14:56:50 +0800125 {
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700126 interface.remove_suffix(1);
Lei YU307554e2021-03-18 14:56:50 +0800127 }
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700128 if (!interface.empty())
129 {
130 result.insert(interface);
131 }
132 if (sep == interfaces.npos)
133 {
134 break;
135 }
136 interfaces = interfaces.substr(sep + 1);
Lei YU307554e2021-03-18 14:56:50 +0800137 }
138 return result;
139}
140
141/** @brief Get the ignored interfaces */
William A. Kennington IIIee5b2c92021-04-28 02:31:28 -0700142const std::set<std::string_view>& getIgnoredInterfaces()
Lei YU307554e2021-03-18 14:56:50 +0800143{
144 static auto ignoredInterfaces = parseInterfaces(getIgnoredInterfacesEnv());
145 return ignoredInterfaces;
146}
147
Lei YU3894ce72021-03-18 14:53:42 +0800148} // namespace internal
Ratan Gupta8804feb2017-05-25 10:49:57 +0530149
Ratan Gupta8804feb2017-05-25 10:49:57 +0530150std::string toMask(int addressFamily, uint8_t prefix)
151{
152 if (addressFamily == AF_INET6)
153 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500154 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530155 return "";
156 }
157
158 if (prefix < 1 || prefix > 30)
159 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500160 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530161 return "";
162 }
163 /* Create the netmask from the number of bits */
164 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500165 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530166 {
167 mask |= 1 << (31 - i);
168 }
169 struct in_addr netmask;
170 netmask.s_addr = htonl(mask);
171 return inet_ntoa(netmask);
172}
173
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800174InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
175{
176 if (addressFamily == AF_INET)
177 {
178 struct in_addr ret;
179 if (buf.size() != sizeof(ret))
180 {
181 throw std::runtime_error("Buf not in_addr sized");
182 }
183 memcpy(&ret, buf.data(), sizeof(ret));
184 return ret;
185 }
186 else if (addressFamily == AF_INET6)
187 {
188 struct in6_addr ret;
189 if (buf.size() != sizeof(ret))
190 {
191 throw std::runtime_error("Buf not in6_addr sized");
192 }
193 memcpy(&ret, buf.data(), sizeof(ret));
194 return ret;
195 }
196
197 throw std::runtime_error("Unsupported address family");
198}
199
Alexander Filippov983da552021-02-08 15:26:54 +0300200std::string toString(const struct in_addr& addr)
201{
202 std::string ip(INET_ADDRSTRLEN, '\0');
203 if (inet_ntop(AF_INET, &addr, ip.data(), ip.size()) == nullptr)
204 {
205 throw std::runtime_error("Failed to convert IP4 to string");
206 }
207
208 ip.resize(strlen(ip.c_str()));
209 return ip;
210}
211
212std::string toString(const struct in6_addr& addr)
213{
214 std::string ip(INET6_ADDRSTRLEN, '\0');
215 if (inet_ntop(AF_INET6, &addr, ip.data(), ip.size()) == nullptr)
216 {
217 throw std::runtime_error("Failed to convert IP6 to string");
218 }
219
220 ip.resize(strlen(ip.c_str()));
221 return ip;
222}
223
William A. Kennington III5058f572019-01-30 17:18:14 -0800224std::string toString(const InAddrAny& addr)
225{
William A. Kennington III5058f572019-01-30 17:18:14 -0800226 if (std::holds_alternative<struct in_addr>(addr))
227 {
228 const auto& v = std::get<struct in_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300229 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800230 }
231 else if (std::holds_alternative<struct in6_addr>(addr))
232 {
233 const auto& v = std::get<struct in6_addr>(addr);
Alexander Filippov983da552021-02-08 15:26:54 +0300234 return toString(v);
William A. Kennington III5058f572019-01-30 17:18:14 -0800235 }
Alexander Filippov983da552021-02-08 15:26:54 +0300236
237 throw std::runtime_error("Invalid addr type");
William A. Kennington III5058f572019-01-30 17:18:14 -0800238}
239
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500240bool isValidIP(int addressFamily, const std::string& address)
241{
242 unsigned char buf[sizeof(struct in6_addr)];
243
244 return inet_pton(addressFamily, address.c_str(), buf) > 0;
245}
246
247bool isValidPrefix(int addressFamily, uint8_t prefixLength)
248{
249 if (addressFamily == AF_INET)
250 {
251 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
252 prefixLength > IPV4_MAX_PREFIX_LENGTH)
253 {
254 return false;
255 }
256 }
257
258 if (addressFamily == AF_INET6)
259 {
260 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
261 prefixLength > IPV6_MAX_PREFIX_LENGTH)
262 {
263 return false;
264 }
265 }
266
267 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530268}
269
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530270InterfaceList getInterfaces()
271{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500272 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530273 struct ifaddrs* ifaddr = nullptr;
274
275 // attempt to fill struct with ifaddrs
276 if (getifaddrs(&ifaddr) == -1)
277 {
278 auto error = errno;
279 log<level::ERR>("Error occurred during the getifaddrs call",
280 entry("ERRNO=%d", error));
281 elog<InternalFailure>();
282 }
283
284 AddrPtr ifaddrPtr(ifaddr);
285 ifaddr = nullptr;
Lei YUefda98b2021-03-18 15:52:19 +0800286 const auto& ignoredInterfaces = internal::getIgnoredInterfaces();
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530287
288 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
289 {
290 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700291 // if loopback ignore
Lei YUefda98b2021-03-18 15:52:19 +0800292 if (ifa->ifa_flags & IFF_LOOPBACK ||
293 ignoredInterfaces.find(ifa->ifa_name) != ignoredInterfaces.end())
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530294 {
295 continue;
296 }
297 interfaces.emplace(ifa->ifa_name);
298 }
299 return interfaces;
300}
301
Ratan Guptabc886292017-07-25 18:29:57 +0530302void deleteInterface(const std::string& intf)
303{
304 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500305 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530306
307 if (pid == 0)
308 {
309
310 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
311 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500312 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530313 entry("INTF=%s", intf.c_str()));
314 elog<InternalFailure>();
315 }
316 else if (pid < 0)
317 {
318 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500319 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530320 elog<InternalFailure>();
321 }
322 else if (pid > 0)
323 {
324 while (waitpid(pid, &status, 0) == -1)
325 {
326 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500327 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530328 status = -1;
329 break;
330 }
331 }
332
Gunnar Mills57d9c502018-09-14 14:42:34 -0500333 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530334 {
335 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500336 entry("INTF=%s", intf.c_str()),
337 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530338 elog<InternalFailure>();
339 }
340 }
341}
342
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700343std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
344{
345 constexpr char ethPrefix[] = "eth";
346 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
347 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
348 {
349 return std::nullopt;
350 }
351 const auto intfSuffix = intf + ethPrefixLen;
352 if (intfSuffix[0] == '\0')
353 {
354 return std::nullopt;
355 }
356 char* end;
357 unsigned long idx = strtoul(intfSuffix, &end, 10);
358 if (end[0] != '\0')
359 {
360 return std::nullopt;
361 }
362 if (idx == 0)
363 {
364 return "ethaddr";
365 }
366 return "eth" + std::to_string(idx) + "addr";
367}
368
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700369bool getIPv6AcceptRA(const config::Parser& config)
Ratan Gupta56187e72017-08-13 09:40:14 +0530370{
William A. Kennington III324d2602022-08-18 18:32:56 -0700371#ifdef ENABLE_IPV6_ACCEPT_RA
372 constexpr bool def = true;
373#else
374 constexpr bool def = false;
375#endif
376
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700377 auto value = config.map.getLastValueString("Network", "IPv6AcceptRA");
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700378 if (value == nullptr)
Ratan Gupta56187e72017-08-13 09:40:14 +0530379 {
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700380 auto msg = fmt::format(
381 "Unable to get the value for Network[IPv6AcceptRA] from {}",
382 config.getFilename().native());
383 log<level::NOTICE>(msg.c_str(),
384 entry("FILE=%s", config.getFilename().c_str()));
William A. Kennington III324d2602022-08-18 18:32:56 -0700385 return def;
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700386 }
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700387 auto ret = config::parseBool(*value);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700388 if (!ret.has_value())
389 {
390 auto msg = fmt::format(
391 "Failed to parse section Network[IPv6AcceptRA] from {}: `{}`",
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700392 config.getFilename().native(), *value);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700393 log<level::NOTICE>(msg.c_str(),
394 entry("FILE=%s", config.getFilename().c_str()),
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700395 entry("VALUE=%s", value->c_str()));
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700396 }
William A. Kennington III324d2602022-08-18 18:32:56 -0700397 return ret.value_or(def);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700398}
399
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700400DHCPVal getDHCPValue(const config::Parser& config)
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700401{
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700402 constexpr auto def = DHCPVal{.v4 = true, .v6 = true};
William A. Kennington III324d2602022-08-18 18:32:56 -0700403
William A. Kennington III34bb3e22022-08-18 15:17:22 -0700404 const auto value = config.map.getLastValueString("Network", "DHCP");
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700405 if (value == nullptr)
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700406 {
407 auto msg =
408 fmt::format("Unable to get the value for Network[DHCP] from {}",
409 config.getFilename().native());
410 log<level::NOTICE>(msg.c_str(),
411 entry("FILE=%s", config.getFilename().c_str()));
William A. Kennington III324d2602022-08-18 18:32:56 -0700412 return def;
Ratan Gupta56187e72017-08-13 09:40:14 +0530413 }
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700414 if (config::icaseeq(*value, "ipv4"))
Ratan Gupta56187e72017-08-13 09:40:14 +0530415 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700416 return DHCPVal{.v4 = true, .v6 = false};
Johnathan Mantey817012a2020-01-30 15:07:39 -0800417 }
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700418 if (config::icaseeq(*value, "ipv6"))
Johnathan Mantey817012a2020-01-30 15:07:39 -0800419 {
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700420 return DHCPVal{.v4 = false, .v6 = true};
Johnathan Mantey817012a2020-01-30 15:07:39 -0800421 }
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700422 auto ret = config::parseBool(*value);
William A. Kennington III150753f2022-08-05 15:20:54 -0700423 if (!ret.has_value())
Johnathan Mantey817012a2020-01-30 15:07:39 -0800424 {
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700425 auto str = fmt::format("Unable to parse Network[DHCP] from {}: `{}`",
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700426 config.getFilename().native(), *value);
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700427 log<level::NOTICE>(str.c_str(),
428 entry("FILE=%s", config.getFilename().c_str()),
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700429 entry("VALUE=%s", value->c_str()));
William A. Kennington III324d2602022-08-18 18:32:56 -0700430 return def;
Ratan Gupta56187e72017-08-13 09:40:14 +0530431 }
William A. Kennington III8060c0d2022-08-18 19:19:34 -0700432 return *ret ? DHCPVal{.v4 = true, .v6 = true}
433 : DHCPVal{.v4 = false, .v6 = false};
Ratan Gupta56187e72017-08-13 09:40:14 +0530434}
435
Ratan Guptabd303b12017-08-18 17:10:07 +0530436namespace mac_address
437{
438
439constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
440constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
441constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
442constexpr auto propIntf = "org.freedesktop.DBus.Properties";
443constexpr auto methodGet = "Get";
Manojkiran Edacc099a82020-05-11 14:25:16 +0530444constexpr auto configFile = "/usr/share/network/config.json";
Ratan Guptabd303b12017-08-18 17:10:07 +0530445
446using DbusObjectPath = std::string;
447using DbusService = std::string;
448using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500449using ObjectTree =
450 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530451
452constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
453constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500454 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530455constexpr auto invRoot = "/xyz/openbmc_project/inventory";
456
Patrick Williamsc38b0712022-07-22 19:26:54 -0500457ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530458{
Manojkiran Edacc099a82020-05-11 14:25:16 +0530459
460 std::string interfaceName = intfName;
461
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700462#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530463 // load the config JSON from the Read Only Path
464 std::ifstream in(configFile);
465 nlohmann::json configJson;
466 in >> configJson;
467 interfaceName = configJson[intfName];
468#endif
469
Ratan Guptabd303b12017-08-18 17:10:07 +0530470 std::vector<DbusInterface> interfaces;
471 interfaces.emplace_back(invNetworkIntf);
472
473 auto depth = 0;
474
Gunnar Mills57d9c502018-09-14 14:42:34 -0500475 auto mapperCall =
476 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530477
478 mapperCall.append(invRoot, depth, interfaces);
479
480 auto mapperReply = bus.call(mapperCall);
481 if (mapperReply.is_method_error())
482 {
483 log<level::ERR>("Error in mapper call");
484 elog<InternalFailure>();
485 }
486
487 ObjectTree objectTree;
488 mapperReply.read(objectTree);
489
490 if (objectTree.empty())
491 {
492 log<level::ERR>("No Object has implemented the interface",
493 entry("INTERFACE=%s", invNetworkIntf));
494 elog<InternalFailure>();
495 }
496
Alvin Wang38a63c32019-08-29 22:56:46 +0800497 DbusObjectPath objPath;
498 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530499
Alvin Wang38a63c32019-08-29 22:56:46 +0800500 if (1 == objectTree.size())
501 {
502 objPath = objectTree.begin()->first;
503 service = objectTree.begin()->second.begin()->first;
504 }
505 else
506 {
507 // If there are more than 2 objects, object path must contain the
508 // interface name
509 for (auto const& object : objectTree)
510 {
Manojkiran Edacc099a82020-05-11 14:25:16 +0530511 log<level::INFO>("interface",
512 entry("INT=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800513 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
Manojkiran Edacc099a82020-05-11 14:25:16 +0530514
515 if (std::string::npos != object.first.find(interfaceName.c_str()))
Alvin Wang38a63c32019-08-29 22:56:46 +0800516 {
517 objPath = object.first;
518 service = object.second.begin()->first;
519 break;
520 }
521 }
522
523 if (objPath.empty())
524 {
525 log<level::ERR>("Can't find the object for the interface",
Manojkiran Edacc099a82020-05-11 14:25:16 +0530526 entry("intfName=%s", interfaceName.c_str()));
Alvin Wang38a63c32019-08-29 22:56:46 +0800527 elog<InternalFailure>();
528 }
529 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530530
Gunnar Mills57d9c502018-09-14 14:42:34 -0500531 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
532 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530533
534 method.append(invNetworkIntf, "MACAddress");
535
536 auto reply = bus.call(method);
537 if (reply.is_method_error())
538 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500539 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530540 entry("PATH=%s", objPath.c_str()),
541 entry("INTERFACE=%s", invNetworkIntf));
542 elog<InternalFailure>();
543 }
544
William A. Kennington III1137a972019-04-20 20:49:58 -0700545 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530546 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700547 return fromString(std::get<std::string>(value));
548}
549
William A. Kennington III1c776022022-01-05 14:12:16 -0800550ether_addr fromString(const char* str)
William A. Kennington III1137a972019-04-20 20:49:58 -0700551{
William A. Kennington III1c776022022-01-05 14:12:16 -0800552 std::string genstr;
Potin Laida0b1d42021-12-26 20:08:20 +0800553
554 // MAC address without colons
William A. Kennington III1c776022022-01-05 14:12:16 -0800555 std::string_view strv = str;
556 if (strv.size() == 12 && strv.find(":") == strv.npos)
William A. Kennington III1137a972019-04-20 20:49:58 -0700557 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800558 genstr =
559 fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), strv.substr(0, 2),
560 strv.substr(2, 2), strv.substr(4, 2), strv.substr(6, 2),
561 strv.substr(8, 2), strv.substr(10, 2));
562 str = genstr.c_str();
William A. Kennington III1137a972019-04-20 20:49:58 -0700563 }
Potin Laida0b1d42021-12-26 20:08:20 +0800564
William A. Kennington III1c776022022-01-05 14:12:16 -0800565 ether_addr addr;
566 if (ether_aton_r(str, &addr) == nullptr)
Potin Laida0b1d42021-12-26 20:08:20 +0800567 {
William A. Kennington III1c776022022-01-05 14:12:16 -0800568 throw std::invalid_argument("Invalid MAC Address");
Potin Laida0b1d42021-12-26 20:08:20 +0800569 }
William A. Kennington III1c776022022-01-05 14:12:16 -0800570 return addr;
Ratan Guptabd303b12017-08-18 17:10:07 +0530571}
572
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700573std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800574{
Karthick Sundarrajandbd328d2019-11-20 15:19:08 -0800575 char buf[18] = {0};
576 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac.ether_addr_octet[0],
577 mac.ether_addr_octet[1], mac.ether_addr_octet[2],
578 mac.ether_addr_octet[3], mac.ether_addr_octet[4],
579 mac.ether_addr_octet[5]);
580 return buf;
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800581}
582
William A. Kennington III1137a972019-04-20 20:49:58 -0700583bool isEmpty(const ether_addr& mac)
584{
William A. Kennington III12beaad2020-06-13 19:30:41 -0700585 return stdplus::raw::equal(mac, ether_addr{});
William A. Kennington III1137a972019-04-20 20:49:58 -0700586}
587
588bool isMulticast(const ether_addr& mac)
589{
590 return mac.ether_addr_octet[0] & 0b1;
591}
592
593bool isUnicast(const ether_addr& mac)
594{
595 return !isEmpty(mac) && !isMulticast(mac);
596}
597
Gunnar Mills57d9c502018-09-14 14:42:34 -0500598} // namespace mac_address
599} // namespace network
600} // namespace phosphor