| #include "system_queries.hpp" | 
 |  | 
 | #include "netlink.hpp" | 
 |  | 
 | #include <fmt/format.h> | 
 | #include <linux/ethtool.h> | 
 | #include <linux/rtnetlink.h> | 
 | #include <linux/sockios.h> | 
 | #include <net/if.h> | 
 |  | 
 | #include <phosphor-logging/lg2.hpp> | 
 | #include <stdplus/fd/create.hpp> | 
 | #include <stdplus/util/cexec.hpp> | 
 |  | 
 | #include <algorithm> | 
 | #include <optional> | 
 | #include <stdexcept> | 
 | #include <string_view> | 
 |  | 
 | namespace phosphor::network::system | 
 | { | 
 |  | 
 | using std::literals::string_view_literals::operator""sv; | 
 |  | 
 | static stdplus::Fd& getIFSock() | 
 | { | 
 |     using namespace stdplus::fd; | 
 |     static auto fd = socket(SocketDomain::INet, SocketType::Datagram, | 
 |                             SocketProto::IP); | 
 |     return fd; | 
 | } | 
 |  | 
 | static ifreq makeIFReq(std::string_view ifname) | 
 | { | 
 |     ifreq ifr = {}; | 
 |     const auto copied = std::min<std::size_t>(ifname.size(), IFNAMSIZ - 1); | 
 |     std::copy_n(ifname.begin(), copied, ifr.ifr_name); | 
 |     return ifr; | 
 | } | 
 |  | 
 | static ifreq executeIFReq(std::string_view ifname, unsigned long cmd, | 
 |                           void* data = nullptr) | 
 | { | 
 |     ifreq ifr = makeIFReq(ifname); | 
 |     ifr.ifr_data = reinterpret_cast<char*>(data); | 
 |     getIFSock().ioctl(cmd, &ifr); | 
 |     return ifr; | 
 | } | 
 |  | 
 | inline auto optionalIFReq(stdplus::zstring_view ifname, unsigned long long cmd, | 
 |                           std::string_view cmdname, auto&& complete, | 
 |                           void* data = nullptr) | 
 | { | 
 |     ifreq ifr; | 
 |     std::optional<decltype(complete(ifr))> ret; | 
 |     auto ukey = std::make_tuple(std::string(ifname), cmd); | 
 |     static std::unordered_set<std::tuple<std::string, unsigned long long>> | 
 |         unsupported; | 
 |     try | 
 |     { | 
 |         ifr = executeIFReq(ifname, cmd, data); | 
 |     } | 
 |     catch (const std::system_error& e) | 
 |     { | 
 |         if (e.code() == std::errc::operation_not_supported) | 
 |         { | 
 |             if (unsupported.find(ukey) == unsupported.end()) | 
 |             { | 
 |                 unsupported.emplace(std::move(ukey)); | 
 |                 lg2::info("{NET_IFREQ} not supported on {NET_INTF}", | 
 |                           "NET_IFREQ", cmdname, "NET_INTF", ifname); | 
 |             } | 
 |             return ret; | 
 |         } | 
 |         throw; | 
 |     } | 
 |     unsupported.erase(ukey); | 
 |     ret.emplace(complete(ifr)); | 
 |     return ret; | 
 | } | 
 |  | 
 | EthInfo getEthInfo(stdplus::zstring_view ifname) | 
 | { | 
 |     ethtool_cmd edata = {}; | 
 |     edata.cmd = ETHTOOL_GSET; | 
 |     return optionalIFReq( | 
 |                ifname, SIOCETHTOOL, "ETHTOOL"sv, | 
 |                [&](const ifreq&) { | 
 |         return EthInfo{.autoneg = edata.autoneg != 0, .speed = edata.speed}; | 
 |                }, | 
 |                &edata) | 
 |         .value_or(EthInfo{}); | 
 | } | 
 |  | 
 | void setMTU(std::string_view ifname, unsigned mtu) | 
 | { | 
 |     auto ifr = makeIFReq(ifname); | 
 |     ifr.ifr_mtu = mtu; | 
 |     getIFSock().ioctl(SIOCSIFMTU, &ifr); | 
 | } | 
 |  | 
 | void setNICUp(std::string_view ifname, bool up) | 
 | { | 
 |     ifreq ifr = executeIFReq(ifname, SIOCGIFFLAGS); | 
 |     ifr.ifr_flags &= ~IFF_UP; | 
 |     ifr.ifr_flags |= up ? IFF_UP : 0; | 
 |     getIFSock().ioctl(SIOCSIFFLAGS, &ifr); | 
 | } | 
 |  | 
 | void deleteIntf(unsigned idx) | 
 | { | 
 |     if (idx == 0) | 
 |     { | 
 |         return; | 
 |     } | 
 |     ifinfomsg msg = {}; | 
 |     msg.ifi_family = AF_UNSPEC; | 
 |     msg.ifi_index = idx; | 
 |     netlink::performRequest(NETLINK_ROUTE, RTM_DELLINK, NLM_F_REPLACE, msg, | 
 |                             [&](const nlmsghdr& hdr, std::string_view data) { | 
 |         int err = 0; | 
 |         if (hdr.nlmsg_type == NLMSG_ERROR) | 
 |         { | 
 |             err = netlink::extractRtData<nlmsgerr>(data).error; | 
 |         } | 
 |         throw std::runtime_error( | 
 |             fmt::format("Failed to delete `{}`: {}", idx, strerror(err))); | 
 |     }); | 
 | } | 
 |  | 
 | } // namespace phosphor::network::system |