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