daemon: Reload face_system section of the config file when NIC configuration changes

The main desired effect of the reloading is re-creation of multicast
faces, e.g., when a new interface appears in the system.

Change-Id: I8384e5f96285ddca363981c92e1b6de39e0072ef
Refs: #2460
diff --git a/daemon/nfd.cpp b/daemon/nfd.cpp
index c4d312f..d880ebb 100644
--- a/daemon/nfd.cpp
+++ b/daemon/nfd.cpp
@@ -25,8 +25,10 @@
 
 #include "nfd.hpp"
 
+#include "core/global-io.hpp"
 #include "core/logger-factory.hpp"
 #include "core/privilege-helper.hpp"
+#include "core/config-file.hpp"
 #include "fw/forwarder.hpp"
 #include "face/null-face.hpp"
 #include "mgmt/internal-face.hpp"
@@ -34,23 +36,26 @@
 #include "mgmt/face-manager.hpp"
 #include "mgmt/strategy-choice-manager.hpp"
 #include "mgmt/status-server.hpp"
-#include "core/config-file.hpp"
 #include "mgmt/general-config-section.hpp"
 #include "mgmt/tables-config-section.hpp"
 
 namespace nfd {
 
+NFD_LOG_INIT("Nfd");
+
 static const std::string INTERNAL_CONFIG = "internal://nfd.conf";
 
 Nfd::Nfd(const std::string& configFile, ndn::KeyChain& keyChain)
   : m_configFile(configFile)
   , m_keyChain(keyChain)
+  , m_networkMonitor(getGlobalIoService())
 {
 }
 
 Nfd::Nfd(const ConfigSection& config, ndn::KeyChain& keyChain)
   : m_configSection(config)
   , m_keyChain(keyChain)
+  , m_networkMonitor(getGlobalIoService())
 {
 }
 
@@ -75,6 +80,16 @@
                                           FACEID_CONTENT_STORE);
 
   PrivilegeHelper::drop();
+
+  m_networkMonitor.onNetworkStateChanged.connect([this] {
+      // delay stages, so if multiple events are triggered in short sequence,
+      // only one auto-detection procedure is triggered
+      m_reloadConfigEvent = scheduler::schedule(time::seconds(5),
+        [this] {
+          NFD_LOG_INFO("Network change detected, reloading face section of the config file...");
+          this->reloadConfigFileFaceSection();
+        });
+    });
 }
 
 void
@@ -189,4 +204,19 @@
   }
 }
 
+void
+Nfd::reloadConfigFileFaceSection()
+{
+  // reload only face_system section of the config file to re-initialize multicast faces
+  ConfigFile config(&ConfigFile::ignoreUnknownSection);
+  m_faceManager->setConfigFile(config);
+
+  if (!m_configFile.empty()) {
+    config.parse(m_configFile, false);
+  }
+  else {
+    config.parse(m_configSection, false, INTERNAL_CONFIG);
+  }
+}
+
 } // namespace nfd
diff --git a/daemon/nfd.hpp b/daemon/nfd.hpp
index 92e6efd..4710554 100644
--- a/daemon/nfd.hpp
+++ b/daemon/nfd.hpp
@@ -28,8 +28,10 @@
 
 #include "common.hpp"
 #include "core/config-file.hpp"
+#include "core/scheduler.hpp"
 
 #include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/util/network-monitor.hpp>
 
 namespace nfd {
 
@@ -86,6 +88,9 @@
   void
   initializeManagement();
 
+  void
+  reloadConfigFileFaceSection();
+
 private:
   std::string m_configFile;
   ConfigSection m_configSection;
@@ -99,6 +104,9 @@
   unique_ptr<StatusServer>          m_statusServer;
 
   ndn::KeyChain&                    m_keyChain;
+
+  ndn::util::NetworkMonitor         m_networkMonitor;
+  scheduler::ScopedEventId          m_reloadConfigEvent;
 };
 
 } // namespace nfd