d7c9636078
Change-Id: I8418de6d5bb9615af898df5dbf9ed4cc2cb6a43a Refs: #3211, #2413
473 lines
17 KiB
C++
473 lines
17 KiB
C++
/* -*- 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
|