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-2024, 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 // drop if HopLimit zero, decrement otherwise (if present)
100 if (hopLimit) {
101 NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
102 << " nonce=" << nonce << " hop-limit=" << static_cast<unsigned>(*hopLimit));
103 if (*hopLimit == 0) {
104 ++ingress.face.getCounters().nInHopLimitZero;
105 // drop
106 return;
107 }
108 const_cast<Interest&>(interest).setHopLimit(*hopLimit - 1);
109 }
110 else {
111 NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
112 << " nonce=" << nonce);
113 }
114
115 // /localhost scope control
116 bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
117 scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
118 if (isViolatingLocalhost) {
119 NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
120 << " nonce=" << nonce << " violates /localhost");
121 // drop
122 return;
123 }
124
125 // detect duplicate Nonce with Dead Nonce List
126 bool hasDuplicateNonceInDnl = m_deadNonceList.has(interest.getName(), nonce);
127 if (hasDuplicateNonceInDnl) {
128 // go to Interest loop pipeline
129 this->onInterestLoop(interest, ingress);
130 return;
131 }
132
133 // strip forwarding hint if Interest has reached producer region
134 if (!interest.getForwardingHint().empty() &&
135 m_networkRegionTable.isInProducerRegion(interest.getForwardingHint())) {
136 NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
137 << " nonce=" << nonce << " reaching-producer-region");
138 const_cast<Interest&>(interest).setForwardingHint({});
139 }
140
141 // PIT insert
142 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
143
144 // detect duplicate Nonce in PIT entry
145 int dnw = fw::findDuplicateNonce(*pitEntry, nonce, ingress.face);
146 bool hasDuplicateNonceInPit = dnw != fw::DUPLICATE_NONCE_NONE;
147 if (ingress.face.getLinkType() == ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
148 // for p2p face: duplicate Nonce from same incoming face is not loop
149 hasDuplicateNonceInPit = hasDuplicateNonceInPit && !(dnw & fw::DUPLICATE_NONCE_IN_SAME);
150 }
151 if (hasDuplicateNonceInPit) {
152 // go to Interest loop pipeline
153 this->onInterestLoop(interest, ingress);
154 return;
155 }
156
157 // is pending?
158 if (!pitEntry->hasInRecords()) {
159 m_cs.find(interest,
160 [=] (const Interest& i, const Data& d) { onContentStoreHit(i, ingress, pitEntry, d); },
161 [=] (const Interest& i) { onContentStoreMiss(i, ingress, pitEntry); });
162 }
163 else {
164 this->onContentStoreMiss(interest, ingress, pitEntry);
165 }
166}
167
168void
169Forwarder::onInterestLoop(const Interest& interest, const FaceEndpoint& ingress)
170{
171 // if multi-access or ad hoc face, drop
172 if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
173 NFD_LOG_DEBUG("onInterestLoop in=" << ingress << " interest=" << interest.getName()
174 << " nonce=" << interest.getNonce() << " drop");
175 return;
176 }
177
178 NFD_LOG_DEBUG("onInterestLoop in=" << ingress << " interest=" << interest.getName()
179 << " nonce=" << interest.getNonce());
180
181 // leave loop handling up to the strategy (e.g., whether to reply with a Nack)
182 m_strategyChoice.findEffectiveStrategy(interest.getName()).onInterestLoop(interest, ingress);
183}
184
185void
186Forwarder::onContentStoreMiss(const Interest& interest, const FaceEndpoint& ingress,
187 const shared_ptr<pit::Entry>& pitEntry)
188{
189 NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName() << " nonce=" << interest.getNonce());
190 ++m_counters.nCsMisses;
191
192 // attach HopLimit if configured and not present in Interest
193 if (m_config.defaultHopLimit > 0 && !interest.getHopLimit()) {
194 const_cast<Interest&>(interest).setHopLimit(m_config.defaultHopLimit);
195 }
196
197 // insert in-record
198 pitEntry->insertOrUpdateInRecord(ingress.face, interest);
199
200 // set PIT expiry timer to the time that the last PIT in-record expires
201 auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
202 [] (const auto& a, const auto& b) {
203 return a.getExpiry() < b.getExpiry();
204 });
205 auto lastExpiryFromNow = lastExpiring->getExpiry() - time::steady_clock::now();
206 this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
207
208 // has NextHopFaceId?
209 auto nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
210 if (nextHopTag != nullptr) {
211 // chosen NextHop face exists?
212 Face* nextHopFace = m_faceTable.get(*nextHopTag);
213 if (nextHopFace != nullptr) {
214 NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName()
215 << " nonce=" << interest.getNonce() << " nexthop-faceid=" << nextHopFace->getId());
216 // go to outgoing Interest pipeline
217 // scope control is unnecessary, because privileged app explicitly wants to forward
218 this->onOutgoingInterest(interest, *nextHopFace, pitEntry);
219 }
220 return;
221 }
222
223 // dispatch to strategy: after receive Interest
224 m_strategyChoice.findEffectiveStrategy(*pitEntry)
225 .afterReceiveInterest(interest, FaceEndpoint(ingress.face), pitEntry);
226}
227
228void
229Forwarder::onContentStoreHit(const Interest& interest, const FaceEndpoint& ingress,
230 const shared_ptr<pit::Entry>& pitEntry, const Data& data)
231{
232 NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName() << " nonce=" << interest.getNonce());
233 ++m_counters.nCsHits;
234
235 data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
236 data.setTag(interest.getTag<lp::PitToken>());
237 // FIXME Should we lookup PIT for other Interests that also match the data?
238
239 pitEntry->isSatisfied = true;
240 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
241
242 // set PIT expiry timer to now
243 this->setExpiryTimer(pitEntry, 0_ms);
244
245 // dispatch to strategy: after Content Store hit
246 m_strategyChoice.findEffectiveStrategy(*pitEntry).afterContentStoreHit(data, ingress, pitEntry);
247}
248
249pit::OutRecord*
250Forwarder::onOutgoingInterest(const Interest& interest, Face& egress,
251 const shared_ptr<pit::Entry>& pitEntry)
252{
253 // drop if HopLimit == 0 but sending on non-local face
254 if (interest.getHopLimit() == 0 && egress.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
255 NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << interest.getName()
256 << " nonce=" << interest.getNonce() << " non-local hop-limit=0");
257 ++egress.getCounters().nOutHopLimitZero;
258 return nullptr;
259 }
260
261 NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << interest.getName()
262 << " nonce=" << interest.getNonce());
263
264 // insert out-record
265 auto it = pitEntry->insertOrUpdateOutRecord(egress, interest);
266 BOOST_ASSERT(it != pitEntry->out_end());
267
268 // send Interest
269 egress.sendInterest(interest);
270 ++m_counters.nOutInterests;
271
272 return &*it;
273}
274
275void
276Forwarder::onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry)
277{
278 NFD_LOG_DEBUG("onInterestFinalize interest=" << pitEntry->getName()
279 << (pitEntry->isSatisfied ? " satisfied" : " unsatisfied"));
280
281 // Dead Nonce List insert if necessary
282 this->insertDeadNonceList(*pitEntry, nullptr);
283
284 // Increment satisfied/unsatisfied Interests counter
285 if (pitEntry->isSatisfied) {
286 ++m_counters.nSatisfiedInterests;
287 }
288 else {
289 ++m_counters.nUnsatisfiedInterests;
290 }
291
292 // PIT delete
293 pitEntry->expiryTimer.cancel();
294 m_pit.erase(pitEntry.get());
295}
296
297void
298Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
299{
300 data.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
301 ++m_counters.nInData;
302 NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName());
303
304 // /localhost scope control
305 bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
306 scope_prefix::LOCALHOST.isPrefixOf(data.getName());
307 if (isViolatingLocalhost) {
308 NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName() << " violates /localhost");
309 // drop
310 return;
311 }
312
313 // PIT match
314 pit::DataMatchResult pitMatches = m_pit.findAllDataMatches(data);
315 if (pitMatches.size() == 0) {
316 // go to Data unsolicited pipeline
317 this->onDataUnsolicited(data, ingress);
318 return;
319 }
320
321 // CS insert
322 m_cs.insert(data);
323
324 // when only one PIT entry is matched, trigger strategy: after receive Data
325 if (pitMatches.size() == 1) {
326 auto& pitEntry = pitMatches.front();
327
328 NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
329
330 // set PIT expiry timer to now
331 this->setExpiryTimer(pitEntry, 0_ms);
332
333 // trigger strategy: after receive Data
334 m_strategyChoice.findEffectiveStrategy(*pitEntry).afterReceiveData(data, ingress, pitEntry);
335
336 // mark PIT satisfied
337 pitEntry->isSatisfied = true;
338 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
339
340 // Dead Nonce List insert if necessary (for out-record of ingress face)
341 this->insertDeadNonceList(*pitEntry, &ingress.face);
342
343 // delete PIT entry's out-record
344 pitEntry->deleteOutRecord(ingress.face);
345 }
346 // when more than one PIT entry is matched, trigger strategy: before satisfy Interest,
347 // and send Data to all matched out faces
348 else {
349 std::set<Face*> pendingDownstreams;
350 auto now = time::steady_clock::now();
351
352 for (const auto& pitEntry : pitMatches) {
353 NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
354
355 // remember pending downstreams
356 for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
357 if (inRecord.getExpiry() > now) {
358 pendingDownstreams.insert(&inRecord.getFace());
359 }
360 }
361
362 // set PIT expiry timer to now
363 this->setExpiryTimer(pitEntry, 0_ms);
364
365 // invoke PIT satisfy callback
366 m_strategyChoice.findEffectiveStrategy(*pitEntry).beforeSatisfyInterest(data, ingress, pitEntry);
367
368 // mark PIT satisfied
369 pitEntry->isSatisfied = true;
370 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
371
372 // Dead Nonce List insert if necessary (for out-record of ingress face)
373 this->insertDeadNonceList(*pitEntry, &ingress.face);
374
375 // clear PIT entry's in and out records
376 pitEntry->clearInRecords();
377 pitEntry->deleteOutRecord(ingress.face);
378 }
379
380 for (Face* pendingDownstream : pendingDownstreams) {
381 if (pendingDownstream->getId() == ingress.face.getId() &&
382 pendingDownstream->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
383 continue;
384 }
385 // go to outgoing Data pipeline
386 this->onOutgoingData(data, *pendingDownstream);
387 }
388 }
389}
390
391void
392Forwarder::onDataUnsolicited(const Data& data, const FaceEndpoint& ingress)
393{
394 ++m_counters.nUnsolicitedData;
395
396 // accept to cache?
397 auto decision = m_unsolicitedDataPolicy->decide(ingress.face, data);
398 NFD_LOG_DEBUG("onDataUnsolicited in=" << ingress << " data=" << data.getName()
399 << " decision=" << decision);
400 if (decision == fw::UnsolicitedDataDecision::CACHE) {
401 // CS insert
402 m_cs.insert(data, true);
403 }
404}
405
406bool
407Forwarder::onOutgoingData(const Data& data, Face& egress)
408{
409 if (egress.getId() == face::INVALID_FACEID) {
410 NFD_LOG_WARN("onOutgoingData out=(invalid) data=" << data.getName());
411 return false;
412 }
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 NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName());
425
426 // send Data
427 egress.sendData(data);
428 ++m_counters.nOutData;
429
430 return true;
431}
432
433void
434Forwarder::onIncomingNack(const lp::Nack& nack, const FaceEndpoint& ingress)
435{
436 nack.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
437 ++m_counters.nInNacks;
438
439 // if multi-access or ad hoc face, drop
440 if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
441 NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
442 << "~" << nack.getReason() << " link-type=" << ingress.face.getLinkType());
443 return;
444 }
445
446 // PIT match
447 shared_ptr<pit::Entry> pitEntry = m_pit.find(nack.getInterest());
448 // if no PIT entry found, drop
449 if (pitEntry == nullptr) {
450 NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
451 << "~" << nack.getReason() << " no-pit-entry");
452 return;
453 }
454
455 // has out-record?
456 auto outRecord = pitEntry->findOutRecord(ingress.face);
457 // if no out-record found, drop
458 if (outRecord == pitEntry->out_end()) {
459 NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
460 << "~" << nack.getReason() << " no-out-record");
461 return;
462 }
463
464 // if out-record has different Nonce, drop
465 if (nack.getInterest().getNonce() != outRecord->getLastNonce()) {
466 NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
467 << "~" << nack.getReason() << " nonce-mismatch " << nack.getInterest().getNonce()
468 << "!=" << outRecord->getLastNonce());
469 return;
470 }
471
472 NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
473 << "~" << nack.getReason());
474
475 // record Nack on out-record
476 outRecord->setIncomingNack(nack);
477
478 // set PIT expiry timer to now when all out-record receive Nack
479 if (!fw::hasPendingOutRecords(*pitEntry)) {
480 this->setExpiryTimer(pitEntry, 0_ms);
481 }
482
483 // trigger strategy: after receive Nack
484 m_strategyChoice.findEffectiveStrategy(*pitEntry).afterReceiveNack(nack, ingress, pitEntry);
485}
486
487bool
488Forwarder::onOutgoingNack(const lp::NackHeader& nack, Face& egress,
489 const shared_ptr<pit::Entry>& pitEntry)
490{
491 if (egress.getId() == face::INVALID_FACEID) {
492 NFD_LOG_WARN("onOutgoingNack out=(invalid)" << " nack=" << pitEntry->getName()
493 << "~" << nack.getReason());
494 return false;
495 }
496
497 // has in-record?
498 auto inRecord = pitEntry->findInRecord(egress);
499
500 // if no in-record found, drop
501 if (inRecord == pitEntry->in_end()) {
502 NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId() << " nack=" << pitEntry->getName()
503 << "~" << nack.getReason() << " no-in-record");
504 return false;
505 }
506
507 // if multi-access or ad hoc face, drop
508 if (egress.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
509 NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId() << " nack=" << pitEntry->getName()
510 << "~" << nack.getReason() << " link-type=" << egress.getLinkType());
511 return false;
512 }
513
514 NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId() << " nack=" << pitEntry->getName()
515 << "~" << nack.getReason());
516
517 // create Nack packet with the Interest from in-record
518 lp::Nack nackPkt(inRecord->getInterest());
519 nackPkt.setHeader(nack);
520
521 // erase in-record
522 pitEntry->deleteInRecord(inRecord);
523
524 // send Nack on face
525 egress.sendNack(nackPkt);
526 ++m_counters.nOutNacks;
527
528 return true;
529}
530
531void
532Forwarder::onDroppedInterest(const Interest& interest, Face& egress)
533{
534 m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(interest, egress);
535}
536
537void
538Forwarder::onNewNextHop(const Name& prefix, const fib::NextHop& nextHop)
539{
540 const auto affectedEntries = this->getNameTree().partialEnumerate(prefix,
541 [&] (const name_tree::Entry& nte) -> std::pair<bool, bool> {
542 // we ignore an NTE and skip visiting its descendants if that NTE has an
543 // associated FIB entry (1st condition), since in that case the new nexthop
544 // won't affect any PIT entries anywhere in that subtree, *unless* this is
545 // the initial NTE from which the enumeration started (2nd condition), which
546 // must always be considered
547 if (nte.getFibEntry() != nullptr && nte.getName().size() > prefix.size()) {
548 return {false, false};
549 }
550 return {nte.hasPitEntries(), true};
551 });
552
553 for (const auto& nte : affectedEntries) {
554 for (const auto& pitEntry : nte.getPitEntries()) {
555 m_strategyChoice.findEffectiveStrategy(*pitEntry).afterNewNextHop(nextHop, pitEntry);
556 }
557 }
558}
559
560void
561Forwarder::setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
562{
563 BOOST_ASSERT(pitEntry);
564 duration = std::max(duration, 0_ms);
565
566 pitEntry->expiryTimer.cancel();
567 pitEntry->expiryTimer = getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
568}
569
570void
571Forwarder::insertDeadNonceList(pit::Entry& pitEntry, const Face* upstream)
572{
573 // need Dead Nonce List insert?
574 bool needDnl = true;
575 if (pitEntry.isSatisfied) {
576 BOOST_ASSERT(pitEntry.dataFreshnessPeriod >= 0_ms);
577 needDnl = pitEntry.getInterest().getMustBeFresh() &&
578 pitEntry.dataFreshnessPeriod < m_deadNonceList.getLifetime();
579 }
580
581 if (!needDnl) {
582 return;
583 }
584
585 // Dead Nonce List insert
586 if (upstream == nullptr) {
587 // insert all outgoing Nonces
588 std::for_each(pitEntry.out_begin(), pitEntry.out_end(), [&] (const auto& outRecord) {
589 m_deadNonceList.add(pitEntry.getName(), outRecord.getLastNonce());
590 });
591 }
592 else {
593 // insert outgoing Nonce of a specific face
594 auto outRecord = pitEntry.findOutRecord(*upstream);
595 if (outRecord != pitEntry.out_end()) {
596 m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
597 }
598 }
599}
600
601void
602Forwarder::setConfigFile(ConfigFile& configFile)
603{
604 configFile.addSectionHandler(CFG_FORWARDER, [this] (auto&&... args) {
605 processConfig(std::forward<decltype(args)>(args)...);
606 });
607}
608
609void
610Forwarder::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string&)
611{
612 Config config;
613
614 for (const auto& pair : configSection) {
615 const std::string& key = pair.first;
616 if (key == "default_hop_limit") {
617 config.defaultHopLimit = ConfigFile::parseNumber<uint8_t>(pair, CFG_FORWARDER);
618 }
619 else {
620 NDN_THROW(ConfigFile::Error("Unrecognized option " + CFG_FORWARDER + "." + key));
621 }
622 }
623
624 if (!isDryRun) {
625 m_config = config;
626 }
627}
628
629} // 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:223
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:187
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:216
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:205
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:197
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.
-status-http-server
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