NFD: Named Data Networking Forwarding Daemon 24.07-28-gdcc0e6e0
Loading...
Searching...
No Matches
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-2025, 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"
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
39namespace nfd {
40
41NFD_LOG_INIT(Forwarder);
42
43const std::string CFG_FORWARDER = "forwarder";
44
45static Name
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
87}
88
89void
90Forwarder::onIncomingInterest(const Interest& interest, const FaceEndpoint& ingress)
91{
92 interest.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
93 ++m_counters.nInInterests;
94
95 // ensure the received Interest has a Nonce
96 auto nonce = interest.getNonce();
97 auto hopLimit = interest.getHopLimit();
98
99 NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
100 << " nonce=" << nonce << " hop-limit="
101 << (hopLimit.has_value() ? std::to_string(static_cast<unsigned>(*hopLimit)) : "(null)")
102 << (hopLimit == 0 ? " -> DROP" : ""));
103
104 if (hopLimit.has_value()) {
105 // drop if HopLimit zero, decrement otherwise
106 if (*hopLimit == 0) {
107 ++ingress.face.getCounters().nInHopLimitZero;
108 return;
109 }
110 const_cast<Interest&>(interest).setHopLimit(*hopLimit - 1);
111 }
112
113 // /localhost scope control
114 bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
115 scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
116 if (isViolatingLocalhost) {
117 NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
118 << " nonce=" << nonce << " violates /localhost -> DROP");
119 return;
120 }
121
122 // detect duplicate Nonce with Dead Nonce List
123 bool hasDuplicateNonceInDnl = m_deadNonceList.has(interest.getName(), nonce);
124 if (hasDuplicateNonceInDnl) {
125 // go to Interest loop pipeline
126 this->onInterestLoop(interest, ingress);
127 return;
128 }
129
130 // strip forwarding hint if Interest has reached producer region
131 if (!interest.getForwardingHint().empty() &&
132 m_networkRegionTable.isInProducerRegion(interest.getForwardingHint())) {
133 NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
134 << " nonce=" << nonce << " reaching-producer-region");
135 const_cast<Interest&>(interest).setForwardingHint({});
136 }
137
138 // PIT insert
139 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
140
141 // detect duplicate Nonce in PIT entry
142 int dnw = fw::findDuplicateNonce(*pitEntry, nonce, ingress.face);
143 bool hasDuplicateNonceInPit = dnw != fw::DUPLICATE_NONCE_NONE;
144 if (ingress.face.getLinkType() == ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
145 // for p2p face: duplicate Nonce from same incoming face is not loop
146 hasDuplicateNonceInPit = hasDuplicateNonceInPit && !(dnw & fw::DUPLICATE_NONCE_IN_SAME);
147 }
148 if (hasDuplicateNonceInPit) {
149 // go to Interest loop pipeline
150 this->onInterestLoop(interest, ingress);
151 return;
152 }
153
154 // is pending?
155 if (!pitEntry->hasInRecords()) {
156 m_cs.find(interest,
157 [=] (const Interest& i, const Data& d) { onContentStoreHit(i, ingress, pitEntry, d); },
158 [=] (const Interest& i) { onContentStoreMiss(i, ingress, pitEntry); });
159 }
160 else {
161 this->onContentStoreMiss(interest, ingress, pitEntry);
162 }
163}
164
165void
166Forwarder::onInterestLoop(const Interest& interest, const FaceEndpoint& ingress)
167{
168 // if multi-access or ad hoc face, drop
169 if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
170 NFD_LOG_DEBUG("onInterestLoop in=" << ingress << " interest=" << interest.getName()
171 << " nonce=" << interest.getNonce() << " -> DROP");
172 return;
173 }
174
175 NFD_LOG_DEBUG("onInterestLoop in=" << ingress << " interest=" << interest.getName()
176 << " nonce=" << interest.getNonce());
177
178 // leave loop handling up to the strategy (e.g., whether to reply with a Nack)
179 m_strategyChoice.findEffectiveStrategy(interest.getName()).onInterestLoop(interest, ingress);
180}
181
182void
183Forwarder::onContentStoreMiss(const Interest& interest, const FaceEndpoint& ingress,
184 const shared_ptr<pit::Entry>& pitEntry)
185{
186 ++m_counters.nCsMisses;
187 NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName() << " nonce=" << interest.getNonce());
188
189 // attach HopLimit if configured and not present in Interest
190 if (m_config.defaultHopLimit > 0 && !interest.getHopLimit().has_value()) {
191 const_cast<Interest&>(interest).setHopLimit(m_config.defaultHopLimit);
192 }
193
194 // insert in-record
195 pitEntry->insertOrUpdateInRecord(ingress.face, interest);
196
197 // set PIT expiry timer to the time that the last PIT in-record expires
198 auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
199 [] (const auto& a, const auto& b) {
200 return a.getExpiry() < b.getExpiry();
201 });
202 auto lastExpiryFromNow = lastExpiring->getExpiry() - time::steady_clock::now();
203 this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
204
205 // has NextHopFaceId?
206 auto nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
207 if (nextHopTag != nullptr) {
208 // chosen NextHop face exists?
209 Face* nextHopFace = m_faceTable.get(*nextHopTag);
210 if (nextHopFace != nullptr) {
211 NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName()
212 << " nonce=" << interest.getNonce() << " nexthop-faceid=" << nextHopFace->getId());
213 // go to outgoing Interest pipeline
214 // scope control is unnecessary, because privileged app explicitly wants to forward
215 this->onOutgoingInterest(interest, *nextHopFace, pitEntry);
216 }
217 return;
218 }
219
220 // dispatch to strategy: after receive Interest
221 m_strategyChoice.findEffectiveStrategy(*pitEntry)
222 .afterReceiveInterest(interest, FaceEndpoint(ingress.face), pitEntry);
223}
224
225void
226Forwarder::onContentStoreHit(const Interest& interest, const FaceEndpoint& ingress,
227 const shared_ptr<pit::Entry>& pitEntry, const Data& data)
228{
229 ++m_counters.nCsHits;
230 NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName() << " nonce=" << interest.getNonce()
231 << " data=" << data.getName());
232
233 data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
234 data.setTag(interest.getTag<lp::PitToken>());
235 // FIXME Should we lookup PIT for other Interests that also match the data?
236
237 pitEntry->isSatisfied = true;
238 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
239
240 // set PIT expiry timer to now
241 this->setExpiryTimer(pitEntry, 0_ms);
242
243 // dispatch to strategy: after Content Store hit
244 m_strategyChoice.findEffectiveStrategy(*pitEntry).afterContentStoreHit(data, ingress, pitEntry);
245}
246
247pit::OutRecord*
248Forwarder::onOutgoingInterest(const Interest& interest, Face& egress,
249 const shared_ptr<pit::Entry>& pitEntry)
250{
251 auto hopLimit = interest.getHopLimit();
252
253 // drop if HopLimit == 0 but sending on non-local face
254 if (hopLimit == 0 && egress.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
255 NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << interest.getName()
256 << " nonce=" << interest.getNonce() << " hop-limit=0 non-local -> DROP");
257 ++egress.getCounters().nOutHopLimitZero;
258 return nullptr;
259 }
260
261 NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << interest.getName()
262 << " nonce=" << interest.getNonce() << " hop-limit="
263 << (hopLimit.has_value() ? std::to_string(static_cast<unsigned>(*hopLimit)) : "(null)"));
264
265 // insert out-record
266 auto it = pitEntry->insertOrUpdateOutRecord(egress, interest);
267 BOOST_ASSERT(it != pitEntry->out_end());
268
269 // send Interest
270 egress.sendInterest(interest);
271 ++m_counters.nOutInterests;
272
273 return &*it;
274}
275
276void
277Forwarder::onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry)
278{
279 NFD_LOG_DEBUG("onInterestFinalize interest=" << pitEntry->getName()
280 << (pitEntry->isSatisfied ? " satisfied" : " unsatisfied"));
281
282 // Dead Nonce List insert if necessary
283 this->insertDeadNonceList(*pitEntry, nullptr);
284
285 // Increment satisfied/unsatisfied Interests counter
286 if (pitEntry->isSatisfied) {
287 ++m_counters.nSatisfiedInterests;
288 }
289 else {
290 ++m_counters.nUnsatisfiedInterests;
291 }
292
293 // PIT delete
294 pitEntry->expiryTimer.cancel();
295 m_pit.erase(pitEntry.get());
296}
297
298void
299Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
300{
301 data.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
302 ++m_counters.nInData;
303 NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName());
304
305 // /localhost scope control
306 bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
307 scope_prefix::LOCALHOST.isPrefixOf(data.getName());
308 if (isViolatingLocalhost) {
309 NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName()
310 << " violates /localhost -> DROP");
311 return;
312 }
313
314 // PIT match
315 pit::DataMatchResult pitMatches = m_pit.findAllDataMatches(data);
316 if (pitMatches.size() == 0) {
317 // go to Data unsolicited pipeline
318 this->onDataUnsolicited(data, ingress);
319 return;
320 }
321
322 // CS insert
323 m_cs.insert(data);
324
325 // when only one PIT entry is matched, trigger strategy: after receive Data
326 if (pitMatches.size() == 1) {
327 auto& pitEntry = pitMatches.front();
328 NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName()
329 << " matching=" << pitEntry->getName());
330
331 // set PIT expiry timer to now
332 this->setExpiryTimer(pitEntry, 0_ms);
333
334 // trigger strategy: after receive Data
335 m_strategyChoice.findEffectiveStrategy(*pitEntry).afterReceiveData(data, ingress, pitEntry);
336
337 // mark PIT satisfied
338 pitEntry->isSatisfied = true;
339 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
340
341 // Dead Nonce List insert if necessary (for out-record of ingress face)
342 this->insertDeadNonceList(*pitEntry, &ingress.face);
343
344 // delete PIT entry's out-record
345 pitEntry->deleteOutRecord(ingress.face);
346 }
347 // when more than one PIT entry is matched, trigger strategy: before satisfy Interest,
348 // and send Data to all matched out faces
349 else {
350 std::set<Face*> pendingDownstreams;
351 auto now = time::steady_clock::now();
352
353 for (const auto& pitEntry : pitMatches) {
354 NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName()
355 << " matching=" << pitEntry->getName());
356
357 // remember pending downstreams
358 for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
359 if (inRecord.getExpiry() > now) {
360 pendingDownstreams.insert(&inRecord.getFace());
361 }
362 }
363
364 // set PIT expiry timer to now
365 this->setExpiryTimer(pitEntry, 0_ms);
366
367 // invoke PIT satisfy callback
368 m_strategyChoice.findEffectiveStrategy(*pitEntry).beforeSatisfyInterest(data, ingress, pitEntry);
369
370 // mark PIT satisfied
371 pitEntry->isSatisfied = true;
372 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
373
374 // Dead Nonce List insert if necessary (for out-record of ingress face)
375 this->insertDeadNonceList(*pitEntry, &ingress.face);
376
377 // clear PIT entry's in and out records
378 pitEntry->clearInRecords();
379 pitEntry->deleteOutRecord(ingress.face);
380 }
381
382 for (Face* pendingDownstream : pendingDownstreams) {
383 if (pendingDownstream->getId() == ingress.face.getId() &&
384 pendingDownstream->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
385 continue;
386 }
387 // go to outgoing Data pipeline
388 this->onOutgoingData(data, *pendingDownstream);
389 }
390 }
391}
392
393void
394Forwarder::onDataUnsolicited(const Data& data, const FaceEndpoint& ingress)
395{
396 ++m_counters.nUnsolicitedData;
397
398 // accept to cache?
399 auto decision = m_unsolicitedDataPolicy->decide(ingress.face, data);
400 NFD_LOG_DEBUG("onDataUnsolicited in=" << ingress << " data=" << data.getName()
401 << " decision=" << decision);
402 if (decision == fw::UnsolicitedDataDecision::CACHE) {
403 // CS insert
404 m_cs.insert(data, true);
405 }
406}
407
408bool
409Forwarder::onOutgoingData(const Data& data, Face& egress)
410{
411 if (egress.getId() == face::INVALID_FACEID) {
412 NFD_LOG_WARN("onOutgoingData out=(invalid) data=" << data.getName() << " -> DROP");
413 return false;
414 }
415
416 // /localhost scope control
417 bool isViolatingLocalhost = egress.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
418 scope_prefix::LOCALHOST.isPrefixOf(data.getName());
419 if (isViolatingLocalhost) {
420 NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName()
421 << " violates /localhost -> DROP");
422 return false;
423 }
424
425 NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName());
426
427 // send Data
428 egress.sendData(data);
429 ++m_counters.nOutData;
430
431 return true;
432}
433
434void
435Forwarder::onIncomingNack(const lp::Nack& nack, const FaceEndpoint& ingress)
436{
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 << " nack=" << nack.getInterest().getName()
443 << " reason=" << nack.getReason() << " link-type=" << ingress.face.getLinkType()
444 << " -> DROP");
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 << " reason=" << nack.getReason() << " no-pit-entry -> DROP");
454 return;
455 }
456
457 // has out-record?
458 auto outRecord = pitEntry->findOutRecord(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 << " reason=" << nack.getReason() << " no-out-record -> DROP");
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 << " reason=" << nack.getReason() << " nonce-mismatch "
470 << nack.getInterest().getNonce() << "!=" << outRecord->getLastNonce() << " -> DROP");
471 return;
472 }
473
474 NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
475 << " reason=" << nack.getReason());
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
489bool
490Forwarder::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)" << " nack=" << pitEntry->getName()
495 << " reason=" << nack.getReason() << " -> DROP");
496 return false;
497 }
498
499 // has in-record?
500 auto inRecord = pitEntry->findInRecord(egress);
501
502 // if no in-record found, drop
503 if (inRecord == pitEntry->in_end()) {
504 NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId() << " nack=" << pitEntry->getName()
505 << " reason=" << nack.getReason() << " no-in-record -> DROP");
506 return false;
507 }
508
509 // if multi-access or ad hoc face, drop
510 if (egress.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
511 NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId() << " nack=" << pitEntry->getName()
512 << " reason=" << nack.getReason() << " link-type=" << egress.getLinkType()
513 << " -> DROP");
514 return false;
515 }
516
517 NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId() << " nack=" << pitEntry->getName()
518 << " reason=" << nack.getReason());
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(inRecord);
526
527 // send Nack on face
528 egress.sendNack(nackPkt);
529 ++m_counters.nOutNacks;
530
531 return true;
532}
533
534void
535Forwarder::onDroppedInterest(const Interest& interest, Face& egress)
536{
537 NFD_LOG_DEBUG("onDroppedInterest out=" << egress.getId() << " interest=" << interest.getName());
538 m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(interest, egress);
539}
540
541void
542Forwarder::onNewNextHop(const Name& prefix, const fib::NextHop& nextHop)
543{
544 const auto affectedEntries = this->getNameTree().partialEnumerate(prefix,
545 [&] (const name_tree::Entry& nte) -> std::pair<bool, bool> {
546 // we ignore an NTE and skip visiting its descendants if that NTE has an
547 // associated FIB entry (1st condition), since in that case the new nexthop
548 // won't affect any PIT entries anywhere in that subtree, *unless* this is
549 // the initial NTE from which the enumeration started (2nd condition), which
550 // must always be considered
551 if (nte.getFibEntry() != nullptr && nte.getName().size() > prefix.size()) {
552 return {false, false};
553 }
554 return {nte.hasPitEntries(), true};
555 });
556
557 for (const auto& nte : affectedEntries) {
558 for (const auto& pitEntry : nte.getPitEntries()) {
559 m_strategyChoice.findEffectiveStrategy(*pitEntry).afterNewNextHop(nextHop, pitEntry);
560 }
561 }
562}
563
564void
565Forwarder::setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
566{
567 BOOST_ASSERT(pitEntry);
568 duration = std::max(duration, 0_ms);
569
570 pitEntry->expiryTimer.cancel();
571 pitEntry->expiryTimer = getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
572}
573
574void
575Forwarder::insertDeadNonceList(pit::Entry& pitEntry, const Face* upstream)
576{
577 // need Dead Nonce List insert?
578 bool needDnl = true;
579 if (pitEntry.isSatisfied) {
580 BOOST_ASSERT(pitEntry.dataFreshnessPeriod >= 0_ms);
581 needDnl = pitEntry.getInterest().getMustBeFresh() &&
582 pitEntry.dataFreshnessPeriod < m_deadNonceList.getLifetime();
583 }
584
585 if (!needDnl) {
586 return;
587 }
588
589 // Dead Nonce List insert
590 if (upstream == nullptr) {
591 // insert all outgoing Nonces
592 std::for_each(pitEntry.out_begin(), pitEntry.out_end(), [&] (const auto& outRecord) {
593 m_deadNonceList.add(pitEntry.getName(), outRecord.getLastNonce());
594 });
595 }
596 else {
597 // insert outgoing Nonce of a specific face
598 auto outRecord = pitEntry.findOutRecord(*upstream);
599 if (outRecord != pitEntry.out_end()) {
600 m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
601 }
602 }
603}
604
605void
606Forwarder::setConfigFile(ConfigFile& configFile)
607{
608 configFile.addSectionHandler(CFG_FORWARDER, [this] (auto&&... args) {
609 processConfig(std::forward<decltype(args)>(args)...);
610 });
611}
612
613void
614Forwarder::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string&)
615{
616 Config config;
617
618 for (const auto& pair : configSection) {
619 const std::string& key = pair.first;
620 if (key == "default_hop_limit") {
621 config.defaultHopLimit = ConfigFile::parseNumber<uint8_t>(pair, CFG_FORWARDER);
622 }
623 else {
624 NDN_THROW(ConfigFile::Error("Unrecognized option " + CFG_FORWARDER + "." + key));
625 }
626 }
627
628 if (!isDryRun) {
629 m_config = config;
630 }
631}
632
633} // namespace nfd
This file contains common algorithms used by forwarding strategies.
Configuration file parsing utility.
void addSectionHandler(const std::string &sectionName, ConfigSectionHandler subscriber)
Setup notification of configuration file sections.
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.
signal::Signal< FaceTable, Face > beforeRemove
Fires immediately before a face is removed.
signal::Signal< FaceTable, Face > afterAdd
Fires immediately after a face is added.
Face * get(FaceId id) const noexcept
Get face by FaceId.
NameTree & getNameTree() noexcept
Definition forwarder.hpp:84
Forwarder(FaceTable &faceTable)
Definition forwarder.cpp:51
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:49
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.
Definition face.hpp:96
Generalization of a network interface.
Definition face.hpp:118
const FaceCounters & getCounters() const noexcept
Definition face.hpp:298
signal::Signal< LinkService, Data, EndpointId > & afterReceiveData
Called when a Data packet is received.
Definition face.hpp:182
ndn::nfd::FaceScope getScope() const noexcept
Returns whether the face is local or non-local for scope control purposes.
Definition face.hpp:232
signal::Signal< LinkService, Interest > & onDroppedInterest
Called when an Interest is dropped by the reliability system for exceeding the allowed number of retr...
Definition face.hpp:188
signal::Signal< LinkService, lp::Nack, EndpointId > & afterReceiveNack
Called when a Nack packet is received.
Definition face.hpp:185
ndn::nfd::LinkType getLinkType() const noexcept
Returns the link type of the face (point-to-point, multi-access, ...).
Definition face.hpp:259
FaceId getId() const noexcept
Returns the face ID.
Definition face.hpp:195
signal::Signal< LinkService, Interest, EndpointId > & afterReceiveInterest
Called when an Interest packet is received.
Definition face.hpp:179
signal::Signal< Fib, Name, NextHop > afterNewNextHop
Signals on Fib entry nexthop creation.
Definition fib.hpp:154
Represents a nexthop record in a FIB entry.
Definition fib-entry.hpp:50
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:210
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:185
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:205
virtual void onInterestLoop(const Interest &interest, const FaceEndpoint &ingress)
Trigger after an Interest loop is detected.
Definition strategy.cpp:177
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:197
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:192
Range partialEnumerate(const Name &prefix, const EntrySubTreeSelector &entrySubTreeSelector=AnyEntrySubTree()) const
Enumerate all entries under a prefix.
std::pair< shared_ptr< Entry >, bool > insert(const Interest &interest)
Inserts a PIT entry for interest.
Definition pit.hpp:115
shared_ptr< Entry > find(const Interest &interest) const
Finds a PIT entry for interest.
Definition pit.hpp:104
DataMatchResult findAllDataMatches(const Data &data) const
Performs a Data match.
Definition pit.cpp:99
void erase(Entry *entry)
Deletes an entry.
Definition pit.hpp:129
void setDefaultStrategy(const Name &strategyName)
Set the default strategy.
fw::Strategy & findEffectiveStrategy(const Name &prefix) const
Get effective strategy for prefix.
#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
constexpr FaceId INVALID_FACEID
Indicates an invalid FaceId.
constexpr FaceId FACEID_CONTENT_STORE
Identifies a packet comes from the ContentStore.
@ CACHE
the Data should be cached in the ContentStore
@ DUPLICATE_NONCE_NONE
no duplicate Nonce is found
Definition algorithm.hpp:47
@ DUPLICATE_NONCE_IN_SAME
in-record of same face
Definition algorithm.hpp:48
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
std::vector< shared_ptr< Entry > > DataMatchResult
An unordered iterable of all PIT entries matching a Data packet.
Definition pit.hpp:38
const Name LOCALHOST
The localhost scope ndn:/localhost.
Definition common.hpp:71
const std::string CFG_FORWARDER
Definition forwarder.cpp:43
ndn::Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
Definition global.cpp:45
boost::property_tree::ptree ConfigSection
A configuration file section.
void cleanupOnFaceRemoval(NameTree &nt, Fib &fib, Pit &pit, const Face &face)
Cleanup tables when a face is destroyed.
Definition cleanup.cpp:33
static Name getDefaultStrategyName()
Definition forwarder.cpp:46