fw: add strategy parameters to configure exponential retx suppression
Supported by ASF, BestRoute, and Multicast strategies
Refs: #4924
Change-Id: I215d9212d90b93fa622cc65278703dc5198d0c9d
diff --git a/daemon/fw/asf-probing-module.cpp b/daemon/fw/asf-probing-module.cpp
index af29a1b..425b39c 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-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 @@
}
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 >= " +
diff --git a/daemon/fw/asf-probing-module.hpp b/daemon/fw/asf-probing-module.hpp
index 82e7bad..654b569 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-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 @@
afterForwardingProbe(const fib::Entry& fibEntry, const Name& interestName);
void
- setProbingInterval(size_t probingInterval);
+ setProbingInterval(time::milliseconds probingInterval);
time::milliseconds
getProbingInterval() const
diff --git a/daemon/fw/asf-strategy.cpp b/daemon/fw/asf-strategy.cpp
index df38099..79181a2 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-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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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);
}
}
}
diff --git a/daemon/fw/asf-strategy.hpp b/daemon/fw/asf-strategy.hpp
index af3e4b5..95d1d71 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-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 @@
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:
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
diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp
index eecc3b5..94f2e29 100644
--- a/daemon/fw/best-route-strategy.cpp
+++ b/daemon/fw/best-route-strategy.cpp
@@ -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 @@
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 @@
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;
diff --git a/daemon/fw/best-route-strategy.hpp b/daemon/fw/best-route-strategy.hpp
index 3f11c7a..5b4e27d 100644
--- a/daemon/fw/best-route-strategy.hpp
+++ b/daemon/fw/best-route-strategy.hpp
@@ -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 @@
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>;
};
diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp
index 090a560..f49f60a 100644
--- a/daemon/fw/multicast-strategy.cpp
+++ b/daemon/fw/multicast-strategy.cpp
@@ -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_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 @@
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 @@
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);
}
}
}
diff --git a/daemon/fw/multicast-strategy.hpp b/daemon/fw/multicast-strategy.hpp
index fe122a4..6ff301d 100644
--- a/daemon/fw/multicast-strategy.hpp
+++ b/daemon/fw/multicast-strategy.hpp
@@ -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 @@
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
diff --git a/daemon/fw/retx-suppression-exponential.cpp b/daemon/fw/retx-suppression-exponential.cpp
index 7d0749e..114b491 100644
--- a/daemon/fw/retx-suppression-exponential.cpp
+++ b/daemon/fw/retx-suppression-exponential.cpp
@@ -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 @@
}
explicit
- PitInfo(const Duration& initialInterval)
+ PitInfo(const RetxSuppressionExponential::Duration& initialInterval)
: suppressionInterval(initialInterval)
{
}
@@ -51,19 +53,27 @@
/** \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 @@
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
diff --git a/daemon/fw/retx-suppression-exponential.hpp b/daemon/fw/retx-suppression-exponential.hpp
index 8455b5e..3c3be60 100644
--- a/daemon/fw/retx-suppression-exponential.hpp
+++ b/daemon/fw/retx-suppression-exponential.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-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 @@
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
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index 7212c52..fa948ee 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -140,6 +140,29 @@
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 @@
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 @@
}
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
}
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 93a154b..50c79dc 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -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 @@
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: // 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 @@
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 @@
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