35 #include <ndn-cxx/lp/pit-token.hpp> 36 #include <ndn-cxx/lp/tags.hpp> 49 : m_faceTable(faceTable)
53 , m_measurements(m_nameTree)
54 , m_strategyChoice(*this)
58 [
this, &face] (
const Interest& interest,
const EndpointId& endpointId) {
62 [
this, &face] (
const Data& data,
const EndpointId& endpointId) {
66 [
this, &face] (
const lp::Nack& nack,
const EndpointId& endpointId) {
70 [
this, &face] (
const Interest& interest) {
71 this->onDroppedInterest(face, interest);
89 Forwarder::onIncomingInterest(
const FaceEndpoint& ingress,
const Interest& interest)
92 NFD_LOG_DEBUG(
"onIncomingInterest in=" << ingress <<
" interest=" << interest.getName());
93 interest.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.
getId()));
97 if (interest.getHopLimit()) {
98 if (*interest.getHopLimit() < 1) {
99 NFD_LOG_DEBUG(
"onIncomingInterest in=" << ingress <<
" interest=" << interest.getName()
105 const_cast<Interest&
>(interest).setHopLimit(*interest.getHopLimit() - 1);
109 bool isViolatingLocalhost = ingress.
face.
getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
111 if (isViolatingLocalhost) {
113 <<
" interest=" << interest.getName() <<
" violates /localhost");
119 bool hasDuplicateNonceInDnl = m_deadNonceList.
has(interest.getName(), interest.getNonce());
120 if (hasDuplicateNonceInDnl) {
122 this->onInterestLoop(ingress, interest);
127 if (!interest.getForwardingHint().empty() &&
130 <<
" interest=" << interest.getName() <<
" reaching-producer-region");
131 const_cast<Interest&
>(interest).setForwardingHint({});
135 shared_ptr<pit::Entry> pitEntry = m_pit.
insert(interest).first;
140 if (ingress.
face.
getLinkType() == ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
144 if (hasDuplicateNonceInPit) {
146 this->onInterestLoop(ingress, interest);
151 if (!pitEntry->hasInRecords()) {
153 bind(&Forwarder::onContentStoreHit,
this, ingress, pitEntry, _1, _2),
154 bind(&Forwarder::onContentStoreMiss,
this, ingress, pitEntry, _1));
157 this->onContentStoreMiss(ingress, pitEntry, interest);
162 Forwarder::onInterestLoop(
const FaceEndpoint& ingress,
const Interest& interest)
165 if (ingress.
face.
getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
167 <<
" interest=" << interest.getName() <<
" drop");
171 NFD_LOG_DEBUG(
"onInterestLoop in=" << ingress <<
" interest=" << interest.getName()
172 <<
" send-Nack-duplicate");
176 lp::Nack nack(interest);
177 nack.setReason(lp::NackReason::DUPLICATE);
182 Forwarder::onContentStoreMiss(
const FaceEndpoint& ingress,
183 const shared_ptr<pit::Entry>& pitEntry,
const Interest& interest)
185 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName());
189 pitEntry->insertOrUpdateInRecord(ingress.
face, interest);
192 auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
193 [] (
const auto& a,
const auto& b) {
194 return a.getExpiry() < b.getExpiry();
196 auto lastExpiryFromNow = lastExpiring->getExpiry() - time::steady_clock::now();
197 this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
200 auto nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
201 if (nextHopTag !=
nullptr) {
203 Face* nextHopFace = m_faceTable.
get(*nextHopTag);
204 if (nextHopFace !=
nullptr) {
205 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName()
206 <<
" nexthop-faceid=" << nextHopFace->
getId());
209 this->onOutgoingInterest(pitEntry, *nextHopFace, interest);
215 this->dispatchToStrategy(*pitEntry,
222 Forwarder::onContentStoreHit(
const FaceEndpoint& ingress,
const shared_ptr<pit::Entry>& pitEntry,
223 const Interest& interest,
const Data& data)
225 NFD_LOG_DEBUG(
"onContentStoreHit interest=" << interest.getName());
229 data.setTag(interest.getTag<lp::PitToken>());
232 pitEntry->isSatisfied =
true;
233 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
236 this->setExpiryTimer(pitEntry, 0_ms);
239 this->dispatchToStrategy(*pitEntry,
244 Forwarder::onOutgoingInterest(
const shared_ptr<pit::Entry>& pitEntry,
245 Face& egress,
const Interest& interest)
248 if (interest.getHopLimit() == 0 && egress.
getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
249 NFD_LOG_DEBUG(
"onOutgoingInterest out=" << egress.
getId() <<
" interest=" << pitEntry->getName()
250 <<
" non-local hop-limit=0");
255 NFD_LOG_DEBUG(
"onOutgoingInterest out=" << egress.
getId() <<
" interest=" << pitEntry->getName());
258 auto it = pitEntry->insertOrUpdateOutRecord(egress, interest);
259 BOOST_ASSERT(it != pitEntry->out_end());
268 Forwarder::onInterestFinalize(
const shared_ptr<pit::Entry>& pitEntry)
270 NFD_LOG_DEBUG(
"onInterestFinalize interest=" << pitEntry->getName()
271 << (pitEntry->isSatisfied ?
" satisfied" :
" unsatisfied"));
274 this->insertDeadNonceList(*pitEntry,
nullptr);
277 if (pitEntry->isSatisfied) {
285 pitEntry->expiryTimer.cancel();
286 m_pit.
erase(pitEntry.get());
290 Forwarder::onIncomingData(
const FaceEndpoint& ingress,
const Data& data)
293 NFD_LOG_DEBUG(
"onIncomingData in=" << ingress <<
" data=" << data.getName());
294 data.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.
getId()));
298 bool isViolatingLocalhost = ingress.
face.
getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
300 if (isViolatingLocalhost) {
301 NFD_LOG_DEBUG(
"onIncomingData in=" << ingress <<
" data=" << data.getName() <<
" violates /localhost");
308 if (pitMatches.size() == 0) {
310 this->onDataUnsolicited(ingress, data);
318 if (pitMatches.size() == 1) {
319 auto& pitEntry = pitMatches.front();
321 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
324 this->setExpiryTimer(pitEntry, 0_ms);
327 this->dispatchToStrategy(*pitEntry,
331 pitEntry->isSatisfied =
true;
332 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
335 this->insertDeadNonceList(*pitEntry, &ingress.
face);
338 pitEntry->deleteOutRecord(ingress.
face);
343 std::set<Face*> pendingDownstreams;
344 auto now = time::steady_clock::now();
346 for (
const auto& pitEntry : pitMatches) {
347 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
350 for (
const pit::InRecord& inRecord : pitEntry->getInRecords()) {
351 if (inRecord.getExpiry() > now) {
352 pendingDownstreams.insert(&inRecord.getFace());
357 this->setExpiryTimer(pitEntry, 0_ms);
360 this->dispatchToStrategy(*pitEntry,
364 pitEntry->isSatisfied =
true;
365 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
368 this->insertDeadNonceList(*pitEntry, &ingress.
face);
371 pitEntry->clearInRecords();
372 pitEntry->deleteOutRecord(ingress.
face);
376 for (
const auto& pendingDownstream : pendingDownstreams) {
377 if (pendingDownstream->getId() == ingress.
face.
getId() &&
378 pendingDownstream->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
382 this->onOutgoingData(data, *pendingDownstream);
388 Forwarder::onDataUnsolicited(
const FaceEndpoint& ingress,
const Data& data)
391 auto decision = m_unsolicitedDataPolicy->decide(ingress.
face, data);
397 NFD_LOG_DEBUG(
"onDataUnsolicited in=" << ingress <<
" data=" << data.getName()
398 <<
" decision=" << decision);
403 Forwarder::onOutgoingData(
const Data& data,
Face& egress)
406 NFD_LOG_WARN(
"onOutgoingData out=(invalid) data=" << data.getName());
412 bool isViolatingLocalhost = egress.
getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
414 if (isViolatingLocalhost) {
416 <<
" violates /localhost");
431 Forwarder::onIncomingNack(
const FaceEndpoint& ingress,
const lp::Nack& nack)
434 nack.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.
getId()));
438 if (ingress.
face.
getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
440 <<
" nack=" << nack.getInterest().getName() <<
"~" << nack.getReason()
446 shared_ptr<pit::Entry> pitEntry = m_pit.
find(nack.getInterest());
448 if (pitEntry ==
nullptr) {
449 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
450 <<
"~" << nack.getReason() <<
" no-PIT-entry");
455 auto outRecord = pitEntry->getOutRecord(ingress.
face);
457 if (outRecord == pitEntry->out_end()) {
458 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
459 <<
"~" << nack.getReason() <<
" no-out-record");
464 if (nack.getInterest().getNonce() != outRecord->getLastNonce()) {
465 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
466 <<
"~" << nack.getReason() <<
" wrong-Nonce " << nack.getInterest().getNonce()
467 <<
"!=" << outRecord->getLastNonce());
471 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
472 <<
"~" << nack.getReason() <<
" OK");
475 outRecord->setIncomingNack(nack);
479 this->setExpiryTimer(pitEntry, 0_ms);
483 this->dispatchToStrategy(*pitEntry,
488 Forwarder::onOutgoingNack(
const shared_ptr<pit::Entry>& pitEntry,
489 Face& egress,
const lp::NackHeader& nack)
493 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.getReason());
498 auto inRecord = pitEntry->getInRecord(egress);
501 if (inRecord == pitEntry->in_end()) {
503 <<
" nack=" << pitEntry->getInterest().getName()
504 <<
"~" << nack.getReason() <<
" no-in-record");
509 if (egress.
getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
511 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.getReason()
517 <<
" nack=" << pitEntry->getInterest().getName()
518 <<
"~" << nack.getReason() <<
" OK");
521 lp::Nack nackPkt(inRecord->getInterest());
522 nackPkt.setHeader(nack);
525 pitEntry->deleteInRecord(egress);
535 Forwarder::onDroppedInterest(
const Face& egress,
const Interest& interest)
541 Forwarder::onNewNextHop(
const Name& prefix,
const fib::NextHop& nextHop)
552 if (nte.
getName().size() == 0 ||
560 else if (fibEntry ==
nullptr) {
561 return {
false,
true};
566 return {
false,
false};
570 for (
const auto& nte : affectedEntries) {
572 this->dispatchToStrategy(*pitEntry,
581 Forwarder::setExpiryTimer(
const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
583 BOOST_ASSERT(pitEntry);
584 duration = std::max(duration, 0_ms);
586 pitEntry->expiryTimer.cancel();
587 pitEntry->expiryTimer =
getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
591 Forwarder::insertDeadNonceList(
pit::Entry& pitEntry,
Face* upstream)
597 needDnl =
static_cast<bool>(pitEntry.
getInterest().getMustBeFresh()) &&
606 if (upstream ==
nullptr) {
609 std::for_each(outRecords.begin(), outRecords.end(), [&] (
const auto& outRecord) {
610 m_deadNonceList.
add(pitEntry.
getName(), outRecord.getLastNonce());
617 m_deadNonceList.
add(pitEntry.
getName(), outRecord->getLastNonce());
virtual void afterNewNextHop(const fib::NextHop &nextHop, const shared_ptr< pit::Entry > &pitEntry)
Trigger after new nexthop is added.
void startProcessNewNextHop(const Name &prefix, const fib::NextHop &nextHop)
start new nexthop processing
const FaceCounters & getCounters() const
bool isSatisfied
Indicates whether this PIT entry is satisfied.
OutRecordCollection::iterator getOutRecord(const Face &face)
get the out-record for face
void cleanupOnFaceRemoval(NameTree &nt, Fib &fib, Pit &pit, const Face &face)
cleanup tables when a face is destroyed
PacketCounter nInInterests
PacketCounter nUnsatisfiedInterests
signal::Signal< LinkService, Interest, EndpointId > & afterReceiveInterest
signals on Interest received
Contains information about an Interest toward an outgoing face.
PacketCounter nOutHopLimitZero
count of outgoing Interests dropped due to HopLimit == 0 on non-local faces
virtual void afterReceiveInterest(const FaceEndpoint &ingress, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry)=0
Trigger after Interest is received.
signal::Signal< Fib, Name, NextHop > afterNewNextHop
signals on Fib entry nexthop creation
static const Name & getStrategyName()
signal::Signal< LinkService, Data, EndpointId > & afterReceiveData
signals on Data received
void startProcessData(const FaceEndpoint &ingress, const Data &data)
start incoming Data processing
Face * get(FaceId id) const
get face by FaceId
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.
uint64_t EndpointId
Identifies a remote endpoint on the link.
signal::Signal< FaceTable, Face > afterAdd
Fires immediately after a face is added.
ndn::nfd::LinkType getLinkType() const
ndn::nfd::FaceScope getScope() const
PacketCounter nOutInterests
fib::Entry * getFibEntry() const
const std::vector< shared_ptr< pit::Entry > > & getPitEntries() const
represents a counter of number of packets
DropAllUnsolicitedDataPolicy DefaultUnsolicitedDataPolicy
the default UnsolicitedDataPolicy
PacketCounter nInHopLimitZero
count of incoming Interests dropped due to HopLimit == 0
virtual void afterReceiveNack(const FaceEndpoint &ingress, const lp::Nack &nack, const shared_ptr< pit::Entry > &pitEntry)
Trigger after Nack is received.
int findDuplicateNonce(const pit::Entry &pitEntry, Interest::Nonce nonce, const Face &face)
determine whether pitEntry has duplicate Nonce nonce
Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
fw::Strategy & findEffectiveStrategy(const Name &prefix) const
Get effective strategy for prefix.
Forwarder(FaceTable &faceTable)
DataMatchResult findAllDataMatches(const Data &data) const
Performs a Data match.
const Interest & getInterest() const
signal::Signal< FaceTable, Face > beforeRemove
Fires immediately before a face is removed.
Represents a face-endpoint pair in the forwarder.
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
void insert(const Data &data, bool isUnsolicited=false)
inserts a Data packet
Contains information about an Interest from an incoming face.
const Name & getName() const
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.
strategy_choice::Entry * getStrategyChoiceEntry() const
std::pair< shared_ptr< Entry >, bool > insert(const Interest &interest)
Inserts a PIT entry for interest.
const Name & getName() const
generalization of a network interface
void sendData(const Data &data)
send Data
bool hasPendingOutRecords(const pit::Entry &pitEntry)
determine whether pitEntry has any pending out-records
const Name LOCALHOST
ndn:/localhost
An entry in the name tree.
no duplicate Nonce is found
virtual void afterContentStoreHit(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
Trigger after a Data is matched in CS.
const OutRecordCollection & getOutRecords() const
static Name getDefaultStrategyName()
Represents a forwarding strategy.
This file contains common algorithms used by forwarding strategies.
fw::Strategy & getStrategy() const
#define NFD_LOG_INIT(name)
void sendNack(const lp::Nack &nack)
send Nack
virtual void afterReceiveData(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
Trigger after Data is received.
void startProcessInterest(const FaceEndpoint &ingress, const Interest &interest)
start incoming Interest processing
the Data should be cached in the ContentStore
bool has(const Name &name, Interest::Nonce nonce) const
Determines if name+nonce exists.
An unordered iterable of all PIT entries matching Data.
void erase(Entry *entry)
Deletes an entry.
signal::Signal< LinkService, lp::Nack, EndpointId > & afterReceiveNack
signals on Nack received
PacketCounter nUnsolicitedData
signal::Signal< LinkService, Interest > & onDroppedInterest
signals on Interest dropped by reliability system for exceeding allowed number of retx ...
void sendInterest(const Interest &interest)
send Interest
time::milliseconds dataFreshnessPeriod
Data freshness period.
void startProcessNack(const FaceEndpoint &ingress, const lp::Nack &nack)
start incoming Nack processing
const FaceId FACEID_CONTENT_STORE
identifies a packet comes from the ContentStore
Represents a nexthop record in a FIB entry.
PacketCounter nSatisfiedInterests
const FaceId INVALID_FACEID
indicates an invalid FaceId
void find(const Interest &interest, HitCallback &&hit, MissCallback &&miss) const
finds the best matching Data packet
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
Trigger before PIT entry is satisfied.
bool hasPitEntries() const
void add(const Name &name, Interest::Nonce nonce)
Records name+nonce.
bool wantNewNextHopTrigger() const