fw: forward Interest/Data to ad hoc incoming face

Change-Id: Ia2eacf2a54d65ea4bffb607a709e1d1263547fd7
Refs: #3968
This commit is contained in:
Teng Liang
2017-04-04 22:09:39 +00:00
committed by Junxiao Shi
parent cad76b6242
commit f995f382ec
8 changed files with 250 additions and 55 deletions
+3 -2
View File
@@ -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;
}
+3 -3
View File
@@ -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
+3 -2
View File
@@ -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(),
+9 -6
View File
@@ -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) {
+155
View File
@@ -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
+3 -3
View File
@@ -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>
>;
+42 -24
View File
@@ -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));
}
}
+32 -15
View File
@@ -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;