route: Refresh FIB entries independently of routing table calculation

refs: #2778

Change-Id: I3536faa9c097152bfb99ebc0270221ca359cba35
diff --git a/src/route/face-map.hpp b/src/route/face-map.hpp
index cbf1f18..9505229 100644
--- a/src/route/face-map.hpp
+++ b/src/route/face-map.hpp
@@ -18,11 +18,11 @@
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
  **/
+
 #ifndef NLSR_FACE_MAP_HPP
 #define NLSR_FACE_MAP_HPP
 
-#include <ndn-cxx/common.hpp>
-#include <algorithm>
+#include "common.hpp"
 
 #include <map>
 
@@ -118,4 +118,4 @@
 
 } // namespace nlsr
 
-#endif //NLSR_FACE_MAP_HPP
+#endif // NLSR_FACE_MAP_HPP
diff --git a/src/route/fib-entry.cpp b/src/route/fib-entry.cpp
index 2a6f495..ccbb887 100644
--- a/src/route/fib-entry.cpp
+++ b/src/route/fib-entry.cpp
@@ -16,13 +16,9 @@
  *
  * You should have received a copy of the GNU General Public License along with
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * \author A K M Mahmudul Hoque <ahoque1@memphis.edu>
- *
  **/
-#include <list>
+
 #include "fib-entry.hpp"
-#include "nexthop.hpp"
 #include "logger.hpp"
 
 namespace nlsr {
@@ -35,7 +31,6 @@
 FibEntry::writeLog()
 {
   _LOG_DEBUG("Name Prefix: " << m_name);
-  _LOG_DEBUG("Time to Refresh: " << m_expirationTimePoint);
   _LOG_DEBUG("Seq No: " << m_seqNo);
   m_nexthopList.writeLog();
 }
diff --git a/src/route/fib-entry.hpp b/src/route/fib-entry.hpp
index 4ade88d..f43ddb1 100644
--- a/src/route/fib-entry.hpp
+++ b/src/route/fib-entry.hpp
@@ -16,21 +16,13 @@
  *
  * You should have received a copy of the GNU General Public License along with
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * \author A K M Mahmudul Hoque <ahoque1@memphis.edu>
- *
  **/
+
 #ifndef NLSR_FIB_ENTRY_HPP
 #define NLSR_FIB_ENTRY_HPP
 
-#include <list>
-#include <iostream>
-#include <boost/cstdint.hpp>
-
 #include <ndn-cxx/util/scheduler.hpp>
-#include <ndn-cxx/util/time.hpp>
 
-#include "nexthop.hpp"
 #include "nexthop-list.hpp"
 
 namespace nlsr {
@@ -40,15 +32,13 @@
 public:
   FibEntry()
     : m_name()
-    , m_expirationTimePoint()
-    , m_seqNo(0)
+    , m_seqNo(1)
     , m_nexthopList()
   {
   }
 
   FibEntry(const ndn::Name& name)
-    : m_expirationTimePoint()
-    , m_seqNo(0)
+    : m_seqNo(1)
     , m_nexthopList()
   {
     m_name = name;
@@ -66,28 +56,16 @@
     return m_nexthopList;
   }
 
-  const ndn::time::system_clock::TimePoint&
-  getExpirationTimePoint() const
-  {
-    return m_expirationTimePoint;
-  }
-
   void
-  setExpirationTimePoint(const ndn::time::system_clock::TimePoint& ttr)
+  setRefreshEventId(ndn::EventId id)
   {
-    m_expirationTimePoint = ttr;
-  }
-
-  void
-  setExpiringEventId(ndn::EventId feid)
-  {
-    m_expiringEventId = feid;
+    m_refreshEventId = id;
   }
 
   ndn::EventId
-  getExpiringEventId() const
+  getRefreshEventId() const
   {
-    return m_expiringEventId;
+    return m_refreshEventId;
   }
 
   void
@@ -97,7 +75,7 @@
   }
 
   int32_t
-  getSeqNo()
+  getSeqNo() const
   {
     return m_seqNo;
   }
@@ -105,14 +83,33 @@
   void
   writeLog();
 
+  typedef NexthopList::const_iterator const_iterator;
+
+  const_iterator
+  begin() const;
+
+  const_iterator
+  end() const;
+
 private:
   ndn::Name m_name;
-  ndn::time::system_clock::TimePoint m_expirationTimePoint;
-  ndn::EventId m_expiringEventId;
+  ndn::EventId m_refreshEventId;
   int32_t m_seqNo;
   NexthopList m_nexthopList;
 };
 
+inline FibEntry::const_iterator
+FibEntry::begin() const
+{
+  return m_nexthopList.cbegin();
+}
+
+inline FibEntry::const_iterator
+FibEntry::end() const
+{
+  return m_nexthopList.cend();
+}
+
 } // namespace nlsr
 
-#endif //NLSR_FIB_ENTRY_HPP
+#endif // NLSR_FIB_ENTRY_HPP
diff --git a/src/route/fib.cpp b/src/route/fib.cpp
index 5de9929..7c14d78 100644
--- a/src/route/fib.cpp
+++ b/src/route/fib.cpp
@@ -17,19 +17,15 @@
  * You should have received a copy of the GNU General Public License along with
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  **/
-#include <map>
 
-#include <cmath>
-#include <ndn-cxx/common.hpp>
-#include <ndn-cxx/encoding/nfd-constants.hpp>
-
-#include "adjacency-list.hpp"
-#include "common.hpp"
-#include "conf-parameter.hpp"
-#include "nexthop-list.hpp"
-#include "face-map.hpp"
 #include "fib.hpp"
+#include "adjacency-list.hpp"
+#include "conf-parameter.hpp"
 #include "logger.hpp"
+#include "nexthop-list.hpp"
+
+#include <map>
+#include <cmath>
 
 namespace nlsr {
 
@@ -41,22 +37,6 @@
 using namespace ndn;
 
 void
-Fib::cancelScheduledExpiringEvent(EventId eid)
-{
-  m_scheduler.cancelEvent(eid);
-}
-
-ndn::EventId
-Fib::scheduleEntryExpiration(const ndn::Name& name, int32_t feSeqNum,
-                             const ndn::time::seconds& expTime)
-{
-  _LOG_DEBUG("Fib::scheduleEntryExpiration Called");
-  _LOG_INFO("Name: " << name << " Seq Num: " << feSeqNum);
-
-  return m_scheduler.scheduleEvent(expTime, std::bind(&Fib::remove, this, name));
-}
-
-void
 Fib::remove(const ndn::Name& name)
 {
   _LOG_DEBUG("Fib::remove called");
@@ -70,8 +50,7 @@
         unregisterPrefix((it->second).getName(), nhit->getConnectingFaceUri());
       }
     }
-    _LOG_DEBUG("Cancelling Scheduled event. Name: " << name);
-    cancelScheduledExpiringEvent((it->second).getExpiringEventId());
+    cancelEntryRefresh(it->second);
     m_table.erase(it);
   }
 }
@@ -142,6 +121,18 @@
 void
 Fib::update(const ndn::Name& name, NexthopList& allHops)
 {
+  FibEntry* entry = processUpdate(name, allHops);
+  if (entry != nullptr && !entry->getRefreshEventId()) {
+    scheduleEntryRefresh(*entry,
+                         [this] (FibEntry& fibEntry) {
+                           this->scheduleLoop(fibEntry);
+                         });
+  }
+}
+
+FibEntry*
+Fib::processUpdate(const ndn::Name& name, NexthopList& allHops)
+{
   _LOG_DEBUG("Fib::update called");
 
   // Get the max possible faces which is the minumum of the configuration setting and
@@ -153,63 +144,44 @@
 
   // Create a list of next hops to be installed with length == maxFaces
   for (NexthopList::iterator it = allHops.begin(); it != allHops.end() && nFaces < maxFaces;
-       ++it, ++nFaces)
-  {
+       ++it, ++nFaces) {
     hopsToAdd.addNextHop(*it);
   }
 
   std::map<ndn::Name, FibEntry>::iterator entryIt = m_table.find(name);
 
-  // New FIB entry
-  if (entryIt == m_table.end()) {
+  // New FIB entry that has nextHops
+  if (entryIt == m_table.end() && hopsToAdd.getSize() != 0) {
     _LOG_DEBUG("New FIB Entry");
 
-    // Don't create an entry for a name with no nexthops
-    if (hopsToAdd.getSize() == 0) {
-      return;
-    }
-
     FibEntry entry(name);
 
     addNextHopsToFibEntryAndNfd(entry, hopsToAdd);
 
-    // Set entry's expiration time point and sequence number
-    entry.setExpirationTimePoint(ndn::time::system_clock::now() +
-                                  ndn::time::seconds(m_refreshTime));
-    entry.setSeqNo(1);
-
-    // Schedule entry to be refreshed
-    entry.setExpiringEventId(scheduleEntryExpiration(name , entry.getSeqNo(),
-                                                     ndn::time::seconds(m_refreshTime)));
     m_table.emplace(name, entry);
+
+    return &m_table.find(name)->second;
   }
+  // Existing FIB entry that may or may not have nextHops
   else {
     // Existing FIB entry
     _LOG_DEBUG("Existing FIB Entry");
-    FibEntry& entry = (entryIt->second);
 
     // Remove empty FIB entry
     if (hopsToAdd.getSize() == 0) {
       remove(name);
-      return;
+      return nullptr;
     }
 
+    FibEntry& entry = (entryIt->second);
     addNextHopsToFibEntryAndNfd(entry, hopsToAdd);
 
     removeOldNextHopsFromFibEntryAndNfd(entry, hopsToAdd);
 
-    // Set entry's expiration time point
-    entry.setExpirationTimePoint(ndn::time::system_clock::now() +
-                                  ndn::time::seconds(m_refreshTime));
     // Increment sequence number
     entry.setSeqNo(entry.getSeqNo() + 1);
 
-    // Cancel previously scheduled event
-    m_scheduler.cancelEvent(entry.getExpiringEventId());
-
-    // Schedule entry to be refreshed
-    entry.setExpiringEventId(scheduleEntryExpiration(name , entry.getSeqNo(),
-                                                     ndn::time::seconds(m_refreshTime)));
+    return &(m_table.find(name)->second);
   }
 }
 
@@ -220,8 +192,8 @@
   for (std::map<ndn::Name, FibEntry>::iterator it = m_table.begin();
        it != m_table.end();
        ++it) {
-    _LOG_DEBUG("Cancelling Scheduled event. Name: " << (it->second).getName());
-    cancelScheduledExpiringEvent((it->second).getExpiringEventId());
+    _LOG_DEBUG("Cancelling Scheduled event. Name: " << it->second.getName());
+    cancelEntryRefresh(it->second);
     for (std::set<NextHop, NextHopComparator>::iterator nhit =
          (it->second).getNexthopList().getNextHops().begin();
          nhit != (it->second).getNexthopList().getNextHops().end(); nhit++) {
@@ -259,21 +231,6 @@
 }
 
 void
-Fib::removeHop(NexthopList& nl, const std::string& doNotRemoveHopFaceUri,
-               const ndn::Name& name)
-{
-  for (std::set<NextHop, NextHopComparator>::iterator it = nl.getNextHops().begin();
-       it != nl.getNextHops().end();   ++it) {
-    if (it->getConnectingFaceUri() != doNotRemoveHopFaceUri) {
-      //Remove FIB Entry from NDN-FIB
-      if (isPrefixUpdatable(name)) {
-        unregisterPrefix(name, it->getConnectingFaceUri());
-      }
-    }
-  }
-}
-
-void
 Fib::createFace(const std::string& faceUri,
                 const CommandSucceedCallback& onSuccess,
                 const CommandFailCallback& onFailure)
@@ -364,7 +321,7 @@
                          uint8_t times)
 {
   m_controller.start<ndn::nfd::RibRegisterCommand>(parameters,
-                                                   std::bind(&Fib::onRegistration, this, _1,
+                                                   std::bind(&Fib::onRegistrationSuccess, this, _1,
                                                              "Successful in name registration",
                                                              faceUri),
                                                    std::bind(&Fib::onRegistrationFailure,
@@ -406,11 +363,11 @@
       .setFaceId(faceId)
       .setOrigin(ndn::nfd::ROUTE_ORIGIN_NLSR);
     m_controller.start<ndn::nfd::RibUnregisterCommand>(controlParameters,
-                                                     std::bind(&Fib::onUnregistration, this, _1,
-                                                               "Successful in unregistering name"),
-                                                     std::bind(&Fib::onUnregistrationFailure,
-                                                               this, _1,
-                                                               "Failed in unregistering name"));
+                                                       std::bind(&Fib::onUnregistrationSuccess, this, _1,
+                                                                 "Successful in unregistering name"),
+                                                       std::bind(&Fib::onUnregistrationFailure,
+                                                                 this, _1,
+                                                                 "Failed in unregistering name"));
   }
 }
 
@@ -432,24 +389,17 @@
 }
 
 void
-Fib::onRegistration(const ndn::nfd::ControlParameters& commandSuccessResult,
-                    const std::string& message, const std::string& faceUri)
+Fib::onRegistrationSuccess(const ndn::nfd::ControlParameters& commandSuccessResult,
+                           const std::string& message, const std::string& faceUri)
 {
   _LOG_DEBUG("Register successful Prefix: " << commandSuccessResult.getName() <<
              " Face Uri: " << faceUri);
+
   m_faceMap.update(faceUri, commandSuccessResult.getFaceId());
   m_faceMap.writeLog();
 }
 
 void
-Fib::onUnregistration(const ndn::nfd::ControlParameters& commandSuccessResult,
-                      const std::string& message)
-{
-  _LOG_DEBUG("Unregister successful Prefix: " << commandSuccessResult.getName() <<
-             " Face Id: " << commandSuccessResult.getFaceId());
-}
-
-void
 Fib::onRegistrationFailure(const ndn::nfd::ControlResponse& response,
                            const std::string& message,
                            const ndn::nfd::ControlParameters& parameters,
@@ -471,6 +421,14 @@
 }
 
 void
+Fib::onUnregistrationSuccess(const ndn::nfd::ControlParameters& commandSuccessResult,
+                             const std::string& message)
+{
+  _LOG_DEBUG("Unregister successful Prefix: " << commandSuccessResult.getName() <<
+             " Face Id: " << commandSuccessResult.getFaceId());
+}
+
+void
 Fib::onUnregistrationFailure(const ndn::nfd::ControlResponse& response,
                              const std::string& message)
 {
@@ -499,6 +457,60 @@
 }
 
 void
+Fib::scheduleEntryRefresh(FibEntry& entry, const afterRefreshCallback& refreshCallback)
+{
+  _LOG_DEBUG("Scheduling refresh for " << entry.getName()
+                                       << " Seq Num: " << entry.getSeqNo()
+                                       << " in " << m_refreshTime << " seconds");
+
+  entry.setRefreshEventId(m_scheduler.scheduleEvent(ndn::time::seconds(m_refreshTime),
+                                                    std::bind(&Fib::refreshEntry, this,
+                                                              entry.getName(), refreshCallback)));
+}
+
+void
+Fib::scheduleLoop(FibEntry& entry)
+{
+  scheduleEntryRefresh(entry,
+                       std::bind(&Fib::scheduleLoop, this, _1));
+}
+
+void
+Fib::cancelEntryRefresh(const FibEntry& entry)
+{
+  _LOG_DEBUG("Cancelling refresh for " << entry.getName() << " Seq Num: " << entry.getSeqNo());
+
+  m_scheduler.cancelEvent(entry.getRefreshEventId());
+  entry.getRefreshEventId().reset();
+}
+
+void
+Fib::refreshEntry(const ndn::Name& name, afterRefreshCallback refreshCb)
+{
+  std::map<ndn::Name, FibEntry>::iterator it = m_table.find(name);
+
+  if (it == m_table.end()) {
+    return;
+  }
+
+  FibEntry& entry = it->second;
+  _LOG_DEBUG("Refreshing " << entry.getName() << " Seq Num: " << entry.getSeqNo());
+
+  // Increment sequence number
+    entry.setSeqNo(entry.getSeqNo() + 1);
+
+  for (const NextHop& hop : entry) {
+    registerPrefix(entry.getName(),
+    hop.getConnectingFaceUri(),
+    hop.getRouteCostAsAdjustedInteger(),
+    ndn::time::seconds(m_refreshTime + GRACE_PERIOD),
+    ndn::nfd::ROUTE_FLAG_CAPTURE, 0);
+  }
+
+  refreshCb(entry);
+}
+
+void
 Fib::writeLog()
 {
   _LOG_DEBUG("-------------------FIB-----------------------------");
diff --git a/src/route/fib.hpp b/src/route/fib.hpp
index 3dea4a3..32eba00 100644
--- a/src/route/fib.hpp
+++ b/src/route/fib.hpp
@@ -19,27 +19,27 @@
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
  **/
-#ifndef NLSR_FIB_HPP
-#define NLSR_FIB_HPP
 
-#include <map>
+#ifndef NLSR_ROUTE_FIB_HPP
+#define NLSR_ROUTE_FIB_HPP
 
-#include <boost/cstdint.hpp>
-
-#include <ndn-cxx/mgmt/nfd/controller.hpp>
-#include <ndn-cxx/util/time.hpp>
 #include "face-map.hpp"
 #include "fib-entry.hpp"
 #include "test-access-control.hpp"
 #include "utility/face-controller.hpp"
 
+#include <ndn-cxx/management/nfd-controller.hpp>
+#include <ndn-cxx/util/time.hpp>
+
 namespace nlsr {
 
 typedef ndn::nfd::Controller::CommandSucceedCallback CommandSucceedCallback;
 typedef ndn::nfd::Controller::CommandFailCallback CommandFailCallback;
+typedef std::function<void(FibEntry&)> afterRefreshCallback;
 
 class AdjacencyList;
 class ConfParameter;
+class FibEntry;
 
 class Fib
 {
@@ -47,27 +47,24 @@
   Fib(ndn::Face& face, ndn::Scheduler& scheduler, AdjacencyList& adjacencyList, ConfParameter& conf,
       ndn::KeyChain& keyChain)
     : m_scheduler(scheduler)
-    , m_table()
     , m_refreshTime(0)
     , m_controller(face, keyChain)
     , m_faceController(face.getIoService(), m_controller)
-    , m_faceMap()
     , m_adjacencyList(adjacencyList)
     , m_confParameter(conf)
   {
   }
 
-  ~Fib()
-  {
-  }
+  void
+  update(const ndn::Name& name, NexthopList& allHops);
+
+  FibEntry*
+  processUpdate(const ndn::Name& name, NexthopList& allHops);
 
   void
   remove(const ndn::Name& name);
 
   void
-  update(const ndn::Name& name, NexthopList& allHops);
-
-  void
   clean();
 
   void
@@ -76,36 +73,13 @@
     m_refreshTime = fert;
   }
 
-private:
-  bool
-  isPrefixUpdatable(const ndn::Name& name);
-
   void
-  addNextHopsToFibEntryAndNfd(FibEntry& entry, NexthopList& hopsToAdd);
-
-  void
-  removeOldNextHopsFromFibEntryAndNfd(FibEntry& entry, const NexthopList& installedHops);
-
-  void
-  removeHop(NexthopList& nl, const std::string& doNotRemoveHopFaceUri,
-            const ndn::Name& name);
-
-  unsigned int
-  getNumberOfFacesForName(NexthopList& nextHopList);
-
-  ndn::EventId
-  scheduleEntryExpiration(const ndn::Name& name, int32_t feSeqNum,
-                          const ndn::time::seconds& expTime);
-
-  void
-  cancelScheduledExpiringEvent(ndn::EventId eid);
-
-public:
-  void
-  registerPrefix(const ndn::Name& namePrefix, const std::string& faceUri,
+  registerPrefix(const ndn::Name& namePrefix,
+                 const std::string& faceUri,
                  uint64_t faceCost,
                  const ndn::time::milliseconds& timeout,
-                 uint64_t flags, uint8_t times);
+                 uint64_t flags,
+                 uint8_t times);
 
   void
   registerPrefix(const ndn::Name& namePrefix,
@@ -129,6 +103,18 @@
               const CommandFailCallback& onFailure);
 
 private:
+  bool
+  isPrefixUpdatable(const ndn::Name& name);
+
+  void
+  addNextHopsToFibEntryAndNfd(FibEntry& entry, NexthopList& hopsToAdd);
+
+  void
+  removeOldNextHopsFromFibEntryAndNfd(FibEntry& entry, const NexthopList& installedHops);
+
+  unsigned int
+  getNumberOfFacesForName(NexthopList& nextHopList);
+
   void
   createFace(const std::string& faceUri,
              const CommandSucceedCallback& onSuccess,
@@ -155,12 +141,8 @@
   unregisterPrefix(const ndn::Name& namePrefix, const std::string& faceUri);
 
   void
-  onRegistration(const ndn::nfd::ControlParameters& commandSuccessResult,
-                 const std::string& message, const std::string& faceUri);
-
-  void
-  onUnregistration(const ndn::nfd::ControlParameters& commandSuccessResult,
-                   const std::string& message);
+  onRegistrationSuccess(const ndn::nfd::ControlParameters& commandSuccessResult,
+                        const std::string& message, const std::string& faceUri);
 
   void
   onRegistrationFailure(const ndn::nfd::ControlResponse& response,
@@ -170,10 +152,14 @@
                         uint8_t times);
 
   void
-  onUnregistrationFailure(const ndn::nfd::ControlResponse& response,
+  onUnregistrationSuccess(const ndn::nfd::ControlParameters& commandSuccessResult,
                           const std::string& message);
 
   void
+  onUnregistrationFailure(const ndn::nfd::ControlResponse& response,
+                               const std::string& message);
+
+  void
   onSetStrategySuccess(const ndn::nfd::ControlParameters& commandSuccessResult,
                        const std::string& message);
 
@@ -183,15 +169,29 @@
                        uint32_t count,
                        const std::string& message);
 
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  void
+  scheduleEntryRefresh(FibEntry& entry, const afterRefreshCallback& refreshCb);
+
+private:
+  void
+  scheduleLoop(FibEntry& entry);
+
+  void
+  cancelEntryRefresh(const FibEntry& entry);
+
+  void
+  refreshEntry(const ndn::Name& name, afterRefreshCallback refreshCb);
+
 private:
   ndn::Scheduler& m_scheduler;
-  std::map<ndn::Name, FibEntry> m_table;
   int32_t m_refreshTime;
   ndn::nfd::Controller m_controller;
   util::FaceController m_faceController;
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   FaceMap m_faceMap;
+  std::map<ndn::Name, FibEntry> m_table;
 
 private:
   AdjacencyList& m_adjacencyList;
@@ -201,4 +201,5 @@
 };
 
 } // namespace nlsr
-#endif //NLSR_FIB_HPP
+
+#endif // NLSR_ROUTE_FIB_HPP