summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-network/network
diff options
context:
space:
mode:
authorJason M. Bills <jason.m.bills@linux.intel.com>2020-02-28 02:57:13 +0300
committerJason M. Bills <jason.m.bills@linux.intel.com>2020-03-02 22:06:57 +0300
commit6c1caca70063aa707ba809a6b4695d0f0c5646f1 (patch)
tree84da2f29a60cb571686d3a4fb93f9d1f1189d989 /meta-openbmc-mods/meta-common/recipes-network/network
parent9600a7403ba2848c8751280077503a3e0f2f3481 (diff)
downloadopenbmc-6c1caca70063aa707ba809a6b4695d0f0c5646f1.tar.xz
Update to internal 2020-02-27
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-network/network')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch (renamed from meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0001-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch)295
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch120
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch191
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch504
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch282
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend9
6 files changed, 1175 insertions, 226 deletions
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/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch
index 41541500f..b6cf8f77d 100644
--- 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/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch
@@ -1,6 +1,6 @@
-From c7050f4a1f87d49e8a619d5d8752d1c98bfed3e8 Mon Sep 17 00:00:00 2001
+From 42f361622a9c029221c8a90f92104703166e48c2 Mon Sep 17 00:00:00 2001
From: Johnathan Mantey <johnathanx.mantey@intel.com>
-Date: Wed, 3 Jul 2019 14:12:49 -0700
+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
@@ -17,7 +17,7 @@ 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.
+address.
Assigned static IPv4 address.
Assigned static IPv6 address.
@@ -33,39 +33,33 @@ DHCP.
Change-Id: I2e0ff80ac3a5e88bcff28adac419bf21e37be162
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
---
- Makefile.am | 5 +
+ Makefile.am | 1 +
configure.ac | 1 +
- ethernet_interface.cpp | 170 ++++++++++++++++++++++---------
- ethernet_interface.hpp | 31 +++++-
- ipaddress.cpp | 2 +-
- network_manager.cpp | 2 +-
+ 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 | 69 ++++++++++++-
- util.hpp | 13 ++-
+ util.cpp | 16 +++-
+ util.hpp | 7 +-
vlan_interface.cpp | 2 +-
vlan_interface.hpp | 4 +-
- 13 files changed, 246 insertions(+), 62 deletions(-)
+ 11 files changed, 165 insertions(+), 53 deletions(-)
diff --git a/Makefile.am b/Makefile.am
-index 79db184..2768e38 100644
+index 1c47747..ff252fc 100644
--- a/Makefile.am
+++ b/Makefile.am
-@@ -97,6 +97,11 @@ phosphor_network_manager_CXXFLAGS = \
+@@ -97,6 +97,7 @@ 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
+ if FEATURE_NIC_ETHTOOL
+ phosphor_network_manager_CXXFLAGS += -DNIC_SUPPORTS_ETHTOOL
diff --git a/configure.ac b/configure.ac
-index 8870fcd..00b23bc 100644
+index 12d6caa..fed3e09 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,7 @@ AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++])
@@ -77,21 +71,18 @@ index 8870fcd..00b23bc 100644
# 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
+index 73fd8fe..ba6195e 100644
--- a/ethernet_interface.cpp
+++ b/ethernet_interface.cpp
-@@ -3,9 +3,9 @@
+@@ -3,7 +3,6 @@
#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 <arpa/inet.h>
-@@ -40,9 +40,12 @@ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+@@ -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";
@@ -105,7 +96,7 @@ index c3edd4b..537054f 100644
bool emitSignal) :
Ifaces(bus, objPath.c_str(), true),
bus(bus), manager(parent), objPath(objPath)
-@@ -81,24 +84,78 @@ static IP::Protocol convertFamily(int family)
+@@ -83,6 +85,65 @@ static IP::Protocol convertFamily(int family)
throw std::invalid_argument("Bad address family");
}
@@ -171,38 +162,16 @@ index c3edd4b..537054f 100644
void EthernetInterface::createIPAddressObjects()
{
addrs.clear();
-
- auto addrs = getInterfaceAddrs()[interfaceName()];
-+ if (getIPAddrOrigins(addrs))
-+ {
-+ return;
-+ }
-
- for (auto& addr : addrs)
+@@ -93,7 +154,7 @@ void EthernetInterface::createIPAddressObjects()
{
IP::Protocol addressType = convertFamily(addr.addrType);
-- IP::AddressOrigin origin = IP::AddressOrigin::Static;
+ 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<phosphor::network::IPAddress>(
- 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,
++ 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)
{
@@ -216,7 +185,7 @@ index c3edd4b..537054f 100644
}
IP::AddressOrigin origin = IP::AddressOrigin::Static;
-@@ -438,7 +495,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value)
+@@ -441,7 +502,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value)
return value;
}
@@ -225,7 +194,7 @@ index c3edd4b..537054f 100644
{
if (value == EthernetInterfaceIntf::dHCPEnabled())
{
-@@ -505,7 +562,7 @@ void EthernetInterface::loadVLAN(VlanId id)
+@@ -508,7 +569,7 @@ void EthernetInterface::loadVLAN(VlanId id)
std::string path = objPath;
path += "_" + std::to_string(id);
@@ -234,7 +203,7 @@ index c3edd4b..537054f 100644
getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
-@@ -527,7 +584,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id)
+@@ -530,7 +591,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id)
path += "_" + std::to_string(id);
auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
@@ -244,7 +213,7 @@ index c3edd4b..537054f 100644
// write the device file for the vlan interface.
vlanIntf->writeDeviceFile();
-@@ -600,8 +658,6 @@ void EthernetInterface::writeConfigurationFile()
+@@ -603,8 +665,6 @@ void EthernetInterface::writeConfigurationFile()
// write all the static ip address in the systemd-network conf file
using namespace std::string_literals;
@@ -253,24 +222,15 @@ index c3edd4b..537054f 100644
namespace fs = std::experimental::filesystem;
// if there is vlan interafce then write the configuration file
-@@ -670,41 +726,57 @@ void EthernetInterface::writeConfigurationFile()
+@@ -673,42 +733,45 @@ 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::size_type loc = value.rfind(".");
++ std::string requestedDHCPState = value.substr(loc + 1);
+ std::string mappedDHCPState = mapDHCPToSystemd[requestedDHCPState];
+ stream << "DHCP="s + mappedDHCPState + "\n";
+
@@ -284,12 +244,8 @@ index c3edd4b..537054f 100644
+ 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
-- )
++ {
++ // Process all static addresses
+ std::string address = addr.second->address() + "/" +
+ std::to_string(addr.second->prefixLength());
+
@@ -297,50 +253,53 @@ index c3edd4b..537054f 100644
+ // 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() != "")
- {
++ }
++ }
+
+- // 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";
-+ gw = addr.second->gateway();
- }
-- }
+- }
++ 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())
-+ 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";
- }
+- }
++ stream << "Gateway=" << gateway6 << "\n";
}
}
-@@ -816,7 +888,7 @@ std::string EthernetInterface::mACAddress(std::string value)
+
+@@ -819,7 +882,7 @@ std::string EthernetInterface::mACAddress(std::string value)
void EthernetInterface::deleteAll()
{
@@ -398,32 +357,6 @@ index 3e4cf12..a962751 100644
/** @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<level::ERR>("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<phosphor::network::EthernetInterface>(
- 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
@@ -473,83 +406,10 @@ index 123067a..c4409fe 100644
};
diff --git a/util.cpp b/util.cpp
-index afbc229..2e5b164 100644
+index 13a607f..554d7f6 100644
--- a/util.cpp
+++ b/util.cpp
-@@ -6,12 +6,17 @@
- #include <arpa/inet.h>
- #include <dirent.h>
- #include <net/if.h>
-+#include <sys/stat.h>
- #include <sys/wait.h>
-
- #include <algorithm>
-+#include <boost/algorithm/string/classification.hpp>
-+#include <boost/algorithm/string/split.hpp>
-+#include <boost/process.hpp>
- #include <cstdlib>
- #include <cstring>
- #include <experimental/filesystem>
-+#include <fstream>
- #include <iostream>
- #include <list>
- #include <phosphor-logging/elog-errors.hpp>
-@@ -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<std::string> addressElements;
-+ std::vector<std::string> 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<std::string> interfaceToUbootEthAddr(const char* intf)
+@@ -410,9 +410,11 @@ std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
return "eth" + std::to_string(idx) + "addr";
}
@@ -563,7 +423,7 @@ index afbc229..2e5b164 100644
// 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)
+@@ -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")
{
@@ -581,7 +441,7 @@ index afbc229..2e5b164 100644
return dhcp;
}
diff --git a/util.hpp b/util.hpp
-index 251aa0d..b3f7bba 100644
+index 251aa0d..ee11f4e 100644
--- a/util.hpp
+++ b/util.hpp
@@ -13,12 +13,16 @@
@@ -611,19 +471,6 @@ index 251aa0d..b3f7bba 100644
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
@@ -653,5 +500,5 @@ index a994d05..37ae7ee 100644
/** @brief Delete this d-bus object.
*/
--
-2.21.0
+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 <johnathanx.mantey@intel.com>
+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 <johnathanx.mantey@intel.com>
+---
+ 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 <johnathanx.mantey@intel.com>
+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 <johnathanx.mantey@intel.com>
+---
+ 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<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
++ entry("ERROR=%s", strerror(errno)));
++ break;
++ }
++ nicEnabled = static_cast<bool>(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<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
+ entry("ERROR=%s", strerror(errno)));
++ close(sock);
+ elog<InternalFailure>();
+ }
+
++ close(sock);
+ static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
+ std::string_view hwaddr(reinterpret_cast<char*>(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<level::ERR>("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<level::ERR>("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<level::ERR>("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<LinkSpeed, DuplexMode, Autoneg>;
++using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg, NICEnabled>;
+ using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>;
+ using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>;
+ 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 <johnathanx.mantey@intel.com>
+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 <johnathanx.mantey@intel.com>
+---
+ 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<std::string, std::string> 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<level::INFO>("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<phosphor::network::VlanInterface>(
+@@ -530,7 +591,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id)
+ path += "_" + std::to_string(id);
+
+ auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
+- 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<level::INFO>("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 <ifaddrs.h>
+ #include <netinet/in.h>
+ #include <systemd/sd-event.h>
+@@ -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<std::string> 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 <sdbusplus/bus.hpp>
+ #include <string>
+ #include <string_view>
++#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
+
+ 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<std::string> 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 <johnathanx.mantey@intel.com>
+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 <johnathanx.mantey@intel.com>
+---
+ 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<std::string, std::string> 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<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,
+ 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<level::ERR>("socket creation failed:",
+- entry("ERROR=%s", strerror(errno)));
+- break;
+- }
++ LinkUp linkState{false};
+
+- strcpy(ifr.ifr_name, interfaceName().c_str());
+- ifr.ifr_data = reinterpret_cast<char*>(&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<level::ERR>("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<char*>(&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<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
+- entry("ERROR=%s", strerror(errno)));
+- break;
+- }
+- nicEnabled = static_cast<bool>(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<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)));
+- close(sock);
+ elog<InternalFailure>();
+ }
+
+- close(sock);
+ static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr));
+ std::string_view hwaddr(reinterpret_cast<char*>(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<level::ERR>("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<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 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<LinkSpeed, DuplexMode, Autoneg, NICEnabled>;
++using InterfaceInfo =
++ std::tuple<LinkSpeed, DuplexMode, Autoneg, NICEnabled, LinkUp>;
+ using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>;
+ using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>;
+ 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"