lsdb: emit signals when modified

RoutingTable and NamePrefixTable consume the signal
and behave accordingly.

refs: #4127

Change-Id: I6540f30f0222f804b01dc7d9640831c84e5264cc
diff --git a/src/lsa/adj-lsa.cpp b/src/lsa/adj-lsa.cpp
index 781422c..3d49533 100644
--- a/src/lsa/adj-lsa.cpp
+++ b/src/lsa/adj-lsa.cpp
@@ -124,7 +124,7 @@
 AdjLsa::toString() const
 {
   std::ostringstream os;
-  os << Lsa::toString();
+  os << getString();
   os << "      Adjacent(s):\n";
 
   int adjacencyIndex = 0;
@@ -139,6 +139,20 @@
   return os.str();
 }
 
+std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+AdjLsa::update(const std::shared_ptr<Lsa>& lsa)
+{
+  auto alsa = std::static_pointer_cast<AdjLsa>(lsa);
+  if (!isEqualContent(*alsa)) {
+    resetAdl();
+    for (const auto& adjacent : alsa->getAdl()) {
+      addAdjacent(adjacent);
+    }
+    return std::make_tuple(true, std::list<ndn::Name>{}, std::list<ndn::Name>{});
+  }
+  return std::make_tuple(false, std::list<ndn::Name>{}, std::list<ndn::Name>{});
+}
+
 std::ostream&
 operator<<(std::ostream& os, const AdjLsa& lsa)
 {
diff --git a/src/lsa/adj-lsa.hpp b/src/lsa/adj-lsa.hpp
index 9857cc8..43562a6 100644
--- a/src/lsa/adj-lsa.hpp
+++ b/src/lsa/adj-lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -113,6 +113,9 @@
   std::string
   toString() const override;
 
+  std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  update(const std::shared_ptr<Lsa>& lsa) override;
+
 private:
   uint32_t m_noLink;
 
diff --git a/src/lsa/coordinate-lsa.cpp b/src/lsa/coordinate-lsa.cpp
index 32172e6..f61fb29 100644
--- a/src/lsa/coordinate-lsa.cpp
+++ b/src/lsa/coordinate-lsa.cpp
@@ -144,7 +144,7 @@
 CoordinateLsa::toString() const
 {
   std::ostringstream os;
-  os << Lsa::toString();
+  os << getString();
   os << "      Hyperbolic Radius  : " << m_hyperbolicRadius << "\n";
   int i = 0;
   for (const auto& value : m_hyperbolicAngles) {
@@ -154,6 +154,21 @@
   return os.str();
 }
 
+std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+CoordinateLsa::update(const std::shared_ptr<Lsa>& lsa)
+{
+  auto clsa = std::static_pointer_cast<CoordinateLsa>(lsa);
+  if (!isEqualContent(*clsa)) {
+    m_hyperbolicRadius = clsa->getCorRadius();
+    m_hyperbolicAngles.clear();
+    for (const auto& angle : clsa->getCorTheta()) {
+      m_hyperbolicAngles.push_back(angle);
+    }
+    return std::make_tuple(true, std::list<ndn::Name>{}, std::list<ndn::Name>{});
+  }
+  return std::make_tuple(false, std::list<ndn::Name>{}, std::list<ndn::Name>{});
+}
+
 std::ostream&
 operator<<(std::ostream& os, const CoordinateLsa& lsa)
 {
diff --git a/src/lsa/coordinate-lsa.hpp b/src/lsa/coordinate-lsa.hpp
index 4b07627..c1d3a13 100644
--- a/src/lsa/coordinate-lsa.hpp
+++ b/src/lsa/coordinate-lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -98,6 +98,9 @@
   std::string
   toString() const override;
 
+  std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  update(const std::shared_ptr<Lsa>& lsa) override;
+
 private:
   double m_hyperbolicRadius = 0.0;
   std::vector<double> m_hyperbolicAngles;
diff --git a/src/lsa/lsa.cpp b/src/lsa/lsa.cpp
index 25841d2..c633549 100644
--- a/src/lsa/lsa.cpp
+++ b/src/lsa/lsa.cpp
@@ -35,6 +35,13 @@
 {
 }
 
+Lsa::Lsa(const Lsa& lsa)
+  : m_originRouter(lsa.getOriginRouter())
+  , m_seqNo(lsa.getSeqNo())
+  , m_expirationTimePoint(lsa.getExpirationTimePoint())
+{
+}
+
 template<ndn::encoding::Tag TAG>
 size_t
 Lsa::wireEncode(ndn::EncodingImpl<TAG>& encoder) const
@@ -138,13 +145,13 @@
 }
 
 std::string
-Lsa::toString() const
+Lsa::getString() const
 {
   std::ostringstream os;
-  auto duration = getExpirationTimePoint() - ndn::time::system_clock::now();
+  auto duration = m_expirationTimePoint - ndn::time::system_clock::now();
   os << "    " << getType() << " LSA:\n"
-     << "      Origin Router      : " << getOriginRouter() << "\n"
-     << "      Sequence Number    : " << getSeqNo() << "\n"
+     << "      Origin Router      : " << m_originRouter << "\n"
+     << "      Sequence Number    : " << m_seqNo << "\n"
      << "      Expires in         : " << ndn::time::duration_cast<ndn::time::milliseconds>(duration)
      << "\n";
   return os.str();
diff --git a/src/lsa/lsa.hpp b/src/lsa/lsa.hpp
index 7fb1058..89ddb85 100644
--- a/src/lsa/lsa.hpp
+++ b/src/lsa/lsa.hpp
@@ -60,6 +60,8 @@
 
   Lsa() = default;
 
+  Lsa(const Lsa& lsa);
+
 public:
   virtual
   ~Lsa() = default;
@@ -108,19 +110,16 @@
   void
   setExpiringEventId(ndn::scheduler::EventId eid)
   {
-    m_expiringEventId = std::move(eid);
+    m_expiringEventId = eid;
   }
 
-  ndn::scheduler::EventId
-  getExpiringEventId() const
-  {
-    return m_expiringEventId;
-  }
-
-  /*! Get data common to all LSA types.
+  /*! Get data common to all LSA types for printing purposes.
    */
   virtual std::string
-  toString() const;
+  toString() const = 0;
+
+  virtual std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  update(const std::shared_ptr<Lsa>& lsa) = 0;
 
   virtual const ndn::Block&
   wireEncode() const = 0;
@@ -133,11 +132,14 @@
   void
   wireDecode(const ndn::Block& wire);
 
+  std::string
+  getString() const;
+
 PUBLIC_WITH_TESTS_ELSE_PROTECTED:
   ndn::Name m_originRouter;
   uint64_t m_seqNo = 0;
   ndn::time::system_clock::TimePoint m_expirationTimePoint;
-  ndn::scheduler::EventId m_expiringEventId;
+  ndn::scheduler::ScopedEventId m_expiringEventId;
 
   mutable ndn::Block m_wire;
 };
diff --git a/src/lsa/name-lsa.cpp b/src/lsa/name-lsa.cpp
index 173b9c7..266649a 100644
--- a/src/lsa/name-lsa.cpp
+++ b/src/lsa/name-lsa.cpp
@@ -122,7 +122,7 @@
 NameLsa::toString() const
 {
   std::ostringstream os;
-  os << Lsa::toString();
+  os << getString();
   os << "      Names:\n";
   int i = 0;
   for (const auto& name : m_npl.getNames()) {
@@ -132,6 +132,38 @@
   return os.str();
 }
 
+std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+NameLsa::update(const std::shared_ptr<Lsa>& lsa)
+{
+  auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
+  bool updated = false;
+
+  // Obtain the set difference of the current and the incoming
+  // name prefix sets, and add those.
+  std::list<ndn::Name> newNames = nlsa->getNpl().getNames();
+  std::list<ndn::Name> oldNames = m_npl.getNames();
+  std::list<ndn::Name> namesToAdd;
+  std::set_difference(newNames.begin(), newNames.end(), oldNames.begin(), oldNames.end(),
+                      std::inserter(namesToAdd, namesToAdd.begin()));
+  for (const auto& name : namesToAdd) {
+    addName(name);
+    updated = true;
+  }
+
+  m_npl.sort();
+
+  // Also remove any names that are no longer being advertised.
+  std::list<ndn::Name> namesToRemove;
+  std::set_difference(oldNames.begin(), oldNames.end(), newNames.begin(), newNames.end(),
+                      std::inserter(namesToRemove, namesToRemove.begin()));
+  for (const auto& name : namesToRemove) {
+    removeName(name);
+    updated = true;
+  }
+
+  return std::make_tuple(updated, namesToAdd, namesToRemove);
+}
+
 std::ostream&
 operator<<(std::ostream& os, const NameLsa& lsa)
 {
diff --git a/src/lsa/name-lsa.hpp b/src/lsa/name-lsa.hpp
index 5e9c8d5..5d6e02b 100644
--- a/src/lsa/name-lsa.hpp
+++ b/src/lsa/name-lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -97,6 +97,9 @@
   std::string
   toString() const override;
 
+  std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  update(const std::shared_ptr<Lsa>& lsa) override;
+
 private:
   NamePrefixList m_npl;
 };
diff --git a/src/lsdb.cpp b/src/lsdb.cpp
index a2f552d..5e416b3 100644
--- a/src/lsdb.cpp
+++ b/src/lsdb.cpp
@@ -32,13 +32,10 @@
 const ndn::time::steady_clock::TimePoint Lsdb::DEFAULT_LSA_RETRIEVAL_DEADLINE =
   ndn::time::steady_clock::TimePoint::min();
 
-Lsdb::Lsdb(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam,
-           NamePrefixTable& namePrefixTable, RoutingTable& routingTable)
+Lsdb::Lsdb(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam)
   : m_face(face)
   , m_scheduler(face.getIoService())
   , m_confParam(confParam)
-  , m_namePrefixTable(namePrefixTable)
-  , m_routingTable(routingTable)
   , m_sync(m_face,
            [this] (const ndn::Name& routerName, const Lsa::Type& lsaType,
                    const uint64_t& sequenceNumber) {
@@ -56,9 +53,26 @@
         expressInterest(lsaInterest, 0);
       }))
   , m_segmentPublisher(m_face, keyChain)
-  , m_isBuildAdjLsaSheduled(false)
+  , m_isBuildAdjLsaScheduled(false)
   , m_adjBuildCount(0)
 {
+  ndn::Name name = m_confParam.getLsaPrefix();
+  NLSR_LOG_DEBUG("Setting interest filter for LsaPrefix: " << name);
+
+  m_face.setInterestFilter(ndn::InterestFilter(name).allowLoopback(false),
+    [this] (const auto& name, const auto& interest) { processInterest(name, interest); },
+    [] (const auto& name) { NLSR_LOG_DEBUG("Successfully registered prefix: " << name); },
+    [] (const auto& name, const auto& reason) {
+      NLSR_LOG_ERROR("Failed to register prefix " << name);
+      NDN_THROW(std::runtime_error("Register prefix failed: " + reason));
+    },
+    m_confParam.getSigningInfo(), ndn::nfd::ROUTE_FLAG_CAPTURE);
+
+  buildAndInstallOwnNameLsa();
+  // Install coordinate LSAs if using HR or dry-run HR.
+  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
+    buildAndInstallOwnCoordinateLsa();
+  }
 }
 
 void
@@ -101,44 +115,37 @@
     return;
   }
 
-  if (m_isBuildAdjLsaSheduled) {
+  if (m_isBuildAdjLsaScheduled) {
     NLSR_LOG_DEBUG("Rescheduling Adjacency LSA build in " << m_adjLsaBuildInterval);
   }
   else {
     NLSR_LOG_DEBUG("Scheduling Adjacency LSA build in " << m_adjLsaBuildInterval);
-    m_isBuildAdjLsaSheduled = true;
+    m_isBuildAdjLsaScheduled = true;
   }
   m_scheduledAdjLsaBuild = m_scheduler.schedule(m_adjLsaBuildInterval, [this] { buildAdjLsa(); });
 }
 
-template<typename T>
 void
 Lsdb::writeLog() const
 {
-  if ((T::type() == Lsa::Type::COORDINATE &&
-      m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_OFF) ||
-      (T::type() == Lsa::Type::ADJACENCY &&
-      m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON)) {
-    return;
-  }
+  static const Lsa::Type types[] = {Lsa::Type::COORDINATE, Lsa::Type::NAME, Lsa::Type::ADJACENCY};
+  for (const auto& type : types) {
+    if ((type == Lsa::Type::COORDINATE &&
+         m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_OFF) ||
+        (type == Lsa::Type::ADJACENCY &&
+       m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON)) {
+      continue;
+    }
 
-  NLSR_LOG_DEBUG("---------------" << T::type() << " LSDB-------------------");
-  auto lsaRange = m_lsdb.get<byType>().equal_range(T::type());
-  for (auto lsaIt = lsaRange.first; lsaIt != lsaRange.second; ++lsaIt) {
-    auto lsaPtr = std::static_pointer_cast<T>(*lsaIt);
-    NLSR_LOG_DEBUG(lsaPtr->toString());
+    NLSR_LOG_DEBUG("---------------" << type << " LSDB-------------------");
+    auto lsaRange = m_lsdb.get<byType>().equal_range(type);
+    for (auto lsaIt = lsaRange.first; lsaIt != lsaRange.second; ++lsaIt) {
+      NLSR_LOG_DEBUG((*lsaIt)->toString());
+    }
   }
 }
 
 void
-Lsdb::writeLog() const
-{
-  writeLog<CoordinateLsa>();
-  writeLog<NameLsa>();
-  writeLog<AdjLsa>();
-}
-
-void
 Lsdb::processInterest(const ndn::Name& name, const ndn::Interest& interest)
 {
   ndn::Name interestName(interest.getName());
@@ -199,8 +206,7 @@
   if (auto lsaPtr = findLsa(originRouter, lsaType)) {
     NLSR_LOG_TRACE("Verifying SeqNo for " << lsaType << " is same as requested.");
     if (lsaPtr->getSeqNo() == seqNo) {
-      m_segmentPublisher.publish(interest.getName(), interest.getName(),
-                                 lsaPtr->wireEncode(),
+      m_segmentPublisher.publish(interest.getName(), interest.getName(), lsaPtr->wireEncode(),
                                  m_lsaRefreshTime, m_confParam.getSigningInfo());
       incrementDataSentStats(lsaType);
       return true;
@@ -216,39 +222,21 @@
 Lsdb::installLsa(std::shared_ptr<Lsa> lsa)
 {
   auto timeToExpire = m_lsaRefreshTime;
+  if (lsa->getOriginRouter() != m_thisRouterPrefix) {
+    auto duration = lsa->getExpirationTimePoint() - ndn::time::system_clock::now();
+    if (duration > ndn::time::seconds(0)) {
+      timeToExpire = ndn::time::duration_cast<ndn::time::seconds>(duration);
+    }
+  }
 
   auto chkLsa = findLsa(lsa->getOriginRouter(), lsa->getType());
   if (chkLsa == nullptr) {
     NLSR_LOG_DEBUG("Adding " << lsa->getType() << " LSA");
     NLSR_LOG_DEBUG(lsa->toString());
-    ndn::time::seconds timeToExpire = m_lsaRefreshTime;
 
     m_lsdb.emplace(lsa);
 
-    // Add any new name prefixes to the NPT if from another router
-    if (lsa->getOriginRouter() != m_thisRouterPrefix) {
-      // Pass the origin router as both the name to register and where it came from.
-      m_namePrefixTable.addEntry(lsa->getOriginRouter(), lsa->getOriginRouter());
-
-      if (lsa->getType() == Lsa::Type::NAME) {
-        auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
-        for (const auto& name : nlsa->getNpl().getNames()) {
-          if (name != m_thisRouterPrefix) {
-            m_namePrefixTable.addEntry(name, nlsa->getOriginRouter());
-          }
-        }
-      }
-
-      auto duration = lsa->getExpirationTimePoint() - ndn::time::system_clock::now();
-      if (duration > ndn::time::seconds(0)) {
-        timeToExpire = ndn::time::duration_cast<ndn::time::seconds>(duration);
-      }
-    }
-
-    if ((lsa->getType() == Lsa::Type::ADJACENCY && m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_ON)||
-        (lsa->getType() == Lsa::Type::COORDINATE && m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF)) {
-      m_routingTable.scheduleRoutingTableCalculation();
-    }
+    onLsdbModified(lsa, LsdbUpdate::INSTALLED, {}, {});
 
     lsa->setExpiringEventId(scheduleLsaExpiration(lsa, timeToExpire));
   }
@@ -259,104 +247,36 @@
     chkLsa->setSeqNo(lsa->getSeqNo());
     chkLsa->setExpirationTimePoint(lsa->getExpirationTimePoint());
 
-    if (lsa->getType() == Lsa::Type::NAME) {
-      auto chkNameLsa = std::static_pointer_cast<NameLsa>(chkLsa);
-      auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
-      chkNameLsa->getNpl().sort();
-      nlsa->getNpl().sort();
-      if (!chkNameLsa->isEqualContent(*nlsa)) {
-        // Obtain the set difference of the current and the incoming
-        // name prefix sets, and add those.
-        std::list<ndn::Name> newNames = nlsa->getNpl().getNames();
-        std::list<ndn::Name> oldNames = chkNameLsa->getNpl().getNames();
-        std::list<ndn::Name> namesToAdd;
-        std::set_difference(newNames.begin(), newNames.end(), oldNames.begin(), oldNames.end(),
-                            std::inserter(namesToAdd, namesToAdd.begin()));
-        for (const auto& name : namesToAdd) {
-          chkNameLsa->addName(name);
-          if (nlsa->getOriginRouter() != m_thisRouterPrefix && name != m_thisRouterPrefix) {
-            m_namePrefixTable.addEntry(name, nlsa->getOriginRouter());
-          }
-        }
+    bool updated;
+    std::list<ndn::Name> namesToAdd, namesToRemove;
+    std::tie(updated, namesToAdd, namesToRemove) = chkLsa->update(lsa);
 
-        chkNameLsa->getNpl().sort();
-
-        // Also remove any names that are no longer being advertised.
-        std::list<ndn::Name> namesToRemove;
-        std::set_difference(oldNames.begin(), oldNames.end(), newNames.begin(), newNames.end(),
-                            std::inserter(namesToRemove, namesToRemove.begin()));
-        for (const auto& name : namesToRemove) {
-          NLSR_LOG_DEBUG("Removing name" << name << " from Name LSA no longer advertised.");
-          chkNameLsa->removeName(name);
-          if (nlsa->getOriginRouter() != m_thisRouterPrefix && name != m_thisRouterPrefix) {
-            m_namePrefixTable.removeEntry(name, nlsa->getOriginRouter());
-          }
-        }
-      }
-    }
-    else if (lsa->getType() == Lsa::Type::ADJACENCY) {
-      auto chkAdjLsa = std::static_pointer_cast<AdjLsa>(chkLsa);
-      auto alsa = std::static_pointer_cast<AdjLsa>(lsa);
-      if (!chkAdjLsa->isEqualContent(*alsa)) {
-        chkAdjLsa->resetAdl();
-        for (const auto& adjacent : alsa->getAdl()) {
-          chkAdjLsa->addAdjacent(adjacent);
-        }
-        m_routingTable.scheduleRoutingTableCalculation();
-      }
-    }
-    else {
-      auto chkCorLsa = std::static_pointer_cast<CoordinateLsa>(chkLsa);
-      auto clsa = std::static_pointer_cast<CoordinateLsa>(lsa);
-      if (!chkCorLsa->isEqualContent(*clsa)) {
-        chkCorLsa->setCorRadius(clsa->getCorRadius());
-        chkCorLsa->setCorTheta(clsa->getCorTheta());
-        if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
-          m_routingTable.scheduleRoutingTableCalculation();
-        }
-      }
+    if (updated) {
+      onLsdbModified(lsa, LsdbUpdate::UPDATED, namesToAdd, namesToRemove);
     }
 
-    if (chkLsa->getOriginRouter() != m_thisRouterPrefix) {
-      auto duration = lsa->getExpirationTimePoint() - ndn::time::system_clock::now();
-      if (duration > ndn::time::seconds(0)) {
-        timeToExpire = ndn::time::duration_cast<ndn::time::seconds>(duration);
-      }
-    }
-    chkLsa->getExpiringEventId().cancel();
     chkLsa->setExpiringEventId(scheduleLsaExpiration(chkLsa, timeToExpire));
     NLSR_LOG_DEBUG("Updated " << lsa->getType() << " LSA:");
     NLSR_LOG_DEBUG(chkLsa->toString());
   }
 }
 
-bool
-Lsdb::removeLsa(const ndn::Name& router, Lsa::Type lsaType)
+void
+Lsdb::removeLsa(const LsaContainer::index<Lsdb::byName>::type::iterator& lsaIt)
 {
-  auto lsaIt = m_lsdb.get<byName>().find(std::make_tuple(router, lsaType));
-
   if (lsaIt != m_lsdb.end()) {
     auto lsaPtr = *lsaIt;
-    NLSR_LOG_DEBUG("Removing " << lsaType << " LSA:");
+    NLSR_LOG_DEBUG("Removing " << lsaPtr->getType() << " LSA:");
     NLSR_LOG_DEBUG(lsaPtr->toString());
-    // If the requested name LSA is not ours, we also need to remove
-    // its entries from the NPT.
-    if (lsaPtr->getOriginRouter() != m_thisRouterPrefix) {
-      m_namePrefixTable.removeEntry(lsaPtr->getOriginRouter(), lsaPtr->getOriginRouter());
-
-      if (lsaType == Lsa::Type::NAME) {
-        auto nlsaPtr = std::static_pointer_cast<NameLsa>(lsaPtr);
-        for (const auto& name : nlsaPtr->getNpl().getNames()) {
-          if (name != m_thisRouterPrefix) {
-            m_namePrefixTable.removeEntry(name, nlsaPtr->getOriginRouter());
-          }
-        }
-      }
-    }
     m_lsdb.erase(lsaIt);
-    return true;
+    onLsdbModified(lsaPtr, LsdbUpdate::REMOVED, {}, {});
   }
-  return false;
+}
+
+void
+Lsdb::removeLsa(const ndn::Name& router, Lsa::Type lsaType)
+{
+  removeLsa(m_lsdb.get<byName>().find(std::make_tuple(router, lsaType)));
 }
 
 void
@@ -364,7 +284,7 @@
 {
   NLSR_LOG_TRACE("buildAdjLsa called");
 
-  m_isBuildAdjLsaSheduled = false;
+  m_isBuildAdjLsaScheduled = false;
 
   if (m_confParam.getAdjacencyList().isAdjLsaBuildable(m_confParam.getInterestRetryNumber())) {
 
@@ -382,10 +302,7 @@
       // routers to delete it, too.
       else {
         NLSR_LOG_DEBUG("Removing own Adj LSA; no ACTIVE neighbors");
-
         removeLsa(m_thisRouterPrefix, Lsa::Type::ADJACENCY);
-        // Recompute routing table after removal
-        m_routingTable.scheduleRoutingTableCalculation();
       }
       // In the case that during building the adj LSA, the FIB has to
       // wait on an Interest response, the number of scheduled adj LSA
@@ -397,7 +314,7 @@
   // neighbor, so schedule a build for later (when all that has
   // hopefully finished)
   else {
-    m_isBuildAdjLsaSheduled = true;
+    m_isBuildAdjLsaScheduled = true;
     auto schedulingTime = ndn::time::seconds(m_confParam.getInterestRetryNumber() *
                                              m_confParam.getInterestResendTime());
     m_scheduledAdjLsaBuild = m_scheduler.schedule(schedulingTime, [this] { buildAdjLsa(); });
@@ -422,6 +339,13 @@
   installLsa(std::make_shared<AdjLsa>(adjLsa));
 }
 
+ndn::scheduler::EventId
+Lsdb::scheduleLsaExpiration(std::shared_ptr<Lsa> lsa, ndn::time::seconds expTime)
+{
+  NLSR_LOG_DEBUG("Scheduling expiration in: " << expTime + GRACE_PERIOD << " for " << lsa->getOriginRouter());
+  return m_scheduler.schedule(expTime + GRACE_PERIOD, [this, lsa] { expireOrRefreshLsa(lsa); });
+}
+
 void
 Lsdb::expireOrRefreshLsa(std::shared_ptr<Lsa> lsa)
 {
@@ -454,7 +378,7 @@
       // Since we cannot refresh other router's LSAs, our only choice is to expire.
       else {
         NLSR_LOG_DEBUG("Other's " << lsaPtr->getType() << " LSA, so removing from LSDB");
-        removeLsa(lsaPtr->getOriginRouter(), lsaPtr->getType());
+        removeLsa(lsaIt);
       }
     }
   }
@@ -581,7 +505,6 @@
     ndn::Name originRouter = m_confParam.getNetwork();
     originRouter.append(interestName.getSubName(lsaPosition + 1,
                                                 interestName.size() - lsaPosition - 3));
-
     try {
       Lsa::Type interestedLsType;
       std::istringstream(interestName[-2].toUri()) >> interestedLsType;
@@ -613,7 +536,6 @@
     }
     catch (const std::exception& e) {
       NLSR_LOG_TRACE("LSA data decoding error :( " << e.what());
-      return;
     }
   }
 }
diff --git a/src/lsdb.hpp b/src/lsdb.hpp
index 9a5f147..7d77cd3 100644
--- a/src/lsdb.hpp
+++ b/src/lsdb.hpp
@@ -31,7 +31,6 @@
 #include "test-access-control.hpp"
 #include "communication/sync-logic-handler.hpp"
 #include "statistics.hpp"
-#include "route/name-prefix-table.hpp"
 
 #include <ndn-cxx/security/key-chain.hpp>
 #include <ndn-cxx/util/signal.hpp>
@@ -51,11 +50,16 @@
 
 static constexpr ndn::time::seconds GRACE_PERIOD = 10_s;
 
+enum class LsdbUpdate {
+  INSTALLED,
+  UPDATED,
+  REMOVED
+};
+
 class Lsdb
 {
 public:
-  Lsdb(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam,
-       NamePrefixTable& namePrefixTable, RoutingTable& routingTable);
+  Lsdb(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam);
 
   ~Lsdb()
   {
@@ -78,18 +82,16 @@
   void
   buildAndInstallOwnNameLsa();
 
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   /*! \brief Builds a cor. LSA for this router and installs it into the LSDB. */
   void
   buildAndInstallOwnCoordinateLsa();
 
+public:
   /*! \brief Schedules a build of this router's LSA. */
   void
   scheduleAdjLsaBuild();
 
-  template<typename T>
-  void
-  writeLog() const;
-
   void
   writeLog() const;
 
@@ -103,9 +105,9 @@
   processInterest(const ndn::Name& name, const ndn::Interest& interest);
 
   bool
-  getIsBuildAdjLsaSheduled() const
+  getIsBuildAdjLsaScheduled() const
   {
-    return m_isBuildAdjLsaSheduled;
+    return m_isBuildAdjLsaScheduled;
   }
 
   SyncLogicHandler&
@@ -238,9 +240,12 @@
     LSA whose name matches key. This removal also causes the NPT to
     remove those name prefixes if no more LSAs advertise them.
    */
-  bool
+  void
   removeLsa(const ndn::Name& router, Lsa::Type lsaType);
 
+  void
+  removeLsa(const LsaContainer::index<Lsdb::byName>::type::iterator& lsaIt);
+
   /*! \brief Attempts to construct an adj. LSA.
 
     This function will attempt to construct an adjacency LSA. An LSA
@@ -260,10 +265,7 @@
     \param expTime How many seconds to wait before triggering the event.
    */
   ndn::scheduler::EventId
-  scheduleLsaExpiration(std::shared_ptr<Lsa> lsa, ndn::time::seconds expTime)
-  {
-    return m_scheduler.schedule(expTime + GRACE_PERIOD, [this, lsa] { expireOrRefreshLsa(lsa); });
-  }
+  scheduleLsaExpiration(std::shared_ptr<Lsa> lsa, ndn::time::seconds expTime);
 
   /*! \brief Either allow to expire, or refresh a name LSA.
     \param lsa The LSA.
@@ -321,16 +323,17 @@
   }
 
 public:
-  ndn::util::signal::Signal<Lsdb, Statistics::PacketType> lsaIncrementSignal;
-  ndn::util::signal::Signal<Lsdb, const ndn::Data&> afterSegmentValidatedSignal;
+  ndn::util::Signal<Lsdb, Statistics::PacketType> lsaIncrementSignal;
+  ndn::util::Signal<Lsdb, ndn::Data> afterSegmentValidatedSignal;
+  using AfterLsdbModified = ndn::util::Signal<Lsdb, std::shared_ptr<Lsa>, LsdbUpdate,
+                                              std::list<ndn::Name>, std::list<ndn::Name>>;
+  AfterLsdbModified onLsdbModified;
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   ndn::Face& m_face;
   ndn::Scheduler m_scheduler;
 
   ConfParameter& m_confParam;
-  NamePrefixTable& m_namePrefixTable;
-  RoutingTable& m_routingTable;
 
   SyncLogicHandler m_sync;
 
@@ -351,7 +354,7 @@
   std::set<std::shared_ptr<ndn::util::SegmentFetcher>> m_fetchers;
   psync::SegmentPublisher m_segmentPublisher;
 
-  bool m_isBuildAdjLsaSheduled;
+  bool m_isBuildAdjLsaScheduled;
   int64_t m_adjBuildCount;
   ndn::scheduler::ScopedEventId m_scheduledAdjLsaBuild;
 
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index b8cec28..cb24559 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -42,9 +42,10 @@
   , m_adjacencyList(confParam.getAdjacencyList())
   , m_namePrefixList(confParam.getNamePrefixList())
   , m_fib(m_face, m_scheduler, m_adjacencyList, m_confParam, keyChain)
-  , m_routingTable(m_scheduler, m_fib, m_lsdb, m_namePrefixTable, m_confParam)
-  , m_namePrefixTable(m_fib, m_routingTable, m_routingTable.afterRoutingChange)
-  , m_lsdb(m_face, keyChain, m_confParam, m_namePrefixTable, m_routingTable)
+  , m_lsdb(m_face, keyChain, m_confParam)
+  , m_routingTable(m_scheduler, m_lsdb, m_confParam)
+  , m_namePrefixTable(confParam.getRouterPrefix(), m_fib, m_routingTable,
+                      m_routingTable.afterRoutingChange, m_lsdb.onLsdbModified)
   , m_helloProtocol(m_face, keyChain, confParam, m_routingTable, m_lsdb)
   , m_onNewLsaConnection(m_lsdb.getSync().onNewLsa->connect(
       [this] (const ndn::Name& updateName, uint64_t sequenceNumber,
@@ -83,30 +84,29 @@
   m_faceMonitor.onNotification.connect(std::bind(&Nlsr::onFaceEventNotification, this, _1));
   m_faceMonitor.start();
 
-  // Do key initialization and registrations first, then initialize faces
-  // which will create routes to neighbor
-
-  setStrategies();
+  m_fib.setStrategy(m_confParam.getLsaPrefix(), Fib::MULTICAST_STRATEGY, 0);
+  m_fib.setStrategy(m_confParam.getSyncPrefix(), Fib::MULTICAST_STRATEGY, 0);
 
   NLSR_LOG_DEBUG("Default NLSR identity: " << m_confParam.getSigningInfo().getSignerName());
 
-  // Can be moved to Lsdb ctor
-  setLsaInterestFilter();
-
   // Add top-level prefixes: router and localhost prefix
   addDispatcherTopPrefix(ndn::Name(m_confParam.getRouterPrefix()).append("nlsr"));
   addDispatcherTopPrefix(LOCALHOST_PREFIX);
 
   enableIncomingFaceIdIndication();
 
-  registerLocalhostPrefix();
-  registerRouterPrefix();
-
   initializeFaces(std::bind(&Nlsr::processFaceDataset, this, _1),
                   std::bind(&Nlsr::onFaceDatasetFetchTimeout, this, _1, _2, 0));
 
-  // Could be moved into ctor, but unit tests need to be modified
-  initialize();
+  m_adjacencyList.writeLog();
+  NLSR_LOG_DEBUG(m_namePrefixList);
+
+  // Need to set direct neighbors' costs to 0 for hyperbolic routing
+  if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
+    for (auto&& neighbor : m_adjacencyList.getAdjList()) {
+      neighbor.setLinkCost(0);
+    }
+  }
 }
 
 void
@@ -145,87 +145,29 @@
 }
 
 void
-Nlsr::registrationFailed(const ndn::Name& name)
-{
-  NLSR_LOG_ERROR("ERROR: Failed to register prefix " << name << " in local hub's daemon");
-  NDN_THROW(Error("Error: Prefix registration failed"));
-}
-
-void
-Nlsr::onRegistrationSuccess(const ndn::Name& name)
-{
-  NLSR_LOG_DEBUG("Successfully registered prefix: " << name);
-}
-
-void
-Nlsr::setLsaInterestFilter()
-{
-  ndn::Name name = m_confParam.getLsaPrefix();
-
-  NLSR_LOG_DEBUG("Setting interest filter for LsaPrefix: " << name);
-
-  m_face.setInterestFilter(ndn::InterestFilter(name).allowLoopback(false),
-                           std::bind(&Lsdb::processInterest, &m_lsdb, _1, _2),
-                           std::bind(&Nlsr::onRegistrationSuccess, this, _1),
-                           std::bind(&Nlsr::registrationFailed, this, _1),
-                           m_confParam.getSigningInfo(), ndn::nfd::ROUTE_FLAG_CAPTURE);
-}
-
-void
 Nlsr::addDispatcherTopPrefix(const ndn::Name& topPrefix)
 {
+  registerPrefix(topPrefix);
   try {
     // false since we want to have control over the registration process
     m_dispatcher.addTopPrefix(topPrefix, false, m_confParam.getSigningInfo());
   }
   catch (const std::exception& e) {
-    NLSR_LOG_ERROR("Error setting top-level prefix in dispatcher: " << e.what() << "\n");
+    NLSR_LOG_ERROR("Error setting top-level prefix in dispatcher: " << e.what());
   }
 }
 
 void
-Nlsr::setStrategies()
+Nlsr::registerPrefix(const ndn::Name& prefix)
 {
-  m_fib.setStrategy(m_confParam.getLsaPrefix(), Fib::MULTICAST_STRATEGY, 0);
-  m_fib.setStrategy(m_confParam.getSyncPrefix(), Fib::MULTICAST_STRATEGY, 0);
-}
-
-void
-Nlsr::initialize()
-{
-  // Logging start
-  m_adjacencyList.writeLog();
-  NLSR_LOG_DEBUG(m_namePrefixList);
-
-  m_lsdb.buildAndInstallOwnNameLsa();
-
-  // Install coordinate LSAs if using HR or dry-run HR.
-  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
-    m_lsdb.buildAndInstallOwnCoordinateLsa();
-  }
-
-  // Need to set direct neighbors' costs to 0 for hyperbolic routing
-  if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
-    for (auto&& neighbor : m_adjacencyList.getAdjList()) {
-      neighbor.setLinkCost(0);
-    }
-  }
-}
-
-void
-Nlsr::registerLocalhostPrefix()
-{
-  m_face.registerPrefix(LOCALHOST_PREFIX,
-                        std::bind(&Nlsr::onRegistrationSuccess, this, _1),
-                        std::bind(&Nlsr::registrationFailed, this, _1));
-}
-
-void
-Nlsr::registerRouterPrefix()
-{
-  m_face.registerPrefix(ndn::Name(m_confParam.getRouterPrefix()).append("nlsr"),
-                        std::bind(&Nlsr::onRegistrationSuccess, this, _1),
-                        std::bind(&Nlsr::registrationFailed, this, _1));
+  m_face.registerPrefix(prefix,
+    [] (const ndn::Name& name) {
+      NLSR_LOG_DEBUG("Successfully registered prefix: " << name);
+    },
+    [] (const ndn::Name& name, const std::string& reason) {
+      NLSR_LOG_ERROR("ERROR: Failed to register prefix " << name << " in local hub's daemon");
+      NDN_THROW(Error("Error: Prefix registration failed: " + reason));
+    });
 }
 
 void
@@ -319,9 +261,7 @@
                       const FetchDatasetTimeoutCallback& onFetchFailure)
 {
   NLSR_LOG_TRACE("Initializing Faces...");
-
   m_faceDatasetController.fetch<ndn::nfd::FaceDataset>(onFetchSuccess, onFetchFailure);
-
 }
 
 void
@@ -359,8 +299,7 @@
 }
 
 void
-Nlsr::registerAdjacencyPrefixes(const Adjacent& adj,
-                                const ndn::time::milliseconds& timeout)
+Nlsr::registerAdjacencyPrefixes(const Adjacent& adj, ndn::time::milliseconds timeout)
 {
   ndn::FaceUri faceUri = adj.getFaceUri();
   double linkCost = adj.getLinkCost();
@@ -423,22 +362,14 @@
   m_controller.start<ndn::nfd::FaceUpdateCommand>(
     ndn::nfd::ControlParameters()
       .setFlagBit(ndn::nfd::FaceFlagBit::BIT_LOCAL_FIELDS_ENABLED, true),
-    std::bind(&Nlsr::onFaceIdIndicationSuccess, this, _1),
-    std::bind(&Nlsr::onFaceIdIndicationFailure, this, _1));
-}
-
-void
-Nlsr::onFaceIdIndicationSuccess(const ndn::nfd::ControlParameters& cp)
-{
-  NLSR_LOG_DEBUG("Successfully enabled incoming face id indication"
-                 << "for face id " << cp.getFaceId());
-}
-
-void
-Nlsr::onFaceIdIndicationFailure(const ndn::nfd::ControlResponse& cr)
-{
-  NLSR_LOG_DEBUG("Failed to enable incoming face id indication feature: " <<
-                 "(code: " << cr.getCode() << ", reason: " << cr.getText() << ")");
+    [] (const ndn::nfd::ControlParameters& cp) {
+      NLSR_LOG_DEBUG("Successfully enabled incoming face id indication"
+                     << "for face id " << cp.getFaceId());
+    },
+    [] (const ndn::nfd::ControlResponse& cr) {
+      NLSR_LOG_WARN("Failed to enable incoming face id indication feature: " <<
+                    "(code: " << cr.getCode() << ", reason: " << cr.getText() << ")");
+    });
 }
 
 } // namespace nlsr
diff --git a/src/nlsr.hpp b/src/nlsr.hpp
index 23d73c2..3e22874 100644
--- a/src/nlsr.hpp
+++ b/src/nlsr.hpp
@@ -40,16 +40,11 @@
 
 #include <ndn-cxx/face.hpp>
 #include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/security/certificate-fetcher-direct-fetch.hpp>
-#include <ndn-cxx/security/signing-helpers.hpp>
-#include <ndn-cxx/security/signing-info.hpp>
 #include <ndn-cxx/util/scheduler.hpp>
 #include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
 #include <ndn-cxx/mgmt/nfd/face-monitor.hpp>
 #include <ndn-cxx/mgmt/dispatcher.hpp>
 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
-#include <ndn-cxx/data.hpp>
-#include <ndn-cxx/encoding/block.hpp>
 #include <ndn-cxx/encoding/nfd-constants.hpp>
 #include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
@@ -70,26 +65,6 @@
 
   Nlsr(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam);
 
-  void
-  registerStrategyForCerts(const ndn::Name& originRouter);
-
-  void
-  registrationFailed(const ndn::Name& name);
-
-  void
-  onRegistrationSuccess(const ndn::Name& name);
-
-  void
-  setLsaInterestFilter();
-
-  /*! \brief Add top level prefixes for Dispatcher
-   *
-   * All dispatcher-related sub-prefixes *must* be registered before sub-prefixes
-   * must be added before adding top
-   */
-  void
-  addDispatcherTopPrefix(const ndn::Name& topPrefix);
-
   Lsdb&
   getLsdb()
   {
@@ -102,9 +77,19 @@
     return m_fib;
   }
 
+private:
   void
-  initialize();
+  registerStrategyForCerts(const ndn::Name& originRouter);
 
+  /*! \brief Add top level prefixes for Dispatcher
+   *
+   * All dispatcher-related sub-prefixes *must* be registered before sub-prefixes
+   * must be added before adding top
+   */
+  void
+  addDispatcherTopPrefix(const ndn::Name& topPrefix);
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   /*! \brief Initializes neighbors' Faces using information from NFD.
    * \sa Nlsr::initialize()
    * \sa Nlsr::processFaceDataset()
@@ -137,6 +122,7 @@
   void
   processFaceDataset(const std::vector<ndn::nfd::FaceStatus>& faces);
 
+private:
   /*! \brief Registers NLSR-specific prefixes for a neighbor (Adjacent)
    * \sa Nlsr::initializeFaces
    * \param adj A reference to the neighbor to register prefixes for
@@ -147,22 +133,12 @@
    * *each* registration request that is made.
    */
   void
-  registerAdjacencyPrefixes(const Adjacent& adj,
-                            const ndn::time::milliseconds& timeout);
+  registerAdjacencyPrefixes(const Adjacent& adj, ndn::time::milliseconds timeout);
 
-  void
-  setStrategies();
-
-private:
-  /*! \brief Registers the prefix that NLSR will consider to be the machine-local, secure prefix.
+  /*! \brief Registers the prefix
    */
   void
-  registerLocalhostPrefix();
-
-  /*! \brief Registers the <router-prefix>/nlsr so that NLSR can respond to status requests from remote routers.
-   */
-  void
-  registerRouterPrefix();
+  registerPrefix(const ndn::Name& prefix);
 
   /*! \brief Do nothing.
    */
@@ -182,12 +158,6 @@
   void
   enableIncomingFaceIdIndication();
 
-  void
-  onFaceIdIndicationSuccess(const ndn::nfd::ControlParameters& cp);
-
-  void
-  onFaceIdIndicationFailure(const ndn::nfd::ControlResponse& cr);
-
 public:
   static const ndn::Name LOCALHOST_PREFIX;
 
@@ -201,9 +171,9 @@
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   Fib m_fib;
+  Lsdb m_lsdb;
   RoutingTable m_routingTable;
   NamePrefixTable m_namePrefixTable;
-  Lsdb m_lsdb;
   HelloProtocol m_helloProtocol;
 
 private:
diff --git a/src/publisher/dataset-interest-handler.cpp b/src/publisher/dataset-interest-handler.cpp
index 373b62b..46b1ab8 100644
--- a/src/publisher/dataset-interest-handler.cpp
+++ b/src/publisher/dataset-interest-handler.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -38,16 +38,9 @@
 DatasetInterestHandler::DatasetInterestHandler(ndn::mgmt::Dispatcher& dispatcher,
                                                const Lsdb& lsdb,
                                                const RoutingTable& rt)
-  : m_dispatcher(dispatcher)
-  , m_lsdb(lsdb)
+  : m_lsdb(lsdb)
   , m_routingTable(rt)
 {
-  setDispatcher(m_dispatcher);
-}
-
-void
-DatasetInterestHandler::setDispatcher(ndn::mgmt::Dispatcher& dispatcher)
-{
   dispatcher.addStatusDataset(ADJACENCIES_DATASET,
     ndn::mgmt::makeAcceptAllAuthorization(),
     std::bind(&DatasetInterestHandler::publishLsaStatus<AdjLsa>, this, _1, _2, _3));
@@ -67,6 +60,7 @@
 DatasetInterestHandler::publishLsaStatus(const ndn::Name& topPrefix, const ndn::Interest& interest,
                                          ndn::mgmt::StatusDatasetContext& context)
 {
+  NLSR_LOG_TRACE("Received interest: " << interest);
   auto lsaRange = m_lsdb.getLsdbIterator<T>();
   for (auto lsaIt = lsaRange.first; lsaIt != lsaRange.second; ++lsaIt) {
     context.append((*lsaIt)->wireEncode());
@@ -78,7 +72,7 @@
 DatasetInterestHandler::publishRtStatus(const ndn::Name& topPrefix, const ndn::Interest& interest,
                                         ndn::mgmt::StatusDatasetContext& context)
 {
-  NLSR_LOG_DEBUG("Received interest: " << interest);
+  NLSR_LOG_TRACE("Received interest: " << interest);
   context.append(m_routingTable.wireEncode());
   context.end();
 }
diff --git a/src/publisher/dataset-interest-handler.hpp b/src/publisher/dataset-interest-handler.hpp
index cfd21c9..9e5caaf 100644
--- a/src/publisher/dataset-interest-handler.hpp
+++ b/src/publisher/dataset-interest-handler.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -71,11 +71,6 @@
                          const RoutingTable& rt);
 
 private:
-  /*! \brief set dispatcher for localhost or remote router
-   */
-  void
-  setDispatcher(ndn::mgmt::Dispatcher& dispatcher);
-
   /*! \brief provide routing-table dataset
   */
   void
@@ -90,7 +85,6 @@
                    ndn::mgmt::StatusDatasetContext& context);
 
 private:
-  ndn::mgmt::Dispatcher& m_dispatcher;
   const Lsdb& m_lsdb;
   const RoutingTable& m_routingTable;
 };
diff --git a/src/route/name-prefix-table.cpp b/src/route/name-prefix-table.cpp
index 91e6210..deb9af7 100644
--- a/src/route/name-prefix-table.cpp
+++ b/src/route/name-prefix-table.cpp
@@ -33,26 +33,88 @@
 
 INIT_LOGGER(route.NamePrefixTable);
 
-NamePrefixTable::NamePrefixTable(Fib& fib, RoutingTable& routingTable,
-                                 std::unique_ptr<AfterRoutingChange>& afterRoutingChangeSignal)
-  : m_fib(fib)
+NamePrefixTable::NamePrefixTable(const ndn::Name& ownRouterName, Fib& fib,
+                                 RoutingTable& routingTable,
+                                 AfterRoutingChange& afterRoutingChangeSignal,
+                                 Lsdb::AfterLsdbModified& afterLsdbModifiedSignal)
+  : m_ownRouterName(ownRouterName)
+  , m_fib(fib)
   , m_routingTable(routingTable)
 {
-  m_afterRoutingChangeConnection = afterRoutingChangeSignal->connect(
+  m_afterRoutingChangeConnection = afterRoutingChangeSignal.connect(
     [this] (const std::list<RoutingTableEntry>& entries) {
       updateWithNewRoute(entries);
     });
+
+  m_afterLsdbModified = afterLsdbModifiedSignal.connect(
+    [this] (std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
+            const auto& namesToAdd, const auto& namesToRemove) {
+      updateFromLsdb(lsa, updateType, namesToAdd, namesToRemove);
+    }
+  );
 }
 
 NamePrefixTable::~NamePrefixTable()
 {
   m_afterRoutingChangeConnection.disconnect();
+  m_afterLsdbModified.disconnect();
+}
+
+void
+NamePrefixTable::updateFromLsdb(std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
+                                const std::list<ndn::Name>& namesToAdd,
+                                const std::list<ndn::Name>& namesToRemove)
+{
+  if (m_ownRouterName == lsa->getOriginRouter()) {
+    return;
+  }
+  NLSR_LOG_TRACE("Got update from Lsdb for router: " << lsa->getOriginRouter());
+
+  if (updateType == LsdbUpdate::INSTALLED) {
+    addEntry(lsa->getOriginRouter(), lsa->getOriginRouter());
+
+    if (lsa->getType() == Lsa::Type::NAME) {
+      auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
+      for (const auto& name : nlsa->getNpl().getNames()) {
+        if (name != m_ownRouterName) {
+          addEntry(name, lsa->getOriginRouter());
+        }
+      }
+    }
+  }
+  else if (updateType == LsdbUpdate::UPDATED) {
+    if (lsa->getType() != Lsa::Type::NAME) {
+      return;
+    }
+
+    for (const auto& name : namesToAdd) {
+      if (name != m_ownRouterName) {
+        addEntry(name, lsa->getOriginRouter());
+      }
+    }
+
+    for (const auto& name : namesToRemove) {
+      if (name != m_ownRouterName) {
+        removeEntry(name, lsa->getOriginRouter());
+      }
+    }
+  }
+  else {
+    removeEntry(lsa->getOriginRouter(), lsa->getOriginRouter());
+    if (lsa->getType() == Lsa::Type::NAME) {
+      auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
+      for (const auto& name : nlsa->getNpl().getNames()) {
+        if (name != m_ownRouterName) {
+          removeEntry(name, lsa->getOriginRouter());
+        }
+      }
+    }
+  }
 }
 
 void
 NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
 {
-
   // Check if the advertised name prefix is in the table already.
   NptEntryList::iterator nameItr =
     std::find_if(m_table.begin(),
diff --git a/src/route/name-prefix-table.hpp b/src/route/name-prefix-table.hpp
index 370e515..449b928 100644
--- a/src/route/name-prefix-table.hpp
+++ b/src/route/name-prefix-table.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2020,  The University of Memphis,
+/*
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -17,7 +17,7 @@
  *
  * 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/>.
- **/
+ */
 
 #ifndef NLSR_NAME_PREFIX_TABLE_HPP
 #define NLSR_NAME_PREFIX_TABLE_HPP
@@ -27,6 +27,7 @@
 #include "signals.hpp"
 #include "test-access-control.hpp"
 #include "route/fib.hpp"
+#include "lsdb.hpp"
 
 #include <list>
 #include <unordered_map>
@@ -41,11 +42,23 @@
   using NptEntryList = std::list<std::shared_ptr<NamePrefixTableEntry>>;
   using const_iterator = NptEntryList::const_iterator;
 
-  NamePrefixTable(Fib& fib, RoutingTable& routingTable,
-                  std::unique_ptr<AfterRoutingChange>& afterRoutingChangeSignal);
+  NamePrefixTable(const ndn::Name& ownRouterName, Fib& fib, RoutingTable& routingTable,
+                  AfterRoutingChange& afterRoutingChangeSignal,
+                  Lsdb::AfterLsdbModified& afterLsdbModifiedSignal);
 
   ~NamePrefixTable();
 
+  /*! \brief Add, update, or remove Names according to the Lsdb update
+    \param lsa The LSA class pointer
+    \param updateType Update type from Lsdb (INSTALLED, UPDATED, REMOVED)
+    \param namesToAdd If LSA is UPDATED, then these are the names to add
+    \param namesToRemove If LSA is UPDATED, then these are the names to remove
+   */
+  void
+  updateFromLsdb(std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
+                 const std::list<ndn::Name>& namesToAdd,
+                 const std::list<ndn::Name>& namesToRemove);
+
   /*! \brief Adds a destination to the specified name prefix.
     \param name The name prefix
     \param destRouter The destination router prefix
@@ -125,9 +138,11 @@
   NptEntryList m_table;
 
 private:
+  const ndn::Name& m_ownRouterName;
   Fib& m_fib;
   RoutingTable& m_routingTable;
   ndn::util::signal::Connection m_afterRoutingChangeConnection;
+  ndn::util::signal::Connection m_afterLsdbModified;
 };
 
 inline NamePrefixTable::const_iterator
diff --git a/src/route/routing-table.cpp b/src/route/routing-table.cpp
index b600882..c06b429 100644
--- a/src/route/routing-table.cpp
+++ b/src/route/routing-table.cpp
@@ -24,93 +24,85 @@
 #include "conf-parameter.hpp"
 #include "routing-table-calculator.hpp"
 #include "routing-table-entry.hpp"
-#include "name-prefix-table.hpp"
 #include "logger.hpp"
 #include "tlv-nlsr.hpp"
 
-#include <list>
-#include <string>
-
 namespace nlsr {
 
 INIT_LOGGER(route.RoutingTable);
 
-RoutingTable::RoutingTable(ndn::Scheduler& scheduler, Fib& fib, Lsdb& lsdb,
-                           NamePrefixTable& namePrefixTable, ConfParameter& confParam)
-  : afterRoutingChange{std::make_unique<AfterRoutingChange>()}
-  , m_scheduler(scheduler)
-  , m_fib(fib)
+RoutingTable::RoutingTable(ndn::Scheduler& scheduler, Lsdb& lsdb, ConfParameter& confParam)
+  : m_scheduler(scheduler)
   , m_lsdb(lsdb)
-  , m_namePrefixTable(namePrefixTable)
   , m_routingCalcInterval{confParam.getRoutingCalcInterval()}
   , m_isRoutingTableCalculating(false)
   , m_isRouteCalculationScheduled(false)
   , m_confParam(confParam)
+  , m_hyperbolicState(m_confParam.getHyperbolicState())
 {
+  m_afterLsdbModified = lsdb.onLsdbModified.connect(
+    [this] (std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
+            const auto& namesToAdd, const auto& namesToRemove) {
+      auto type = lsa->getType();
+      bool updateForOwnAdjacencyLsa = lsa->getOriginRouter() == m_confParam.getRouterPrefix() &&
+                                      type == Lsa::Type::ADJACENCY;
+      bool scheduleCalculation = false;
+
+      if (updateType == LsdbUpdate::REMOVED && updateForOwnAdjacencyLsa) {
+        // If own Adjacency LSA is removed then we have no ACTIVE neighbors.
+        // (Own Coordinate LSA is never removed. But routing table calculation is scheduled
+        // in HelloProtocol. The routing table calculator for HR takes into account
+        // the INACTIVE status of the link).
+        NLSR_LOG_DEBUG("No Adj LSA of router itself, routing table can not be calculated :(");
+        clearRoutingTable();
+        clearDryRoutingTable();
+        NLSR_LOG_DEBUG("Calling Update NPT With new Route");
+        afterRoutingChange(m_rTable);
+        NLSR_LOG_DEBUG(*this);
+        m_ownAdjLsaExist = false;
+      }
+
+      if (updateType == LsdbUpdate::INSTALLED && updateForOwnAdjacencyLsa) {
+        m_ownAdjLsaExist = true;
+      }
+
+      // Don;t do anything on removal, wait for HelloProtocol to confirm and then react
+      if (updateType == LsdbUpdate::INSTALLED || updateType == LsdbUpdate::UPDATED) {
+        if ((type == Lsa::Type::ADJACENCY  && m_hyperbolicState != HYPERBOLIC_STATE_ON) ||
+            (type == Lsa::Type::COORDINATE && m_hyperbolicState != HYPERBOLIC_STATE_OFF)) {
+          scheduleCalculation = true;
+        }
+      }
+
+      if (scheduleCalculation) {
+        scheduleRoutingTableCalculation();
+      }
+    }
+  );
 }
 
 void
 RoutingTable::calculate()
 {
   m_lsdb.writeLog();
-  m_namePrefixTable.writeLog();
+  NLSR_LOG_TRACE("Calculating routing table");
+
   if (m_isRoutingTableCalculating == false) {
-    // setting routing table calculation
     m_isRoutingTableCalculating = true;
 
-    bool isHrEnabled = m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF;
-
-    if ((!isHrEnabled &&
-         m_lsdb.doesLsaExist(m_confParam.getRouterPrefix(), Lsa::Type::ADJACENCY))
-        ||
-        (isHrEnabled &&
-         m_lsdb.doesLsaExist(m_confParam.getRouterPrefix(), Lsa::Type::COORDINATE))) {
-      if (m_lsdb.getIsBuildAdjLsaSheduled() != 1) {
-        NLSR_LOG_TRACE("Clearing old routing table");
-        clearRoutingTable();
-        // for dry run options
-        clearDryRoutingTable();
-
-        NLSR_LOG_DEBUG("Calculating routing table");
-
-        // calculate Link State routing
-        if ((m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_OFF) ||
-            (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_DRY_RUN)) {
-          calculateLsRoutingTable();
-        }
-        // calculate hyperbolic routing
-        if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
-          calculateHypRoutingTable(false);
-        }
-        // calculate dry hyperbolic routing
-        if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_DRY_RUN) {
-          calculateHypRoutingTable(true);
-        }
-        // Inform the NPT that updates have been made
-        NLSR_LOG_DEBUG("Calling Update NPT With new Route");
-        (*afterRoutingChange)(m_rTable);
-        NLSR_LOG_DEBUG(*this);
-        m_namePrefixTable.writeLog();
-        m_fib.writeLog();
-      }
-      else {
-        NLSR_LOG_DEBUG("Adjacency building is scheduled, so routing table can not be calculated :(");
-      }
+    if (m_hyperbolicState == HYPERBOLIC_STATE_OFF) {
+      calculateLsRoutingTable();
     }
-    else {
-      NLSR_LOG_DEBUG("No Adj LSA of router itself, so Routing table can not be calculated :(");
-      clearRoutingTable();
-      clearDryRoutingTable(); // for dry run options
-      // need to update NPT here
-      NLSR_LOG_DEBUG("Calling Update NPT With new Route");
-      (*afterRoutingChange)(m_rTable);
-      NLSR_LOG_DEBUG(*this);
-      m_namePrefixTable.writeLog();
-      m_fib.writeLog();
-      // debugging purpose end
+    else if (m_hyperbolicState == HYPERBOLIC_STATE_DRY_RUN) {
+      calculateLsRoutingTable();
+      calculateHypRoutingTable(true);
     }
-    m_isRouteCalculationScheduled = false; // clear scheduled flag
-    m_isRoutingTableCalculating = false; // unsetting routing table calculation
+    else if (m_hyperbolicState == HYPERBOLIC_STATE_ON) {
+      calculateHypRoutingTable(false);
+    }
+
+    m_isRouteCalculationScheduled = false;
+    m_isRoutingTableCalculating = false;
   }
   else {
     scheduleRoutingTableCalculation();
@@ -122,6 +114,19 @@
 {
   NLSR_LOG_TRACE("CalculateLsRoutingTable Called");
 
+  if (m_lsdb.getIsBuildAdjLsaScheduled()) {
+    NLSR_LOG_DEBUG("Adjacency build is scheduled, routing table can not be calculated :(");
+    return;
+  }
+
+  // We only check this in LS since we never remove our own Coordinate LSA,
+  // whereas we remove our own Adjacency LSA if we don't have any neighbors
+  if (!m_ownAdjLsaExist) {
+    return;
+  }
+
+  clearRoutingTable();
+
   Map map;
   auto lsaRange = m_lsdb.getLsdbIterator<AdjLsa>();
   map.createFromAdjLsdb(lsaRange.first, lsaRange.second);
@@ -132,11 +137,22 @@
   LinkStateRoutingTableCalculator calculator(nRouters);
 
   calculator.calculatePath(map, *this, m_confParam, m_lsdb);
+
+  NLSR_LOG_DEBUG("Calling Update NPT With new Route");
+  afterRoutingChange(m_rTable);
+  NLSR_LOG_DEBUG(*this);
 }
 
 void
 RoutingTable::calculateHypRoutingTable(bool isDryRun)
 {
+  if (isDryRun) {
+    clearDryRoutingTable();
+  }
+  else {
+    clearRoutingTable();
+  }
+
   Map map;
   auto lsaRange = m_lsdb.getLsdbIterator<CoordinateLsa>();
   map.createFromCoordinateLsdb(lsaRange.first, lsaRange.second);
@@ -147,6 +163,12 @@
   HyperbolicRoutingCalculator calculator(nRouters, isDryRun, m_confParam.getRouterPrefix());
 
   calculator.calculatePath(map, *this, m_lsdb, m_confParam.getAdjacencyList());
+
+  if (!isDryRun) {
+    NLSR_LOG_DEBUG("Calling Update NPT With new Route");
+    afterRoutingChange(m_rTable);
+    NLSR_LOG_DEBUG(*this);
+  }
 }
 
 void
@@ -179,6 +201,7 @@
   else {
     rteChk->getNexthopList().addNextHop(nh);
   }
+  m_wire.reset();
 }
 
 RoutingTableEntry*
@@ -207,22 +230,21 @@
   else {
     it->getNexthopList().addNextHop(nh);
   }
+  m_wire.reset();
 }
 
 void
 RoutingTable::clearRoutingTable()
 {
-  if (m_rTable.size() > 0) {
-    m_rTable.clear();
-  }
+  m_rTable.clear();
+  m_wire.reset();
 }
 
 void
 RoutingTable::clearDryRoutingTable()
 {
-  if (m_dryTable.size() > 0) {
-    m_dryTable.clear();
-  }
+  m_dryTable.clear();
+  m_wire.reset();
 }
 
 template<ndn::encoding::Tag TAG>
diff --git a/src/route/routing-table.hpp b/src/route/routing-table.hpp
index 4a0ebd2..f7e0525 100644
--- a/src/route/routing-table.hpp
+++ b/src/route/routing-table.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California
  *
  * This file is part of NLSR (Named-data Link State Routing).
@@ -27,6 +27,7 @@
 #include "lsdb.hpp"
 #include "route/fib.hpp"
 #include "test-access-control.hpp"
+#include "route/name-prefix-table.hpp"
 
 #include <ndn-cxx/util/scheduler.hpp>
 
@@ -89,8 +90,12 @@
 {
 public:
   explicit
-  RoutingTable(ndn::Scheduler& scheduler, Fib& fib, Lsdb& lsdb,
-               NamePrefixTable& namePrefixTable, ConfParameter& confParam);
+  RoutingTable(ndn::Scheduler& scheduler, Lsdb& lsdb, ConfParameter& confParam);
+
+  ~RoutingTable()
+  {
+    m_afterLsdbModified.disconnect();
+  }
 
   /*! \brief Calculates a list of next hops for each router in the network.
    *
@@ -122,24 +127,6 @@
   void
   scheduleRoutingTableCalculation();
 
-  void
-  setRoutingCalcInterval(uint32_t interval)
-  {
-    m_routingCalcInterval = ndn::time::seconds(interval);
-  }
-
-  const ndn::time::seconds&
-  getRoutingCalcInterval() const
-  {
-    return m_routingCalcInterval;
-  }
-
-  uint64_t
-  getRtSize()
-  {
-    return m_rTable.size();
-  }
-
 private:
   /*! \brief Calculates a link-state routing table. */
   void
@@ -156,21 +143,21 @@
   clearDryRoutingTable();
 
 public:
-  std::unique_ptr<AfterRoutingChange> afterRoutingChange;
+  AfterRoutingChange afterRoutingChange;
 
 private:
   ndn::Scheduler& m_scheduler;
-  Fib& m_fib;
   Lsdb& m_lsdb;
-  NamePrefixTable& m_namePrefixTable;
-
-  ndn::time::seconds m_routingCalcInterval;
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  ndn::time::seconds m_routingCalcInterval;
   bool m_isRoutingTableCalculating;
   bool m_isRouteCalculationScheduled;
 
   ConfParameter& m_confParam;
+  ndn::util::signal::Connection m_afterLsdbModified;
+  int32_t m_hyperbolicState;
+  bool m_ownAdjLsaExist = false;
 };
 
 } // namespace nlsr
diff --git a/src/security/certificate-store.cpp b/src/security/certificate-store.cpp
index 99067a7..1a3025e 100644
--- a/src/security/certificate-store.cpp
+++ b/src/security/certificate-store.cpp
@@ -33,11 +33,7 @@
 CertificateStore::CertificateStore(ndn::Face& face, ConfParameter& confParam, Lsdb& lsdb)
   : m_face(face)
   , m_confParam(confParam)
-  , m_lsdb(lsdb)
   , m_validator(m_confParam.getValidator())
-  , m_afterSegmentValidatedConnection(m_lsdb.afterSegmentValidatedSignal.connect(
-                                      std::bind(&CertificateStore::afterFetcherSignalEmitted,
-                                                this, _1)))
 {
   for (const auto& x: confParam.getIdCerts()) {
     auto idCert = ndn::io::load<ndn::security::Certificate>(x);
@@ -45,6 +41,9 @@
   }
 
   registerKeyPrefixes();
+
+  m_afterSegmentValidatedConnection = lsdb.afterSegmentValidatedSignal.connect(
+    [this] (const ndn::Data& data) { afterFetcherSignalEmitted(data); });
 }
 
 void
diff --git a/src/security/certificate-store.hpp b/src/security/certificate-store.hpp
index 95437c5..79a0cf7 100644
--- a/src/security/certificate-store.hpp
+++ b/src/security/certificate-store.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -96,7 +96,6 @@
   CertMap m_certificates;
   ndn::Face& m_face;
   ConfParameter& m_confParam;
-  Lsdb& m_lsdb;
   ndn::security::ValidatorConfig& m_validator;
   ndn::util::signal::ScopedConnection m_afterSegmentValidatedConnection;
 };
diff --git a/tests/publisher/publisher-fixture.hpp b/tests/publisher/publisher-fixture.hpp
index 18a51f0..3dcf103 100644
--- a/tests/publisher/publisher-fixture.hpp
+++ b/tests/publisher/publisher-fixture.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2020,  The University of Memphis,
+/*
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -17,7 +17,7 @@
  *
  * 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/>.
- **/
+ */
 
 #ifndef NLSR_PUBLISHER_FIXTURE_HPP
 #define NLSR_PUBLISHER_FIXTURE_HPP
@@ -52,8 +52,6 @@
     , rt1(nlsr.m_routingTable)
   {
     routerId = addIdentity(conf.getRouterPrefix());
-
-    nlsr.initialize();
     face.processEvents(ndn::time::milliseconds(100));
   }
 
diff --git a/tests/route/test-name-prefix-table.cpp b/tests/route/test-name-prefix-table.cpp
index 9585106..fbe6c5a 100644
--- a/tests/route/test-name-prefix-table.cpp
+++ b/tests/route/test-name-prefix-table.cpp
@@ -20,7 +20,9 @@
  */
 
 #include "route/name-prefix-table.hpp"
-#include "nlsr.hpp"
+#include "route/fib.hpp"
+#include "route/routing-table.hpp"
+#include "lsdb.hpp"
 #include "../test-common.hpp"
 
 #include <ndn-cxx/util/dummy-client-face.hpp>
@@ -34,32 +36,38 @@
   NamePrefixTableFixture()
     : face(m_ioService, m_keyChain)
     , conf(face, m_keyChain)
-    , nlsr(face, m_keyChain, conf)
-    , lsdb(nlsr.m_lsdb)
-    , npt(nlsr.m_namePrefixTable)
+    , confProcessor(conf)
+    , lsdb(face, m_keyChain, conf)
+    , fib(face, m_scheduler, conf.getAdjacencyList(), conf, m_keyChain)
+    , rt(m_scheduler, lsdb, conf)
+    , npt(conf.getRouterPrefix(), fib, rt, rt.afterRoutingChange, lsdb.onLsdbModified)
   {
   }
 
+  bool
+  isNameInNpt(const ndn::Name& name)
+  {
+    auto it = std::find_if(npt.begin(), npt.end(),
+                           [&] (const auto& entry) { return name == entry->getNamePrefix(); });
+    return it != npt.end();
+  }
+
 public:
   ndn::util::DummyClientFace face;
   ConfParameter conf;
-  Nlsr nlsr;
+  DummyConfFileProcessor confProcessor;
 
-  Lsdb& lsdb;
-  NamePrefixTable& npt;
+  Lsdb lsdb;
+  Fib fib;
+  RoutingTable rt;
+  NamePrefixTable npt;
 };
 
 BOOST_AUTO_TEST_SUITE(TestNamePrefixTable)
 
 BOOST_FIXTURE_TEST_CASE(Bupt, NamePrefixTableFixture)
 {
-  conf.setNetwork("/ndn");
-  conf.setSiteName("/router");
-  conf.setRouterName("/a");
-  conf.buildRouterAndSyncUserPrefix();
-
-  RoutingTable& routingTable = nlsr.m_routingTable;
-  routingTable.setRoutingCalcInterval(0);
+  rt.m_routingCalcInterval = 0_s;
 
   Adjacent thisRouter(conf.getRouterPrefix(), ndn::FaceUri("udp4://10.0.0.1"), 0, Adjacent::STATUS_ACTIVE, 0, 0);
 
@@ -265,7 +273,6 @@
 
 BOOST_FIXTURE_TEST_CASE(RoutingTableUpdate, NamePrefixTableFixture)
 {
-  RoutingTable& routingTable = nlsr.m_routingTable;
   const ndn::Name destination = ndn::Name{"/ndn/destination1"};
   NextHop hop1{"upd4://10.0.0.1", 0};
   NextHop hop2{"udp4://10.0.0.2", 1};
@@ -273,10 +280,10 @@
   const NamePrefixTableEntry entry1{"/ndn/router1"};
   npt.addEntry(entry1.getNamePrefix(), destination);
 
-  routingTable.addNextHop(destination, hop1);
-  routingTable.addNextHop(destination, hop2);
+  rt.addNextHop(destination, hop1);
+  rt.addNextHop(destination, hop2);
 
-  npt.updateWithNewRoute(routingTable.m_rTable);
+  npt.updateWithNewRoute(rt.m_rTable);
 
   // At this point the NamePrefixTableEntry should have two NextHops.
   auto nameIterator = std::find_if(npt.begin(), npt.end(),
@@ -291,8 +298,8 @@
   BOOST_CHECK_EQUAL(nextHops.size(), 2);
 
   // Add the other NextHop
-  routingTable.addNextHop(destination, hop3);
-  npt.updateWithNewRoute(routingTable.m_rTable);
+  rt.addNextHop(destination, hop3);
+  npt.updateWithNewRoute(rt.m_rTable);
 
   // At this point the NamePrefixTableEntry should have three NextHops.
   nameIterator = std::find_if(npt.begin(), npt.end(),
@@ -306,6 +313,65 @@
   BOOST_CHECK_EQUAL(nextHops.size(), 3);
 }
 
+BOOST_FIXTURE_TEST_CASE(UpdateFromLsdb, NamePrefixTableFixture)
+{
+  ndn::time::system_clock::TimePoint testTimePoint =  ndn::time::system_clock::now();
+  NamePrefixList npl1;
+  ndn::Name n1("name1");
+  ndn::Name n2("name2");
+  ndn::Name router1("/router1/1");
+
+  npl1.insert(n1);
+  npl1.insert(n2);
+
+  NameLsa nlsa1(router1, 12, testTimePoint, npl1);
+  std::shared_ptr<Lsa> lsaPtr = std::make_shared<NameLsa>(nlsa1);
+
+  BOOST_CHECK(npt.begin() == npt.end());
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::INSTALLED, {}, {});
+  BOOST_CHECK_EQUAL(npt.m_table.size(), 3); // Router + 2 names
+
+  BOOST_CHECK(isNameInNpt(n1));
+  BOOST_CHECK(isNameInNpt(n2));
+
+  ndn::Name n3("name3");
+  auto nlsa = std::static_pointer_cast<NameLsa>(lsaPtr);
+  nlsa->removeName(n2);
+  nlsa->addName(n3);
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::UPDATED, {n3}, {n2});
+  BOOST_CHECK(isNameInNpt(n1));
+  BOOST_CHECK(!isNameInNpt(n2)); // Removed
+  BOOST_CHECK(isNameInNpt(n3));
+
+  BOOST_CHECK_EQUAL(npt.m_table.size(), 3); // Still router + 2 names
+
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::REMOVED, {}, {});
+  BOOST_CHECK_EQUAL(npt.m_table.size(), 0);
+
+  // Adj and Coordinate LSAs router
+  ndn::Name router2("/router2/2");
+  AdjLsa adjLsa(router2, 12, testTimePoint, 2, conf.getAdjacencyList());
+  lsaPtr = std::make_shared<AdjLsa>(adjLsa);
+  BOOST_CHECK(npt.begin() == npt.end());
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::INSTALLED, {}, {});
+  BOOST_CHECK_EQUAL(npt.m_table.size(), 1);
+  BOOST_CHECK(isNameInNpt(router2));
+
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::REMOVED, {}, {});
+  BOOST_CHECK_EQUAL(npt.m_table.size(), 0);
+
+  ndn::Name router3("/router3/3");
+  CoordinateLsa corLsa(router3, 12, testTimePoint, 2, {3});
+  lsaPtr = std::make_shared<CoordinateLsa>(corLsa);
+  BOOST_CHECK(npt.begin() == npt.end());
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::INSTALLED, {}, {});
+  BOOST_CHECK_EQUAL(npt.m_table.size(), 1);
+  BOOST_CHECK(isNameInNpt(router3));
+
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::REMOVED, {}, {});
+  BOOST_CHECK_EQUAL(npt.m_table.size(), 0);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace test
diff --git a/tests/route/test-routing-table.cpp b/tests/route/test-routing-table.cpp
index 0bce153..6a2971e 100644
--- a/tests/route/test-routing-table.cpp
+++ b/tests/route/test-routing-table.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California
  *
  * This file is part of NLSR (Named-data Link State Routing).
@@ -28,23 +28,25 @@
 namespace nlsr {
 namespace test {
 
-class RoutingTableFixture
+class RoutingTableFixture : public UnitTestTimeFixture
 {
 public:
   RoutingTableFixture()
-    : conf(face, keyChain)
-    , nlsr(face, keyChain, conf)
-    , rt(nlsr.m_routingTable)
+    : face(m_ioService, m_keyChain, {true, true})
+    , conf(face, m_keyChain)
+    , confProcessor(conf)
+    , lsdb(face, m_keyChain, conf)
+    , rt(m_scheduler, lsdb, conf)
   {
   }
 
 public:
   ndn::util::DummyClientFace face;
-  ndn::KeyChain keyChain;
   ConfParameter conf;
-  Nlsr nlsr;
+  DummyConfFileProcessor confProcessor;
 
-  RoutingTable& rt;
+  Lsdb lsdb;
+  RoutingTable rt;
 };
 
 BOOST_AUTO_TEST_SUITE(TestRoutingTable)
@@ -130,6 +132,83 @@
                     "    NextHop(Uri: nexthop, Cost: 99)\n");
 }
 
+BOOST_FIXTURE_TEST_CASE(UpdateFromLsdb, RoutingTableFixture)
+{
+  ndn::time::system_clock::TimePoint testTimePoint = ndn::time::system_clock::now() + 3600_s;
+  ndn::Name router2("/router2");
+  AdjLsa adjLsa(router2, 12, testTimePoint, 2, conf.getAdjacencyList());
+  std::shared_ptr<Lsa> lsaPtr = std::make_shared<AdjLsa>(adjLsa);
+  BOOST_CHECK(!rt.m_isRouteCalculationScheduled);
+  lsdb.installLsa(lsaPtr);
+  BOOST_CHECK(rt.m_isRouteCalculationScheduled);
+
+  // After 15_s (by default) routing table calculation is done
+  advanceClocks(15_s);
+  BOOST_CHECK(!rt.m_isRouteCalculationScheduled);
+
+  // Update to installed LSA
+  std::shared_ptr<Lsa> lsaPtr2 = std::make_shared<AdjLsa>(adjLsa);
+  auto adjPtr = std::static_pointer_cast<AdjLsa>(lsaPtr2);
+  adjPtr->addAdjacent(Adjacent("router3"));
+  adjPtr->setSeqNo(13);
+  lsdb.installLsa(lsaPtr2);
+  BOOST_CHECK(rt.m_isRouteCalculationScheduled);
+
+  // Insert a neighbor so that AdjLsa can be installed
+  AdjacencyList adjl;
+  Adjacent ownAdj(conf.getRouterPrefix());
+  ownAdj.setStatus(Adjacent::STATUS_ACTIVE);
+  adjl.insert(ownAdj);
+  AdjLsa adjLsa4("/router4", 12, testTimePoint, 2, adjl);
+  lsaPtr = std::make_shared<AdjLsa>(adjLsa4);
+  lsdb.installLsa(lsaPtr);
+
+  Adjacent adj("/router4");
+  adj.setStatus(Adjacent::STATUS_ACTIVE);
+  conf.getAdjacencyList().insert(adj);
+  lsdb.scheduleAdjLsaBuild();
+  BOOST_CHECK_EQUAL(rt.m_rTable.size(), 0);
+  advanceClocks(15_s);
+  BOOST_CHECK_EQUAL(rt.m_rTable.size(), 1);
+
+  rt.wireEncode();
+  BOOST_CHECK(rt.m_wire.isValid());
+  BOOST_CHECK_GT(rt.m_wire.size(), 0);
+
+  // Remove own Adj Lsa - Make sure routing table is wiped out
+  conf.getAdjacencyList().setStatusOfNeighbor("/router4", Adjacent::STATUS_INACTIVE);
+  conf.getAdjacencyList().setTimedOutInterestCount("/router4", HELLO_RETRIES_MAX);
+  lsdb.scheduleAdjLsaBuild();
+  advanceClocks(15_s);
+  BOOST_CHECK_EQUAL(rt.m_rTable.size(), 0);
+  BOOST_CHECK(!rt.m_wire.isValid());
+
+  // Check that HR routing is scheduled, once Coordinate LSA is added
+  BOOST_CHECK(!rt.m_isRouteCalculationScheduled);
+  rt.m_hyperbolicState = HYPERBOLIC_STATE_ON;
+  CoordinateLsa clsa("router5", 12, testTimePoint, 2.5, {30.0});
+  auto clsaPtr = std::make_shared<CoordinateLsa>(clsa);
+  lsdb.installLsa(clsaPtr);
+  BOOST_CHECK(rt.m_isRouteCalculationScheduled);
+
+  Adjacent router5("/router5");
+  router5.setStatus(Adjacent::STATUS_ACTIVE);
+  conf.getAdjacencyList().insert(router5);
+  conf.getAdjacencyList().setStatusOfNeighbor("/router5", Adjacent::STATUS_ACTIVE);
+  advanceClocks(15_s);
+  rt.wireEncode();
+  BOOST_CHECK(rt.m_wire.isValid());
+  BOOST_CHECK_GT(rt.m_wire.size(), 0);
+  BOOST_CHECK(!rt.m_isRouteCalculationScheduled);
+
+  // Emulate HelloProtocol neighbor down
+  conf.getAdjacencyList().setStatusOfNeighbor("/router5", Adjacent::STATUS_INACTIVE);
+  rt.scheduleRoutingTableCalculation();
+  advanceClocks(15_s);
+  BOOST_CHECK_EQUAL(rt.m_rTable.size(), 0);
+  BOOST_CHECK(!rt.m_wire.isValid());
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace test
diff --git a/tests/test-hello-protocol.cpp b/tests/test-hello-protocol.cpp
index 67bf272..f5aee2b 100644
--- a/tests/test-hello-protocol.cpp
+++ b/tests/test-hello-protocol.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -68,7 +68,7 @@
       BOOST_CHECK_EQUAL(nlsr.m_routingTable.m_isRouteCalculationScheduled, false);
     }
     else {
-      BOOST_CHECK_EQUAL(nlsr.m_lsdb.m_isBuildAdjLsaSheduled, false);
+      BOOST_CHECK_EQUAL(nlsr.m_lsdb.m_isBuildAdjLsaScheduled, false);
     }
     BOOST_CHECK_EQUAL(adjList.findAdjacent(ndn::Name(ACTIVE_NEIGHBOR))->getStatus(),
                       Adjacent::STATUS_ACTIVE);
@@ -79,7 +79,7 @@
       BOOST_CHECK_EQUAL(nlsr.m_routingTable.m_isRouteCalculationScheduled, true);
     }
     else {
-      BOOST_CHECK_EQUAL(nlsr.m_lsdb.m_isBuildAdjLsaSheduled, true);
+      BOOST_CHECK_EQUAL(nlsr.m_lsdb.m_isBuildAdjLsaScheduled, true);
     }
     BOOST_CHECK_EQUAL(adjList.findAdjacent(ndn::Name(ACTIVE_NEIGHBOR))->getStatus(),
                       Adjacent::STATUS_INACTIVE);
diff --git a/tests/test-lsa-rule.cpp b/tests/test-lsa-rule.cpp
index 2827cd1..e6d4458 100644
--- a/tests/test-lsa-rule.cpp
+++ b/tests/test-lsa-rule.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -50,7 +50,7 @@
     , confParam(face, m_keyChain)
     , confProcessor(confParam, SYNC_PROTOCOL_PSYNC, HYPERBOLIC_STATE_OFF,
                     "/ndn/", "/edu/test-site", "/%C1.Router/router1")
-    , nlsr(face, m_keyChain, confParam)
+    , lsdb(face, m_keyChain, confParam)
     , ROOT_CERT_PATH(boost::filesystem::current_path() / std::string("root.cert"))
   {
     rootId = addIdentity(rootIdName);
@@ -90,9 +90,6 @@
     }
     inputFile.close();
 
-    // Initialize NLSR to initialize the keyChain
-    nlsr.initialize();
-
     this->advanceClocks(ndn::time::milliseconds(10));
 
     face.sentInterests.clear();
@@ -105,7 +102,7 @@
   ndn::security::pib::Identity rootId, siteIdentity, opIdentity, routerId;
   ConfParameter confParam;
   DummyConfFileProcessor confProcessor;
-  Nlsr nlsr;
+  Lsdb lsdb;
 
   const boost::filesystem::path ROOT_CERT_PATH;
 };
@@ -122,7 +119,7 @@
   lsaDataName.append(boost::lexical_cast<std::string>(Lsa::Type::NAME));
 
   // This would be the sequence number of its own NameLsa
-  lsaDataName.appendNumber(nlsr.m_lsdb.m_sequencingManager.getNameLsaSeq());
+  lsaDataName.appendNumber(lsdb.m_sequencingManager.getNameLsaSeq());
 
   // Append version, segmentNo
   lsaDataName.appendNumber(1).appendNumber(1);
@@ -152,7 +149,7 @@
   lsaDataName.append(boost::lexical_cast<std::string>(Lsa::Type::NAME));
 
   // This would be the sequence number of its own NameLsa
-  lsaDataName.appendNumber(nlsr.m_lsdb.m_sequencingManager.getNameLsaSeq());
+  lsaDataName.appendNumber(lsdb.m_sequencingManager.getNameLsaSeq());
 
   // Append version, segmentNo
   lsaDataName.appendNumber(1).appendNumber(1);
diff --git a/tests/test-lsa-segment-storage.cpp b/tests/test-lsa-segment-storage.cpp
index 7862e45..3110e87 100644
--- a/tests/test-lsa-segment-storage.cpp
+++ b/tests/test-lsa-segment-storage.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2020,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2021,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -53,10 +53,7 @@
                           )CONF";
     conf.m_validator.load(config, "config-file-from-string");
 
-    nlsr.initialize();
-
     this->advanceClocks(ndn::time::milliseconds(10));
-
     face.sentInterests.clear();
   }
 
diff --git a/tests/test-lsdb.cpp b/tests/test-lsdb.cpp
index 317cc6b..db1c60b 100644
--- a/tests/test-lsdb.cpp
+++ b/tests/test-lsdb.cpp
@@ -22,7 +22,6 @@
 #include "lsdb.hpp"
 
 #include "test-common.hpp"
-#include "nlsr.hpp"
 #include "lsa/lsa.hpp"
 #include "name-prefix-list.hpp"
 
@@ -41,15 +40,12 @@
     : face(m_ioService, m_keyChain, {true, true})
     , conf(face, m_keyChain)
     , confProcessor(conf)
-    , nlsr(face, m_keyChain, conf)
-    , lsdb(nlsr.m_lsdb)
+    , lsdb(face, m_keyChain, conf)
     , REGISTER_COMMAND_PREFIX("/localhost/nfd/rib")
     , REGISTER_VERB("register")
   {
     addIdentity("/ndn/site/%C1.Router/this-router");
 
-    nlsr.initialize();
-
     advanceClocks(10_ms);
     face.sentInterests.clear();
   }
@@ -100,15 +96,50 @@
     BOOST_CHECK(false);
   }
 
+  void
+  checkSignalResult(LsdbUpdate updateType,
+                    const std::shared_ptr<Lsa>& lsaPtr,
+                    const std::list<ndn::Name>& namesToAdd,
+                    const std::list<ndn::Name>& namesToRemove)
+  {
+    BOOST_CHECK(updateHappened);
+    BOOST_CHECK_EQUAL(lsaPtrCheck->getOriginRouter(), lsaPtr->getOriginRouter());
+    BOOST_CHECK_EQUAL(lsaPtrCheck->getType(), lsaPtr->getType());
+    BOOST_CHECK(updateType == updateTypeCheck);
+    BOOST_CHECK(namesToAdd == namesToAddCheck);
+    BOOST_CHECK(namesToRemove == namesToRemoveCheck);
+    updateHappened = false;
+  }
+
+  void
+  connectSignal()
+  {
+    lsdb.onLsdbModified.connect(
+      [&] (std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
+           const auto& namesToAdd, const auto& namesToRemove) {
+        lsaPtrCheck = lsa;
+        updateTypeCheck = updateType;
+        namesToAddCheck = namesToAdd;
+        namesToRemoveCheck = namesToRemove;
+        updateHappened = true;
+      }
+    );
+  }
+
 public:
   ndn::util::DummyClientFace face;
   ConfParameter conf;
   DummyConfFileProcessor confProcessor;
-  Nlsr nlsr;
-  Lsdb& lsdb;
+  Lsdb lsdb;
 
   ndn::Name REGISTER_COMMAND_PREFIX;
   ndn::Name::Component REGISTER_VERB;
+
+  LsdbUpdate updateTypeCheck = LsdbUpdate::INSTALLED;
+  std::list<ndn::Name> namesToAddCheck;
+  std::list<ndn::Name> namesToRemoveCheck;
+  std::shared_ptr<Lsa> lsaPtrCheck = nullptr;
+  bool updateHappened = false;
 };
 
 BOOST_FIXTURE_TEST_SUITE(TestLsdb, LsdbFixture)
@@ -212,9 +243,8 @@
                 }
             )CONF";
   conf2.getValidator().load(config, "config-file-from-string");
-  Nlsr nlsr2(face2, m_keyChain, conf2);
 
-  Lsdb& lsdb2(nlsr2.m_lsdb);
+  Lsdb lsdb2(face2, m_keyChain, conf2);
 
   advanceClocks(ndn::time::milliseconds(10), 10);
 
@@ -304,7 +334,7 @@
   // 1800 seconds is the default life time.
   NameLsa nlsa1(router1, 12, testTimePoint, npl1);
 
-  Lsdb& lsdb1(nlsr.m_lsdb);
+  Lsdb& lsdb1(lsdb);
 
   lsdb1.installLsa(std::make_shared<NameLsa>(nlsa1));
 
@@ -404,6 +434,70 @@
   BOOST_CHECK(lsdb.isLsaNew(originRouter, Lsa::Type::NAME, higherSeqNo));
 }
 
+BOOST_AUTO_TEST_CASE(LsdbSignals)
+{
+  connectSignal();
+  auto testTimePoint = ndn::time::system_clock::now() + 3600_s;
+  ndn::Name router2("/router2");
+  AdjLsa adjLsa(router2, 12, testTimePoint, 2, conf.getAdjacencyList());
+  std::shared_ptr<Lsa> lsaPtr = std::make_shared<AdjLsa>(adjLsa);
+  lsdb.installLsa(lsaPtr);
+  checkSignalResult(LsdbUpdate::INSTALLED, lsaPtr, {}, {});
+
+  adjLsa.setSeqNo(13);
+  updateHappened = false;
+  lsaPtr = std::make_shared<AdjLsa>(adjLsa);
+  lsdb.installLsa(lsaPtr);
+  BOOST_CHECK(!updateHappened);
+
+  Adjacent adj("Neighbor1");
+  adjLsa.setSeqNo(14);
+  adjLsa.addAdjacent(adj);
+  lsaPtr = std::make_shared<AdjLsa>(adjLsa);
+  lsdb.installLsa(lsaPtr);
+  checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {}, {});
+
+  lsdb.removeLsa(lsaPtrCheck->getOriginRouter(), Lsa::Type::ADJACENCY);
+  checkSignalResult(LsdbUpdate::REMOVED, lsaPtr, {}, {});
+
+  // Name LSA
+  NamePrefixList npl1{"name1", "name2"};
+  NameLsa nameLsa(router2, 12, testTimePoint, npl1);
+  lsaPtr = std::make_shared<NameLsa>(nameLsa);
+  lsdb.installLsa(lsaPtr);
+  checkSignalResult(LsdbUpdate::INSTALLED, lsaPtr, {}, {});
+
+  nameLsa.setSeqNo(13);
+  lsaPtr = std::make_shared<NameLsa>(nameLsa);
+  lsdb.installLsa(lsaPtr);
+  BOOST_CHECK(!updateHappened);
+
+  NamePrefixList npl2{"name2", "name3"};
+  NameLsa nameLsa2(router2, 14, testTimePoint, npl2);
+  lsaPtr = std::make_shared<NameLsa>(nameLsa2);
+  lsdb.installLsa(lsaPtr);
+  checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {"name3"}, {"name1"});
+
+  lsdb.removeLsa(lsaPtrCheck->getOriginRouter(), Lsa::Type::NAME);
+  checkSignalResult(LsdbUpdate::REMOVED, lsaPtr, {}, {});
+
+  // Coordinate LSA
+  lsaPtr = std::make_shared<CoordinateLsa>(CoordinateLsa("router1", 12, testTimePoint, 2.5, {30}));
+  lsdb.installLsa(lsaPtr);
+  checkSignalResult(LsdbUpdate::INSTALLED, lsaPtr, {}, {});
+
+  lsaPtr = std::make_shared<CoordinateLsa>(CoordinateLsa("router1", 13, testTimePoint, 2.5, {30}));
+  lsdb.installLsa(lsaPtr);
+  BOOST_CHECK(!updateHappened);
+
+  lsaPtr = std::make_shared<CoordinateLsa>(CoordinateLsa("router1", 14, testTimePoint, 2.5, {40}));
+  lsdb.installLsa(lsaPtr);
+  checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {}, {});
+
+  lsdb.removeLsa(lsaPtrCheck->getOriginRouter(), Lsa::Type::COORDINATE);
+  checkSignalResult(LsdbUpdate::REMOVED, lsaPtr, {}, {});
+}
+
 BOOST_AUTO_TEST_SUITE_END() // TestLsdb
 
 } // namespace test
diff --git a/tests/test-nlsr.cpp b/tests/test-nlsr.cpp
index dc91c73..1f6c23c 100644
--- a/tests/test-nlsr.cpp
+++ b/tests/test-nlsr.cpp
@@ -85,7 +85,7 @@
 
   conf.setHyperbolicState(HYPERBOLIC_STATE_ON);
 
-  nlsr.initialize();
+  Nlsr nlsr2(m_face, m_keyChain, conf);
 
   for (const auto& neighbor : neighbors.getAdjList()) {
     BOOST_CHECK_EQUAL(neighbor.getLinkCost(), 0);
@@ -107,7 +107,7 @@
                      Adjacent::STATUS_INACTIVE, 0, 0);
   neighbors.insert(neighborC);
 
-  nlsr.initialize();
+  Nlsr nlsr2(m_face, m_keyChain, conf);
 
   for (const auto& neighbor : neighbors.getAdjList()) {
     BOOST_CHECK_NE(neighbor.getLinkCost(), 0);
@@ -125,8 +125,8 @@
   const Lsdb& lsdb = nlsr2.m_lsdb;
   const RoutingTable& rt = nlsr2.m_routingTable;
 
-  BOOST_CHECK_EQUAL(lsdb.m_adjLsaBuildInterval, ndn::time::seconds(3));
-  BOOST_CHECK_EQUAL(rt.getRoutingCalcInterval(), ndn::time::seconds(9));
+  BOOST_CHECK_EQUAL(lsdb.m_adjLsaBuildInterval, 3_s);
+  BOOST_CHECK_EQUAL(rt.m_routingCalcInterval, 9_s);
 }
 
 BOOST_AUTO_TEST_CASE(FaceCreateEvent)
@@ -263,7 +263,6 @@
   // Set HelloInterest lifetime as 10 seconds so that neighbors are not marked INACTIVE
   // upon timeout before this test ends
   conf.setInterestResendTime(10);
-  nlsr.initialize();
 
   // Simulate successful HELLO responses
   lsdb.scheduleAdjLsaBuild();
@@ -367,8 +366,6 @@
 
   neighbors.insert(neighborB);
 
-  nlsr.initialize();
-
   this->advanceClocks(10_ms);
 
   // Receive HELLO response from Router A
diff --git a/tests/test-statistics.cpp b/tests/test-statistics.cpp
index 016d51e..0000fb0 100644
--- a/tests/test-statistics.cpp
+++ b/tests/test-statistics.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -47,8 +47,6 @@
 
     addIdentity(conf.getRouterPrefix());
 
-    nlsr.initialize();
-
     this->advanceClocks(ndn::time::milliseconds(1), 10);
     face.sentInterests.clear();
   }
diff --git a/tests/update/test-advertise-crash.cpp b/tests/update/test-advertise-crash.cpp
index 4e8f112..d6aea8a 100644
--- a/tests/update/test-advertise-crash.cpp
+++ b/tests/update/test-advertise-crash.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2020,  The University of Memphis,
+/*
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -17,7 +17,7 @@
  *
  * 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 "nlsr.hpp"
 
@@ -51,9 +51,6 @@
 
     addIdentity(conf.getRouterPrefix());
 
-    // So that NLSR starts listening on prefixes
-    nlsr.initialize();
-
     // Simulate a callback with fake response
     // This will trigger the undefined behavior found
     // in fib.cpp if an operation is done on non-existent faceUri
diff --git a/tests/update/test-nfd-rib-command-processor.cpp b/tests/update/test-nfd-rib-command-processor.cpp
index 47f02c5..d5fa0c8 100644
--- a/tests/update/test-nfd-rib-command-processor.cpp
+++ b/tests/update/test-nfd-rib-command-processor.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2020,  The University of Memphis,
+/*
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -17,7 +17,7 @@
  *
  * 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 "update/nfd-rib-command-processor.hpp"
 #include "adjacency-list.hpp"
@@ -43,9 +43,6 @@
   {
     addIdentity(conf.getRouterPrefix());
 
-    // Initialize NLSR so a sync socket is created
-    nlsr.initialize();
-
     this->advanceClocks(ndn::time::milliseconds(10), 10);
     face.sentInterests.clear();
 
diff --git a/tests/update/test-prefix-update-processor.cpp b/tests/update/test-prefix-update-processor.cpp
index ca887d1..e5a5890 100644
--- a/tests/update/test-prefix-update-processor.cpp
+++ b/tests/update/test-prefix-update-processor.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2020,  The University of Memphis,
+/*
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -17,7 +17,7 @@
  *
  * 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 "update/prefix-update-processor.hpp"
 #include "nlsr.hpp"
@@ -86,9 +86,6 @@
 
     addIdentity(conf.getRouterPrefix());
 
-    // Initialize NLSR so a sync socket is created
-    nlsr.initialize();
-
     this->advanceClocks(ndn::time::milliseconds(10));
 
     face.sentInterests.clear();
diff --git a/tests/update/test-save-delete-prefix.cpp b/tests/update/test-save-delete-prefix.cpp
index 1bcca79..336ec8a 100644
--- a/tests/update/test-save-delete-prefix.cpp
+++ b/tests/update/test-save-delete-prefix.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2020,  The University of Memphis,
+/*
+ * Copyright (c) 2014-2021,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -17,7 +17,7 @@
  *
  * 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 "update/prefix-update-processor.hpp"
 #include "nlsr.hpp"
@@ -100,8 +100,6 @@
     // Set the network so the LSA prefix is constructed
     addIdentity(conf.getRouterPrefix());
 
-    // Initialize NLSR so a sync socket is created
-    nlsr.initialize();
     this->advanceClocks(ndn::time::milliseconds(10));
     face.sentInterests.clear();
   }