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 <johnathanx.mantey@intel.com>
diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
index 2375482..f293ef5 100644
--- a/ethernet_interface.cpp
+++ b/ethernet_interface.cpp
@@ -37,6 +37,28 @@
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
using Argument = xyz::openbmc_project::Common::InvalidArgument;
+struct EthernetIntfSocket
+{
+ EthernetIntfSocket(int domain, int type, int protocol)
+ {
+ if ((sock = socket(domain, type, protocol)) < 0)
+ {
+ log<level::ERR>("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,
bool dhcpEnabled, Manager& parent,
@@ -56,6 +78,7 @@
EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
+ EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo));
// Emit deferred signal.
if (emitSignal)
@@ -227,43 +250,33 @@
InterfaceInfo EthernetInterface::getInterfaceInfo() const
{
- int sock{-1};
ifreq ifr{0};
ethtool_cmd edata{0};
LinkSpeed speed{0};
Autoneg autoneg{0};
DuplexMode duplex{0};
- do
+ LinkUp linkState{false};
+ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (eifSocket.sock < 0)
{
- sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
- if (sock < 0)
- {
- log<level::ERR>("socket creation failed:",
- entry("ERROR=%s", strerror(errno)));
- break;
- }
+ return std::make_tuple(speed, duplex, autoneg, linkState);
+ }
- strcpy(ifr.ifr_name, interfaceName().c_str());
- ifr.ifr_data = reinterpret_cast<char*>(&edata);
+ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
+ ifr.ifr_data = reinterpret_cast<char*>(&edata);
- edata.cmd = ETHTOOL_GSET;
-
- if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
- {
- log<level::ERR>("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);
}
/** @brief get the mac address of the interface.
@@ -273,17 +286,17 @@
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<level::ERR>("socket creation failed:",
- entry("ERROR=%s", strerror(errno)));
- elog<InternalFailure>();
+ 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<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
entry("ERROR=%s", strerror(errno)));
@@ -446,6 +459,31 @@
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<bool>(ifr.ifr_flags & IFF_RUNNING);
+ }
+ else
+ {
+ log<level::ERR>("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 60c56e3..68668d6 100644
--- a/ethernet_interface.hpp
+++ b/ethernet_interface.hpp
@@ -50,9 +50,10 @@
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<LinkSpeed, DuplexMode, Autoneg>;
+using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg, LinkUp>;
using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>;
using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>;
using VlanInterfaceMap =
@@ -150,6 +151,9 @@
/** Set value of DHCPEnabled */
bool dHCPEnabled(bool value) override;
+ /** 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.
@@ -197,6 +201,7 @@
using EthernetInterfaceIntf::dHCPEnabled;
using EthernetInterfaceIntf::interfaceName;
+ using EthernetInterfaceIntf::linkUp;
using MacAddressIntf::mACAddress;
/** @brief Absolute path of the resolv conf file */