34 #include <ndn-cxx/lp/tags.hpp> 50 , m_measurements(m_nameTree)
51 , m_strategyChoice(*this)
53 m_faceTable.
afterAdd.connect([
this] (Face& face) {
54 face.afterReceiveInterest.connect(
55 [
this, &face] (
const Interest& interest) {
58 face.afterReceiveData.connect(
59 [
this, &face] (
const Data& data) {
62 face.afterReceiveNack.connect(
63 [
this, &face] (
const lp::Nack& nack) {
66 face.onDroppedInterest.connect(
67 [
this, &face] (
const Interest& interest) {
68 this->onDroppedInterest(face, interest);
82 Forwarder::onIncomingInterest(Face& inFace,
const Interest& interest)
86 " interest=" << interest.getName());
87 interest.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
91 bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
93 if (isViolatingLocalhost) {
95 " interest=" << interest.getName() <<
" violates /localhost");
101 bool hasDuplicateNonceInDnl = m_deadNonceList.
has(interest.getName(), interest.getNonce());
102 if (hasDuplicateNonceInDnl) {
104 this->onInterestLoop(inFace, interest);
109 if (!interest.getForwardingHint().empty() &&
111 NFD_LOG_DEBUG(
"onIncomingInterest face=" << inFace.getId() <<
112 " interest=" << interest.getName() <<
" reaching-producer-region");
113 const_cast<Interest&
>(interest).setForwardingHint({});
117 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
122 if (inFace.getLinkType() == ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
126 if (hasDuplicateNonceInPit) {
128 this->onInterestLoop(inFace, interest);
133 if (!pitEntry->hasInRecords()) {
135 bind(&Forwarder::onContentStoreHit,
this, std::ref(inFace), pitEntry, _1, _2),
136 bind(&Forwarder::onContentStoreMiss,
this, std::ref(inFace), pitEntry, _1));
139 this->onContentStoreMiss(inFace, pitEntry, interest);
144 Forwarder::onInterestLoop(Face& inFace,
const Interest& interest)
147 if (inFace.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
149 " interest=" << interest.getName() <<
155 " interest=" << interest.getName() <<
156 " send-Nack-duplicate");
160 lp::Nack nack(interest);
161 nack.setReason(lp::NackReason::DUPLICATE);
162 inFace.sendNack(nack);
172 Forwarder::onContentStoreMiss(
const Face& inFace,
const shared_ptr<pit::Entry>& pitEntry,
173 const Interest& interest)
175 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName());
179 pitEntry->insertOrUpdateInRecord(const_cast<Face&>(inFace), interest);
183 auto lastExpiryFromNow = lastExpiring->getExpiry() - time::steady_clock::now();
184 this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
187 shared_ptr<lp::NextHopFaceIdTag> nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
188 if (nextHopTag !=
nullptr) {
190 Face* nextHopFace = m_faceTable.
get(*nextHopTag);
191 if (nextHopFace !=
nullptr) {
192 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName() <<
" nexthop-faceid=" << nextHopFace->getId());
195 this->onOutgoingInterest(pitEntry, *nextHopFace, interest);
201 this->dispatchToStrategy(*pitEntry,
206 Forwarder::onContentStoreHit(
const Face& inFace,
const shared_ptr<pit::Entry>& pitEntry,
207 const Interest& interest,
const Data& data)
209 NFD_LOG_DEBUG(
"onContentStoreHit interest=" << interest.getName());
215 pitEntry->isSatisfied =
true;
216 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
219 this->setExpiryTimer(pitEntry, 0_ms);
222 this->dispatchToStrategy(*pitEntry,
227 Forwarder::onOutgoingInterest(
const shared_ptr<pit::Entry>& pitEntry, Face& outFace,
const Interest& interest)
229 NFD_LOG_DEBUG(
"onOutgoingInterest face=" << outFace.getId() <<
230 " interest=" << pitEntry->getName());
233 pitEntry->insertOrUpdateOutRecord(outFace, interest);
236 outFace.sendInterest(interest);
241 Forwarder::onInterestFinalize(
const shared_ptr<pit::Entry>& pitEntry)
243 NFD_LOG_DEBUG(
"onInterestFinalize interest=" << pitEntry->getName() <<
244 (pitEntry->isSatisfied ?
" satisfied" :
" unsatisfied"));
247 this->insertDeadNonceList(*pitEntry, 0);
250 if (pitEntry->isSatisfied) {
259 m_pit.erase(pitEntry.get());
263 Forwarder::onIncomingData(Face& inFace,
const Data& data)
266 NFD_LOG_DEBUG(
"onIncomingData face=" << inFace.getId() <<
" data=" << data.getName());
267 data.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
271 bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
273 if (isViolatingLocalhost) {
275 " data=" << data.getName() <<
" violates /localhost");
282 if (pitMatches.size() == 0) {
284 this->onDataUnsolicited(inFace, data);
292 if (pitMatches.size() == 1) {
293 auto& pitEntry = pitMatches.front();
295 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
298 this->setExpiryTimer(pitEntry, 0_ms);
301 this->dispatchToStrategy(*pitEntry,
305 pitEntry->isSatisfied =
true;
306 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
309 this->insertDeadNonceList(*pitEntry, &inFace);
312 pitEntry->deleteOutRecord(inFace);
317 std::set<Face*> pendingDownstreams;
318 auto now = time::steady_clock::now();
320 for (
const shared_ptr<pit::Entry>& pitEntry : pitMatches) {
321 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
324 for (
const pit::InRecord& inRecord : pitEntry->getInRecords()) {
325 if (inRecord.getExpiry() > now) {
326 pendingDownstreams.insert(&inRecord.getFace());
331 this->setExpiryTimer(pitEntry, 0_ms);
334 this->dispatchToStrategy(*pitEntry,
338 pitEntry->isSatisfied =
true;
339 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
342 this->insertDeadNonceList(*pitEntry, &inFace);
345 pitEntry->clearInRecords();
346 pitEntry->deleteOutRecord(inFace);
350 for (Face* pendingDownstream : pendingDownstreams) {
351 if (pendingDownstream->getId() == inFace.getId() &&
352 pendingDownstream->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
356 this->onOutgoingData(data, *pendingDownstream);
362 Forwarder::onDataUnsolicited(Face& inFace,
const Data& data)
368 m_cs.insert(data,
true);
372 " data=" << data.getName() <<
373 " decision=" << decision);
377 Forwarder::onOutgoingData(
const Data& data, Face& outFace)
380 NFD_LOG_WARN(
"onOutgoingData face=invalid data=" << data.getName());
383 NFD_LOG_DEBUG(
"onOutgoingData face=" << outFace.getId() <<
" data=" << data.getName());
386 bool isViolatingLocalhost = outFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
388 if (isViolatingLocalhost) {
390 " data=" << data.getName() <<
" violates /localhost");
398 outFace.sendData(data);
403 Forwarder::onIncomingNack(Face& inFace,
const lp::Nack& nack)
406 nack.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
410 if (inFace.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
412 " nack=" << nack.getInterest().getName() <<
413 "~" << nack.getReason() <<
" face-is-multi-access");
418 shared_ptr<pit::Entry> pitEntry = m_pit.find(nack.getInterest());
420 if (pitEntry ==
nullptr) {
422 " nack=" << nack.getInterest().getName() <<
423 "~" << nack.getReason() <<
" no-PIT-entry");
430 if (outRecord == pitEntry->out_end()) {
432 " nack=" << nack.getInterest().getName() <<
433 "~" << nack.getReason() <<
" no-out-record");
438 if (nack.getInterest().getNonce() != outRecord->getLastNonce()) {
440 " nack=" << nack.getInterest().getName() <<
441 "~" << nack.getReason() <<
" wrong-Nonce " <<
442 nack.getInterest().getNonce() <<
"!=" << outRecord->getLastNonce());
447 " nack=" << nack.getInterest().getName() <<
448 "~" << nack.getReason() <<
" OK");
451 outRecord->setIncomingNack(nack);
455 this->setExpiryTimer(pitEntry, 0_ms);
459 this->dispatchToStrategy(*pitEntry,
464 Forwarder::onOutgoingNack(
const shared_ptr<pit::Entry>& pitEntry,
const Face& outFace,
465 const lp::NackHeader& nack)
469 " nack=" << pitEntry->getInterest().getName() <<
470 "~" << nack.getReason() <<
" no-in-record");
478 if (inRecord == pitEntry->in_end()) {
480 " nack=" << pitEntry->getInterest().getName() <<
481 "~" << nack.getReason() <<
" no-in-record");
486 if (outFace.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
488 " nack=" << pitEntry->getInterest().getName() <<
489 "~" << nack.getReason() <<
" face-is-multi-access");
494 " nack=" << pitEntry->getInterest().getName() <<
495 "~" << nack.getReason() <<
" OK");
498 lp::Nack nackPkt(inRecord->getInterest());
499 nackPkt.setHeader(nack);
502 pitEntry->deleteInRecord(outFace);
505 const_cast<Face&
>(outFace).sendNack(nackPkt);
510 Forwarder::onDroppedInterest(Face& outFace,
const Interest& interest)
512 m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(outFace, interest);
516 Forwarder::setExpiryTimer(
const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
518 BOOST_ASSERT(pitEntry);
519 BOOST_ASSERT(duration >= 0_ms);
523 pitEntry->expiryTimer =
scheduler::schedule(duration, [=] { onInterestFinalize(pitEntry); });
527 Forwarder::insertDeadNonceList(
pit::Entry& pitEntry, Face* upstream)
533 needDnl =
static_cast<bool>(pitEntry.
getInterest().getMustBeFresh()) &&
542 if (upstream ==
nullptr) {
545 std::for_each(outRecords.begin(), outRecords.end(), [&] (
const auto& outRecord) {
546 m_deadNonceList.
add(pitEntry.
getName(), outRecord.getLastNonce());
553 m_deadNonceList.
add(pitEntry.
getName(), outRecord->getLastNonce());
bool isSatisfied
indicate if 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
virtual void afterReceiveInterest(const Face &inFace, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry)=0
trigger after Interest is received
virtual void afterReceiveData(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace, const Data &data)
trigger after Data is received
static const Name & getStrategyName()
time::steady_clock::TimePoint getExpiry() const
gives the time point this record expires
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace, const Data &data)
trigger before PIT entry is satisfied
Face * get(FaceId id) const
get face by FaceId
const time::nanoseconds & getLifetime() const
void add(const Name &name, uint32_t nonce)
records name+nonce
static bool compare_InRecord_expiry(const pit::InRecord &a, const pit::InRecord &b)
PacketCounter nOutInterests
bool has(const Name &name, uint32_t nonce) const
determines if name+nonce exists
DropAllUnsolicitedDataPolicy DefaultUnsolicitedDataPolicy
the default UnsolicitedDataPolicy
Table::const_iterator iterator
void cancel(EventId eventId)
Cancel a scheduled event.
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
contains information about an Interest from an incoming face
virtual void afterReceiveNack(const Face &inFace, const lp::Nack &nack, const shared_ptr< pit::Entry > &pitEntry)
trigger after Nack is received
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
void startProcessInterest(Face &face, const Interest &interest)
start incoming Interest processing
signal::Signal< FaceTable, Face & > afterAdd
fires after a face is added
bool hasPendingOutRecords(const pit::Entry &pitEntry)
determine whether pitEntry has any pending out-records
const Interest & getInterest() const
const Name LOCALHOST
ndn:/localhost
no duplicate Nonce is found
int findDuplicateNonce(const pit::Entry &pitEntry, uint32_t nonce, const Face &face)
determine whether pitEntry has duplicate Nonce nonce
virtual void afterContentStoreHit(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace, const Data &data)
trigger after a Data is matched in CS
static Name getDefaultStrategyName()
represents a forwarding strategy
This file contains common algorithms used by forwarding strategies.
#define NFD_LOG_INIT(name)
UnsolicitedDataDecision
a decision made by UnsolicitedDataPolicy
EventId schedule(time::nanoseconds after, const EventCallback &event)
Schedule an event.
the Data should be cached in the ContentStore
bool isInProducerRegion(const DelegationList &forwardingHint) const
determines whether an Interest has reached a producer region
An unordered iterable of all PIT entries matching Data.
time::milliseconds dataFreshnessPeriod
Data freshness period.
const OutRecordCollection & getOutRecords() const
void startProcessData(Face &face, const Data &data)
start incoming Data processing
const FaceId FACEID_CONTENT_STORE
identifies a packet comes from the ContentStore
PacketCounter nSatisfiedInterests
const FaceId INVALID_FACEID
indicates an invalid FaceId
const Name & getName() const
void startProcessNack(Face &face, const lp::Nack &nack)
start incoming Nack processing