diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp index d053482e..9543e6f1 100644 --- a/daemon/fw/multicast-strategy.cpp +++ b/daemon/fw/multicast-strategy.cpp @@ -34,9 +34,15 @@ NFD_REGISTER_STRATEGY(MulticastStrategy); NFD_LOG_INIT("MulticastStrategy"); +const time::milliseconds MulticastStrategy::RETX_SUPPRESSION_INITIAL(10); +const time::milliseconds MulticastStrategy::RETX_SUPPRESSION_MAX(250); + MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name) : Strategy(forwarder) , ProcessNackTraits(this) + , m_retxSuppression(RETX_SUPPRESSION_INITIAL, + RetxSuppressionExponential::DEFAULT_MULTIPLIER, + RETX_SUPPRESSION_MAX) { ParsedInstanceName parsed = parseInstanceName(name); if (!parsed.parameters.empty()) { @@ -52,7 +58,7 @@ MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name) const Name& MulticastStrategy::getStrategyName() { - static Name strategyName("/localhost/nfd/strategy/multicast/%FD%01"); + static Name strategyName("/localhost/nfd/strategy/multicast/%FD%02"); return strategyName; } @@ -60,8 +66,14 @@ void MulticastStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest, const shared_ptr& pitEntry) { - if (hasPendingOutRecords(*pitEntry)) { - // not a new Interest, don't forward + // Should the Interest be suppressed? + RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry); + switch (suppressResult) { + case RetxSuppression::NEW: + case RetxSuppression::FORWARD: + break; + case RetxSuppression::SUPPRESS: + NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed"); return; } diff --git a/daemon/fw/multicast-strategy.hpp b/daemon/fw/multicast-strategy.hpp index 7e77d72d..d75e3a15 100644 --- a/daemon/fw/multicast-strategy.hpp +++ b/daemon/fw/multicast-strategy.hpp @@ -28,6 +28,7 @@ #include "strategy.hpp" #include "process-nack-traits.hpp" +#include "retx-suppression-exponential.hpp" namespace nfd { namespace fw { @@ -54,6 +55,11 @@ public: private: friend ProcessNackTraits; + RetxSuppressionExponential m_retxSuppression; + +PUBLIC_WITH_TESTS_ELSE_PRIVATE: + static const time::milliseconds RETX_SUPPRESSION_INITIAL; + static const time::milliseconds RETX_SUPPRESSION_MAX; }; } // namespace fw diff --git a/tests/daemon/fw/multicast-strategy.t.cpp b/tests/daemon/fw/multicast-strategy.t.cpp index be879301..07e854cc 100644 --- a/tests/daemon/fw/multicast-strategy.t.cpp +++ b/tests/daemon/fw/multicast-strategy.t.cpp @@ -38,7 +38,7 @@ using namespace nfd::tests; typedef StrategyTester MulticastStrategyTester; NFD_REGISTER_STRATEGY(MulticastStrategyTester); -class MulticastStrategyFixture : public BaseFixture +class MulticastStrategyFixture : public UnitTestTimeFixture { protected: MulticastStrategyFixture() @@ -91,23 +91,34 @@ BOOST_AUTO_TEST_CASE(Forward2) BOOST_CHECK_EQUAL_COLLECTIONS(sentInterestFaceIds.begin(), sentInterestFaceIds.end(), expectedInterestFaceIds.begin(), expectedInterestFaceIds.end()); - // Check retransmission suppression, sendInterestHistory should remain 2 - strategy.afterReceiveInterest(*face3, *interest, pitEntry); - BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 2); -} + const time::nanoseconds TICK = time::duration_cast( + MulticastStrategy::RETX_SUPPRESSION_INITIAL * 0.1); -BOOST_AUTO_TEST_CASE(RejectScope) -{ - fib::Entry& fibEntry = *fib.insert("ndn:/localhop/uS09bub6tm").first; - fibEntry.addNextHop(*face2, 0); + // downstream retransmits frequently, but the strategy should not send Interests + // more often than DEFAULT_MIN_RETX_INTERVAL + scheduler::EventId retxFrom4Evt; + size_t nSentLast = strategy.sendInterestHistory.size(); + time::steady_clock::TimePoint timeSentLast = time::steady_clock::now(); + function periodicalRetxFrom4; // let periodicalRetxFrom4 lambda capture itself + periodicalRetxFrom4 = [&] { + pitEntry->insertOrUpdateInRecord(*face3, *interest); + strategy.afterReceiveInterest(*face3, *interest, pitEntry); - shared_ptr interest = makeInterest("ndn:/localhop/uS09bub6tm/eG3MMoP6z"); - shared_ptr pitEntry = pit.insert(*interest).first; - pitEntry->insertOrUpdateInRecord(*face1, *interest); + size_t nSent = strategy.sendInterestHistory.size(); + if (nSent > nSentLast) { + // Multicast strategy should multicast the interest to other two faces + BOOST_CHECK_EQUAL(nSent - nSentLast, 2); + time::steady_clock::TimePoint timeSent = time::steady_clock::now(); + BOOST_CHECK_GE(timeSent - timeSentLast, TICK * 8); + nSentLast = nSent; + timeSentLast = timeSent; + } - strategy.afterReceiveInterest(*face1, *interest, pitEntry); - BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 1); - BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 0); + retxFrom4Evt = scheduler::schedule(TICK * 5, periodicalRetxFrom4); + }; + periodicalRetxFrom4(); + this->advanceClocks(TICK, MulticastStrategy::RETX_SUPPRESSION_MAX * 16); + scheduler::cancel(retxFrom4Evt); } BOOST_AUTO_TEST_CASE(RejectLoopback) diff --git a/tests/daemon/fw/strategy-instantiation.t.cpp b/tests/daemon/fw/strategy-instantiation.t.cpp index 21ab9a54..0e012b45 100644 --- a/tests/daemon/fw/strategy-instantiation.t.cpp +++ b/tests/daemon/fw/strategy-instantiation.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -79,7 +79,7 @@ using Tests = boost::mpl::vector< Test, Test, Test, - Test, + Test, Test >;