Configure DHCP4 and DHCP6 parameters independently

At present, DHCP parameters like DNSEnabled, NTPEnabled etc. are
shared between DHCPv4 and DHCPv6 in the network configuration.

Hence any update on the ipv4 parameters impacts the ipv6 and get
applied to both the interfaces.

This change is to enable the possibility to configure DHCP attributes
independently, by having different dbus objects for dhcp4 and dhcp6
and moving the dhcp configuration from network level to ethernet
interface.

tested by:

Used the busctl command to set and get the parameter values
individually for both DHCPv4 and DHCPv6.
Verified the network configuration file is updated accordingly

Tree Structure:
busctl tree xyz.openbmc_project.Network
`-/xyz
  `-/xyz/openbmc_project
    `-/xyz/openbmc_project/network
      |-/xyz/openbmc_project/network/config
      |-/xyz/openbmc_project/network/eth0
      | |-/xyz/openbmc_project/network/eth0/dhcp4
      | `-/xyz/openbmc_project/network/eth0/dhcp6
      `-/xyz/openbmc_project/network/eth1
        |-/xyz/openbmc_project/network/eth1/dhcp4
        `-/xyz/openbmc_project/network/eth1/dhcp6

Change-Id: If7dbbf596bdaf866ea459d631e716153f54302ec
Signed-off-by: Jishnu CM <jishnunambiarcm@duck.com>
diff --git a/src/dhcp_configuration.cpp b/src/dhcp_configuration.cpp
index c649568..04a56a0 100644
--- a/src/dhcp_configuration.cpp
+++ b/src/dhcp_configuration.cpp
@@ -2,7 +2,6 @@
 
 #include "config_parser.hpp"
 #include "network_manager.hpp"
-#include "util.hpp"
 
 #include <sys/stat.h>
 
@@ -24,15 +23,16 @@
 
 Configuration::Configuration(sdbusplus::bus_t& bus,
                              stdplus::const_zstring objPath,
-                             stdplus::PinnedRef<Manager> parent) :
+                             stdplus::PinnedRef<EthernetInterface> parent,
+                             DHCPType type) :
     Iface(bus, objPath.c_str(), Iface::action::defer_emit),
-    manager(parent)
+    parent(parent), type(type)
 {
     config::Parser conf;
     std::filesystem::directory_entry newest_file;
     time_t newest_time = 0;
-    for (const auto& dirent :
-         std::filesystem::directory_iterator(manager.get().getConfDir()))
+    for (const auto& dirent : std::filesystem::directory_iterator(
+             parent.get().manager.get().getConfDir()))
     {
         struct stat st = {};
         stat(dirent.path().native().c_str(), &st);
@@ -49,10 +49,15 @@
         conf.setFile(newest_file.path());
     }
 
-    ConfigIntf::dnsEnabled(getDHCPProp(conf, "UseDNS"), true);
-    ConfigIntf::ntpEnabled(getDHCPProp(conf, "UseNTP"), true);
-    ConfigIntf::hostNameEnabled(getDHCPProp(conf, "UseHostname"), true);
-    ConfigIntf::sendHostNameEnabled(getDHCPProp(conf, "SendHostname"), true);
+    ConfigIntf::dnsEnabled(getDHCPProp(conf, type, "UseDNS"), true);
+    ConfigIntf::ntpEnabled(getDHCPProp(conf, type, "UseNTP"), true);
+    ConfigIntf::hostNameEnabled(getDHCPProp(conf, type, "UseHostname"), true);
+    if (type == DHCPType::v4)
+    {
+        ConfigIntf::sendHostNameEnabled(getDHCPProp(conf, type, "SendHostname"),
+                                        true);
+    }
+
     emit_object_added();
 }
 
@@ -64,10 +69,8 @@
     }
 
     auto name = ConfigIntf::sendHostNameEnabled(value);
-
-    manager.get().writeToConfigurationFile();
-    manager.get().reloadConfigs();
-
+    parent.get().writeConfigurationFile();
+    parent.get().reloadConfigs();
     return name;
 }
 
@@ -79,8 +82,8 @@
     }
 
     auto name = ConfigIntf::hostNameEnabled(value);
-    manager.get().writeToConfigurationFile();
-    manager.get().reloadConfigs();
+    parent.get().writeConfigurationFile();
+    parent.get().reloadConfigs();
 
     return name;
 }
@@ -93,8 +96,8 @@
     }
 
     auto ntp = ConfigIntf::ntpEnabled(value);
-    manager.get().writeToConfigurationFile();
-    manager.get().reloadConfigs();
+    parent.get().writeConfigurationFile();
+    parent.get().reloadConfigs();
 
     return ntp;
 }
@@ -107,8 +110,8 @@
     }
 
     auto dns = ConfigIntf::dnsEnabled(value);
-    manager.get().writeToConfigurationFile();
-    manager.get().reloadConfigs();
+    parent.get().writeConfigurationFile();
+    parent.get().reloadConfigs();
 
     return dns;
 }
diff --git a/src/dhcp_configuration.hpp b/src/dhcp_configuration.hpp
index 964b7d5..95aa203 100644
--- a/src/dhcp_configuration.hpp
+++ b/src/dhcp_configuration.hpp
@@ -1,4 +1,6 @@
 #pragma once
+#include "util.hpp"
+
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/object.hpp>
 #include <stdplus/pinned.hpp>
@@ -10,7 +12,7 @@
 namespace network
 {
 
-class Manager; // forward declaration of network manager.
+class EthernetInterface;
 
 namespace dhcp
 {
@@ -32,9 +34,10 @@
      *  @param[in] bus - Bus to attach to.
      *  @param[in] objPath - Path to attach at.
      *  @param[in] parent - Parent object.
+     *  @param[in] type - Network type.
      */
     Configuration(sdbusplus::bus_t& bus, stdplus::const_zstring objPath,
-                  stdplus::PinnedRef<Manager> parent);
+                  stdplus::PinnedRef<EthernetInterface> parent, DHCPType type);
 
     /** @brief If true then DNS servers received from the DHCP server
      *         will be used and take precedence over any statically
@@ -66,7 +69,7 @@
      */
     bool sendHostNameEnabled(bool value) override;
 
-    /* @brief Network Manager needed the below function to know the
+    /* @brief Ethernet Interface needed the below function to know the
      *        value of the properties (ntpEnabled,dnsEnabled,hostnameEnabled
               sendHostNameEnabled).
      *
@@ -77,8 +80,9 @@
     using ConfigIntf::sendHostNameEnabled;
 
   private:
-    /** @brief Network Manager object. */
-    stdplus::PinnedRef<Manager> manager;
+    /** @brief Ethernet Interface object. */
+    stdplus::PinnedRef<EthernetInterface> parent;
+    DHCPType type;
 };
 
 } // namespace dhcp
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index bac778f..65ea7ac 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -118,6 +118,7 @@
     {
         EthernetInterface::defaultGateway6(stdplus::toStr(*info.defgw6), true);
     }
+    addDHCPConfigurations();
     emit_object_added();
 
     if (info.intf.vlan_id)
@@ -753,17 +754,27 @@
         }
     }
     {
-        auto& dhcp = config.map["DHCP"].emplace_back();
-        dhcp["ClientIdentifier"].emplace_back("mac");
-        const auto& conf = manager.get().getDHCPConf();
+        auto& dhcp4 = config.map["DHCPv4"].emplace_back();
+        dhcp4["ClientIdentifier"].emplace_back("mac");
+        const auto& conf = *dhcpConfigs[static_cast<int>(DHCPType::v4)];
         auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
-        dhcp["UseDNS"].emplace_back(dns_enabled);
-        dhcp["UseDomains"].emplace_back(dns_enabled);
-        dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
-        dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
-                                                                : "false");
-        dhcp["SendHostname"].emplace_back(conf.sendHostNameEnabled() ? "true"
-                                                                     : "false");
+        dhcp4["UseDNS"].emplace_back(dns_enabled);
+        dhcp4["UseDomains"].emplace_back(dns_enabled);
+        dhcp4["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
+        dhcp4["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
+                                                                 : "false");
+        dhcp4["SendHostname"].emplace_back(
+            conf.sendHostNameEnabled() ? "true" : "false");
+    }
+    {
+        auto& dhcp6 = config.map["DHCPv6"].emplace_back();
+        const auto& conf = *dhcpConfigs[static_cast<int>(DHCPType::v6)];
+        auto dns_enabled = conf.dnsEnabled() ? "true" : "false";
+        dhcp6["UseDNS"].emplace_back(dns_enabled);
+        dhcp6["UseDomains"].emplace_back(dns_enabled);
+        dhcp6["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false");
+        dhcp6["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true"
+                                                                 : "false");
     }
     auto path = config::pathForIntfConf(manager.get().getConfDir(),
                                         interfaceName());
@@ -957,5 +968,18 @@
     eth.get().manager.get().reloadConfigs();
 }
 
+void EthernetInterface::addDHCPConfigurations()
+{
+    this->dhcpConfigs.emplace_back(std::make_unique<dhcp::Configuration>(
+        bus, objPath + "/dhcp4", *this, DHCPType::v4));
+    this->dhcpConfigs.emplace_back(std::make_unique<dhcp::Configuration>(
+        bus, objPath + "/dhcp6", *this, DHCPType::v6));
+}
+
+void EthernetInterface::reloadConfigs()
+{
+    manager.get().reloadConfigs();
+}
+
 } // namespace network
 } // namespace phosphor
diff --git a/src/ethernet_interface.hpp b/src/ethernet_interface.hpp
index 7f3771e..f41a381 100644
--- a/src/ethernet_interface.hpp
+++ b/src/ethernet_interface.hpp
@@ -1,4 +1,5 @@
 #pragma once
+#include "dhcp_configuration.hpp"
 #include "ipaddress.hpp"
 #include "neighbor.hpp"
 #include "types.hpp"
@@ -8,6 +9,7 @@
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/object.hpp>
 #include <stdplus/pinned.hpp>
+#include <stdplus/str/maps.hpp>
 #include <stdplus/zstring_view.hpp>
 #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp>
 #include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
@@ -202,6 +204,10 @@
      */
     std::string defaultGateway6(std::string gateway) override;
 
+    /** @brief Function to reload network configurations.
+     */
+    void reloadConfigs();
+
     using EthernetInterfaceIntf::interfaceName;
     using EthernetInterfaceIntf::linkUp;
     using EthernetInterfaceIntf::mtu;
@@ -256,6 +262,14 @@
      *  @returns true/false value if the address is static
      */
     bool originIsManuallyAssigned(IP::AddressOrigin origin);
+
+    /** @brief Function to add DHCP configurations.
+     */
+    void addDHCPConfigurations();
+
+    /** @brief Map of DHCP conf objects.
+     */
+    std::vector<std::unique_ptr<dhcp::Configuration>> dhcpConfigs;
 };
 
 } // namespace network
diff --git a/src/network_manager.cpp b/src/network_manager.cpp
index 5f4a89f..089e0e7 100644
--- a/src/network_manager.cpp
+++ b/src/network_manager.cpp
@@ -154,8 +154,6 @@
     std::filesystem::create_directories(confDir);
     systemConf = std::make_unique<phosphor::network::SystemConfiguration>(
         bus, (this->objPath / "config").str);
-    dhcpConf = std::make_unique<phosphor::network::dhcp::Configuration>(
-        bus, (this->objPath / "dhcp").str, *this);
 }
 
 void Manager::createInterface(const AllIntfInfo& info, bool enabled)
diff --git a/src/util.cpp b/src/util.cpp
index 3e1916a..edee79a 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -212,9 +212,17 @@
         .value_or(DHCPVal{.v4 = true, .v6 = true});
 }
 
-bool getDHCPProp(const config::Parser& config, std::string_view key)
+bool getDHCPProp(const config::Parser& config, DHCPType dhcpType,
+                 std::string_view key)
 {
-    return systemdParseLast(config, "DHCP", key, config::parseBool)
+    std::string_view type = (dhcpType == DHCPType::v4) ? "DHCPv4" : "DHCPv6";
+
+    if (!config.map.contains(type))
+    {
+        type = "DHCP";
+    }
+
+    return systemdParseLast(config, type, key, config::parseBool)
         .value_or(true);
 }
 
diff --git a/src/util.hpp b/src/util.hpp
index a1742fa..ae34ad6 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -55,13 +55,22 @@
 {
     bool v4, v6;
 };
+
+enum class DHCPType
+{
+    v4,
+    v6
+};
+
 DHCPVal getDHCPValue(const config::Parser& config);
 
 /** @brief Read a boolean DHCP property from a conf file
  *  @param[in] config - The parsed configuration.
+ *  @param[in] nwType - The network type.
  *  @param[in] key - The property name.
  */
-bool getDHCPProp(const config::Parser& config, std::string_view key);
+bool getDHCPProp(const config::Parser& config, DHCPType dhcpType,
+                 std::string_view key);
 
 namespace internal
 {