mgmt: added FIB manager support for insert, delete, and remove-nexthop verbs
Refactor option decoding, verb authorization (placeholder),
and response sending into single location.
Added unit tests for ManagerBase.
refs: #1223
Change-Id: I731be586ee8f06defb00fcadc6010409560891a1
diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp
index 69be19f..3bcbb1a 100644
--- a/daemon/mgmt/fib-manager.cpp
+++ b/daemon/mgmt/fib-manager.cpp
@@ -11,12 +11,9 @@
#include "mgmt/internal-face.hpp"
#include "mgmt/app-face.hpp"
-
-
#include <ndn-cpp-dev/management/fib-management-options.hpp>
#include <ndn-cpp-dev/encoding/tlv.hpp>
-#include <ndn-cpp-dev/management/fib-management-options.hpp>
namespace nfd {
@@ -35,33 +32,32 @@
const FibManager::VerbAndProcessor FibManager::FIB_MANAGER_COMMAND_VERBS[] =
{
- // Unsupported
+ VerbAndProcessor(
+ "insert",
+ &FibManager::insertEntry
+ ),
- // VerbAndProcessor(
- // "insert",
- // &FibManager::fibInsert
- // ),
-
- // VerbAndProcessor(
- // "delete",
- // &FibManager::fibDelete
- // ),
+ VerbAndProcessor(
+ "delete",
+ &FibManager::deleteEntry
+ ),
VerbAndProcessor(
"add-nexthop",
- &FibManager::fibAddNextHop
+ &FibManager::addNextHop
+ ),
+
+
+
+ VerbAndProcessor(
+ "remove-nexthop",
+ &FibManager::removeNextHop
),
// Unsupported
-
- // VerbAndProcessor(
- // "remove-nexthop",
- // &FibManager::fibRemoveNextHop
- // ),
-
// VerbAndProcessor(
// "strategy",
- // &FibManager::fibStrategy
+ // &FibManager::strategy
// )
};
@@ -86,12 +82,10 @@
const Name& command = request.getName();
const size_t commandNComps = command.size();
- /// \todo Separate out response status codes 400 and 401
-
if (FIB_MANAGER_COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
commandNComps < FIB_MANAGER_COMMAND_SIGNED_NCOMPS)
{
- NFD_LOG_INFO("Unsigned command: " << command);
+ NFD_LOG_INFO("command result: unsigned verb: " << command);
sendResponse(command, 401, "Signature required");
return;
@@ -99,45 +93,51 @@
else if (commandNComps < FIB_MANAGER_COMMAND_SIGNED_NCOMPS ||
!FIB_MANAGER_COMMAND_PREFIX.isPrefixOf(command))
{
- NFD_LOG_INFO("Malformed command: " << command);
+ NFD_LOG_INFO("command result: malformed");
sendResponse(command, 400, "Malformed command");
return;
}
-
const Name::Component& verb = command.get(FIB_MANAGER_COMMAND_PREFIX.size());
VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find (verb);
if (verbProcessor != m_verbDispatch.end())
{
- NFD_LOG_INFO("Processing command verb: " << verb);
- (verbProcessor->second)(this, request);
+ ndn::FibManagementOptions options;
+ if (!extractOptions(request, options))
+ {
+ sendResponse(command, 400, "Malformed command");
+ return;
+ }
+
+ /// \todo authorize command
+ if (false)
+ {
+ NFD_LOG_INFO("command result: unauthorized verb: " << command);
+ sendResponse(request.getName(), 403, "Unauthorized command");
+ return;
+ }
+
+ NFD_LOG_INFO("command result: processing verb: " << verb);
+
+ ndn::ControlResponse response;
+ (verbProcessor->second)(this, options, response);
+
+ sendResponse(command, response);
}
else
{
- NFD_LOG_INFO("Unsupported command verb: " << verb);
+ NFD_LOG_INFO("command result: unsupported verb: " << verb);
sendResponse(request.getName(), 501, "Unsupported command");
}
}
-void
-FibManager::fibInsert(const Interest& request)
-{
-
-}
-
-void
-FibManager::fibDelete(const Interest& request)
-{
-
-}
-
-void
-FibManager::fibAddNextHop(const Interest& request)
+bool
+FibManager::extractOptions(const Interest& request,
+ ndn::FibManagementOptions& extractedOptions)
{
const Name& command = request.getName();
- ndn::FibManagementOptions options;
const size_t optionCompIndex =
FIB_MANAGER_COMMAND_PREFIX.size() + 1;
@@ -148,49 +148,117 @@
try
{
Block rawOptions(tmpOptionBuffer);
- options.wireDecode(rawOptions);
+ extractedOptions.wireDecode(rawOptions);
}
catch (const ndn::Tlv::Error& e)
{
NFD_LOG_INFO("Bad command option parse: " << command);
- sendResponse(request.getName(), 400, "Malformed command");
- return;
+ return false;
}
+ NFD_LOG_DEBUG("Options parsed OK");
+ return true;
+}
- /// \todo authorize command
- if (false)
- {
- NFD_LOG_INFO("Unauthorized command attempt: " << command);
- sendResponse(request.getName(), 403, "Unauthorized command");
- return;
- }
+void
+FibManager::insertEntry(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response)
+{
+ NFD_LOG_DEBUG("insert prefix: " << options.getName());
+ NFD_LOG_INFO("insert result: OK"
+ << " prefix: " << options.getName());
+ std::pair<shared_ptr<fib::Entry>, bool> insertResult = m_managedFib.insert(options.getName());
+ setResponse(response, 200, "OK");
+}
- NFD_LOG_INFO("add-nexthop Name: " << options.getName()
- << " FaceId: " << options.getFaceId()
- << " Cost: " << options.getCost());
+void
+FibManager::deleteEntry(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response)
+{
+ NFD_LOG_DEBUG("delete prefix: " << options.getName());
+ NFD_LOG_INFO("delete result: OK"
+ << " prefix: " << options.getName());
+
+ m_managedFib.remove(options.getName());
+ setResponse(response, 200, "OK");
+}
+
+static inline bool
+nextHopEqPredicate(const fib::NextHop& target, const fib::NextHop& hop)
+{
+ return target.getFace()->getId() == hop.getFace()->getId();
+}
+
+void
+FibManager::addNextHop(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response)
+{
+ NFD_LOG_DEBUG("add-nexthop prefix: " << options.getName()
+ << " faceid: " << options.getFaceId()
+ << " cost: " << options.getCost());
shared_ptr<Face> nextHopFace = m_getFace(options.getFaceId());
if (static_cast<bool>(nextHopFace))
{
- std::pair<shared_ptr<fib::Entry>, bool> insertResult = m_managedFib.insert(options.getName());
- insertResult.first->addNextHop(nextHopFace, options.getCost());
- sendResponse(request.getName(), 200, "OK");
+ shared_ptr<fib::Entry> entry = m_managedFib.findExactMatch(options.getName());
+ if (static_cast<bool>(entry))
+ {
+ entry->addNextHop(nextHopFace, options.getCost());
+
+ NFD_LOG_INFO("add-nexthop result: OK"
+ << " prefix:" << options.getName()
+ << " faceid: " << options.getFaceId()
+ << " cost: " << options.getCost());
+ setResponse(response, 200, "OK");
+ }
+ else
+ {
+ NFD_LOG_INFO("add-nexthop result: FAIL reason: unknown-prefix: " << options.getName());
+ setResponse(response, 404, "Prefix not found");
+ }
}
else
{
- NFD_LOG_INFO("Unknown FaceId: " << command);
- sendResponse(request.getName(), 400, "Malformed command");
+ NFD_LOG_INFO("add-nexthop result: FAIL reason: unknown-faceid: " << options.getFaceId());
+ setResponse(response, 404, "Face not found");
}
}
void
-FibManager::fibRemoveNextHop(const Interest& request)
+FibManager::removeNextHop(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse &response)
{
+ NFD_LOG_DEBUG("remove-nexthop prefix: " << options.getName()
+ << " faceid: " << options.getFaceId());
+ shared_ptr<Face> faceToRemove = m_getFace(options.getFaceId());
+ if (static_cast<bool>(faceToRemove))
+ {
+ shared_ptr<fib::Entry> entry = m_managedFib.findExactMatch(options.getName());
+ if (static_cast<bool>(entry))
+ {
+ entry->removeNextHop(faceToRemove);
+ NFD_LOG_INFO("remove-nexthop result: OK prefix: " << options.getName()
+ << " faceid: " << options.getFaceId());
+
+ setResponse(response, 200, "OK");
+ }
+ else
+ {
+ NFD_LOG_INFO("remove-nexthop result: FAIL reason: unknown-prefix: "
+ << options.getName());
+ setResponse(response, 404, "Prefix not found");
+ }
+ }
+ else
+ {
+ NFD_LOG_INFO("remove-nexthop result: FAIL reason: unknown-faceid: "
+ << options.getFaceId());
+ setResponse(response, 404, "Face not found");
+ }
}
void
-FibManager::fibStrategy(const Interest& request)
+FibManager::strategy(const ndn::FibManagementOptions& options, ndn::ControlResponse& response)
{
}
diff --git a/daemon/mgmt/fib-manager.hpp b/daemon/mgmt/fib-manager.hpp
index d77a2f2..3b36aeb 100644
--- a/daemon/mgmt/fib-manager.hpp
+++ b/daemon/mgmt/fib-manager.hpp
@@ -13,6 +13,9 @@
#include "fw/strategy.hpp"
#include "mgmt/manager-base.hpp"
+#include <ndn-cpp-dev/management/fib-management-options.hpp>
+#include <ndn-cpp-dev/management/control-response.hpp>
+
namespace nfd {
class Forwarder;
@@ -32,19 +35,28 @@
private:
void
- fibInsert(const Interest& request);
+ insertEntry(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response);
void
- fibDelete(const Interest& request);
+ deleteEntry(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response);
void
- fibAddNextHop(const Interest& request);
+ addNextHop(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response);
void
- fibRemoveNextHop(const Interest& request);
+ removeNextHop(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response);
void
- fibStrategy(const Interest& request);
+ strategy(const ndn::FibManagementOptions& options,
+ ndn::ControlResponse& response);
+
+ bool
+ extractOptions(const Interest& request,
+ ndn::FibManagementOptions& extractedOptions);
// void
// onConfig(ConfigFile::Node section, bool isDryRun);
@@ -56,7 +68,8 @@
std::map<Name, shared_ptr<fw::Strategy> > m_namespaceToStrategyMap;
typedef function<void(FibManager*,
- const Interest&)> VerbProcessor;
+ const ndn::FibManagementOptions&,
+ ndn::ControlResponse&)> VerbProcessor;
typedef std::map<Name::Component, VerbProcessor> VerbDispatchTable;
diff --git a/daemon/mgmt/manager-base.cpp b/daemon/mgmt/manager-base.cpp
index 55787b6..8ab06e8 100644
--- a/daemon/mgmt/manager-base.cpp
+++ b/daemon/mgmt/manager-base.cpp
@@ -7,8 +7,6 @@
#include "manager-base.hpp"
#include "mgmt/app-face.hpp"
-#include <ndn-cpp-dev/management/control-response.hpp>
-
namespace nfd {
NFD_LOG_INIT("ManagerBase");
@@ -26,22 +24,29 @@
void
ManagerBase::sendResponse(const Name& name,
- uint32_t code,
- const std::string& text)
+ uint32_t code,
+ const std::string& text)
{
- ndn::ControlResponse control(code, text);
- const Block& encodedControl = control.wireEncode();
+ ndn::ControlResponse response(code, text);
+ sendResponse(name, response);
+}
- NFD_LOG_DEBUG("sending control response"
- << " Name: " << name
- << " code: " << code
- << " text: " << text);
+void
+ManagerBase::sendResponse(const Name& name,
+ const ndn::ControlResponse& response)
+{
+ NFD_LOG_DEBUG("responding"
+ << " name: " << name
+ << " code: " << response.getCode()
+ << " text: " << response.getText());
- Data response(name);
- response.setContent(encodedControl);
+ const Block& encodedControl = response.wireEncode();
- m_face->sign(response);
- m_face->put(response);
+ Data responseData(name);
+ responseData.setContent(encodedControl);
+
+ m_face->sign(responseData);
+ m_face->put(responseData);
}
diff --git a/daemon/mgmt/manager-base.hpp b/daemon/mgmt/manager-base.hpp
index d62b1c0..e8da7c9 100644
--- a/daemon/mgmt/manager-base.hpp
+++ b/daemon/mgmt/manager-base.hpp
@@ -8,7 +8,7 @@
#define NFD_MGMT_MANAGER_BASE_HPP
#include "common.hpp"
-
+#include <ndn-cpp-dev/management/control-response.hpp>
namespace nfd {
@@ -25,14 +25,32 @@
protected:
void
+ setResponse(ndn::ControlResponse& response,
+ uint32_t code,
+ const std::string& text);
+
+ void
sendResponse(const Name& name,
- uint32_t code,
- const std::string& text);
+ const ndn::ControlResponse& response);
+
+ void
+ sendResponse(const Name& name,
+ uint32_t code,
+ const std::string& text);
protected:
shared_ptr<AppFace> m_face;
};
+inline void
+ManagerBase::setResponse(ndn::ControlResponse& response,
+ uint32_t code,
+ const std::string& text)
+{
+ response.setCode(code);
+ response.setText(text);
+}
+
} // namespace nfd
diff --git a/tests/mgmt/fib-manager.cpp b/tests/mgmt/fib-manager.cpp
index b07d11b..25c38b3 100644
--- a/tests/mgmt/fib-manager.cpp
+++ b/tests/mgmt/fib-manager.cpp
@@ -5,7 +5,6 @@
*/
#include "mgmt/fib-manager.hpp"
-#include "fw/forwarder.hpp"
#include "table/fib.hpp"
#include "table/fib-nexthop.hpp"
#include "face/face.hpp"
@@ -52,6 +51,7 @@
void
validateControlResponse(const Data& response,
+ const Name& expectedName,
uint32_t expectedCode,
const std::string& expectedText)
{
@@ -66,8 +66,9 @@
<< " code: " << control.getCode()
<< " text: " << control.getText());
- BOOST_REQUIRE(control.getCode() == expectedCode);
- BOOST_REQUIRE(control.getText() == expectedText);
+ BOOST_CHECK_EQUAL(response.getName(), expectedName);
+ BOOST_CHECK_EQUAL(control.getCode(), expectedCode);
+ BOOST_CHECK_EQUAL(control.getText(), expectedText);
}
bool
@@ -101,7 +102,7 @@
bool
addedNextHopWithCost(const Fib& fib, const Name& prefix, size_t oldSize, uint32_t cost)
{
- shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch(prefix);
+ shared_ptr<fib::Entry> entry = fib.findExactMatch(prefix);
if (static_cast<bool>(entry))
{
@@ -112,42 +113,44 @@
return false;
}
-BOOST_AUTO_TEST_CASE(TestFireInterestFilter)
+BOOST_FIXTURE_TEST_CASE(TestFireInterestFilter, FibManagerFixture)
{
- FibManagerFixture fixture;
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- &fixture, _1),
- face);
-
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, &fixture, _1, 400, "Malformed command");
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
Interest command("/localhost/nfd/fib");
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ command.getName(), 400, "Malformed command");
+
face->sendInterest(command);
+
+ BOOST_REQUIRE(didCallbackFire());
}
-BOOST_AUTO_TEST_CASE(MalformedCommmand)
+BOOST_FIXTURE_TEST_CASE(MalformedCommmand, FibManagerFixture)
{
- FibManagerFixture fixture;
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- &fixture, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- BOOST_REQUIRE(fixture.didCallbackFire() == false);
-
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, &fixture, _1, 400, "Malformed command");
+ BOOST_REQUIRE(didCallbackFire() == false);
Interest command("/localhost/nfd/fib");
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ command.getName(), 400, "Malformed command");
+
manager.onFibRequest(command);
- BOOST_REQUIRE(fixture.didCallbackFire());
+ BOOST_REQUIRE(didCallbackFire());
}
BOOST_FIXTURE_TEST_CASE(UnsupportedVerb, FibManagerFixture)
@@ -155,13 +158,9 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 501, "Unsupported command");
-
ndn::FibManagementOptions options;
options.setName("/hello");
options.setFaceId(1);
@@ -173,6 +172,10 @@
commandName.append("unsupported");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 501, "Unsupported command");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -186,13 +189,8 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
- /// \todo enable once sig checking implement
- // bind(&FibManagerFixture::validateControlResponse, this, _1, 401, "SIGREG");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -205,11 +203,17 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Prefix not found");
+ /// \todo enable once sig checking implemented
+ // bind(&FibManagerFixture::validateControlResponse, this, _1, 401, "Signature required");
+
Interest command(commandName);
manager.onFibRequest(command);
BOOST_REQUIRE(didCallbackFire());
- BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", 0, 101));
+ BOOST_REQUIRE(!addedNextHopWithCost(fib, "/hello", 0, 101));
}
BOOST_FIXTURE_TEST_CASE(UnauthorizedCommand, FibManagerFixture)
@@ -219,13 +223,8 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
- /// \todo enable once sig checking implement
- // bind(&FibManagerFixture::validateControlResponse, this, _1, 403, "Unauthorized command");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -238,11 +237,17 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Prefix not found");
+ /// \todo enable once sig checking implemented
+ // bind(&FibManagerFixture::validateControlResponse, this, _1, 403, "Unauthorized command");
+
Interest command(commandName);
manager.onFibRequest(command);
BOOST_REQUIRE(didCallbackFire());
- BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", 0, 101));
+ BOOST_REQUIRE(!addedNextHopWithCost(fib, "/hello", 0, 101));
}
BOOST_FIXTURE_TEST_CASE(BadOptionParse, FibManagerFixture)
@@ -252,17 +257,17 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 400, "Malformed command");
-
Name commandName("/localhost/nfd/fib");
commandName.append("add-nexthop");
commandName.append("NotReallyOptions");
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 400, "Malformed command");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -276,13 +281,9 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 400, "Malformed command");
-
ndn::FibManagementOptions options;
options.setName("/hello");
options.setFaceId(1000);
@@ -294,6 +295,10 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Face not found");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -308,11 +313,8 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -325,6 +327,12 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
+ fib.insert("/hello");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -335,26 +343,21 @@
BOOST_FIXTURE_TEST_CASE(AddNextHopVerbAddToExisting, FibManagerFixture)
{
addFace(make_shared<DummyFace>());
- addFace(make_shared<DummyFace>());
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
- // Add faces with cost == FaceID for the name /hello
- // This test assumes:
- // FaceIDs are -1 because we don't add them to a forwarder
+ fib.insert("/hello");
for (int i = 1; i <= 2; i++)
{
+
ndn::FibManagementOptions options;
options.setName("/hello");
- options.setFaceId(i);
+ options.setFaceId(1);
options.setCost(100 + i);
Block encodedOptions(options.wireEncode());
@@ -363,25 +366,31 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
Interest command(commandName);
manager.onFibRequest(command);
BOOST_REQUIRE(didCallbackFire());
resetCallbackFired();
- shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
+ shared_ptr<fib::Entry> entry = fib.findExactMatch("/hello");
if (static_cast<bool>(entry))
{
const fib::NextHopList& hops = entry->getNextHops();
- for (int j = 1; j <= i; j++)
- {
- BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", i - 1, 100 + j));
- }
+ BOOST_REQUIRE(hops.size() == 1);
+ BOOST_REQUIRE(std::find_if(hops.begin(), hops.end(),
+ bind(&foundNextHop, -1, 100 + i, _1)) != hops.end());
+
}
else
{
BOOST_FAIL("Failed to find expected fib entry");
}
+
+ face->onReceiveData.clear();
}
}
@@ -396,8 +405,8 @@
bind(&FibManagerFixture::getFace,
this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
+
+ fib.insert("/hello");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -412,12 +421,19 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
Interest command(commandName);
manager.onFibRequest(command);
+
BOOST_REQUIRE(didCallbackFire());
- resetCallbackFired();
}
+ resetCallbackFired();
+ face->onReceiveData.clear();
+
{
options.setCost(102);
@@ -427,12 +443,17 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
Interest command(commandName);
manager.onFibRequest(command);
+
BOOST_REQUIRE(didCallbackFire());
}
- shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
+ shared_ptr<fib::Entry> entry = fib.findExactMatch("/hello");
// Add faces with cost == FaceID for the name /hello
// This test assumes:
@@ -451,6 +472,286 @@
}
}
+BOOST_FIXTURE_TEST_CASE(Insert, FibManagerFixture)
+{
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ {
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("insert");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+ }
+
+ BOOST_REQUIRE(didCallbackFire());
+
+ shared_ptr<fib::Entry> entry = fib.findExactMatch("/hello");
+ if (static_cast<bool>(entry))
+ {
+ const fib::NextHopList& hops = entry->getNextHops();
+ BOOST_CHECK_EQUAL(hops.size(), 0);
+ }
+
+ resetCallbackFired();
+
+ {
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("insert");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+ }
+
+ BOOST_REQUIRE(didCallbackFire());
+
+ entry = fib.findExactMatch("/hello");
+ if (static_cast<bool>(entry))
+ {
+ const fib::NextHopList& hops = entry->getNextHops();
+ BOOST_CHECK_EQUAL(hops.size(), 0);
+ }
+
+}
+
+void
+testRemove(FibManagerFixture* fixture,
+ FibManager& manager,
+ Fib& fib,
+ shared_ptr<Face> face,
+ const Name& target)
+{
+ ndn::FibManagementOptions options;
+ options.setName(target);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("delete");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, fixture, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(fixture->didCallbackFire());
+
+ if (static_cast<bool>(fib.findExactMatch(target)))
+ {
+ BOOST_FAIL("Found \"removed\" prefix");
+ }
+ face->onReceiveData.clear();
+}
+
+BOOST_FIXTURE_TEST_CASE(Delete, FibManagerFixture)
+{
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ fib.insert("/a");
+ fib.insert("/a/b");
+ fib.insert("/a/b/c");
+
+ testRemove(this, manager, fib, face, "/");
+
+ if (!static_cast<bool>(fib.findExactMatch("/a")) ||
+ !static_cast<bool>(fib.findExactMatch("/a/b")) ||
+ !static_cast<bool>(fib.findExactMatch("/a/b/c")))
+ {
+ BOOST_FAIL("Removed incorrect entry");
+ }
+
+ testRemove(this, manager, fib, face, "/a/b");
+
+ if (!static_cast<bool>(fib.findExactMatch("/a")) ||
+ !static_cast<bool>(fib.findExactMatch("/a/b/c")))
+ {
+ BOOST_FAIL("Removed incorrect entry");
+ }
+
+ testRemove(this, manager, fib, face, "/a/b/c");
+
+ if (!static_cast<bool>(fib.findExactMatch("/a")))
+ {
+ BOOST_FAIL("Removed incorrect entry");
+ }
+
+ testRemove(this, manager, fib, face, "/a");
+
+ testRemove(this, manager, fib, face, "/does/not/exist");
+}
+
+bool
+removedNextHopWithCost(const Fib& fib, const Name& prefix, size_t oldSize, uint32_t cost)
+{
+ shared_ptr<fib::Entry> entry = fib.findExactMatch(prefix);
+
+ if (static_cast<bool>(entry))
+ {
+ const fib::NextHopList& hops = entry->getNextHops();
+ return hops.size() == oldSize - 1 &&
+ std::find_if(hops.begin(), hops.end(), bind(&foundNextHop, -1, cost, _1)) == hops.end();
+ }
+ return false;
+}
+
+void
+testRemoveNextHop(FibManagerFixture* fixture,
+ FibManager& manager,
+ Fib& fib,
+ shared_ptr<Face> face,
+ const Name& targetName,
+ FaceId targetFace)
+{
+ ndn::FibManagementOptions options;
+ options.setName(targetName);
+ options.setFaceId(targetFace);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("remove-nexthop");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, fixture, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(fixture->didCallbackFire());
+
+ fixture->resetCallbackFired();
+ face->onReceiveData.clear();
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveNextHop, FibManagerFixture)
+{
+ shared_ptr<Face> face1 = make_shared<DummyFace>();
+ shared_ptr<Face> face2 = make_shared<DummyFace>();
+ shared_ptr<Face> face3 = make_shared<DummyFace>();
+
+ addFace(face1);
+ addFace(face2);
+ addFace(face3);
+
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ shared_ptr<fib::Entry> entry = fib.insert("/hello").first;
+
+ entry->addNextHop(face1, 101);
+ entry->addNextHop(face2, 202);
+ entry->addNextHop(face3, 303);
+
+ testRemoveNextHop(this, manager, fib, face, "/hello", 2);
+ BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 3, 202));
+
+ testRemoveNextHop(this, manager, fib, face, "/hello", 3);
+ BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 2, 303));
+
+ testRemoveNextHop(this, manager, fib, face, "/hello", 1);
+ BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 1, 101));
+
+ if (!static_cast<bool>(fib.findExactMatch("/hello")))
+ {
+ BOOST_FAIL("removed entry after removing all next hops");
+ }
+
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveNoFace, FibManagerFixture)
+{
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+ options.setFaceId(1);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("remove-nexthop");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Face not found");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(didCallbackFire());
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveNoPrefix, FibManagerFixture)
+{
+ addFace(make_shared<DummyFace>());
+
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+ options.setFaceId(1);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("remove-nexthop");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Prefix not found");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(didCallbackFire());
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace nfd
diff --git a/tests/mgmt/manager-base.cpp b/tests/mgmt/manager-base.cpp
new file mode 100644
index 0000000..6105699
--- /dev/null
+++ b/tests/mgmt/manager-base.cpp
@@ -0,0 +1,141 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "mgmt/manager-base.hpp"
+#include "mgmt/internal-face.hpp"
+
+#include <ndn-cpp-dev/management/control-response.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+namespace nfd {
+
+NFD_LOG_INIT("ManagerBaseTest");
+
+BOOST_AUTO_TEST_SUITE(MgmtManagerBase)
+
+class ManagerBaseTest : public ManagerBase
+{
+
+public:
+
+ ManagerBaseTest()
+ : ManagerBase(make_shared<InternalFace>()),
+ m_callbackFired(false)
+ {
+
+ }
+
+ void
+ testSetResponse(ndn::ControlResponse& response,
+ uint32_t code,
+ const std::string& text)
+ {
+ setResponse(response, code, text);
+ }
+
+ void
+ testSendResponse(const Name& name,
+ uint32_t code,
+ const std::string& text)
+ {
+ sendResponse(name, code, text);
+ }
+
+ void
+ testSendResponse(const Name& name,
+ const ndn::ControlResponse& response)
+ {
+ sendResponse(name, response);
+ }
+
+ shared_ptr<InternalFace>
+ getInternalFace()
+ {
+ return ndn::ptr_lib::static_pointer_cast<InternalFace>(m_face);
+ }
+
+ void
+ validateControlResponse(const Data& response,
+ const Name& expectedName,
+ uint32_t expectedCode,
+ const std::string& expectedText)
+ {
+ m_callbackFired = true;
+ Block controlRaw = response.getContent().blockFromValue();
+
+ ndn::ControlResponse control;
+ control.wireDecode(controlRaw);
+
+ NFD_LOG_DEBUG("received control response"
+ << " name: " << response.getName()
+ << " code: " << control.getCode()
+ << " text: " << control.getText());
+
+ BOOST_REQUIRE(response.getName() == expectedName);
+ BOOST_REQUIRE(control.getCode() == expectedCode);
+ BOOST_REQUIRE(control.getText() == expectedText);
+ }
+
+ bool
+ didCallbackFire()
+ {
+ return m_callbackFired;
+ }
+
+private:
+
+ bool m_callbackFired;
+
+};
+
+BOOST_FIXTURE_TEST_CASE(SetResponse, ManagerBaseTest)
+{
+ ndn::ControlResponse response(200, "OK");
+
+ BOOST_CHECK_EQUAL(response.getCode(), 200);
+ BOOST_CHECK_EQUAL(response.getText(), "OK");
+
+ testSetResponse(response, 100, "test");
+
+ BOOST_CHECK_EQUAL(response.getCode(), 100);
+ BOOST_CHECK_EQUAL(response.getText(), "test");
+}
+
+
+BOOST_FIXTURE_TEST_CASE(SendResponse3Arg, ManagerBaseTest)
+{
+ getInternalFace()->onReceiveData +=
+ bind(&ManagerBaseTest::validateControlResponse, this, _1,
+ "/response", 100, "test");
+
+ testSendResponse("/response", 100, "test");
+ BOOST_REQUIRE(didCallbackFire());
+}
+
+
+BOOST_FIXTURE_TEST_CASE(SendResponse2Arg, ManagerBaseTest)
+{
+ getInternalFace()->onReceiveData +=
+ bind(&ManagerBaseTest::validateControlResponse, this, _1,
+ "/response", 100, "test");
+
+ ndn::ControlResponse response(100, "test");
+
+ testSendResponse("/response", 100, "test");
+ BOOST_REQUIRE(didCallbackFire());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+
+
+
+
+
+
+