rib: reimplement auto prefix propagation based on readvertise

Change-Id: I6c4d81b829cf78084d26121c81d977d0a86c9a0c
Refs: #3819
diff --git a/core/scope-prefix.cpp b/core/scope-prefix.cpp
new file mode 100644
index 0000000..487d675
--- /dev/null
+++ b/core/scope-prefix.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "scope-prefix.hpp"
+
+namespace nfd {
+namespace scope_prefix {
+
+const Name LOCALHOST("ndn:/localhost");
+const Name LOCALHOP("ndn:/localhop");
+
+} // namespace scope_prefix
+} // namespace nfd
diff --git a/core/scope-prefix.hpp b/core/scope-prefix.hpp
new file mode 100644
index 0000000..05e3b68
--- /dev/null
+++ b/core/scope-prefix.hpp
@@ -0,0 +1,64 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_CORE_SCOPE_PREFIX_HPP
+#define NFD_CORE_SCOPE_PREFIX_HPP
+
+#include "common.hpp"
+
+/** \brief contain name prefixes that affect namespace-based scope control
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl
+ */
+namespace nfd {
+namespace scope_prefix {
+
+/** \brief ndn:/localhost
+ *
+ *  The localhost scope limits propagation to the applications on the originating host.
+ *
+ *  Interest and Data packets under prefix ndn:/localhost are restricted by these rules:
+ *  \li Interest can come from and go to local faces only.
+ *  \li Data can come from and go to local faces only.
+ */
+extern const Name LOCALHOST;
+
+/** \brief ndn:/localhop
+ *
+ *  The localhop scope limits propagation to no further than the next node.
+ *
+ *  Interest packets under prefix ndn:/localhop are restricted by these rules:
+ *  \li If an Interest is received from a local face, it can be forwarded to a non-local face.
+ *  \li If an Interest is received from a non-local face, it cannot be forwarded to a non-local face.
+ *  \li In either case the Interest can be forwarded to a local face.
+ *  \li PIT entry can be satisfied by Data from any source.
+ *
+ *  Data packets under prefix ndn:/localhop are unrestricted.
+ */
+extern const Name LOCALHOP;
+
+} // namespace scope_prefix
+} // namespace nfd
+
+#endif // NFD_CORE_SCOPE_PREFIX_HPP
diff --git a/daemon/fw/algorithm.cpp b/daemon/fw/algorithm.cpp
index db2c4cf..a0c8bc4 100644
--- a/daemon/fw/algorithm.cpp
+++ b/daemon/fw/algorithm.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017,  Regents of the University of California,
+ * Copyright (c) 2014-2018,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,11 +26,6 @@
 #include "algorithm.hpp"
 
 namespace nfd {
-namespace scope_prefix {
-const Name LOCALHOST("ndn:/localhost");
-const Name LOCALHOP("ndn:/localhop");
-} // namespace scope_prefix
-
 namespace fw {
 
 bool
diff --git a/daemon/fw/algorithm.hpp b/daemon/fw/algorithm.hpp
index c696d16..7ee0f38 100644
--- a/daemon/fw/algorithm.hpp
+++ b/daemon/fw/algorithm.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017,  Regents of the University of California,
+ * Copyright (c) 2014-2018,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,6 +26,7 @@
 #ifndef NFD_DAEMON_FW_PIT_ALGORITHM_HPP
 #define NFD_DAEMON_FW_PIT_ALGORITHM_HPP
 
+#include "core/scope-prefix.hpp"
 #include "table/pit-entry.hpp"
 
 /** \file
@@ -33,38 +34,6 @@
  */
 
 namespace nfd {
-
-/** \brief contain name prefixes that affect namespace-based scope control
- *  \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl
- */
-namespace scope_prefix {
-
-/** \brief ndn:/localhost
- *
- *  The localhost scope limits propagation to the applications on the originating host.
- *
- *  Interest and Data packets under prefix ndn:/localhost are restricted by these rules:
- *  \li Interest can come from and go to local faces only.
- *  \li Data can come from and go to local faces only.
- */
-extern const Name LOCALHOST;
-
-/** \brief ndn:/localhop
- *
- *  The localhop scope limits propagation to no further than the next node.
- *
- *  Interest packets under prefix ndn:/localhop are restricted by these rules:
- *  \li If an Interest is received from a local face, it can be forwarded to a non-local face.
- *  \li If an Interest is received from a non-local face, it cannot be forwarded to a non-local face.
- *  \li In either case the Interest can be forwarded to a local face.
- *  \li PIT entry can be satisfied by Data from any source.
- *
- *  Data packets under prefix ndn:/localhop are unrestricted.
- */
-extern const Name LOCALHOP;
-
-} // namespace scope_prefix
-
 namespace fw {
 
 /** \brief determine whether forwarding the Interest in \p pitEntry to \p outFace would violate scope
diff --git a/rib/auto-prefix-propagator.cpp b/rib/auto-prefix-propagator.cpp
deleted file mode 100644
index a03302a..0000000
--- a/rib/auto-prefix-propagator.cpp
+++ /dev/null
@@ -1,482 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2018,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "auto-prefix-propagator.hpp"
-#include "core/logger.hpp"
-
-#include <ndn-cxx/security/pib/identity.hpp>
-#include <ndn-cxx/security/pib/identity-container.hpp>
-#include <ndn-cxx/security/pib/pib.hpp>
-#include <ndn-cxx/security/signing-helpers.hpp>
-
-namespace nfd {
-namespace rib {
-
-NFD_LOG_INIT(AutoPrefixPropagator);
-
-using ndn::nfd::ControlParameters;
-using ndn::nfd::CommandOptions;
-using ndn::util::scheduler::EventCallback;
-
-const Name LOCAL_REGISTRATION_PREFIX("/localhost");
-const Name LINK_LOCAL_NFD_PREFIX("/localhop/nfd");
-const name::Component IGNORE_COMMPONENT("nrd");
-const time::seconds PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL = time::seconds(25);
-const time::seconds PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL = time::seconds(600);
-const time::seconds PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT = time::seconds(50);
-const time::seconds PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT = time::seconds(3600);
-const uint64_t PREFIX_PROPAGATION_DEFAULT_COST = 15;
-const time::milliseconds PREFIX_PROPAGATION_DEFAULT_TIMEOUT = time::milliseconds(10000);
-
-AutoPrefixPropagator::AutoPrefixPropagator(ndn::nfd::Controller& controller,
-                                           ndn::KeyChain& keyChain,
-                                           ndn::util::Scheduler& scheduler,
-                                           Rib& rib)
-  : m_nfdController(controller)
-  , m_keyChain(keyChain)
-  , m_scheduler(scheduler)
-  , m_rib(rib)
-  , m_refreshInterval(PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL)
-  , m_baseRetryWait(PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT)
-  , m_maxRetryWait(PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT)
-  , m_hasConnectedHub(false)
-{
-}
-
-void
-AutoPrefixPropagator::loadConfig(const ConfigSection& configSection)
-{
-  m_refreshInterval = PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL;
-  m_baseRetryWait = PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT;
-  m_maxRetryWait = PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT;
-
-  m_controlParameters
-     .setCost(PREFIX_PROPAGATION_DEFAULT_COST)
-     .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client.
-     .setFaceId(0);// the remote hub will take the input face as the faceId.
-
-   m_commandOptions
-     .setPrefix(LINK_LOCAL_NFD_PREFIX)
-     .setTimeout(PREFIX_PROPAGATION_DEFAULT_TIMEOUT);
-
-  NFD_LOG_INFO("Load auto_prefix_propagate section in rib section");
-
-  for (auto&& i : configSection) {
-    if (i.first == "cost") {
-      m_controlParameters.setCost(i.second.get_value<uint64_t>());
-    }
-    else if (i.first == "timeout") {
-      m_commandOptions.setTimeout(time::milliseconds(i.second.get_value<size_t>()));
-    }
-    else if (i.first == "refresh_interval") {
-      m_refreshInterval = std::min(PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL,
-                                   time::seconds(i.second.get_value<size_t>()));
-    }
-    else if (i.first == "base_retry_wait") {
-      m_baseRetryWait = time::seconds(i.second.get_value<size_t>());
-    }
-    else if (i.first == "max_retry_wait") {
-      m_maxRetryWait = time::seconds(i.second.get_value<size_t>());
-    }
-    else {
-      BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" + i.first +
-                                              "\" in \"auto_prefix_propagate\" section"));
-    }
-  }
-}
-
-void
-AutoPrefixPropagator::enable()
-{
-  m_afterInsertConnection =
-    m_rib.afterInsertEntry.connect(bind(&AutoPrefixPropagator::afterInsertRibEntry, this, _1));
-  m_afterEraseConnection =
-    m_rib.afterEraseEntry.connect(bind(&AutoPrefixPropagator::afterEraseRibEntry, this, _1));
-}
-
-void
-AutoPrefixPropagator::disable()
-{
-  m_afterInsertConnection.disconnect();
-  m_afterEraseConnection.disconnect();
-}
-
-AutoPrefixPropagator::PrefixPropagationParameters
-AutoPrefixPropagator::getPrefixPropagationParameters(const Name& localRibPrefix)
-{
-  // shortest prefix matching to all identies.
-  Name propagatedPrefix;
-  ndn::security::pib::Identity signingIdentity;
-  bool isFound = false;
-  for (auto&& identity : m_keyChain.getPib().getIdentities()) {
-    Name idName = identity.getName();
-    Name prefix = !idName.empty() && IGNORE_COMMPONENT == idName.at(-1) ?
-                  idName.getPrefix(-1) : idName;
-    if (prefix.isPrefixOf(localRibPrefix) && (!isFound || prefix.size() < propagatedPrefix.size())) {
-      isFound = true;
-      propagatedPrefix = prefix;
-      signingIdentity = identity;
-    }
-  }
-
-  PrefixPropagationParameters propagateParameters;
-  if (!isFound) {
-    propagateParameters.isValid = false;
-  }
-  else {
-    propagateParameters.isValid = true;
-    propagateParameters.parameters = m_controlParameters;
-    propagateParameters.options = m_commandOptions;
-    propagateParameters.parameters.setName(propagatedPrefix);
-    propagateParameters.options.setSigningInfo(ndn::security::signingByIdentity(signingIdentity));
-  }
-
-  return propagateParameters;
-}
-
-void
-AutoPrefixPropagator::afterInsertRibEntry(const Name& prefix)
-{
-  if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) {
-    NFD_LOG_INFO("local registration only for " << prefix);
-    return;
-  }
-
-  if (prefix == LINK_LOCAL_NFD_PREFIX) {
-    NFD_LOG_INFO("this is a prefix registered by some hub: " << prefix);
-
-    m_hasConnectedHub = true;
-    return afterHubConnect();
-  }
-
-  auto propagateParameters = getPrefixPropagationParameters(prefix);
-  if (!propagateParameters.isValid) {
-    NFD_LOG_INFO("no signing identity available for: " << prefix);
-    return;
-  }
-
-  auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
-  if (entryIt != m_propagatedEntries.end()) {
-    // in addition to PROPAGATED and PROPAGATE_FAIL, the state may also be NEW,
-    // if there is no hub connected to propagate this prefix.
-    if (entryIt->second.isNew()) {
-      NFD_LOG_INFO("no hub connected to propagate "
-                   << propagateParameters.parameters.getName());
-    }
-    else {
-      NFD_LOG_INFO("prefix has already been propagated: "
-                   << propagateParameters.parameters.getName());
-    }
-    return;
-  }
-
-  afterRibInsert(propagateParameters.parameters, propagateParameters.options);
-}
-
-void
-AutoPrefixPropagator::afterEraseRibEntry(const Name& prefix)
-{
-  if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) {
-    NFD_LOG_INFO("local unregistration only for " << prefix);
-    return;
-  }
-
-  if (prefix == LINK_LOCAL_NFD_PREFIX) {
-    NFD_LOG_INFO("disconnected to hub with prefix: " << prefix);
-
-    m_hasConnectedHub = false;
-    return afterHubDisconnect();
-  }
-
-  auto propagateParameters = getPrefixPropagationParameters(prefix);
-  if (!propagateParameters.isValid) {
-    NFD_LOG_INFO("no signing identity available for: " << prefix);
-    return;
-  }
-
-  auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
-  if (entryIt == m_propagatedEntries.end()) {
-    NFD_LOG_INFO("prefix has not been propagated yet: "
-                 << propagateParameters.parameters.getName());
-    return;
-  }
-
-  for (auto&& ribTableEntry : m_rib) {
-    if (propagateParameters.parameters.getName().isPrefixOf(ribTableEntry.first) &&
-        propagateParameters.options.getSigningInfo().getSignerName() ==
-        getPrefixPropagationParameters(ribTableEntry.first)
-          .options.getSigningInfo().getSignerName()) {
-      NFD_LOG_INFO("should be kept for another RIB entry: " << ribTableEntry.first);
-      return;
-    }
-  }
-
-  afterRibErase(propagateParameters.parameters.unsetCost(), propagateParameters.options);
-}
-
-bool
-AutoPrefixPropagator::doesCurrentPropagatedPrefixWork(const Name& prefix)
-{
-  auto propagateParameters = getPrefixPropagationParameters(prefix);
-  if (!propagateParameters.isValid) {
-    // no identity can sign the input prefix
-    return false;
-  }
-
-  // there is at least one identity can sign the input prefix, so the prefix selected for
-  // propagation (i.e., propagateParameters.parameters.getName()) must be a prefix of the input
-  // prefix. Namely it's either equal to the input prefix or a better choice.
-  return propagateParameters.parameters.getName().size() == prefix.size();
-}
-
-void
-AutoPrefixPropagator::redoPropagation(PropagatedEntryIt entryIt,
-                                      const ControlParameters& parameters,
-                                      const CommandOptions& options,
-                                      time::seconds retryWaitTime)
-{
-  if (doesCurrentPropagatedPrefixWork(parameters.getName())) {
-    // PROPAGATED / PROPAGATE_FAIL --> PROPAGATING
-    entryIt->second.startPropagation();
-    return advertise(parameters, options, retryWaitTime);
-  }
-
-  NFD_LOG_INFO("current propagated prefix does not work any more");
-  m_propagatedEntries.erase(entryIt);
-
-  // re-handle all locally RIB entries that can be covered by this propagated prefix
-  for (auto&& ribTableEntry : m_rib) {
-    if (parameters.getName().isPrefixOf(ribTableEntry.first)) {
-      afterInsertRibEntry(ribTableEntry.first);
-    }
-  }
-}
-
-void
-AutoPrefixPropagator::advertise(const ControlParameters& parameters,
-                                const CommandOptions& options,
-                                time::seconds retryWaitTime)
-{
-  NFD_LOG_INFO("advertise " << parameters.getName());
-
-  EventCallback refreshEvent =
-    bind(&AutoPrefixPropagator::onRefreshTimer, this, parameters, options);
-  EventCallback retryEvent =
-    bind(&AutoPrefixPropagator::onRetryTimer, this, parameters, options,
-         std::min(m_maxRetryWait, retryWaitTime * 2));
-
-  m_nfdController.start<ndn::nfd::RibRegisterCommand>(
-     parameters,
-     bind(&AutoPrefixPropagator::afterPropagateSucceed, this, parameters, options, refreshEvent),
-     bind(&AutoPrefixPropagator::afterPropagateFail,
-          this, _1, parameters, options, retryWaitTime, retryEvent),
-     options);
-}
-
-void
-AutoPrefixPropagator::withdraw(const ControlParameters& parameters,
-                               const CommandOptions& options,
-                               time::seconds retryWaitTime)
-{
-  NFD_LOG_INFO("withdraw " << parameters.getName());
-
-  m_nfdController.start<ndn::nfd::RibUnregisterCommand>(
-     parameters,
-     bind(&AutoPrefixPropagator::afterRevokeSucceed, this, parameters, options, retryWaitTime),
-     bind(&AutoPrefixPropagator::afterRevokeFail, this, _1, parameters, options),
-     options);
-}
-
-void
-AutoPrefixPropagator::afterRibInsert(const ControlParameters& parameters,
-                                     const CommandOptions& options)
-{
-  BOOST_ASSERT(m_propagatedEntries.find(parameters.getName()) == m_propagatedEntries.end());
-
-  // keep valid entries although there is no connectivity to hub
-  auto& entry = m_propagatedEntries[parameters.getName()]
-    .setSigningIdentity(options.getSigningInfo().getSignerName());
-
-  if (!m_hasConnectedHub) {
-    NFD_LOG_INFO("no hub connected to propagate " << parameters.getName());
-    return;
-  }
-
-  // NEW --> PROPAGATING
-  entry.startPropagation();
-  advertise(parameters, options, m_baseRetryWait);
-}
-
-void
-AutoPrefixPropagator::afterRibErase(const ControlParameters& parameters,
-                                    const CommandOptions& options)
-{
-  auto entryIt = m_propagatedEntries.find(parameters.getName());
-  BOOST_ASSERT(entryIt != m_propagatedEntries.end());
-
-  bool hasPropagationSucceeded = entryIt->second.isPropagated();
-
-  // --> "RELEASED"
-  m_propagatedEntries.erase(entryIt);
-
-  if (!m_hasConnectedHub) {
-    NFD_LOG_INFO("no hub connected to revoke propagation of " << parameters.getName());
-    return;
-  }
-
-  if (!hasPropagationSucceeded) {
-    NFD_LOG_INFO("propagation has not succeeded: " << parameters.getName());
-    return;
-  }
-
-  withdraw(parameters, options, m_baseRetryWait);
-}
-
-void
-AutoPrefixPropagator::afterHubConnect()
-{
-  NFD_LOG_INFO("redo " << m_propagatedEntries.size()
-                       << " propagations when new Hub connectivity is built.");
-
-  std::vector<PropagatedEntryIt> regEntryIterators;
-  for (auto it = m_propagatedEntries.begin() ; it != m_propagatedEntries.end() ; it ++) {
-    BOOST_ASSERT(it->second.isNew());
-    regEntryIterators.push_back(it);
-  }
-
-  for (auto&& it : regEntryIterators) {
-    auto parameters = m_controlParameters;
-    auto options = m_commandOptions;
-
-    redoPropagation(it,
-                     parameters.setName(it->first),
-                     options.setSigningInfo(signingByIdentity(it->second.getSigningIdentity())),
-                     m_baseRetryWait);
-  }
-}
-
-void
-AutoPrefixPropagator::afterHubDisconnect()
-{
-  for (auto&& entry : m_propagatedEntries) {
-    // --> NEW
-    BOOST_ASSERT(!entry.second.isNew());
-    entry.second.initialize();
-  }
-}
-
-void
-AutoPrefixPropagator::afterPropagateSucceed(const ControlParameters& parameters,
-                                            const CommandOptions& options,
-                                            const EventCallback& refreshEvent)
-{
-  NFD_LOG_TRACE("success to propagate " << parameters.getName());
-
-  auto entryIt = m_propagatedEntries.find(parameters.getName());
-  if (entryIt == m_propagatedEntries.end()) {
-    // propagation should be revoked if this entry has been erased (i.e., be in RELEASED state)
-    NFD_LOG_DEBUG("Already erased!");
-    ControlParameters newParameters = parameters;
-    return withdraw(newParameters.unsetCost(), options, m_baseRetryWait);
-  }
-
-  // PROPAGATING --> PROPAGATED
-  BOOST_ASSERT(entryIt->second.isPropagating());
-  entryIt->second.succeed(m_scheduler, m_scheduler.scheduleEvent(m_refreshInterval, refreshEvent));
-}
-
-void
-AutoPrefixPropagator::afterPropagateFail(const ndn::nfd::ControlResponse& response,
-                                         const ControlParameters& parameters,
-                                         const CommandOptions& options,
-                                         time::seconds retryWaitTime,
-                                         const EventCallback& retryEvent)
-{
-  NFD_LOG_TRACE("fail to propagate " << parameters.getName()
-                                     << "\n\t reason:" << response.getText()
-                                     << "\n\t retry wait time: " << retryWaitTime);
-
-  auto entryIt = m_propagatedEntries.find(parameters.getName());
-  if (entryIt == m_propagatedEntries.end()) {
-    // current state is RELEASED
-    return;
-  }
-
-  // PROPAGATING --> PROPAGATE_FAIL
-  BOOST_ASSERT(entryIt->second.isPropagating());
-  entryIt->second.fail(m_scheduler, m_scheduler.scheduleEvent(retryWaitTime, retryEvent));
-}
-
-void
-AutoPrefixPropagator::afterRevokeSucceed(const ControlParameters& parameters,
-                                         const CommandOptions& options,
-                                         time::seconds retryWaitTime)
-{
-  NFD_LOG_TRACE("success to revoke propagation of " << parameters.getName());
-
-  auto entryIt = m_propagatedEntries.find(parameters.getName());
-  if (m_propagatedEntries.end() != entryIt && !entryIt->second.isPropagateFail()) {
-    // if is not RELEASED or PROPAGATE_FAIL
-    NFD_LOG_DEBUG("propagated entry still exists");
-
-    // PROPAGATING / PROPAGATED --> PROPAGATING
-    BOOST_ASSERT(!entryIt->second.isNew());
-    entryIt->second.startPropagation();
-
-    ControlParameters newParameters = parameters;
-    advertise(newParameters.setCost(m_controlParameters.getCost()), options, retryWaitTime);
-  }
-}
-
-void
-AutoPrefixPropagator::afterRevokeFail(const ndn::nfd::ControlResponse& response,
-                                      const ControlParameters& parameters,
-                                      const CommandOptions& options)
-{
-  NFD_LOG_INFO("fail to revoke the propagation of  " << parameters.getName()
-                                                     << "\n\t reason:" << response.getText());
-}
-
-void
-AutoPrefixPropagator::onRefreshTimer(const ControlParameters& parameters,
-                                     const CommandOptions& options)
-{
-  auto entryIt = m_propagatedEntries.find(parameters.getName());
-  BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagated());
-  redoPropagation(entryIt, parameters, options, m_baseRetryWait);
-}
-
-void
-AutoPrefixPropagator::onRetryTimer(const ControlParameters& parameters,
-                                   const CommandOptions& options,
-                                   time::seconds retryWaitTime)
-{
-  auto entryIt = m_propagatedEntries.find(parameters.getName());
-  BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagateFail());
-  redoPropagation(entryIt, parameters, options, retryWaitTime);
-}
-
-} // namespace rib
-} // namespace nfd
diff --git a/rib/auto-prefix-propagator.hpp b/rib/auto-prefix-propagator.hpp
deleted file mode 100644
index 802a105..0000000
--- a/rib/auto-prefix-propagator.hpp
+++ /dev/null
@@ -1,418 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2018,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NFD_RIB_AUTO_PREFIX_PROPAGATOR_HPP
-#define NFD_RIB_AUTO_PREFIX_PROPAGATOR_HPP
-
-#include "propagated-entry.hpp"
-#include "rib.hpp"
-#include "core/config-file.hpp"
-
-#include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/mgmt/nfd/controller.hpp>
-#include <ndn-cxx/mgmt/nfd/control-command.hpp>
-#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
-#include <ndn-cxx/mgmt/nfd/command-options.hpp>
-#include <ndn-cxx/util/scheduler.hpp>
-#include <ndn-cxx/util/signal.hpp>
-
-namespace nfd {
-namespace rib {
-
-/** @brief provides automatic prefix propagation feature
- *
- * The AutoPrefixPropagator monitors changes to local RIB, and registers prefixes onto a
- * connected gateway router (HUB), so that Interests under propagated prefixes will be forwarded
- * toward the local host by the HUB.
- *
- * The route origin of propagated prefix is CLIENT, as shown on the HUB.
- *
- * Connectivity to a HUB is indicated with a special RIB entry "ndn:/localhop/nfd".
- * Currently, the AutoPrefixPropagator can process the connection to at most one HUB.
- *
- * For every RIB entry except "ndn:/localhop/nfd" and those starting with "ndn:/localhost", the
- * AutoPrefixPropagator queries the local KeyChain for signing identities that is authorized
- * to sign a prefix registration command of a prefix of the RIB prefix.
- *
- * If one or more signing identities are found, the identity that can sign a prefix registration
- * command of the shortest prefix is chosen, and the AutoPrefixPropagator will attempt to
- * propagte a prefix to the HUB using the shortest prefix. It's noteworthy that no route flags will
- * be inherited from the local registration.
- * If no signing identity is available, no prefix of the RIB entry is propagated to the HUB.
- *
- * When a RIB entry is erased, the corresponding propagated entry would be revoked,
- * unless another local RIB entry is causing the propagation of that prefix.
- *
- * After a successful propagation, the AutoPrefixPropagator will refresh the propagation
- * periodically by resending the registration command.
- *
- * In case of a failure or timeout in a registration command, the command will be retried with an
- * exponential back-off strategy.
- *
- * The AutoPrefixPropagator can be configured in NFD configuration file, at the
- * rib.auto_prefix_propagate section.
- */
-class AutoPrefixPropagator : noncopyable
-{
-public:
-  class Error : public std::runtime_error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
-  };
-
-  AutoPrefixPropagator(ndn::nfd::Controller& controller,
-                       ndn::KeyChain& keyChain,
-                       ndn::util::Scheduler& scheduler,
-                       Rib& rib);
-  /**
-   * @brief load the "auto_prefix_propagate" section from config file
-   *
-   * @param configSection the sub section in "rib" section.
-   */
-  void
-  loadConfig(const ConfigSection& configSection);
-
-  /**
-   * @brief enable automatic prefix propagation
-   */
-  void
-  enable();
-
-  /**
-   * @brief disable automatic prefix propagation
-   */
-  void
-  disable();
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
-  /**
-   * When a local RIB prefix triggers prefix propagation, we propagate the shortest identity that
-   * can sign this prefix to the HUB.
-   *
-   * Thus, the propagated prefix does not equal to local RIB prefix.
-   * So it needs separate storage instead of storing within the RIB.
-   *
-   * the propagated prefix is used as the key to retrive the corresponding entry.
-   */
-  typedef std::unordered_map<Name, PropagatedEntry> PropagatedEntryList;
-  typedef PropagatedEntryList::iterator PropagatedEntryIt;
-
-  /**
-   * @brief parameters used by the registration commands for prefix propagation
-   *
-   * consists of a ControlParameters and a CommandOptions, as well as a bool variable indicates
-   * whether this set of parameters is valid (i.e., the signing identity exists)
-   */
-  struct PrefixPropagationParameters
-  {
-    bool isValid;
-    ndn::nfd::ControlParameters parameters;
-    ndn::nfd::CommandOptions options;
-  };
-
-  /**
-   * @brief get the required parameters for prefix propagation.
-   *
-   * given a local RIB prefix @p localRibPrefix, find out, in local KeyChain, a proper identity
-   * whose namespace covers the input prefix. If there is no desired identity, return a invalid
-   * PrefixPropagationParameters.
-   *
-   * Otherwise, set the selected identity as the signing identity in CommandOptions. Meanwhile,
-   * set this identity (or its prefix with the last component eliminated if it ends with "nrd")
-   * as the name of ControlParameters.
-   *
-   * @return the PrefixPropagationParameters.
-   */
-  PrefixPropagationParameters
-  getPrefixPropagationParameters(const Name& localRibPrefix);
-
-  /**
-   * @brief check whether current propagated prefix still works
-   *
-   * the current propagated prefix @p prefix will still work if and only if its corresponding
-   * signing identity still exists and there is no better signing identity covering it.
-   *
-   * @return true if current propagated prefix still works, otherwise false
-   */
-  bool
-  doesCurrentPropagatedPrefixWork(const Name& prefix);
-
-  /**
-   * @brief process re-propagation for the given propagated entry
-   *
-   * This function may be invoked in 3 cases:
-   * 1. After the hub is connected to redo some propagations.
-   * 2. On refresh timer to handle refresh requests.
-   * 3. On retry timer to handle retry requests.
-   *
-   * @param entryIt the propagated entry need to do re-propagation
-   * @param parameters the ControlParameters used by registration commands for propagation
-   * @param options the CommandOptions used for registration commands for propagation
-   * @param retryWaitTime the current wait time before retrying propagation
-   */
-  void
-  redoPropagation(PropagatedEntryIt entryIt,
-                  const ndn::nfd::ControlParameters& parameters,
-                  const ndn::nfd::CommandOptions& options,
-                  time::seconds retryWaitTime);
-
-private:
-  /**
-   * @brief send out the registration command for propagation
-   *
-   * Before sending out the command, two events, for refresh and retry respectively, are
-   * established (but not scheduled) and assigned to two callbacks, afterPropagateSucceed and
-   * afterPropagateFail respectively.
-   *
-   * The retry event requires an argument to define the retry wait time, which is calculated
-   * according to the back-off policy based on current retry wait time @p retryWaitTime and the
-   * maxRetryWait.
-   *
-   * The baseRetryWait and maxRetryWait used in back-off strategy are all configured at
-   * rib.auto_prefix_propagate.base_retry_wait and
-   * rib.auto_prefix_propagate.max_retry_wait respectively
-
-   * @param parameters the ControlParameters used by the registration command for propagation
-   * @param options the CommandOptions used by the registration command for propagation
-   * @param retryWaitTime the current wait time before retrying propagation
-   */
-  void
-  advertise(const ndn::nfd::ControlParameters& parameters,
-            const ndn::nfd::CommandOptions& options,
-            time::seconds retryWaitTime);
-
-  /**
-   * @brief send out the unregistration command to revoke the corresponding propagation.
-   *
-   * @param parameters the ControlParameters used by the unregistration command for revocation
-   * @param options the CommandOptions used by the unregistration command for revocation
-   * @param retryWaitTime the current wait time before retrying propagation
-   */
-  void
-  withdraw(const ndn::nfd::ControlParameters& parameters,
-           const ndn::nfd::CommandOptions& options,
-           time::seconds retryWaitTime);
-
-  /**
-   * @brief invoked when Rib::afterInsertEntry signal is emitted
-   *
-   * step1: if the local RIB prefix @param prefix is for local use only, return
-   * step2: if the local RIB prefix @param prefix is a hub prefix, invoke afterHubConnect
-   * step3: if no valid PrefixPropagationParameters can be found for the local RIB prefix
-   *        @param prefix, or the propagated prefix has already been processed, return
-   * step4: invoke afterRibInsert
-   */
-  void
-  afterInsertRibEntry(const Name& prefix);
-
-  /**
-   * @brief invoked when Rib::afterEraseEntry signal is emitted
-   *
-   * step1: if local RIB prefix @param prefix is for local use only, return
-   * step2: if local RIB prefix @param prefix is a hub prefix, invoke afterHubDisconnect
-   * step3: if no valid PrefixPropagationParameters can be found for local RIB prefix
-   *        @param prefix, or there are other local RIB prefixes can be covered by the propagated
-   *        prefix, return
-   * step4: invoke afterRibErase
-   */
-  void
-  afterEraseRibEntry(const Name& prefix);
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE: // PropagatedEntry state changes
-  /**
-   * @brief invoked after rib insertion for non-hub prefixes
-   * @pre the PropagatedEntry is in RELEASED state
-   * @post the PropagatedEntry will be in NEW state
-   *
-   * @param parameters the ControlParameters used by registration commands for propagation
-   * @param options the CommandOptions used by registration commands for propagation
-   */
-  void
-  afterRibInsert(const ndn::nfd::ControlParameters& parameters,
-                 const ndn::nfd::CommandOptions& options);
-
-  /**
-   * @brief invoked after rib deletion for non-hub prefixes
-   * @pre the PropagatedEntry is not in RELEASED state
-   * @post the PropagatedEntry will be in RELEASED state
-   *
-   * @param parameters the ControlParameters used by registration commands for propagation
-   * @param options the CommandOptions used by registration commands for propagation
-   */
-  void
-  afterRibErase(const ndn::nfd::ControlParameters& parameters,
-                const ndn::nfd::CommandOptions& options);
-
-  /**
-   * @brief invoked after the hub is connected
-   * @pre the PropagatedEntry is in NEW state or RELEASED state
-   * @post the PropagatedEntry will be in PROPAGATING state or keep in RELEASED state
-   *
-   * call redoPropagation for each propagated entry.
-   */
-  void
-  afterHubConnect();
-
-  /**
-   * @brief invoked after the hub is disconnected
-   * @pre the PropagatedEntry is not in NEW state
-   * @post the PropagatedEntry will be in NEW state or keep in RELEASED state
-   *
-   * for each propagated entry, switch its state to NEW and cancel its event.
-   */
-  void
-  afterHubDisconnect();
-
-  /**
-   * @brief invoked after propagation succeeds
-   * @pre the PropagatedEntry is in PROPAGATING state or RELEASED state
-   * @post the PropagatedEntry will be in PROPAGATED state or keep in RELEASED state
-   *
-   * If the PropagatedEntry does not exist (in RELEASED state), an unregistration command is
-   * sent immediately for revocation.
-   *
-   * If the PropagatedEntry is in PROPAGATING state, switch it to PROPAGATED, and schedule a
-   * refresh timer to redo propagation after a duration, which is configured at
-   * rib.auto_prefix_propagate.refresh_interval.
-   *
-   * Otherwise, make a copy of the ControlParameters @p parameters, unset its Cost field, and then
-   * invoke withdraw with this new ControlParameters.
-   *
-   * @param parameters the ControlParameters used by the registration command for propagation
-   * @param options the CommandOptions used by the registration command for propagation
-   * @param refreshEvent the event of refreshing propagation
-   */
-  void
-  afterPropagateSucceed(const ndn::nfd::ControlParameters& parameters,
-                        const ndn::nfd::CommandOptions& options,
-                        const ndn::util::scheduler::EventCallback& refreshEvent);
-
-  /**
-   * @brief invoked after propagation fails.
-   * @pre the PropagatedEntry is in PROPAGATING state or RELEASED state
-   * @post the PropagatedEntry will be in PROPAGATE_FAIL state or keep in RELEASED state
-   *
-   * If the PropagatedEntry still exists, schedule a retry timer to redo propagation
-   * after a duration defined by current retry time @p retryWaitTime
-   *
-   * @param response ControlResponse from remote NFD-RIB
-   * @param parameters the ControlParameters used by the registration command for propagation
-   * @param options the CommandOptions used by registration command for propagation
-   * @param retryWaitTime the current wait time before retrying propagation
-   * @param retryEvent the event of retrying propagation
-   */
-  void
-  afterPropagateFail(const ndn::nfd::ControlResponse& response,
-                     const ndn::nfd::ControlParameters& parameters,
-                     const ndn::nfd::CommandOptions& options,
-                     time::seconds retryWaitTime,
-                     const ndn::util::scheduler::EventCallback& retryEvent);
-
-  /**
-   * @brief invoked after revocation succeeds
-   * @pre the PropagatedEntry is not in NEW state
-   * @post the PropagatedEntry will be in PROPAGATING state, or keep in PROPAGATE_FAIL state,
-   * or keep in RELEASED state
-   *
-   * If the PropagatedEntry still exists and is not in PROPAGATE_FAIL state, switch it to
-   * PROPAGATING. Then make a copy of the ControlParameters @p parameters, reset its Cost, and
-   * invoke advertise with this new ControlParameters.
-   *
-   * @param parameters the ControlParameters used by the unregistration command for revocation
-   * @param options the CommandOptions used by the unregistration command for revocation
-   * @param retryWaitTime the current wait time before retrying propagation
-   */
-  void
-  afterRevokeSucceed(const ndn::nfd::ControlParameters& parameters,
-                     const ndn::nfd::CommandOptions& options,
-                     time::seconds retryWaitTime);
-
-  /**
-   * @brief invoked after revocation fails.
-   *
-   * @param response ControlResponse from remote NFD-RIB
-   * @param parameters the ControlParameters used by the unregistration command for revocation
-   * @param options the CommandOptions used by the unregistration command for revocation
-   */
-  void
-  afterRevokeFail(const ndn::nfd::ControlResponse& response,
-                  const ndn::nfd::ControlParameters& parameters,
-                  const ndn::nfd::CommandOptions& options);
-
-  /**
-   * @brief invoked when the refresh timer is triggered.
-   * @pre the PropagatedEntry is in PROPAGATED state
-   * @post the PropagatedEntry will be in PROPAGATING state
-   *
-   * call redoPropagation to handle this refresh request
-   *
-   * @param parameters the ControlParameters used by registration commands for propagation
-   * @param options the CommandOptions used by registration commands for propagation
-   */
-  void
-  onRefreshTimer(const ndn::nfd::ControlParameters& parameters,
-                 const ndn::nfd::CommandOptions& options);
-
-  /**
-   * @brief invoked when the retry timer is triggered.
-   * @pre the PropagatedEntry is in PROPAGATE_FAIL state
-   * @post the PropagatedEntry will be in PROPAGATING state
-   *
-   * call redoPropagation to handle this retry request
-   *
-   * @param parameters the ControlParameters used by registration commands for propagation
-   * @param options the CommandOptions used by registration commands for propagation
-   * @param retryWaitTime the current wait time before retrying propagation
-   */
-  void
-  onRetryTimer(const ndn::nfd::ControlParameters& parameters,
-               const ndn::nfd::CommandOptions& options,
-               time::seconds retryWaitTime);
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  ndn::nfd::Controller& m_nfdController;
-  ndn::KeyChain& m_keyChain;
-  ndn::util::Scheduler& m_scheduler;
-  Rib& m_rib;
-  ndn::util::signal::ScopedConnection m_afterInsertConnection;
-  ndn::util::signal::ScopedConnection m_afterEraseConnection;
-  ndn::nfd::ControlParameters m_controlParameters;
-  ndn::nfd::CommandOptions m_commandOptions;
-  time::seconds m_refreshInterval;
-  time::seconds m_baseRetryWait;
-  time::seconds m_maxRetryWait;
-  bool m_hasConnectedHub;
-  PropagatedEntryList m_propagatedEntries;
-};
-
-} // namespace rib
-} // namespace nfd
-
-#endif // NFD_RIB_AUTO_PREFIX_PROPAGATOR_HPP
diff --git a/rib/propagated-entry.cpp b/rib/propagated-entry.cpp
deleted file mode 100644
index 34a8976..0000000
--- a/rib/propagated-entry.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2018,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "propagated-entry.hpp"
-
-namespace nfd {
-namespace rib {
-
-void
-operator<<(std::ostream& out, PropagationStatus status)
-{
-  switch (status) {
-  case PropagationStatus::NEW:
-    out << "NEW";
-    break;
-  case PropagationStatus::PROPAGATING:
-    out << "PROPAGATING";
-    break;
-  case PropagationStatus::PROPAGATED:
-    out << "PROPAGATED";
-    break;
-  case PropagationStatus::PROPAGATE_FAIL:
-    out << "PROPAGATE_FAIL";
-    break;
-  default:
-    out << "undefined status";
-    break;
-  }
-}
-
-PropagatedEntry::PropagatedEntry(const PropagatedEntry& other)
-  : m_signingIdentity(other.m_signingIdentity)
-  , m_propagationStatus(other.m_propagationStatus)
-{
-  BOOST_ASSERT(!other.isPropagated() && !other.isPropagateFail());
-}
-
-PropagatedEntry&
-PropagatedEntry::setSigningIdentity(const Name& identity)
-{
-  m_signingIdentity = identity;
-  return *this;
-}
-
-const Name&
-PropagatedEntry::getSigningIdentity() const
-{
-  return m_signingIdentity;
-}
-
-void
-PropagatedEntry::startPropagation()
-{
-  m_propagationStatus = PropagationStatus::PROPAGATING;
-}
-
-void
-PropagatedEntry::succeed(ndn::util::Scheduler& scheduler, const ndn::util::scheduler::EventId& event)
-{
-  m_propagationStatus = PropagationStatus::PROPAGATED;
-  m_rePropagateEvent = ndn::util::scheduler::ScopedEventId(scheduler);
-  *m_rePropagateEvent = event;
-}
-
-void
-PropagatedEntry::fail(ndn::util::Scheduler& scheduler, const ndn::util::scheduler::EventId& event)
-{
-  m_propagationStatus = PropagationStatus::PROPAGATE_FAIL;
-  m_rePropagateEvent = ndn::util::scheduler::ScopedEventId(scheduler);
-  *m_rePropagateEvent = event;
-}
-
-void
-PropagatedEntry::initialize()
-{
-  m_propagationStatus = PropagationStatus::NEW;
-  if (m_rePropagateEvent)
-    m_rePropagateEvent->cancel();
-}
-
-bool
-PropagatedEntry::isNew() const
-{
-  return PropagationStatus::NEW == m_propagationStatus;
-}
-
-bool
-PropagatedEntry::isPropagating() const
-{
-  return PropagationStatus::PROPAGATING == m_propagationStatus;
-}
-
-bool
-PropagatedEntry::isPropagated() const
-{
-  return PropagationStatus::PROPAGATED == m_propagationStatus;
-}
-
-bool
-PropagatedEntry::isPropagateFail() const
-{
-  return PropagationStatus::PROPAGATE_FAIL == m_propagationStatus;
-}
-
-} // namespace rib
-} // namespace nfd
diff --git a/rib/propagated-entry.hpp b/rib/propagated-entry.hpp
deleted file mode 100644
index c4b0601..0000000
--- a/rib/propagated-entry.hpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2018,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NFD_RIB_PROPAGATED_ENTRY_HPP
-#define NFD_RIB_PROPAGATED_ENTRY_HPP
-
-#include "core/common.hpp"
-
-#include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
-
-namespace nfd {
-namespace rib {
-
-enum class PropagationStatus {
-  /// initial status
-  NEW,
-  /// is being propagated
-  PROPAGATING,
-  /// has been propagated successfully
-  PROPAGATED,
-  /// has failed in propagation
-  PROPAGATE_FAIL
-};
-
-void
-operator<<(std::ostream& out, PropagationStatus status);
-
-/**
- * @brief represents an entry for prefix propagation.
- *
- * it consists of a PropagationStatus indicates current state of the state machine, as
- * well as an event scheduled for refresh or retry (i.e., the RefreshTimer and the RetryTimer of
- * the state machine respectively). Besides, it stores a copy of signing identity for this entry.
- */
-class PropagatedEntry
-{
-public:
-  PropagatedEntry() = default;
-
-  /**
-   * @pre other is not in PROPAGATED or PROPAGATE_FAIL state
-   */
-  PropagatedEntry(const PropagatedEntry& other);
-
-  PropagatedEntry&
-  operator=(const PropagatedEntry& other) = delete;
-
-  /**
-   * @brief set the signing identity
-   */
-  PropagatedEntry&
-  setSigningIdentity(const Name& identity);
-
-  /**
-   * @brief get the signing identity
-   *
-   * @return the signing identity
-   */
-  const Name&
-  getSigningIdentity() const;
-
-  /**
-   * @brief switch the propagation status to PROPAGATING.
-   *
-   * this is called before start the propagation process of this entry.
-   */
-  void
-  startPropagation();
-
-  /**
-   * @brief switch the propagation status to PROPAGATED, and set the
-   *        rePropagateEvent to @p event for refresh.
-   *
-   * this is called just after this entry is successfully propagated.
-   */
-  void
-  succeed(ndn::util::Scheduler& scheduler, const ndn::util::scheduler::EventId& event);
-
-  /**
-   * @brief switch the propagation status to PROPAGATE_FAIL, and then set the
-   *        rePropagateEvent to @p event for retry.
-   *
-   * this is called just after propagation for this entry fails.
-   */
-  void
-  fail(ndn::util::Scheduler& scheduler, const ndn::util::scheduler::EventId& event);
-
-  /**
-   * @brief cancel the events of re-sending propagation commands.
-   *
-   * switch the propagation status to NEW.
-   */
-  void
-  initialize();
-
-  /**
-   * @brief check whether this entry is a new entry.
-   *
-   * @return true if current status is NEW.
-   */
-  bool
-  isNew() const;
-
-  /**
-   * @brief check whether this entry is being propagated.
-   *
-   * @return true if current status is PROPAGATING.
-   */
-  bool
-  isPropagating() const;
-
-  /**
-   * @brief check whether this entry has been successfully propagated.
-   *
-   * @return true if current status is PROPAGATED.
-   */
-  bool
-  isPropagated() const;
-
-  /**
-   * @brief check whether this entry has failed in propagating.
-   *
-   * @return true if current status is PROPAGATE_FAIL.
-   */
-  bool
-  isPropagateFail() const;
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  Name m_signingIdentity;
-  optional<ndn::util::scheduler::ScopedEventId> m_rePropagateEvent;
-  PropagationStatus m_propagationStatus = PropagationStatus::NEW;
-};
-
-} // namespace rib
-} // namespace nfd
-
-#endif // NFD_RIB_PROPAGATED_ENTRY_HPP
diff --git a/rib/readvertise/host-to-gateway-readvertise-policy.cpp b/rib/readvertise/host-to-gateway-readvertise-policy.cpp
new file mode 100644
index 0000000..2d508f8
--- /dev/null
+++ b/rib/readvertise/host-to-gateway-readvertise-policy.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "host-to-gateway-readvertise-policy.hpp"
+#include "core/scope-prefix.hpp"
+#include "rib/rib-manager.hpp"
+
+#include <ndn-cxx/security/pib/identity.hpp>
+#include <ndn-cxx/security/signing-helpers.hpp>
+
+namespace nfd {
+namespace rib {
+
+static const name::Component IGNORE_COMPONENT("nrd");
+static const time::seconds DEFAULT_REFRESH_INTERVAL = 25_s;
+
+HostToGatewayReadvertisePolicy::HostToGatewayReadvertisePolicy(const ndn::KeyChain& keyChain,
+                                                               const ConfigSection& section)
+  : m_keyChain(keyChain)
+{
+  auto interval = section.get_optional<uint64_t>("refresh_interval");
+  m_refreshInterval = interval ? time::seconds(*interval) : DEFAULT_REFRESH_INTERVAL;
+}
+
+optional<ReadvertiseAction>
+HostToGatewayReadvertisePolicy::handleNewRoute(const RibRouteRef& ribRoute) const
+{
+  auto ribEntryName = ribRoute.entry->getName();
+  if (scope_prefix::LOCALHOST.isPrefixOf(ribEntryName) ||
+      ribEntryName == RibManager::LOCALHOP_TOP_PREFIX) {
+    return nullopt;
+  }
+
+  // find out the shortest identity whose name is a prefix of the RIB entry name
+  auto prefixToAdvertise = ribEntryName;
+  ndn::security::pib::Identity signingIdentity;
+  bool isFound = false;
+
+  for (const auto& identity : m_keyChain.getPib().getIdentities()) {
+    auto prefix = identity.getName();
+
+    // ignore the identity name's last component if it is "nrd"
+    if (!prefix.empty() && IGNORE_COMPONENT == prefix.at(-1)) {
+      prefix = prefix.getPrefix(-1);
+    }
+
+    if (prefix.isPrefixOf(prefixToAdvertise)) {
+      isFound = true;
+      prefixToAdvertise = prefix;
+      signingIdentity = identity;
+    }
+  }
+
+  if (isFound) {
+    return ReadvertiseAction{prefixToAdvertise, ndn::security::signingByIdentity(signingIdentity)};
+  }
+  else {
+    return nullopt;
+  }
+}
+
+time::milliseconds
+HostToGatewayReadvertisePolicy::getRefreshInterval() const
+{
+  return m_refreshInterval;
+}
+
+} // namespace rib
+} // namespace nfd
diff --git a/rib/readvertise/host-to-gateway-readvertise-policy.hpp b/rib/readvertise/host-to-gateway-readvertise-policy.hpp
new file mode 100644
index 0000000..a2961b3
--- /dev/null
+++ b/rib/readvertise/host-to-gateway-readvertise-policy.hpp
@@ -0,0 +1,60 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_RIB_READVERTISE_HOST_TO_GATEWAY_READVERTISE_POLICY_HPP
+#define NFD_RIB_READVERTISE_HOST_TO_GATEWAY_READVERTISE_POLICY_HPP
+
+#include "readvertise-policy.hpp"
+#include "core/config-file.hpp"
+
+#include <ndn-cxx/security/key-chain.hpp>
+
+namespace nfd {
+namespace rib {
+
+/** \brief a policy to readvertise routes registered by local applications into remote gateway
+ */
+class HostToGatewayReadvertisePolicy : public ReadvertisePolicy
+{
+public:
+  HostToGatewayReadvertisePolicy(const ndn::KeyChain& keyChain,
+                                 const ConfigSection& section);
+
+public:
+  optional<ReadvertiseAction>
+  handleNewRoute(const RibRouteRef& ribRoute) const override;
+
+  time::milliseconds
+  getRefreshInterval() const override;
+
+private:
+  const ndn::KeyChain& m_keyChain;
+  time::seconds m_refreshInterval;
+};
+
+} // namespace rib
+} // namespace nfd
+
+#endif // NFD_RIB_READVERTISE_HOST_TO_GATEWAY_READVERTISE_POLICY_HPP
diff --git a/rib/readvertise/nfd-rib-readvertise-destination.cpp b/rib/readvertise/nfd-rib-readvertise-destination.cpp
index 530a9d4..f0a0482 100644
--- a/rib/readvertise/nfd-rib-readvertise-destination.cpp
+++ b/rib/readvertise/nfd-rib-readvertise-destination.cpp
@@ -26,9 +26,7 @@
 #include "nfd-rib-readvertise-destination.hpp"
 #include "core/logger.hpp"
 
-#include <ndn-cxx/mgmt/nfd/command-options.hpp>
 #include <ndn-cxx/mgmt/nfd/control-command.hpp>
-#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
 
 namespace nfd {
@@ -36,15 +34,15 @@
 
 NFD_LOG_INIT(NfdRibReadvertiseDestination);
 
-using ndn::nfd::CommandOptions;
-using ndn::nfd::ControlParameters;
 using ndn::nfd::ControlResponse;
 
 NfdRibReadvertiseDestination::NfdRibReadvertiseDestination(ndn::nfd::Controller& controller,
-                                                           const Name& commandPrefix,
-                                                           Rib& rib)
+                                                           Rib& rib,
+                                                           const ndn::nfd::CommandOptions& options,
+                                                           const ndn::nfd::ControlParameters& parameters)
   : m_controller(controller)
-  , m_commandPrefix(commandPrefix)
+  , m_commandOptions(options)
+  , m_controlParameters(parameters)
 {
   m_ribInsertConn = rib.afterInsertEntry.connect(
     std::bind(&NfdRibReadvertiseDestination::handleRibInsert, this, _1));
@@ -57,13 +55,13 @@
                                         std::function<void()> successCb,
                                         std::function<void(const std::string&)> failureCb)
 {
-  NFD_LOG_DEBUG("advertise " << rr.prefix << " on " << m_commandPrefix);
+  NFD_LOG_DEBUG("advertise " << rr.prefix << " on " << m_commandOptions.getPrefix());
 
   m_controller.start<ndn::nfd::RibRegisterCommand>(
-    ControlParameters().setName(rr.prefix).setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT),
+    getControlParameters().setName(rr.prefix),
     [=] (const ControlParameters& cp) { successCb(); },
     [=] (const ControlResponse& cr) { failureCb(cr.getText()); },
-    CommandOptions().setPrefix(m_commandPrefix).setSigningInfo(rr.signer));
+    getCommandOptions().setSigningInfo(rr.signer));
 }
 
 void
@@ -71,19 +69,31 @@
                                        std::function<void()> successCb,
                                        std::function<void(const std::string&)> failureCb)
 {
-  NFD_LOG_DEBUG("withdraw " << rr.prefix << " on " << m_commandPrefix);
+  NFD_LOG_DEBUG("withdraw " << rr.prefix << " on " << m_commandOptions.getPrefix());
 
   m_controller.start<ndn::nfd::RibUnregisterCommand>(
-    ControlParameters().setName(rr.prefix).setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT),
+    getControlParameters().setName(rr.prefix),
     [=] (const ControlParameters& cp) { successCb(); },
     [=] (const ControlResponse& cr) { failureCb(cr.getText()); },
-    CommandOptions().setPrefix(m_commandPrefix).setSigningInfo(rr.signer));
+    getCommandOptions().setSigningInfo(rr.signer));
+}
+
+ndn::nfd::ControlParameters
+NfdRibReadvertiseDestination::getControlParameters()
+{
+  return m_controlParameters;
+}
+
+ndn::nfd::CommandOptions
+NfdRibReadvertiseDestination::getCommandOptions()
+{
+  return m_commandOptions;
 }
 
 void
 NfdRibReadvertiseDestination::handleRibInsert(const ndn::Name& name)
 {
-  if (name.isPrefixOf(m_commandPrefix)) {
+  if (name.isPrefixOf(m_commandOptions.getPrefix())) {
     setAvailability(true);
   }
 }
@@ -91,7 +101,7 @@
 void
 NfdRibReadvertiseDestination::handleRibErase(const ndn::Name& name)
 {
-  if (name.isPrefixOf(m_commandPrefix)) {
+  if (name.isPrefixOf(m_commandOptions.getPrefix())) {
     setAvailability(false);
   }
 }
diff --git a/rib/readvertise/nfd-rib-readvertise-destination.hpp b/rib/readvertise/nfd-rib-readvertise-destination.hpp
index ec71d98..d31e81b 100644
--- a/rib/readvertise/nfd-rib-readvertise-destination.hpp
+++ b/rib/readvertise/nfd-rib-readvertise-destination.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2017,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2018,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -29,7 +29,9 @@
 #include "readvertise-destination.hpp"
 #include "../rib.hpp"
 
+#include <ndn-cxx/mgmt/nfd/command-options.hpp>
 #include <ndn-cxx/mgmt/nfd/controller.hpp>
+#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
 
 namespace nfd {
 namespace rib {
@@ -40,8 +42,11 @@
 {
 public:
   NfdRibReadvertiseDestination(ndn::nfd::Controller& controller,
-                               const Name& commandPrefix,
-                               Rib& rib);
+                               Rib& rib,
+                               const ndn::nfd::CommandOptions& options = ndn::nfd::CommandOptions(),
+                               const ndn::nfd::ControlParameters& parameters =
+                                 ndn::nfd::ControlParameters()
+                                   .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT));
 
   /** \brief add a name prefix into NFD RIB
    */
@@ -57,6 +62,13 @@
            std::function<void()> successCb,
            std::function<void(const std::string&)> failureCb) override;
 
+protected:
+  ndn::nfd::ControlParameters
+  getControlParameters();
+
+  ndn::nfd::CommandOptions
+  getCommandOptions();
+
 private:
   void
   handleRibInsert(const Name& name);
@@ -66,10 +78,12 @@
 
 private:
   ndn::nfd::Controller& m_controller;
-  Name m_commandPrefix;
 
   signal::ScopedConnection m_ribInsertConn;
   signal::ScopedConnection m_ribEraseConn;
+
+  ndn::nfd::CommandOptions m_commandOptions;
+  ndn::nfd::ControlParameters m_controlParameters;
 };
 
 } // namespace rib
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index 5ba99b8..8762e39 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -42,9 +42,10 @@
 
 static const std::string MGMT_MODULE_NAME = "rib";
 static const Name LOCALHOST_TOP_PREFIX = "/localhost/nfd";
-static const Name LOCALHOP_TOP_PREFIX = "/localhop/nfd";
 static const time::seconds ACTIVE_FACE_FETCH_INTERVAL = 5_min;
 
+const Name RibManager::LOCALHOP_TOP_PREFIX = "/localhop/nfd";
+
 RibManager::RibManager(Rib& rib, ndn::Face& face, ndn::KeyChain& keyChain,
                        ndn::nfd::Controller& nfdController, Dispatcher& dispatcher,
                        ndn::util::Scheduler& scheduler)
diff --git a/rib/rib-manager.hpp b/rib/rib-manager.hpp
index bb1a970..98d29f6 100644
--- a/rib/rib-manager.hpp
+++ b/rib/rib-manager.hpp
@@ -26,7 +26,6 @@
 #ifndef NFD_RIB_RIB_MANAGER_HPP
 #define NFD_RIB_RIB_MANAGER_HPP
 
-#include "auto-prefix-propagator.hpp"
 #include "fib-updater.hpp"
 #include "rib.hpp"
 
@@ -240,6 +239,9 @@
   void
   onNotification(const ndn::nfd::FaceEventNotification& notification);
 
+public:
+  static const Name LOCALHOP_TOP_PREFIX;
+
 private:
   Rib& m_rib;
   ndn::KeyChain& m_keyChain;
diff --git a/rib/service.cpp b/rib/service.cpp
index 48ff69c..a91a93e 100644
--- a/rib/service.cpp
+++ b/rib/service.cpp
@@ -25,9 +25,9 @@
 
 #include "service.hpp"
 
-#include "auto-prefix-propagator.hpp"
 #include "fib-updater.hpp"
 #include "readvertise/client-to-nlsr-readvertise-policy.hpp"
+#include "readvertise/host-to-gateway-readvertise-policy.hpp"
 #include "readvertise/nfd-rib-readvertise-destination.hpp"
 #include "readvertise/readvertise.hpp"
 
@@ -51,6 +51,8 @@
 static const std::string CFG_PREFIX_PROPAGATE = "auto_prefix_propagate";
 static const std::string CFG_READVERTISE_NLSR = "readvertise_nlsr";
 static const Name READVERTISE_NLSR_PREFIX = "/localhost/nlsr";
+static const uint64_t PROPAGATE_DEFAULT_COST = 15;
+static const time::milliseconds PROPAGATE_DEFAULT_TIMEOUT = 10_s;
 
 static ConfigSection
 loadConfigSectionFromFile(const std::string& filename)
@@ -194,13 +196,33 @@
       m_ribManager.enableLocalhop(value, filename);
     }
     else if (key == CFG_PREFIX_PROPAGATE) {
-      if (m_prefixPropagator == nullptr) {
-        m_prefixPropagator = make_unique<AutoPrefixPropagator>(m_nfdController, m_keyChain,
-                                                               m_scheduler, m_rib);
-      }
-      m_prefixPropagator->loadConfig(item.second);
-      m_prefixPropagator->enable();
       wantPrefixPropagate = true;
+
+      if (!m_readvertisePropagation) {
+        NFD_LOG_DEBUG("Enabling automatic prefix propagation");
+
+        auto parameters = ndn::nfd::ControlParameters()
+          .setCost(PROPAGATE_DEFAULT_COST)
+          .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT);
+        auto cost = item.second.get_optional<uint64_t>("cost");
+        if (cost) {
+          parameters.setCost(*cost);
+        }
+
+        auto options = ndn::nfd::CommandOptions()
+          .setPrefix(RibManager::LOCALHOP_TOP_PREFIX)
+          .setTimeout(PROPAGATE_DEFAULT_TIMEOUT);
+        auto timeout = item.second.get_optional<uint64_t>("timeout");
+        if (timeout) {
+          options.setTimeout(time::milliseconds(*timeout));
+        }
+
+        m_readvertisePropagation = make_unique<Readvertise>(
+          m_rib,
+          m_scheduler,
+          make_unique<HostToGatewayReadvertisePolicy>(m_keyChain, item.second),
+          make_unique<NfdRibReadvertiseDestination>(m_nfdController, m_rib, options, parameters));
+      }
     }
     else if (key == CFG_READVERTISE_NLSR) {
       wantReadvertiseNlsr = ConfigFile::parseYesNo(item, CFG_SECTION + "." + CFG_READVERTISE_NLSR);
@@ -210,17 +232,19 @@
     }
   }
 
-  if (!wantPrefixPropagate && m_prefixPropagator != nullptr) {
-    m_prefixPropagator->disable();
+  if (!wantPrefixPropagate && m_readvertisePropagation != nullptr) {
+    NFD_LOG_DEBUG("Disabling automatic prefix propagation");
+    m_readvertisePropagation.reset();
   }
 
   if (wantReadvertiseNlsr && m_readvertiseNlsr == nullptr) {
     NFD_LOG_DEBUG("Enabling readvertise-to-nlsr");
+    auto options = ndn::nfd::CommandOptions().setPrefix(READVERTISE_NLSR_PREFIX);
     m_readvertiseNlsr = make_unique<Readvertise>(
       m_rib,
       m_scheduler,
       make_unique<ClientToNlsrReadvertisePolicy>(),
-      make_unique<NfdRibReadvertiseDestination>(m_nfdController, READVERTISE_NLSR_PREFIX, m_rib));
+      make_unique<NfdRibReadvertiseDestination>(m_nfdController, m_rib, options));
   }
   else if (!wantReadvertiseNlsr && m_readvertiseNlsr != nullptr) {
     NFD_LOG_DEBUG("Disabling readvertise-to-nlsr");
diff --git a/rib/service.hpp b/rib/service.hpp
index 0b06013..e372a0d 100644
--- a/rib/service.hpp
+++ b/rib/service.hpp
@@ -40,7 +40,6 @@
 namespace nfd {
 namespace rib {
 
-class AutoPrefixPropagator;
 class Readvertise;
 
 /**
@@ -116,8 +115,8 @@
 
   Rib m_rib;
   FibUpdater m_fibUpdater;
-  unique_ptr<AutoPrefixPropagator> m_prefixPropagator;
   unique_ptr<Readvertise> m_readvertiseNlsr;
+  unique_ptr<Readvertise> m_readvertisePropagation;
   ndn::mgmt::Dispatcher m_dispatcher;
   RibManager m_ribManager;
 };
diff --git a/tests/rib/auto-prefix-propagator.t.cpp b/tests/rib/auto-prefix-propagator.t.cpp
deleted file mode 100644
index f33c7ae..0000000
--- a/tests/rib/auto-prefix-propagator.t.cpp
+++ /dev/null
@@ -1,684 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2018,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "rib/auto-prefix-propagator.hpp"
-
-#include "tests/identity-management-fixture.hpp"
-
-#include <ndn-cxx/security/pib/pib.hpp>
-#include <ndn-cxx/util/dummy-client-face.hpp>
-
-namespace nfd {
-namespace rib {
-namespace tests {
-
-using namespace nfd::tests;
-
-const Name TEST_LINK_LOCAL_NFD_PREFIX("/localhop/nfd");
-const time::milliseconds TEST_PREFIX_PROPAGATION_TIMEOUT(1000);
-
-class AutoPrefixPropagatorFixture : public IdentityManagementTimeFixture
-{
-public:
-  AutoPrefixPropagatorFixture()
-    : m_face(g_io, m_keyChain, {true, true})
-    , m_scheduler(g_io)
-    , m_controller(m_face, m_keyChain)
-    , m_propagator(m_controller, m_keyChain, m_scheduler, m_rib)
-    , m_requests(m_face.sentInterests)
-    , m_entries(m_propagator.m_propagatedEntries)
-  {
-    m_propagator.enable();
-    m_propagator.m_controlParameters
-      .setCost(15)
-      .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client.
-      .setFaceId(0);// the remote hub will take the input face as the faceId.
-    m_propagator.m_commandOptions
-      .setPrefix(TEST_LINK_LOCAL_NFD_PREFIX)
-      .setTimeout(TEST_PREFIX_PROPAGATION_TIMEOUT);
-  }
-
-public: // helpers for test
-  bool
-  insertEntryToRib(const Name& name, const uint64_t& faceId = 0)
-  {
-    if (m_rib.find(name) != m_rib.end()) {
-      BOOST_TEST_MESSAGE("RIB entry already exists: " + name.toUri());
-      return false;
-    }
-
-    Route route;
-    route.faceId = faceId;
-    m_rib.insert(name, route);
-    advanceClocks(time::milliseconds(1));
-
-    return m_rib.find(name) != m_rib.end(); // return whether afterInserEntry will be triggered
-  }
-
-  bool
-  eraseEntryFromRib(const Name& name)
-  {
-    if (m_rib.find(name) == m_rib.end()) {
-      BOOST_TEST_MESSAGE("RIB entry does not exist: " + name.toUri());
-      return false;
-    }
-
-    std::vector<Route> routeList;
-    std::copy(m_rib.find(name)->second->begin(), m_rib.find(name)->second->end(),
-              std::back_inserter(routeList));
-    for (auto&& route : routeList) {
-      m_rib.erase(name, route);
-    }
-    advanceClocks(time::milliseconds(1));
-
-    return m_rib.find(name) == m_rib.end(); // return whether afterEraseEntry will be triggered
-  }
-
-  void
-  connectToHub()
-  {
-    insertEntryToRib("/localhop/nfd");
-  }
-
-  void
-  disconnectFromHub()
-  {
-    eraseEntryFromRib("/localhop/nfd");
-  }
-
-public: // helpers for check
-  enum class CheckRequestResult {
-    OK,
-    OUT_OF_BOUNDARY,
-    INVALID_N_COMPONENTS,
-    WRONG_COMMAND_PREFIX,
-    WRONG_VERB,
-    INVALID_PARAMETERS,
-    WRONG_REGISTERING_PREFIX
-  };
-
-  /**
-   * @brief check a request at specified index
-   *
-   * @param idx the index of the specified request in m_requests
-   * @param verb the expected verb of request
-   * @param registeringPrefix the expected registering prefix of request
-
-   * @retval OK the specified request has a valid name, the right verb, a valid ControlParameters
-   *            and the right registering prefix
-   * @retval OUT_OF_BOUNDARY the specified index out of boundary
-   * @retval INVALID_N_COMPONENTS the number of components of the request name is invalid
-   * @retval WRONG_COMMAND_PREFIX the command prefix of the request is wrong
-   * @retval WRONG_VERB the command verb of the request is wrong
-   * @retval INVALID_PARAMETERS no valid parameters can be decoded from the request's name
-   * @retval WRONG_REGISTERING_PREFIX the registering prefix of the request is wrong
-   */
-  CheckRequestResult
-  checkRequest(size_t idx, const std::string& verb, const Name& registeringPrefix)
-  {
-    Name requestName;
-    try {
-      requestName = m_requests.at(idx).getName();
-    }
-    catch (const std::out_of_range&) {
-      return CheckRequestResult::OUT_OF_BOUNDARY;
-    }
-
-    if (requestName.size() < 5) {
-      return CheckRequestResult::INVALID_N_COMPONENTS;
-    }
-
-    if (requestName.getPrefix(2) != TEST_LINK_LOCAL_NFD_PREFIX) {
-      return CheckRequestResult::WRONG_COMMAND_PREFIX;
-    }
-
-    if (requestName.get(3) != Name::Component(verb)) {
-      return CheckRequestResult::WRONG_VERB;
-    }
-
-    ControlParameters parameters;
-    try {
-      parameters.wireDecode(requestName.get(4).blockFromValue());
-    }
-    catch (const tlv::Error&) {
-      return CheckRequestResult::INVALID_PARAMETERS;
-    }
-
-    if (parameters.getName() != registeringPrefix) {
-      return CheckRequestResult::WRONG_REGISTERING_PREFIX;
-    }
-
-    return CheckRequestResult::OK;
-  }
-
-protected:
-  ndn::util::DummyClientFace m_face;
-  ndn::util::Scheduler m_scheduler;
-  ndn::nfd::Controller m_controller;
-  Rib m_rib;
-  AutoPrefixPropagator m_propagator;
-  std::vector<Interest>& m_requests; ///< store sent out requests
-  AutoPrefixPropagator::PropagatedEntryList& m_entries; ///< store propagated entries
-};
-
-std::ostream&
-operator<<(std::ostream &os, const AutoPrefixPropagatorFixture::CheckRequestResult& result)
-{
-  switch (result) {
-  case AutoPrefixPropagatorFixture::CheckRequestResult::OK:
-    os << "OK";
-    break;
-  case AutoPrefixPropagatorFixture::CheckRequestResult::OUT_OF_BOUNDARY:
-    os << "OUT_OF_BOUNDARY";
-    break;
-  case AutoPrefixPropagatorFixture::CheckRequestResult::INVALID_N_COMPONENTS:
-    os << "INVALID_N_COMPONENTS";
-    break;
-  case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_COMMAND_PREFIX:
-    os << "WRONG_COMMAND_PREFIX";
-    break;
-  case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_VERB:
-    os << "WRONG_VERB";
-    break;
-  case AutoPrefixPropagatorFixture::CheckRequestResult::INVALID_PARAMETERS:
-    os << "INVALID_PARAMETERS";
-    break;
-  case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_REGISTERING_PREFIX:
-    os << "WRONG_REGISTERING_PREFIX";
-    break;
-  default:
-    break;
-  }
-
-  return os;
-}
-
-BOOST_FIXTURE_TEST_SUITE(TestAutoPrefixPropagator, AutoPrefixPropagatorFixture)
-
-BOOST_AUTO_TEST_CASE(EnableDisable)
-{
-  connectToHub();
-  BOOST_REQUIRE(addIdentity("/test/A"));
-
-  auto testPropagateRevokeBasic = [this] () -> bool {
-    m_propagator.m_propagatedEntries.clear();
-
-    if (!insertEntryToRib("/test/A/app")) {
-      return false;
-    }
-    m_entries["/test/A"].succeed(m_scheduler, nullptr);
-    if (!eraseEntryFromRib("/test/A/app")) {
-      return false;
-    }
-    return true;
-  };
-
-  m_propagator.disable();
-  BOOST_REQUIRE(testPropagateRevokeBasic());
-  BOOST_CHECK(m_requests.empty());
-
-  m_propagator.enable();
-  BOOST_REQUIRE(testPropagateRevokeBasic());
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 2);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
-  BOOST_CHECK_EQUAL(checkRequest(1, "unregister", "/test/A"), CheckRequestResult::OK);
-}
-
-BOOST_AUTO_TEST_CASE(LoadConfiguration)
-{
-  ConfigFile config;
-  config.addSectionHandler("auto_prefix_propagate",
-                           bind(&AutoPrefixPropagator::loadConfig, &m_propagator, _1));
-
-  const std::string CONFIG_STRING =
-    "auto_prefix_propagate\n"
-    "{\n"
-    "  cost 11\n"
-    "  timeout 22\n"
-    "  refresh_interval 33\n"
-    "  base_retry_wait 44\n"
-    "  max_retry_wait 55\n"
-    "}";
-  config.parse(CONFIG_STRING, true, "test-auto-prefix-propagator");
-
-  BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getCost(), 11);
-  BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getOrigin(), ndn::nfd::ROUTE_ORIGIN_CLIENT);
-  BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getFaceId(), 0);
-
-  BOOST_CHECK_EQUAL(m_propagator.m_commandOptions.getPrefix(), TEST_LINK_LOCAL_NFD_PREFIX);
-  BOOST_CHECK_EQUAL(m_propagator.m_commandOptions.getTimeout(), time::milliseconds(22));
-
-  BOOST_CHECK_EQUAL(m_propagator.m_refreshInterval, time::seconds(33));
-  BOOST_CHECK_EQUAL(m_propagator.m_baseRetryWait, time::seconds(44));
-  BOOST_CHECK_EQUAL(m_propagator.m_maxRetryWait, time::seconds(55));
-}
-
-BOOST_AUTO_TEST_CASE(GetPrefixPropagationParameters)
-{
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  BOOST_REQUIRE(addIdentity("/test/A/B"));
-  BOOST_REQUIRE(addIdentity("/test/C/nrd"));
-
-  auto parameters1 = m_propagator.getPrefixPropagationParameters("/none/A/B/app");
-  auto parameters2 = m_propagator.getPrefixPropagationParameters("/test/A/B/app");
-  auto parameters3 = m_propagator.getPrefixPropagationParameters("/test/C/D/app");
-
-  BOOST_CHECK(!parameters1.isValid);
-
-  BOOST_CHECK(parameters2.isValid);
-  BOOST_CHECK_EQUAL(parameters2.parameters.getName(), "/test/A");
-  BOOST_CHECK_EQUAL(parameters2.options.getSigningInfo().getSignerName(), "/test/A");
-
-  BOOST_CHECK(parameters3.isValid);
-  BOOST_CHECK_EQUAL(parameters3.parameters.getName(), "/test/C");
-  BOOST_CHECK_EQUAL(parameters3.options.getSigningInfo().getSignerName(), "/test/C/nrd");
-}
-
-BOOST_AUTO_TEST_CASE(CheckCurrentPropagatedPrefix)
-{
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  BOOST_REQUIRE(addIdentity("/test/B/nrd"));
-  BOOST_REQUIRE(addIdentity("/test/A/B"));
-
-  BOOST_CHECK(!m_propagator.doesCurrentPropagatedPrefixWork("/test/E")); // does not exist
-  BOOST_CHECK(!m_propagator.doesCurrentPropagatedPrefixWork("/test/A/B")); // has a better option
-  BOOST_CHECK(m_propagator.doesCurrentPropagatedPrefixWork("/test/A"));
-  BOOST_CHECK(m_propagator.doesCurrentPropagatedPrefixWork("/test/B"));
-}
-
-BOOST_AUTO_TEST_CASE(RedoPropagation)
-{
-  connectToHub();
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  BOOST_REQUIRE(addIdentity("/test/B"));
-  BOOST_REQUIRE(addIdentity("/test/B/C"));
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
-  BOOST_REQUIRE(insertEntryToRib("/test/B/C/app"));
-  BOOST_REQUIRE(insertEntryToRib("/test/B/D/app"));
-
-  auto testRedoPropagation = [this] (const Name& signingIdentity) {
-    m_requests.clear();
-
-    m_entries[signingIdentity].setSigningIdentity(signingIdentity);
-
-    auto parameters = m_propagator.m_controlParameters;
-    auto options = m_propagator.m_commandOptions;
-    ndn::security::SigningInfo info(ndn::security::SigningInfo::SIGNER_TYPE_ID, signingIdentity);
-    m_propagator.redoPropagation(m_entries.find(signingIdentity),
-                                  parameters.setName(signingIdentity),
-                                  options.setSigningInfo(info),
-                                  time::seconds(0));
-    advanceClocks(time::milliseconds(1));
-  };
-
-  testRedoPropagation("/test/A"); // current propagated prefix still works
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
-  BOOST_CHECK(m_entries.find("test/A") != m_entries.end());
-
-  m_keyChain.deleteIdentity(m_keyChain.getPib().getIdentity("/test/B"));
-  testRedoPropagation("/test/B"); // signingIdentity no longer exists
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/B/C"), CheckRequestResult::OK);
-  BOOST_CHECK(m_entries.find("/test/B") == m_entries.end());
-  BOOST_CHECK(m_entries.find("/test/B/C") != m_entries.end());
-
-  testRedoPropagation("/test/B"); // no alternative identity
-  BOOST_CHECK(m_requests.empty());
-  BOOST_CHECK(m_entries.find("/test/B") == m_entries.end());
-
-  m_entries["/test/B/C"].succeed(m_scheduler, nullptr);
-  testRedoPropagation("/test/B"); // alternative identity has been propagated
-  BOOST_CHECK(m_requests.empty());
-  BOOST_CHECK(m_entries.find("/test/B") == m_entries.end());
-
-  BOOST_REQUIRE(addIdentity("/test/B/"));
-  testRedoPropagation("/test/B/C"); // better option exists: /test/B
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/B"), CheckRequestResult::OK);
-  BOOST_CHECK(m_entries.find("test/B/C") == m_entries.end());
-}
-
-BOOST_AUTO_TEST_SUITE(PropagateRevokeSemantics)
-
-BOOST_AUTO_TEST_CASE(Basic)
-{
-  connectToHub(); // ensure connectivity to the hub
-  BOOST_REQUIRE(addIdentity("/test/A"));
-
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app")); // ensure afterInsertEntry signal emitted
-  m_entries["/test/A"].succeed(m_scheduler, nullptr); // ensure there is a valid entry inserted
-  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app")); // ensure afterEraseEntry signal emitted
-
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 2);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
-  BOOST_CHECK_EQUAL(checkRequest(1, "unregister", "/test/A"), CheckRequestResult::OK);
-}
-
-BOOST_AUTO_TEST_CASE(LocalPrefix)
-{
-  connectToHub();
-  BOOST_REQUIRE(addIdentity("/localhost/A"));
-
-  BOOST_REQUIRE(insertEntryToRib("/localhost/A/app"));
-  BOOST_CHECK(m_requests.empty());
-
-  m_propagator.m_propagatedEntries["/localhost/A"].succeed(m_scheduler, nullptr);
-  BOOST_REQUIRE(eraseEntryFromRib("/localhost/A/app"));
-  BOOST_CHECK(m_requests.empty());
-}
-
-BOOST_AUTO_TEST_CASE(InvalidPropagationParameters)
-{
-  connectToHub();
-
-  // no identity can be found
-  BOOST_CHECK(!m_propagator.getPrefixPropagationParameters("/test/A/app").isValid);
-
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
-  BOOST_CHECK(m_requests.empty());
-
-  m_entries["/test/A"].succeed(m_scheduler, nullptr);
-  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app"));
-  BOOST_CHECK(m_requests.empty());
-}
-
-BOOST_AUTO_TEST_CASE(NoHubConnectivity)
-{
-  BOOST_REQUIRE(addIdentity("/test/A"));
-
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
-  BOOST_CHECK(m_requests.empty());
-
-  m_entries["/test/A"].succeed(m_scheduler, nullptr);
-  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app"));
-  BOOST_CHECK(m_requests.empty());
-}
-
-BOOST_AUTO_TEST_CASE(ProcessSuspendedEntries)
-{
-  BOOST_REQUIRE(addIdentity("/test/A"));
-
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app1"));
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app2"));
-  BOOST_CHECK(m_requests.empty()); // no propagation because no hub is connected
-  BOOST_CHECK_EQUAL(m_entries.size(), 1); // /test/A was suspended
-
-  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app2"));
-  BOOST_CHECK_EQUAL(m_entries.size(), 1); // /test/A was kept for app1
-
-  // repeat the scenario that leads to BUG 3362.
-  // ensure there is no improper assertion.
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app2"));
-}
-
-BOOST_AUTO_TEST_CASE(PropagatedEntryExists)
-{
-  connectToHub();
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app1"));
-
-  m_requests.clear();
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app2")); // /test/A has been propagated by /test/A/app1
-  BOOST_CHECK(m_requests.empty());
-}
-
-BOOST_AUTO_TEST_CASE(PropagatedEntryShouldKeep)
-{
-  connectToHub();
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app1"));
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app2"));
-
-  m_requests.clear();
-  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app2")); // /test/A should be kept for /test/A/app1
-  BOOST_CHECK(m_requests.empty());
-}
-
-BOOST_AUTO_TEST_CASE(BackOffRetryPolicy)
-{
-  m_propagator.m_commandOptions.setTimeout(time::milliseconds(1));
-  m_propagator.m_baseRetryWait = time::seconds(1);
-  m_propagator.m_maxRetryWait = time::seconds(2);
-
-  connectToHub();
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
-
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
-
-  advanceClocks(time::milliseconds(10), time::milliseconds(1050)); // wait for the 1st retry
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 2);
-  BOOST_CHECK_EQUAL(checkRequest(1, "register", "/test/A"), CheckRequestResult::OK);
-
-  advanceClocks(time::milliseconds(10), time::milliseconds(2050)); // wait for the 2nd retry, 2 times
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 3);
-  BOOST_CHECK_EQUAL(checkRequest(2, "register", "/test/A"), CheckRequestResult::OK);
-
-  advanceClocks(time::milliseconds(10), time::milliseconds(2050)); // wait for the 3rd retry, reach the upper bound
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 4);
-  BOOST_CHECK_EQUAL(checkRequest(3, "register", "/test/A"), CheckRequestResult::OK);
-}
-
-BOOST_AUTO_TEST_SUITE_END() // PropagateRevokeSemantics
-
-BOOST_AUTO_TEST_SUITE(PropagatedEntryStateChanges)
-
-BOOST_AUTO_TEST_CASE(AfterRibInsert)
-{
-  BOOST_REQUIRE(addIdentity("/test/A"));
-
-  auto testAfterRibInsert = [this] (const Name& ribEntryPrefix) {
-    m_requests.clear();
-    m_propagator.m_propagatedEntries.clear(); // ensure entry does not exist
-
-    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
-    m_propagator.afterRibInsert(propagateParameters.parameters, propagateParameters.options);
-    advanceClocks(time::milliseconds(1));
-  };
-
-  testAfterRibInsert("/test/A/app1");
-  BOOST_CHECK(m_requests.empty()); // no connectivity now
-  BOOST_CHECK(m_entries.find("/test/A") != m_entries.end());
-
-  connectToHub();
-  testAfterRibInsert("/test/A/app2");
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
-  BOOST_CHECK(m_entries.find("/test/A") != m_entries.end());
-}
-
-BOOST_AUTO_TEST_CASE(AfterRibErase)
-{
-  BOOST_REQUIRE(addIdentity("/test/A"));
-
-  auto testAfterRibInsert = [this] (const Name& localUnregPrefix) {
-    m_requests.clear();
-
-    auto propagateParameters = m_propagator.getPrefixPropagationParameters(localUnregPrefix);
-    m_propagator.afterRibErase(propagateParameters.parameters.unsetCost(),
-                               propagateParameters.options);
-    advanceClocks(time::milliseconds(1));
-  };
-
-  m_entries["/test/A"].succeed(m_scheduler, nullptr);
-  testAfterRibInsert("/test/A/app");
-  BOOST_CHECK(m_requests.empty()); // no connectivity
-  BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased
-
-  connectToHub();
-  m_entries["/test/A"].fail(m_scheduler, nullptr);
-  testAfterRibInsert("/test/A/app");
-  BOOST_CHECK(m_requests.empty()); // previous propagation has not succeeded
-  BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased
-
-  m_entries["/test/A"].succeed(m_scheduler, nullptr);
-  testAfterRibInsert("/test/A/app");
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "unregister", "/test/A"), CheckRequestResult::OK);
-  BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased
-}
-
-BOOST_AUTO_TEST_CASE(AfterHubConnectDisconnect)
-{
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  BOOST_REQUIRE(addIdentity("/test/B"));
-  BOOST_REQUIRE(addIdentity("/test/C"));
-  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
-  BOOST_REQUIRE(insertEntryToRib("/test/B/app"));
-
-  // recorder the prefixes that will be propagated in order
-  std::vector<Name> propagatedPrefixes;
-
-  BOOST_CHECK(m_requests.empty()); // no request because there is no connectivity to the hub now
-  BOOST_REQUIRE_EQUAL(m_entries.size(), 2); // valid entries will be kept
-
-  connectToHub(); // 2 cached entries will be processed
-  for (auto&& entry : m_entries) {
-    propagatedPrefixes.push_back(entry.first);
-  }
-
-  BOOST_REQUIRE(insertEntryToRib("/test/C/app")); // will be processed directly
-  propagatedPrefixes.push_back("/test/C");
-  BOOST_REQUIRE_EQUAL(m_entries.size(), 3);
-
-  BOOST_REQUIRE(m_entries["/test/A"].isPropagating());
-  BOOST_REQUIRE(m_entries["/test/B"].isPropagating());
-  BOOST_REQUIRE(m_entries["/test/C"].isPropagating());
-
-  disconnectFromHub(); // all 3 entries are initialized
-  BOOST_CHECK(m_entries["/test/A"].isNew());
-  BOOST_CHECK(m_entries["/test/B"].isNew());
-  BOOST_CHECK(m_entries["/test/C"].isNew());
-
-  connectToHub(); // all 3 entries will be processed
-  for (auto&& entry : m_entries) {
-    propagatedPrefixes.push_back(entry.first);
-  }
-
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 6);
-  BOOST_REQUIRE_EQUAL(propagatedPrefixes.size(), 6);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", propagatedPrefixes[0]), CheckRequestResult::OK);
-  BOOST_CHECK_EQUAL(checkRequest(1, "register", propagatedPrefixes[1]), CheckRequestResult::OK);
-  BOOST_CHECK_EQUAL(checkRequest(2, "register", propagatedPrefixes[2]), CheckRequestResult::OK);
-  BOOST_CHECK_EQUAL(checkRequest(3, "register", propagatedPrefixes[3]), CheckRequestResult::OK);
-  BOOST_CHECK_EQUAL(checkRequest(4, "register", propagatedPrefixes[4]), CheckRequestResult::OK);
-  BOOST_CHECK_EQUAL(checkRequest(5, "register", propagatedPrefixes[5]), CheckRequestResult::OK);
-}
-
-BOOST_AUTO_TEST_CASE(AfterPropagateSucceed)
-{
-  bool wasRefreshEventTriggered = false;
-  auto testAfterPropagateSucceed = [&] (const Name& ribEntryPrefix) {
-    m_requests.clear();
-    wasRefreshEventTriggered = false;
-
-    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
-    m_propagator.afterPropagateSucceed(propagateParameters.parameters, propagateParameters.options,
-                                       [&]{ wasRefreshEventTriggered = true; });
-    advanceClocks(time::milliseconds(1));
-  };
-
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  m_propagator.m_refreshInterval = time::seconds(0); // event will be executed at once
-  m_entries["/test/A"].startPropagation(); // set to be in PROPAGATING state
-
-  testAfterPropagateSucceed("/test/A/app"); // will trigger refresh event
-  BOOST_CHECK(wasRefreshEventTriggered);
-  BOOST_CHECK(m_requests.empty());
-
-  m_entries.erase(m_entries.find("/test/A")); // set to be in RELEASED state
-  testAfterPropagateSucceed("/test/A/app"); // will call startRevocation
-  BOOST_CHECK(!wasRefreshEventTriggered);
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "unregister", "/test/A"), CheckRequestResult::OK);
-}
-
-BOOST_AUTO_TEST_CASE(AfterPropagateFail)
-{
-  bool wasRetryEventTriggered = false;
-  auto testAfterPropagateFail = [&] (const Name& ribEntryPrefix) {
-    m_requests.clear();
-    wasRetryEventTriggered = false;
-
-    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
-    m_propagator.afterPropagateFail(ndn::nfd::ControlResponse(400, "test"),
-                                    propagateParameters.parameters, propagateParameters.options,
-                                    time::seconds(0), [&] { wasRetryEventTriggered = true; });
-    advanceClocks(time::milliseconds(1));
-  };
-
-  BOOST_REQUIRE(addIdentity("/test/A"));
-  m_entries["/test/A"].startPropagation(); // set to be in PROPAGATING state
-
-  testAfterPropagateFail("/test/A/app"); // will trigger retry event
-  BOOST_CHECK(wasRetryEventTriggered);
-  BOOST_CHECK(m_requests.empty());
-
-  m_entries.erase(m_entries.find("/test/A")); // set to be in RELEASED state
-  testAfterPropagateFail("/test/A/app"); // will do nothing
-  BOOST_CHECK(!wasRetryEventTriggered);
-  BOOST_CHECK(m_requests.empty());
-}
-
-BOOST_AUTO_TEST_CASE(AfterRevokeSucceed)
-{
-  auto testAfterRevokeSucceed = [&] (const Name& ribEntryPrefix) {
-    m_requests.clear();
-    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
-    m_propagator.afterRevokeSucceed(propagateParameters.parameters,
-                                    propagateParameters.options,
-                                    time::seconds(0));
-    advanceClocks(time::milliseconds(1));
-  };
-
-  BOOST_REQUIRE(addIdentity("/test/A"));
-
-  testAfterRevokeSucceed("/test/A/app"); // in RELEASED state
-  BOOST_CHECK(m_requests.empty());
-
-  m_entries["/test/A"].fail(m_scheduler, nullptr); // in PROPAGATE_FAIL state
-  testAfterRevokeSucceed("/test/A/app");
-  BOOST_CHECK(m_requests.empty());
-
-  m_entries["/test/A"].succeed(m_scheduler, nullptr); // in PROPAGATED state
-  testAfterRevokeSucceed("/test/A/app");
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
-
-  m_entries["/test/A"].startPropagation(); // in PROPAGATING state
-  testAfterRevokeSucceed("/test/A/app");
-  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
-  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
-}
-
-BOOST_AUTO_TEST_SUITE_END() // PropagatedEntryStateChanges
-
-BOOST_AUTO_TEST_SUITE_END() // TestAutoPrefixPropagator
-
-} // namespace tests
-} // namespace rib
-} // namespace nfd
diff --git a/tests/rib/propagated-entry.t.cpp b/tests/rib/propagated-entry.t.cpp
deleted file mode 100644
index b03f153..0000000
--- a/tests/rib/propagated-entry.t.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2018,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "rib/propagated-entry.hpp"
-
-#include "tests/test-common.hpp"
-
-namespace nfd {
-namespace rib {
-namespace tests {
-
-BOOST_FIXTURE_TEST_SUITE(TestPropagatedEntry, nfd::tests::BaseFixture)
-
-BOOST_AUTO_TEST_CASE(Identity)
-{
-  PropagatedEntry entry;
-  BOOST_CHECK(entry.m_signingIdentity.empty());
-
-  entry.setSigningIdentity("/test");
-  BOOST_CHECK_EQUAL(entry.m_signingIdentity, "/test");
-  BOOST_CHECK_EQUAL(entry.getSigningIdentity(), "/test");
-}
-
-BOOST_AUTO_TEST_CASE(Start)
-{
-  PropagatedEntry entry;
-  BOOST_CHECK(!entry.isPropagating());
-
-  entry.startPropagation();
-  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATING, entry.m_propagationStatus);
-  BOOST_CHECK(entry.isPropagating());
-}
-
-BOOST_AUTO_TEST_CASE(Succeed)
-{
-  ndn::util::Scheduler scheduler(g_io);
-  PropagatedEntry entry;
-  entry.succeed(scheduler, nullptr);
-  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATED, entry.m_propagationStatus);
-  BOOST_CHECK(entry.isPropagated());
-}
-
-BOOST_AUTO_TEST_CASE(Fail)
-{
-  ndn::util::Scheduler scheduler(g_io);
-  PropagatedEntry entry;
-  entry.fail(scheduler, nullptr);
-  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATE_FAIL, entry.m_propagationStatus);
-  BOOST_CHECK(entry.isPropagateFail());
-}
-
-BOOST_AUTO_TEST_CASE(Initialize)
-{
-  PropagatedEntry entry;
-  entry.startPropagation();
-  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATING, entry.m_propagationStatus);
-
-  entry.initialize();
-  BOOST_CHECK_EQUAL(PropagationStatus::NEW, entry.m_propagationStatus);
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestPropagatedEntry
-
-} // namespace tests
-} // namespace rib
-} // namespace nfd
diff --git a/tests/rib/readvertise/host-to-gateway-readvertise-policy.t.cpp b/tests/rib/readvertise/host-to-gateway-readvertise-policy.t.cpp
new file mode 100644
index 0000000..1b357cb
--- /dev/null
+++ b/tests/rib/readvertise/host-to-gateway-readvertise-policy.t.cpp
@@ -0,0 +1,114 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "rib/readvertise/host-to-gateway-readvertise-policy.hpp"
+
+#include "tests/identity-management-fixture.hpp"
+
+#include <ndn-cxx/security/signing-helpers.hpp>
+
+namespace nfd {
+namespace rib {
+namespace tests {
+
+using namespace nfd::tests;
+
+class HostToGatewayReadvertisePolicyFixture : public IdentityManagementFixture
+{
+public:
+  RibRouteRef
+  makeNewRoute(const Name& prefix) {
+    auto entry = make_shared<RibEntry>();
+    entry->setName(prefix);
+
+    Route route;
+    auto routeIt = entry->insertRoute(route).first;
+    return RibRouteRef{entry, routeIt};
+  }
+
+  shared_ptr<HostToGatewayReadvertisePolicy>
+  makePolicy(const ConfigSection& section = ConfigSection())
+  {
+    return make_shared<HostToGatewayReadvertisePolicy>(m_keyChain, section);
+  }
+};
+
+BOOST_AUTO_TEST_SUITE(Readvertise)
+BOOST_FIXTURE_TEST_SUITE(TestHostToGatewayReadvertisePolicy,
+                         HostToGatewayReadvertisePolicyFixture)
+
+BOOST_AUTO_TEST_CASE(PrefixToAdvertise)
+{
+  BOOST_REQUIRE(addIdentity("/A"));
+  BOOST_REQUIRE(addIdentity("/A/B"));
+  BOOST_REQUIRE(addIdentity("/C/nrd"));
+
+  auto test = [this] (Name routeName, optional<ReadvertiseAction> expectedAction) {
+    auto policy = makePolicy();
+    auto action = policy->handleNewRoute(makeNewRoute(routeName));
+
+    if (expectedAction) {
+      BOOST_REQUIRE(action);
+      BOOST_CHECK_EQUAL(action->prefix, expectedAction->prefix);
+      BOOST_REQUIRE_EQUAL(action->signer, expectedAction->signer);
+    }
+    else {
+      BOOST_REQUIRE(!action);
+    }
+  };
+
+  test("/D/app", nullopt);
+  test("/A/B/app", ReadvertiseAction{"/A", ndn::security::signingByIdentity("/A")});
+  test("/C/nrd", ReadvertiseAction{"/C", ndn::security::signingByIdentity("/C/nrd")});
+}
+
+BOOST_AUTO_TEST_CASE(DontReadvertise)
+{
+  auto policy = makePolicy();
+  BOOST_REQUIRE(!policy->handleNewRoute(makeNewRoute("/localhost/test")));
+  BOOST_REQUIRE(!policy->handleNewRoute(makeNewRoute("/localhop/nfd")));
+}
+
+BOOST_AUTO_TEST_CASE(LoadRefreshInterval)
+{
+  auto policy = makePolicy();
+  BOOST_CHECK_EQUAL(policy->getRefreshInterval(), time::seconds(25)); // default setting is 25
+
+  ConfigSection section;
+  section.put("refresh_interval_wrong", 10);
+  policy = makePolicy(section);
+  BOOST_CHECK_EQUAL(policy->getRefreshInterval(), time::seconds(25)); // wrong formate
+
+  section.put("refresh_interval", 10);
+  policy = makePolicy(section);
+  BOOST_CHECK_EQUAL(policy->getRefreshInterval(), time::seconds(10));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestHostToGatewayReadvertisePolicy
+BOOST_AUTO_TEST_SUITE_END() // Readvertise
+
+} // namespace tests
+} // namespace rib
+} // namespace nfd
diff --git a/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp b/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
index 483f94a..48164bd 100644
--- a/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
+++ b/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
@@ -46,9 +46,9 @@
     , face(g_io, m_keyChain, {true, false})
     , scheduler(g_io)
     , controller(face, m_keyChain)
-    , dest(controller, Name("/localhost/nlsr"), rib)
+    , dest(controller, rib, ndn::nfd::CommandOptions().setPrefix("/localhost/nlsr"))
     , successCallback([this] { nSuccessCallbacks++; })
-    , failureCallback([this] (const std::string&) { nFailureCallbacks++; })
+    , failureCallback([this] (const std::string& str) { nFailureCallbacks++; })
   {
   }