fw: properly handle consumer retransmission in AsfStrategy
Do not reject an existing PIT entry if there are no
next hops during consumer retransmission
refs: #4874
Change-Id: Iea8602897e99fdf2f6fd0226b5eb74bd7a4bced1
diff --git a/daemon/fw/algorithm.cpp b/daemon/fw/algorithm.cpp
index a0c8bc4..6ea610f 100644
--- a/daemon/fw/algorithm.cpp
+++ b/daemon/fw/algorithm.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2018, Regents of the University of California,
+ * Copyright (c) 2014-2019, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -128,5 +128,51 @@
return lastOutgoing->getLastRenewed();
}
+fib::NextHopList::const_iterator
+findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& interest,
+ const fib::NextHopList& nexthops,
+ const shared_ptr<pit::Entry>& pitEntry)
+{
+ auto found = nexthops.end();
+ auto earliestRenewed = time::steady_clock::TimePoint::max();
+
+ for (auto it = nexthops.begin(); it != nexthops.end(); ++it) {
+ if (!isNextHopEligible(inFace, interest, *it, pitEntry))
+ continue;
+
+ auto outRecord = pitEntry->getOutRecord(it->getFace(), 0);
+ BOOST_ASSERT(outRecord != pitEntry->out_end());
+ if (outRecord->getLastRenewed() < earliestRenewed) {
+ found = it;
+ earliestRenewed = outRecord->getLastRenewed();
+ }
+ }
+ return found;
+}
+
+bool
+isNextHopEligible(const Face& inFace, const Interest& interest,
+ const fib::NextHop& nexthop,
+ const shared_ptr<pit::Entry>& pitEntry,
+ bool wantUnused,
+ time::steady_clock::TimePoint now)
+{
+ const Face& outFace = nexthop.getFace();
+
+ // do not forward back to the same face, unless it is ad hoc
+ if ((outFace.getId() == inFace.getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
+ (wouldViolateScope(inFace, interest, outFace)))
+ return false;
+
+ if (wantUnused) {
+ // nexthop must not have unexpired out-record
+ auto outRecord = pitEntry->getOutRecord(outFace, 0);
+ if (outRecord != pitEntry->out_end() && outRecord->getExpiry() > now) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace fw
} // namespace nfd
diff --git a/daemon/fw/algorithm.hpp b/daemon/fw/algorithm.hpp
index 7ee0f38..95d8bc5 100644
--- a/daemon/fw/algorithm.hpp
+++ b/daemon/fw/algorithm.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2018, Regents of the University of California,
+ * Copyright (c) 2014-2019, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,6 +27,7 @@
#define NFD_DAEMON_FW_PIT_ALGORITHM_HPP
#include "core/scope-prefix.hpp"
+#include "table/fib.hpp"
#include "table/pit-entry.hpp"
/** \file
@@ -83,6 +84,29 @@
time::steady_clock::TimePoint
getLastOutgoing(const pit::Entry& pitEntry);
+/** \brief pick an eligible NextHop with earliest out-record
+ * \note It is assumed that every nexthop has an out-record.
+ */
+fib::NextHopList::const_iterator
+findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& interest,
+ const fib::NextHopList& nexthops,
+ const shared_ptr<pit::Entry>& pitEntry);
+
+/** \brief determines whether a NextHop is eligible i.e. not the same inFace
+ * \param inFace incoming face of current Interest
+ * \param interest incoming Interest
+ * \param nexthop next hop
+ * \param pitEntry PIT entry
+ * \param wantUnused if true, NextHop must not have unexpired out-record
+ * \param now time::steady_clock::now(), ignored if !wantUnused
+ */
+bool
+isNextHopEligible(const Face& inFace, const Interest& interest,
+ const fib::NextHop& nexthop,
+ const shared_ptr<pit::Entry>& pitEntry,
+ bool wantUnused = false,
+ time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min());
+
} // namespace fw
} // namespace nfd
diff --git a/daemon/fw/asf-strategy.cpp b/daemon/fw/asf-strategy.cpp
index 46acaf4..e013fab 100644
--- a/daemon/fw/asf-strategy.cpp
+++ b/daemon/fw/asf-strategy.cpp
@@ -108,17 +108,24 @@
}
void
+AsfStrategy::sendAsfProbe(const FaceEndpoint& ingress, const Interest& interest,
+ const shared_ptr<pit::Entry>& pitEntry, const Face& faceToUse,
+ const fib::Entry& fibEntry)
+{
+ Face* faceToProbe = m_probing.getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
+ if (faceToProbe != nullptr) {
+ forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, true);
+ m_probing.afterForwardingProbe(fibEntry, interest);
+ }
+}
+
+void
AsfStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
// Should the Interest be suppressed?
RetxSuppressionResult suppressResult = m_retxSuppression.decidePerPitEntry(*pitEntry);
-
- switch (suppressResult) {
- case RetxSuppressionResult::NEW:
- case RetxSuppressionResult::FORWARD:
- break;
- case RetxSuppressionResult::SUPPRESS:
+ if (suppressResult == RetxSuppressionResult::SUPPRESS) {
NFD_LOG_DEBUG(interest << " from=" << ingress << " suppressed");
return;
}
@@ -126,33 +133,52 @@
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
const fib::NextHopList& nexthops = fibEntry.getNextHops();
- if (nexthops.size() == 0) {
- sendNoRouteNack(ingress, interest, pitEntry);
- this->rejectPendingInterest(pitEntry);
- return;
- }
-
- Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, ingress.face);
-
- if (faceToUse == nullptr) {
- sendNoRouteNack(ingress, interest, pitEntry);
- this->rejectPendingInterest(pitEntry);
- return;
- }
-
- NFD_LOG_TRACE("Forwarding interest to face: " << faceToUse->getId());
-
- forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
-
- // If necessary, send probe
- if (m_probing.isProbingNeeded(fibEntry, interest)) {
- Face* faceToProbe = m_probing.getFaceToProbe(ingress.face, interest, fibEntry, *faceToUse);
-
- if (faceToProbe != nullptr) {
- bool wantNewNonce = true;
- forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
- m_probing.afterForwardingProbe(fibEntry, interest);
+ if (suppressResult == RetxSuppressionResult::NEW) {
+ if (nexthops.size() == 0) {
+ // send noRouteNack if nexthop is not available
+ sendNoRouteNack(ingress, interest, pitEntry);
+ this->rejectPendingInterest(pitEntry);
+ return;
}
+
+ Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, ingress.face, pitEntry);
+
+ if (faceToUse == nullptr) {
+ sendNoRouteNack(ingress, interest, pitEntry);
+ this->rejectPendingInterest(pitEntry);
+ return;
+ }
+
+ NFD_LOG_TRACE("Forwarding interest to face: " << faceToUse->getId());
+ forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
+
+ // If necessary, send probe
+ if (m_probing.isProbingNeeded(fibEntry, interest)) {
+ sendAsfProbe(ingress, interest, pitEntry, *faceToUse, fibEntry);
+ }
+ return;
+ }
+
+ Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, ingress.face, pitEntry, false);
+ // if unused face not found, select nexthop with earliest out record
+ if (faceToUse != nullptr) {
+
+ NFD_LOG_TRACE("Forwarding interest to face: " << faceToUse->getId());
+ forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
+ // avoid probing in case of forwarding
+ return;
+ }
+
+ // find an eligible upstream that is used earliest
+ auto it = nexthops.end();
+ it = findEligibleNextHopWithEarliestOutRecord(ingress.face, interest, nexthops, pitEntry);
+ if (it == nexthops.end()) {
+ NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmitNoNextHop");
+ }
+ else {
+ auto egress = FaceEndpoint(it->getFace(), 0);
+ NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-retry-to=" << egress);
+ this->sendInterest(pitEntry, egress, interest);
}
}
@@ -201,7 +227,6 @@
bool wantNewNonce)
{
auto egress = FaceEndpoint(outFace, 0);
-
if (wantNewNonce) {
//Send probe: interest with new Nonce
Interest probeInterest(interest);
@@ -262,7 +287,8 @@
Face*
AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
- const Face& inFace)
+ const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
+ bool isInterestNew)
{
NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
@@ -286,11 +312,11 @@
}
});
+ auto now = time::steady_clock::now();
for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Face& hopFace = hop.getFace();
- if ((hopFace.getId() == inFace.getId() && hopFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
- wouldViolateScope(inFace, interest, hopFace)) {
+ if (!isNextHopEligible(inFace, interest, hop, pitEntry, !isInterestNew, now)) {
continue;
}
diff --git a/daemon/fw/asf-strategy.hpp b/daemon/fw/asf-strategy.hpp
index 2155d94..a181676 100644
--- a/daemon/fw/asf-strategy.hpp
+++ b/daemon/fw/asf-strategy.hpp
@@ -73,8 +73,15 @@
Face& outFace,
bool wantNewNonce = false);
+ void
+ sendAsfProbe(const FaceEndpoint& ingress, const Interest& interest,
+ const shared_ptr<pit::Entry>& pitEntry, const Face& faceToUse,
+ const fib::Entry& fibEntry);
+
Face*
- getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest, const Face& inFace);
+ getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
+ const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
+ bool isNewInterest = true);
void
onTimeout(const Name& interestName, const FaceId faceId);
diff --git a/daemon/fw/best-route-strategy2.cpp b/daemon/fw/best-route-strategy2.cpp
index ebab2ef..5c7d6a2 100644
--- a/daemon/fw/best-route-strategy2.cpp
+++ b/daemon/fw/best-route-strategy2.cpp
@@ -61,68 +61,6 @@
return strategyName;
}
-/** \brief determines whether a NextHop is eligible
- * \param inFace incoming face of current Interest
- * \param interest incoming Interest
- * \param nexthop next hop
- * \param pitEntry PIT entry
- * \param wantUnused if true, NextHop must not have unexpired out-record
- * \param now time::steady_clock::now(), ignored if !wantUnused
- */
-static bool
-isNextHopEligible(const Face& inFace, const Interest& interest,
- const fib::NextHop& nexthop,
- const shared_ptr<pit::Entry>& pitEntry,
- bool wantUnused = false,
- time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min())
-{
- const Face& outFace = nexthop.getFace();
-
- // do not forward back to the same face, unless it is ad hoc
- if (outFace.getId() == inFace.getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC)
- return false;
-
- // forwarding would violate scope
- if (wouldViolateScope(inFace, interest, outFace))
- return false;
-
- if (wantUnused) {
- // nexthop must not have unexpired out-record
- auto outRecord = pitEntry->getOutRecord(outFace, 0);
- if (outRecord != pitEntry->out_end() && outRecord->getExpiry() > now) {
- return false;
- }
- }
-
- return true;
-}
-
-/** \brief pick an eligible NextHop with earliest out-record
- * \note It is assumed that every nexthop has an out-record.
- */
-static fib::NextHopList::const_iterator
-findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& interest,
- const fib::NextHopList& nexthops,
- const shared_ptr<pit::Entry>& pitEntry)
-{
- auto found = nexthops.end();
- auto earliestRenewed = time::steady_clock::TimePoint::max();
-
- for (auto it = nexthops.begin(); it != nexthops.end(); ++it) {
- if (!isNextHopEligible(inFace, interest, *it, pitEntry))
- continue;
-
- auto outRecord = pitEntry->getOutRecord(it->getFace(), 0);
- BOOST_ASSERT(outRecord != pitEntry->out_end());
- if (outRecord->getLastRenewed() < earliestRenewed) {
- found = it;
- earliestRenewed = outRecord->getLastRenewed();
- }
- }
-
- return found;
-}
-
void
BestRouteStrategy2::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
@@ -155,8 +93,8 @@
}
auto egress = FaceEndpoint(it->getFace(), 0);
- this->sendInterest(pitEntry, egress, interest);
NFD_LOG_DEBUG(interest << " from=" << ingress << " newPitEntry-to=" << egress);
+ this->sendInterest(pitEntry, egress, interest);
return;
}