mgmt: add config file-based strategy selection
refs: #2053
Change-Id: I76b5945768403578651429ca3170f29d9e66ad54
diff --git a/daemon/mgmt/tables-config-section.cpp b/daemon/mgmt/tables-config-section.cpp
index 7e1ed8f..861ed7f 100644
--- a/daemon/mgmt/tables-config-section.cpp
+++ b/daemon/mgmt/tables-config-section.cpp
@@ -43,7 +43,7 @@
: m_cs(cs)
// , m_pit(pit)
// , m_fib(fib)
- // , m_strategyChoice(strategyChoice)
+ , m_strategyChoice(strategyChoice)
// , m_measurements(measurements)
, m_areTablesConfigured(false)
{
@@ -80,6 +80,14 @@
// tables
// {
// cs_max_packets 65536
+ //
+ // strategy_choice
+ // {
+ // / /localhost/nfd/strategy/best-route
+ // /localhost /localhost/nfd/strategy/broadcast
+ // /localhost/nfd /localhost/nfd/strategy/best-route
+ // /ndn/broadcast /localhost/nfd/strategy/broadcast
+ // }
// }
size_t nCsMaxPackets = DEFAULT_CS_MAX_PACKETS;
@@ -101,6 +109,14 @@
nCsMaxPackets = *valCsMaxPackets;
}
+ boost::optional<const ConfigSection&> strategyChoiceSection =
+ configSection.get_child_optional("strategy_choice");
+
+ if (strategyChoiceSection)
+ {
+ processSectionStrategyChoice(*strategyChoiceSection, isDryRun);
+ }
+
if (!isDryRun)
{
NFD_LOG_INFO("Setting CS max packets to " << nCsMaxPackets);
@@ -110,4 +126,59 @@
}
}
+void
+TablesConfigSection::processSectionStrategyChoice(const ConfigSection& configSection,
+ bool isDryRun)
+{
+ // strategy_choice
+ // {
+ // / /localhost/nfd/strategy/best-route
+ // /localhost /localhost/nfd/strategy/broadcast
+ // /localhost/nfd /localhost/nfd/strategy/best-route
+ // /ndn/broadcast /localhost/nfd/strategy/broadcast
+ // }
+
+ std::map<Name, Name> choices;
+
+ for (const auto& prefixAndStrategy : configSection)
+ {
+ const Name prefix(prefixAndStrategy.first);
+ if (choices.find(prefix) != choices.end())
+ {
+ throw ConfigFile::Error("Duplicate strategy choice for prefix \"" +
+ prefix.toUri() + "\" in \"strategy_choice\" section");
+ }
+
+ const std::string strategyString(prefixAndStrategy.second.get_value<std::string>());
+ if (strategyString.empty())
+ {
+ throw ConfigFile::Error("Invalid strategy choice \"\" for prefix \"" +
+ prefix.toUri() + "\" in \"strategy_choice\" section");
+ }
+
+ const Name strategyName(strategyString);
+ if (!m_strategyChoice.hasStrategy(strategyName))
+ {
+ throw ConfigFile::Error("Invalid strategy choice \"" +
+ strategyName.toUri() + "\" for prefix \"" +
+ prefix.toUri() + "\" in \"strategy_choice\" section");
+ }
+
+ choices[prefix] = strategyName;
+ }
+
+
+ for (const auto& prefixAndStrategy : choices)
+ {
+ if (!isDryRun && !m_strategyChoice.insert(prefixAndStrategy.first, prefixAndStrategy.second))
+ {
+ throw ConfigFile::Error("Failed to set strategy \"" +
+ prefixAndStrategy.second.toUri() + "\" for prefix \"" +
+ prefixAndStrategy.first.toUri() + "\" in \"strategy_choicev\"");
+ }
+ }
+}
+
+
+
} // namespace nfd
diff --git a/daemon/mgmt/tables-config-section.hpp b/daemon/mgmt/tables-config-section.hpp
index 4571a59..3f132f7 100644
--- a/daemon/mgmt/tables-config-section.hpp
+++ b/daemon/mgmt/tables-config-section.hpp
@@ -58,11 +58,15 @@
bool isDryRun,
const std::string& filename);
+ void
+ processSectionStrategyChoice(const ConfigSection& configSection,
+ bool isDryRun);
+
private:
Cs& m_cs;
// Pit& m_pit;
// Fib& m_fib;
- // StrategyChoice& m_strategyChoice;
+ StrategyChoice& m_strategyChoice;
// Measurements& m_measurements;
bool m_areTablesConfigured;
diff --git a/nfd.conf.sample.in b/nfd.conf.sample.in
index 05c11f8..210ecba 100644
--- a/nfd.conf.sample.in
+++ b/nfd.conf.sample.in
@@ -49,6 +49,16 @@
; ContentStore size limit in number of packets
; default is 65536, about 500MB with 8KB packet size
cs_max_packets 65536
+
+ ; Set the forwarding strategy for the specified prefixes:
+ ; <prefix> <strategy>
+ strategy_choice
+ {
+ / /localhost/nfd/strategy/best-route
+ /localhost /localhost/nfd/strategy/broadcast
+ /localhost/nfd /localhost/nfd/strategy/best-route
+ /ndn/broadcast /localhost/nfd/strategy/broadcast
+ }
}
; The face_system section defines what faces and channels are created.
diff --git a/tests/daemon/mgmt/tables-config-section.cpp b/tests/daemon/mgmt/tables-config-section.cpp
index 6ec274c..5129287 100644
--- a/tests/daemon/mgmt/tables-config-section.cpp
+++ b/tests/daemon/mgmt/tables-config-section.cpp
@@ -28,10 +28,13 @@
#include "tests/test-common.hpp"
+#include "tests/daemon/fw/dummy-strategy.hpp"
namespace nfd {
namespace tests {
+NFD_LOG_INIT("MgmtTablesConfigSection");
+
class TablesConfigSectionFixture : protected BaseFixture
{
public:
@@ -56,7 +59,14 @@
bool
validateException(const std::runtime_error& exception, const std::string& expectedMsg)
{
- return exception.what() == expectedMsg;
+ if (exception.what() != expectedMsg)
+ {
+ NFD_LOG_DEBUG("exception.what(): " << exception.what());
+ NFD_LOG_DEBUG("msg: : " << expectedMsg);
+
+ return false;
+ }
+ return true;
}
protected:
@@ -168,6 +178,181 @@
this, _1, expectedMsg));
}
+BOOST_AUTO_TEST_CASE(ConfigStrategy)
+{
+ const std::string CONFIG =
+ "tables\n"
+ "{\n"
+ "strategy_choice\n"
+ "{\n"
+ " / /localhost/nfd/strategy/test-strategy-a\n"
+ " /a /localhost/nfd/strategy/test-strategy-b\n"
+ "}\n"
+ "}\n";
+
+ m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
+ "/localhost/nfd/strategy/test-strategy-a"));
+ m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
+ "/localhost/nfd/strategy/test-strategy-b"));
+
+ runConfig(CONFIG, true);
+ {
+ fw::Strategy& rootStrategy = m_strategyChoice.findEffectiveStrategy("/");
+ BOOST_REQUIRE_NE(rootStrategy.getName(), "/localhost/nfd/strategy/test-strategy-a");
+ BOOST_REQUIRE_NE(rootStrategy.getName(), "/localhost/nfd/strategy/test-strategy-b");
+
+ fw::Strategy& aStrategy = m_strategyChoice.findEffectiveStrategy("/a");
+ BOOST_REQUIRE_NE(aStrategy.getName(), "/localhost/nfd/strategy/test-strategy-b");
+ BOOST_REQUIRE_NE(aStrategy.getName(), "/localhost/nfd/strategy/test-strategy-a");
+ }
+
+ runConfig(CONFIG, false);
+ {
+ fw::Strategy& rootStrategy = m_strategyChoice.findEffectiveStrategy("/");
+ BOOST_REQUIRE_EQUAL(rootStrategy.getName(), "/localhost/nfd/strategy/test-strategy-a");
+
+ fw::Strategy& aStrategy = m_strategyChoice.findEffectiveStrategy("/a");
+ BOOST_REQUIRE_EQUAL(aStrategy.getName(), "/localhost/nfd/strategy/test-strategy-b");
+ }
+}
+
+BOOST_AUTO_TEST_CASE(ConfigVersionedStrategy)
+{
+ const std::string CONFIG =
+ "tables\n"
+ "{\n"
+ "strategy_choice\n"
+ "{\n"
+ " /test/latest /localhost/nfd/strategy/test-strategy-a\n"
+ " /test/old /localhost/nfd/strategy/test-strategy-a/%FD%01\n"
+ "}\n"
+ "}\n";
+
+
+ auto version1 = make_shared<DummyStrategy>(ref(m_forwarder),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%01");
+
+ auto version2 = make_shared<DummyStrategy>(ref(m_forwarder),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%02");
+ m_strategyChoice.install(version1);
+ m_strategyChoice.install(version2);
+
+ runConfig(CONFIG, true);
+ {
+ fw::Strategy& testLatestStrategy = m_strategyChoice.findEffectiveStrategy("/test/latest");
+ BOOST_REQUIRE_NE(testLatestStrategy.getName(),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%01");
+ BOOST_REQUIRE_NE(testLatestStrategy.getName(),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%02");
+
+ fw::Strategy& testOldStrategy = m_strategyChoice.findEffectiveStrategy("/test/old");
+ BOOST_REQUIRE_NE(testOldStrategy.getName(),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%01");
+ BOOST_REQUIRE_NE(testOldStrategy.getName(),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%02");
+ }
+
+ runConfig(CONFIG, false);
+ {
+ fw::Strategy& testLatestStrategy = m_strategyChoice.findEffectiveStrategy("/test/latest");
+ BOOST_REQUIRE_EQUAL(testLatestStrategy.getName(),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%02");
+
+ fw::Strategy& testOldStrategy = m_strategyChoice.findEffectiveStrategy("/test/old");
+ BOOST_REQUIRE_EQUAL(testOldStrategy.getName(),
+ "/localhost/nfd/strategy/test-strategy-a/%FD%01");
+ }
+}
+
+BOOST_AUTO_TEST_CASE(InvalidStrategy)
+{
+ const std::string CONFIG =
+ "tables\n"
+ "{\n"
+ "strategy_choice\n"
+ "{\n"
+ " / /localhost/nfd/strategy/test-doesnotexist\n"
+ "}\n"
+ "}\n";
+
+
+ const std::string expectedMsg =
+ "Invalid strategy choice \"/localhost/nfd/strategy/test-doesnotexist\" "
+ "for prefix \"/\" in \"strategy_choice\" section";
+
+ BOOST_CHECK_EXCEPTION(runConfig(CONFIG, true),
+ ConfigFile::Error,
+ bind(&TablesConfigSectionFixture::validateException,
+ this, _1, expectedMsg));
+
+ BOOST_CHECK_EXCEPTION(runConfig(CONFIG, false),
+ ConfigFile::Error,
+ bind(&TablesConfigSectionFixture::validateException,
+ this, _1, expectedMsg));
+}
+
+BOOST_AUTO_TEST_CASE(MissingStrategyPrefix)
+{
+ const std::string CONFIG =
+ "tables\n"
+ "{\n"
+ "strategy_choice\n"
+ "{\n"
+ " /localhost/nfd/strategy/test-strategy-a\n"
+ "}\n"
+ "}\n";
+
+
+ m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
+ "/localhost/nfd/strategy/test-strategy-a"));
+
+
+ const std::string expectedMsg = "Invalid strategy choice \"\" for prefix "
+ "\"/localhost/nfd/strategy/test-strategy-a\" in \"strategy_choice\" section";
+
+ BOOST_CHECK_EXCEPTION(runConfig(CONFIG, true),
+ ConfigFile::Error,
+ bind(&TablesConfigSectionFixture::validateException,
+ this, _1, expectedMsg));
+
+ BOOST_CHECK_EXCEPTION(runConfig(CONFIG, false),
+ ConfigFile::Error,
+ bind(&TablesConfigSectionFixture::validateException,
+ this, _1, expectedMsg));
+}
+
+BOOST_AUTO_TEST_CASE(DuplicateStrategy)
+{
+ const std::string CONFIG =
+ "tables\n"
+ "{\n"
+ "strategy_choice\n"
+ "{\n"
+ " / /localhost/nfd/strategy/test-strategy-a\n"
+ " /a /localhost/nfd/strategy/test-strategy-b\n"
+ " / /localhost/nfd/strategy/test-strategy-b\n"
+ "}\n"
+ "}\n";
+
+ m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
+ "/localhost/nfd/strategy/test-strategy-a"));
+ m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
+ "/localhost/nfd/strategy/test-strategy-b"));
+
+ const std::string expectedMsg =
+ "Duplicate strategy choice for prefix \"/\" in \"strategy_choice\" section";
+
+ BOOST_CHECK_EXCEPTION(runConfig(CONFIG, true),
+ ConfigFile::Error,
+ bind(&TablesConfigSectionFixture::validateException,
+ this, _1, expectedMsg));
+
+ BOOST_CHECK_EXCEPTION(runConfig(CONFIG, false),
+ ConfigFile::Error,
+ bind(&TablesConfigSectionFixture::validateException,
+ this, _1, expectedMsg));
+}
+
class IgnoreNotTablesSection
{
public: