50 : m_faceTable(faceTable)
54 , m_measurements(m_nameTree)
55 , m_strategyChoice(*this)
74 [
this, &face] (
const Interest& interest) {
75 this->onDroppedInterest(
FaceEndpoint(face, 0), interest);
97 interest.
setTag(make_shared<lp::IncomingFaceIdTag>(ingress.
face.
getId()));
103 if (isViolatingLocalhost) {
105 <<
" interest=" << interest.
getName() <<
" violates /localhost");
111 bool hasDuplicateNonceInDnl = m_deadNonceList.
has(interest.
getName(), interest.
getNonce());
112 if (hasDuplicateNonceInDnl) {
114 this->onInterestLoop(ingress, interest);
122 <<
" interest=" << interest.
getName() <<
" reaching-producer-region");
123 const_cast<Interest&
>(interest).setForwardingHint({});
127 shared_ptr<pit::Entry> pitEntry = m_pit.
insert(interest).first;
136 if (hasDuplicateNonceInPit) {
138 this->onInterestLoop(ingress, interest);
139 this->dispatchToStrategy(*pitEntry,
140 [&] (
fw::Strategy& strategy) { strategy.afterReceiveLoopedInterest(ingress, interest, *pitEntry); });
145 if (!pitEntry->hasInRecords()) {
147 bind(&Forwarder::onContentStoreHit,
this, ingress, pitEntry, _1, _2),
148 bind(&Forwarder::onContentStoreMiss,
this, ingress, pitEntry, _1));
151 this->onContentStoreMiss(ingress, pitEntry, interest);
156 Forwarder::onInterestLoop(
const FaceEndpoint& ingress,
const Interest& interest)
161 <<
" interest=" << interest.getName() <<
" drop");
165 NFD_LOG_DEBUG(
"onInterestLoop in=" << ingress <<
" interest=" << interest.getName()
166 <<
" send-Nack-duplicate");
171 nack.setReason(lp::NackReason::DUPLICATE);
172 ingress.face.sendNack(nack, ingress.endpoint);
176 Forwarder::onContentStoreMiss(
const FaceEndpoint& ingress,
177 const shared_ptr<pit::Entry>& pitEntry,
const Interest& interest)
179 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName());
184 pitEntry->insertOrUpdateInRecord(ingress.face, interest);
187 auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
188 [] (
const auto& a,
const auto& b) {
189 return a.getExpiry() < b.getExpiry();
192 this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
196 if (nextHopTag !=
nullptr) {
198 Face* nextHopFace = m_faceTable.
get(*nextHopTag);
199 if (nextHopFace !=
nullptr) {
200 NFD_LOG_DEBUG(
"onContentStoreMiss interest=" << interest.getName()
201 <<
" nexthop-faceid=" << nextHopFace->getId());
204 this->onOutgoingInterest(pitEntry, FaceEndpoint(*nextHopFace, 0), interest);
210 this->dispatchToStrategy(*pitEntry,
212 strategy.afterReceiveInterest(FaceEndpoint(ingress.face, 0), interest, pitEntry);
217 Forwarder::onContentStoreHit(
const FaceEndpoint& ingress,
const shared_ptr<pit::Entry>& pitEntry,
220 NFD_LOG_DEBUG(
"onContentStoreHit interest=" << interest.getName());
227 pitEntry->isSatisfied =
true;
228 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
231 this->setExpiryTimer(pitEntry, 0_ms);
234 this->dispatchToStrategy(*pitEntry,
235 [&] (
fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, FaceEndpoint(*m_csFace, 0), data); });
238 this->dispatchToStrategy(*pitEntry,
239 [&] (
fw::Strategy& strategy) { strategy.afterContentStoreHit(pitEntry, ingress, data); });
243 Forwarder::onOutgoingInterest(
const shared_ptr<pit::Entry>& pitEntry,
244 const FaceEndpoint& egress,
const Interest& interest)
246 NFD_LOG_DEBUG(
"onOutgoingInterest out=" << egress <<
" interest=" << pitEntry->getName());
249 pitEntry->insertOrUpdateOutRecord(egress.face, interest);
252 egress.face.sendInterest(interest, egress.endpoint);
257 Forwarder::onInterestFinalize(
const shared_ptr<pit::Entry>& pitEntry)
259 NFD_LOG_DEBUG(
"onInterestFinalize interest=" << pitEntry->getName()
260 << (pitEntry->isSatisfied ?
" satisfied" :
" unsatisfied"));
262 if (!pitEntry->isSatisfied) {
267 this->insertDeadNonceList(*pitEntry,
nullptr);
270 if (pitEntry->isSatisfied) {
278 pitEntry->expiryTimer.cancel();
279 m_pit.
erase(pitEntry.get());
283 Forwarder::onIncomingData(
const FaceEndpoint& ingress,
const Data& data)
286 NFD_LOG_DEBUG(
"onIncomingData in=" << ingress <<
" data=" << data.getName());
287 data.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
293 if (isViolatingLocalhost) {
294 NFD_LOG_DEBUG(
"onIncomingData in=" << ingress <<
" data=" << data.getName() <<
" violates /localhost");
301 if (pitMatches.size() == 0) {
303 this->onDataUnsolicited(ingress, data);
311 if (pitMatches.size() == 1) {
312 auto& pitEntry = pitMatches.front();
314 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
317 this->setExpiryTimer(pitEntry, 0_ms);
321 this->dispatchToStrategy(*pitEntry,
322 [&] (
fw::Strategy& strategy) { strategy.afterReceiveData(pitEntry, ingress, data); });
325 pitEntry->isSatisfied =
true;
326 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
329 this->insertDeadNonceList(*pitEntry, &ingress.face);
332 pitEntry->deleteOutRecord(ingress.face);
337 std::set<std::pair<Face*, EndpointId>> pendingDownstreams;
340 for (
const auto& pitEntry : pitMatches) {
341 NFD_LOG_DEBUG(
"onIncomingData matching=" << pitEntry->getName());
344 for (
const pit::InRecord& inRecord : pitEntry->getInRecords()) {
345 if (inRecord.getExpiry() > now) {
346 pendingDownstreams.emplace(&inRecord.getFace(), 0);
351 this->setExpiryTimer(pitEntry, 0_ms);
355 this->dispatchToStrategy(*pitEntry,
356 [&] (
fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, ingress, data); });
359 pitEntry->isSatisfied =
true;
360 pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
363 this->insertDeadNonceList(*pitEntry, &ingress.face);
366 pitEntry->clearInRecords();
367 pitEntry->deleteOutRecord(ingress.face);
371 for (
const auto& pendingDownstream : pendingDownstreams) {
372 if (pendingDownstream.first->getId() == ingress.face.getId() &&
373 pendingDownstream.second == ingress.endpoint &&
378 this->onOutgoingData(data, FaceEndpoint(*pendingDownstream.first, pendingDownstream.second));
384 Forwarder::onDataUnsolicited(
const FaceEndpoint& ingress,
const Data& data)
393 NFD_LOG_DEBUG(
"onDataUnsolicited in=" << ingress <<
" data=" << data.getName() <<
" decision=" << decision);
397 Forwarder::onOutgoingData(
const Data& data,
const FaceEndpoint& egress)
400 NFD_LOG_WARN(
"onOutgoingData out=(invalid) data=" << data.getName());
403 NFD_LOG_DEBUG(
"onOutgoingData out=" << egress <<
" data=" << data.getName());
408 if (isViolatingLocalhost) {
409 NFD_LOG_DEBUG(
"onOutgoingData out=" << egress <<
" data=" << data.getName() <<
" violates /localhost");
417 egress.face.sendData(data, egress.endpoint);
422 Forwarder::onIncomingNack(
const FaceEndpoint& ingress,
const lp::Nack& nack)
425 nack.
setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
432 <<
" link-type=" << ingress.face.getLinkType());
439 if (pitEntry ==
nullptr) {
441 <<
"~" << nack.
getReason() <<
" no-PIT-entry");
446 auto outRecord = pitEntry->getOutRecord(ingress.face);
448 if (outRecord == pitEntry->out_end()) {
450 <<
"~" << nack.
getReason() <<
" no-out-record");
458 <<
"!=" << outRecord->getLastNonce());
466 outRecord->setIncomingNack(nack);
470 this->setExpiryTimer(pitEntry, 0_ms);
474 this->dispatchToStrategy(*pitEntry,
475 [&] (
fw::Strategy& strategy) { strategy.afterReceiveNack(ingress, nack, pitEntry); });
479 Forwarder::onOutgoingNack(
const shared_ptr<pit::Entry>& pitEntry,
484 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.
getReason());
489 auto inRecord = pitEntry->getInRecord(egress.face);
492 if (inRecord == pitEntry->in_end()) {
494 <<
" nack=" << pitEntry->getInterest().getName()
495 <<
"~" << nack.
getReason() <<
" no-in-record");
502 <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.
getReason()
503 <<
" link-type=" << egress.face.getLinkType());
508 <<
" nack=" << pitEntry->getInterest().getName()
512 lp::Nack nackPkt(inRecord->getInterest());
513 nackPkt.setHeader(nack);
516 pitEntry->deleteInRecord(egress.face);
519 egress.face.sendNack(nackPkt, egress.endpoint);
524 Forwarder::onDroppedInterest(
const FaceEndpoint& egress,
const Interest& interest)
530 Forwarder::onNewNextHop(
const Name& prefix,
const fib::NextHop& nextHop)
533 [&] (
const name_tree::Entry& nte) -> std::pair<bool, bool> {
534 const fib::Entry* fibEntry = nte.getFibEntry();
536 if (nte.getStrategyChoiceEntry() !=
nullptr) {
537 strategy = &nte.getStrategyChoiceEntry()->getStrategy();
541 if (nte.getName().size() == 0 ||
542 (strategy !=
nullptr && strategy->wantNewNextHopTrigger() &&
543 fibEntry ==
nullptr && nte.hasPitEntries())) {
549 else if (fibEntry ==
nullptr) {
550 return {
false,
true};
555 return {
false,
false};
559 for (
const auto& nte : affectedEntries) {
560 for (
const auto& pitEntry : nte.getPitEntries()) {
561 this->dispatchToStrategy(*pitEntry,
563 strategy.afterNewNextHop(nextHop, pitEntry);
570 Forwarder::setExpiryTimer(
const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
572 BOOST_ASSERT(pitEntry);
573 BOOST_ASSERT(duration >= 0_ms);
575 pitEntry->expiryTimer.cancel();
576 pitEntry->expiryTimer =
getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
580 Forwarder::insertDeadNonceList(pit::Entry& pitEntry,
Face* upstream)
584 if (pitEntry.isSatisfied) {
585 BOOST_ASSERT(pitEntry.dataFreshnessPeriod >= 0_ms);
586 needDnl =
static_cast<bool>(pitEntry.getInterest().getMustBeFresh()) &&
587 pitEntry.dataFreshnessPeriod < m_deadNonceList.getLifetime();
595 if (upstream ==
nullptr) {
597 const auto& outRecords = pitEntry.getOutRecords();
598 std::for_each(outRecords.begin(), outRecords.end(), [&] (
const auto& outRecord) {
599 m_deadNonceList.add(pitEntry.getName(), outRecord.getLastNonce());
604 auto outRecord = pitEntry.getOutRecord(*upstream);
605 if (outRecord != pitEntry.getOutRecords().end()) {
606 m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());