rib: redesign of remote prefix registration
Change-Id: I8418de6d5bb9615af898df5dbf9ed4cc2cb6a43a
Refs: #3211, #2413
diff --git a/rib/auto-prefix-propagator.cpp b/rib/auto-prefix-propagator.cpp
new file mode 100644
index 0000000..12344e2
--- /dev/null
+++ b/rib/auto-prefix-propagator.cpp
@@ -0,0 +1,472 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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 "core/scheduler.hpp"
+#include <ndn-cxx/security/signing-helpers.hpp>
+#include <vector>
+
+namespace nfd {
+namespace rib {
+
+NFD_LOG_INIT("AutoPrefixPropagator");
+
+using ndn::nfd::ControlParameters;
+using ndn::nfd::CommandOptions;
+
+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,
+ Rib& rib)
+ : m_nfdController(controller)
+ , m_keyChain(keyChain)
+ , 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)
+{
+ // get all identities from the KeyChain
+ std::vector<Name> identities;
+ m_keyChain.getAllIdentities(identities, false); // get all except the default
+ identities.push_back(m_keyChain.getDefaultIdentity()); // get the default
+
+ // shortest prefix matching to all identies.
+ Name propagatedPrefix, signingIdentity;
+ bool isFound = false;
+ for (auto&& i : identities) {
+ Name prefix = !i.empty() && IGNORE_COMMPONENT == i.at(-1) ? i.getPrefix(-1) : i;
+ if (prefix.isPrefixOf(localRibPrefix) && (!isFound || i.size() < signingIdentity.size())) {
+ isFound = true;
+ propagatedPrefix = prefix;
+ signingIdentity = i;
+ }
+ }
+
+ 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(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()) {
+ BOOST_ASSERT(!entryIt->second.isNew());
+ 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 startPropagation(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::startPropagation(const ControlParameters& parameters,
+ const CommandOptions& options,
+ time::seconds retryWaitTime)
+{
+ NFD_LOG_TRACE("start propagate " << parameters.getName());
+
+ ndn::Scheduler::Event refreshEvent =
+ bind(&AutoPrefixPropagator::onRefreshTimer, this, parameters, options);
+ ndn::Scheduler::Event 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, _2, parameters, options, retryWaitTime, retryEvent),
+ options);
+}
+
+void
+AutoPrefixPropagator::startRevocation(const ControlParameters& parameters,
+ const CommandOptions& options,
+ time::seconds retryWaitTime)
+{
+ NFD_LOG_INFO("start revoke propagation of " << parameters.getName());
+
+ m_nfdController.start<ndn::nfd::RibUnregisterCommand>(
+ parameters,
+ bind(&AutoPrefixPropagator::afterRevokeSucceed, this, parameters, options, retryWaitTime),
+ bind(&AutoPrefixPropagator::afterRevokeFail, this, _1, _2, 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();
+ startPropagation(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;
+ }
+
+ startRevocation(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 ndn::Scheduler::Event& 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 startRevocation(newParameters.unsetCost(), options, m_baseRetryWait);
+ }
+
+ // PROPAGATING --> PROPAGATED
+ BOOST_ASSERT(entryIt->second.isPropagating());
+ entryIt->second.succeed(scheduler::schedule(m_refreshInterval, refreshEvent));
+}
+
+void
+AutoPrefixPropagator::afterPropagateFail(uint32_t code, const std::string& reason,
+ const ControlParameters& parameters,
+ const CommandOptions& options,
+ time::seconds retryWaitTime,
+ const ndn::Scheduler::Event& retryEvent)
+{
+ NFD_LOG_TRACE("fail to propagate " << parameters.getName()
+ << "\n\t reason:" << reason
+ << "\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(scheduler::schedule(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;
+ startPropagation(newParameters.setCost(m_controlParameters.getCost()), options, retryWaitTime);
+ }
+}
+
+void
+AutoPrefixPropagator::afterRevokeFail(uint32_t code, const std::string& reason,
+ const ControlParameters& parameters,
+ const CommandOptions& options)
+{
+ NFD_LOG_INFO("fail to revoke the propagation of " << parameters.getName()
+ << "\n\t reason:" << reason);
+}
+
+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
new file mode 100644
index 0000000..11ad67f
--- /dev/null
+++ b/rib/auto-prefix-propagator.hpp
@@ -0,0 +1,418 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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 "rib.hpp"
+#include "core/config-file.hpp"
+#include "rib-status-publisher.hpp"
+#include "propagated-entry.hpp"
+
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/management/nfd-controller.hpp>
+#include <ndn-cxx/management/nfd-control-command.hpp>
+#include <ndn-cxx/management/nfd-control-parameters.hpp>
+#include <ndn-cxx/management/nfd-command-options.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,
+ 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
+ startPropagation(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
+ startRevocation(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 startRevocation 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::Scheduler::Event& 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 code error code.
+ * @param reason error reason in string.
+ * @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(uint32_t code, const std::string& reason,
+ const ndn::nfd::ControlParameters& parameters,
+ const ndn::nfd::CommandOptions& options,
+ time::seconds retryWaitTime,
+ const ndn::Scheduler::Event& 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 startPropagation 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 code error code.
+ * @param reason error reason in string.
+ * @param parameters the ControlParameters used by the unregistration command for revocation
+ * @param options the CommandOptions used by the unregistration command for revocation
+ */
+ void
+ afterRevokeFail(uint32_t code, const std::string& reason,
+ 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;
+ 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
new file mode 100644
index 0000000..8dff54a
--- /dev/null
+++ b/rib/propagated-entry.cpp
@@ -0,0 +1,131 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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 "core/logger.hpp"
+#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()
+ : m_propagationStatus(PropagationStatus::NEW)
+{
+}
+
+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(const scheduler::EventId& event)
+{
+ m_propagationStatus = PropagationStatus::PROPAGATED;
+ m_rePropagateEvent = event;
+}
+
+void
+PropagatedEntry::fail(const scheduler::EventId& event)
+{
+ m_propagationStatus = PropagationStatus::PROPAGATE_FAIL;
+ m_rePropagateEvent = event;
+}
+
+void
+PropagatedEntry::initialize()
+{
+ m_propagationStatus = PropagationStatus::NEW;
+ 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
new file mode 100644
index 0000000..f4e61dd
--- /dev/null
+++ b/rib/propagated-entry.hpp
@@ -0,0 +1,158 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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/scheduler.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.
+ * @sa http://redmine.named-data.net/issues/3211
+ *
+ * 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();
+
+ /**
+ * @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(const 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(const 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;
+ scheduler::ScopedEventId m_rePropagateEvent;
+ PropagationStatus m_propagationStatus;
+};
+
+} // namespace rib
+} // namespace nfd
+
+#endif // NFD_RIB_PROPAGATED_ENTRY_HPP
diff --git a/rib/remote-registrator.cpp b/rib/remote-registrator.cpp
deleted file mode 100644
index d33ba1b..0000000
--- a/rib/remote-registrator.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015, 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 "remote-registrator.hpp"
-#include "core/logger.hpp"
-#include "core/scheduler.hpp"
-#include <ndn-cxx/security/signing-helpers.hpp>
-
-namespace nfd {
-namespace rib {
-
-NFD_LOG_INIT("RemoteRegistrator");
-
-using ndn::nfd::ControlParameters;
-using ndn::nfd::CommandOptions;
-
-const Name RemoteRegistrator::LOCAL_REGISTRATION_PREFIX = "/localhost";
-const Name RemoteRegistrator::REMOTE_HUB_PREFIX = "/localhop/nfd";
-const name::Component RemoteRegistrator::IGNORE_COMMPONENT("rib");
-
-RemoteRegistrator::RemoteRegistrator(ndn::nfd::Controller& controller,
- ndn::KeyChain& keyChain,
- Rib& rib)
- : m_nfdController(controller)
- , m_keyChain(keyChain)
- , m_rib(rib)
- , m_refreshInterval(time::seconds(25))
- , m_hasConnectedHub(false)
- , m_nRetries(0)
-{
-}
-
-RemoteRegistrator::~RemoteRegistrator()
-{
- // cancel all periodically refresh events.
- for (auto&& entry : m_regEntries)
- {
- scheduler::cancel(entry.second);
- }
-}
-
-void
-RemoteRegistrator::loadConfig(const ConfigSection& configSection)
-{
- size_t cost = 15, timeout = 10000;
- size_t retry = 0;
- size_t interval = 0;
- const size_t intervalDef = 25, intervalMax = 600;
-
- NFD_LOG_INFO("Load remote_register section in rib section");
- for (auto&& i : configSection)
- {
- if (i.first == "cost")
- {
- cost = i.second.get_value<size_t>();
- }
- else if (i.first == "timeout")
- {
- timeout = i.second.get_value<size_t>();
- }
- else if (i.first == "retry")
- {
- retry = i.second.get_value<size_t>();
- }
- else if (i.first == "refresh_interval")
- {
- interval = i.second.get_value<size_t>();
- }
- else
- {
- BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" + i.first +
- "\" in \"remote-registrator\" section"));
- }
- }
-
- m_controlParameters
- .setCost(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(REMOTE_HUB_PREFIX)
- .setTimeout(time::milliseconds(timeout));
-
- m_nRetries = retry;
-
- if (interval == 0)
- {
- interval = intervalDef;
- }
-
- interval = std::min(interval, intervalMax);
-
- m_refreshInterval = time::seconds(interval);
-}
-
-void
-RemoteRegistrator::enable()
-{
- // do remote registration after an entry is inserted into the RIB.
- m_afterInsertConnection =
- m_rib.afterInsertEntry.connect([this] (const Name& prefix) {
- registerPrefix(prefix);
- });
-
- // do remote unregistration after an entry is erased from the RIB.
- m_afterEraseConnection =
- m_rib.afterEraseEntry.connect([this] (const Name& prefix) {
- unregisterPrefix(prefix);
- });
-}
-
-void
-RemoteRegistrator::disable()
-{
- m_afterInsertConnection.disconnect();
- m_afterEraseConnection.disconnect();
-}
-
-void
-RemoteRegistrator::registerPrefix(const Name& prefix)
-{
- if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix))
- {
- NFD_LOG_INFO("local registration only for " << prefix);
- return;
- }
-
- bool isHubPrefix = prefix == REMOTE_HUB_PREFIX;
-
- if (isHubPrefix)
- {
- NFD_LOG_INFO("this is a prefix registered by some hub: " << prefix);
-
- m_hasConnectedHub = true;
-
- redoRegistration();
- return;
- }
-
- if (!m_hasConnectedHub)
- {
- NFD_LOG_INFO("no hub connected when registering " << prefix);
- return;
- }
-
- std::pair<Name, size_t> identity = findIdentityForRegistration(prefix);
-
- if (0 == identity.second)
- {
- NFD_LOG_INFO("no proper identity found for registering " << prefix);
- return;
- }
-
- Name prefixForRegistration;
- if (identity.first.size() == identity.second)
- {
- prefixForRegistration = identity.first;
- }
- else
- {
- prefixForRegistration = identity.first.getPrefix(-1);
- }
-
- if (m_regEntries.find(prefixForRegistration) != m_regEntries.end())
- {
- NFD_LOG_INFO("registration already in process for " << prefix);
- return;
- }
-
- // make copies of m_controlParameters and m_commandOptions to
- // avoid unreasonable overwriting during concurrent registration
- // and unregistration.
- ControlParameters parameters = m_controlParameters;
- CommandOptions options = m_commandOptions;
-
- startRegistration(parameters.setName(prefixForRegistration),
- options.setSigningInfo(signingByIdentity(identity.first)),
- m_nRetries);
-}
-
-void
-RemoteRegistrator::unregisterPrefix(const Name& prefix)
-{
- if (prefix == REMOTE_HUB_PREFIX)
- {
- NFD_LOG_INFO("disconnected to hub with prefix: " << prefix);
-
- // for phase 1: suppose there is at most one hub connected.
- // if the hub prefix has been unregistered locally, there may
- // be no connected hub.
- m_hasConnectedHub = false;
-
- clearRefreshEvents();
- return;
- }
-
- if (!m_hasConnectedHub)
- {
- NFD_LOG_INFO("no hub connected when unregistering " << prefix);
- return;
- }
-
- std::pair<Name, size_t> identity = findIdentityForRegistration(prefix);
-
- if (0 == identity.second)
- {
- NFD_LOG_INFO("no proper identity found for unregistering " << prefix);
- return;
- }
-
- Name prefixForRegistration;
- if (identity.first.size() == identity.second)
- {
- prefixForRegistration = identity.first;
- }
- else
- {
- prefixForRegistration = identity.first.getPrefix(-1);
- }
-
- RegisteredEntryIt iRegEntry = m_regEntries.find(prefixForRegistration);
- if (m_regEntries.end() == iRegEntry)
- {
- NFD_LOG_INFO("no existing entry found when unregistering " << prefix);
- return;
- }
-
- for (auto&& entry : m_rib)
- {
- if (prefixForRegistration.isPrefixOf(entry.first) &&
- findIdentityForRegistration(entry.first) == identity)
- {
- NFD_LOG_INFO("this identity should be kept for other rib entry: "
- << entry.first);
- return;
- }
- }
-
- scheduler::cancel(iRegEntry->second);
- m_regEntries.erase(iRegEntry);
-
- // make copies of m_controlParameters and m_commandOptions to
- // avoid unreasonable overwriting during concurrent registration
- // and unregistration.
- ControlParameters parameters = m_controlParameters;
- CommandOptions options = m_commandOptions;
-
- startUnregistration(parameters.setName(prefixForRegistration).unsetCost(),
- options.setSigningInfo(signingByIdentity(identity.first)),
- m_nRetries);
-}
-
-std::pair<Name, size_t>
-RemoteRegistrator::findIdentityForRegistration(const Name& prefix)
-{
- std::pair<Name, size_t> candidateIdentity;
- std::vector<Name> identities;
- bool isPrefix = false;
- size_t maxLength = 0, curLength = 0;
-
- // get all identies from the key-cahin except the default one.
- m_keyChain.getAllIdentities(identities, false);
-
- // get the default identity.
- identities.push_back(m_keyChain.getDefaultIdentity());
-
- // longest prefix matching to all indenties.
- for (auto&& i : identities)
- {
- if (!i.empty() && IGNORE_COMMPONENT == i.at(-1))
- {
- isPrefix = i.getPrefix(-1).isPrefixOf(prefix);
- curLength = i.size() - 1;
- }
- else
- {
- isPrefix = i.isPrefixOf(prefix);
- curLength = i.size();
- }
-
- if (isPrefix && curLength > maxLength)
- {
- candidateIdentity.first = i;
- maxLength = curLength;
- }
- }
-
- candidateIdentity.second = maxLength;
-
- return candidateIdentity;
-}
-
-void
-RemoteRegistrator::startRegistration(const ControlParameters& parameters,
- const CommandOptions& options,
- int nRetries)
-{
- NFD_LOG_INFO("start register " << parameters.getName());
-
- m_nfdController.start<ndn::nfd::RibRegisterCommand>(
- parameters,
- bind(&RemoteRegistrator::onRegSuccess,
- this, parameters, options),
- bind(&RemoteRegistrator::onRegFailure,
- this, _1, _2, parameters, options, nRetries),
- options);
-}
-
-void
-RemoteRegistrator::startUnregistration(const ControlParameters& parameters,
- const CommandOptions& options,
- int nRetries)
-{
- NFD_LOG_INFO("start unregister " << parameters.getName());
-
- m_nfdController.start<ndn::nfd::RibUnregisterCommand>(
- parameters,
- bind(&RemoteRegistrator::onUnregSuccess,
- this, parameters, options),
- bind(&RemoteRegistrator::onUnregFailure,
- this, _1, _2, parameters, options, nRetries),
- options);
-}
-
-void
-RemoteRegistrator::onRegSuccess(const ControlParameters& parameters,
- const CommandOptions& options)
-{
- NFD_LOG_INFO("success to register " << parameters.getName());
-
- RegisteredEntryIt iRegEntry = m_regEntries.find(parameters.getName());
-
- if (m_regEntries.end() != iRegEntry)
- {
- NFD_LOG_DEBUG("Existing Entry: (" << iRegEntry->first
- << ", " << iRegEntry->second
- << ")");
-
- scheduler::cancel(iRegEntry->second);
- iRegEntry->second = scheduler::schedule(
- m_refreshInterval,
- bind(&RemoteRegistrator::startRegistration,
- this, parameters, options, m_nRetries));
- }
- else
- {
- NFD_LOG_DEBUG("New Entry");
- m_regEntries.insert(RegisteredEntry(
- parameters.getName(),
- scheduler::schedule(
- m_refreshInterval,
- bind(&RemoteRegistrator::startRegistration,
- this, parameters, options, m_nRetries))));
- }
-}
-
-void
-RemoteRegistrator::onRegFailure(uint32_t code, const std::string& reason,
- const ControlParameters& parameters,
- const CommandOptions& options,
- int nRetries)
-{
- NFD_LOG_INFO("fail to register " << parameters.getName()
- << "\n\t reason:" << reason
- << "\n\t remain retries:" << nRetries);
-
- if (nRetries > 0)
- {
- startRegistration(parameters, options, nRetries - 1);
- }
-}
-
-void
-RemoteRegistrator::onUnregSuccess(const ControlParameters& parameters,
- const CommandOptions& options)
-{
- NFD_LOG_INFO("success to unregister " << parameters.getName());
-}
-
-void
-RemoteRegistrator::onUnregFailure(uint32_t code, const std::string& reason,
- const ControlParameters& parameters,
- const CommandOptions& options,
- int nRetries)
-{
- NFD_LOG_INFO("fail to unregister " << parameters.getName()
- << "\n\t reason:" << reason
- << "\n\t remain retries:" << nRetries);
-
- if (nRetries > 0)
- {
- startUnregistration(parameters, options, nRetries - 1);
- }
-}
-
-void
-RemoteRegistrator::redoRegistration()
-{
- NFD_LOG_INFO("redo " << m_regEntries.size()
- << " registration when new Hub connection is built.");
-
- for (auto&& entry : m_regEntries)
- {
- // make copies to avoid unreasonable overwrite.
- ControlParameters parameters = m_controlParameters;
- CommandOptions options = m_commandOptions;
- startRegistration(parameters.setName(entry.first),
- options.setSigningInfo(signingByIdentity(entry.first)),
- m_nRetries);
- }
-}
-
-void
-RemoteRegistrator::clearRefreshEvents()
-{
- for (auto&& entry : m_regEntries)
- {
- scheduler::cancel(entry.second);
- }
-}
-
-} // namespace rib
-} // namespace nfd
diff --git a/rib/remote-registrator.hpp b/rib/remote-registrator.hpp
deleted file mode 100644
index 2eea754..0000000
--- a/rib/remote-registrator.hpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015, 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_REMOTE_REGISTRATOR_HPP
-#define NFD_RIB_REMOTE_REGISTRATOR_HPP
-
-#include "rib.hpp"
-#include "core/config-file.hpp"
-#include "rib-status-publisher.hpp"
-
-#include <unordered_map>
-#include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/management/nfd-controller.hpp>
-#include <ndn-cxx/management/nfd-control-command.hpp>
-#include <ndn-cxx/management/nfd-control-parameters.hpp>
-#include <ndn-cxx/management/nfd-command-options.hpp>
-#include <ndn-cxx/util/signal.hpp>
-
-namespace nfd {
-namespace rib {
-
-/**
- * @brief define the RemoteRegistrator class, which handles
- * the registration/unregistration to remote hub(s).
- */
-class RemoteRegistrator : noncopyable
-{
-public:
- class Error : public std::runtime_error
- {
- public:
- explicit
- Error(const std::string& what)
- : std::runtime_error(what)
- {
- }
- };
-
- RemoteRegistrator(ndn::nfd::Controller& controller,
- ndn::KeyChain& keyChain,
- Rib& rib);
-
- ~RemoteRegistrator();
-
- /**
- * @brief load the "remote_register" section from config file
- *
- * @param configSection the sub section in "rib" section.
- */
- void
- loadConfig(const ConfigSection& configSection);
-
- /**
- * @brief enable remote registration/unregistration.
- *
- */
- void
- enable();
-
- /**
- * @brief disable remote registration/unregistration.
- *
- */
- void
- disable();
-
- /**
- * @brief register a prefix to remote hub(s).
- *
- * For the input prefix, we find the longest identity
- * in the key-chain that can sign it, and then
- * register this identity to remote hub(s).
- *
- * @param prefix the prefix being registered in local RIB.
- */
- void
- registerPrefix(const Name& prefix);
-
- /**
- * @brief unregister a prefix from remote hub(s).
- *
- * For the input prefix, if the longest identity can sign it
- * is already registered remotely, that identity should be
- * unregistered from remote hub(s).
- *
- * @param prefix the prefix being unregistered in local RIB.
- */
- void
- unregisterPrefix(const Name& prefix);
-
-private:
- /**
- * @brief find the most proper identity that can sign the
- * registration/unregistration command for the input prefix.
- *
- * @return the identity and the length of the longest match to the
- * input prefix.
- *
- * @retval { ignored, 0 } no matching identity
- */
- std::pair<Name, size_t>
- findIdentityForRegistration(const Name& prefix);
-
- /**
- * @brief make and send the remote registration command.
- *
- * @param nRetries remaining number of retries.
- */
- void
- startRegistration(const ndn::nfd::ControlParameters& parameters,
- const ndn::nfd::CommandOptions& options,
- int nRetries);
-
- /**
- * @brief make and send the remote unregistration command.
- *
- * @param nRetries remaining number of retries.
- */
- void
- startUnregistration(const ndn::nfd::ControlParameters& parameters,
- const ndn::nfd::CommandOptions& options,
- int nRetries);
- /**
- * @brief refresh the remotely registered entry if registration
- * successes by re-sending the registration command.
- *
- * The interval of sending refresh command is defined in the
- * "remote_register" section of the config file.
- *
- * @param parameters the same paremeters from startRegistration.
- * @param options the same options as in startRegistration.
- */
- void
- onRegSuccess(const ndn::nfd::ControlParameters& parameters,
- const ndn::nfd::CommandOptions& options);
-
- /**
- * @brief retry to send registration command if registration fails.
- *
- * the number of retries is defined in the "remote_register"
- * section of the config file.
- *
- * @param code error code.
- * @param reason error reason in string.
- * @param parameters the same paremeters from startRegistration.
- * @param options the same options from startRegistration.
- * @param nRetries remaining number of retries.
- */
- void
- onRegFailure(uint32_t code, const std::string& reason,
- const ndn::nfd::ControlParameters& parameters,
- const ndn::nfd::CommandOptions& options,
- int nRetries);
-
- void
- onUnregSuccess(const ndn::nfd::ControlParameters& parameters,
- const ndn::nfd::CommandOptions& options);
-
- /**
- * @brief retry to send unregistration command if registration fails.
- *
- * the number of retries is defined in the "remote_register"
- * section of the config file.
- *
- * @param code error code.
- * @param reason error reason in string.
- * @param parameters the same paremeters as in startRegistration.
- * @param options the same options as in startRegistration.
- * @param nRetries remaining number of retries.
- */
- void
- onUnregFailure(uint32_t code, const std::string& reason,
- const ndn::nfd::ControlParameters& parameters,
- const ndn::nfd::CommandOptions& options,
- int nRetries);
-
- /**
- * @brief re-register all prefixes
- *
- * This is called when a HUB connection is established.
- */
- void
- redoRegistration();
-
- /**
- * @brief clear all refresh events
- *
- * This is called when all HUB connections are lost.
- */
- void
- clearRefreshEvents();
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
- /**
- * When a locally registered prefix triggles remote
- * registration, we actually register the longest
- * identity that can sign this prefix to remote hub(s).
- *
- * Thus, the remotely reigstered prefix does not equal
- * to Route Name. So it needs seperate sotrage instead
- * of storing within the RIB.
- */
- typedef std::unordered_map<Name, scheduler::EventId> RegisteredList;
- typedef RegisteredList::iterator RegisteredEntryIt;
- typedef RegisteredList::value_type RegisteredEntry;
- RegisteredList m_regEntries;
-
-private:
- ndn::nfd::Controller& m_nfdController;
- ndn::KeyChain& m_keyChain;
- 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;
- bool m_hasConnectedHub;
- int m_nRetries;
-
- static const Name LOCAL_REGISTRATION_PREFIX; // /localhost
- static const Name REMOTE_HUB_PREFIX; // /localhop/nfd
- static const name::Component IGNORE_COMMPONENT; // rib
-};
-
-} // namespace rib
-} // namespace nfd
-
-#endif // NFD_RIB_REMOTE_REGISTRATOR_HPP
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index 91f0eda..33d1622 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -81,7 +81,7 @@
, m_localhopValidator(m_face)
, m_faceMonitor(m_face)
, m_isLocalhopEnabled(false)
- , m_remoteRegistrator(m_nfdController, m_keyChain, m_managedRib)
+ , m_prefixPropagator(m_nfdController, m_keyChain, m_managedRib)
, m_ribStatusPublisher(m_managedRib, face, LIST_COMMAND_PREFIX, m_keyChain)
, m_fibUpdater(m_managedRib, m_nfdController)
, m_signedVerbDispatch(SIGNED_COMMAND_VERBS,
@@ -145,7 +145,7 @@
bool isDryRun,
const std::string& filename)
{
- bool isRemoteRegisterEnabled = false;
+ bool isAutoPrefixPropagatorEnabled = false;
for (const auto& item : configSection) {
if (item.first == "localhost_security") {
@@ -155,24 +155,24 @@
m_localhopValidator.load(item.second, filename);
m_isLocalhopEnabled = true;
}
- else if (item.first == "remote_register") {
- m_remoteRegistrator.loadConfig(item.second);
- isRemoteRegisterEnabled = true;
+ else if (item.first == "auto_prefix_propagate") {
+ m_prefixPropagator.loadConfig(item.second);
+ isAutoPrefixPropagatorEnabled = true;
// Avoid other actions when isDryRun == true
if (isDryRun) {
continue;
}
- m_remoteRegistrator.enable();
+ m_prefixPropagator.enable();
}
else {
BOOST_THROW_EXCEPTION(Error("Unrecognized rib property: " + item.first));
}
}
- if (!isRemoteRegisterEnabled) {
- m_remoteRegistrator.disable();
+ if (!isAutoPrefixPropagatorEnabled) {
+ m_prefixPropagator.disable();
}
}
diff --git a/rib/rib-manager.hpp b/rib/rib-manager.hpp
index e38ee3c..d7c6819 100644
--- a/rib/rib-manager.hpp
+++ b/rib/rib-manager.hpp
@@ -29,7 +29,7 @@
#include "rib.hpp"
#include "core/config-file.hpp"
#include "rib-status-publisher.hpp"
-#include "remote-registrator.hpp"
+#include "auto-prefix-propagator.hpp"
#include "fib-updater.hpp"
#include <ndn-cxx/security/validator-config.hpp>
@@ -207,7 +207,7 @@
ndn::ValidatorConfig m_localhopValidator;
ndn::nfd::FaceMonitor m_faceMonitor;
bool m_isLocalhopEnabled;
- RemoteRegistrator m_remoteRegistrator;
+ AutoPrefixPropagator m_prefixPropagator;
RibStatusPublisher m_ribStatusPublisher;