From 7e99cfbb5cdbf47cd0350d869be236c88f982fd3 Mon Sep 17 00:00:00 2001 From: Johnathan Mantey Date: Wed, 8 Jan 2020 10:38:58 -0800 Subject: [PATCH] Enable the network link carrier state to be reported. This change allows networkd to keep track of, and report, the state of the network carrier signal. When a NIC cable is pulled, or inserted, a DBus client is able identify the condition. Tested: ip link set down dev eth0 # take eth0 down Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = LinkDown # InterfaceEnabled = false ip link set up dev eth0 # bring eth0 back Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = Linkup # InterfaceEnabled = true Pull eth0 cable Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = LinkDown # InterfaceEnabled = true Insert eth0 cable Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = Linkup # InterfaceEnabled = true Change-Id: I5530cf7882cfbfdba1436dd34b3219c735047c5e Signed-off-by: Johnathan Mantey --- ethernet_interface.cpp | 104 ++++++++++++++++++++++++++++------------- ethernet_interface.hpp | 7 ++- 2 files changed, 77 insertions(+), 34 deletions(-) diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp index ba6195e..8b8f698 100644 --- a/ethernet_interface.cpp +++ b/ethernet_interface.cpp @@ -42,6 +42,28 @@ static constexpr const char* defaultChannelPriv = "priv-admin"; std::map mapDHCPToSystemd = { {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}}; +struct EthernetIntfSocket +{ + EthernetIntfSocket(int domain, int type, int protocol) + { + if ((sock = socket(domain, type, protocol)) < 0) + { + log("socket creation failed:", + entry("ERROR=%s", strerror(errno))); + } + } + + ~EthernetIntfSocket() + { + if (sock >= 0) + { + close(sock); + } + } + + int sock{-1}; +}; + EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath, DHCPConf dhcpEnabled, Manager& parent, @@ -62,6 +84,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); + EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo)); #endif getChannelPrivilege(intfName); @@ -294,43 +317,33 @@ ObjectPath EthernetInterface::neighbor(std::string iPAddress, */ InterfaceInfo EthernetInterface::getInterfaceInfo() const { - int sock{-1}; ifreq ifr{0}; ethtool_cmd edata{0}; LinkSpeed speed{0}; Autoneg autoneg{0}; DuplexMode duplex{0}; - do - { - sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - if (sock < 0) - { - log("socket creation failed:", - entry("ERROR=%s", strerror(errno))); - break; - } + LinkUp linkState{false}; + EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - strcpy(ifr.ifr_name, interfaceName().c_str()); - ifr.ifr_data = reinterpret_cast(&edata); + if (eifSocket.sock < 0) + { + return std::make_tuple(speed, duplex, autoneg, linkState); + } - edata.cmd = ETHTOOL_GSET; + std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1); + ifr.ifr_data = reinterpret_cast(&edata); - if (ioctl(sock, SIOCETHTOOL, &ifr) < 0) - { - log("ioctl failed for SIOCETHTOOL:", - entry("ERROR=%s", strerror(errno))); - break; - } + edata.cmd = ETHTOOL_GSET; + if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0) + { speed = edata.speed; duplex = edata.duplex; autoneg = edata.autoneg; - } while (0); - - if (sock) - { - close(sock); } - return std::make_tuple(speed, duplex, autoneg); + + linkState = linkUp(); + + return std::make_tuple(speed, duplex, autoneg, linkState); } #endif @@ -341,17 +354,17 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const std::string EthernetInterface::getMACAddress(const std::string& interfaceName) const { - ifreq ifr{}; - int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - if (sock < 0) + std::string activeMACAddr = MacAddressIntf::mACAddress(); + EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + + if (eifSocket.sock < 0) { - log("socket creation failed:", - entry("ERROR=%s", strerror(errno))); - elog(); + return activeMACAddr; } - std::strcpy(ifr.ifr_name, interfaceName.c_str()); - if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) + ifreq ifr{0}; + std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1); + if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0) { log("ioctl failed for SIOCGIFHWADDR:", entry("ERROR=%s", strerror(errno))); @@ -514,6 +527,31 @@ EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) return value; } +bool EthernetInterface::linkUp() const +{ + EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + bool value = EthernetInterfaceIntf::linkUp(); + + if (eifSocket.sock < 0) + { + return value; + } + + ifreq ifr{0}; + std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1); + if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0) + { + value = static_cast(ifr.ifr_flags & IFF_RUNNING); + } + else + { + log("ioctl failed for SIOCGIFFLAGS:", + entry("ERROR=%s", strerror(errno))); + } + + return value; +} + ServerList EthernetInterface::nameservers(ServerList value) { for (const auto& nameserverip : value) diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp index a962751..4e36ae8 100644 --- a/ethernet_interface.hpp +++ b/ethernet_interface.hpp @@ -59,9 +59,10 @@ class Neighbor; using LinkSpeed = uint16_t; using DuplexMode = uint8_t; using Autoneg = uint8_t; +using LinkUp = bool; using VlanId = uint32_t; using InterfaceName = std::string; -using InterfaceInfo = std::tuple; +using InterfaceInfo = std::tuple; using AddressMap = std::map>; using NeighborMap = std::map>; using VlanInterfaceMap = @@ -186,6 +187,9 @@ class EthernetInterface : public Ifaces */ void disableDHCP(IP::Protocol protocol); + /** Retrieve Link State */ + bool linkUp() const override; + /** @brief sets the MAC address. * @param[in] value - MAC address which needs to be set on the system. * @returns macAddress of the interface or throws an error. @@ -241,6 +245,7 @@ class EthernetInterface : public Ifaces using ChannelAccessIntf::maxPrivilege; using EthernetInterfaceIntf::dHCPEnabled; using EthernetInterfaceIntf::interfaceName; + using EthernetInterfaceIntf::linkUp; using MacAddressIntf::mACAddress; /** @brief Absolute path of the resolv conf file */ -- 2.24.1