summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-network
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-network')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch409
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch506
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check109
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service11
6 files changed, 1071 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch
new file mode 100644
index 000000000..f361c3d07
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch
@@ -0,0 +1,409 @@
+From 5dfcd6c81a9f26c6c9c867a7a49f5259c3512be2 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Thu, 2 Apr 2020 17:06:07 +0530
+Subject: [PATCH 1/2] Adding channel specific privilege to network
+
+ - Adding the channel access information to the network
+ interface object. This privilege will be used in
+ channel specific authorization.
+ - Get supported priv from user manager service dynamically.
+ - Signal handling for capturing the supported priv list
+ changes from user managerment.
+
+Tested-by:
+Verified channel access through ipmitool get/set channel
+access command
+
+Change-Id: I3b592a19363eef684e31d5f7c34dad8f2f9211df
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ ethernet_interface.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++++
+ ethernet_interface.hpp | 39 +++++++++++++++-
+ network_manager.cpp | 104 +++++++++++++++++++++++++++++++++++++++++
+ network_manager.hpp | 9 ++++
+ 4 files changed, 274 insertions(+), 1 deletion(-)
+
+diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
+index ed1e1ba..fca86bd 100644
+--- a/ethernet_interface.cpp
++++ b/ethernet_interface.cpp
+@@ -37,6 +37,10 @@ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+
++static constexpr const char* networkChannelCfgFile =
++ "/var/channel_intf_data.json";
++static constexpr const char* defaultChannelPriv = "priv-admin";
++
+ struct EthernetIntfSocket
+ {
+ EthernetIntfSocket(int domain, int type, int protocol)
+@@ -86,6 +90,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+ EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
+ EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo));
+ #endif
++ getChannelPrivilege(intfName);
+
+ // Emit deferred signal.
+ if (emitSignal)
+@@ -869,5 +874,123 @@ void EthernetInterface::deleteAll()
+ manager.writeToConfigurationFile();
+ }
+
++nlohmann::json EthernetInterface::readJsonFile(const std::string& configFile)
++{
++ std::ifstream jsonFile(configFile);
++ if (!jsonFile.good())
++ {
++ log<level::ERR>("JSON file not found");
++ return nullptr;
++ }
++
++ nlohmann::json data = nullptr;
++ try
++ {
++ data = nlohmann::json::parse(jsonFile, nullptr, false);
++ }
++ catch (nlohmann::json::parse_error& e)
++ {
++ log<level::DEBUG>("Corrupted channel config.",
++ entry("MSG: %s", e.what()));
++ throw std::runtime_error("Corrupted channel config file");
++ }
++
++ return data;
++}
++
++int EthernetInterface::writeJsonFile(const std::string& configFile,
++ const nlohmann::json& jsonData)
++{
++ std::ofstream jsonFile(configFile);
++ if (!jsonFile.good())
++ {
++ log<level::ERR>("JSON file open failed",
++ entry("FILE=%s", networkChannelCfgFile));
++ return -1;
++ }
++
++ // Write JSON to file
++ jsonFile << jsonData;
++
++ jsonFile.flush();
++ return 0;
++}
++
++std::string
++ EthernetInterface::getChannelPrivilege(const std::string& interfaceName)
++{
++ std::string priv(defaultChannelPriv);
++ std::string retPriv;
++
++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile);
++ if (jsonData != nullptr)
++ {
++ try
++ {
++ priv = jsonData[interfaceName].get<std::string>();
++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv));
++ return retPriv;
++ }
++ catch (const nlohmann::json::exception& e)
++ {
++ jsonData[interfaceName] = priv;
++ }
++ }
++ else
++ {
++ jsonData[interfaceName] = priv;
++ }
++
++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0)
++ {
++ log<level::DEBUG>("Error in write JSON data to file",
++ entry("FILE=%s", networkChannelCfgFile));
++ elog<InternalFailure>();
++ }
++
++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv));
++
++ return retPriv;
++}
++
++std::string EthernetInterface::maxPrivilege(std::string priv)
++{
++ std::string intfName = interfaceName();
++
++ if (manager.supportedPrivList.empty())
++ {
++ // Populate the supported privilege list
++ manager.initSupportedPrivilges();
++ }
++
++ if (!priv.empty() && (std::find(manager.supportedPrivList.begin(),
++ manager.supportedPrivList.end(),
++ priv) == manager.supportedPrivList.end()))
++ {
++ log<level::ERR>("Invalid privilege");
++ elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege"),
++ Argument::ARGUMENT_VALUE(priv.c_str()));
++ }
++
++ if (ChannelAccessIntf::maxPrivilege() == priv)
++ {
++ // No change in privilege so just return.
++ return priv;
++ }
++
++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile);
++ jsonData[intfName] = priv;
++
++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0)
++ {
++ log<level::DEBUG>("Error in write JSON data to file",
++ entry("FILE=%s", networkChannelCfgFile));
++ elog<InternalFailure>();
++ }
++
++ // Property change signal will be sent
++ return ChannelAccessIntf::maxPrivilege(std::move(priv));
++}
++
+ } // namespace network
+ } // namespace phosphor
+diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
+index 68668d6..058d328 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -2,11 +2,14 @@
+
+ #include "types.hpp"
+ #include "util.hpp"
++#include "xyz/openbmc_project/Channel/ChannelAccess/server.hpp"
+ #include "xyz/openbmc_project/Network/IP/Create/server.hpp"
+ #include "xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp"
+
+ #include <experimental/filesystem>
++#include <nlohmann/json.hpp>
+ #include <sdbusplus/bus.hpp>
++#include <sdbusplus/bus/match.hpp>
+ #include <sdbusplus/server/object.hpp>
+ #include <string>
+ #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp>
+@@ -23,7 +26,8 @@ using Ifaces = sdbusplus::server::object::object<
+ sdbusplus::xyz::openbmc_project::Network::server::MACAddress,
+ sdbusplus::xyz::openbmc_project::Network::IP::server::Create,
+ sdbusplus::xyz::openbmc_project::Network::Neighbor::server::CreateStatic,
+- sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>;
++ sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll,
++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess>;
+
+ using IP = sdbusplus::xyz::openbmc_project::Network::server::IP;
+
+@@ -31,10 +35,14 @@ using EthernetInterfaceIntf =
+ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
+ using MacAddressIntf =
+ sdbusplus::xyz::openbmc_project::Network::server::MACAddress;
++using ChannelAccessIntf =
++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess;
+
+ using ServerList = std::vector<std::string>;
+ using ObjectPath = sdbusplus::message::object_path;
+
++using DbusVariant = std::variant<std::string, std::vector<std::string>>;
++
+ namespace fs = std::experimental::filesystem;
+
+ class Manager; // forward declaration of network manager.
+@@ -199,6 +208,14 @@ class EthernetInterface : public Ifaces
+ */
+ void deleteAll();
+
++ /** @brief sets the channel maxium privilege.
++ * @param[in] value - Channel privilege which needs to be set on the
++ * system.
++ * @returns privilege of the interface or throws an error.
++ */
++ std::string maxPrivilege(std::string value) override;
++
++ using ChannelAccessIntf::maxPrivilege;
+ using EthernetInterfaceIntf::dHCPEnabled;
+ using EthernetInterfaceIntf::interfaceName;
+ using EthernetInterfaceIntf::linkUp;
+@@ -296,6 +313,26 @@ class EthernetInterface : public Ifaces
+ std::string objPath;
+
+ friend class TestEthernetInterface;
++
++ /** @brief gets the channel privilege.
++ * @param[in] interfaceName - Network interface name.
++ * @returns privilege of the interface
++ */
++ std::string getChannelPrivilege(const std::string& interfaceName);
++
++ /** @brief reads the channel access info from file.
++ * @param[in] configFile - channel access filename
++ * @returns json file data
++ */
++ nlohmann::json readJsonFile(const std::string& configFile);
++
++ /** @brief writes the channel access info to file.
++ * @param[in] configFile - channel access filename
++ * @param[in] jsonData - json data to write
++ * @returns success or failure
++ */
++ int writeJsonFile(const std::string& configFile,
++ const nlohmann::json& jsonData);
+ };
+
+ } // namespace network
+diff --git a/network_manager.cpp b/network_manager.cpp
+index 043d7a2..75f4e5f 100644
+--- a/network_manager.cpp
++++ b/network_manager.cpp
+@@ -34,6 +34,13 @@ extern std::unique_ptr<Timer> restartTimer;
+ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
++static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user";
++static constexpr const char* userMgrInterface =
++ "xyz.openbmc_project.User.Manager";
++static constexpr const char* propNameAllPrivileges = "AllPrivileges";
++
++std::unique_ptr<sdbusplus::bus::match_t> usrMgmtSignal(nullptr);
++
+ Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath,
+ const std::string& path) :
+ details::VLANCreateIface(bus, objPath, true),
+@@ -41,6 +48,101 @@ Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath,
+ {
+ fs::path confDir(path);
+ setConfDir(confDir);
++ initSupportedPrivilges();
++}
++
++std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf,
++ const std::string& path)
++{
++ auto mapperCall =
++ bus.new_method_call("xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject");
++
++ mapperCall.append(path);
++ mapperCall.append(std::vector<std::string>({intf}));
++
++ auto mapperResponseMsg = bus.call(mapperCall);
++
++ std::map<std::string, std::vector<std::string>> mapperResponse;
++ mapperResponseMsg.read(mapperResponse);
++
++ if (mapperResponse.begin() == mapperResponse.end())
++ {
++ throw std::runtime_error("ERROR in reading the mapper response");
++ }
++
++ return mapperResponse.begin()->first;
++}
++
++std::string Manager::getUserServiceName()
++{
++ static std::string userMgmtService;
++ if (userMgmtService.empty())
++ {
++ try
++ {
++ userMgmtService =
++ getUserService(bus, userMgrInterface, userMgrObjBasePath);
++ }
++ catch (const std::exception& e)
++ {
++ log<level::ERR>("Exception caught in getUserServiceName.");
++ userMgmtService.clear();
++ }
++ }
++ return userMgmtService;
++}
++
++void Manager::initSupportedPrivilges()
++{
++ std::string userServiceName = getUserServiceName();
++ if (!userServiceName.empty())
++ {
++ auto method = bus.new_method_call(
++ getUserServiceName().c_str(), userMgrObjBasePath,
++ "org.freedesktop.DBus.Properties", "Get");
++ method.append(userMgrInterface, propNameAllPrivileges);
++
++ auto reply = bus.call(method);
++ if (reply.is_method_error())
++ {
++ log<level::DEBUG>("get-property AllPrivileges failed",
++ entry("OBJPATH:%s", userMgrObjBasePath),
++ entry("INTERFACE:%s", userMgrInterface));
++ return;
++ }
++
++ std::variant<std::vector<std::string>> result;
++ reply.read(result);
++
++ supportedPrivList = std::get<std::vector<std::string>>(result);
++ }
++
++ // Resgister the signal
++ if (usrMgmtSignal == nullptr)
++ {
++ log<level::DEBUG>("Registering User.Manager propertychange signal.");
++ usrMgmtSignal = std::make_unique<sdbusplus::bus::match_t>(
++ bus,
++ sdbusplus::bus::match::rules::propertiesChanged(userMgrObjBasePath,
++ userMgrInterface),
++ [&](sdbusplus::message::message& msg) {
++ log<level::DEBUG>("UserMgr properties changed signal");
++ std::map<std::string, DbusVariant> props;
++ std::string iface;
++ msg.read(iface, props);
++ for (const auto& t : props)
++ {
++ if (t.first == propNameAllPrivileges)
++ {
++ supportedPrivList =
++ std::get<std::vector<std::string>>(t.second);
++ }
++ }
++ });
++ }
++ return;
+ }
+
+ bool Manager::createDefaultNetworkFiles(bool force)
+diff --git a/network_manager.hpp b/network_manager.hpp
+index edb341f..5fb9fe8 100644
+--- a/network_manager.hpp
++++ b/network_manager.hpp
+@@ -137,6 +137,12 @@ class Manager : public details::VLANCreateIface
+ return (interfaces.find(intf) != interfaces.end());
+ }
+
++ /** supported privilege list **/
++ std::vector<std::string> supportedPrivList;
++
++ /** @brief initializes the supportedPrivilege List */
++ void initSupportedPrivilges();
++
+ protected:
+ /** @brief Persistent sdbusplus DBus bus connection. */
+ sdbusplus::bus::bus& bus;
+@@ -159,6 +165,9 @@ class Manager : public details::VLANCreateIface
+
+ /** @brief Network Configuration directory. */
+ fs::path confDir;
++
++ /** Get the user management service name dynamically **/
++ std::string getUserServiceName();
+ };
+
+ } // namespace network
+--
+2.7.4
+
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..1b36e9d77
--- /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,506 @@
+From 8aee963295f7da07ae67aa09c4eba3fbd2a6ff19 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>
+
+%% original patch: 0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch
+---
+ Makefile.am | 1 +
+ configure.ac | 1 +
+ ethernet_interface.cpp | 146 ++++++++++++++++++++++---------
+ 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, 164 insertions(+), 53 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 3bb5e7b..0bbbc8f 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
+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 d6c7bdd..82716f9 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"
+@@ -69,10 +68,12 @@ struct EthernetIntfSocket
+
+ int sock{-1};
+ };
++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)
+@@ -119,6 +120,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();
+@@ -129,7 +189,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;
+ }
+@@ -190,11 +250,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;
+@@ -469,7 +529,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value)
+ return value;
+ }
+
+-bool EthernetInterface::dHCPEnabled(bool value)
++EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value)
+ {
+ if (value == EthernetInterfaceIntf::dHCPEnabled())
+ {
+@@ -685,7 +745,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>(
+@@ -707,7 +767,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();
+@@ -780,8 +841,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
+@@ -855,42 +914,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";
+ }
+ }
+
+@@ -1001,7 +1063,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 6344533..3f7fd31 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -94,7 +94,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 used to load the nameservers.
+@@ -164,7 +164,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);
+
+ /** Retrieve Link State */
+ bool linkUp() const override;
+diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp
+index d0beef7..3e2f9ff 100644
+--- a/test/test_ethernet_interface.cpp
++++ b/test/test_ethernet_interface.cpp
+@@ -59,7 +59,8 @@ class TestEthernetInterface : public testing::Test
+ {
+ mock_clear();
+ mock_addIF("test0", 1, mac);
+- return {bus, "/xyz/openbmc_test/network/test0", false, manager, true};
++ 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.25.2
+
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
new file mode 100644
index 000000000..5774d5318
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend
@@ -0,0 +1,12 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += "nlohmann-json boost"
+
+#todo: Appu, fix nobranch
+SRC_URI = "git://github.com/openbmc/phosphor-networkd;nobranch=1"
+SRC_URI += "file://0003-Adding-channel-specific-privilege-to-network.patch \
+ file://0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch \
+ "
+SRCREV = "d0679f9bb46670c593061c4aaebec2a577cdd5c3"
+
+EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb
new file mode 100644
index 000000000..0dab0fc1a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb
@@ -0,0 +1,24 @@
+SUMMARY = "Enforce static MAC addresses"
+DESCRIPTION = "Set a priority on MAC addresses to run with: \
+ factory-specified > u-boot-specified > random"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+PV = "1.0"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SRC_URI = "\
+ file://mac-check \
+ file://${PN}.service \
+ "
+
+inherit obmc-phosphor-systemd
+
+SYSTEMD_SERVICE_${PN} += "${PN}.service"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/mac-check ${D}${bindir}
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check
new file mode 100644
index 000000000..7e81ad63a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check
@@ -0,0 +1,109 @@
+#!/bin/sh
+# Copyright 2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SOFS_MNT=/var/sofs
+SOFS_MACDIR=${SOFS_MNT}/factory-settings/network/mac
+
+read_hw_mac() {
+ local iface="$1"
+ cat /sys/class/net/"$iface"/address 2>/dev/null
+}
+
+set_hw_mac() {
+ local iface="$1"
+ local mac="$2"
+ ip link show dev "$iface" | grep -q "${iface}:.*\<UP\>" 2>/dev/null
+ local up=$?
+ [[ $up -eq 0 ]] && ip link set dev "$iface" down
+ ip link set dev "$iface" address "$mac"
+ [[ $up -eq 0 ]] && ip link set dev "$iface" up
+}
+
+read_sofs_mac() {
+ local iface="$1"
+ cat "${SOFS_MACDIR}/${iface}" 2>/dev/null
+}
+
+read_fw_env_mac() {
+ local envname="$1"
+ fw_printenv "$envname" 2>/dev/null | sed "s/^$envname=//"
+}
+
+set_fw_env_mac() {
+ local envname="$1"
+ local mac="$2"
+ fw_setenv "$envname" "$mac"
+}
+
+create_macdir() {
+if [ -a ${SOFS_MACDIR} ]; then
+ if [ ! -d ${SOFS_MACDIR} ]; then
+ rm -rf ${SOFS_MACDIR}
+ mkdir -p ${SOFS_MACDIR}
+ fi
+else
+ mkdir -p ${SOFS_MACDIR}
+fi
+return 0
+}
+
+mac_check() {
+ local iface="$1"
+ local envname="$2"
+
+ # Read the MAC address in use by the NIC
+ local hw_mac=$(read_hw_mac "$iface")
+
+ # Read the MAC address stored in the non-volatile file provisioned in
+ # manufacturing.
+ local sofs_mac=$(read_sofs_mac "$iface")
+
+ if [ -n "$sofs_mac" ] && [ "$hw_mac" != "$sofs_mac" ]; then
+ # A factory assigned address was found, and it is newly assigned.
+ # Update the active interface and save the new value to the u-boot
+ # environment.
+ set_hw_mac "$iface" "$sofs_mac"
+ set_fw_env_mac "$envname" "$sofs_mac"
+ return $?
+ elif [ -n "$hw_mac" ]; then
+ # Read the MAC address stored by U-Boot
+ local fw_env_mac=$(read_fw_env_mac "$envname")
+ if [ -z "$fw_env_mac" ] || [ "$fw_env_mac" != "$hw_mac" ]; then
+ set_fw_env_mac "$envname" "$hw_mac"
+ return $?
+ fi
+ else
+ # Could not identify a MAC address
+ return 255
+ fi
+ return 0
+}
+
+create_macdir
+
+error=0
+first_error_seen=0
+
+while read IFACE UBDEV; do
+ mac_check "$IFACE" "$UBDEV"
+ error=$?
+ if [ $error -ne 0 ] && [ $first_error_seen -eq 0 ]; then
+ first_error_seen=$error
+ fi
+done <<-END_CONF
+ eth0 eth1addr
+ eth1 ethaddr
+END_CONF
+exit $first_error_seen
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service
new file mode 100644
index 000000000..86371db11
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Enforce Static MAC addr mapping
+
+[Service]
+Type=oneshot
+Restart=no
+ExecStart=/usr/bin/mac-check
+
+[Install]
+WantedBy=network.target
+