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