35 #include <ndn-cxx/lp/tags.hpp> 51 , m_measurements(m_nameTree)
52 , m_strategyChoice(*this)
54 m_faceTable.
afterAdd.connect([
this] (Face& face) {
55 face.afterReceiveInterest.connect(
56 [
this, &face] (
const Interest& interest) {
59 face.afterReceiveData.connect(
60 [
this, &face] (
const Data& data) {
63 face.afterReceiveNack.connect(
64 [
this, &face] (
const lp::Nack& nack) {
67 face.onDroppedInterest.connect(
68 [
this, &face] (
const Interest& interest) {
69 this->onDroppedInterest(
FaceEndpoint(face, 0), interest);
83 Forwarder::onIncomingInterest(
const FaceEndpoint& ingress,
const Interest& interest)
86 NFD_LOG_DEBUG(
"onIncomingInterest in=" << ingress <<
" interest=" << interest.getName());
87 interest.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.getId()));
91 bool isViolatingLocalhost = ingress.
face.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(ingress, interest);
109 if (!interest.getForwardingHint().empty() &&
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 (ingress.
face.getLinkType() == ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
126 if (hasDuplicateNonceInPit) {
128 this->onInterestLoop(ingress, interest);
133 if (!pitEntry->hasInRecords()) {
135 bind(&Forwarder::onContentStoreHit,
this, ingress, pitEntry, _1, _2),
136 bind(&Forwarder::onContentStoreMiss,
this, ingress, pitEntry, _1));
139 this->onContentStoreMiss(ingress, pitEntry, interest);
144 Forwarder::onInterestLoop(
const FaceEndpoint& ingress,
const Interest& interest)
147 if (ingress.
face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
149 <<
" interest=" << interest.getName() <<
" drop");
153 NFD_LOG_DEBUG(
"onInterestLoop in=" << ingress <<
" interest=" << interest.getName()
154 <<
" send-Nack-duplicate");
158 lp::Nack nack(interest);
159 nack.setReason(lp::NackReason::DUPLICATE);
160 ingress.
face.sendNack(nack);
164 Forwarder::onContentStoreMiss(
const FaceEndpoint& ingress,
165 const shared_ptr<pit::Entry>& pitEntry,
const Interest& interest)
167 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName());
174 pitEntry->insertOrUpdateInRecord(ingress.
face, 0, interest);
177 auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
178 [] (
const auto& a,
const auto& b) {
179 return a.getExpiry() < b.getExpiry();
181 auto lastExpiryFromNow = lastExpiring->getExpiry() - time::steady_clock::now();
182 this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
185 auto nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
186 if (nextHopTag !=
nullptr) {
188 Face* nextHopFace = m_faceTable.
get(*nextHopTag);
189 if (nextHopFace !=
nullptr) {
190 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName()
191 <<
" nexthop-faceid=" << nextHopFace->getId());
194 this->onOutgoingInterest(pitEntry,
FaceEndpoint(*nextHopFace, 0), interest);
200 this->dispatchToStrategy(*pitEntry,
205 Forwarder::onContentStoreHit(
const FaceEndpoint& ingress,
const shared_ptr<pit::Entry>& pitEntry,
206 const Interest& interest,
const Data& data)
208 NFD_LOG_DEBUG(
"onContentStoreHit interest=" << interest.getName());
214 pitEntry->isSatisfied =
true;
215 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
218 this->setExpiryTimer(pitEntry, 0_ms);
221 this->dispatchToStrategy(*pitEntry,
226 Forwarder::onOutgoingInterest(
const shared_ptr<pit::Entry>& pitEntry,
229 NFD_LOG_DEBUG(
"onOutgoingInterest out=" << egress <<
" interest=" << pitEntry->getName());
232 pitEntry->insertOrUpdateOutRecord(egress.
face, egress.
endpoint, interest);
235 egress.
face.sendInterest(interest);
240 Forwarder::onInterestFinalize(
const shared_ptr<pit::Entry>& pitEntry)
242 NFD_LOG_DEBUG(
"onInterestFinalize interest=" << pitEntry->getName()
243 << (pitEntry->isSatisfied ?
" satisfied" :
" unsatisfied"));
246 this->insertDeadNonceList(*pitEntry,
nullptr);
249 if (pitEntry->isSatisfied) {
257 pitEntry->expiryTimer.cancel();
258 m_pit.erase(pitEntry.get());
262 Forwarder::onIncomingData(
const FaceEndpoint& ingress,
const Data& data)
265 NFD_LOG_DEBUG(
"onIncomingData in=" << ingress <<
" data=" << data.getName());
266 data.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.getId()));
270 bool isViolatingLocalhost = ingress.
face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
272 if (isViolatingLocalhost) {
273 NFD_LOG_DEBUG(
"onIncomingData in=" << ingress <<
" data=" << data.getName() <<
" violates /localhost");
280 if (pitMatches.size() == 0) {
282 this->onDataUnsolicited(ingress, data);
290 if (pitMatches.size() == 1) {
291 auto& pitEntry = pitMatches.front();
293 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
296 this->setExpiryTimer(pitEntry, 0_ms);
299 this->dispatchToStrategy(*pitEntry,
303 pitEntry->isSatisfied =
true;
304 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
307 this->insertDeadNonceList(*pitEntry, &ingress.
face);
310 pitEntry->deleteOutRecord(ingress.
face, ingress.
endpoint);
315 std::set<std::pair<Face*, EndpointId>> pendingDownstreams;
316 auto now = time::steady_clock::now();
318 for (
const auto& pitEntry : pitMatches) {
319 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
322 for (
const pit::InRecord& inRecord : pitEntry->getInRecords()) {
323 if (inRecord.getExpiry() > now) {
324 pendingDownstreams.emplace(&inRecord.getFace(), inRecord.getEndpointId());
329 this->setExpiryTimer(pitEntry, 0_ms);
332 this->dispatchToStrategy(*pitEntry,
336 pitEntry->isSatisfied =
true;
337 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
340 this->insertDeadNonceList(*pitEntry, &ingress.
face);
343 pitEntry->clearInRecords();
344 pitEntry->deleteOutRecord(ingress.
face, ingress.
endpoint);
348 for (
const auto& pendingDownstream : pendingDownstreams) {
349 if (pendingDownstream.first->getId() == ingress.
face.getId() &&
350 pendingDownstream.second == ingress.
endpoint &&
351 pendingDownstream.first->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
355 this->onOutgoingData(data,
FaceEndpoint(*pendingDownstream.first, pendingDownstream.second));
361 Forwarder::onDataUnsolicited(
const FaceEndpoint& ingress,
const Data& data)
367 m_cs.insert(data,
true);
370 NFD_LOG_DEBUG(
"onDataUnsolicited in=" << ingress <<
" data=" << data.getName() <<
" decision=" << decision);
374 Forwarder::onOutgoingData(
const Data& data,
FaceEndpoint egress)
377 NFD_LOG_WARN(
"onOutgoingData out=(invalid) data=" << data.getName());
380 NFD_LOG_DEBUG(
"onOutgoingData out=" << egress <<
" data=" << data.getName());
383 bool isViolatingLocalhost = egress.
face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
385 if (isViolatingLocalhost) {
386 NFD_LOG_DEBUG(
"onOutgoingData out=" << egress <<
" data=" << data.getName() <<
" violates /localhost");
394 egress.
face.sendData(data);
399 Forwarder::onIncomingNack(
const FaceEndpoint& ingress,
const lp::Nack& nack)
402 nack.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.getId()));
406 if (ingress.
face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
408 <<
" nack=" << nack.getInterest().getName() <<
"~" << nack.getReason()
409 <<
" link-type=" << ingress.
face.getLinkType());
414 shared_ptr<pit::Entry> pitEntry = m_pit.find(nack.getInterest());
416 if (pitEntry ==
nullptr) {
417 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
418 <<
"~" << nack.getReason() <<
" no-PIT-entry");
423 auto outRecord = pitEntry->getOutRecord(ingress.
face, ingress.
endpoint);
425 if (outRecord == pitEntry->out_end()) {
426 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
427 <<
"~" << nack.getReason() <<
" no-out-record");
432 if (nack.getInterest().getNonce() != outRecord->getLastNonce()) {
433 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
434 <<
"~" << nack.getReason() <<
" wrong-Nonce " << nack.getInterest().getNonce()
435 <<
"!=" << outRecord->getLastNonce());
439 NFD_LOG_DEBUG(
"onIncomingNack in=" << ingress <<
" nack=" << nack.getInterest().getName()
440 <<
"~" << nack.getReason() <<
" OK");
443 outRecord->setIncomingNack(nack);
447 this->setExpiryTimer(pitEntry, 0_ms);
451 this->dispatchToStrategy(*pitEntry,
456 Forwarder::onOutgoingNack(
const shared_ptr<pit::Entry>& pitEntry,
461 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.getReason());
466 auto inRecord = pitEntry->getInRecord(egress.
face, egress.
endpoint);
469 if (inRecord == pitEntry->in_end()) {
471 <<
" nack=" << pitEntry->getInterest().getName()
472 <<
"~" << nack.getReason() <<
" no-in-record");
477 if (egress.
face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
479 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.getReason()
480 <<
" link-type=" << egress.
face.getLinkType());
485 <<
" nack=" << pitEntry->getInterest().getName()
486 <<
"~" << nack.getReason() <<
" OK");
489 lp::Nack nackPkt(inRecord->getInterest());
490 nackPkt.setHeader(nack);
496 egress.
face.sendNack(nackPkt);
501 Forwarder::onDroppedInterest(
const FaceEndpoint& egress,
const Interest& interest)
503 m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(egress, interest);
507 Forwarder::setExpiryTimer(
const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
509 BOOST_ASSERT(pitEntry);
510 BOOST_ASSERT(duration >= 0_ms);
512 pitEntry->expiryTimer.cancel();
513 pitEntry->expiryTimer =
getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
517 Forwarder::insertDeadNonceList(
pit::Entry& pitEntry, Face* upstream)
523 needDnl =
static_cast<bool>(pitEntry.
getInterest().getMustBeFresh()) &&
532 if (upstream ==
nullptr) {
535 std::for_each(outRecords.begin(), outRecords.end(), [&] (
const auto& outRecord) {
536 m_deadNonceList.
add(pitEntry.
getName(), outRecord.getLastNonce());
543 m_deadNonceList.
add(pitEntry.
getName(), outRecord->getLastNonce());
const EndpointId endpoint
bool isSatisfied
Indicates whether this PIT entry is satisfied.
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 FaceEndpoint &ingress, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry)=0
trigger after Interest is received
static const Name & getStrategyName()
OutRecordCollection::iterator getOutRecord(const Face &face, EndpointId endpointId)
get the out-record for face and endpointId
Face * get(FaceId id) const
get face by FaceId
void startProcessData(const FaceEndpoint &ingress, const Data &data)
start incoming Data processing
void add(const Name &name, uint32_t nonce)
Records name+nonce.
PacketCounter nOutInterests
bool has(const Name &name, uint32_t nonce) const
Determines if name+nonce exists.
DropAllUnsolicitedDataPolicy DefaultUnsolicitedDataPolicy
the default UnsolicitedDataPolicy
virtual void afterReceiveNack(const FaceEndpoint &ingress, const lp::Nack &nack, const shared_ptr< pit::Entry > &pitEntry)
trigger after Nack is received
Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
Represents a face-endpoint pair in the forwarder.
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Contains information about an Interest from an incoming face.
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
time::nanoseconds getLifetime() const
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
virtual void afterContentStoreHit(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
trigger after a Data is matched in CS
int findDuplicateNonce(const pit::Entry &pitEntry, uint32_t nonce, const Face &face)
determine whether pitEntry has duplicate Nonce nonce
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
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 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.
void startProcessNack(const FaceEndpoint &ingress, const lp::Nack &nack)
start incoming Nack processing
const OutRecordCollection & getOutRecords() const
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
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
trigger before PIT entry is satisfied