fw: Dispatch pending interests on new nexhop in multicast strategy
Change-Id: Ifac7b27c9943bd164d0a6579edc68fb959ebe887
Refs: #4931
diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp
index 7c12041..1b36e16 100644
--- a/daemon/fw/multicast-strategy.cpp
+++ b/daemon/fw/multicast-strategy.cpp
@@ -83,12 +83,36 @@
}
NFD_LOG_DEBUG(interest << " from=" << ingress << " pitEntry-to=" << outFace.getId());
- bool wasSent = this->sendInterest(pitEntry, outFace, interest) != nullptr;
- if (wasSent && suppressResult == RetxSuppressionResult::FORWARD) {
- m_retxSuppression.incrementIntervalForOutRecord(*pitEntry->getOutRecord(outFace));
+ auto* sentOutRecord = this->sendInterest(pitEntry, outFace, interest);
+ if (sentOutRecord && suppressResult == RetxSuppressionResult::FORWARD) {
+ m_retxSuppression.incrementIntervalForOutRecord(*sentOutRecord);
}
}
}
+void
+MulticastStrategy::afterNewNextHop(const fib::NextHop& nextHop,
+ const shared_ptr<pit::Entry>& pitEntry)
+{
+ // no need to check for suppression, as it is a new next hop
+
+ auto nextHopFaceId = nextHop.getFace().getId();
+ auto& interest = pitEntry->getInterest();
+
+ // try to find an incoming face record that doesn't violate scope restrictions
+ for (const auto& r : pitEntry->getInRecords()) {
+ auto& inFace = r.getFace();
+ if (isNextHopEligible(inFace, interest, nextHop, pitEntry)) {
+
+ NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " pitEntry-to=" << nextHopFaceId);
+ this->sendInterest(pitEntry, nextHop.getFace(), interest);
+
+ break; // just one eligible incoming face record is enough
+ }
+ }
+
+ // if nothing found, the interest will not be forwarded
+}
+
} // namespace fw
} // namespace nfd
diff --git a/daemon/fw/multicast-strategy.hpp b/daemon/fw/multicast-strategy.hpp
index b5bfb2d..7ef0080 100644
--- a/daemon/fw/multicast-strategy.hpp
+++ b/daemon/fw/multicast-strategy.hpp
@@ -47,6 +47,9 @@
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry) override;
+ void
+ afterNewNextHop(const fib::NextHop& nextHop, const shared_ptr<pit::Entry>& pitEntry) override;
+
private:
RetxSuppressionExponential m_retxSuppression;
diff --git a/tests/daemon/fw/multicast-strategy.t.cpp b/tests/daemon/fw/multicast-strategy.t.cpp
index d9a749c..0ab54ef 100644
--- a/tests/daemon/fw/multicast-strategy.t.cpp
+++ b/tests/daemon/fw/multicast-strategy.t.cpp
@@ -28,6 +28,7 @@
#include "tests/test-common.hpp"
#include "tests/daemon/face/dummy-face.hpp"
+#include "choose-strategy.hpp"
#include "strategy-tester.hpp"
#include "topology-tester.hpp"
@@ -42,7 +43,8 @@
{
protected:
MulticastStrategyFixture()
- : face1(make_shared<DummyFace>())
+ : strategy(choose<MulticastStrategyTester>(forwarder))
+ , face1(make_shared<DummyFace>())
, face2(make_shared<DummyFace>())
, face3(make_shared<DummyFace>())
{
@@ -54,7 +56,7 @@
protected:
FaceTable faceTable;
Forwarder forwarder{faceTable};
- MulticastStrategyTester strategy{forwarder};
+ MulticastStrategyTester& strategy;
Fib& fib{forwarder.getFib()};
Pit& pit{forwarder.getPit()};
@@ -209,6 +211,218 @@
BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 0);
}
+BOOST_AUTO_TEST_CASE(ForwardAsync)
+{
+ fib::Entry& fibEntry = *fib.insert(Name()).first;
+ fib.addOrUpdateNextHop(fibEntry, *face1, 0);
+ fib.addOrUpdateNextHop(fibEntry, *face2, 0);
+
+ shared_ptr<Interest> interest = makeInterest("ndn:/H0D6i5fc");
+ shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
+ pitEntry->insertOrUpdateInRecord(*face1, *interest);
+
+ strategy.afterReceiveInterest(FaceEndpoint(*face1, 0), *interest, pitEntry);
+ BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 0);
+ BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 1);
+
+ fib.addOrUpdateNextHop(fibEntry, *face3, 0);
+ BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 0);
+ BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 2);
+}
+
+BOOST_AUTO_TEST_SUITE(LocalhopScope)
+
+class ForwardAsyncFixture : public MulticastStrategyFixture
+{
+protected:
+ shared_ptr<Face> inFace1;
+ shared_ptr<Face> inFace2;
+ shared_ptr<Face> fibFace1;
+ shared_ptr<Face> fibFace2;
+ shared_ptr<Face> newFibFace;
+
+ size_t expectedInterests = 0;
+};
+
+class BasicNonLocal : public ForwardAsyncFixture
+{
+protected:
+ BasicNonLocal()
+ {
+ inFace1 = face1;
+ // inFace2 = nullptr;
+ fibFace1 = face1;
+ fibFace2 = face2;
+ newFibFace = face3;
+ expectedInterests = 0; // anything received on non-local face can only be sent to local face
+ }
+};
+
+class NewFibLocal : public ForwardAsyncFixture
+{
+protected:
+ NewFibLocal()
+ {
+ inFace1 = face1;
+ // inFace2 = nullptr;
+ fibFace1 = face1;
+ fibFace2 = face2;
+ newFibFace = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+ expectedInterests = 1;
+
+ faceTable.add(newFibFace);
+ }
+};
+
+class InFaceLocal : public ForwardAsyncFixture
+{
+protected:
+ InFaceLocal()
+ {
+ inFace1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+ // inFace2 = nullptr;
+ fibFace1 = face1;
+ fibFace2 = face2;
+ newFibFace = face3;
+ expectedInterests = 1;
+
+ faceTable.add(inFace1);
+ }
+};
+
+class InFaceLocalSameNewFace : public ForwardAsyncFixture
+{
+protected:
+ InFaceLocalSameNewFace()
+ {
+ inFace1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+ // inFace2 = nullptr;
+ fibFace1 = face1;
+ fibFace2 = face2;
+ newFibFace = inFace1;
+ expectedInterests = 0;
+
+ faceTable.add(inFace1);
+ }
+};
+
+class InFaceLocalAdHocSameNewFace : public ForwardAsyncFixture
+{
+protected:
+ InFaceLocalAdHocSameNewFace()
+ {
+ inFace1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL,
+ ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+ ndn::nfd::LINK_TYPE_AD_HOC);
+ // inFace2 = nullptr;
+ fibFace1 = face1;
+ fibFace2 = face2;
+ newFibFace = inFace1;
+ expectedInterests = 1;
+
+ faceTable.add(inFace1);
+ }
+};
+
+class InFaceLocalAndNonLocal1 : public ForwardAsyncFixture
+{
+protected:
+ InFaceLocalAndNonLocal1()
+ {
+ inFace1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+ inFace2 = face1;
+ fibFace1 = face1;
+ fibFace2 = face2;
+ newFibFace = face3;
+ expectedInterests = 1;
+
+ faceTable.add(inFace1);
+ }
+};
+
+class InFaceLocalAndNonLocal2 : public ForwardAsyncFixture
+{
+protected:
+ InFaceLocalAndNonLocal2()
+ {
+ inFace1 = face1;
+ inFace2 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+ fibFace1 = face1;
+ fibFace2 = face2;
+ newFibFace = face3;
+ expectedInterests = 1;
+
+ faceTable.add(inFace2);
+ }
+};
+
+class InFaceSelection1 : public ForwardAsyncFixture
+{
+protected:
+ InFaceSelection1()
+ {
+ inFace1 = face1;
+ // inFace2 = nullptr;
+ fibFace1 = face3;
+ fibFace2 = face2;
+ newFibFace = face1;
+
+ expectedInterests = 0;
+ }
+};
+
+class InFaceSelection2 : public ForwardAsyncFixture
+{
+protected:
+ InFaceSelection2()
+ {
+ inFace1 = face2;
+ inFace2 = face1;
+ fibFace1 = face2;
+ fibFace2 = face3;
+ newFibFace = face1;
+
+ // this test will trigger the check for additional branch, but it
+ // still is not going to pass the localhop check
+ expectedInterests = 0;
+ }
+};
+
+using Tests = boost::mpl::vector<
+ BasicNonLocal,
+ NewFibLocal,
+ InFaceLocal,
+ InFaceLocalSameNewFace,
+ InFaceLocalAdHocSameNewFace,
+ InFaceLocalAndNonLocal1,
+ InFaceLocalAndNonLocal2,
+ InFaceSelection1,
+ InFaceSelection2
+>;
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(ForwardAsync, T, Tests, T)
+{
+ fib::Entry& fibEntry = *this->fib.insert(Name("/localhop")).first;
+ this->fib.addOrUpdateNextHop(fibEntry, *this->fibFace1, 0);
+ this->fib.addOrUpdateNextHop(fibEntry, *this->fibFace2, 0);
+
+ shared_ptr<Interest> interest = makeInterest("ndn:/localhop/H0D6i5fc");
+ shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
+ pitEntry->insertOrUpdateInRecord(*this->inFace1, *interest);
+ this->strategy.afterReceiveInterest(FaceEndpoint(*this->inFace1, 0), *interest, pitEntry);
+
+ if (this->inFace2 != nullptr) {
+ shared_ptr<Interest> interest2 = makeInterest("ndn:/localhop/H0D6i5fc");
+ pitEntry->insertOrUpdateInRecord(*this->inFace2, *interest2);
+ this->strategy.afterReceiveInterest(FaceEndpoint(*this->inFace2, 0), *interest2, pitEntry);
+ }
+
+ this->strategy.sendInterestHistory.clear();
+ this->fib.addOrUpdateNextHop(fibEntry, *this->newFibFace, 0);
+ BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), this->expectedInterests);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // LocalhopScope
BOOST_AUTO_TEST_SUITE_END() // TestMulticastStrategy
BOOST_AUTO_TEST_SUITE_END() // Fw