NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
auto-prefix-propagator.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
27 #include "core/logger.hpp"
28 #include "core/scheduler.hpp"
29 #include <ndn-cxx/security/pib/identity.hpp>
30 #include <ndn-cxx/security/pib/identity-container.hpp>
31 #include <ndn-cxx/security/pib/pib.hpp>
32 #include <ndn-cxx/security/signing-helpers.hpp>
33 #include <vector>
34 
35 namespace nfd {
36 namespace rib {
37 
38 NFD_LOG_INIT("AutoPrefixPropagator");
39 
42 
43 const Name LOCAL_REGISTRATION_PREFIX("/localhost");
44 const Name LINK_LOCAL_NFD_PREFIX("/localhop/nfd");
46 const time::seconds PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL = time::seconds(25);
47 const time::seconds PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL = time::seconds(600);
48 const time::seconds PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT = time::seconds(50);
49 const time::seconds PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT = time::seconds(3600);
50 const uint64_t PREFIX_PROPAGATION_DEFAULT_COST = 15;
52 
54  ndn::KeyChain& keyChain,
55  Rib& rib)
56  : m_nfdController(controller)
57  , m_keyChain(keyChain)
58  , m_rib(rib)
59  , m_refreshInterval(PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL)
60  , m_baseRetryWait(PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT)
61  , m_maxRetryWait(PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT)
62  , m_hasConnectedHub(false)
63 {
64 }
65 
66 void
68 {
72 
73  m_controlParameters
74  .setCost(PREFIX_PROPAGATION_DEFAULT_COST)
75  .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client.
76  .setFaceId(0);// the remote hub will take the input face as the faceId.
77 
78  m_commandOptions
80  .setTimeout(PREFIX_PROPAGATION_DEFAULT_TIMEOUT);
81 
82  NFD_LOG_INFO("Load auto_prefix_propagate section in rib section");
83 
84  for (auto&& i : configSection) {
85  if (i.first == "cost") {
86  m_controlParameters.setCost(i.second.get_value<uint64_t>());
87  }
88  else if (i.first == "timeout") {
89  m_commandOptions.setTimeout(time::milliseconds(i.second.get_value<size_t>()));
90  }
91  else if (i.first == "refresh_interval") {
92  m_refreshInterval = std::min(PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL,
93  time::seconds(i.second.get_value<size_t>()));
94  }
95  else if (i.first == "base_retry_wait") {
96  m_baseRetryWait = time::seconds(i.second.get_value<size_t>());
97  }
98  else if (i.first == "max_retry_wait") {
99  m_maxRetryWait = time::seconds(i.second.get_value<size_t>());
100  }
101  else {
102  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" + i.first +
103  "\" in \"auto_prefix_propagate\" section"));
104  }
105  }
106 }
107 
108 void
110 {
111  m_afterInsertConnection =
112  m_rib.afterInsertEntry.connect(bind(&AutoPrefixPropagator::afterInsertRibEntry, this, _1));
113  m_afterEraseConnection =
114  m_rib.afterEraseEntry.connect(bind(&AutoPrefixPropagator::afterEraseRibEntry, this, _1));
115 }
116 
117 void
119 {
120  m_afterInsertConnection.disconnect();
121  m_afterEraseConnection.disconnect();
122 }
123 
124 AutoPrefixPropagator::PrefixPropagationParameters
125 AutoPrefixPropagator::getPrefixPropagationParameters(const Name& localRibPrefix)
126 {
127  // shortest prefix matching to all identies.
128  Name propagatedPrefix;
129  ndn::security::pib::Identity signingIdentity;
130  bool isFound = false;
131  for (auto&& identity : m_keyChain.getPib().getIdentities()) {
132  Name idName = identity.getName();
133  Name prefix = !idName.empty() && IGNORE_COMMPONENT == idName.at(-1) ?
134  idName.getPrefix(-1) : idName;
135  if (prefix.isPrefixOf(localRibPrefix) && (!isFound || prefix.size() < propagatedPrefix.size())) {
136  isFound = true;
137  propagatedPrefix = prefix;
138  signingIdentity = identity;
139  }
140  }
141 
142  PrefixPropagationParameters propagateParameters;
143  if (!isFound) {
144  propagateParameters.isValid = false;
145  }
146  else {
147  propagateParameters.isValid = true;
148  propagateParameters.parameters = m_controlParameters;
149  propagateParameters.options = m_commandOptions;
150  propagateParameters.parameters.setName(propagatedPrefix);
151  propagateParameters.options.setSigningInfo(ndn::security::signingByIdentity(signingIdentity));
152  }
153 
154  return propagateParameters;
155 }
156 
157 void
158 AutoPrefixPropagator::afterInsertRibEntry(const Name& prefix)
159 {
161  NFD_LOG_INFO("local registration only for " << prefix);
162  return;
163  }
164 
165  if (prefix == LINK_LOCAL_NFD_PREFIX) {
166  NFD_LOG_INFO("this is a prefix registered by some hub: " << prefix);
167 
168  m_hasConnectedHub = true;
169  return afterHubConnect();
170  }
171 
172  auto propagateParameters = getPrefixPropagationParameters(prefix);
173  if (!propagateParameters.isValid) {
174  NFD_LOG_INFO("no signing identity available for: " << prefix);
175  return;
176  }
177 
178  auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
179  if (entryIt != m_propagatedEntries.end()) {
180  // in addition to PROPAGATED and PROPAGATE_FAIL, the state may also be NEW,
181  // if there is no hub connected to propagate this prefix.
182  if (entryIt->second.isNew()) {
183  NFD_LOG_INFO("no hub connected to propagate "
184  << propagateParameters.parameters.getName());
185  }
186  else {
187  NFD_LOG_INFO("prefix has already been propagated: "
188  << propagateParameters.parameters.getName());
189  }
190  return;
191  }
192 
193  afterRibInsert(propagateParameters.parameters, propagateParameters.options);
194 }
195 
196 void
197 AutoPrefixPropagator::afterEraseRibEntry(const Name& prefix)
198 {
200  NFD_LOG_INFO("local unregistration only for " << prefix);
201  return;
202  }
203 
204  if (prefix == LINK_LOCAL_NFD_PREFIX) {
205  NFD_LOG_INFO("disconnected to hub with prefix: " << prefix);
206 
207  m_hasConnectedHub = false;
208  return afterHubDisconnect();
209  }
210 
211  auto propagateParameters = getPrefixPropagationParameters(prefix);
212  if (!propagateParameters.isValid) {
213  NFD_LOG_INFO("no signing identity available for: " << prefix);
214  return;
215  }
216 
217  auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
218  if (entryIt == m_propagatedEntries.end()) {
219  NFD_LOG_INFO("prefix has not been propagated yet: "
220  << propagateParameters.parameters.getName());
221  return;
222  }
223 
224  for (auto&& ribTableEntry : m_rib) {
225  if (propagateParameters.parameters.getName().isPrefixOf(ribTableEntry.first) &&
226  propagateParameters.options.getSigningInfo().getSignerName() ==
227  getPrefixPropagationParameters(ribTableEntry.first)
228  .options.getSigningInfo().getSignerName()) {
229  NFD_LOG_INFO("should be kept for another RIB entry: " << ribTableEntry.first);
230  return;
231  }
232  }
233 
234  afterRibErase(propagateParameters.parameters.unsetCost(), propagateParameters.options);
235 }
236 
237 bool
238 AutoPrefixPropagator::doesCurrentPropagatedPrefixWork(const Name& prefix)
239 {
240  auto propagateParameters = getPrefixPropagationParameters(prefix);
241  if (!propagateParameters.isValid) {
242  // no identity can sign the input prefix
243  return false;
244  }
245 
246  // there is at least one identity can sign the input prefix, so the prefix selected for
247  // propagation (i.e., propagateParameters.parameters.getName()) must be a prefix of the input
248  // prefix. Namely it's either equal to the input prefix or a better choice.
249  return propagateParameters.parameters.getName().size() == prefix.size();
250 }
251 
252 void
253 AutoPrefixPropagator::redoPropagation(PropagatedEntryIt entryIt,
254  const ControlParameters& parameters,
255  const CommandOptions& options,
256  time::seconds retryWaitTime)
257 {
258  if (doesCurrentPropagatedPrefixWork(parameters.getName())) {
259  // PROPAGATED / PROPAGATE_FAIL --> PROPAGATING
260  entryIt->second.startPropagation();
261  return advertise(parameters, options, retryWaitTime);
262  }
263 
264  NFD_LOG_INFO("current propagated prefix does not work any more");
265  m_propagatedEntries.erase(entryIt);
266 
267  // re-handle all locally RIB entries that can be covered by this propagated prefix
268  for (auto&& ribTableEntry : m_rib) {
269  if (parameters.getName().isPrefixOf(ribTableEntry.first)) {
270  afterInsertRibEntry(ribTableEntry.first);
271  }
272  }
273 }
274 
275 void
276 AutoPrefixPropagator::advertise(const ControlParameters& parameters,
277  const CommandOptions& options,
278  time::seconds retryWaitTime)
279 {
280  NFD_LOG_INFO("advertise " << parameters.getName());
281 
282  scheduler::EventCallback refreshEvent =
283  bind(&AutoPrefixPropagator::onRefreshTimer, this, parameters, options);
284  scheduler::EventCallback retryEvent =
285  bind(&AutoPrefixPropagator::onRetryTimer, this, parameters, options,
286  std::min(m_maxRetryWait, retryWaitTime * 2));
287 
288  m_nfdController.start<ndn::nfd::RibRegisterCommand>(
289  parameters,
290  bind(&AutoPrefixPropagator::afterPropagateSucceed, this, parameters, options, refreshEvent),
291  bind(&AutoPrefixPropagator::afterPropagateFail,
292  this, _1, parameters, options, retryWaitTime, retryEvent),
293  options);
294 }
295 
296 void
297 AutoPrefixPropagator::withdraw(const ControlParameters& parameters,
298  const CommandOptions& options,
299  time::seconds retryWaitTime)
300 {
301  NFD_LOG_INFO("withdraw " << parameters.getName());
302 
303  m_nfdController.start<ndn::nfd::RibUnregisterCommand>(
304  parameters,
305  bind(&AutoPrefixPropagator::afterRevokeSucceed, this, parameters, options, retryWaitTime),
306  bind(&AutoPrefixPropagator::afterRevokeFail, this, _1, parameters, options),
307  options);
308 }
309 
310 void
311 AutoPrefixPropagator::afterRibInsert(const ControlParameters& parameters,
312  const CommandOptions& options)
313 {
314  BOOST_ASSERT(m_propagatedEntries.find(parameters.getName()) == m_propagatedEntries.end());
315 
316  // keep valid entries although there is no connectivity to hub
317  auto& entry = m_propagatedEntries[parameters.getName()]
318  .setSigningIdentity(options.getSigningInfo().getSignerName());
319 
320  if (!m_hasConnectedHub) {
321  NFD_LOG_INFO("no hub connected to propagate " << parameters.getName());
322  return;
323  }
324 
325  // NEW --> PROPAGATING
326  entry.startPropagation();
327  advertise(parameters, options, m_baseRetryWait);
328 }
329 
330 void
331 AutoPrefixPropagator::afterRibErase(const ControlParameters& parameters,
332  const CommandOptions& options)
333 {
334  auto entryIt = m_propagatedEntries.find(parameters.getName());
335  BOOST_ASSERT(entryIt != m_propagatedEntries.end());
336 
337  bool hasPropagationSucceeded = entryIt->second.isPropagated();
338 
339  // --> "RELEASED"
340  m_propagatedEntries.erase(entryIt);
341 
342  if (!m_hasConnectedHub) {
343  NFD_LOG_INFO("no hub connected to revoke propagation of " << parameters.getName());
344  return;
345  }
346 
347  if (!hasPropagationSucceeded) {
348  NFD_LOG_INFO("propagation has not succeeded: " << parameters.getName());
349  return;
350  }
351 
352  withdraw(parameters, options, m_baseRetryWait);
353 }
354 
355 void
356 AutoPrefixPropagator::afterHubConnect()
357 {
358  NFD_LOG_INFO("redo " << m_propagatedEntries.size()
359  << " propagations when new Hub connectivity is built.");
360 
361  std::vector<PropagatedEntryIt> regEntryIterators;
362  for (auto it = m_propagatedEntries.begin() ; it != m_propagatedEntries.end() ; it ++) {
363  BOOST_ASSERT(it->second.isNew());
364  regEntryIterators.push_back(it);
365  }
366 
367  for (auto&& it : regEntryIterators) {
368  auto parameters = m_controlParameters;
369  auto options = m_commandOptions;
370 
371  redoPropagation(it,
372  parameters.setName(it->first),
373  options.setSigningInfo(signingByIdentity(it->second.getSigningIdentity())),
374  m_baseRetryWait);
375  }
376 }
377 
378 void
379 AutoPrefixPropagator::afterHubDisconnect()
380 {
381  for (auto&& entry : m_propagatedEntries) {
382  // --> NEW
383  BOOST_ASSERT(!entry.second.isNew());
384  entry.second.initialize();
385  }
386 }
387 
388 void
389 AutoPrefixPropagator::afterPropagateSucceed(const ControlParameters& parameters,
390  const CommandOptions& options,
391  const scheduler::EventCallback& refreshEvent)
392 {
393  NFD_LOG_TRACE("success to propagate " << parameters.getName());
394 
395  auto entryIt = m_propagatedEntries.find(parameters.getName());
396  if (entryIt == m_propagatedEntries.end()) {
397  // propagation should be revoked if this entry has been erased (i.e., be in RELEASED state)
398  NFD_LOG_DEBUG("Already erased!");
399  ControlParameters newParameters = parameters;
400  return withdraw(newParameters.unsetCost(), options, m_baseRetryWait);
401  }
402 
403  // PROPAGATING --> PROPAGATED
404  BOOST_ASSERT(entryIt->second.isPropagating());
405  entryIt->second.succeed(scheduler::schedule(m_refreshInterval, refreshEvent));
406 }
407 
408 void
409 AutoPrefixPropagator::afterPropagateFail(const ndn::nfd::ControlResponse& response,
410  const ControlParameters& parameters,
411  const CommandOptions& options,
412  time::seconds retryWaitTime,
413  const scheduler::EventCallback& retryEvent)
414 {
415  NFD_LOG_TRACE("fail to propagate " << parameters.getName()
416  << "\n\t reason:" << response.getText()
417  << "\n\t retry wait time: " << retryWaitTime);
418 
419  auto entryIt = m_propagatedEntries.find(parameters.getName());
420  if (entryIt == m_propagatedEntries.end()) {
421  // current state is RELEASED
422  return;
423  }
424 
425  // PROPAGATING --> PROPAGATE_FAIL
426  BOOST_ASSERT(entryIt->second.isPropagating());
427  entryIt->second.fail(scheduler::schedule(retryWaitTime, retryEvent));
428 }
429 
430 void
431 AutoPrefixPropagator::afterRevokeSucceed(const ControlParameters& parameters,
432  const CommandOptions& options,
433  time::seconds retryWaitTime)
434 {
435  NFD_LOG_TRACE("success to revoke propagation of " << parameters.getName());
436 
437  auto entryIt = m_propagatedEntries.find(parameters.getName());
438  if (m_propagatedEntries.end() != entryIt && !entryIt->second.isPropagateFail()) {
439  // if is not RELEASED or PROPAGATE_FAIL
440  NFD_LOG_DEBUG("propagated entry still exists");
441 
442  // PROPAGATING / PROPAGATED --> PROPAGATING
443  BOOST_ASSERT(!entryIt->second.isNew());
444  entryIt->second.startPropagation();
445 
446  ControlParameters newParameters = parameters;
447  advertise(newParameters.setCost(m_controlParameters.getCost()), options, retryWaitTime);
448  }
449 }
450 
451 void
452 AutoPrefixPropagator::afterRevokeFail(const ndn::nfd::ControlResponse& response,
453  const ControlParameters& parameters,
454  const CommandOptions& options)
455 {
456  NFD_LOG_INFO("fail to revoke the propagation of " << parameters.getName()
457  << "\n\t reason:" << response.getText());
458 }
459 
460 void
461 AutoPrefixPropagator::onRefreshTimer(const ControlParameters& parameters,
462  const CommandOptions& options)
463 {
464  auto entryIt = m_propagatedEntries.find(parameters.getName());
465  BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagated());
466  redoPropagation(entryIt, parameters, options, m_baseRetryWait);
467 }
468 
469 void
470 AutoPrefixPropagator::onRetryTimer(const ControlParameters& parameters,
471  const CommandOptions& options,
472  time::seconds retryWaitTime)
473 {
474  auto entryIt = m_propagatedEntries.find(parameters.getName());
475  BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagateFail());
476  redoPropagation(entryIt, parameters, options, retryWaitTime);
477 }
478 
479 } // namespace rib
480 } // namespace nfd
const Name LINK_LOCAL_NFD_PREFIX("/localhop/nfd")
function< void()> EventCallback
Definition: scheduler.hpp:43
void start(const ControlParameters &parameters, const CommandSucceedCallback &onSuccess, const CommandFailCallback &onFailure, const CommandOptions &options=CommandOptions())
start command execution
Definition: controller.hpp:74
ControlParameters & setFaceId(uint64_t faceId)
represents the Routing Information Base
Definition: rib.hpp:59
const Name LOCAL_REGISTRATION_PREFIX("/localhost")
const time::seconds PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL
represents parameters in a ControlCommand request or response
const Name & getSignerName() const
boost::posix_time::time_duration milliseconds(long duration)
Definition: asio.hpp:117
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:55
ControlParameters & unsetCost()
const name::Component IGNORE_COMMPONENT("nrd")
void disable()
disable automatic prefix propagation
#define NFD_LOG_INFO(expression)
Definition: logger.hpp:56
const std::string & getText() const
const time::milliseconds PREFIX_PROPAGATION_DEFAULT_TIMEOUT
CommandOptions & setTimeout(const time::milliseconds &timeout)
sets command timeout
const time::seconds PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54
contains options for ControlCommand execution
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
const uint64_t PREFIX_PROPAGATION_DEFAULT_COST
const time::seconds PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL
void loadConfig(const ConfigSection &configSection)
load the "auto_prefix_propagate" section from config file
NFD Management protocol client.
Definition: controller.hpp:50
size_t size() const
Get number of components.
Definition: name.hpp:154
boost::property_tree::ptree ConfigSection
a config file section
Represents an absolute name.
Definition: name.hpp:42
bool isPrefixOf(const Name &other) const
Check if this name is a prefix of another name.
Definition: name.cpp:260
represents a rib/unregister command
const Component & at(ssize_t i) const
Get the component at the given index.
Definition: name.cpp:185
CommandOptions & setSigningInfo(const security::SigningInfo &signingInfo)
sets signing parameters
represents a rib/register command
ndn::util::signal::Signal< Rib, Name > afterInsertEntry
signals after a RIB entry is inserted
Definition: rib.hpp:225
void enable()
enable automatic prefix propagation
ControlParameters & setCost(uint64_t cost)
void disconnect()
disconnects the connection manually
SigningInfo signingByIdentity(const Name &identityName)
Component holds a read-only name component value.
ndn::util::signal::Signal< Rib, Name > afterEraseEntry
signals after a RIB entry is erased
Definition: rib.hpp:233
EventId schedule(time::nanoseconds after, const EventCallback &event)
schedule an event
Definition: scheduler.cpp:47
ControlParameters & setName(const Name &name)
ControlParameters & setOrigin(RouteOrigin origin)
bool empty() const
Check if name is empty.
Definition: name.hpp:146
AutoPrefixPropagator(ndn::nfd::Controller &controller, ndn::KeyChain &keyChain, Rib &rib)
A frontend handle of an Identity.
Definition: identity.hpp:42
PartialName getPrefix(ssize_t nComponents) const
Extract a prefix of the name.
Definition: name.hpp:210
ControlCommand response.
const time::seconds PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
ndn security v2 KeyChain
Definition: key-chain.cpp:76
CommandOptions & setPrefix(const Name &prefix)
sets command prefix
const security::SigningInfo & getSigningInfo() const