fw: Add ASF strategy parameters n-silent-timeouts & probing-interval
refs: #4193
Change-Id: I9572425a2fdcbf67b9886c2a5b6b50a10a0856e2
diff --git a/daemon/fw/asf-measurements.cpp b/daemon/fw/asf-measurements.cpp
index e8bc8fd..e85ec3f 100644
--- a/daemon/fw/asf-measurements.cpp
+++ b/daemon/fw/asf-measurements.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-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -66,6 +66,7 @@
FaceInfo::FaceInfo()
: m_isTimeoutScheduled(false)
+ , m_nSilentTimeouts(0)
{
}
@@ -147,9 +148,9 @@
}
FaceInfo*
-NamespaceInfo::getFaceInfo(const fib::Entry& fibEntry, const Face& face)
+NamespaceInfo::getFaceInfo(const fib::Entry& fibEntry, FaceId faceId)
{
- FaceInfoTable::iterator it = m_fit.find(face.getId());
+ FaceInfoTable::iterator it = m_fit.find(faceId);
if (it != m_fit.end()) {
return &it->second;
@@ -160,17 +161,17 @@
}
FaceInfo&
-NamespaceInfo::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face)
+NamespaceInfo::getOrCreateFaceInfo(const fib::Entry& fibEntry, FaceId faceId)
{
- FaceInfoTable::iterator it = m_fit.find(face.getId());
+ FaceInfoTable::iterator it = m_fit.find(faceId);
FaceInfo* info = nullptr;
if (it == m_fit.end()) {
- const auto& pair = m_fit.insert(std::make_pair(face.getId(), FaceInfo()));
+ const auto& pair = m_fit.insert(std::make_pair(faceId, FaceInfo()));
info = &pair.first->second;
- extendFaceInfoLifetime(*info, face);
+ extendFaceInfoLifetime(*info, faceId);
}
else {
info = &it->second;
@@ -180,20 +181,20 @@
}
void
-NamespaceInfo::expireFaceInfo(nfd::face::FaceId faceId)
+NamespaceInfo::expireFaceInfo(FaceId faceId)
{
m_fit.erase(faceId);
}
void
-NamespaceInfo::extendFaceInfoLifetime(FaceInfo& info, const Face& face)
+NamespaceInfo::extendFaceInfoLifetime(FaceInfo& info, FaceId faceId)
{
// Cancel previous expiration
scheduler::cancel(info.getMeasurementExpirationEventId());
// Refresh measurement
scheduler::EventId id = scheduler::schedule(AsfMeasurements::MEASUREMENTS_LIFETIME,
- bind(&NamespaceInfo::expireFaceInfo, this, face.getId()));
+ bind(&NamespaceInfo::expireFaceInfo, this, faceId));
info.setMeasurementExpirationEventId(id);
}
@@ -209,17 +210,18 @@
}
FaceInfo*
-AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
+AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, FaceId faceId)
{
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
- return info.getFaceInfo(fibEntry, face);
+ return info.getFaceInfo(fibEntry, faceId);
}
FaceInfo&
-AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
+AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest,
+ FaceId faceId)
{
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
- return info.getOrCreateFaceInfo(fibEntry, face);
+ return info.getOrCreateFaceInfo(fibEntry, faceId);
}
NamespaceInfo*
diff --git a/daemon/fw/asf-measurements.hpp b/daemon/fw/asf-measurements.hpp
index ba858df..ee5885d 100644
--- a/daemon/fw/asf-measurements.hpp
+++ b/daemon/fw/asf-measurements.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2017, Regents of the University of California,
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -166,6 +166,18 @@
return getSrtt() != RttStats::RTT_NO_MEASUREMENT;
}
+ size_t
+ getNSilentTimeouts() const
+ {
+ return m_nSilentTimeouts;
+ }
+
+ void
+ setNSilentTimeouts(size_t nSilentTimeouts)
+ {
+ m_nSilentTimeouts = nSilentTimeouts;
+ }
+
private:
void
cancelTimeoutEvent();
@@ -183,9 +195,10 @@
// RTO associated with Interest
scheduler::EventId m_timeoutEventId;
bool m_isTimeoutScheduled;
+ size_t m_nSilentTimeouts;
};
-typedef std::unordered_map<face::FaceId, FaceInfo> FaceInfoTable;
+typedef std::unordered_map<FaceId, FaceInfo> FaceInfoTable;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -204,19 +217,19 @@
}
FaceInfo&
- getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face);
+ getOrCreateFaceInfo(const fib::Entry& fibEntry, FaceId faceId);
FaceInfo*
- getFaceInfo(const fib::Entry& fibEntry, const Face& face);
+ getFaceInfo(const fib::Entry& fibEntry, FaceId faceId);
void
- expireFaceInfo(nfd::face::FaceId faceId);
+ expireFaceInfo(FaceId faceId);
void
- extendFaceInfoLifetime(FaceInfo& info, const Face& face);
+ extendFaceInfoLifetime(FaceInfo& info, FaceId faceId);
FaceInfo*
- get(nfd::face::FaceId faceId)
+ get(FaceId faceId)
{
if (m_fit.find(faceId) != m_fit.end()) {
return &m_fit.at(faceId);
@@ -227,7 +240,7 @@
}
FaceInfoTable::iterator
- find(nfd::face::FaceId faceId)
+ find(FaceId faceId)
{
return m_fit.find(faceId);
}
@@ -239,7 +252,7 @@
}
const FaceInfoTable::iterator
- insert(nfd::face::FaceId faceId)
+ insert(FaceId faceId)
{
const auto& pair = m_fit.insert(std::make_pair(faceId, FaceInfo()));
return pair.first;
@@ -288,10 +301,10 @@
AsfMeasurements(MeasurementsAccessor& measurements);
FaceInfo*
- getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
+ getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, FaceId faceId);
FaceInfo&
- getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
+ getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, FaceId faceId);
NamespaceInfo*
getNamespaceInfo(const Name& prefix);
diff --git a/daemon/fw/asf-probing-module.cpp b/daemon/fw/asf-probing-module.cpp
index f29d0e7..24b4577 100644
--- a/daemon/fw/asf-probing-module.cpp
+++ b/daemon/fw/asf-probing-module.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-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -31,7 +31,8 @@
namespace fw {
namespace asf {
-constexpr time::seconds ProbingModule::DEFAULT_PROBING_INTERVAL;
+constexpr time::milliseconds ProbingModule::DEFAULT_PROBING_INTERVAL;
+constexpr time::milliseconds ProbingModule::MIN_PROBING_INTERVAL;
static_assert(ProbingModule::DEFAULT_PROBING_INTERVAL < AsfMeasurements::MEASUREMENTS_LIFETIME,
"ProbingModule::DEFAULT_PROBING_INTERVAL must be less than AsfMeasurements::MEASUREMENTS_LIFETIME");
@@ -91,7 +92,7 @@
continue;
}
- FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
+ FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace.getId());
// If no RTT has been recorded, probe this face
if (info == nullptr || !info->hasSrttMeasurement()) {
@@ -189,6 +190,19 @@
return dist(getGlobalRng());
}
+void
+ProbingModule::setProbingInterval(size_t probingInterval)
+{
+ if (time::milliseconds(probingInterval) >= MIN_PROBING_INTERVAL) {
+ m_probingInterval = time::milliseconds(probingInterval);
+ }
+ else {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Probing interval should be >= "
+ + to_string(MIN_PROBING_INTERVAL.count())
+ + " milliseconds"));
+ }
+}
+
} // namespace asf
} // namespace fw
} // namespace nfd
diff --git a/daemon/fw/asf-probing-module.hpp b/daemon/fw/asf-probing-module.hpp
index 055adb0..785abd8 100644
--- a/daemon/fw/asf-probing-module.hpp
+++ b/daemon/fw/asf-probing-module.hpp
@@ -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-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -55,6 +55,15 @@
void
afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest);
+ void
+ setProbingInterval(size_t probingInterval);
+
+ time::milliseconds
+ getProbingInterval() const
+ {
+ return m_probingInterval;
+ }
+
private:
// Used to associate FaceInfo with the face in a NextHop
typedef std::pair<FaceInfo*, Face*> FaceInfoFacePair;
@@ -71,10 +80,11 @@
getRandomNumber(double start, double end);
public:
- static constexpr time::seconds DEFAULT_PROBING_INTERVAL = time::seconds(60);
+ static constexpr time::milliseconds DEFAULT_PROBING_INTERVAL = time::milliseconds(60000);
+ static constexpr time::milliseconds MIN_PROBING_INTERVAL = time::milliseconds(1000);
private:
- time::seconds m_probingInterval;
+ time::milliseconds m_probingInterval;
AsfMeasurements& m_measurements;
};
diff --git a/daemon/fw/asf-strategy.cpp b/daemon/fw/asf-strategy.cpp
index 5e14e37..ab629f9 100644
--- a/daemon/fw/asf-strategy.cpp
+++ b/daemon/fw/asf-strategy.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2017, Regents of the University of California,
+ * Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -42,29 +42,72 @@
: Strategy(forwarder)
, m_measurements(getMeasurements())
, m_probing(m_measurements)
+ , m_maxSilentTimeouts(0)
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
RETX_SUPPRESSION_MAX)
{
ParsedInstanceName parsed = parseInstanceName(name);
if (!parsed.parameters.empty()) {
- BOOST_THROW_EXCEPTION(std::invalid_argument("AsfStrategy does not accept parameters"));
+ processParams(parsed.parameters);
}
+
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
BOOST_THROW_EXCEPTION(std::invalid_argument(
"AsfStrategy does not support version " + to_string(*parsed.version)));
}
this->setInstanceName(makeInstanceName(name, getStrategyName()));
+
+ NFD_LOG_DEBUG("Probing interval=" << m_probing.getProbingInterval()
+ << ", Num silent timeouts=" << m_maxSilentTimeouts);
}
const Name&
AsfStrategy::getStrategyName()
{
- static Name strategyName("/localhost/nfd/strategy/asf/%FD%02");
+ static Name strategyName("/localhost/nfd/strategy/asf/%FD%03");
return strategyName;
}
void
+AsfStrategy::processParams(const PartialName& parsed)
+{
+ for (const auto& component : parsed) {
+ std::string parsedStr(reinterpret_cast<const char*>(component.value()), component.value_size());
+ auto n = parsedStr.find("~");
+ if (n == std::string::npos) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Format is <parameter>~<value>"));
+ }
+
+ auto f = parsedStr.substr(0, n);
+ auto s = parsedStr.substr(n + 1);
+ if (f == "probing-interval") {
+ m_probing.setProbingInterval(getParamValue(f, s));
+ }
+ else if (f == "n-silent-timeouts") {
+ m_maxSilentTimeouts = getParamValue(f, s);
+ }
+ else {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Parameter should be probing-interval or n-silent-timeouts"));
+ }
+ }
+}
+
+uint64_t
+AsfStrategy::getParamValue(const std::string& param, const std::string& value)
+{
+ try {
+ if (!value.empty() && value[0] == '-')
+ BOOST_THROW_EXCEPTION(boost::bad_lexical_cast());
+
+ return boost::lexical_cast<uint64_t>(value);
+ }
+ catch (const boost::bad_lexical_cast&) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Value of " + param + " must be a non-negative integer"));
+ }
+}
+
+void
AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
@@ -132,7 +175,7 @@
faceInfo->recordRtt(pitEntry, inFace);
// Extend lifetime for measurements associated with Face
- namespaceInfo->extendFaceInfoLifetime(*faceInfo, inFace);
+ namespaceInfo->extendFaceInfoLifetime(*faceInfo, inFace.getId());
if (faceInfo->isTimeoutScheduled()) {
faceInfo->cancelTimeoutEvent(data.getName());
@@ -169,11 +212,11 @@
this->sendInterest(pitEntry, outFace, interest);
}
- FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
+ FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace.getId());
// Refresh measurements since Face is being used for forwarding
NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
- namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
+ namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace.getId());
if (!faceInfo.isTimeoutScheduled()) {
// Estimate and schedule timeout
@@ -251,7 +294,7 @@
continue;
}
- FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
+ FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace.getId());
if (info == nullptr) {
FaceStats stats = {&hopFace,
@@ -278,10 +321,8 @@
}
void
-AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
+AsfStrategy::onTimeout(const Name& interestName, const face::FaceId faceId)
{
- NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
-
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
if (namespaceInfo == nullptr) {
@@ -296,7 +337,23 @@
}
FaceInfo& faceInfo = it->second;
- faceInfo.recordTimeout(interestName);
+
+ faceInfo.setNSilentTimeouts(faceInfo.getNSilentTimeouts() + 1);
+
+ if (faceInfo.getNSilentTimeouts() <= m_maxSilentTimeouts) {
+ NFD_LOG_TRACE("FaceId " << faceId << " for " << interestName << " has timed-out "
+ << faceInfo.getNSilentTimeouts() << " time(s), ignoring");
+ // Extend lifetime for measurements associated with Face
+ namespaceInfo->extendFaceInfoLifetime(faceInfo, faceId);
+
+ if (faceInfo.isTimeoutScheduled()) {
+ faceInfo.cancelTimeoutEvent(interestName);
+ }
+ }
+ else {
+ NFD_LOG_TRACE("FaceId " << faceId << " for " << interestName << " has timed-out");
+ faceInfo.recordTimeout(interestName);
+ }
}
void
diff --git a/daemon/fw/asf-strategy.hpp b/daemon/fw/asf-strategy.hpp
index eb1c65c..b58e656 100644
--- a/daemon/fw/asf-strategy.hpp
+++ b/daemon/fw/asf-strategy.hpp
@@ -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-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -51,15 +51,15 @@
getStrategyName();
public: // triggers
- virtual void
+ void
afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry) override;
- virtual void
+ void
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace, const Data& data) override;
- virtual void
+ void
afterReceiveNack(const Face& inFace, const lp::Nack& nack,
const shared_ptr<pit::Entry>& pitEntry) override;
@@ -75,14 +75,21 @@
getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest, const Face& inFace);
void
- onTimeout(const Name& interestName, face::FaceId faceId);
+ onTimeout(const Name& interestName, const FaceId faceId);
void
sendNoRouteNack(const Face& inFace, const Interest& interest, const shared_ptr<pit::Entry>& pitEntry);
+ void
+ processParams(const PartialName& parsed);
+
+ static uint64_t
+ getParamValue(const std::string& param, const std::string& value);
+
private:
AsfMeasurements m_measurements;
ProbingModule m_probing;
+ size_t m_maxSilentTimeouts;
private:
RetxSuppressionExponential m_retxSuppression;
diff --git a/docs/conf.py b/docs/conf.py
index 4b0e9e1..6cf5ccb 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -258,6 +258,7 @@
('manpages/ndn-autoconfig.conf', 'ndn-autoconfig.conf',
u'NDN auto-configuration client configuration file', None, 5),
('manpages/nfd-autoreg', 'nfd-autoreg', u'NFD Auto-registration Server', None, 1),
+ ('manpages/nfd-asf-strategy', 'nfd-asf-strategy', u'NFD ASF Strategy', None, 7),
]
diff --git a/docs/manpages.rst b/docs/manpages.rst
index 0dd78eb..e2e0582 100644
--- a/docs/manpages.rst
+++ b/docs/manpages.rst
@@ -18,4 +18,5 @@
manpages/ndn-autoconfig-server
misc/local-prefix-discovery
manpages/nfd-autoreg
+ manpages/nfd-asf-strategy
:maxdepth: 1
diff --git a/docs/manpages/nfd-asf-strategy.rst b/docs/manpages/nfd-asf-strategy.rst
new file mode 100644
index 0000000..5a7d785
--- /dev/null
+++ b/docs/manpages/nfd-asf-strategy.rst
@@ -0,0 +1,46 @@
+nfd-asf-strategy
+================
+
+SYNOPSIS
+--------
+| nfdc strategy set prefix <PREFIX> strategy /localhost/nfd/strategy/asf/%FD%02[/probing-interval~<PROBING-INTERVAL>][/n-silent-timeouts~<N-SILENT-TIMEOUTS>]
+
+DESCRIPTION
+-----------
+
+ASF is an Adaptive Smoothed RTT-based Forwarding Strategy that chooses the best next hop based on SRTT measurement, and also periodically probes other next hops to learn their RTTs.
+
+OPTIONS
+-------
+<PROBING-INTERVAL>
+ Tells ASF how often to send a probe to determine alternative paths.
+ The value is specified in milliseconds (non-negative integer)
+ Lower value means high overhead but faster reaction.
+ Default value is 1 minute and minimum value is 1 second.
+ It is optional to specify probing-interval.
+
+<N-SILENT-TIMEOUTS>
+ ASF switches immediately to another appropriate face (if available) upon timeout.
+ This behavior may be too sensitive for application use and appropriate only for link
+ failures and not transient timeouts. So this parameter makes ASF switch paths
+ only after it has encountered the specified number of timeouts (non-negative integer).
+ Default and minimum value is 0 i.e. switch immediately.
+ It is optional to specify n-silent-timeouts.
+
+EXAMPLES
+--------
+nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf
+ Use the default values.
+
+nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf/%FD%03/probing-interval~30000
+ Set probing interval as 30 seconds.
+
+nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf/%FD%03/n-silent-timeouts~5
+ Set n-silent-timeouts as 5.
+
+nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf/%FD%03/probing-interval~30000/n-silent-timeouts~5
+ Set probing interval as 30 seconds and n-silent-timeouts as 5.
+
+SEE ALSO
+--------
+nfdc(1), nfdc-strategy(1)
\ No newline at end of file
diff --git a/docs/manpages/nfdc-strategy.rst b/docs/manpages/nfdc-strategy.rst
index 20e33f1..a9f6886 100644
--- a/docs/manpages/nfdc-strategy.rst
+++ b/docs/manpages/nfdc-strategy.rst
@@ -71,4 +71,4 @@
SEE ALSO
--------
-nfd(1), nfdc(1)
+nfd(1), nfdc(1), nfd-asf-strategy(7)
diff --git a/tests/daemon/fw/asf-strategy.t.cpp b/tests/daemon/fw/asf-strategy.t.cpp
index 750effd..5759e68 100644
--- a/tests/daemon/fw/asf-strategy.t.cpp
+++ b/tests/daemon/fw/asf-strategy.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-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -46,7 +46,8 @@
class AsfGridFixture : public UnitTestTimeFixture
{
protected:
- AsfGridFixture()
+ AsfGridFixture(Name parameters = AsfStrategy::getStrategyName())
+ : parameters(parameters)
{
/*
* +---------+
@@ -69,10 +70,10 @@
nodeC = topo.addForwarder("C");
nodeD = topo.addForwarder("D");
- topo.setStrategy<fw::AsfStrategy>(nodeA);
- topo.setStrategy<fw::AsfStrategy>(nodeB);
- topo.setStrategy<fw::AsfStrategy>(nodeC);
- topo.setStrategy<fw::AsfStrategy>(nodeD);
+ topo.setStrategy<AsfStrategy>(nodeA, Name("ndn:/"), parameters);
+ topo.setStrategy<AsfStrategy>(nodeB, Name("ndn:/"), parameters);
+ topo.setStrategy<AsfStrategy>(nodeC, Name("ndn:/"), parameters);
+ topo.setStrategy<AsfStrategy>(nodeD, Name("ndn:/"), parameters);
linkAB = topo.addLink("AB", time::milliseconds(10), {nodeA, nodeB});
linkAD = topo.addLink("AD", time::milliseconds(100), {nodeA, nodeD});
@@ -89,13 +90,14 @@
}
void
- runConsumer()
+ runConsumer(int numInterests = 30)
{
- topo.addIntervalConsumer(consumer->getClientFace(), PRODUCER_PREFIX, time::seconds(1), 30);
- this->advanceClocks(time::milliseconds(10), time::seconds(30));
+ topo.addIntervalConsumer(consumer->getClientFace(), PRODUCER_PREFIX, time::seconds(1), numInterests);
+ this->advanceClocks(time::milliseconds(10), time::seconds(numInterests));
}
protected:
+ Name parameters;
TopologyTester topo;
TopologyNode nodeA;
@@ -114,6 +116,17 @@
static const Name PRODUCER_PREFIX;
};
+class AsfStrategyParametersGridFixture : public AsfGridFixture
+{
+protected:
+ AsfStrategyParametersGridFixture()
+ : AsfGridFixture(Name(AsfStrategy::getStrategyName())
+ .append("probing-interval~30000")
+ .append("n-silent-timeouts~5"))
+ {
+ }
+};
+
const Name AsfGridFixture::PRODUCER_PREFIX = Name("ndn:/hr/C");
BOOST_FIXTURE_TEST_CASE(Basic, AsfGridFixture)
@@ -214,7 +227,7 @@
nodeD = topo.addForwarder("D");
for (TopologyNode node : {nodeA, nodeB, nodeC, nodeD}) {
- topo.setStrategy<fw::AsfStrategy>(node);
+ topo.setStrategy<AsfStrategy>(node);
}
shared_ptr<TopologyLink> linkAB = topo.addLink("AB", time::milliseconds(15), {nodeA, nodeB}),
@@ -304,6 +317,91 @@
}
}
+BOOST_FIXTURE_TEST_CASE(IgnoreTimeouts, AsfStrategyParametersGridFixture)
+{
+ // Both nodeB and nodeD have FIB entries to reach the producer
+ topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
+ topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
+
+ // Send 15 interests let it change to use the 10 ms link
+ runConsumer(15);
+
+ int outInterestsBeforeFailure = linkAD->getFace(nodeA).getCounters().nOutInterests;
+
+ // Bring down 10 ms link
+ linkAB->fail();
+
+ // Send 6 interests, first 5 will be ignored and on the 6th it will record the timeout
+ // ready to switch for the next interest
+ runConsumer(6);
+
+ // Check that link has not been switched to 100 ms because n-silent-timeouts = 5
+ BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests - outInterestsBeforeFailure, 0);
+
+ // Send 5 interests, check that 100 ms link is used
+ runConsumer(5);
+
+ BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests - outInterestsBeforeFailure, 5);
+}
+
+BOOST_FIXTURE_TEST_CASE(ProbingInterval, AsfStrategyParametersGridFixture)
+{
+ // Both nodeB and nodeD have FIB entries to reach the producer
+ topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
+ topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
+
+ // Send 6 interests let it change to use the 10 ms link
+ runConsumer(6);
+
+ shared_ptr<TopologyLink> linkAC = topo.addLink("AC", time::milliseconds(5), {nodeA, nodeD});
+ topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 1);
+
+ BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 0);
+
+ // After 30 seconds a probe would be sent that would switch make ASF switch
+ runConsumer(30);
+
+ BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 1);
+}
+
+class ParametersFixture
+{
+public:
+ void
+ checkValidity(std::string parameters, bool isCorrect)
+ {
+ Name strategyName(Name(AsfStrategy::getStrategyName()).append(parameters));
+ if (isCorrect) {
+ BOOST_CHECK_NO_THROW(make_unique<AsfStrategy>(forwarder, strategyName));
+ }
+ else {
+ BOOST_CHECK_THROW(make_unique<AsfStrategy>(forwarder, strategyName), std::invalid_argument);
+ }
+ }
+
+protected:
+ Forwarder forwarder;
+};
+
+BOOST_FIXTURE_TEST_CASE(InstantiationTest, ParametersFixture)
+{
+ checkValidity("/probing-interval~30000/n-silent-timeouts~5", true);
+ checkValidity("/n-silent-timeouts~5/probing-interval~30000", true);
+ checkValidity("/probing-interval~30000", true);
+ checkValidity("/n-silent-timeouts~5", true);
+ checkValidity("", true);
+
+ checkValidity("/probing-interval~500", false); // At least 1 seconds
+ checkValidity("/probing-interval~-5000", false);
+ checkValidity("/n-silent-timeouts~-5", false);
+ checkValidity("/n-silent-timeouts~-5/probing-interval~-30000", false);
+ checkValidity("/n-silent-timeouts", false);
+ checkValidity("/probing-interval~", false);
+ checkValidity("/~1000", false);
+ checkValidity("/probing-interval~foo", false);
+ checkValidity("/n-silent-timeouts~1~2", false);
+}
+
BOOST_AUTO_TEST_SUITE_END() // TestAsfStrategy
BOOST_AUTO_TEST_SUITE_END() // Fw
diff --git a/tests/daemon/fw/strategy-instantiation.t.cpp b/tests/daemon/fw/strategy-instantiation.t.cpp
index 391c761..cde39bb 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-2017, Regents of the University of California,
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -75,7 +75,7 @@
using Tests = boost::mpl::vector<
Test<AccessStrategy, false, 1>,
- Test<AsfStrategy, true, 2>,
+ Test<AsfStrategy, true, 3>,
Test<BestRouteStrategy, false, 1>,
Test<BestRouteStrategy2, false, 5>,
Test<ClientControlStrategy, false, 2>,
diff --git a/tests/daemon/fw/topology-tester.hpp b/tests/daemon/fw/topology-tester.hpp
index 892dc01..cbd8fd9 100644
--- a/tests/daemon/fw/topology-tester.hpp
+++ b/tests/daemon/fw/topology-tester.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2017, Regents of the University of California,
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -209,10 +209,11 @@
*/
template<typename S>
void
- setStrategy(TopologyNode i, Name prefix = Name("ndn:/"))
+ setStrategy(TopologyNode i, Name prefix = Name("ndn:/"),
+ Name instanceName = S::getStrategyName())
{
Forwarder& forwarder = this->getForwarder(i);
- choose<S>(forwarder, prefix);
+ choose<S>(forwarder, prefix, instanceName);
}
/** \brief makes a link that interconnects two or more forwarders