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