From 6c1caca70063aa707ba809a6b4695d0f0c5646f1 Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Thu, 27 Feb 2020 15:57:13 -0800 Subject: Update to internal 2020-02-27 Signed-off-by: Jason M. Bills --- ...HCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch | 657 --------------------- ...HCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch | 504 ++++++++++++++++ ...itional-use-of-ETHTOOL-features-in-the-NI.patch | 120 ++++ ...e-disable-control-of-the-Network-Interfac.patch | 191 ++++++ ...HCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch | 504 ++++++++++++++++ ...network-link-carrier-state-to-be-reported.patch | 282 +++++++++ .../network/phosphor-network_%.bbappend | 9 +- 7 files changed, 1608 insertions(+), 659 deletions(-) delete mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0001-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch (limited to 'meta-openbmc-mods/meta-common/recipes-network/network') diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0001-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0001-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch deleted file mode 100644 index 41541500f..000000000 --- a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0001-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch +++ /dev/null @@ -1,657 +0,0 @@ -From c7050f4a1f87d49e8a619d5d8752d1c98bfed3e8 Mon Sep 17 00:00:00 2001 -From: Johnathan Mantey -Date: Wed, 3 Jul 2019 14:12:49 -0700 -Subject: [PATCH] Enhance DHCP beyond just OFF and IPv4/IPv6 enabled. - -DHCP is not a binary option. The network interface can have DHCP -disabled, IPv4 only, IPv6 only, and IPv4/IPv6. - -Tested: -Using dbus-send or busctl: -Disabled DHCP, and confirmed only link local addresses were present. - -Assigned only static addresses. Both with/and without the gateway set -to 0.0.0.0 - -Deleted static IPv4 addresses. -Reassigned static addresses. - -Enabled DHCP for ipv4 only, and witnessed a DHCP server assign a valid -address. It also correctly managed the routing table. - -Assigned static IPv4 address. -Assigned static IPv6 address. -Confirmed both IPv4 and IPv6 static addresses are active. - -Enabled DHCP for ipv6 only, and confirmed the static v4 address -remains. The ipv6 address is removed, waiting for a DHCP6 server. - -Enabled DHCP for both ipv4 and ipv6. IPv4 address was assigned. IPv6 -address is assumed to succeed, as systemd config file enables IPv6 -DHCP. - -Change-Id: I2e0ff80ac3a5e88bcff28adac419bf21e37be162 -Signed-off-by: Johnathan Mantey ---- - Makefile.am | 5 + - configure.ac | 1 + - ethernet_interface.cpp | 170 ++++++++++++++++++++++--------- - ethernet_interface.hpp | 31 +++++- - ipaddress.cpp | 2 +- - network_manager.cpp | 2 +- - test/test_ethernet_interface.cpp | 3 +- - test/test_vlan_interface.cpp | 3 +- - types.hpp | 3 + - util.cpp | 69 ++++++++++++- - util.hpp | 13 ++- - vlan_interface.cpp | 2 +- - vlan_interface.hpp | 4 +- - 13 files changed, 246 insertions(+), 62 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 79db184..2768e38 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -97,6 +97,11 @@ phosphor_network_manager_CXXFLAGS = \ - $(SDEVENTPLUS_CFLAGS) \ - $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ - $(PHOSPHOR_LOGGING_CFLAGS) \ -+ -DBOOST_ERROR_CODE_HEADER_ONLY \ -+ -DBOOST_SYSTEM_NO_DEPRECATED \ -+ -DBOOST_COROUTINES_NO_DEPRECATION_WARNING \ -+ -DBOOST_ASIO_DISABLE_THREADS \ -+ -DBOOST_ALL_NO_LIB \ - -flto - - xyz/openbmc_project/Network/VLAN/Create/server.cpp: xyz/openbmc_project/Network/VLAN/Create.interface.yaml xyz/openbmc_project/Network/VLAN/Create/server.hpp -diff --git a/configure.ac b/configure.ac -index 8870fcd..00b23bc 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -36,6 +36,7 @@ AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++]) - PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging]) - PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces]) - PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0]) -+AC_CHECK_HEADER(boost/algorithm/string/split.hpp, [], [AC_MSG_ERROR([Could not find boost/algorithm/string/split.hpp])]) - - # Checks for header files. - AC_CHECK_HEADER(systemd/sd-bus.h, ,\ -diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp -index c3edd4b..537054f 100644 ---- a/ethernet_interface.cpp -+++ b/ethernet_interface.cpp -@@ -3,9 +3,9 @@ - #include "ethernet_interface.hpp" - - #include "config_parser.hpp" --#include "ipaddress.hpp" - #include "neighbor.hpp" - #include "network_manager.hpp" -+#include "util.hpp" - #include "vlan_interface.hpp" - - #include -@@ -40,9 +40,12 @@ using Argument = xyz::openbmc_project::Common::InvalidArgument; - static constexpr const char* networkChannelCfgFile = - "/var/channel_intf_data.json"; - static constexpr const char* defaultChannelPriv = "priv-admin"; -+std::map mapDHCPToSystemd = { -+ {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}}; -+ - EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, - const std::string& objPath, -- bool dhcpEnabled, Manager& parent, -+ DHCPConf dhcpEnabled, Manager& parent, - bool emitSignal) : - Ifaces(bus, objPath.c_str(), true), - bus(bus), manager(parent), objPath(objPath) -@@ -81,24 +84,78 @@ static IP::Protocol convertFamily(int family) - throw std::invalid_argument("Bad address family"); - } - -+void EthernetInterface::disableDHCP(IP::Protocol protocol) -+{ -+ DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled(); -+ if (dhcpState == EthernetInterface::DHCPConf::both) -+ { -+ if (protocol == IP::Protocol::IPv4) -+ { -+ dHCPEnabled(EthernetInterface::DHCPConf::v6); -+ } -+ else if (protocol == IP::Protocol::IPv6) -+ { -+ dHCPEnabled(EthernetInterface::DHCPConf::v4); -+ } -+ } -+ else if ((dhcpState == EthernetInterface::DHCPConf::v4) && -+ (protocol == IP::Protocol::IPv4)) -+ { -+ dHCPEnabled(EthernetInterface::DHCPConf::none); -+ } -+ else if ((dhcpState == EthernetInterface::DHCPConf::v6) && -+ (protocol == IP::Protocol::IPv6)) -+ { -+ dHCPEnabled(EthernetInterface::DHCPConf::none); -+ } -+} -+ -+bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol) -+{ -+ return ((EthernetInterfaceIntf::dHCPEnabled() == -+ EthernetInterface::DHCPConf::both) || -+ ((EthernetInterfaceIntf::dHCPEnabled() == -+ EthernetInterface::DHCPConf::v6) && -+ ((family == IP::Protocol::IPv6) || ignoreProtocol)) || -+ ((EthernetInterfaceIntf::dHCPEnabled() == -+ EthernetInterface::DHCPConf::v4) && -+ ((family == IP::Protocol::IPv4) || ignoreProtocol))); -+} -+ -+bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family, -+ std::string& nextDHCPState) -+{ -+ return ((nextDHCPState == "true") || -+ ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) || -+ ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4))); -+} -+ -+bool EthernetInterface::addressIsStatic(IP::AddressOrigin origin) -+{ -+ return ( -+#ifdef LINK_LOCAL_AUTOCONFIGURATION -+ (origin == IP::AddressOrigin::Static) -+#else -+ (origin == IP::AddressOrigin::Static || -+ origin == IP::AddressOrigin::LinkLocal) -+#endif -+ -+ ); -+} -+ - void EthernetInterface::createIPAddressObjects() - { - addrs.clear(); - - auto addrs = getInterfaceAddrs()[interfaceName()]; -+ if (getIPAddrOrigins(addrs)) -+ { -+ return; -+ } - - for (auto& addr : addrs) - { - IP::Protocol addressType = convertFamily(addr.addrType); -- IP::AddressOrigin origin = IP::AddressOrigin::Static; -- if (dHCPEnabled()) -- { -- origin = IP::AddressOrigin::DHCP; -- } -- if (isLinkLocalIP(addr.ipaddress)) -- { -- origin = IP::AddressOrigin::LinkLocal; -- } - // Obsolete parameter - std::string gateway = ""; - -@@ -108,7 +165,7 @@ void EthernetInterface::createIPAddressObjects() - this->addrs.emplace(addr.ipaddress, - std::make_shared( - bus, ipAddressObjectPath.c_str(), *this, -- addressType, addr.ipaddress, origin, -+ addressType, addr.ipaddress, addr.origin, - addr.prefix, gateway)); - } - } -@@ -152,11 +209,11 @@ ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress, - uint8_t prefixLength, std::string gateway) - { - -- if (dHCPEnabled()) -+ if (dhcpIsEnabled(protType)) - { - log("DHCP enabled on the interface"), - entry("INTERFACE=%s", interfaceName().c_str()); -- dHCPEnabled(false); -+ disableDHCP(protType); - } - - IP::AddressOrigin origin = IP::AddressOrigin::Static; -@@ -438,7 +495,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value) - return value; - } - --bool EthernetInterface::dHCPEnabled(bool value) -+EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) - { - if (value == EthernetInterfaceIntf::dHCPEnabled()) - { -@@ -505,7 +562,7 @@ void EthernetInterface::loadVLAN(VlanId id) - std::string path = objPath; - path += "_" + std::to_string(id); - -- auto dhcpEnabled = -+ DHCPConf dhcpEnabled = - getDHCPValue(manager.getConfDir().string(), vlanInterfaceName); - - auto vlanIntf = std::make_unique( -@@ -527,7 +584,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id) - path += "_" + std::to_string(id); - - auto vlanIntf = std::make_unique( -- bus, path.c_str(), false, id, *this, manager); -+ bus, path.c_str(), EthernetInterface::DHCPConf::none, id, *this, -+ manager); - - // write the device file for the vlan interface. - vlanIntf->writeDeviceFile(); -@@ -600,8 +658,6 @@ void EthernetInterface::writeConfigurationFile() - // write all the static ip address in the systemd-network conf file - - using namespace std::string_literals; -- using AddressOrigin = -- sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin; - namespace fs = std::experimental::filesystem; - - // if there is vlan interafce then write the configuration file -@@ -670,41 +726,57 @@ void EthernetInterface::writeConfigurationFile() - } - - // Add the DHCP entry -- auto value = dHCPEnabled() ? "true"s : "false"s; -- stream << "DHCP="s + value + "\n"; -- -- // When the interface configured as dhcp, we don't need below given entries -- // in config file. -- if (dHCPEnabled() == false) -- { -- // Static -- for (const auto& addr : addrs) -+ std::string requestedDHCPState; -+ std::string::size_type loc; -+ std::string value = convertForMessage(EthernetInterfaceIntf::dHCPEnabled()); -+ loc = value.rfind("."); -+ requestedDHCPState = value.substr(loc + 1); -+ std::string mappedDHCPState = mapDHCPToSystemd[requestedDHCPState]; -+ stream << "DHCP="s + mappedDHCPState + "\n"; -+ -+ bool dhcpv6Requested = dhcpToBeEnabled(IP::Protocol::IPv6, mappedDHCPState); -+ bool dhcpv4Requested = dhcpToBeEnabled(IP::Protocol::IPv4, mappedDHCPState); -+ // Static IP addresses -+ for (const auto& addr : addrs) -+ { -+ bool isValidIPv4 = isValidIP(AF_INET, addr.second->address()); -+ bool isValidIPv6 = isValidIP(AF_INET6, addr.second->address()); -+ if (((!dhcpv4Requested && isValidIPv4) || -+ (!dhcpv6Requested && isValidIPv6)) && -+ addressIsStatic(addr.second->origin())) - { -- if (addr.second->origin() == AddressOrigin::Static --#ifndef LINK_LOCAL_AUTOCONFIGURATION -- || addr.second->origin() == AddressOrigin::LinkLocal --#endif -- ) -+ std::string address = addr.second->address() + "/" + -+ std::to_string(addr.second->prefixLength()); -+ -+ // build the address entries. Do not use [Network] shortcuts to -+ // insert address entries. -+ stream << "[Address]\n"; -+ stream << "Address=" << address << "\n"; -+ -+ // build the route section. Do not use [Network] shortcuts to apply -+ // default gateway values. -+ std::string gw = "0.0.0.0"; -+ if (addr.second->gateway() != "0.0.0.0" && -+ addr.second->gateway() != "") - { -- std::string address = -- addr.second->address() + "/" + -- std::to_string(addr.second->prefixLength()); -- -- stream << "Address=" << address << "\n"; -+ gw = addr.second->gateway(); - } -- } -- -- if (manager.getSystemConf()) -- { -- const auto& gateway = manager.getSystemConf()->defaultGateway(); -- if (!gateway.empty()) -+ else - { -- stream << "Gateway=" << gateway << "\n"; -+ if (isValidIPv4) -+ { -+ gw = manager.getSystemConf()->defaultGateway(); -+ } -+ else if (isValidIPv6) -+ { -+ gw = manager.getSystemConf()->defaultGateway6(); -+ } - } -- const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); -- if (!gateway6.empty()) -+ -+ if (!gw.empty()) - { -- stream << "Gateway=" << gateway6 << "\n"; -+ stream << "[Route]\n"; -+ stream << "Gateway=" << gw << "\n"; - } - } - } -@@ -816,7 +888,7 @@ std::string EthernetInterface::mACAddress(std::string value) - - void EthernetInterface::deleteAll() - { -- if (EthernetInterfaceIntf::dHCPEnabled()) -+ if (dhcpIsEnabled(IP::Protocol::IPv4, true)) - { - log("DHCP enabled on the interface"), - entry("INTERFACE=%s", interfaceName().c_str()); -diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp -index 3e4cf12..a962751 100644 ---- a/ethernet_interface.hpp -+++ b/ethernet_interface.hpp -@@ -91,7 +91,7 @@ class EthernetInterface : public Ifaces - * send. - */ - EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath, -- bool dhcpEnabled, Manager& parent, -+ DHCPConf dhcpEnabled, Manager& parent, - bool emitSignal = true); - - /** @brief Function to create ipaddress dbus object. -@@ -157,7 +157,34 @@ class EthernetInterface : public Ifaces - } - - /** Set value of DHCPEnabled */ -- bool dHCPEnabled(bool value) override; -+ DHCPConf dHCPEnabled(DHCPConf value) override; -+ -+ /** @brief Determines if DHCP is active for the IP::Protocol supplied. -+ * @param[in] protocol - Either IPv4 or IPv6 -+ * @param[in] ignoreProtocol - Allows IPv4 and IPv6 to be checked using a -+ * single call. -+ * @returns true/false value if DHCP is active for the input protocol -+ */ -+ bool dhcpIsEnabled(IP::Protocol protocol, bool ignoreProtocol = false); -+ -+ /** @brief Determines if DHCP will be active following next reconfig -+ * @param[in] protocol - Either IPv4 or IPv6 -+ * @param[in] nextDHCPState - The new DHCP mode to take affect -+ * @returns true/false value if DHCP is active for the input protocol -+ */ -+ bool dhcpToBeEnabled(IP::Protocol family, std::string& nextDHCPState); -+ -+ /** @brief Determines if the address is manually assigned -+ * @param[in] origin - The origin entry of the IP::Address -+ * @returns true/false value if the address is static -+ */ -+ bool addressIsStatic(IP::AddressOrigin origin); -+ -+ /** @brief Selectively disables DHCP -+ * @param[in] protocol - The IPv4 or IPv6 protocol to return to static -+ * addressing mode -+ */ -+ void disableDHCP(IP::Protocol protocol); - - /** @brief sets the MAC address. - * @param[in] value - MAC address which needs to be set on the system. -diff --git a/ipaddress.cpp b/ipaddress.cpp -index 10a22b2..5b2bf56 100644 ---- a/ipaddress.cpp -+++ b/ipaddress.cpp -@@ -57,7 +57,7 @@ IP::AddressOrigin IPAddress::origin(IP::AddressOrigin origin) - } - void IPAddress::delete_() - { -- if (origin() != IP::AddressOrigin::Static) -+ if (parent.dhcpIsEnabled(type())) - { - log("Tried to delete a non-static address"), - entry("ADDRESS=%s", address().c_str()), -diff --git a/network_manager.cpp b/network_manager.cpp -index 75f4e5f..f7e8a75 100644 ---- a/network_manager.cpp -+++ b/network_manager.cpp -@@ -248,7 +248,7 @@ void Manager::createInterfaces() - // normal ethernet interface - objPath /= interface; - -- auto dhcp = getDHCPValue(confDir, interface); -+ EthernetInterfaceIntf::DHCPConf dhcp = getDHCPValue(confDir, interface); - - auto intf = std::make_shared( - bus, objPath.string(), dhcp, *this); -diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp -index 30dee8a..87fd68d 100644 ---- a/test/test_ethernet_interface.cpp -+++ b/test/test_ethernet_interface.cpp -@@ -58,7 +58,8 @@ class TestEthernetInterface : public testing::Test - { - mock_clear(); - mock_addIF("test0", 1, mac); -- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; -+ return {bus, "/xyz/openbmc_test/network/test0", -+ EthernetInterface::DHCPConf::none, manager}; - } - - int countIPObjects() -diff --git a/test/test_vlan_interface.cpp b/test/test_vlan_interface.cpp -index 1dffc7e..e49b43f 100644 ---- a/test/test_vlan_interface.cpp -+++ b/test/test_vlan_interface.cpp -@@ -50,7 +50,8 @@ class TestVlanInterface : public testing::Test - { - mock_clear(); - mock_addIF("test0", 1); -- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; -+ return {bus, "/xyz/openbmc_test/network/test0", -+ EthernetInterface::DHCPConf::none, manager}; - } - - void setConfDir() -diff --git a/types.hpp b/types.hpp -index 123067a..c4409fe 100644 ---- a/types.hpp -+++ b/types.hpp -@@ -1,5 +1,7 @@ - #pragma once - -+#include "ipaddress.hpp" -+ - #include - #include - #include -@@ -50,6 +52,7 @@ struct AddrInfo - { - uint8_t addrType; - std::string ipaddress; -+ IP::AddressOrigin origin; - uint16_t prefix; - }; - -diff --git a/util.cpp b/util.cpp -index afbc229..2e5b164 100644 ---- a/util.cpp -+++ b/util.cpp -@@ -6,12 +6,17 @@ - #include - #include - #include -+#include - #include - - #include -+#include -+#include -+#include - #include - #include - #include -+#include - #include - #include - #include -@@ -26,6 +31,54 @@ namespace phosphor - namespace network - { - -+int getIPAddrOrigins(AddrList& addressList) -+{ -+ boost::process::ipstream inputStream; -+ boost::process::child ipaddr("ip -o addr", -+ boost::process::std_out > inputStream); -+ std::string ipaddrLine; -+ -+ while (inputStream && std::getline(inputStream, ipaddrLine) && -+ !ipaddrLine.empty()) -+ { -+ std::vector addressElements; -+ std::vector addrPrefixVec; -+ -+ boost::split(addressElements, ipaddrLine, boost::is_any_of(" "), -+ boost::token_compress_on); -+ boost::split(addrPrefixVec, addressElements[3], boost::is_any_of("/"), -+ boost::token_compress_on); -+ std::string& nic = addressElements[1]; -+ std::string& ipClass = addressElements[2]; // inet | inet6 -+ std::string& address = addrPrefixVec[0]; -+ if (nic != "lo") -+ { -+ for (auto it = addressList.begin(); it != addressList.end(); it++) -+ { -+ if (it->ipaddress == address) -+ { -+ bool isIPv6 = (ipClass == "inet6"); -+ int globalStrIdx = isIPv6 ? 5 : 7; -+ if (addressElements[globalStrIdx] == "global") -+ { -+ it->origin = (addressElements[8] == "dynamic") -+ ? IP::AddressOrigin::DHCP -+ : IP::AddressOrigin::Static; -+ } -+ else if (addressElements[globalStrIdx] == "link") -+ { -+ it->origin = isIPv6 ? IP::AddressOrigin::SLAAC -+ : IP::AddressOrigin::LinkLocal; -+ } -+ break; -+ } -+ } -+ } -+ } -+ ipaddr.wait(); -+ return 0; -+} -+ - namespace - { - -@@ -410,9 +463,11 @@ std::optional interfaceToUbootEthAddr(const char* intf) - return "eth" + std::to_string(idx) + "addr"; - } - --bool getDHCPValue(const std::string& confDir, const std::string& intf) -+EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, -+ const std::string& intf) - { -- bool dhcp = false; -+ EthernetInterfaceIntf::DHCPConf dhcp = -+ EthernetInterfaceIntf::DHCPConf::none; - // Get the interface mode value from systemd conf - // using namespace std::string_literals; - fs::path confPath = confDir; -@@ -434,7 +489,15 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf) - // There will be only single value for DHCP key. - if (values[0] == "true") - { -- dhcp = true; -+ dhcp = EthernetInterfaceIntf::DHCPConf::both; -+ } -+ else if (values[0] == "ipv4") -+ { -+ dhcp = EthernetInterfaceIntf::DHCPConf::v4; -+ } -+ else if (values[0] == "ipv6") -+ { -+ dhcp = EthernetInterfaceIntf::DHCPConf::v6; - } - return dhcp; - } -diff --git a/util.hpp b/util.hpp -index 251aa0d..b3f7bba 100644 ---- a/util.hpp -+++ b/util.hpp -@@ -13,12 +13,16 @@ - #include - #include - #include -+#include - - namespace phosphor - { - namespace network - { - -+using EthernetInterfaceIntf = -+ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; -+ - constexpr auto IPV4_MIN_PREFIX_LENGTH = 1; - constexpr auto IPV4_MAX_PREFIX_LENGTH = 32; - constexpr auto IPV6_MAX_PREFIX_LENGTH = 64; -@@ -156,7 +160,8 @@ std::optional interfaceToUbootEthAddr(const char* intf); - * @param[in] confDir - Network configuration directory. - * @param[in] intf - Interface name. - */ --bool getDHCPValue(const std::string& confDir, const std::string& intf); -+EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, -+ const std::string& intf); - - namespace internal - { -@@ -183,6 +188,12 @@ void execute(const char* path, ArgTypes&&... tArgs) - internal::executeCommandinChildProcess(path, args); - } - -+/* @brief Retrieve the source (DHCP, Static, Local/Self assigned) for -+ * each IP address supplied -+ * @param[in] addressList - List of IP addresses active on one interface -+ */ -+int getIPAddrOrigins(AddrList& addressList); -+ - } // namespace network - - /** @brief Copies data from a buffer into a copyable type -diff --git a/vlan_interface.cpp b/vlan_interface.cpp -index 73de4e8..26282cb 100644 ---- a/vlan_interface.cpp -+++ b/vlan_interface.cpp -@@ -22,7 +22,7 @@ using namespace phosphor::logging; - using namespace sdbusplus::xyz::openbmc_project::Common::Error; - - VlanInterface::VlanInterface(sdbusplus::bus::bus& bus, -- const std::string& objPath, bool dhcpEnabled, -+ const std::string& objPath, DHCPConf dhcpEnabled, - uint32_t vlanID, EthernetInterface& intf, - Manager& parent) : - VlanIface(bus, objPath.c_str()), -diff --git a/vlan_interface.hpp b/vlan_interface.hpp -index a994d05..37ae7ee 100644 ---- a/vlan_interface.hpp -+++ b/vlan_interface.hpp -@@ -45,8 +45,8 @@ class VlanInterface : public VlanIface, - * @param[in] manager - network manager object. - */ - VlanInterface(sdbusplus::bus::bus& bus, const std::string& objPath, -- bool dhcpEnabled, uint32_t vlanID, EthernetInterface& intf, -- Manager& manager); -+ DHCPConf dhcpEnabled, uint32_t vlanID, -+ EthernetInterface& intf, Manager& manager); - - /** @brief Delete this d-bus object. - */ --- -2.21.0 - diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch new file mode 100644 index 000000000..b6cf8f77d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch @@ -0,0 +1,504 @@ +From 42f361622a9c029221c8a90f92104703166e48c2 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey +Date: Thu, 30 Jan 2020 15:07:39 -0800 +Subject: [PATCH] Enhance DHCP beyond just OFF and IPv4/IPv6 enabled. + +DHCP is not a binary option. The network interface can have DHCP +disabled, IPv4 only, IPv6 only, and IPv4/IPv6. + +Tested: +Using dbus-send or busctl: +Disabled DHCP, and confirmed only link local addresses were present. + +Assigned only static addresses. Both with/and without the gateway set +to 0.0.0.0 + +Deleted static IPv4 addresses. +Reassigned static addresses. + +Enabled DHCP for ipv4 only, and witnessed a DHCP server assign a valid +address. + +Assigned static IPv4 address. +Assigned static IPv6 address. +Confirmed both IPv4 and IPv6 static addresses are active. + +Enabled DHCP for ipv6 only, and confirmed the static v4 address +remains. The ipv6 address is removed, waiting for a DHCP6 server. + +Enabled DHCP for both ipv4 and ipv6. IPv4 address was assigned. IPv6 +address is assumed to succeed, as systemd config file enables IPv6 +DHCP. + +Change-Id: I2e0ff80ac3a5e88bcff28adac419bf21e37be162 +Signed-off-by: Johnathan Mantey +--- + Makefile.am | 1 + + configure.ac | 1 + + ethernet_interface.cpp | 147 ++++++++++++++++++++++--------- + ethernet_interface.hpp | 31 ++++++- + test/test_ethernet_interface.cpp | 3 +- + test/test_vlan_interface.cpp | 3 +- + types.hpp | 3 + + util.cpp | 16 +++- + util.hpp | 7 +- + vlan_interface.cpp | 2 +- + vlan_interface.hpp | 4 +- + 11 files changed, 165 insertions(+), 53 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 1c47747..ff252fc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -97,6 +97,7 @@ phosphor_network_manager_CXXFLAGS = \ + $(SDEVENTPLUS_CFLAGS) \ + $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ + $(PHOSPHOR_LOGGING_CFLAGS) \ ++ -DBOOST_ASIO_DISABLE_THREADS \ + -flto + if FEATURE_NIC_ETHTOOL + phosphor_network_manager_CXXFLAGS += -DNIC_SUPPORTS_ETHTOOL +diff --git a/configure.ac b/configure.ac +index 12d6caa..fed3e09 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -36,6 +36,7 @@ AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++]) + PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging]) + PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces]) + PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0]) ++AC_CHECK_HEADER(boost/algorithm/string/split.hpp, [], [AC_MSG_ERROR([Could not find boost/algorithm/string/split.hpp])]) + + # Checks for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,\ +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 73fd8fe..ba6195e 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -3,7 +3,6 @@ + #include "ethernet_interface.hpp" + + #include "config_parser.hpp" +-#include "ipaddress.hpp" + #include "neighbor.hpp" + #include "network_manager.hpp" + #include "vlan_interface.hpp" +@@ -40,9 +39,12 @@ using Argument = xyz::openbmc_project::Common::InvalidArgument; + static constexpr const char* networkChannelCfgFile = + "/var/channel_intf_data.json"; + static constexpr const char* defaultChannelPriv = "priv-admin"; ++std::map mapDHCPToSystemd = { ++ {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}}; ++ + EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal) : + Ifaces(bus, objPath.c_str(), true), + bus(bus), manager(parent), objPath(objPath) +@@ -83,6 +85,65 @@ static IP::Protocol convertFamily(int family) + throw std::invalid_argument("Bad address family"); + } + ++void EthernetInterface::disableDHCP(IP::Protocol protocol) ++{ ++ DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled(); ++ if (dhcpState == EthernetInterface::DHCPConf::both) ++ { ++ if (protocol == IP::Protocol::IPv4) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v6); ++ } ++ else if (protocol == IP::Protocol::IPv6) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v4); ++ } ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v4) && ++ (protocol == IP::Protocol::IPv4)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v6) && ++ (protocol == IP::Protocol::IPv6)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++} ++ ++bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol) ++{ ++ return ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::both) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v6) && ++ ((family == IP::Protocol::IPv6) || ignoreProtocol)) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v4) && ++ ((family == IP::Protocol::IPv4) || ignoreProtocol))); ++} ++ ++bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family, ++ std::string& nextDHCPState) ++{ ++ return ((nextDHCPState == "true") || ++ ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) || ++ ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4))); ++} ++ ++bool EthernetInterface::addressIsStatic(IP::AddressOrigin origin) ++{ ++ return ( ++#ifdef LINK_LOCAL_AUTOCONFIGURATION ++ (origin == IP::AddressOrigin::Static) ++#else ++ (origin == IP::AddressOrigin::Static || ++ origin == IP::AddressOrigin::LinkLocal) ++#endif ++ ++ ); ++} ++ + void EthernetInterface::createIPAddressObjects() + { + addrs.clear(); +@@ -93,7 +154,7 @@ void EthernetInterface::createIPAddressObjects() + { + IP::Protocol addressType = convertFamily(addr.addrType); + IP::AddressOrigin origin = IP::AddressOrigin::Static; +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(addressType)) + { + origin = IP::AddressOrigin::DHCP; + } +@@ -154,11 +215,11 @@ ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress, + uint8_t prefixLength, std::string gateway) + { + +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(protType)) + { + log("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +- dHCPEnabled(false); ++ disableDHCP(protType); + } + + IP::AddressOrigin origin = IP::AddressOrigin::Static; +@@ -441,7 +502,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value) + return value; + } + +-bool EthernetInterface::dHCPEnabled(bool value) ++EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) + { + if (value == EthernetInterfaceIntf::dHCPEnabled()) + { +@@ -508,7 +569,7 @@ void EthernetInterface::loadVLAN(VlanId id) + std::string path = objPath; + path += "_" + std::to_string(id); + +- auto dhcpEnabled = ++ DHCPConf dhcpEnabled = + getDHCPValue(manager.getConfDir().string(), vlanInterfaceName); + + auto vlanIntf = std::make_unique( +@@ -530,7 +591,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id) + path += "_" + std::to_string(id); + + auto vlanIntf = std::make_unique( +- bus, path.c_str(), false, id, *this, manager); ++ bus, path.c_str(), EthernetInterface::DHCPConf::none, id, *this, ++ manager); + + // write the device file for the vlan interface. + vlanIntf->writeDeviceFile(); +@@ -603,8 +665,6 @@ void EthernetInterface::writeConfigurationFile() + // write all the static ip address in the systemd-network conf file + + using namespace std::string_literals; +- using AddressOrigin = +- sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin; + namespace fs = std::experimental::filesystem; + + // if there is vlan interafce then write the configuration file +@@ -673,42 +733,45 @@ void EthernetInterface::writeConfigurationFile() + } + + // Add the DHCP entry +- auto value = dHCPEnabled() ? "true"s : "false"s; +- stream << "DHCP="s + value + "\n"; ++ std::string value = convertForMessage(EthernetInterfaceIntf::dHCPEnabled()); ++ std::string::size_type loc = value.rfind("."); ++ std::string requestedDHCPState = value.substr(loc + 1); ++ std::string mappedDHCPState = mapDHCPToSystemd[requestedDHCPState]; ++ stream << "DHCP="s + mappedDHCPState + "\n"; ++ ++ bool dhcpv6Requested = dhcpToBeEnabled(IP::Protocol::IPv6, mappedDHCPState); ++ bool dhcpv4Requested = dhcpToBeEnabled(IP::Protocol::IPv4, mappedDHCPState); ++ // Static IP addresses ++ for (const auto& addr : addrs) ++ { ++ bool isValidIPv4 = isValidIP(AF_INET, addr.second->address()); ++ bool isValidIPv6 = isValidIP(AF_INET6, addr.second->address()); ++ if (((!dhcpv4Requested && isValidIPv4) || ++ (!dhcpv6Requested && isValidIPv6)) && ++ addressIsStatic(addr.second->origin())) ++ { ++ // Process all static addresses ++ std::string address = addr.second->address() + "/" + ++ std::to_string(addr.second->prefixLength()); ++ ++ // build the address entries. Do not use [Network] shortcuts to ++ // insert address entries. ++ stream << "[Address]\n"; ++ stream << "Address=" << address << "\n"; ++ } ++ } + +- // When the interface configured as dhcp, we don't need below given entries +- // in config file. +- if (dHCPEnabled() == false) ++ if (manager.getSystemConf()) + { +- // Static +- for (const auto& addr : addrs) ++ const auto& gateway = manager.getSystemConf()->defaultGateway(); ++ if (!gateway.empty()) + { +- if (addr.second->origin() == AddressOrigin::Static +-#ifndef LINK_LOCAL_AUTOCONFIGURATION +- || addr.second->origin() == AddressOrigin::LinkLocal +-#endif +- ) +- { +- std::string address = +- addr.second->address() + "/" + +- std::to_string(addr.second->prefixLength()); +- +- stream << "Address=" << address << "\n"; +- } ++ stream << "Gateway=" << gateway << "\n"; + } +- +- if (manager.getSystemConf()) ++ const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); ++ if (!gateway6.empty()) + { +- const auto& gateway = manager.getSystemConf()->defaultGateway(); +- if (!gateway.empty()) +- { +- stream << "Gateway=" << gateway << "\n"; +- } +- const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); +- if (!gateway6.empty()) +- { +- stream << "Gateway=" << gateway6 << "\n"; +- } ++ stream << "Gateway=" << gateway6 << "\n"; + } + } + +@@ -819,7 +882,7 @@ std::string EthernetInterface::mACAddress(std::string value) + + void EthernetInterface::deleteAll() + { +- if (EthernetInterfaceIntf::dHCPEnabled()) ++ if (dhcpIsEnabled(IP::Protocol::IPv4, true)) + { + log("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index 3e4cf12..a962751 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -91,7 +91,7 @@ class EthernetInterface : public Ifaces + * send. + */ + EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal = true); + + /** @brief Function to create ipaddress dbus object. +@@ -157,7 +157,34 @@ class EthernetInterface : public Ifaces + } + + /** Set value of DHCPEnabled */ +- bool dHCPEnabled(bool value) override; ++ DHCPConf dHCPEnabled(DHCPConf value) override; ++ ++ /** @brief Determines if DHCP is active for the IP::Protocol supplied. ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] ignoreProtocol - Allows IPv4 and IPv6 to be checked using a ++ * single call. ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpIsEnabled(IP::Protocol protocol, bool ignoreProtocol = false); ++ ++ /** @brief Determines if DHCP will be active following next reconfig ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] nextDHCPState - The new DHCP mode to take affect ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpToBeEnabled(IP::Protocol family, std::string& nextDHCPState); ++ ++ /** @brief Determines if the address is manually assigned ++ * @param[in] origin - The origin entry of the IP::Address ++ * @returns true/false value if the address is static ++ */ ++ bool addressIsStatic(IP::AddressOrigin origin); ++ ++ /** @brief Selectively disables DHCP ++ * @param[in] protocol - The IPv4 or IPv6 protocol to return to static ++ * addressing mode ++ */ ++ void disableDHCP(IP::Protocol protocol); + + /** @brief sets the MAC address. + * @param[in] value - MAC address which needs to be set on the system. +diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp +index 30dee8a..87fd68d 100644 +--- a/test/test_ethernet_interface.cpp ++++ b/test/test_ethernet_interface.cpp +@@ -58,7 +58,8 @@ class TestEthernetInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1, mac); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + int countIPObjects() +diff --git a/test/test_vlan_interface.cpp b/test/test_vlan_interface.cpp +index 1dffc7e..e49b43f 100644 +--- a/test/test_vlan_interface.cpp ++++ b/test/test_vlan_interface.cpp +@@ -50,7 +50,8 @@ class TestVlanInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + void setConfDir() +diff --git a/types.hpp b/types.hpp +index 123067a..c4409fe 100644 +--- a/types.hpp ++++ b/types.hpp +@@ -1,5 +1,7 @@ + #pragma once + ++#include "ipaddress.hpp" ++ + #include + #include + #include +@@ -50,6 +52,7 @@ struct AddrInfo + { + uint8_t addrType; + std::string ipaddress; ++ IP::AddressOrigin origin; + uint16_t prefix; + }; + +diff --git a/util.cpp b/util.cpp +index 13a607f..554d7f6 100644 +--- a/util.cpp ++++ b/util.cpp +@@ -410,9 +410,11 @@ std::optional interfaceToUbootEthAddr(const char* intf) + return "eth" + std::to_string(idx) + "addr"; + } + +-bool getDHCPValue(const std::string& confDir, const std::string& intf) ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf) + { +- bool dhcp = false; ++ EthernetInterfaceIntf::DHCPConf dhcp = ++ EthernetInterfaceIntf::DHCPConf::none; + // Get the interface mode value from systemd conf + // using namespace std::string_literals; + fs::path confPath = confDir; +@@ -434,7 +436,15 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf) + // There will be only single value for DHCP key. + if (values[0] == "true") + { +- dhcp = true; ++ dhcp = EthernetInterfaceIntf::DHCPConf::both; ++ } ++ else if (values[0] == "ipv4") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v4; ++ } ++ else if (values[0] == "ipv6") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v6; + } + return dhcp; + } +diff --git a/util.hpp b/util.hpp +index 251aa0d..ee11f4e 100644 +--- a/util.hpp ++++ b/util.hpp +@@ -13,12 +13,16 @@ + #include + #include + #include ++#include + + namespace phosphor + { + namespace network + { + ++using EthernetInterfaceIntf = ++ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; ++ + constexpr auto IPV4_MIN_PREFIX_LENGTH = 1; + constexpr auto IPV4_MAX_PREFIX_LENGTH = 32; + constexpr auto IPV6_MAX_PREFIX_LENGTH = 64; +@@ -156,7 +160,8 @@ std::optional interfaceToUbootEthAddr(const char* intf); + * @param[in] confDir - Network configuration directory. + * @param[in] intf - Interface name. + */ +-bool getDHCPValue(const std::string& confDir, const std::string& intf); ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf); + + namespace internal + { +diff --git a/vlan_interface.cpp b/vlan_interface.cpp +index 73de4e8..26282cb 100644 +--- a/vlan_interface.cpp ++++ b/vlan_interface.cpp +@@ -22,7 +22,7 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + + VlanInterface::VlanInterface(sdbusplus::bus::bus& bus, +- const std::string& objPath, bool dhcpEnabled, ++ const std::string& objPath, DHCPConf dhcpEnabled, + uint32_t vlanID, EthernetInterface& intf, + Manager& parent) : + VlanIface(bus, objPath.c_str()), +diff --git a/vlan_interface.hpp b/vlan_interface.hpp +index a994d05..37ae7ee 100644 +--- a/vlan_interface.hpp ++++ b/vlan_interface.hpp +@@ -45,8 +45,8 @@ class VlanInterface : public VlanIface, + * @param[in] manager - network manager object. + */ + VlanInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, uint32_t vlanID, EthernetInterface& intf, +- Manager& manager); ++ DHCPConf dhcpEnabled, uint32_t vlanID, ++ EthernetInterface& intf, Manager& manager); + + /** @brief Delete this d-bus object. + */ +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch new file mode 100644 index 000000000..c05088990 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch @@ -0,0 +1,120 @@ +From 6d3d50c506e2d6b4982ff6040af9fd61edaa8beb Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey +Date: Fri, 24 Jan 2020 13:30:39 -0800 +Subject: [PATCH] Enable conditional use of ETHTOOL features in the NIC driver + +The retrieval of the NIC speed, duplex, and autonegotiation +capabilities using the ETHTOOL driver extensions is not supported in +every NIC. + +Depending on the driver, the use of the ETHTOOL_GSET command may +result in undesirable messages being printed by the kernel. In order +to avoid these kernel messages a compile time switch is added. By +default the switch disables the use of the ETHTOOL features. Enable +the ETHTOOL feature by adding: + EXTRA_OECONF_append = " --enable-nic-ethtool=yes" +to the phosphor-network bbappend file. + +Tested: +Compiled the source without changing the bbappend file. The code +compiled as is, and after code was added that would cause a compile +time failure. +Loaded the code, and performed a Redfish read of the NIC. The +SpeedMbps field was confirmed to be set to 0. + +Enabled compiling the code by adding the EXTRA_OECONF entry to the +bbappend file. The code compiled as is, and failed to compile after +adding invalid code to the protected blocks. +Loaded the code, and performed a Redfish read of the NIC. The +SpeedMbps reported the correct link speed. + +Change-Id: If03e7d473d439ebb4a01b5d3f45e37ede2a5a84f +Signed-off-by: Johnathan Mantey +--- + Makefile.am | 3 +++ + configure.ac | 10 ++++++++++ + ethernet_interface.cpp | 13 ++++++++----- + 3 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 2a54797..ff252fc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -99,6 +99,9 @@ phosphor_network_manager_CXXFLAGS = \ + $(PHOSPHOR_LOGGING_CFLAGS) \ + -DBOOST_ASIO_DISABLE_THREADS \ + -flto ++if FEATURE_NIC_ETHTOOL ++phosphor_network_manager_CXXFLAGS += -DNIC_SUPPORTS_ETHTOOL ++endif + + xyz/openbmc_project/Network/VLAN/Create/server.cpp: xyz/openbmc_project/Network/VLAN/Create.interface.yaml xyz/openbmc_project/Network/VLAN/Create/server.hpp + @mkdir -p `dirname $@` +diff --git a/configure.ac b/configure.ac +index 00b23bc..fed3e09 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -114,6 +114,16 @@ AC_SUBST(DEFAULT_BUSNAME, ["$DEFAULT_BUSNAME"]) + AC_ARG_VAR(SYSTEMD_TARGET, "Target for starting this service") + AS_IF([test "x$SYSTEMD_TARGET" == "x"], [SYSTEMD_TARGET="multi-user.target"]) + ++AC_ARG_ENABLE([nic_ethtool], ++ [ --enable-nic-ethtool Enable/disable the use of ETHTOOL features in the NIC driver], ++ [case "${enableval}" in ++ yes) nic_ethtool=true ;; ++ no) nic_ethtool=false ;; ++ *) AC_MSG_ERROR([bad value ${nic_ethtool} for --enable-nic-ethtool]) ;; ++ esac],[nic_ethtool=false] ++ ) ++AM_CONDITIONAL([FEATURE_NIC_ETHTOOL], [test x$nic_ethtool = xtrue]) ++ + # Create configured output. + AC_CONFIG_FILES([Makefile test/Makefile]) + AC_CONFIG_FILES([xyz.openbmc_project.Network.service]) +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 7f81003..ba6195e 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -57,10 +57,12 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + MacAddressIntf::mACAddress(getMACAddress(intfName)); + EthernetInterfaceIntf::nTPServers(getNTPServersFromConf()); + EthernetInterfaceIntf::nameservers(getNameServerFromConf()); ++#if NIC_SUPPORTS_ETHTOOL + InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo(); + + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); ++#endif + getChannelPrivilege(intfName); + + // Emit deferred signal. +@@ -283,13 +285,13 @@ ObjectPath EthernetInterface::neighbor(std::string iPAddress, + return objectPath; + } + ++#if NIC_SUPPORTS_ETHTOOL + /* +-Note: We don't have support for ethtool now +-will enable this code once we bring the ethtool +-in the image. +-TODO: https://github.com/openbmc/openbmc/issues/1484 ++ Enable this code if your NIC driver supports the ETHTOOL features. ++ Do this by adding the following to your phosphor-network*.bbappend file. ++ EXTRA_OECONF_append = " --enable-nic-ethtool=yes" ++ The default compile mode is to omit getInterfaceInfo() + */ +- + InterfaceInfo EthernetInterface::getInterfaceInfo() const + { + int sock{-1}; +@@ -330,6 +332,7 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const + } + return std::make_tuple(speed, duplex, autoneg); + } ++#endif + + /** @brief get the mac address of the interface. + * @return macaddress on success +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch new file mode 100644 index 000000000..e1972e815 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch @@ -0,0 +1,191 @@ +From 0e415f23b7a97e9a0f0fa616b6bcccec6035bbed Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey +Date: Tue, 29 Oct 2019 16:20:28 -0700 +Subject: [PATCH] Added enable/disable control of the Network Interface Card + +Implemented enable/disable function to perform +"ip link set eth(x) up" +"ip link set eth(x) down" +functionality from DBus. + +Tested: + +Confirmed Redfish PATCH commands on the InterfaceEnabled property +changes the NIC state. Confirmed the NIC is DOWN/UP using "ip link". +Confirmed "ip link" state changes can be obsserved from dbus-send +commands, and from Redfish GET actions. + +Confirmed the link is inactive after a reboot. + +Confirmed link stays down despite assigning an IP manually. + +Confirmed link stays down despite enabling DHCP. + +Change-Id: I4152b53055e6546f7a6ca81b5a5eef6f689bcc66 +Signed-off-by: Johnathan Mantey +--- + ethernet_interface.cpp | 70 ++++++++++++++++++++++++++++++++++++++++-- + ethernet_interface.hpp | 7 ++++- + 2 files changed, 74 insertions(+), 3 deletions(-) + +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index ba6195e..671e8c4 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -60,6 +60,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + #if NIC_SUPPORTS_ETHTOOL + InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo(); + ++ EthernetInterfaceIntf::nICEnabled(std::get<3>(ifInfo)); + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); + #endif +@@ -300,6 +301,7 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const + LinkSpeed speed{0}; + Autoneg autoneg{0}; + DuplexMode duplex{0}; ++ NICEnabled nicEnabled{false}; + do + { + sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); +@@ -324,13 +326,21 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const + speed = edata.speed; + duplex = edata.duplex; + autoneg = edata.autoneg; ++ ++ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) ++ { ++ log("ioctl failed for SIOCGIFFLAGS:", ++ entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ nicEnabled = static_cast(ifr.ifr_flags & IFF_UP); + } while (0); + +- if (sock) ++ if (sock >= 0) + { + close(sock); + } +- return std::make_tuple(speed, duplex, autoneg); ++ return std::make_tuple(speed, duplex, autoneg, nicEnabled); + } + #endif + +@@ -355,9 +365,11 @@ std::string + { + log("ioctl failed for SIOCGIFHWADDR:", + entry("ERROR=%s", strerror(errno))); ++ close(sock); + elog(); + } + ++ close(sock); + static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr)); + std::string_view hwaddr(reinterpret_cast(ifr.ifr_hwaddr.sa_data), + sizeof(ifr.ifr_hwaddr.sa_data)); +@@ -514,6 +526,55 @@ EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) + return value; + } + ++bool EthernetInterface::nICEnabled(bool value) ++{ ++ if (value == EthernetInterfaceIntf::nICEnabled()) ++ { ++ return value; ++ } ++ ++ int sock{-1}; ++ ifreq ifr{0}; ++ EthernetInterfaceIntf::nICEnabled(value); ++ sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); ++ if (sock < 0) ++ { ++ log("socket creation failed:", ++ entry("ERROR=%s", strerror(errno))); ++ return value; ++ } ++ ++ do ++ { ++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE); ++ if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) ++ { ++ log("ioctl failed for SIOCGIFFLAGS:", ++ entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ ++ ifr.ifr_flags &= ~IFF_UP; ++ if (value) ++ { ++ ifr.ifr_flags |= IFF_UP; ++ } ++ ++ if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) ++ { ++ log("ioctl failed for SIOCSIFFLAGS:", ++ entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ } while (0); ++ ++ close(sock); ++ writeConfigurationFile(); ++ manager.restartSystemdUnit(networkdService); ++ ++ return value; ++} ++ + ServerList EthernetInterface::nameservers(ServerList value) + { + for (const auto& nameserverip : value) +@@ -704,6 +765,11 @@ void EthernetInterface::writeConfigurationFile() + stream << "MACAddress=" << mac << "\n"; + } + ++ if (!nICEnabled()) ++ { ++ stream << "Unmanaged=yes\n"; ++ } ++ + // write the network section + stream << "[Network]\n"; + #ifdef LINK_LOCAL_AUTOCONFIGURATION +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index a962751..3dee311 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 NICEnabled = 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); + ++ /** Set value of NICEnabled */ ++ bool nICEnabled(bool value) 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::nICEnabled; + using MacAddressIntf::mACAddress; + + /** @brief Absolute path of the resolv conf file */ +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch new file mode 100644 index 000000000..b6cf8f77d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch @@ -0,0 +1,504 @@ +From 42f361622a9c029221c8a90f92104703166e48c2 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey +Date: Thu, 30 Jan 2020 15:07:39 -0800 +Subject: [PATCH] Enhance DHCP beyond just OFF and IPv4/IPv6 enabled. + +DHCP is not a binary option. The network interface can have DHCP +disabled, IPv4 only, IPv6 only, and IPv4/IPv6. + +Tested: +Using dbus-send or busctl: +Disabled DHCP, and confirmed only link local addresses were present. + +Assigned only static addresses. Both with/and without the gateway set +to 0.0.0.0 + +Deleted static IPv4 addresses. +Reassigned static addresses. + +Enabled DHCP for ipv4 only, and witnessed a DHCP server assign a valid +address. + +Assigned static IPv4 address. +Assigned static IPv6 address. +Confirmed both IPv4 and IPv6 static addresses are active. + +Enabled DHCP for ipv6 only, and confirmed the static v4 address +remains. The ipv6 address is removed, waiting for a DHCP6 server. + +Enabled DHCP for both ipv4 and ipv6. IPv4 address was assigned. IPv6 +address is assumed to succeed, as systemd config file enables IPv6 +DHCP. + +Change-Id: I2e0ff80ac3a5e88bcff28adac419bf21e37be162 +Signed-off-by: Johnathan Mantey +--- + Makefile.am | 1 + + configure.ac | 1 + + ethernet_interface.cpp | 147 ++++++++++++++++++++++--------- + ethernet_interface.hpp | 31 ++++++- + test/test_ethernet_interface.cpp | 3 +- + test/test_vlan_interface.cpp | 3 +- + types.hpp | 3 + + util.cpp | 16 +++- + util.hpp | 7 +- + vlan_interface.cpp | 2 +- + vlan_interface.hpp | 4 +- + 11 files changed, 165 insertions(+), 53 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 1c47747..ff252fc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -97,6 +97,7 @@ phosphor_network_manager_CXXFLAGS = \ + $(SDEVENTPLUS_CFLAGS) \ + $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ + $(PHOSPHOR_LOGGING_CFLAGS) \ ++ -DBOOST_ASIO_DISABLE_THREADS \ + -flto + if FEATURE_NIC_ETHTOOL + phosphor_network_manager_CXXFLAGS += -DNIC_SUPPORTS_ETHTOOL +diff --git a/configure.ac b/configure.ac +index 12d6caa..fed3e09 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -36,6 +36,7 @@ AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++]) + PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging]) + PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces]) + PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0]) ++AC_CHECK_HEADER(boost/algorithm/string/split.hpp, [], [AC_MSG_ERROR([Could not find boost/algorithm/string/split.hpp])]) + + # Checks for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,\ +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 73fd8fe..ba6195e 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -3,7 +3,6 @@ + #include "ethernet_interface.hpp" + + #include "config_parser.hpp" +-#include "ipaddress.hpp" + #include "neighbor.hpp" + #include "network_manager.hpp" + #include "vlan_interface.hpp" +@@ -40,9 +39,12 @@ using Argument = xyz::openbmc_project::Common::InvalidArgument; + static constexpr const char* networkChannelCfgFile = + "/var/channel_intf_data.json"; + static constexpr const char* defaultChannelPriv = "priv-admin"; ++std::map mapDHCPToSystemd = { ++ {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}}; ++ + EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal) : + Ifaces(bus, objPath.c_str(), true), + bus(bus), manager(parent), objPath(objPath) +@@ -83,6 +85,65 @@ static IP::Protocol convertFamily(int family) + throw std::invalid_argument("Bad address family"); + } + ++void EthernetInterface::disableDHCP(IP::Protocol protocol) ++{ ++ DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled(); ++ if (dhcpState == EthernetInterface::DHCPConf::both) ++ { ++ if (protocol == IP::Protocol::IPv4) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v6); ++ } ++ else if (protocol == IP::Protocol::IPv6) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v4); ++ } ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v4) && ++ (protocol == IP::Protocol::IPv4)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v6) && ++ (protocol == IP::Protocol::IPv6)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++} ++ ++bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol) ++{ ++ return ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::both) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v6) && ++ ((family == IP::Protocol::IPv6) || ignoreProtocol)) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v4) && ++ ((family == IP::Protocol::IPv4) || ignoreProtocol))); ++} ++ ++bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family, ++ std::string& nextDHCPState) ++{ ++ return ((nextDHCPState == "true") || ++ ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) || ++ ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4))); ++} ++ ++bool EthernetInterface::addressIsStatic(IP::AddressOrigin origin) ++{ ++ return ( ++#ifdef LINK_LOCAL_AUTOCONFIGURATION ++ (origin == IP::AddressOrigin::Static) ++#else ++ (origin == IP::AddressOrigin::Static || ++ origin == IP::AddressOrigin::LinkLocal) ++#endif ++ ++ ); ++} ++ + void EthernetInterface::createIPAddressObjects() + { + addrs.clear(); +@@ -93,7 +154,7 @@ void EthernetInterface::createIPAddressObjects() + { + IP::Protocol addressType = convertFamily(addr.addrType); + IP::AddressOrigin origin = IP::AddressOrigin::Static; +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(addressType)) + { + origin = IP::AddressOrigin::DHCP; + } +@@ -154,11 +215,11 @@ ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress, + uint8_t prefixLength, std::string gateway) + { + +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(protType)) + { + log("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +- dHCPEnabled(false); ++ disableDHCP(protType); + } + + IP::AddressOrigin origin = IP::AddressOrigin::Static; +@@ -441,7 +502,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value) + return value; + } + +-bool EthernetInterface::dHCPEnabled(bool value) ++EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) + { + if (value == EthernetInterfaceIntf::dHCPEnabled()) + { +@@ -508,7 +569,7 @@ void EthernetInterface::loadVLAN(VlanId id) + std::string path = objPath; + path += "_" + std::to_string(id); + +- auto dhcpEnabled = ++ DHCPConf dhcpEnabled = + getDHCPValue(manager.getConfDir().string(), vlanInterfaceName); + + auto vlanIntf = std::make_unique( +@@ -530,7 +591,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id) + path += "_" + std::to_string(id); + + auto vlanIntf = std::make_unique( +- bus, path.c_str(), false, id, *this, manager); ++ bus, path.c_str(), EthernetInterface::DHCPConf::none, id, *this, ++ manager); + + // write the device file for the vlan interface. + vlanIntf->writeDeviceFile(); +@@ -603,8 +665,6 @@ void EthernetInterface::writeConfigurationFile() + // write all the static ip address in the systemd-network conf file + + using namespace std::string_literals; +- using AddressOrigin = +- sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin; + namespace fs = std::experimental::filesystem; + + // if there is vlan interafce then write the configuration file +@@ -673,42 +733,45 @@ void EthernetInterface::writeConfigurationFile() + } + + // Add the DHCP entry +- auto value = dHCPEnabled() ? "true"s : "false"s; +- stream << "DHCP="s + value + "\n"; ++ std::string value = convertForMessage(EthernetInterfaceIntf::dHCPEnabled()); ++ std::string::size_type loc = value.rfind("."); ++ std::string requestedDHCPState = value.substr(loc + 1); ++ std::string mappedDHCPState = mapDHCPToSystemd[requestedDHCPState]; ++ stream << "DHCP="s + mappedDHCPState + "\n"; ++ ++ bool dhcpv6Requested = dhcpToBeEnabled(IP::Protocol::IPv6, mappedDHCPState); ++ bool dhcpv4Requested = dhcpToBeEnabled(IP::Protocol::IPv4, mappedDHCPState); ++ // Static IP addresses ++ for (const auto& addr : addrs) ++ { ++ bool isValidIPv4 = isValidIP(AF_INET, addr.second->address()); ++ bool isValidIPv6 = isValidIP(AF_INET6, addr.second->address()); ++ if (((!dhcpv4Requested && isValidIPv4) || ++ (!dhcpv6Requested && isValidIPv6)) && ++ addressIsStatic(addr.second->origin())) ++ { ++ // Process all static addresses ++ std::string address = addr.second->address() + "/" + ++ std::to_string(addr.second->prefixLength()); ++ ++ // build the address entries. Do not use [Network] shortcuts to ++ // insert address entries. ++ stream << "[Address]\n"; ++ stream << "Address=" << address << "\n"; ++ } ++ } + +- // When the interface configured as dhcp, we don't need below given entries +- // in config file. +- if (dHCPEnabled() == false) ++ if (manager.getSystemConf()) + { +- // Static +- for (const auto& addr : addrs) ++ const auto& gateway = manager.getSystemConf()->defaultGateway(); ++ if (!gateway.empty()) + { +- if (addr.second->origin() == AddressOrigin::Static +-#ifndef LINK_LOCAL_AUTOCONFIGURATION +- || addr.second->origin() == AddressOrigin::LinkLocal +-#endif +- ) +- { +- std::string address = +- addr.second->address() + "/" + +- std::to_string(addr.second->prefixLength()); +- +- stream << "Address=" << address << "\n"; +- } ++ stream << "Gateway=" << gateway << "\n"; + } +- +- if (manager.getSystemConf()) ++ const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); ++ if (!gateway6.empty()) + { +- const auto& gateway = manager.getSystemConf()->defaultGateway(); +- if (!gateway.empty()) +- { +- stream << "Gateway=" << gateway << "\n"; +- } +- const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); +- if (!gateway6.empty()) +- { +- stream << "Gateway=" << gateway6 << "\n"; +- } ++ stream << "Gateway=" << gateway6 << "\n"; + } + } + +@@ -819,7 +882,7 @@ std::string EthernetInterface::mACAddress(std::string value) + + void EthernetInterface::deleteAll() + { +- if (EthernetInterfaceIntf::dHCPEnabled()) ++ if (dhcpIsEnabled(IP::Protocol::IPv4, true)) + { + log("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index 3e4cf12..a962751 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -91,7 +91,7 @@ class EthernetInterface : public Ifaces + * send. + */ + EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal = true); + + /** @brief Function to create ipaddress dbus object. +@@ -157,7 +157,34 @@ class EthernetInterface : public Ifaces + } + + /** Set value of DHCPEnabled */ +- bool dHCPEnabled(bool value) override; ++ DHCPConf dHCPEnabled(DHCPConf value) override; ++ ++ /** @brief Determines if DHCP is active for the IP::Protocol supplied. ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] ignoreProtocol - Allows IPv4 and IPv6 to be checked using a ++ * single call. ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpIsEnabled(IP::Protocol protocol, bool ignoreProtocol = false); ++ ++ /** @brief Determines if DHCP will be active following next reconfig ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] nextDHCPState - The new DHCP mode to take affect ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpToBeEnabled(IP::Protocol family, std::string& nextDHCPState); ++ ++ /** @brief Determines if the address is manually assigned ++ * @param[in] origin - The origin entry of the IP::Address ++ * @returns true/false value if the address is static ++ */ ++ bool addressIsStatic(IP::AddressOrigin origin); ++ ++ /** @brief Selectively disables DHCP ++ * @param[in] protocol - The IPv4 or IPv6 protocol to return to static ++ * addressing mode ++ */ ++ void disableDHCP(IP::Protocol protocol); + + /** @brief sets the MAC address. + * @param[in] value - MAC address which needs to be set on the system. +diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp +index 30dee8a..87fd68d 100644 +--- a/test/test_ethernet_interface.cpp ++++ b/test/test_ethernet_interface.cpp +@@ -58,7 +58,8 @@ class TestEthernetInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1, mac); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + int countIPObjects() +diff --git a/test/test_vlan_interface.cpp b/test/test_vlan_interface.cpp +index 1dffc7e..e49b43f 100644 +--- a/test/test_vlan_interface.cpp ++++ b/test/test_vlan_interface.cpp +@@ -50,7 +50,8 @@ class TestVlanInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + void setConfDir() +diff --git a/types.hpp b/types.hpp +index 123067a..c4409fe 100644 +--- a/types.hpp ++++ b/types.hpp +@@ -1,5 +1,7 @@ + #pragma once + ++#include "ipaddress.hpp" ++ + #include + #include + #include +@@ -50,6 +52,7 @@ struct AddrInfo + { + uint8_t addrType; + std::string ipaddress; ++ IP::AddressOrigin origin; + uint16_t prefix; + }; + +diff --git a/util.cpp b/util.cpp +index 13a607f..554d7f6 100644 +--- a/util.cpp ++++ b/util.cpp +@@ -410,9 +410,11 @@ std::optional interfaceToUbootEthAddr(const char* intf) + return "eth" + std::to_string(idx) + "addr"; + } + +-bool getDHCPValue(const std::string& confDir, const std::string& intf) ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf) + { +- bool dhcp = false; ++ EthernetInterfaceIntf::DHCPConf dhcp = ++ EthernetInterfaceIntf::DHCPConf::none; + // Get the interface mode value from systemd conf + // using namespace std::string_literals; + fs::path confPath = confDir; +@@ -434,7 +436,15 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf) + // There will be only single value for DHCP key. + if (values[0] == "true") + { +- dhcp = true; ++ dhcp = EthernetInterfaceIntf::DHCPConf::both; ++ } ++ else if (values[0] == "ipv4") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v4; ++ } ++ else if (values[0] == "ipv6") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v6; + } + return dhcp; + } +diff --git a/util.hpp b/util.hpp +index 251aa0d..ee11f4e 100644 +--- a/util.hpp ++++ b/util.hpp +@@ -13,12 +13,16 @@ + #include + #include + #include ++#include + + namespace phosphor + { + namespace network + { + ++using EthernetInterfaceIntf = ++ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; ++ + constexpr auto IPV4_MIN_PREFIX_LENGTH = 1; + constexpr auto IPV4_MAX_PREFIX_LENGTH = 32; + constexpr auto IPV6_MAX_PREFIX_LENGTH = 64; +@@ -156,7 +160,8 @@ std::optional interfaceToUbootEthAddr(const char* intf); + * @param[in] confDir - Network configuration directory. + * @param[in] intf - Interface name. + */ +-bool getDHCPValue(const std::string& confDir, const std::string& intf); ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf); + + namespace internal + { +diff --git a/vlan_interface.cpp b/vlan_interface.cpp +index 73de4e8..26282cb 100644 +--- a/vlan_interface.cpp ++++ b/vlan_interface.cpp +@@ -22,7 +22,7 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + + VlanInterface::VlanInterface(sdbusplus::bus::bus& bus, +- const std::string& objPath, bool dhcpEnabled, ++ const std::string& objPath, DHCPConf dhcpEnabled, + uint32_t vlanID, EthernetInterface& intf, + Manager& parent) : + VlanIface(bus, objPath.c_str()), +diff --git a/vlan_interface.hpp b/vlan_interface.hpp +index a994d05..37ae7ee 100644 +--- a/vlan_interface.hpp ++++ b/vlan_interface.hpp +@@ -45,8 +45,8 @@ class VlanInterface : public VlanIface, + * @param[in] manager - network manager object. + */ + VlanInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, uint32_t vlanID, EthernetInterface& intf, +- Manager& manager); ++ DHCPConf dhcpEnabled, uint32_t vlanID, ++ EthernetInterface& intf, Manager& manager); + + /** @brief Delete this d-bus object. + */ +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch new file mode 100644 index 000000000..51957ffff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch @@ -0,0 +1,282 @@ +From 8f6f3ccb1f5a4af8065485c2e683402ec2b38abf 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 | 141 +++++++++++++++++++++++++---------------- + ethernet_interface.hpp | 8 ++- + 2 files changed, 92 insertions(+), 57 deletions(-) + +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 671e8c4..018f2e1 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, +@@ -57,12 +79,12 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + MacAddressIntf::mACAddress(getMACAddress(intfName)); + EthernetInterfaceIntf::nTPServers(getNTPServersFromConf()); + EthernetInterfaceIntf::nameservers(getNameServerFromConf()); +-#if NIC_SUPPORTS_ETHTOOL + InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo(); +- +- EthernetInterfaceIntf::nICEnabled(std::get<3>(ifInfo)); ++#if NIC_SUPPORTS_ETHTOOL + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); ++ EthernetInterfaceIntf::nICEnabled(std::get<3>(ifInfo)); ++ EthernetInterfaceIntf::linkUp(std::get<4>(ifInfo)); + #endif + getChannelPrivilege(intfName); + +@@ -286,63 +308,47 @@ ObjectPath EthernetInterface::neighbor(std::string iPAddress, + return objectPath; + } + +-#if NIC_SUPPORTS_ETHTOOL +-/* +- Enable this code if your NIC driver supports the ETHTOOL features. +- Do this by adding the following to your phosphor-network*.bbappend file. +- EXTRA_OECONF_append = " --enable-nic-ethtool=yes" +- The default compile mode is to omit getInterfaceInfo() +-*/ + InterfaceInfo EthernetInterface::getInterfaceInfo() const + { +- int sock{-1}; +- ifreq ifr{0}; +- ethtool_cmd edata{0}; + LinkSpeed speed{0}; + Autoneg autoneg{0}; + DuplexMode duplex{0}; + NICEnabled nicEnabled{false}; +- 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}; + +- strcpy(ifr.ifr_name, interfaceName().c_str()); +- ifr.ifr_data = reinterpret_cast(&edata); ++#if NIC_SUPPORTS_ETHTOOL ++ /* ++ Enable this code if your NIC driver supports the ETHTOOL features. ++ Do this by adding the following to your phosphor-network*.bbappend ++ file. EXTRA_OECONF_append = " --enable-nic-ethtool=yes" The ++ default compile mode is to omit getInterfaceInfo() ++ */ ++ ifreq ifr{0}; ++ ethtool_cmd edata{0}; ++ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + +- edata.cmd = ETHTOOL_GSET; ++ if (eifSocket.sock < 0) ++ { ++ return std::make_tuple(speed, duplex, autoneg, nicEnabled, linkState); ++ } + +- if (ioctl(sock, SIOCETHTOOL, &ifr) < 0) +- { +- log("ioctl failed for SIOCETHTOOL:", +- entry("ERROR=%s", strerror(errno))); +- break; +- } ++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1); ++ ifr.ifr_data = reinterpret_cast(&edata); ++ ++ edata.cmd = ETHTOOL_GSET; ++ if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0) ++ { + speed = edata.speed; + duplex = edata.duplex; + autoneg = edata.autoneg; ++ } ++#endif + +- if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) +- { +- log("ioctl failed for SIOCGIFFLAGS:", +- entry("ERROR=%s", strerror(errno))); +- break; +- } +- nicEnabled = static_cast(ifr.ifr_flags & IFF_UP); +- } while (0); ++ nicEnabled = nICEnabled(); ++ linkState = linkUp(); + +- if (sock >= 0) +- { +- close(sock); +- } +- return std::make_tuple(speed, duplex, autoneg, nicEnabled); ++ return std::make_tuple(speed, duplex, autoneg, nicEnabled, linkState); + } +-#endif + + /** @brief get the mac address of the interface. + * @return macaddress on success +@@ -351,25 +357,23 @@ 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))); +- close(sock); + elog(); + } + +- close(sock); + static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr)); + std::string_view hwaddr(reinterpret_cast(ifr.ifr_hwaddr.sa_data), + sizeof(ifr.ifr_hwaddr.sa_data)); +@@ -546,7 +550,7 @@ bool EthernetInterface::nICEnabled(bool value) + + do + { +- std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE); ++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1); + if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) + { + log("ioctl failed for SIOCGIFFLAGS:", +@@ -575,6 +579,31 @@ bool EthernetInterface::nICEnabled(bool 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 3dee311..83d7cb5 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -60,9 +60,11 @@ using LinkSpeed = uint16_t; + using DuplexMode = uint8_t; + using Autoneg = uint8_t; + using NICEnabled = bool; ++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 = +@@ -190,6 +192,9 @@ class EthernetInterface : public Ifaces + /** Set value of NICEnabled */ + bool nICEnabled(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. +@@ -245,6 +250,7 @@ class EthernetInterface : public Ifaces + using ChannelAccessIntf::maxPrivilege; + using EthernetInterfaceIntf::dHCPEnabled; + using EthernetInterfaceIntf::interfaceName; ++ using EthernetInterfaceIntf::linkUp; + using EthernetInterfaceIntf::nICEnabled; + using MacAddressIntf::mACAddress; + +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend index db231d42f..5279b2e52 100644 --- a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend @@ -4,6 +4,11 @@ DEPENDS += "nlohmann-json boost" SRC_URI += "git://github.com/openbmc/phosphor-networkd" SRC_URI += "file://0003-Adding-channel-specific-privilege-to-network.patch \ - file://0001-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch \ + file://0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch \ + file://0008-Added-enable-disable-control-of-the-Network-Interfac.patch \ + file://0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch \ + file://0010-Enable-the-network-link-carrier-state-to-be-reported.patch \ " -SRCREV = "cb42fe26febc9e457a9c4279278bd8c85f60851a" +SRCREV = "dbd328d7e037b1af13fb0f20f3708e2261b9e0b6" + +EXTRA_OECONF_append = " --enable-nic-ethtool=yes" -- cgit v1.2.3