fw: add strategy parameters to configure exponential retx suppression
Supported by ASF, BestRoute, and Multicast strategies Refs: #4924 Change-Id: I215d9212d90b93fa622cc65278703dc5198d0c9d
This commit is contained in:
1 parent
deb5427bb4
commit
1ef93d0316
21 files changed
+384
-188
No files matched your search
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -171,10 +171,10 @@ ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t n
|
||||
}
|
||||
|
||||
void
|
||||
ProbingModule::setProbingInterval(size_t probingInterval)
|
||||
ProbingModule::setProbingInterval(time::milliseconds probingInterval)
|
||||
{
|
||||
if (time::milliseconds(probingInterval) >= MIN_PROBING_INTERVAL) {
|
||||
m_probingInterval = time::milliseconds(probingInterval);
|
||||
if (probingInterval >= MIN_PROBING_INTERVAL) {
|
||||
m_probingInterval = probingInterval;
|
||||
}
|
||||
else {
|
||||
NDN_THROW(std::invalid_argument("Probing interval must be >= " +
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
afterForwardingProbe(const fib::Entry& fibEntry, const Name& interestName);
|
||||
|
||||
void
|
||||
setProbingInterval(size_t probingInterval);
|
||||
setProbingInterval(time::milliseconds probingInterval);
|
||||
|
||||
time::milliseconds
|
||||
getProbingInterval() const
|
||||
|
||||
+14
-55
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -35,28 +35,27 @@ namespace asf {
|
||||
NFD_LOG_INIT(AsfStrategy);
|
||||
NFD_REGISTER_STRATEGY(AsfStrategy);
|
||||
|
||||
const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
|
||||
const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, m_measurements(getMeasurements())
|
||||
, m_probing(m_measurements)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
processParams(parsed.parameters);
|
||||
}
|
||||
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
NDN_THROW(std::invalid_argument(
|
||||
"AsfStrategy does not support version " + to_string(*parsed.version)));
|
||||
}
|
||||
|
||||
StrategyParameters params = parseParameters(parsed.parameters);
|
||||
m_retxSuppression = RetxSuppressionExponential::construct(params);
|
||||
auto probingInterval = params.getOrDefault<time::milliseconds::rep>("probing-interval",
|
||||
m_probing.getProbingInterval().count());
|
||||
m_probing.setProbingInterval(time::milliseconds(probingInterval));
|
||||
m_nMaxTimeouts = params.getOrDefault<size_t>("max-timeouts", m_nMaxTimeouts);
|
||||
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
|
||||
NDN_LOG_DEBUG(*m_retxSuppression);
|
||||
NFD_LOG_DEBUG("probing-interval=" << m_probing.getProbingInterval()
|
||||
<< " max-timeouts=" << m_nMaxTimeouts);
|
||||
}
|
||||
@@ -68,46 +67,6 @@ AsfStrategy::getStrategyName()
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
getParamValue(const std::string& param, const std::string& value)
|
||||
{
|
||||
try {
|
||||
if (!value.empty() && value[0] == '-')
|
||||
NDN_THROW(boost::bad_lexical_cast());
|
||||
|
||||
return boost::lexical_cast<uint64_t>(value);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
NDN_THROW(std::invalid_argument("Value of " + param + " must be a non-negative integer"));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
NDN_THROW(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 == "max-timeouts") {
|
||||
m_nMaxTimeouts = getParamValue(f, s);
|
||||
if (m_nMaxTimeouts <= 0)
|
||||
NDN_THROW(std::invalid_argument("max-timeouts should be greater than 0"));
|
||||
}
|
||||
else {
|
||||
NDN_THROW(std::invalid_argument("Parameter should be probing-interval or max-timeouts"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
@@ -131,7 +90,7 @@ AsfStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint&
|
||||
|
||||
auto* faceToUse = getBestFaceForForwarding(interest, ingress.face, fibEntry, pitEntry, false);
|
||||
if (faceToUse != nullptr) {
|
||||
auto suppressResult = m_retxSuppression.decidePerUpstream(*pitEntry, *faceToUse);
|
||||
auto suppressResult = m_retxSuppression->decidePerUpstream(*pitEntry, *faceToUse);
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
// Cannot be sent on this face, interest was received within the suppression window
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress
|
||||
@@ -143,7 +102,7 @@ AsfStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint&
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " forward-to=" << faceToUse->getId());
|
||||
auto* outRecord = forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
|
||||
if (outRecord && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*outRecord);
|
||||
m_retxSuppression->incrementIntervalForOutRecord(*outRecord);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -158,7 +117,7 @@ AsfStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint&
|
||||
return;
|
||||
}
|
||||
auto& outFace = it->getFace();
|
||||
auto suppressResult = m_retxSuppression.decidePerUpstream(*pitEntry, outFace);
|
||||
auto suppressResult = m_retxSuppression->decidePerUpstream(*pitEntry, outFace);
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress
|
||||
<< " retry-to=" << outFace.getId() << " suppressed");
|
||||
@@ -169,7 +128,7 @@ AsfStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint&
|
||||
// were already attached to this face in the previous forwarding
|
||||
auto* outRecord = sendInterest(interest, outFace, pitEntry);
|
||||
if (outRecord && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*outRecord);
|
||||
m_retxSuppression->incrementIntervalForOutRecord(*outRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,10 +26,10 @@
|
||||
#ifndef NFD_DAEMON_FW_ASF_STRATEGY_HPP
|
||||
#define NFD_DAEMON_FW_ASF_STRATEGY_HPP
|
||||
|
||||
#include "strategy.hpp"
|
||||
#include "asf-measurements.hpp"
|
||||
#include "asf-probing-module.hpp"
|
||||
#include "fw/retx-suppression-exponential.hpp"
|
||||
#include "fw/strategy.hpp"
|
||||
#include "retx-suppression-exponential.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
@@ -65,9 +65,6 @@ public: // triggers
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private:
|
||||
void
|
||||
processParams(const PartialName& parsed);
|
||||
|
||||
pit::OutRecord*
|
||||
forwardInterest(const Interest& interest, Face& outFace, const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
@@ -89,12 +86,11 @@ private:
|
||||
|
||||
private:
|
||||
AsfMeasurements m_measurements;
|
||||
ProbingModule m_probing;
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
size_t m_nMaxTimeouts = 3;
|
||||
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
std::unique_ptr<RetxSuppressionExponential> m_retxSuppression;
|
||||
ProbingModule m_probing;
|
||||
size_t m_nMaxTimeouts = 3;
|
||||
};
|
||||
|
||||
} // namespace asf
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -33,25 +33,22 @@ namespace fw {
|
||||
NFD_LOG_INIT(BestRouteStrategy);
|
||||
NFD_REGISTER_STRATEGY(BestRouteStrategy);
|
||||
|
||||
const time::milliseconds BestRouteStrategy::RETX_SUPPRESSION_INITIAL(10);
|
||||
const time::milliseconds BestRouteStrategy::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
BestRouteStrategy::BestRouteStrategy(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()) {
|
||||
NDN_THROW(std::invalid_argument("BestRouteStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
NDN_THROW(std::invalid_argument(
|
||||
"BestRouteStrategy does not support version " + to_string(*parsed.version)));
|
||||
}
|
||||
|
||||
StrategyParameters params = parseParameters(parsed.parameters);
|
||||
m_retxSuppression = RetxSuppressionExponential::construct(params);
|
||||
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
|
||||
NDN_LOG_DEBUG(*m_retxSuppression);
|
||||
}
|
||||
|
||||
const Name&
|
||||
@@ -65,7 +62,7 @@ void
|
||||
BestRouteStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
RetxSuppressionResult suppression = m_retxSuppression.decidePerPitEntry(*pitEntry);
|
||||
RetxSuppressionResult suppression = m_retxSuppression->decidePerPitEntry(*pitEntry);
|
||||
if (suppression == RetxSuppressionResult::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " suppressed");
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -70,9 +70,7 @@ public: // triggers
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
std::unique_ptr<RetxSuppressionExponential> m_retxSuppression;
|
||||
|
||||
friend ProcessNackTraits<BestRouteStrategy>;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -34,24 +34,21 @@ 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)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
NDN_THROW(std::invalid_argument("MulticastStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
NDN_THROW(std::invalid_argument(
|
||||
"MulticastStrategy does not support version " + to_string(*parsed.version)));
|
||||
}
|
||||
|
||||
StrategyParameters params = parseParameters(parsed.parameters);
|
||||
m_retxSuppression = RetxSuppressionExponential::construct(params);
|
||||
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
|
||||
NDN_LOG_DEBUG(*m_retxSuppression);
|
||||
}
|
||||
|
||||
const Name&
|
||||
@@ -71,7 +68,7 @@ MulticastStrategy::afterReceiveInterest(const Interest& interest, const FaceEndp
|
||||
for (const auto& nexthop : nexthops) {
|
||||
Face& outFace = nexthop.getFace();
|
||||
|
||||
RetxSuppressionResult suppressResult = m_retxSuppression.decidePerUpstream(*pitEntry, outFace);
|
||||
RetxSuppressionResult suppressResult = m_retxSuppression->decidePerUpstream(*pitEntry, outFace);
|
||||
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " to=" << outFace.getId() << " suppressed");
|
||||
@@ -85,7 +82,7 @@ MulticastStrategy::afterReceiveInterest(const Interest& interest, const FaceEndp
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " pitEntry-to=" << outFace.getId());
|
||||
auto* sentOutRecord = this->sendInterest(interest, outFace, pitEntry);
|
||||
if (sentOutRecord && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*sentOutRecord);
|
||||
m_retxSuppression->incrementIntervalForOutRecord(*sentOutRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -51,12 +51,8 @@ public: // triggers
|
||||
void
|
||||
afterNewNextHop(const fib::NextHop& nextHop, const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private:
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
std::unique_ptr<RetxSuppressionExponential> m_retxSuppression;
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -28,11 +28,13 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
const RetxSuppressionExponential::Duration RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL = 1_ms;
|
||||
const RetxSuppressionExponential::Duration RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL = 10_ms;
|
||||
const RetxSuppressionExponential::Duration RetxSuppressionExponential::DEFAULT_MAX_INTERVAL = 250_ms;
|
||||
const float RetxSuppressionExponential::DEFAULT_MULTIPLIER = 2.0f;
|
||||
|
||||
class RetxSuppressionExponential::PitInfo final : public StrategyInfo
|
||||
namespace {
|
||||
|
||||
class PitInfo final : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
@@ -42,7 +44,7 @@ public:
|
||||
}
|
||||
|
||||
explicit
|
||||
PitInfo(const Duration& initialInterval)
|
||||
PitInfo(const RetxSuppressionExponential::Duration& initialInterval)
|
||||
: suppressionInterval(initialInterval)
|
||||
{
|
||||
}
|
||||
@@ -51,19 +53,27 @@ public:
|
||||
/** \brief if last transmission occurred within suppressionInterval,
|
||||
* retransmission will be suppressed
|
||||
*/
|
||||
Duration suppressionInterval;
|
||||
RetxSuppressionExponential::Duration suppressionInterval;
|
||||
};
|
||||
|
||||
RetxSuppressionExponential::RetxSuppressionExponential(const Duration& initialInterval,
|
||||
float multiplier,
|
||||
const Duration& maxInterval)
|
||||
} // namespace
|
||||
|
||||
RetxSuppressionExponential::RetxSuppressionExponential(Duration initialInterval,
|
||||
Duration maxInterval,
|
||||
float multiplier)
|
||||
: m_initialInterval(initialInterval)
|
||||
, m_multiplier(multiplier)
|
||||
, m_maxInterval(maxInterval)
|
||||
, m_multiplier(multiplier)
|
||||
{
|
||||
BOOST_ASSERT(initialInterval > 0_us);
|
||||
BOOST_ASSERT(multiplier >= 1.0f);
|
||||
BOOST_ASSERT(maxInterval >= initialInterval);
|
||||
if (m_initialInterval <= 0_ns) {
|
||||
NDN_THROW(std::invalid_argument("Retx suppression initial interval must be > 0"));
|
||||
}
|
||||
if (m_maxInterval < m_initialInterval) {
|
||||
NDN_THROW(std::invalid_argument("Retx suppression max interval must be >= initial interval"));
|
||||
}
|
||||
if (m_multiplier < 1.0f) {
|
||||
NDN_THROW(std::invalid_argument("Retx suppression multiplier must be >= 1"));
|
||||
}
|
||||
}
|
||||
|
||||
RetxSuppressionResult
|
||||
@@ -123,5 +133,18 @@ RetxSuppressionExponential::incrementIntervalForOutRecord(pit::OutRecord& outRec
|
||||
time::duration_cast<Duration>(pi->suppressionInterval * m_multiplier));
|
||||
}
|
||||
|
||||
std::unique_ptr<RetxSuppressionExponential>
|
||||
RetxSuppressionExponential::construct(const StrategyParameters& params)
|
||||
{
|
||||
auto init = params.getOrDefault<Duration::rep>("retx-suppression-initial",
|
||||
RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL.count());
|
||||
auto max = params.getOrDefault<Duration::rep>("retx-suppression-max",
|
||||
RetxSuppressionExponential::DEFAULT_MAX_INTERVAL.count());
|
||||
auto mult = params.getOrDefault<float>("retx-suppression-multiplier",
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER);
|
||||
|
||||
return make_unique<RetxSuppressionExponential>(Duration(init), Duration(max), mult);
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -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-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -28,27 +28,30 @@
|
||||
|
||||
#include "algorithm.hpp"
|
||||
#include "retx-suppression.hpp"
|
||||
#include "strategy.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief a retransmission suppression decision algorithm that
|
||||
* suppresses retransmissions using exponential backoff
|
||||
/**
|
||||
* \brief A retransmission suppression decision algorithm that suppresses
|
||||
* retransmissions using exponential backoff.
|
||||
*
|
||||
* The i-th retransmission will be suppressed if the last transmission (out-record)
|
||||
* occurred within MIN(initialInterval * multiplier^(i-1), maxInterval)
|
||||
* The i-th retransmission will be suppressed if the last transmission (out-record)
|
||||
* occurred within `MIN(initialInterval * multiplier^(i-1), maxInterval)`.
|
||||
*/
|
||||
class RetxSuppressionExponential
|
||||
{
|
||||
public:
|
||||
/** \brief time granularity
|
||||
/**
|
||||
* \brief Time granularity.
|
||||
*/
|
||||
typedef time::microseconds Duration;
|
||||
using Duration = time::milliseconds;
|
||||
|
||||
explicit
|
||||
RetxSuppressionExponential(const Duration& initialInterval = DEFAULT_INITIAL_INTERVAL,
|
||||
float multiplier = DEFAULT_MULTIPLIER,
|
||||
const Duration& maxInterval = DEFAULT_MAX_INTERVAL);
|
||||
RetxSuppressionExponential(Duration initialInterval = DEFAULT_INITIAL_INTERVAL,
|
||||
Duration maxInterval = DEFAULT_MAX_INTERVAL,
|
||||
float multiplier = DEFAULT_MULTIPLIER);
|
||||
|
||||
/** \brief determines whether Interest is a retransmission per pit entry
|
||||
* and if so, whether it shall be forwarded or suppressed
|
||||
@@ -67,20 +70,27 @@ public:
|
||||
void
|
||||
incrementIntervalForOutRecord(pit::OutRecord& outRecord);
|
||||
|
||||
public:
|
||||
/** \brief StrategyInfo on pit::Entry
|
||||
*/
|
||||
class PitInfo;
|
||||
static std::unique_ptr<RetxSuppressionExponential>
|
||||
construct(const StrategyParameters& params);
|
||||
|
||||
private: // non-member operators (hidden friends)
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, const RetxSuppressionExponential& retxSupp)
|
||||
{
|
||||
return os << "RetxSuppressionExponential initial-interval=" << retxSupp.m_initialInterval
|
||||
<< " max-interval=" << retxSupp.m_maxInterval
|
||||
<< " multiplier=" << retxSupp.m_multiplier;
|
||||
}
|
||||
|
||||
public:
|
||||
static const Duration DEFAULT_INITIAL_INTERVAL;
|
||||
static const float DEFAULT_MULTIPLIER;
|
||||
static const Duration DEFAULT_MAX_INTERVAL;
|
||||
static const float DEFAULT_MULTIPLIER;
|
||||
|
||||
private:
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
const Duration m_initialInterval;
|
||||
const float m_multiplier;
|
||||
const Duration m_maxInterval;
|
||||
const float m_multiplier;
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
|
||||
+26
-3
@@ -140,6 +140,29 @@ Strategy::makeInstanceName(const Name& input, const Name& strategyName)
|
||||
return hasVersion ? input : Name(input).append(strategyName.at(-1));
|
||||
}
|
||||
|
||||
StrategyParameters
|
||||
Strategy::parseParameters(const PartialName& params)
|
||||
{
|
||||
StrategyParameters parsed;
|
||||
|
||||
for (const auto& component : params) {
|
||||
auto sep = std::find(component.value_begin(), component.value_end(), '~');
|
||||
if (sep == component.value_end()) {
|
||||
NDN_THROW(std::invalid_argument("Strategy parameters format is (<parameter>~<value>)*"));
|
||||
}
|
||||
|
||||
std::string p(component.value_begin(), sep);
|
||||
std::advance(sep, 1);
|
||||
std::string v(sep, component.value_end());
|
||||
if (p.empty() || v.empty()) {
|
||||
NDN_THROW(std::invalid_argument("Strategy parameter name and value cannot be empty"));
|
||||
}
|
||||
parsed[std::move(p)] = std::move(v);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
Strategy::Strategy(Forwarder& forwarder)
|
||||
: afterAddFace(forwarder.m_faceTable.afterAdd)
|
||||
, beforeRemoveFace(forwarder.m_faceTable.beforeRemove)
|
||||
@@ -299,7 +322,7 @@ Strategy::lookupFib(const pit::Entry& pitEntry) const
|
||||
for (const auto& delegation : fh) {
|
||||
fibEntry = &fib.findLongestPrefixMatch(delegation);
|
||||
if (fibEntry->hasNextHops()) {
|
||||
if (fibEntry->getPrefix().size() == 0) {
|
||||
if (fibEntry->getPrefix().empty()) {
|
||||
// in consumer region, return the default route
|
||||
NFD_LOG_TRACE("lookupFib inConsumerRegion found=" << fibEntry->getPrefix());
|
||||
}
|
||||
@@ -309,9 +332,9 @@ Strategy::lookupFib(const pit::Entry& pitEntry) const
|
||||
}
|
||||
return *fibEntry;
|
||||
}
|
||||
BOOST_ASSERT(fibEntry->getPrefix().size() == 0); // only ndn:/ FIB entry can have zero nexthop
|
||||
BOOST_ASSERT(fibEntry->getPrefix().empty()); // only ndn:/ FIB entry can have zero nexthop
|
||||
}
|
||||
BOOST_ASSERT(fibEntry != nullptr && fibEntry->getPrefix().size() == 0);
|
||||
BOOST_ASSERT(fibEntry != nullptr && fibEntry->getPrefix().empty());
|
||||
return *fibEntry; // only occurs if no delegation finds a FIB nexthop
|
||||
}
|
||||
|
||||
|
||||
+58
-5
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -32,6 +32,8 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
class StrategyParameters;
|
||||
|
||||
/**
|
||||
* \brief Represents a forwarding strategy
|
||||
*/
|
||||
@@ -66,7 +68,7 @@ public: // registry
|
||||
canCreate(const Name& instanceName);
|
||||
|
||||
/** \return A strategy instance created from \p instanceName
|
||||
* \retval nullptr if !canCreate(instanceName)
|
||||
* \retval nullptr if `canCreate(instanceName) == false`
|
||||
* \throw std::invalid_argument strategy type constructor does not accept
|
||||
* specified version or parameters
|
||||
*/
|
||||
@@ -374,9 +376,9 @@ protected: // accessors
|
||||
protected: // instance name
|
||||
struct ParsedInstanceName
|
||||
{
|
||||
Name strategyName; ///< strategy name without parameters
|
||||
optional<uint64_t> version; ///< whether strategyName contains a version component
|
||||
PartialName parameters; ///< parameter components
|
||||
Name strategyName; ///< Strategy name without parameters
|
||||
optional<uint64_t> version; ///< The strategy version number, if present
|
||||
PartialName parameters; ///< Parameter components, may be empty
|
||||
};
|
||||
|
||||
/** \brief Parse a strategy instance name
|
||||
@@ -408,6 +410,15 @@ protected: // instance name
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
|
||||
/**
|
||||
* \brief Parse strategy parameters encoded in a strategy instance name
|
||||
* \param params encoded parameters, typically obtained from a call to parseInstanceName()
|
||||
* \throw std::invalid_argument the encoding format is invalid or unsupported by this implementation
|
||||
*/
|
||||
static StrategyParameters
|
||||
parseParameters(const PartialName& params);
|
||||
|
||||
private: // registry
|
||||
using CreateFunc = std::function<unique_ptr<Strategy>(Forwarder&, const Name& /*strategyName*/)>;
|
||||
using Registry = std::map<Name, CreateFunc>; // indexed by strategy name
|
||||
@@ -428,6 +439,48 @@ private: // instance fields
|
||||
MeasurementsAccessor m_measurements;
|
||||
};
|
||||
|
||||
class StrategyParameters : public std::map<std::string, std::string>
|
||||
{
|
||||
public:
|
||||
// Note: only arithmetic types are supported by getOrDefault() for now
|
||||
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, T>
|
||||
getOrDefault(const key_type& key, const T& defaultVal) const
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end()) {
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
T val{};
|
||||
if (!boost::conversion::try_lexical_convert(it->second, val)) {
|
||||
NDN_THROW(std::invalid_argument(key + " value is malformed"));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T>
|
||||
getOrDefault(const key_type& key, const T& defaultVal) const
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end()) {
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
if (it->second.find('-') != std::string::npos) {
|
||||
NDN_THROW(std::invalid_argument(key + " cannot be negative"));
|
||||
}
|
||||
|
||||
T val{};
|
||||
if (!boost::conversion::try_lexical_convert(it->second, val)) {
|
||||
NDN_THROW(std::invalid_argument(key + " value is malformed"));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
@@ -40,13 +40,18 @@ nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf
|
||||
Use the default values for all parameters.
|
||||
|
||||
nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf/v=4/probing-interval~30000
|
||||
Set probing interval to 30 seconds.
|
||||
Set the probing interval to 30 seconds.
|
||||
|
||||
nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf/v=4/max-timeouts~5
|
||||
Set max timeouts to 5.
|
||||
Set the maximum number of timeouts to 5.
|
||||
|
||||
nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf/v=4/probing-interval~30000/max-timeouts~2
|
||||
Set probing interval to 30 seconds and max timeouts to 2.
|
||||
Set the probing interval to 30 seconds and the maximum number of timeouts to 2.
|
||||
|
||||
nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/asf/v=4/retx-suppression-multiplier~2.5/probing-interval~45000
|
||||
Set the retransmission suppression multiplier to 2.5 and the probing interval
|
||||
to 45 seconds. See :manpage:`nfdc-strategy(1)` for more information on the
|
||||
retransmission suppression parameters.
|
||||
|
||||
See also
|
||||
--------
|
||||
|
||||
@@ -42,6 +42,29 @@ OPTIONS
|
||||
A name that identifies the forwarding strategy.
|
||||
Consult NFD Developer's Guide for a complete list of all implemented strategies.
|
||||
|
||||
For the ASF, BestRoute, and Multicast strategies, the following options may be supplied
|
||||
to configure exponential retransmission suppression by appending them after the strategy
|
||||
name and version number.
|
||||
|
||||
**retx-suppression-initial**
|
||||
Starting duration of the suppression interval within which any retransmitted
|
||||
Interests are considered for suppression. The default value is 10 ms.
|
||||
|
||||
Format: ``retx-suppression-initial~<milliseconds>``
|
||||
|
||||
**retx-suppression-max**
|
||||
Maximum duration of the suppression interval. Must not be smaller than
|
||||
**retx-suppression-initial**. The default value is 250 ms.
|
||||
|
||||
Format: ``retx-suppression-max~<milliseconds>``
|
||||
|
||||
**retx-suppression-multiplier**
|
||||
The suppression interval is increased by this multiplier. The default value is 2.
|
||||
|
||||
Format: ``retx-suppression-multiplier~<float>``
|
||||
|
||||
See :manpage:`nfd-asf-strategy(7)` for details on additional parameters for ASF strategy.
|
||||
|
||||
EXIT CODES
|
||||
----------
|
||||
0: Success
|
||||
@@ -66,6 +89,10 @@ nfdc strategy set prefix / strategy /localhost/nfd/strategy/best-route
|
||||
nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/multicast/v=4
|
||||
Set the strategy for the "/ndn" prefix to multicast, version 4.
|
||||
|
||||
nfdc strategy set prefix /ndn strategy /localhost/nfd/strategy/multicast/v=4/retx-suppression-initial~20/retx-suppression-max~500
|
||||
Set the strategy for the "/ndn" prefix to multicast, version 4, with retransmission
|
||||
suppression initial interval set to 20 ms and maximum interval set to 500 ms.
|
||||
|
||||
nfdc strategy unset prefix /ndn
|
||||
Clear the strategy choice for the "/ndn" prefix.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -541,39 +541,53 @@ BOOST_FIXTURE_TEST_CASE(ProbingInterval, AsfStrategyParametersGridFixture)
|
||||
BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InstantiationWithParameters)
|
||||
BOOST_AUTO_TEST_CASE(Parameters)
|
||||
{
|
||||
FaceTable faceTable;
|
||||
Forwarder forwarder{faceTable};
|
||||
|
||||
auto checkValidity = [&] (std::string parameters, bool isCorrect) {
|
||||
Name strategyName(Name(AsfStrategy::getStrategyName()).append(std::move(parameters)));
|
||||
if (isCorrect) {
|
||||
BOOST_CHECK_NO_THROW(make_unique<AsfStrategy>(forwarder, strategyName));
|
||||
}
|
||||
else {
|
||||
BOOST_CHECK_THROW(make_unique<AsfStrategy>(forwarder, strategyName), std::invalid_argument);
|
||||
auto checkValidity = [&] (const std::string& parameters, bool isCorrect) {
|
||||
Name strategyName(Name(AsfStrategy::getStrategyName()).append(parameters));
|
||||
std::unique_ptr<AsfStrategy> strategy;
|
||||
BOOST_TEST_CONTEXT(parameters) {
|
||||
if (isCorrect) {
|
||||
strategy = make_unique<AsfStrategy>(forwarder, strategyName);
|
||||
BOOST_CHECK(strategy->m_retxSuppression != nullptr);
|
||||
}
|
||||
else {
|
||||
BOOST_CHECK_THROW(make_unique<AsfStrategy>(forwarder, strategyName), std::invalid_argument);
|
||||
}
|
||||
}
|
||||
return strategy;
|
||||
};
|
||||
|
||||
checkValidity("/probing-interval~30000/max-timeouts~5", true);
|
||||
checkValidity("/max-timeouts~5/probing-interval~30000", true);
|
||||
checkValidity("/probing-interval~30000", true);
|
||||
checkValidity("/max-timeouts~5", true);
|
||||
checkValidity("", true);
|
||||
auto strategy = checkValidity("", true);
|
||||
BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
|
||||
BOOST_TEST(strategy->m_nMaxTimeouts == 3);
|
||||
strategy = checkValidity("/probing-interval~30000/max-timeouts~5", true);
|
||||
BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
|
||||
BOOST_TEST(strategy->m_nMaxTimeouts == 5);
|
||||
strategy = checkValidity("/max-timeouts~5/probing-interval~30000", true);
|
||||
BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
|
||||
BOOST_TEST(strategy->m_nMaxTimeouts == 5);
|
||||
strategy = checkValidity("/probing-interval~1000", true);
|
||||
BOOST_TEST(strategy->m_probing.getProbingInterval() == 1_s);
|
||||
BOOST_TEST(strategy->m_nMaxTimeouts == 3);
|
||||
strategy = checkValidity("/max-timeouts~0", true);
|
||||
BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
|
||||
BOOST_TEST(strategy->m_nMaxTimeouts == 0);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == RetxSuppressionExponential::DEFAULT_MAX_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_multiplier == RetxSuppressionExponential::DEFAULT_MULTIPLIER);
|
||||
|
||||
checkValidity("/probing-interval~500", false); // At least 1 seconds
|
||||
checkValidity("/probing-interval~500", false); // minimum is 1 second
|
||||
checkValidity("/probing-interval~-5000", false);
|
||||
checkValidity("/max-timeouts~0", false);
|
||||
checkValidity("/max-timeouts~-5", false);
|
||||
checkValidity("/max-timeouts~-5/probing-interval~-30000", false);
|
||||
checkValidity("/max-timeouts", false);
|
||||
checkValidity("/probing-interval~", false);
|
||||
checkValidity("/~1000", false);
|
||||
checkValidity("/max-timeouts~-1", false);
|
||||
checkValidity("/max-timeouts~ -1", false);
|
||||
checkValidity("/max-timeouts~1-0", false);
|
||||
checkValidity("/max-timeouts~1/probing-interval~-30000", false);
|
||||
checkValidity("/probing-interval~foo", false);
|
||||
checkValidity("/max-timeouts~1~2", false);
|
||||
checkValidity("/foo", false);
|
||||
checkValidity("/foo~42", false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestAsfStrategy
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(Forward)
|
||||
shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
|
||||
|
||||
const auto TICK = time::duration_cast<time::nanoseconds>(
|
||||
BestRouteStrategy::RETX_SUPPRESSION_INITIAL * 0.1);
|
||||
RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL * 0.1);
|
||||
|
||||
// first Interest goes to nexthop with lowest FIB cost,
|
||||
// however face1 is downstream so it cannot be used
|
||||
@@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(Forward)
|
||||
retxFrom4Evt = getScheduler().schedule(TICK * 5, periodicalRetxFrom4);
|
||||
};
|
||||
periodicalRetxFrom4();
|
||||
this->advanceClocks(TICK, BestRouteStrategy::RETX_SUPPRESSION_MAX * 16);
|
||||
this->advanceClocks(TICK, RetxSuppressionExponential::DEFAULT_MAX_INTERVAL * 16);
|
||||
retxFrom4Evt.cancel();
|
||||
|
||||
// nexthops for accepted retransmissions: follow FIB cost,
|
||||
@@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(Forward)
|
||||
|
||||
strategy.sendInterestHistory.clear();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
this->advanceClocks(TICK, BestRouteStrategy::RETX_SUPPRESSION_MAX * 2);
|
||||
this->advanceClocks(TICK, RetxSuppressionExponential::DEFAULT_MAX_INTERVAL * 2);
|
||||
pitEntry->insertOrUpdateInRecord(*face5, *interest);
|
||||
strategy.afterReceiveInterest(*interest, FaceEndpoint(*face5, 0), pitEntry);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -170,7 +170,8 @@ BOOST_AUTO_TEST_CASE(Forward2)
|
||||
BOOST_TEST(didSendInterestTo(*face1));
|
||||
BOOST_TEST(didSendInterestTo(*face2));
|
||||
|
||||
const auto TICK = time::duration_cast<time::nanoseconds>(MulticastStrategy::RETX_SUPPRESSION_INITIAL) / 10;
|
||||
const auto TICK = time::duration_cast<time::nanoseconds>(
|
||||
RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL) / 10;
|
||||
|
||||
// downstream retransmits frequently, but the strategy should not send Interests
|
||||
// more often than DEFAULT_MIN_RETX_INTERVAL
|
||||
@@ -195,7 +196,7 @@ BOOST_AUTO_TEST_CASE(Forward2)
|
||||
retxFrom4Evt = getScheduler().schedule(TICK * 5, periodicalRetxFrom4);
|
||||
};
|
||||
periodicalRetxFrom4();
|
||||
this->advanceClocks(TICK, MulticastStrategy::RETX_SUPPRESSION_MAX * 16);
|
||||
this->advanceClocks(TICK, RetxSuppressionExponential::DEFAULT_MAX_INTERVAL * 16);
|
||||
retxFrom4Evt.cancel();
|
||||
}
|
||||
|
||||
@@ -215,7 +216,7 @@ BOOST_AUTO_TEST_CASE(LoopingInterest)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RetxSuppression)
|
||||
{
|
||||
const auto suppressPeriod = MulticastStrategy::RETX_SUPPRESSION_INITIAL;
|
||||
const auto suppressPeriod = RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL;
|
||||
BOOST_ASSERT(suppressPeriod >= 8_ms);
|
||||
|
||||
// Set up the FIB
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(Exponential)
|
||||
FaceTable faceTable;
|
||||
Forwarder forwarder(faceTable);
|
||||
Pit& pit = forwarder.getPit();
|
||||
RetxSuppressionExponential rs(10_ms, 3.0, 100_ms);
|
||||
RetxSuppressionExponential rs(10_ms, 100_ms, 3.0);
|
||||
|
||||
shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
|
||||
shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
|
||||
@@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(ExponentialPerUpstream)
|
||||
FaceTable faceTable;
|
||||
Forwarder forwarder(faceTable);
|
||||
Pit& pit = forwarder.getPit();
|
||||
RetxSuppressionExponential rs(10_ms, 3.0, 100_ms);
|
||||
RetxSuppressionExponential rs(10_ms, 100_ms, 3.0);
|
||||
|
||||
shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
|
||||
shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -74,8 +74,8 @@ public:
|
||||
using Tests = boost::mpl::vector<
|
||||
Test<AccessStrategy, false, 1>,
|
||||
Test<AsfStrategy, true, 4>,
|
||||
Test<BestRouteStrategy, false, 5>,
|
||||
Test<MulticastStrategy, false, 4>,
|
||||
Test<BestRouteStrategy, true, 5>,
|
||||
Test<MulticastStrategy, true, 4>,
|
||||
Test<SelfLearningStrategy, false, 1>,
|
||||
Test<RandomStrategy, false, 1>
|
||||
>;
|
||||
@@ -120,6 +120,85 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(InstanceName, T, Tests)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
class SuppressionParametersFixture
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<S>
|
||||
checkValidity(const std::string& parameters, bool isCorrect)
|
||||
{
|
||||
Name strategyName(Name(S::getStrategyName()).append(parameters));
|
||||
std::unique_ptr<S> strategy;
|
||||
BOOST_TEST_CONTEXT(parameters) {
|
||||
if (isCorrect) {
|
||||
strategy = make_unique<S>(m_forwarder, strategyName);
|
||||
BOOST_CHECK(strategy->m_retxSuppression != nullptr);
|
||||
}
|
||||
else {
|
||||
BOOST_CHECK_THROW(make_unique<S>(m_forwarder, strategyName), std::invalid_argument);
|
||||
}
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
|
||||
private:
|
||||
FaceTable m_faceTable;
|
||||
Forwarder m_forwarder{m_faceTable};
|
||||
};
|
||||
|
||||
using StrategiesWithRetxSuppressionExponential = boost::mpl::vector<
|
||||
AsfStrategy,
|
||||
BestRouteStrategy,
|
||||
MulticastStrategy
|
||||
>;
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE_TEMPLATE(SuppressionParameters, S, StrategiesWithRetxSuppressionExponential,
|
||||
SuppressionParametersFixture<S>)
|
||||
{
|
||||
auto strategy = this->checkValidity("", true);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == RetxSuppressionExponential::DEFAULT_MAX_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_multiplier == RetxSuppressionExponential::DEFAULT_MULTIPLIER);
|
||||
|
||||
strategy = this->checkValidity("/retx-suppression-initial~20", true);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == 20_ms);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == RetxSuppressionExponential::DEFAULT_MAX_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_multiplier == RetxSuppressionExponential::DEFAULT_MULTIPLIER);
|
||||
this->checkValidity("/retx-suppression-initial~0", false);
|
||||
this->checkValidity("/retx-suppression-initial~20.5", false);
|
||||
this->checkValidity("/retx-suppression-initial~-10", false);
|
||||
this->checkValidity("/retx-suppression-initial~ -5", false);
|
||||
this->checkValidity("/retx-suppression-initial~NaN", false);
|
||||
|
||||
strategy = this->checkValidity("/retx-suppression-max~1000", true);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == 1_s);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_multiplier == RetxSuppressionExponential::DEFAULT_MULTIPLIER);
|
||||
strategy = this->checkValidity("/retx-suppression-initial~40/retx-suppression-max~500", true);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == 40_ms);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == 500_ms);
|
||||
this->checkValidity("/retx-suppression-initial~20/retx-suppression-max~10", false);
|
||||
this->checkValidity("/retx-suppression-max~ 500", false);
|
||||
this->checkValidity("/retx-suppression-max~521.5", false);
|
||||
|
||||
strategy = this->checkValidity("/retx-suppression-multiplier~2.25", true);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == RetxSuppressionExponential::DEFAULT_MAX_INTERVAL);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_multiplier == 2.25);
|
||||
this->checkValidity("/retx-suppression-multiplier~0", false);
|
||||
this->checkValidity("/retx-suppression-multiplier~0.9", false);
|
||||
this->checkValidity("/retx-suppression-multiplier~-2.1", false);
|
||||
this->checkValidity("/retx-suppression-multiplier~foo", false);
|
||||
|
||||
strategy = this->checkValidity("/retx-suppression-initial~20/retx-suppression-max~500/retx-suppression-multiplier~3",
|
||||
true);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == 20_ms);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == 500_ms);
|
||||
BOOST_TEST(strategy->m_retxSuppression->m_multiplier == 3);
|
||||
|
||||
this->checkValidity("/foo~42", true); // unknown parameters are ignored
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestStrategyInstantiation
|
||||
BOOST_AUTO_TEST_SUITE_END() // Fw
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -94,13 +94,33 @@ BOOST_AUTO_TEST_CASE(FaceTableAccess)
|
||||
FaceId id1 = face1->getId();
|
||||
FaceId id2 = face2->getId();
|
||||
|
||||
BOOST_CHECK(strategy.getLocalFaces() == std::vector<FaceId>{id2});
|
||||
BOOST_TEST(strategy.getLocalFaces() == std::vector<FaceId>{id2}, boost::test_tools::per_element());
|
||||
|
||||
face2->close();
|
||||
face1->close();
|
||||
|
||||
BOOST_CHECK((strategy.addedFaces == std::vector<FaceId>{id1, id2}));
|
||||
BOOST_CHECK((strategy.removedFaces == std::vector<FaceId>{id2, id1}));
|
||||
BOOST_TEST((strategy.addedFaces == std::vector<FaceId>{id1, id2}), boost::test_tools::per_element());
|
||||
BOOST_TEST((strategy.removedFaces == std::vector<FaceId>{id2, id1}), boost::test_tools::per_element());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ParseParameters)
|
||||
{
|
||||
BOOST_TEST(Strategy::parseParameters("").empty());
|
||||
BOOST_TEST(Strategy::parseParameters("/").empty());
|
||||
BOOST_CHECK_THROW(Strategy::parseParameters("/foo"), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(Strategy::parseParameters("/foo~"), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(Strategy::parseParameters("/~bar"), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(Strategy::parseParameters("/~"), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(Strategy::parseParameters("/~~"), std::invalid_argument);
|
||||
|
||||
StrategyParameters expected;
|
||||
expected["foo"] = "bar";
|
||||
BOOST_TEST(Strategy::parseParameters("/foo~bar") == expected);
|
||||
BOOST_CHECK_THROW(Strategy::parseParameters("/foo~bar/42"), std::invalid_argument);
|
||||
expected["the-answer"] = "42";
|
||||
BOOST_TEST(Strategy::parseParameters("/foo~bar/the-answer~42") == expected);
|
||||
expected["foo"] = "foo2";
|
||||
BOOST_TEST(Strategy::parseParameters("/foo~bar/the-answer~42/foo~foo2") == expected);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestStrategy
|
||||
|
||||
Reference in new issue
Block a user