forwarder.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2021, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "forwarder.hpp"
27 
28 #include "algorithm.hpp"
29 #include "best-route-strategy.hpp"
30 #include "scope-prefix.hpp"
31 #include "strategy.hpp"
32 #include "common/global.hpp"
33 #include "common/logger.hpp"
34 #include "table/cleanup.hpp"
35 
36 #include <ndn-cxx/lp/pit-token.hpp>
37 #include <ndn-cxx/lp/tags.hpp>
38 
39 namespace nfd {
40 
41 NFD_LOG_INIT(Forwarder);
42 
43 const std::string CFG_FORWARDER = "forwarder";
44 
45 static Name
47 {
49 }
50 
52  : m_faceTable(faceTable)
53  , m_unsolicitedDataPolicy(make_unique<fw::DefaultUnsolicitedDataPolicy>())
54  , m_fib(m_nameTree)
55  , m_pit(m_nameTree)
56  , m_measurements(m_nameTree)
57  , m_strategyChoice(*this)
58 {
59  m_faceTable.afterAdd.connect([this] (const Face& face) {
60  face.afterReceiveInterest.connect(
61  [this, &face] (const Interest& interest, const EndpointId& endpointId) {
62  this->onIncomingInterest(interest, FaceEndpoint(const_cast<Face&>(face), endpointId));
63  });
64  face.afterReceiveData.connect(
65  [this, &face] (const Data& data, const EndpointId& endpointId) {
66  this->onIncomingData(data, FaceEndpoint(const_cast<Face&>(face), endpointId));
67  });
68  face.afterReceiveNack.connect(
69  [this, &face] (const lp::Nack& nack, const EndpointId& endpointId) {
70  this->onIncomingNack(nack, FaceEndpoint(const_cast<Face&>(face), endpointId));
71  });
72  face.onDroppedInterest.connect(
73  [this, &face] (const Interest& interest) {
74  this->onDroppedInterest(interest, const_cast<Face&>(face));
75  });
76  });
77 
78  m_faceTable.beforeRemove.connect([this] (const Face& face) {
79  cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
80  });
81 
82  m_fib.afterNewNextHop.connect([this] (const Name& prefix, const fib::NextHop& nextHop) {
83  this->onNewNextHop(prefix, nextHop);
84  });
85 
86  m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
87 }
88 
89 Forwarder::~Forwarder() = default;
90 
91 void
92 Forwarder::onIncomingInterest(const Interest& interest, const FaceEndpoint& ingress)
93 {
94  // receive Interest
95  NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName());
96  interest.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
97  ++m_counters.nInInterests;
98 
99  // drop if HopLimit zero, decrement otherwise (if present)
100  if (interest.getHopLimit()) {
101  if (*interest.getHopLimit() == 0) {
102  NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
103  << " hop-limit=0");
104  ++ingress.face.getCounters().nInHopLimitZero;
105  // drop
106  return;
107  }
108  const_cast<Interest&>(interest).setHopLimit(*interest.getHopLimit() - 1);
109  }
110 
111  // /localhost scope control
112  bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
113  scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
114  if (isViolatingLocalhost) {
115  NFD_LOG_DEBUG("onIncomingInterest in=" << ingress
116  << " interest=" << interest.getName() << " violates /localhost");
117  // drop
118  return;
119  }
120 
121  // detect duplicate Nonce with Dead Nonce List
122  bool hasDuplicateNonceInDnl = m_deadNonceList.has(interest.getName(), interest.getNonce());
123  if (hasDuplicateNonceInDnl) {
124  // goto Interest loop pipeline
125  this->onInterestLoop(interest, ingress);
126  return;
127  }
128 
129  // strip forwarding hint if Interest has reached producer region
130  if (!interest.getForwardingHint().empty() &&
131  m_networkRegionTable.isInProducerRegion(interest.getForwardingHint())) {
132  NFD_LOG_DEBUG("onIncomingInterest in=" << ingress
133  << " interest=" << interest.getName() << " reaching-producer-region");
134  const_cast<Interest&>(interest).setForwardingHint({});
135  }
136 
137  // PIT insert
138  shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
139 
140  // detect duplicate Nonce in PIT entry
141  int dnw = fw::findDuplicateNonce(*pitEntry, interest.getNonce(), ingress.face);
142  bool hasDuplicateNonceInPit = dnw != fw::DUPLICATE_NONCE_NONE;
143  if (ingress.face.getLinkType() == ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
144  // for p2p face: duplicate Nonce from same incoming face is not loop
145  hasDuplicateNonceInPit = hasDuplicateNonceInPit && !(dnw & fw::DUPLICATE_NONCE_IN_SAME);
146  }
147  if (hasDuplicateNonceInPit) {
148  // goto Interest loop pipeline
149  this->onInterestLoop(interest, ingress);
150  return;
151  }
152 
153  // is pending?
154  if (!pitEntry->hasInRecords()) {
155  m_cs.find(interest,
156  [=] (const Interest& i, const Data& d) { onContentStoreHit(i, ingress, pitEntry, d); },
157  [=] (const Interest& i) { onContentStoreMiss(i, ingress, pitEntry); });
158  }
159  else {
160  this->onContentStoreMiss(interest, ingress, pitEntry);
161  }
162 }
163 
164 void
165 Forwarder::onInterestLoop(const Interest& interest, const FaceEndpoint& ingress)
166 {
167  // if multi-access or ad hoc face, drop
168  if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
169  NFD_LOG_DEBUG("onInterestLoop in=" << ingress
170  << " interest=" << interest.getName() << " drop");
171  return;
172  }
173 
174  NFD_LOG_DEBUG("onInterestLoop in=" << ingress << " interest=" << interest.getName()
175  << " send-Nack-duplicate");
176 
177  // send Nack with reason=DUPLICATE
178  // note: Don't enter outgoing Nack pipeline because it needs an in-record.
179  lp::Nack nack(interest);
180  nack.setReason(lp::NackReason::DUPLICATE);
181  ingress.face.sendNack(nack);
182 }
183 
184 void
185 Forwarder::onContentStoreMiss(const Interest& interest, const FaceEndpoint& ingress,
186  const shared_ptr<pit::Entry>& pitEntry)
187 {
188  NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
189  ++m_counters.nCsMisses;
190 
191  // attach HopLimit if configured and not present in Interest
192  if (m_config.defaultHopLimit > 0 && !interest.getHopLimit()) {
193  const_cast<Interest&>(interest).setHopLimit(m_config.defaultHopLimit);
194  }
195 
196  // insert in-record
197  pitEntry->insertOrUpdateInRecord(ingress.face, interest);
198 
199  // set PIT expiry timer to the time that the last PIT in-record expires
200  auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
201  [] (const auto& a, const auto& b) {
202  return a.getExpiry() < b.getExpiry();
203  });
204  auto lastExpiryFromNow = lastExpiring->getExpiry() - time::steady_clock::now();
205  this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
206 
207  // has NextHopFaceId?
208  auto nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
209  if (nextHopTag != nullptr) {
210  // chosen NextHop face exists?
211  Face* nextHopFace = m_faceTable.get(*nextHopTag);
212  if (nextHopFace != nullptr) {
213  NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName()
214  << " nexthop-faceid=" << nextHopFace->getId());
215  // go to outgoing Interest pipeline
216  // scope control is unnecessary, because privileged app explicitly wants to forward
217  this->onOutgoingInterest(interest, *nextHopFace, pitEntry);
218  }
219  return;
220  }
221 
222  // dispatch to strategy: after receive Interest
223  m_strategyChoice.findEffectiveStrategy(*pitEntry)
224  .afterReceiveInterest(interest, FaceEndpoint(ingress.face, 0), pitEntry);
225 }
226 
227 void
228 Forwarder::onContentStoreHit(const Interest& interest, const FaceEndpoint& ingress,
229  const shared_ptr<pit::Entry>& pitEntry, const Data& data)
230 {
231  NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
232  ++m_counters.nCsHits;
233 
234  data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
235  data.setTag(interest.getTag<lp::PitToken>());
236  // FIXME Should we lookup PIT for other Interests that also match the data?
237 
238  pitEntry->isSatisfied = true;
239  pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
240 
241  // set PIT expiry timer to now
242  this->setExpiryTimer(pitEntry, 0_ms);
243 
244  // dispatch to strategy: after Content Store hit
245  m_strategyChoice.findEffectiveStrategy(*pitEntry).afterContentStoreHit(data, ingress, pitEntry);
246 }
247 
248 pit::OutRecord*
249 Forwarder::onOutgoingInterest(const Interest& interest, Face& egress,
250  const shared_ptr<pit::Entry>& pitEntry)
251 {
252  // drop if HopLimit == 0 but sending on non-local face
253  if (interest.getHopLimit() == 0 && egress.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
254  NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << pitEntry->getName()
255  << " non-local hop-limit=0");
256  ++egress.getCounters().nOutHopLimitZero;
257  return nullptr;
258  }
259 
260  NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << pitEntry->getName());
261 
262  // insert out-record
263  auto it = pitEntry->insertOrUpdateOutRecord(egress, interest);
264  BOOST_ASSERT(it != pitEntry->out_end());
265 
266  // send Interest
267  egress.sendInterest(interest);
268  ++m_counters.nOutInterests;
269  return &*it;
270 }
271 
272 void
273 Forwarder::onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry)
274 {
275  NFD_LOG_DEBUG("onInterestFinalize interest=" << pitEntry->getName()
276  << (pitEntry->isSatisfied ? " satisfied" : " unsatisfied"));
277 
278  // Dead Nonce List insert if necessary
279  this->insertDeadNonceList(*pitEntry, nullptr);
280 
281  // Increment satisfied/unsatisfied Interests counter
282  if (pitEntry->isSatisfied) {
283  ++m_counters.nSatisfiedInterests;
284  }
285  else {
286  ++m_counters.nUnsatisfiedInterests;
287  }
288 
289  // PIT delete
290  pitEntry->expiryTimer.cancel();
291  m_pit.erase(pitEntry.get());
292 }
293 
294 void
295 Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
296 {
297  // receive Data
298  NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName());
299  data.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
300  ++m_counters.nInData;
301 
302  // /localhost scope control
303  bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
304  scope_prefix::LOCALHOST.isPrefixOf(data.getName());
305  if (isViolatingLocalhost) {
306  NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName() << " violates /localhost");
307  // drop
308  return;
309  }
310 
311  // PIT match
312  pit::DataMatchResult pitMatches = m_pit.findAllDataMatches(data);
313  if (pitMatches.size() == 0) {
314  // goto Data unsolicited pipeline
315  this->onDataUnsolicited(data, ingress);
316  return;
317  }
318 
319  // CS insert
320  m_cs.insert(data);
321 
322  // when only one PIT entry is matched, trigger strategy: after receive Data
323  if (pitMatches.size() == 1) {
324  auto& pitEntry = pitMatches.front();
325 
326  NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
327 
328  // set PIT expiry timer to now
329  this->setExpiryTimer(pitEntry, 0_ms);
330 
331  // trigger strategy: after receive Data
332  m_strategyChoice.findEffectiveStrategy(*pitEntry).afterReceiveData(data, ingress, pitEntry);
333 
334  // mark PIT satisfied
335  pitEntry->isSatisfied = true;
336  pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
337 
338  // Dead Nonce List insert if necessary (for out-record of ingress face)
339  this->insertDeadNonceList(*pitEntry, &ingress.face);
340 
341  // delete PIT entry's out-record
342  pitEntry->deleteOutRecord(ingress.face);
343  }
344  // when more than one PIT entry is matched, trigger strategy: before satisfy Interest,
345  // and send Data to all matched out faces
346  else {
347  std::set<Face*> pendingDownstreams;
348  auto now = time::steady_clock::now();
349 
350  for (const auto& pitEntry : pitMatches) {
351  NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
352 
353  // remember pending downstreams
354  for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
355  if (inRecord.getExpiry() > now) {
356  pendingDownstreams.insert(&inRecord.getFace());
357  }
358  }
359 
360  // set PIT expiry timer to now
361  this->setExpiryTimer(pitEntry, 0_ms);
362 
363  // invoke PIT satisfy callback
364  m_strategyChoice.findEffectiveStrategy(*pitEntry).beforeSatisfyInterest(data, ingress, pitEntry);
365 
366  // mark PIT satisfied
367  pitEntry->isSatisfied = true;
368  pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
369 
370  // Dead Nonce List insert if necessary (for out-record of ingress face)
371  this->insertDeadNonceList(*pitEntry, &ingress.face);
372 
373  // clear PIT entry's in and out records
374  pitEntry->clearInRecords();
375  pitEntry->deleteOutRecord(ingress.face);
376  }
377 
378  // foreach pending downstream
379  for (const auto& pendingDownstream : pendingDownstreams) {
380  if (pendingDownstream->getId() == ingress.face.getId() &&
381  pendingDownstream->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
382  continue;
383  }
384  // goto outgoing Data pipeline
385  this->onOutgoingData(data, *pendingDownstream);
386  }
387  }
388 }
389 
390 void
391 Forwarder::onDataUnsolicited(const Data& data, const FaceEndpoint& ingress)
392 {
393  // accept to cache?
394  auto decision = m_unsolicitedDataPolicy->decide(ingress.face, data);
395  if (decision == fw::UnsolicitedDataDecision::CACHE) {
396  // CS insert
397  m_cs.insert(data, true);
398  }
399 
400  NFD_LOG_DEBUG("onDataUnsolicited in=" << ingress << " data=" << data.getName()
401  << " decision=" << decision);
402  ++m_counters.nUnsolicitedData;
403 }
404 
405 bool
406 Forwarder::onOutgoingData(const Data& data, Face& egress)
407 {
408  if (egress.getId() == face::INVALID_FACEID) {
409  NFD_LOG_WARN("onOutgoingData out=(invalid) data=" << data.getName());
410  return false;
411  }
412  NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName());
413 
414  // /localhost scope control
415  bool isViolatingLocalhost = egress.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
416  scope_prefix::LOCALHOST.isPrefixOf(data.getName());
417  if (isViolatingLocalhost) {
418  NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName()
419  << " violates /localhost");
420  // drop
421  return false;
422  }
423 
424  // TODO traffic manager
425 
426  // send Data
427  egress.sendData(data);
428  ++m_counters.nOutData;
429 
430  return true;
431 }
432 
433 void
434 Forwarder::onIncomingNack(const lp::Nack& nack, const FaceEndpoint& ingress)
435 {
436  // receive Nack
437  nack.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
438  ++m_counters.nInNacks;
439 
440  // if multi-access or ad hoc face, drop
441  if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
442  NFD_LOG_DEBUG("onIncomingNack in=" << ingress
443  << " nack=" << nack.getInterest().getName() << "~" << nack.getReason()
444  << " link-type=" << ingress.face.getLinkType());
445  return;
446  }
447 
448  // PIT match
449  shared_ptr<pit::Entry> pitEntry = m_pit.find(nack.getInterest());
450  // if no PIT entry found, drop
451  if (pitEntry == nullptr) {
452  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
453  << "~" << nack.getReason() << " no-PIT-entry");
454  return;
455  }
456 
457  // has out-record?
458  auto outRecord = pitEntry->getOutRecord(ingress.face);
459  // if no out-record found, drop
460  if (outRecord == pitEntry->out_end()) {
461  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
462  << "~" << nack.getReason() << " no-out-record");
463  return;
464  }
465 
466  // if out-record has different Nonce, drop
467  if (nack.getInterest().getNonce() != outRecord->getLastNonce()) {
468  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
469  << "~" << nack.getReason() << " wrong-Nonce " << nack.getInterest().getNonce()
470  << "!=" << outRecord->getLastNonce());
471  return;
472  }
473 
474  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
475  << "~" << nack.getReason() << " OK");
476 
477  // record Nack on out-record
478  outRecord->setIncomingNack(nack);
479 
480  // set PIT expiry timer to now when all out-record receive Nack
481  if (!fw::hasPendingOutRecords(*pitEntry)) {
482  this->setExpiryTimer(pitEntry, 0_ms);
483  }
484 
485  // trigger strategy: after receive NACK
486  m_strategyChoice.findEffectiveStrategy(*pitEntry).afterReceiveNack(nack, ingress, pitEntry);
487 }
488 
489 bool
490 Forwarder::onOutgoingNack(const lp::NackHeader& nack, Face& egress,
491  const shared_ptr<pit::Entry>& pitEntry)
492 {
493  if (egress.getId() == face::INVALID_FACEID) {
494  NFD_LOG_WARN("onOutgoingNack out=(invalid)"
495  << " nack=" << pitEntry->getInterest().getName() << "~" << nack.getReason());
496  return false;
497  }
498 
499  // has in-record?
500  auto inRecord = pitEntry->getInRecord(egress);
501 
502  // if no in-record found, drop
503  if (inRecord == pitEntry->in_end()) {
504  NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId()
505  << " nack=" << pitEntry->getInterest().getName()
506  << "~" << nack.getReason() << " no-in-record");
507  return false;
508  }
509 
510  // if multi-access or ad hoc face, drop
511  if (egress.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
512  NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId()
513  << " nack=" << pitEntry->getInterest().getName() << "~" << nack.getReason()
514  << " link-type=" << egress.getLinkType());
515  return false;
516  }
517 
518  NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId()
519  << " nack=" << pitEntry->getInterest().getName()
520  << "~" << nack.getReason() << " OK");
521 
522  // create Nack packet with the Interest from in-record
523  lp::Nack nackPkt(inRecord->getInterest());
524  nackPkt.setHeader(nack);
525 
526  // erase in-record
527  pitEntry->deleteInRecord(egress);
528 
529  // send Nack on face
530  egress.sendNack(nackPkt);
531  ++m_counters.nOutNacks;
532 
533  return true;
534 }
535 
536 void
537 Forwarder::onDroppedInterest(const Interest& interest, Face& egress)
538 {
539  m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(interest, egress);
540 }
541 
542 void
543 Forwarder::onNewNextHop(const Name& prefix, const fib::NextHop& nextHop)
544 {
545  const auto affectedEntries = this->getNameTree().partialEnumerate(prefix,
546  [&] (const name_tree::Entry& nte) -> std::pair<bool, bool> {
547  // we ignore an NTE and skip visiting its descendants if that NTE has an
548  // associated FIB entry (1st condition), since in that case the new nexthop
549  // won't affect any PIT entries anywhere in that subtree, *unless* this is
550  // the initial NTE from which the enumeration started (2nd condition), which
551  // must always be considered
552  if (nte.getFibEntry() != nullptr && nte.getName().size() > prefix.size()) {
553  return {false, false};
554  }
555  return {nte.hasPitEntries(), true};
556  });
557 
558  for (const auto& nte : affectedEntries) {
559  for (const auto& pitEntry : nte.getPitEntries()) {
560  m_strategyChoice.findEffectiveStrategy(*pitEntry).afterNewNextHop(nextHop, pitEntry);
561  }
562  }
563 }
564 
565 void
566 Forwarder::setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
567 {
568  BOOST_ASSERT(pitEntry);
569  duration = std::max(duration, 0_ms);
570 
571  pitEntry->expiryTimer.cancel();
572  pitEntry->expiryTimer = getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
573 }
574 
575 void
576 Forwarder::insertDeadNonceList(pit::Entry& pitEntry, const Face* upstream)
577 {
578  // need Dead Nonce List insert?
579  bool needDnl = true;
580  if (pitEntry.isSatisfied) {
581  BOOST_ASSERT(pitEntry.dataFreshnessPeriod >= 0_ms);
582  needDnl = pitEntry.getInterest().getMustBeFresh() &&
583  pitEntry.dataFreshnessPeriod < m_deadNonceList.getLifetime();
584  }
585 
586  if (!needDnl) {
587  return;
588  }
589 
590  // Dead Nonce List insert
591  if (upstream == nullptr) {
592  // insert all outgoing Nonces
593  const auto& outRecords = pitEntry.getOutRecords();
594  std::for_each(outRecords.begin(), outRecords.end(), [&] (const auto& outRecord) {
595  m_deadNonceList.add(pitEntry.getName(), outRecord.getLastNonce());
596  });
597  }
598  else {
599  // insert outgoing Nonce of a specific face
600  auto outRecord = pitEntry.getOutRecord(*upstream);
601  if (outRecord != pitEntry.getOutRecords().end()) {
602  m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
603  }
604  }
605 }
606 
607 void
609 {
610  configFile.addSectionHandler(CFG_FORWARDER, [this] (auto&&... args) {
611  processConfig(std::forward<decltype(args)>(args)...);
612  });
613 }
614 
615 void
616 Forwarder::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string&)
617 {
618  Config config;
619 
620  for (const auto& pair : configSection) {
621  const std::string& key = pair.first;
622  if (key == "default_hop_limit") {
623  config.defaultHopLimit = ConfigFile::parseNumber<uint8_t>(pair, CFG_FORWARDER);
624  }
625  else {
626  NDN_THROW(ConfigFile::Error("Unrecognized option " + CFG_FORWARDER + "." + key));
627  }
628  }
629 
630  if (!isDryRun) {
631  m_config = config;
632  }
633 }
634 
635 } // namespace nfd
configuration file parsing utility
Definition: config-file.hpp:58
void addSectionHandler(const std::string &sectionName, ConfigSectionHandler subscriber)
setup notification of configuration file sections
Definition: config-file.cpp:77
bool has(const Name &name, Interest::Nonce nonce) const
Determines if name+nonce is in the list.
Represents a face-endpoint pair in the forwarder.
container of all faces
Definition: face-table.hpp:39
Face * get(FaceId id) const
get face by FaceId
Definition: face-table.cpp:45
signal::Signal< FaceTable, Face > beforeRemove
Fires immediately before a face is removed.
Definition: face-table.hpp:91
signal::Signal< FaceTable, Face > afterAdd
Fires immediately after a face is added.
Definition: face-table.hpp:85
PacketCounter nUnsatisfiedInterests
Forwarder(FaceTable &faceTable)
Definition: forwarder.cpp:51
NameTree & getNameTree()
Definition: forwarder.hpp:82
bool isInProducerRegion(span< const Name > forwardingHint) const
determines whether an Interest has reached a producer region
void insert(const Data &data, bool isUnsolicited=false)
inserts a Data packet
Definition: cs.cpp:51
void find(const Interest &interest, HitCallback &&hit, MissCallback &&miss) const
finds the best matching Data packet
Definition: cs.hpp:81
PacketCounter nInHopLimitZero
count of incoming Interests dropped due to HopLimit == 0
generalization of a network interface
Definition: face.hpp:55
ndn::nfd::FaceScope getScope() const
Definition: face.hpp:272
signal::Signal< LinkService, Data, EndpointId > & afterReceiveData
signals on Data received
Definition: face.hpp:99
signal::Signal< LinkService, Interest > & onDroppedInterest
signals on Interest dropped by reliability system for exceeding allowed number of retx
Definition: face.hpp:107
signal::Signal< LinkService, lp::Nack, EndpointId > & afterReceiveNack
signals on Nack received
Definition: face.hpp:103
signal::Signal< LinkService, Interest, EndpointId > & afterReceiveInterest
signals on Interest received
Definition: face.hpp:95
FaceId getId() const
Definition: face.hpp:248
const FaceCounters & getCounters() const
Definition: face.hpp:174
ndn::nfd::LinkType getLinkType() const
Definition: face.hpp:290
signal::Signal< Fib, Name, NextHop > afterNewNextHop
signals on Fib entry nexthop creation
Definition: fib.hpp:151
Represents a nexthop record in a FIB entry.
Definition: fib-nexthop.hpp:38
static const Name & getStrategyName()
virtual void onDroppedInterest(const Interest &interest, Face &egress)
Trigger after an Interest is dropped (e.g., for exceeding allowed retransmissions).
Definition: strategy.cpp:190
virtual void afterContentStoreHit(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
Trigger after a matching Data is found in the Content Store.
Definition: strategy.cpp:154
virtual void afterReceiveNack(const lp::Nack &nack, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
Trigger after a Nack is received.
Definition: strategy.cpp:183
virtual void afterReceiveInterest(const Interest &interest, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)=0
Trigger after an Interest is received.
virtual void afterReceiveData(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
Trigger after Data is received.
Definition: strategy.cpp:172
virtual void beforeSatisfyInterest(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
Trigger before a PIT entry is satisfied.
Definition: strategy.cpp:164
Range partialEnumerate(const Name &prefix, const EntrySubTreeSelector &entrySubTreeSelector=AnyEntrySubTree()) const
Enumerate all entries under a prefix.
Definition: name-tree.cpp:232
std::pair< shared_ptr< Entry >, bool > insert(const Interest &interest)
Inserts a PIT entry for interest.
Definition: pit.hpp:77
shared_ptr< Entry > find(const Interest &interest) const
Finds a PIT entry for interest.
Definition: pit.hpp:66
DataMatchResult findAllDataMatches(const Data &data) const
Performs a Data match.
Definition: pit.cpp:86
void erase(Entry *entry)
Deletes an entry.
Definition: pit.hpp:91
void setDefaultStrategy(const Name &strategyName)
Set the default strategy.
fw::Strategy & findEffectiveStrategy(const Name &prefix) const
Get effective strategy for prefix.
This file contains common algorithms used by forwarding strategies.
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31
#define NFD_LOG_WARN
Definition: logger.hpp:40
#define NFD_LOG_DEBUG
Definition: logger.hpp:38
uint64_t EndpointId
Identifies a remote endpoint on the link.
Definition: face-common.hpp:71
const FaceId INVALID_FACEID
indicates an invalid FaceId
Definition: face-common.hpp:47
const FaceId FACEID_CONTENT_STORE
identifies a packet comes from the ContentStore
Definition: face-common.hpp:51
DropAllUnsolicitedDataPolicy DefaultUnsolicitedDataPolicy
The default UnsolicitedDataPolicy.
@ CACHE
the Data should be cached in the ContentStore
@ DUPLICATE_NONCE_NONE
no duplicate Nonce is found
Definition: algorithm.hpp:48
@ DUPLICATE_NONCE_IN_SAME
in-record of same face
Definition: algorithm.hpp:49
int findDuplicateNonce(const pit::Entry &pitEntry, Interest::Nonce nonce, const Face &face)
determine whether pitEntry has duplicate Nonce nonce
Definition: algorithm.cpp:55
bool hasPendingOutRecords(const pit::Entry &pitEntry)
determine whether pitEntry has any pending out-records
Definition: algorithm.cpp:85
void setConfigFile(ConfigFile &config)
std::vector< shared_ptr< Entry > > DataMatchResult
Definition: pit.hpp:43
const Name LOCALHOST
ndn:/localhost
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents,...
Definition: algorithm.hpp:32
const std::string CFG_FORWARDER
Definition: forwarder.cpp:43
boost::property_tree::ptree ConfigSection
a config file section
Definition: config-file.hpp:37
void cleanupOnFaceRemoval(NameTree &nt, Fib &fib, Pit &pit, const Face &face)
cleanup tables when a face is destroyed
Definition: cleanup.cpp:31
static Name getDefaultStrategyName()
Definition: forwarder.cpp:46
Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
Definition: global.cpp:45