diff --git a/daemon/fw/access-strategy.cpp b/daemon/fw/access-strategy.cpp index 94019682..84bac93b 100644 --- a/daemon/fw/access-strategy.cpp +++ b/daemon/fw/access-strategy.cpp @@ -24,7 +24,7 @@ */ #include "access-strategy.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" #include "core/logger.hpp" namespace nfd { diff --git a/daemon/fw/pit-algorithm.cpp b/daemon/fw/algorithm.cpp similarity index 85% rename from daemon/fw/pit-algorithm.cpp rename to daemon/fw/algorithm.cpp index 3ff63b80..7a1f2ccb 100644 --- a/daemon/fw/pit-algorithm.cpp +++ b/daemon/fw/algorithm.cpp @@ -23,7 +23,7 @@ * NFD, e.g., in COPYING.md file. If not, see . */ -#include "pit-algorithm.hpp" +#include "algorithm.hpp" namespace nfd { namespace scope_prefix { @@ -33,6 +33,28 @@ const Name LOCALHOP("ndn:/localhop"); namespace fw { +bool +wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outFace) +{ + if (outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) { + // forwarding to a local face is always allowed + return false; + } + + if (scope_prefix::LOCALHOST.isPrefixOf(interest.getName())) { + // localhost Interests cannot be forwarded to a non-local face + return true; + } + + if (scope_prefix::LOCALHOP.isPrefixOf(interest.getName())) { + // localhop Interests can be forwarded to a non-local face only if it comes from a local face + return inFace.getScope() != ndn::nfd::FACE_SCOPE_LOCAL; + } + + // Interest name is not subject to scope control + return false; +} + bool violatesScope(const pit::Entry& pitEntry, const Face& outFace) { diff --git a/daemon/fw/pit-algorithm.hpp b/daemon/fw/algorithm.hpp similarity index 79% rename from daemon/fw/pit-algorithm.hpp rename to daemon/fw/algorithm.hpp index ed477254..ebf493a5 100644 --- a/daemon/fw/pit-algorithm.hpp +++ b/daemon/fw/algorithm.hpp @@ -29,13 +29,13 @@ #include "table/pit-entry.hpp" /** \file - * This file contains algorithms that operate on a PIT entry. + * This file contains common algorithms used by forwarding strategies. */ namespace nfd { -/** \brief contain Name prefix that affects namespace-based scope control - * \sa http://redmine.named-data.net/projects/nfd/wiki/ScopeControl +/** \brief contain name prefixes that affect namespace-based scope control + * \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl */ namespace scope_prefix { @@ -54,11 +54,9 @@ extern const Name LOCALHOST; * The localhop scope limits propagation to no further than the next node. * * Interest packets under prefix ndn:/localhop are restricted by these rules: - * \li Interest can come from a local face or a non-local face. - * \li If PIT entry has at least one in-record from a local face, - * it can be forwarded to local faces and non-local faces. - * \li If PIT entry has all in-records from non-local faces, - * it can only be forwarded to local faces. + * \li If an Interest is received from a local face, it can be forwarded to a non-local face. + * \li If an Interest is received from a non-local face, it cannot be forwarded to a non-local face. + * \li In either case the Interest can be forwarded to a local face. * \li PIT entry can be satisfied by Data from any source. * * Data packets under prefix ndn:/localhop are unrestricted. @@ -70,10 +68,18 @@ extern const Name LOCALHOP; namespace fw { /** \brief determine whether forwarding the Interest in \p pitEntry to \p outFace would violate scope - * \sa http://redmine.named-data.net/projects/nfd/wiki/ScopeControl + * \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl */ bool -violatesScope(const pit::Entry& pitEntry, const Face& outFace); +wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outFace); + +/** \brief determine whether forwarding the Interest in \p pitEntry to \p outFace would violate scope + * \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl + * \deprecated use violatesScope(inFace, interest, outFace) instead + */ +DEPRECATED( +bool +violatesScope(const pit::Entry& pitEntry, const Face& outFace)); /** \brief decide whether Interest can be forwarded to face * diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp index ac166f48..ebe0d08f 100644 --- a/daemon/fw/best-route-strategy.cpp +++ b/daemon/fw/best-route-strategy.cpp @@ -24,7 +24,7 @@ */ #include "best-route-strategy.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" namespace nfd { namespace fw { diff --git a/daemon/fw/best-route-strategy2.cpp b/daemon/fw/best-route-strategy2.cpp index e897b491..6bb1d428 100644 --- a/daemon/fw/best-route-strategy2.cpp +++ b/daemon/fw/best-route-strategy2.cpp @@ -24,7 +24,7 @@ */ #include "best-route-strategy2.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" #include "core/logger.hpp" namespace nfd { @@ -47,31 +47,33 @@ BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name) } /** \brief determines whether a NextHop is eligible - * \param pitEntry PIT entry + * \param inFace incoming face of current Interest + * \param interest incoming Interest * \param nexthop next hop - * \param currentDownstream incoming FaceId of current Interest + * \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 inline bool -predicate_NextHop_eligible(const shared_ptr& pitEntry, - const fib::NextHop& nexthop, FaceId currentDownstream, - bool wantUnused = false, - time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min()) +isNextHopEligible(const Face& inFace, const Interest& interest, + const fib::NextHop& nexthop, + const shared_ptr& pitEntry, + bool wantUnused = false, + time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min()) { - Face& upstream = nexthop.getFace(); + const Face& outFace = nexthop.getFace(); - // upstream is current downstream - if (upstream.getId() == currentDownstream) + // do not forward back to the same face + if (&outFace == &inFace) return false; // forwarding would violate scope - if (violatesScope(*pitEntry, upstream)) + if (wouldViolateScope(inFace, interest, outFace)) return false; if (wantUnused) { - // NextHop must not have unexpired out-record - pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(upstream); + // nexthop must not have unexpired out-record + pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(outFace); if (outRecord != pitEntry->out_end() && outRecord->getExpiry() > now) { return false; } @@ -84,14 +86,14 @@ predicate_NextHop_eligible(const shared_ptr& pitEntry, * \note It is assumed that every nexthop has an out-record. */ static inline fib::NextHopList::const_iterator -findEligibleNextHopWithEarliestOutRecord(const shared_ptr& pitEntry, +findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& interest, const fib::NextHopList& nexthops, - FaceId currentDownstream) + const shared_ptr& pitEntry) { fib::NextHopList::const_iterator found = nexthops.end(); time::steady_clock::TimePoint earliestRenewed = time::steady_clock::TimePoint::max(); for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) { - if (!predicate_NextHop_eligible(pitEntry, *it, currentDownstream)) + if (!isNextHopEligible(inFace, interest, *it, pitEntry)) continue; pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(it->getFace()); BOOST_ASSERT(outRecord != pitEntry->out_end()); @@ -121,7 +123,7 @@ BestRouteStrategy2::afterReceiveInterest(const Face& inFace, const Interest& int if (suppression == RetxSuppression::NEW) { // forward to nexthop with lowest cost except downstream it = std::find_if(nexthops.begin(), nexthops.end(), - bind(&predicate_NextHop_eligible, pitEntry, _1, inFace.getId(), + bind(&isNextHopEligible, cref(inFace), interest, _1, pitEntry, false, time::steady_clock::TimePoint::min())); if (it == nexthops.end()) { @@ -136,7 +138,7 @@ BestRouteStrategy2::afterReceiveInterest(const Face& inFace, const Interest& int } Face& outFace = it->getFace(); - this->sendInterest(pitEntry, outFace); + this->sendInterest(pitEntry, outFace, interest); NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " newPitEntry-to=" << outFace.getId()); return; @@ -144,24 +146,24 @@ BestRouteStrategy2::afterReceiveInterest(const Face& inFace, const Interest& int // find an unused upstream with lowest cost except downstream it = std::find_if(nexthops.begin(), nexthops.end(), - bind(&predicate_NextHop_eligible, pitEntry, _1, inFace.getId(), + bind(&isNextHopEligible, cref(inFace), interest, _1, pitEntry, true, time::steady_clock::now())); if (it != nexthops.end()) { Face& outFace = it->getFace(); - this->sendInterest(pitEntry, outFace); + this->sendInterest(pitEntry, outFace, interest); NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " retransmit-unused-to=" << outFace.getId()); return; } // find an eligible upstream that is used earliest - it = findEligibleNextHopWithEarliestOutRecord(pitEntry, nexthops, inFace.getId()); + it = findEligibleNextHopWithEarliestOutRecord(inFace, interest, nexthops, pitEntry); if (it == nexthops.end()) { NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " retransmitNoNextHop"); } else { Face& outFace = it->getFace(); - this->sendInterest(pitEntry, outFace); + this->sendInterest(pitEntry, outFace, interest); NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " retransmit-retry-to=" << outFace.getId()); } @@ -226,7 +228,6 @@ BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack, return; } - NFD_LOG_DEBUG(nack.getInterest() << " nack-from=" << inFace.getId() << " nack=" << nack.getReason() << " nack-to=all out-nack=" << outNack.getReason()); diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp index 9648e1bc..7e0df653 100644 --- a/daemon/fw/forwarder.cpp +++ b/daemon/fw/forwarder.cpp @@ -24,7 +24,7 @@ */ #include "forwarder.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" #include "core/logger.hpp" #include "strategy.hpp" #include "table/cleanup.hpp" diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp index 44c8c525..2821d71a 100644 --- a/daemon/fw/multicast-strategy.cpp +++ b/daemon/fw/multicast-strategy.cpp @@ -24,7 +24,7 @@ */ #include "multicast-strategy.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" namespace nfd { namespace fw { diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp index d191326a..2ae2fd05 100644 --- a/daemon/fw/ncc-strategy.cpp +++ b/daemon/fw/ncc-strategy.cpp @@ -24,7 +24,7 @@ */ #include "ncc-strategy.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" #include "core/random.hpp" namespace nfd { diff --git a/daemon/fw/retx-suppression-exponential.cpp b/daemon/fw/retx-suppression-exponential.cpp index aabc719a..28f6df5e 100644 --- a/daemon/fw/retx-suppression-exponential.cpp +++ b/daemon/fw/retx-suppression-exponential.cpp @@ -24,7 +24,7 @@ */ #include "retx-suppression-exponential.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" namespace nfd { namespace fw { diff --git a/daemon/fw/retx-suppression-fixed.cpp b/daemon/fw/retx-suppression-fixed.cpp index b8b2eb8b..d2c74dca 100644 --- a/daemon/fw/retx-suppression-fixed.cpp +++ b/daemon/fw/retx-suppression-fixed.cpp @@ -24,7 +24,7 @@ */ #include "retx-suppression-fixed.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" namespace nfd { namespace fw { diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp index 27d6735e..5de2e757 100644 --- a/daemon/fw/strategy.cpp +++ b/daemon/fw/strategy.cpp @@ -25,7 +25,7 @@ #include "strategy.hpp" #include "forwarder.hpp" -#include "pit-algorithm.hpp" +#include "algorithm.hpp" #include "core/logger.hpp" #include "core/random.hpp" diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp index bb5b6efb..4346e781 100644 --- a/daemon/fw/strategy.hpp +++ b/daemon/fw/strategy.hpp @@ -145,10 +145,12 @@ protected: // actions * \param outFace face through which to send out the Interest * \param wantNewNonce if true, a new Nonce will be generated, * rather than reusing a Nonce from one of the PIT in-records + * \deprecated use sendInterest(pitEntry, outFace, interest) instead */ + DEPRECATED( void sendInterest(const shared_ptr& pitEntry, Face& outFace, - bool wantNewNonce = false); + bool wantNewNonce = false)); /** \brief decide that a pending Interest cannot be forwarded * \param pitEntry PIT entry diff --git a/docs/doxygen.conf.in b/docs/doxygen.conf.in index c1c1ad32..174f2c09 100644 --- a/docs/doxygen.conf.in +++ b/docs/doxygen.conf.in @@ -1924,11 +1924,12 @@ PREDEFINED = DOXYGEN=1 \ BOOST_STATIC_ASSERT(x)= \ BOOST_CONCEPT_ASSERT(x)= \ BOOST_CONCEPT_REQUIRES(x)= \ + DEPRECATED(x)=x \ PUBLIC_WITH_TESTS_ELSE_PRIVATE=private \ PUBLIC_WITH_TESTS_ELSE_PROTECTED=protected \ PROTECTED_WITH_TESTS_ELSE_PRIVATE=private \ FINAL_UNLESS_WITH_TESTS=final \ - VIRTUAL_WITH_TESTS + VIRTUAL_WITH_TESTS= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/tests/daemon/fw/pit-algorithm.t.cpp b/tests/daemon/fw/algorithm.t.cpp similarity index 86% rename from tests/daemon/fw/pit-algorithm.t.cpp rename to tests/daemon/fw/algorithm.t.cpp index 0589e0d3..caebecc7 100644 --- a/tests/daemon/fw/pit-algorithm.t.cpp +++ b/tests/daemon/fw/algorithm.t.cpp @@ -23,7 +23,7 @@ * NFD, e.g., in COPYING.md file. If not, see . */ -#include "fw/pit-algorithm.hpp" +#include "fw/algorithm.hpp" #include "tests/test-common.hpp" #include "tests/daemon/face/dummy-face.hpp" @@ -35,7 +35,7 @@ namespace tests { using namespace nfd::tests; BOOST_AUTO_TEST_SUITE(Fw) -BOOST_FIXTURE_TEST_SUITE(TestPitAlgorithm, BaseFixture) +BOOST_FIXTURE_TEST_SUITE(TestAlgorithm, BaseFixture) class ScopeControlFixture : public BaseFixture { @@ -55,6 +55,40 @@ protected: shared_ptr localFace4; }; +BOOST_FIXTURE_TEST_SUITE(WouldViolateScope, ScopeControlFixture) + +BOOST_AUTO_TEST_CASE(Unrestricted) +{ + shared_ptr interest = makeInterest("ndn:/ieWRzDsCu"); + + BOOST_CHECK_EQUAL(wouldViolateScope(*nonLocalFace1, *interest, *nonLocalFace2), false); + BOOST_CHECK_EQUAL(wouldViolateScope(*nonLocalFace1, *interest, *localFace4), false); + BOOST_CHECK_EQUAL(wouldViolateScope(*localFace3, *interest, *nonLocalFace2), false); + BOOST_CHECK_EQUAL(wouldViolateScope(*localFace3, *interest, *localFace4), false); +} + +BOOST_AUTO_TEST_CASE(Localhost) +{ + shared_ptr interest = makeInterest("ndn:/localhost/5n1LzIt3"); + + // /localhost Interests from non-local faces should be rejected by incoming Interest pipeline, + // and are not tested here. + BOOST_CHECK_EQUAL(wouldViolateScope(*localFace3, *interest, *nonLocalFace2), true); + BOOST_CHECK_EQUAL(wouldViolateScope(*localFace3, *interest, *localFace4), false); +} + +BOOST_AUTO_TEST_CASE(Localhop) +{ + shared_ptr interest = makeInterest("ndn:/localhop/YcIKWCRYJ"); + + BOOST_CHECK_EQUAL(wouldViolateScope(*nonLocalFace1, *interest, *nonLocalFace2), true); + BOOST_CHECK_EQUAL(wouldViolateScope(*nonLocalFace1, *interest, *localFace4), false); + BOOST_CHECK_EQUAL(wouldViolateScope(*localFace3, *interest, *nonLocalFace2), false); + BOOST_CHECK_EQUAL(wouldViolateScope(*localFace3, *interest, *localFace4), false); +} + +BOOST_AUTO_TEST_SUITE_END() // WouldViolateScope + BOOST_FIXTURE_TEST_SUITE(ViolatesScope, ScopeControlFixture) BOOST_AUTO_TEST_CASE(Unrestricted)