fw: forward Interest/Data to ad hoc incoming face
Change-Id: Ia2eacf2a54d65ea4bffb607a709e1d1263547fd7 Refs: #3968
This commit is contained in:
@@ -60,7 +60,7 @@ AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
|
||||
const Name&
|
||||
AsfStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/asf/%FD%01");
|
||||
static Name strategyName("/localhost/nfd/strategy/asf/%FD%02");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
@@ -246,7 +246,8 @@ AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest
|
||||
for (const fib::NextHop& hop : fibEntry.getNextHops()) {
|
||||
Face& hopFace = hop.getFace();
|
||||
|
||||
if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
|
||||
if ((hopFace.getId() == inFace.getId() && hopFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
|
||||
wouldViolateScope(inFace, interest, hopFace)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name)
|
||||
const Name&
|
||||
BestRouteStrategy2::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%04");
|
||||
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%05");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ isNextHopEligible(const Face& inFace, const Interest& interest,
|
||||
{
|
||||
const Face& outFace = nexthop.getFace();
|
||||
|
||||
// do not forward back to the same face
|
||||
if (&outFace == &inFace)
|
||||
// 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
|
||||
|
||||
@@ -375,7 +375,8 @@ Forwarder::onIncomingData(Face& inFace, const Data& data)
|
||||
|
||||
// foreach pending downstream
|
||||
for (Face* pendingDownstream : pendingDownstreams) {
|
||||
if (pendingDownstream == &inFace) {
|
||||
if (pendingDownstream->getId() == inFace.getId() &&
|
||||
pendingDownstream->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
|
||||
continue;
|
||||
}
|
||||
// goto outgoing Data pipeline
|
||||
@@ -595,7 +596,7 @@ Forwarder::insertDeadNonceList(pit::Entry& pitEntry, bool isSatisfied,
|
||||
}
|
||||
|
||||
// Dead Nonce List insert
|
||||
if (upstream == 0) {
|
||||
if (upstream == nullptr) {
|
||||
// insert all outgoing Nonces
|
||||
const pit::OutRecordCollection& outRecords = pitEntry.getOutRecords();
|
||||
std::for_each(outRecords.begin(), outRecords.end(),
|
||||
|
||||
@@ -58,7 +58,7 @@ MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name)
|
||||
const Name&
|
||||
MulticastStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/multicast/%FD%02");
|
||||
static Name strategyName("/localhost/nfd/strategy/multicast/%FD%03");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
@@ -85,12 +85,15 @@ MulticastStrategy::afterReceiveInterest(const Face& inFace, const Interest& inte
|
||||
for (const auto& nexthop : nexthops) {
|
||||
Face& outFace = nexthop.getFace();
|
||||
|
||||
if (&outFace != &inFace && !wouldViolateScope(inFace, interest, outFace)) {
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
|
||||
<< " pitEntry-to=" << outFace.getId());
|
||||
++nEligibleNextHops;
|
||||
if ((outFace.getId() == inFace.getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
|
||||
wouldViolateScope(inFace, interest, outFace)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
|
||||
<< " pitEntry-to=" << outFace.getId());
|
||||
++nEligibleNextHops;
|
||||
}
|
||||
|
||||
if (nEligibleNextHops == 0) {
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* This test suite checks that forwarding can relay Interest and Data via ad hoc face.
|
||||
*/
|
||||
|
||||
// Strategies that can forward Interest to an ad hoc face even if it's the downstream,
|
||||
// sorted alphabetically.
|
||||
#include "fw/asf-strategy.hpp"
|
||||
#include "fw/best-route-strategy2.hpp"
|
||||
#include "fw/multicast-strategy.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "topology-tester.hpp"
|
||||
#include <boost/mpl/vector.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace tests {
|
||||
|
||||
using namespace nfd::tests;
|
||||
|
||||
template<typename S>
|
||||
class AdHocForwardingFixture : public UnitTestTimeFixture
|
||||
{
|
||||
protected:
|
||||
AdHocForwardingFixture()
|
||||
{
|
||||
nodeA = topo.addForwarder("A");
|
||||
nodeB = topo.addForwarder("B");
|
||||
nodeC = topo.addForwarder("C");
|
||||
|
||||
for (TopologyNode node : {nodeA, nodeB, nodeC}) {
|
||||
topo.setStrategy<S>(node);
|
||||
}
|
||||
|
||||
auto wireless = topo.addLink("ABC", time::milliseconds(10), {nodeA, nodeB, nodeC},
|
||||
ndn::nfd::LINK_TYPE_AD_HOC);
|
||||
wireless->block(nodeA, nodeC);
|
||||
wireless->block(nodeC, nodeA);
|
||||
faceA = &wireless->getFace(nodeA);
|
||||
faceB = &wireless->getFace(nodeB);
|
||||
faceC = &wireless->getFace(nodeC);
|
||||
|
||||
appA = topo.addAppFace("consumer", nodeA);
|
||||
topo.registerPrefix(nodeA, *faceA, "/P");
|
||||
appC = topo.addAppFace("producer", nodeC, "/P");
|
||||
topo.addEchoProducer(appC->getClientFace(), "/P");
|
||||
}
|
||||
|
||||
protected:
|
||||
TopologyTester topo;
|
||||
TopologyNode nodeA;
|
||||
TopologyNode nodeB;
|
||||
TopologyNode nodeC;
|
||||
Face* faceA;
|
||||
Face* faceB;
|
||||
Face* faceC;
|
||||
shared_ptr<TopologyAppLink> appA;
|
||||
shared_ptr<TopologyAppLink> appC;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Fw)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestAdHocForwarding, BaseFixture)
|
||||
|
||||
using Strategies = boost::mpl::vector<
|
||||
AsfStrategy,
|
||||
BestRouteStrategy2,
|
||||
MulticastStrategy
|
||||
>;
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE_TEMPLATE(SingleNexthop, S, Strategies,
|
||||
AdHocForwardingFixture<S>)
|
||||
{
|
||||
// +---+---+
|
||||
// A B C
|
||||
//
|
||||
// A is the consumer. C is the producer.
|
||||
// B should relay Interest/Data between A and C.
|
||||
|
||||
this->topo.registerPrefix(this->nodeB, *this->faceB, "/P");
|
||||
this->topo.addIntervalConsumer(this->appA->getClientFace(), "/P", time::milliseconds(100), 10);
|
||||
this->advanceClocks(time::milliseconds(5), time::milliseconds(1200));
|
||||
|
||||
// Consumer should receive Data, and B should be relaying.
|
||||
BOOST_CHECK_EQUAL(this->faceB->getCounters().nInInterests, 10);
|
||||
BOOST_CHECK_EQUAL(this->faceB->getCounters().nOutInterests, 10);
|
||||
BOOST_CHECK_EQUAL(this->appC->getForwarderFace().getCounters().nOutInterests, 10);
|
||||
BOOST_CHECK_EQUAL(this->faceB->getCounters().nInData, 10);
|
||||
BOOST_CHECK_EQUAL(this->faceB->getCounters().nOutData, 10);
|
||||
BOOST_CHECK_EQUAL(this->appA->getForwarderFace().getCounters().nOutData, 10);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE_TEMPLATE(SecondNexthop, S, Strategies,
|
||||
AdHocForwardingFixture<S>)
|
||||
{
|
||||
// +---+---+
|
||||
// A B C
|
||||
// |
|
||||
// D
|
||||
//
|
||||
// A is the consumer. C is the producer.
|
||||
// B's first nexthop is D, but B-D link has failed, so B should relay Interest/Data between A and C.
|
||||
|
||||
TopologyNode nodeD = this->topo.addForwarder("D");
|
||||
shared_ptr<TopologyLink> linkBD = this->topo.addLink("BD", time::milliseconds(5), {this->nodeB, nodeD});
|
||||
this->topo.registerPrefix(this->nodeB, linkBD->getFace(this->nodeB), "/P", 5);
|
||||
linkBD->fail();
|
||||
this->topo.registerPrefix(this->nodeB, *this->faceB, "/P", 10);
|
||||
|
||||
// Two interval consumers are expressing Interests with same name 40ms apart,
|
||||
// so that Interests from the second interval consumer are considered retransmission.
|
||||
this->topo.addIntervalConsumer(this->appA->getClientFace(), "/P", time::milliseconds(100), 50, 1);
|
||||
this->advanceClocks(time::milliseconds(5), time::milliseconds(40));
|
||||
this->topo.addIntervalConsumer(this->appA->getClientFace(), "/P", time::milliseconds(100), 50, 1);
|
||||
this->advanceClocks(time::milliseconds(5), time::milliseconds(5400));
|
||||
|
||||
// Consumer should receive Data, and B should be relaying at least some Interest/Data.
|
||||
BOOST_CHECK_GE(this->faceB->getCounters().nInInterests, 50);
|
||||
BOOST_CHECK_GE(this->faceB->getCounters().nOutInterests, 25);
|
||||
BOOST_CHECK_GE(this->appC->getForwarderFace().getCounters().nOutInterests, 25);
|
||||
BOOST_CHECK_GE(this->faceB->getCounters().nInData, 25);
|
||||
BOOST_CHECK_GE(this->faceB->getCounters().nOutData, 25);
|
||||
BOOST_CHECK_GE(this->appA->getForwarderFace().getCounters().nOutData, 25);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestAdHocForwarding
|
||||
BOOST_AUTO_TEST_SUITE_END() // Fw
|
||||
|
||||
} // namespace tests
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -75,11 +75,11 @@ public:
|
||||
|
||||
using Tests = boost::mpl::vector<
|
||||
Test<AccessStrategy, false, 1>,
|
||||
Test<AsfStrategy, true, 1>,
|
||||
Test<AsfStrategy, true, 2>,
|
||||
Test<BestRouteStrategy, false, 1>,
|
||||
Test<BestRouteStrategy2, false, 4>,
|
||||
Test<BestRouteStrategy2, false, 5>,
|
||||
Test<ClientControlStrategy, false, 2>,
|
||||
Test<MulticastStrategy, false, 2>,
|
||||
Test<MulticastStrategy, false, 3>,
|
||||
Test<NccStrategy, false, 1>
|
||||
>;
|
||||
|
||||
|
||||
@@ -36,36 +36,43 @@ using face::InternalForwarderTransport;
|
||||
using face::InternalClientTransport;
|
||||
using face::GenericLinkService;
|
||||
|
||||
TopologyLink::TopologyLink(const time::nanoseconds& delay)
|
||||
TopologyLink::TopologyLink(time::nanoseconds delay)
|
||||
: m_isUp(true)
|
||||
{
|
||||
this->setDelay(delay);
|
||||
}
|
||||
|
||||
void
|
||||
TopologyLink::setDelay(const time::nanoseconds& delay)
|
||||
TopologyLink::block(TopologyNode i, TopologyNode j)
|
||||
{
|
||||
BOOST_ASSERT(delay > time::nanoseconds::zero());
|
||||
// zero delay does not work on OSX
|
||||
m_transports.at(i).blockedDestinations.insert(j);
|
||||
}
|
||||
|
||||
void
|
||||
TopologyLink::unblock(TopologyNode i, TopologyNode j)
|
||||
{
|
||||
m_transports.at(i).blockedDestinations.erase(j);
|
||||
}
|
||||
|
||||
void
|
||||
TopologyLink::setDelay(time::nanoseconds delay)
|
||||
{
|
||||
BOOST_ASSERT(delay > time::nanoseconds::zero()); // zero delay does not work on macOS
|
||||
m_delay = delay;
|
||||
}
|
||||
|
||||
void
|
||||
TopologyLink::addFace(TopologyNode i, shared_ptr<Face> face)
|
||||
{
|
||||
this->attachTransport(i, dynamic_cast<InternalTransportBase*>(face->getTransport()));
|
||||
m_faces[i] = face;
|
||||
}
|
||||
|
||||
void
|
||||
TopologyLink::attachTransport(TopologyNode i, InternalTransportBase* transport)
|
||||
{
|
||||
BOOST_ASSERT(transport != nullptr);
|
||||
BOOST_ASSERT(m_transports.count(i) == 0);
|
||||
auto& nodeTransport = m_transports[i];
|
||||
|
||||
m_transports[i] = transport;
|
||||
transport->afterSend.connect([this, i] (const Block& packet) { this->transmit(i, packet); });
|
||||
nodeTransport.face = face;
|
||||
|
||||
nodeTransport.transport = dynamic_cast<InternalTransportBase*>(face->getTransport());
|
||||
BOOST_ASSERT(nodeTransport.transport != nullptr);
|
||||
nodeTransport.transport->afterSend.connect(
|
||||
[this, i] (const Block& packet) { this->transmit(i, packet); });
|
||||
}
|
||||
|
||||
void
|
||||
@@ -75,12 +82,14 @@ TopologyLink::transmit(TopologyNode i, const Block& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& blockedDestinations = m_transports.at(i).blockedDestinations;
|
||||
|
||||
for (const auto& p : m_transports) {
|
||||
if (p.first == i) {
|
||||
if (p.first == i || blockedDestinations.count(p.first) > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
InternalTransportBase* recipient = p.second;
|
||||
InternalTransportBase* recipient = p.second.transport;
|
||||
this->scheduleReceive(recipient, packet);
|
||||
}
|
||||
}
|
||||
@@ -156,15 +165,17 @@ TopologyTester::addForwarder(const std::string& label)
|
||||
}
|
||||
|
||||
shared_ptr<TopologyLink>
|
||||
TopologyTester::addLink(const std::string& label, const time::nanoseconds& delay,
|
||||
TopologyTester::addLink(const std::string& label, time::nanoseconds delay,
|
||||
std::initializer_list<TopologyNode> forwarders,
|
||||
bool forceMultiAccessFace)
|
||||
ndn::nfd::LinkType linkType)
|
||||
{
|
||||
auto link = std::make_shared<TopologyLink>(delay);
|
||||
FaceUri remoteUri("topology://link/" + label);
|
||||
ndn::nfd::LinkType linkType = (forceMultiAccessFace || forwarders.size() > 2) ?
|
||||
ndn::nfd::LINK_TYPE_MULTI_ACCESS :
|
||||
ndn::nfd::LINK_TYPE_POINT_TO_POINT;
|
||||
if (linkType == ndn::nfd::LINK_TYPE_NONE) {
|
||||
linkType = forwarders.size() > 2 ? ndn::nfd::LINK_TYPE_MULTI_ACCESS :
|
||||
ndn::nfd::LINK_TYPE_POINT_TO_POINT;
|
||||
}
|
||||
BOOST_ASSERT(forwarders.size() <= 2 || linkType != ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
|
||||
for (TopologyNode i : forwarders) {
|
||||
Forwarder& forwarder = this->getForwarder(i);
|
||||
@@ -244,16 +255,23 @@ TopologyTester::addEchoProducer(ndn::Face& face, const Name& prefix)
|
||||
|
||||
void
|
||||
TopologyTester::addIntervalConsumer(ndn::Face& face, const Name& prefix,
|
||||
const time::nanoseconds& interval, size_t n)
|
||||
time::nanoseconds interval, size_t n, int seq)
|
||||
{
|
||||
Name name(prefix);
|
||||
name.appendTimestamp();
|
||||
if (seq >= 0) {
|
||||
name.appendSequenceNumber(seq);
|
||||
++seq;
|
||||
}
|
||||
else {
|
||||
name.appendTimestamp();
|
||||
}
|
||||
|
||||
shared_ptr<Interest> interest = makeInterest(name);
|
||||
face.expressInterest(*interest, nullptr, nullptr, nullptr);
|
||||
|
||||
if (n > 1) {
|
||||
scheduler::schedule(interval, bind(&TopologyTester::addIntervalConsumer, this,
|
||||
ref(face), prefix, interval, n - 1));
|
||||
ref(face), prefix, interval, n - 1, seq));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class TopologyLink : noncopyable
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
TopologyLink(const time::nanoseconds& delay);
|
||||
TopologyLink(time::nanoseconds delay);
|
||||
|
||||
/** \brief fail the link, cause packets to be dropped silently
|
||||
*/
|
||||
@@ -72,11 +72,24 @@ public:
|
||||
m_isUp = true;
|
||||
}
|
||||
|
||||
/** \brief block transmission from i to j
|
||||
*
|
||||
* Packets transmitted by i would not be delivered to j. Packets from j to i are unaffected.
|
||||
* This can be used to simulate a wireless channel.
|
||||
*/
|
||||
void
|
||||
block(TopologyNode i, TopologyNode j);
|
||||
|
||||
/** \brief unblock transmission from i to j
|
||||
*/
|
||||
void
|
||||
unblock(TopologyNode i, TopologyNode j);
|
||||
|
||||
/** \brief change the link delay
|
||||
* \param delay link delay, must be positive
|
||||
*/
|
||||
void
|
||||
setDelay(const time::nanoseconds& delay);
|
||||
setDelay(time::nanoseconds delay);
|
||||
|
||||
/** \brief attach a face to the link
|
||||
* \param i forwarder index
|
||||
@@ -90,15 +103,9 @@ public:
|
||||
Face&
|
||||
getFace(TopologyNode i)
|
||||
{
|
||||
return *m_faces.at(i);
|
||||
return *m_transports.at(i).face;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief attach a Transport onto this link
|
||||
*/
|
||||
void
|
||||
attachTransport(TopologyNode i, face::InternalTransportBase* transport);
|
||||
|
||||
private:
|
||||
void
|
||||
transmit(TopologyNode i, const Block& packet);
|
||||
@@ -109,8 +116,14 @@ private:
|
||||
private:
|
||||
bool m_isUp;
|
||||
time::nanoseconds m_delay;
|
||||
std::unordered_map<TopologyNode, face::InternalTransportBase*> m_transports;
|
||||
std::unordered_map<TopologyNode, shared_ptr<Face>> m_faces;
|
||||
|
||||
struct NodeTransport
|
||||
{
|
||||
face::InternalTransportBase* transport;
|
||||
shared_ptr<Face> face;
|
||||
std::set<TopologyNode> blockedDestinations;
|
||||
};
|
||||
std::unordered_map<TopologyNode, NodeTransport> m_transports;
|
||||
};
|
||||
|
||||
/** \brief represents a link to a local application
|
||||
@@ -203,15 +216,18 @@ public:
|
||||
}
|
||||
|
||||
/** \brief makes a link that interconnects two or more forwarders
|
||||
* \brief linkType desired link type; LINK_TYPE_NONE to use point-to-point for two forwarders
|
||||
* and multi-access for more than two forwarders; it's an error to specify
|
||||
* point-to-point when there are more than two forwarders
|
||||
*
|
||||
* A face is created on each of \p forwarders .
|
||||
* When a packet is sent onto one of the faces on this link,
|
||||
* this packet will be received by all other faces on this link after \p delay .
|
||||
*/
|
||||
shared_ptr<TopologyLink>
|
||||
addLink(const std::string& label, const time::nanoseconds& delay,
|
||||
addLink(const std::string& label, time::nanoseconds delay,
|
||||
std::initializer_list<TopologyNode> forwarders,
|
||||
bool forceMultiAccessFace = false);
|
||||
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_NONE);
|
||||
|
||||
/** \brief makes a link to local application
|
||||
*/
|
||||
@@ -246,10 +262,11 @@ public:
|
||||
|
||||
/** \brief creates a consumer application that sends \p n Interests under \p prefix
|
||||
* at \p interval fixed rate.
|
||||
* \param seq if non-negative, append sequence number instead of timestamp
|
||||
*/
|
||||
void
|
||||
addIntervalConsumer(ndn::Face& face, const Name& prefix,
|
||||
const time::nanoseconds& interval, size_t n);
|
||||
addIntervalConsumer(ndn::Face& face, const Name& prefix, time::nanoseconds interval,
|
||||
size_t n, int seq = -1);
|
||||
|
||||
private:
|
||||
bool m_wantPcap = false;
|
||||
|
||||
Reference in New Issue
Block a user