Reduce the number of restarts of systemd-networkd

Start the timer once we get the dbus request and wait for timeout
if we get the dbus request in meanwhile, reset the timer and
wait for timeout.

Listen for ipv6 rtnetlink address also.

Resolves openbmc/openbmc#2227

Change-Id: I3f448e84107826defafb9ada523c1ab08ec1b971
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/network_manager.cpp b/network_manager.cpp
index bb6d204..e9d8ad9 100644
--- a/network_manager.cpp
+++ b/network_manager.cpp
@@ -25,7 +25,8 @@
 namespace network
 {
 
-extern std::unique_ptr<phosphor::network::Timer> refreshTimer;
+extern std::unique_ptr<phosphor::network::Timer> refreshObjectTimer;
+extern std::unique_ptr<phosphor::network::Timer> restartTimer;
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 
@@ -201,20 +202,24 @@
         intf.second->writeConfigurationFile();
 
     }
-    restartNetwork();
+    restartTimers();
 }
 
-void Manager::restartNetwork()
+void Manager::restartTimers()
 {
     using namespace std::chrono;
-
-    if (refreshTimer && !refreshTimer->isExpired())
+    if (refreshObjectTimer && restartTimer)
     {
-        auto time =  duration_cast<microseconds>(
-                        phosphor::network::networkChangeTimeout);
-        refreshTimer->startTimer(time);
+        // start the restart timer.
+        auto restartTime = duration_cast<microseconds>(
+                phosphor::network::restartTimeout);
+        restartTimer->startTimer(restartTime);
+
+        // start the refresh timer.
+        auto refreshTime =  duration_cast<microseconds>(
+                phosphor::network::refreshTimeout);
+        refreshObjectTimer->startTimer(refreshTime);
     }
-    restartSystemdUnit("systemd-networkd.service");
 }
 
 }//namespace network
diff --git a/network_manager.hpp b/network_manager.hpp
index 70ed8fc..7685ba8 100644
--- a/network_manager.hpp
+++ b/network_manager.hpp
@@ -103,8 +103,8 @@
          */
         bool createDefaultNetworkFiles(bool force);
 
-        /** @brief restart the systemd networkd. */
-        void restartNetwork();
+        /** @brief restart the network timers. */
+        void restartTimers();
 
     private:
         /** @brief Persistent sdbusplus DBus bus connection. */
diff --git a/network_manager_main.cpp b/network_manager_main.cpp
index 969b705..0c95c8d 100644
--- a/network_manager_main.cpp
+++ b/network_manager_main.cpp
@@ -15,25 +15,47 @@
 {
 
 std::unique_ptr<phosphor::network::Manager> manager = nullptr;
-std::unique_ptr<phosphor::network::Timer> refreshTimer = nullptr;
+std::unique_ptr<phosphor::network::Timer> refreshObjectTimer = nullptr;
+std::unique_ptr<phosphor::network::Timer> restartTimer = nullptr;
 
+/** @brief refresh the network objects. */
 void refreshObjects()
 {
-    manager->createChildObjects();
+    if (manager)
+    {
+        manager->createChildObjects();
+    }
+}
+
+/** @brief restart the systemd networkd. */
+void restartNetwork()
+{
+    restartSystemdUnit("systemd-networkd.service");
 }
 
 } //namespace network
 } //namespace phosphor
 
+void initializeTimers()
+{
+    std::function<void()> refreshFunc(
+            std::bind(&phosphor::network::refreshObjects));
+
+    std::function<void()> restartFunc(
+            std::bind(&phosphor::network::restartNetwork));
+
+    phosphor::network::refreshObjectTimer =
+        std::make_unique<phosphor::network::Timer>(refreshFunc);
+
+    phosphor::network::restartTimer =
+        std::make_unique<phosphor::network::Timer>(restartFunc);
+}
+
 int main(int argc, char *argv[])
 {
     using namespace phosphor::logging;
 
-    std::function<void()> func(
-            std::bind(&phosphor::network::refreshObjects));
-
-    phosphor::network::refreshTimer =
-        std::make_unique<phosphor::network::Timer>(func);
+    initializeTimers();
 
     auto bus = sdbusplus::bus::new_default();
 
@@ -75,7 +97,7 @@
         // if files created restart the network.
         // don't need to call the create child objects as eventhandler
         // will create it.
-        phosphor::network::manager->restartNetwork();
+        phosphor::network::restartNetwork();
     }
     return svr.run();
 }
diff --git a/rtnetlink_server.cpp b/rtnetlink_server.cpp
index 91e9947..31dbfd1 100644
--- a/rtnetlink_server.cpp
+++ b/rtnetlink_server.cpp
@@ -21,7 +21,7 @@
 namespace network
 {
 
-extern std::unique_ptr<phosphor::network::Timer> refreshTimer;
+extern std::unique_ptr<phosphor::network::Timer> refreshObjectTimer;
 
 namespace rtnetlink
 {
@@ -46,13 +46,13 @@
             {
                 // starting the timer here to make sure that we don't want
                 // create the child objects multiple times.
-                if (refreshTimer->isExpired())
+                if (refreshObjectTimer->isExpired())
                 {
                     using namespace std::chrono;
-                    auto time = duration_cast<microseconds>(networkChangeTimeout);
+                    auto time = duration_cast<microseconds>(refreshTimeout);
                     // if start timer throws exception then let the application
                     // crash
-                    refreshTimer->startTimer(time);
+                    refreshObjectTimer->startTimer(time);
                 } // end if
             } // end if
 
@@ -63,7 +63,6 @@
     return 0;
 }
 
-
 int Server::run()
 {
     using namespace phosphor::logging;
@@ -118,7 +117,7 @@
 
     memset(&addr, 0, sizeof(addr));
     addr.nl_family = AF_NETLINK;
-    addr.nl_groups = RTMGRP_IPV4_IFADDR;
+    addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
 
     if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
     {
diff --git a/test/test_network_manager.cpp b/test/test_network_manager.cpp
index 6281081..8413c01 100644
--- a/test/test_network_manager.cpp
+++ b/test/test_network_manager.cpp
@@ -21,7 +21,9 @@
 namespace network
 {
 
-std::unique_ptr<phosphor::network::Timer> refreshTimer = nullptr;
+std::unique_ptr<phosphor::network::Timer> refreshObjectTimer = nullptr;
+std::unique_ptr<phosphor::network::Timer> restartTimer = nullptr;
+
 namespace fs = std::experimental::filesystem;
 
 class TestNetworkManager : public testing::Test
diff --git a/types.hpp b/types.hpp
index f180ece..3fcbe2e 100644
--- a/types.hpp
+++ b/types.hpp
@@ -17,7 +17,13 @@
 {
 
 using namespace std::chrono_literals;
-constexpr auto networkChangeTimeout = 1s;
+
+// wait for three seconds before restarting the networkd
+constexpr auto restartTimeout = 3s;
+
+// refresh the objets after five seconds as network
+// configuration takes 3-4 sec after systemd-networkd restart.
+constexpr auto refreshTimeout = restartTimeout + 5s;
 
 namespace systemd
 {