54 : m_faceTable(faceTable)
58 , m_measurements(m_nameTree)
59 , m_strategyChoice(*this)
65 face.afterReceiveInterest.connect(
67 this->onIncomingInterest(interest,
FaceEndpoint(const_cast<Face&>(face), endpointId));
69 face.afterReceiveData.connect(
73 face.afterReceiveNack.connect(
77 face.onDroppedInterest.connect(
78 [
this, &face] (
const Interest& interest) {
101 interest.
setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.getId()));
109 ++ingress.
face.getCounters().nInHopLimitZero;
119 if (isViolatingLocalhost) {
121 <<
" interest=" << interest.
getName() <<
" violates /localhost");
127 bool hasDuplicateNonceInDnl = m_deadNonceList.
has(interest.
getName(), interest.
getNonce());
128 if (hasDuplicateNonceInDnl) {
138 <<
" interest=" << interest.
getName() <<
" reaching-producer-region");
139 const_cast<Interest&
>(interest).setForwardingHint({});
143 shared_ptr<pit::Entry> pitEntry = m_pit.
insert(interest).first;
152 if (hasDuplicateNonceInPit) {
160 if (!pitEntry->hasInRecords()) {
176 <<
" interest=" << interest.
getName() <<
" drop");
181 <<
" send-Nack-duplicate");
186 nack.setReason(lp::NackReason::DUPLICATE);
187 ingress.
face.sendNack(nack);
192 const shared_ptr<pit::Entry>& pitEntry)
199 if (m_config.defaultHopLimit > 0 && !interest.
getHopLimit()) {
200 const_cast<Interest&
>(interest).setHopLimit(m_config.defaultHopLimit);
204 pitEntry->insertOrUpdateInRecord(ingress.
face, interest);
207 auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
208 [] (
const auto& a,
const auto& b) {
209 return a.getExpiry() < b.getExpiry();
212 this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
216 if (nextHopTag !=
nullptr) {
218 Face* nextHopFace = m_faceTable.
get(*nextHopTag);
219 if (nextHopFace !=
nullptr) {
221 <<
" nexthop-faceid=" << nextHopFace->getId());
236 const shared_ptr<pit::Entry>& pitEntry,
const Data& data)
246 pitEntry->isSatisfied =
true;
250 this->setExpiryTimer(pitEntry, 0_ms);
261 const shared_ptr<pit::Entry>& pitEntry)
265 NFD_LOG_DEBUG(
"onOutgoingInterest out=" << egress.getId() <<
" interest=" << pitEntry->getName()
266 <<
" non-local hop-limit=0");
267 ++egress.getCounters().nOutHopLimitZero;
271 NFD_LOG_DEBUG(
"onOutgoingInterest out=" << egress.getId() <<
" interest=" << pitEntry->getName());
274 auto it = pitEntry->insertOrUpdateOutRecord(egress, interest);
275 BOOST_ASSERT(it != pitEntry->out_end());
278 egress.sendInterest(interest);
286 NFD_LOG_DEBUG(
"onInterestFinalize interest=" << pitEntry->getName()
287 << (pitEntry->isSatisfied ?
" satisfied" :
" unsatisfied"));
289 if (!pitEntry->isSatisfied) {
294 this->insertDeadNonceList(*pitEntry,
nullptr);
297 if (pitEntry->isSatisfied) {
305 pitEntry->expiryTimer.cancel();
306 m_pit.
erase(pitEntry.get());
314 data.
setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.getId()));
320 if (isViolatingLocalhost) {
321 NFD_LOG_DEBUG(
"onIncomingData in=" << ingress <<
" data=" << data.
getName() <<
" violates /localhost");
328 if (pitMatches.size() == 0) {
337 std::set<std::pair<Face*, EndpointId>> satisfiedDownstreams;
338 std::multimap<std::pair<Face*, EndpointId>, std::shared_ptr<pit::Entry>> unsatisfiedPitEntries;
340 for (
const auto& pitEntry : pitMatches) {
341 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
346 std::set<std::pair<Face*, EndpointId>> unsatisfiedDownstreams;
348 satisfiedDownstreams, unsatisfiedDownstreams);
349 for (
const auto& endpoint : unsatisfiedDownstreams) {
350 unsatisfiedPitEntries.emplace(endpoint, pitEntry);
353 if (unsatisfiedDownstreams.empty()) {
355 this->setExpiryTimer(pitEntry, 0_ms);
358 pitEntry->isSatisfied =
true;
362 this->insertDeadNonceList(*pitEntry, &ingress.
face);
367 for (
const auto& endpoint : satisfiedDownstreams) {
368 pitEntry->deleteInRecord(*endpoint.first);
370 pitEntry->deleteOutRecord(ingress.
face);
375 for (
const auto& unsatisfied : unsatisfiedPitEntries) {
376 auto downstreamIt = satisfiedDownstreams.find(unsatisfied.first);
377 if (downstreamIt != satisfiedDownstreams.end()) {
378 auto pitEntry = unsatisfied.second;
379 pitEntry->deleteInRecord(*unsatisfied.first.first);
381 if (pitEntry->getInRecords().empty()) {
383 this->setExpiryTimer(pitEntry, 0_ms);
386 pitEntry->isSatisfied =
true;
392 for (
const auto& downstream : satisfiedDownstreams) {
393 if (downstream.first->getId() == ingress.
face.getId() &&
394 downstream.second == ingress.
endpoint &&
407 auto decision = m_unsolicitedDataPolicy->decide(ingress.
face, data);
414 <<
" decision=" << decision);
430 if (isViolatingLocalhost) {
432 <<
" violates /localhost");
440 egress.sendData(data);
450 nack.
setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.getId()));
457 <<
" link-type=" << ingress.
face.getLinkType());
464 if (pitEntry ==
nullptr) {
466 <<
"~" << nack.
getReason() <<
" no-PIT-entry");
471 auto outRecord = pitEntry->getOutRecord(ingress.
face);
473 if (outRecord == pitEntry->out_end()) {
475 <<
"~" << nack.
getReason() <<
" no-out-record");
483 <<
"!=" << outRecord->getLastNonce());
491 outRecord->setIncomingNack(nack);
495 this->setExpiryTimer(pitEntry, 0_ms);
504 const shared_ptr<pit::Entry>& pitEntry)
508 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.
getReason());
513 auto inRecord = pitEntry->getInRecord(egress);
516 if (inRecord == pitEntry->in_end()) {
518 <<
" nack=" << pitEntry->getInterest().getName()
519 <<
"~" << nack.
getReason() <<
" no-in-record");
526 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.
getReason()
527 <<
" link-type=" << egress.getLinkType());
532 <<
" nack=" << pitEntry->getInterest().getName()
536 lp::Nack nackPkt(inRecord->getInterest());
540 pitEntry->deleteInRecord(egress);
543 egress.sendNack(nackPkt);
566 return {
false,
false};
571 for (
const auto& nte : affectedEntries) {
581 BOOST_ASSERT(pitEntry);
582 duration = std::max(duration, 0_ms);
584 pitEntry->expiryTimer.cancel();
589 Forwarder::insertDeadNonceList(
pit::Entry& pitEntry,
const Face* upstream)
604 if (upstream ==
nullptr) {
607 std::for_each(outRecords.begin(), outRecords.end(), [&] (
const auto& outRecord) {
608 m_deadNonceList.
add(pitEntry.
getName(), outRecord.getLastNonce());
615 m_deadNonceList.
add(pitEntry.
getName(), outRecord->getLastNonce());
624 processConfig(std::forward<decltype(args)>(args)...);
629 Forwarder::processConfig(
const ConfigSection& configSection,
bool isDryRun,
const std::string&)
633 for (
const auto& pair : configSection) {
634 const std::string& key = pair.first;
635 if (key ==
"default_hop_limit") {
636 config.defaultHopLimit = ConfigFile::parseNumber<uint8_t>(pair,
CFG_FORWARDER);
NFD_VIRTUAL_WITH_TESTS ~Forwarder()
virtual void satisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data, std::set< std::pair< Face *, EndpointId >> &satisfiedDownstreams, std::set< std::pair< Face *, EndpointId >> &unsatisfiedDownstreams)
signal::Signal< Forwarder, pit::Entry, Face, Data > beforeSatisfyInterest
trigger before PIT entry is satisfied
bool isSatisfied
Indicates whether this PIT entry is satisfied.
bool getMustBeFresh() const noexcept
Check whether the MustBeFresh element is present.
void setTag(shared_ptr< T > tag) const
set a tag item
NFD_VIRTUAL_WITH_TESTS void onContentStoreHit(const Interest &interest, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry, const Data &data)
Content Store hit pipeline.
virtual void afterNewNextHop(const fib::NextHop &nextHop, const shared_ptr< pit::Entry > &pitEntry)
Trigger after a new nexthop is added.
void erase(Entry *entry)
Deletes an entry.
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE const FaceEndpoint & ingress
void cleanupOnFaceRemoval(NameTree &nt, Fib &fib, Pit &pit, const Face &face)
cleanup tables when a face is destroyed
shared_ptr< Face > makeNullFace(const FaceUri &uri)
shared_ptr< T > getTag() const
get a tag item
const std::string CFG_FORWARDER
OutRecordCollection::iterator getOutRecord(const Face &face)
get the out-record for face
#define NFD_LOG_INIT(name)
time::nanoseconds getLifetime() const
Returns the expected nonce lifetime.
const Name LOCALHOST("ndn:/localhost")
ndn:/localhost
span< const Name > getForwardingHint() const noexcept
const std::vector< shared_ptr< pit::Entry > > & getPitEntries() const
Represents a face-endpoint pair in the forwarder.
static time_point now() noexcept
Nack & setHeader(const NackHeader &header)
bool isPrefixOf(const Name &other) const
Check if this name is a prefix of another name.
configuration file parsing utility
fib::Entry * getFibEntry() const
NFD_VIRTUAL_WITH_TESTS void onDroppedInterest(const Interest &interest, Face &egress)
NFD_VIRTUAL_WITH_TESTS void onIncomingData(const Data &data, const FaceEndpoint &ingress)
incoming Data pipeline
NFD_VIRTUAL_WITH_TESTS void onNewNextHop(const Name &prefix, const fib::NextHop &nextHop)
Main class of NFD's forwarding engine.
boost::chrono::duration< Rep, Period > duration
Forwarder(FaceTable &faceTable)
NFD_VIRTUAL_WITH_TESTS void onDataUnsolicited(const Data &data, const FaceEndpoint &ingress)
Data unsolicited pipeline.
PacketCounter nInInterests
Represents an Interest packet.
void add(const Name &name, Interest::Nonce nonce)
Adds name+nonce to the list.
DataMatchResult findAllDataMatches(const Data &data) const
Performs a Data match.
NFD_VIRTUAL_WITH_TESTS pit::OutRecord * onOutgoingInterest(const Interest &interest, Face &egress, const shared_ptr< pit::Entry > &pitEntry)
outgoing Interest pipeline
uint64_t EndpointId
Identifies a remote endpoint on the link.
virtual void afterContentStoreHit(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
trigger after a Data is matched in CS
bool isInProducerRegion(span< const Name > forwardingHint) const
determines whether an Interest has reached a producer region
NFD_VIRTUAL_WITH_TESTS bool onOutgoingNack(const lp::NackHeader &nack, Face &egress, const shared_ptr< pit::Entry > &pitEntry)
outgoing Nack pipeline
Face * get(FaceId id) const
get face by FaceId
represents a Network Nack
signal::Signal< FaceTable, Face > beforeRemove
Fires immediately before a face is removed.
NackReason getReason() const
int findDuplicateNonce(const pit::Entry &pitEntry, Interest::Nonce nonce, const Face &face)
determine whether pitEntry has duplicate Nonce nonce
virtual void afterReceiveLoopedInterest(const FaceEndpoint &ingress, const Interest &interest, pit::Entry &pitEntry)
trigger after a looped Interest is received
Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
Range partialEnumerate(const Name &prefix, const EntrySubTreeSelector &entrySubTreeSelector=AnyEntrySubTree()) const
Enumerate all entries under a prefix.
provides a tag type for simple types
static const Name & getStrategyName()
DropAllUnsolicitedDataPolicy DefaultUnsolicitedDataPolicy
The default UnsolicitedDataPolicy.
NFD_VIRTUAL_WITH_TESTS bool onOutgoingData(const Data &data, Face &egress)
outgoing Data pipeline
virtual void afterReceiveInterest(const Interest &interest, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)=0
Trigger after an Interest is received.
void insert(const Data &data, bool isUnsolicited=false)
inserts a Data packet
Copyright (c) 2011-2015 Regents of the University of California.
void addSectionHandler(const std::string §ionName, ConfigSectionHandler subscriber)
setup notification of configuration file sections
NFD_VIRTUAL_WITH_TESTS void onIncomingNack(const lp::Nack &nack, const FaceEndpoint &ingress)
incoming Nack pipeline
signal::Signal< Forwarder, pit::Entry > beforeExpirePendingInterest
trigger before PIT entry expires
NFD_VIRTUAL_WITH_TESTS void onInterestLoop(const Interest &interest, const FaceEndpoint &ingress)
Interest loop pipeline.
std::pair< shared_ptr< Entry >, bool > insert(const Interest &interest)
Inserts a PIT entry for interest.
bool has(const Name &name, Interest::Nonce nonce) const
Determines if name+nonce is in the list.
fw::Strategy & findEffectiveStrategy(const Name &prefix) const
Get effective strategy for prefix.
signal::Signal< Fib, Name, NextHop > afterNewNextHop
signals on Fib entry nexthop creation
Nonce getNonce() const
Get nonce value.
virtual void afterReceiveNack(const lp::Nack &nack, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
Trigger after a Nack is received.
const Name & getName() const noexcept
Get name.
signal::Signal< Forwarder, Interest > afterCsMiss
Signals when the incoming interest pipeline gets a miss from the content store.
signal::Signal< Forwarder, Interest, Data > afterCsHit
Signals when the incoming interest pipeline gets a hit from the content store.
boost::property_tree::ptree ConfigSection
a config file section
optional< uint8_t > getHopLimit() const noexcept
Represents an absolute name.
void setDefaultStrategy(const Name &strategyName)
Set the default strategy.
PacketCounter nOutInterests
represents the underlying protocol and address used by a Face
PacketCounter nSatisfiedInterests
bool hasPendingOutRecords(const pit::Entry &pitEntry)
determine whether pitEntry has any pending out-records
const Interest & getInterest() const
no duplicate Nonce is found
size_t size() const
Returns the number of components.
static Name getDefaultStrategyName()
This file contains common algorithms used by forwarding strategies.
bool hasPitEntries() const
const Name & getName() const noexcept
An unordered iterable of all PIT entries matching Data.
const Name & getName() const
void addReserved(shared_ptr< Face > face, FaceId faceId)
add a special face with a reserved FaceId
PacketCounter nUnsolicitedData
Contains information about an Interest toward an outgoing face.
the Data should be cached in the ContentStore
time::milliseconds dataFreshnessPeriod
Data freshness period.
NFD_VIRTUAL_WITH_TESTS void onContentStoreMiss(const Interest &interest, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
Content Store miss pipeline.
shared_ptr< Entry > find(const Interest &interest) const
Finds a PIT entry for interest.
const EndpointId endpoint
time::milliseconds getFreshnessPeriod() const
Represents a Data packet.
const FaceId FACEID_CONTENT_STORE
identifies a packet comes from the ContentStore
void find(const Interest &interest, HitCallback &&hit, MissCallback &&miss) const
finds the best matching Data packet
const FaceId INVALID_FACEID
indicates an invalid FaceId
const Name & getName() const
PacketCounter nUnsatisfiedInterests
void setConfigFile(ConfigFile &configFile)
register handler for forwarder section of NFD configuration file
const Interest & getInterest() const
const OutRecordCollection & getOutRecords() const
virtual void beforeSatisfyInterest(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry)
trigger before PIT entry is satisfied
NFD_VIRTUAL_WITH_TESTS void onInterestFinalize(const shared_ptr< pit::Entry > &pitEntry)
Interest finalize pipeline.
An entry in the name tree.
represent a PIT token field
signal::Signal< FaceTable, Face > afterAdd
Fires immediately after a face is added.
Represents a nexthop record in a FIB entry.
boost::chrono::milliseconds milliseconds