Set static & dhcp sent ntp server ip on ethernet obj

Currently there is no way to differentiate between the Static
and DHCP assigned NTP servers at dbus

This commit adds StaticNTPServers peroperty to hold the static
configuration of NTP servers. This is a read-write property.
The existing NTPServer propery will hold both static and DHCP
assigned NTP servers. This is a read-only property.

The static and dhcp sent ntp server details are present in the
dbus object hosted by systemd-timesyncd service (mentioned in
Tested By section).

In this change, networkd fetches the ntp server details from the
timesyncd dbus object and set the "NTPServers" property with dhcp sent
ip and "StaticNTPServers" will be set from the configuration file.

Tested By:

* Change the ntp server ips in dhcp config file & restart dhcpd
* timesyncd dbus object contains the new list of ips as below:

busctl introspect org.freedesktop.timesync1 /org/freedesktop/timesync1
NAME                                TYPE      SIGNATURE          RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable interface -                  -                                        -
.Introspect                         method    -                  s                                        -
org.freedesktop.DBus.Peer           interface -                  -                                        -
.GetMachineId                       method    -                  s                                        -
.Ping                               method    -                  -                                        -
org.freedesktop.DBus.Properties     interface -                  -                                        -
.Get                                method    ss                 v                                        -
.GetAll                             method    s                  a{sv}                                    -
.Set                                method    ssv                -                                        -
.PropertiesChanged                  signal    sa{sv}as           -                                        -
org.freedesktop.timesync1.Manager   interface -                  -                                        -
.FallbackNTPServers                 property  as                 4 "time1.google.com" "time2.google.com"… const
.Frequency                          property  x                  0                                        -
.LinkNTPServers                     property  as                 1 "1.1.1.1"                              -
.NTPMessage                         property  (uuuuittayttttbtt) 0 0 0 0 0 0 0 4 0 0 0 0 0 1844453508490… emits-change
.PollIntervalMaxUSec                property  t                  2048000000                               const
.PollIntervalMinUSec                property  t                  32000000                                 const
.PollIntervalUSec                   property  t                  2048000000                               -
.RootDistanceMaxUSec                property  t                  5000000                                  const
.ServerAddress                      property  (iay)              2 4 1 1 1 1                              -
.ServerName                         property  s                  "1.1.1.1"                                -
.SystemNTPServers                   property  as                 0                                        const

* Since network configuration has changed, the service restarts and
ntp server details are loaded from timesyncd dbus object & config file,
and are set in dbus objects hosted by networkd.

command: busctl introspect xyz.openbmc_project.Network /xyz/openbmc_project/network/eth0
         busctl introspect xyz.openbmc_project.Network /xyz/openbmc_project/network/eth1

* Ethernet interface network config files will be updated with NTP=<ip addresses> under [Network]

command: cat /etc/systemd/network/00-bmc-eth0.network
         cat /etc/systemd/network/00-bmc-eth1.network

Signed-off-by: Asmitha Karunanithi <asmitk01@in.ibm.com>
Change-Id: If8b1b3ed2afb531f179e00da173f6f86a1bf0c18
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index 632518c..4c31383 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -42,6 +42,11 @@
 constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
 constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
+
+constexpr auto TIMESYNCD_SERVICE = "org.freedesktop.timesync1";
+constexpr auto TIMESYNCD_INTERFACE = "org.freedesktop.timesync1.Manager";
+constexpr auto TIMESYNCD_SERVICE_PATH = "/org/freedesktop/timesync1";
+
 constexpr auto METHOD_GET = "Get";
 
 static stdplus::Fd& getIFSock()
@@ -767,6 +772,13 @@
     return EthernetInterfaceIntf::staticNameServers();
 }
 
+void EthernetInterface::loadNTPServers(const config::Parser& config)
+{
+    EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd());
+    EthernetInterfaceIntf::staticNTPServers(
+        config.map.getValueStrings("Network", "NTP"));
+}
+
 void EthernetInterface::loadNameServers(const config::Parser& config)
 {
     EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
@@ -774,6 +786,30 @@
         config.map.getValueStrings("Network", "DNS"));
 }
 
+ServerList EthernetInterface::getNTPServerFromTimeSyncd()
+{
+    ServerList servers; // Variable to capture the NTP Server IPs
+    auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH,
+                                      PROPERTY_INTERFACE, METHOD_GET);
+
+    method.append(TIMESYNCD_INTERFACE, "LinkNTPServers");
+
+    try
+    {
+        auto reply = bus.call(method);
+        std::variant<ServerList> response;
+        reply.read(response);
+        servers = std::get<ServerList>(response);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        log<level::ERR>(
+            "Failed to get NTP server information from Systemd-Timesyncd");
+    }
+
+    return servers;
+}
+
 ServerList EthernetInterface::getNameServerFromResolvd()
 {
     ServerList servers;
@@ -881,6 +917,7 @@
     vlanIntf->createIPAddressObjects();
     vlanIntf->createStaticNeighborObjects();
     vlanIntf->loadNameServers(config);
+    vlanIntf->loadNTPServers(config);
 
     this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
                                  std::move(vlanIntf));
@@ -917,14 +954,25 @@
     return path;
 }
 
-ServerList EthernetInterface::ntpServers(ServerList servers)
+ServerList EthernetInterface::staticNTPServers(ServerList value)
 {
-    auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);
+    try
+    {
+        EthernetInterfaceIntf::staticNTPServers(value);
 
-    writeConfigurationFile();
-    manager.reloadConfigs();
+        writeConfigurationFile();
+        manager.reloadConfigs();
+    }
+    catch (InternalFailure& e)
+    {
+        log<level::ERR>("Exception processing NTP entries");
+    }
+    return EthernetInterfaceIntf::staticNTPServers();
+}
 
-    return ntpServers;
+ServerList EthernetInterface::ntpServers(ServerList /*servers*/)
+{
+    elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
 }
 // Need to merge the below function with the code which writes the
 // config file during factory reset.
@@ -974,7 +1022,7 @@
         }
         {
             auto& ntps = network["NTP"];
-            for (const auto& ntp : EthernetInterfaceIntf::ntpServers())
+            for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers())
             {
                 ntps.emplace_back(ntp);
             }
diff --git a/src/ethernet_interface.hpp b/src/ethernet_interface.hpp
index 578fc5b..a4b127c 100644
--- a/src/ethernet_interface.hpp
+++ b/src/ethernet_interface.hpp
@@ -79,6 +79,10 @@
                       bool emitSignal = true,
                       std::optional<bool> enabled = std::nullopt);
 
+    /** @brief Function used to load the ntpservers
+     */
+    void loadNTPServers(const config::Parser& config);
+
     /** @brief Function used to load the nameservers.
      */
     void loadNameServers(const config::Parser& config);
@@ -181,6 +185,11 @@
      */
     ServerList ntpServers(ServerList value) override;
 
+    /** @brief sets the static NTP servers.
+     *  @param[in] value - vector of NTP servers.
+     */
+    ServerList staticNTPServers(ServerList value) override;
+
     /** @brief sets the Static DNS/nameservers.
      *  @param[in] value - vector of DNS servers.
      */
@@ -255,10 +264,10 @@
         generateStaticNeighborObjectPath(std::string_view ipAddress,
                                          std::string_view macAddress) const;
 
-    /** @brief get the NTP server list from the network conf
+    /** @brief get the NTP server list from the timsyncd dbus obj
      *
      */
-    ServerList getNTPServersFromConf();
+    virtual ServerList getNTPServerFromTimeSyncd();
 
     /** @brief get the name server details from the network conf
      *
diff --git a/src/network_manager.cpp b/src/network_manager.cpp
index f959a69..25b9c05 100644
--- a/src/network_manager.cpp
+++ b/src/network_manager.cpp
@@ -151,6 +151,7 @@
         intf->createIPAddressObjects();
         intf->createStaticNeighborObjects();
         intf->loadNameServers(config);
+        intf->loadNTPServers(config);
 
         this->interfaces.emplace(std::move(interface), std::move(intf));
     }