rib: Switch RibManager to use NFD RIB Management protocol
Change-Id: I725529a96b5ad4318e0e0a8c2bd61b84ae439a32
Refs: #1490
diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp
index 26c3c2e..5afa492 100644
--- a/daemon/mgmt/fib-manager.cpp
+++ b/daemon/mgmt/fib-manager.cpp
@@ -137,8 +137,8 @@
const Name::Component& verb = command[COMMAND_PREFIX.size()];
const Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
- SignedVerbDispatchTable::const_iterator signedVerbProcessor = m_signedVerbDispatch.find (verb);
- if (signedVerbProcessor != m_signedVerbDispatch.end())
+ SignedVerbDispatchTable::const_iterator verbProcessor = m_signedVerbDispatch.find(verb);
+ if (verbProcessor != m_signedVerbDispatch.end())
{
ControlParameters parameters;
if (!extractParameters(parameterComponent, parameters) || !parameters.hasFaceId())
@@ -155,7 +155,7 @@
NFD_LOG_DEBUG("command result: processing verb: " << verb);
ControlResponse response;
- (signedVerbProcessor->second)(this, parameters, response);
+ (verbProcessor->second)(this, parameters, response);
sendResponse(command, response);
}
else
diff --git a/nfd.conf.sample.in b/nfd.conf.sample.in
index b0288e4..8c48743 100644
--- a/nfd.conf.sample.in
+++ b/nfd.conf.sample.in
@@ -193,7 +193,7 @@
filter
{
type name ; condition on interest name (w/o signature)
- regex ^[<localhop><localhost>]<nrd>[<register><unregister>]<>{3}$
+ regex ^[<localhop><localhost>]<nfd><rib>[<register><unregister>]<>{3}$
}
checker
{
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index afcd1b3..3594a71 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -32,8 +32,8 @@
NFD_LOG_INIT("RibManager");
-const Name RibManager::COMMAND_PREFIX = "/localhost/nrd";
-const Name RibManager::REMOTE_COMMAND_PREFIX = "/localhop/nrd";
+const Name RibManager::COMMAND_PREFIX = "/localhost/nfd/rib";
+const Name RibManager::REMOTE_COMMAND_PREFIX = "/localhop/nfd/rib";
const size_t RibManager::COMMAND_UNSIGNED_NCOMPS =
RibManager::COMMAND_PREFIX.size() +
@@ -48,12 +48,12 @@
{
VerbAndProcessor(
Name::Component("register"),
- &RibManager::insertEntry
+ &RibManager::registerEntry
),
VerbAndProcessor(
Name::Component("unregister"),
- &RibManager::deleteEntry
+ &RibManager::unregisterEntry
),
};
@@ -79,14 +79,14 @@
//check whether the components of localhop and localhost prefixes are same
BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size());
- NFD_LOG_INFO("Setting interest filter on: " << COMMAND_PREFIX.toUri());
+ NFD_LOG_INFO("Setting interest filter on: " << COMMAND_PREFIX);
m_face.setController(m_nfdController);
- m_face.setInterestFilter(COMMAND_PREFIX.toUri(),
+ m_face.setInterestFilter(COMMAND_PREFIX,
bind(&RibManager::onRibRequest, this, _2),
bind(&RibManager::setInterestFilterFailed, this, _1, _2));
- NFD_LOG_INFO("Setting interest filter on: " << REMOTE_COMMAND_PREFIX.toUri());
- m_face.setInterestFilter(REMOTE_COMMAND_PREFIX.toUri(),
+ NFD_LOG_INFO("Setting interest filter on: " << REMOTE_COMMAND_PREFIX);
+ m_face.setInterestFilter(REMOTE_COMMAND_PREFIX,
bind(&RibManager::onRibRequest, this, _2),
bind(&RibManager::setInterestFilterFailed, this, _1, _2));
@@ -145,37 +145,38 @@
RibManager::onRibRequest(const Interest& request)
{
m_validator.validate(request,
- bind(&RibManager::onRibRequestValidated, this, _1),
- bind(&RibManager::onRibRequestValidationFailed, this, _1, _2));
+ bind(&RibManager::onCommandValidated, this, _1),
+ bind(&RibManager::onCommandValidationFailed, this, _1, _2));
}
void
-RibManager::onRibRequestValidated(const shared_ptr<const Interest>& request)
+RibManager::onCommandValidated(const shared_ptr<const Interest>& request)
{
- const Name& command = request->getName();
-
- //REMOTE_COMMAND_PREFIX number of componenets are same as
+ // REMOTE_COMMAND_PREFIX number of componenets are same as
// NRD_COMMAND_PREFIX's so no extra checks are required.
- const Name::Component& verb = command.get(COMMAND_PREFIX.size());
- VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find(verb);
+ const Name& command = request->getName();
+ const Name::Component& verb = command[COMMAND_PREFIX.size()];
+ const Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
+
+ VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find(verb);
if (verbProcessor != m_verbDispatch.end())
{
- NFD_LOG_TRACE("Processing '" << verb << "' verb");
-
- PrefixRegOptions options;
- if (!extractOptions(*request, options))
+ ControlParameters parameters;
+ if (!extractParameters(parameterComponent, parameters))
{
- NFD_LOG_DEBUG("Error while extracting options, returning malformed command");
+ NFD_LOG_DEBUG("command result: malformed verb: " << verb);
sendResponse(command, 400, "Malformed command");
return;
}
- NFD_LOG_DEBUG("Received options (name, faceid, cost): " << options.getName()
- << ", " << options.getFaceId() << ", " << options.getCost());
+ if (!parameters.hasFaceId() || parameters.getFaceId() == 0)
+ {
+ parameters.setFaceId(request->getIncomingFaceId());
+ }
- ControlResponse response;
- (verbProcessor->second)(this, *request, options);
+ NFD_LOG_DEBUG("command result: processing verb: " << verb);
+ (verbProcessor->second)(this, request, parameters);
}
else
{
@@ -185,44 +186,119 @@
}
void
-RibManager::onRibRequestValidationFailed(const shared_ptr<const Interest>& request,
- const std::string& failureInfo)
+RibManager::registerEntry(const shared_ptr<const Interest>& request,
+ ControlParameters& parameters)
+{
+ ndn::nfd::RibRegisterCommand command;
+
+ if (!validateParameters(command, parameters))
+ {
+ NFD_LOG_DEBUG("register result: FAIL reason: malformed");
+ sendResponse(request->getName(), 400, "Malformed command");
+ return;
+ }
+
+ RibEntry ribEntry;
+ ribEntry.name = parameters.getName();
+ ribEntry.faceId = parameters.getFaceId();
+ ribEntry.origin = parameters.getOrigin();
+ ribEntry.cost = parameters.getCost();
+ ribEntry.flags = parameters.getFlags();
+ ribEntry.expires = time::steady_clock::now() + parameters.getExpirationPeriod();
+
+ NFD_LOG_TRACE("register prefix: " << ribEntry);
+
+ // For right now, just pass the options to fib as it is,
+ // without processing flags. Later options will be first added to
+ // Rib tree, then nrd will generate fib updates based on flags and then
+ // will add next hops one by one..
+ m_managedRib.insert(ribEntry);
+ m_nfdController->start<ndn::nfd::FibAddNextHopCommand>(
+ ControlParameters()
+ .setName(ribEntry.name)
+ .setFaceId(ribEntry.faceId)
+ .setCost(ribEntry.cost),
+ bind(&RibManager::onRegSuccess, this, request, parameters, ribEntry),
+ bind(&RibManager::onCommandError, this, _1, _2, request, ribEntry));
+}
+
+void
+RibManager::unregisterEntry(const shared_ptr<const Interest>& request,
+ ControlParameters& parameters)
+{
+ ndn::nfd::RibRegisterCommand command;
+
+ if (!validateParameters(command, parameters))
+ {
+ NFD_LOG_DEBUG("register result: FAIL reason: malformed");
+ sendResponse(request->getName(), 400, "Malformed command");
+ return;
+ }
+
+ RibEntry ribEntry;
+ ribEntry.name = parameters.getName();
+ ribEntry.faceId = parameters.getFaceId();
+ ribEntry.origin = parameters.getOrigin();
+
+ NFD_LOG_TRACE("unregister prefix: " << ribEntry);
+
+ m_nfdController->start<ndn::nfd::FibRemoveNextHopCommand>(
+ ControlParameters()
+ .setName(ribEntry.name)
+ .setFaceId(ribEntry.faceId),
+ bind(&RibManager::onUnRegSuccess, this, request, parameters, ribEntry),
+ bind(&RibManager::onCommandError, this, _1, _2, request, ribEntry));
+}
+
+void
+RibManager::onCommandValidationFailed(const shared_ptr<const Interest>& request,
+ const std::string& failureInfo)
{
NFD_LOG_DEBUG("RibRequestValidationFailed: " << failureInfo);
sendResponse(request->getName(), 403, failureInfo);
}
-bool
-RibManager::extractOptions(const Interest& request,
- PrefixRegOptions& extractedOptions)
-{
- // const Name& command = request.getName();
- //REMOTE_COMMAND_PREFIX is same in size of NRD_COMMAND_PREFIX
- //so no extra processing is required.
- const size_t optionCompIndex = COMMAND_PREFIX.size() + 1;
+bool
+RibManager::extractParameters(const Name::Component& parameterComponent,
+ ControlParameters& extractedParameters)
+{
try
{
- Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
- extractedOptions.wireDecode(rawOptions);
+ Block rawParameters = parameterComponent.blockFromValue();
+ extractedParameters.wireDecode(rawParameters);
}
catch (const ndn::Tlv::Error& e)
{
return false;
}
- if (extractedOptions.getFaceId() == 0)
+ NFD_LOG_DEBUG("Parameters parsed OK");
+ return true;
+}
+
+bool
+RibManager::validateParameters(const ControlCommand& command,
+ ControlParameters& parameters)
+{
+ try
{
- NFD_LOG_TRACE("IncomingFaceId: " << request.getIncomingFaceId());
- extractedOptions.setFaceId(request.getIncomingFaceId());
+ command.validateRequest(parameters);
}
+ catch (const ControlCommand::ArgumentError&)
+ {
+ return false;
+ }
+
+ command.applyDefaultsToRequest(parameters);
+
return true;
}
void
RibManager::onCommandError(uint32_t code, const std::string& error,
- const Interest& request,
- const PrefixRegOptions& options)
+ const shared_ptr<const Interest>& request,
+ const RibEntry& ribEntry)
{
NFD_LOG_ERROR("NFD returned an error: " << error << " (code: " << code << ")");
@@ -241,66 +317,42 @@
response.setText(os.str());
}
- sendResponse(request.getName(), response);
- m_managedRib.erase(options);
+ sendResponse(request->getName(), response);
+ m_managedRib.erase(ribEntry);
}
void
-RibManager::onUnRegSuccess(const Interest& request, const PrefixRegOptions& options)
+RibManager::onRegSuccess(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters,
+ const RibEntry& ribEntry)
{
ControlResponse response;
response.setCode(200);
response.setText("Success");
- response.setBody(options.wireEncode());
+ response.setBody(parameters.wireEncode());
- NFD_LOG_DEBUG("onUnRegSuccess: Name unregistered (" << options.getName()
- << ", " << options.getFaceId() << ")");
+ NFD_LOG_TRACE("onRegSuccess: registered " << ribEntry);
- sendResponse(request.getName(), response);
- m_managedRib.erase(options);
+ sendResponse(request->getName(), response);
}
+
void
-RibManager::onRegSuccess(const Interest& request, const PrefixRegOptions& options)
+RibManager::onUnRegSuccess(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters,
+ const RibEntry& ribEntry)
{
ControlResponse response;
response.setCode(200);
response.setText("Success");
- response.setBody(options.wireEncode());
+ response.setBody(parameters.wireEncode());
- NFD_LOG_DEBUG("onRegSuccess: Name registered (" << options.getName() << ", "
- << options.getFaceId() << ")");
- sendResponse(request.getName(), response);
-}
+ NFD_LOG_TRACE("onUnRegSuccess: unregistered " << ribEntry);
-void
-RibManager::insertEntry(const Interest& request, const PrefixRegOptions& options)
-{
- // For right now, just pass the options to fib as it is,
- // without processing flags. Later options will be first added to
- // Rib tree, then nrd will generate fib updates based on flags and then
- // will add next hops one by one..
- m_managedRib.insert(options);
- m_nfdController->start<ndn::nfd::FibAddNextHopCommand>(
- ControlParameters()
- .setName(options.getName())
- .setFaceId(options.getFaceId())
- .setCost(options.getCost()),
- bind(&RibManager::onRegSuccess, this, request, options),
- bind(&RibManager::onCommandError, this, _1, _2, request, options));
-}
-
-void
-RibManager::deleteEntry(const Interest& request, const PrefixRegOptions& options)
-{
- m_nfdController->start<ndn::nfd::FibRemoveNextHopCommand>(
- ControlParameters()
- .setName(options.getName())
- .setFaceId(options.getFaceId()),
- bind(&RibManager::onUnRegSuccess, this, request, options),
- bind(&RibManager::onCommandError, this, _1, _2, request, options));
+ sendResponse(request->getName(), response);
+ m_managedRib.erase(ribEntry);
}
void
diff --git a/rib/rib-manager.hpp b/rib/rib-manager.hpp
index 44299e6..a8984b1 100644
--- a/rib/rib-manager.hpp
+++ b/rib/rib-manager.hpp
@@ -76,22 +76,35 @@
const std::string& text);
void
- onRibRequestValidated(const shared_ptr<const Interest>& request);
+ registerEntry(const shared_ptr<const Interest>& request,
+ ControlParameters& parameters);
void
- onRibRequestValidationFailed(const shared_ptr<const Interest>& request,
- const std::string& failureInfo);
+ unregisterEntry(const shared_ptr<const Interest>& request,
+ ControlParameters& parameters);
+
+ void
+ onCommandValidated(const shared_ptr<const Interest>& request);
+
+ void
+ onCommandValidationFailed(const shared_ptr<const Interest>& request,
+ const std::string& failureInfo);
+
void
onCommandError(uint32_t code, const std::string& error,
- const ndn::Interest& interest,
- const PrefixRegOptions& options);
+ const shared_ptr<const Interest>& request,
+ const RibEntry& ribEntry);
void
- onRegSuccess(const ndn::Interest& interest, const PrefixRegOptions& options);
+ onRegSuccess(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters,
+ const RibEntry& ribEntry);
void
- onUnRegSuccess(const ndn::Interest& interest, const PrefixRegOptions& options);
+ onUnRegSuccess(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters,
+ const RibEntry& ribEntry);
void
onControlHeaderSuccess();
@@ -102,15 +115,13 @@
void
setInterestFilterFailed(const Name& name, const std::string& msg);
- void
- insertEntry(const Interest& request, const PrefixRegOptions& options);
-
- void
- deleteEntry(const Interest& request, const PrefixRegOptions& options);
+ static bool
+ extractParameters(const Name::Component& parameterComponent,
+ ControlParameters& extractedParameters);
bool
- extractOptions(const Interest& request,
- PrefixRegOptions& extractedOptions);
+ validateParameters(const ControlCommand& command,
+ ControlParameters& parameters);
void
onNotification(const FaceEventNotification& notification);
@@ -124,8 +135,8 @@
FaceMonitor m_faceMonitor;
typedef boost::function<void(RibManager*,
- const Interest&,
- const PrefixRegOptions&)> VerbProcessor;
+ const shared_ptr<const Interest>& request,
+ ControlParameters& parameters)> VerbProcessor;
typedef std::map<name::Component, VerbProcessor> VerbDispatchTable;
diff --git a/rib/rib.cpp b/rib/rib.cpp
index 8ad5ec6..4dc4175 100644
--- a/rib/rib.cpp
+++ b/rib/rib.cpp
@@ -38,19 +38,19 @@
}
static inline bool
-compareNameFaceProtocol(const PrefixRegOptions& opt1, const PrefixRegOptions& opt2)
+compareNameFaceProtocol(const RibEntry& entry1, const RibEntry& entry2)
{
- return (opt1.getName() == opt2.getName() &&
- opt1.getFaceId() == opt2.getFaceId() &&
- opt1.getProtocol() == opt2.getProtocol());
+ return (entry1.name == entry2.name &&
+ entry1.faceId == entry2.faceId &&
+ entry1.origin == entry2.origin);
}
Rib::const_iterator
-Rib::find(const PrefixRegOptions& options) const
+Rib::find(const RibEntry& entry) const
{
RibTable::const_iterator it = std::find_if(m_rib.begin(), m_rib.end(),
- bind(&compareNameFaceProtocol, _1, options));
+ bind(&compareNameFaceProtocol, _1, entry));
if (it == m_rib.end())
{
return end();
@@ -61,30 +61,29 @@
void
-Rib::insert(const PrefixRegOptions& options)
+Rib::insert(const RibEntry& entry)
{
RibTable::iterator it = std::find_if(m_rib.begin(), m_rib.end(),
- bind(&compareNameFaceProtocol, _1, options));
+ bind(&compareNameFaceProtocol, _1, entry));
if (it == m_rib.end())
{
- m_rib.push_front(options);
+ m_rib.push_front(entry);
}
else
{
- //entry exist, update other fields
- it->setFlags(options.getFlags());
- it->setCost(options.getCost());
- it->setExpirationPeriod(options.getExpirationPeriod());
- it->setProtocol(options.getProtocol());
+ // entry exist, update other fields
+ it->flags = entry.flags;
+ it->cost = entry.cost;
+ it->expires = entry.expires;
}
}
void
-Rib::erase(const PrefixRegOptions& options)
+Rib::erase(const RibEntry& entry)
{
RibTable::iterator it = std::find_if(m_rib.begin(), m_rib.end(),
- bind(&compareNameFaceProtocol, _1, options));
+ bind(&compareNameFaceProtocol, _1, entry));
if (it != m_rib.end())
{
m_rib.erase(it);
@@ -94,16 +93,31 @@
void
Rib::erase(uint64_t faceId)
{
- //Keep it simple for now, with Trie this will be changed.
+ // Keep it simple for now, with Trie this will be changed.
RibTable::iterator it = m_rib.begin();
while (it != m_rib.end())
{
- if (it->getFaceId() == faceId)
+ if (it->faceId == faceId)
it = m_rib.erase(it);
else
++it;
}
}
+std::ostream&
+operator<<(std::ostream& os, const RibEntry& entry)
+{
+ os << "RibEntry("
+ << "name: " << entry.name
+ << " faceid: " << entry.faceId
+ << " origin: " << entry.origin
+ << " cost: " << entry.cost
+ << " flags: " << entry.flags
+ << " expires in: " << (entry.expires - time::steady_clock::now())
+ << ")";
+
+ return os;
+}
+
} // namespace rib
} // namespace nfd
diff --git a/rib/rib.hpp b/rib/rib.hpp
index 745a760..e2371eb 100644
--- a/rib/rib.hpp
+++ b/rib/rib.hpp
@@ -27,21 +27,38 @@
#define NFD_RIB_RIB_HPP
#include "common.hpp"
-
-#include <ndn-cpp-dev/management/nrd-prefix-reg-options.hpp>
+#include <ndn-cpp-dev/management/nfd-control-command.hpp>
namespace nfd {
namespace rib {
-using ndn::nrd::PrefixRegOptions;
-namespace tlv = ndn::tlv;
+class RibEntry
+{
+public:
+ RibEntry()
+ : faceId(0)
+ , origin(0)
+ , flags(0)
+ , cost(0)
+ , expires(time::steady_clock::TimePoint::min())
+ {
+ }
+
+public:
+ Name name;
+ uint64_t faceId;
+ uint64_t origin;
+ uint64_t flags;
+ uint64_t cost;
+ time::steady_clock::TimePoint expires;
+};
/** \brief represents the RIB
*/
-class Rib
+class Rib : noncopyable
{
public:
- typedef std::list<PrefixRegOptions> RibTable;
+ typedef std::list<RibEntry> RibTable;
typedef RibTable::const_iterator const_iterator;
Rib();
@@ -49,13 +66,13 @@
~Rib();
const_iterator
- find(const PrefixRegOptions& options) const;
+ find(const RibEntry& entry) const;
void
- insert(const PrefixRegOptions& options);
+ insert(const RibEntry& entry);
void
- erase(const PrefixRegOptions& options);
+ erase(const RibEntry& entry);
void
erase(uint64_t faceId);
@@ -102,6 +119,9 @@
return m_rib.empty();
}
+std::ostream&
+operator<<(std::ostream& os, const RibEntry& entry);
+
} // namespace rib
} // namespace nfd
diff --git a/tests/rib/rib.cpp b/tests/rib/rib.cpp
index fd5777b..a8a0110 100644
--- a/tests/rib/rib.cpp
+++ b/tests/rib/rib.cpp
@@ -37,46 +37,59 @@
{
rib::Rib rib;
- PrefixRegOptions options1;
- options1.setName("/hello/world");
- options1.setFlags(tlv::nrd::NDN_FORW_CHILD_INHERIT | tlv::nrd::NDN_FORW_CAPTURE);
- options1.setCost(10);
- options1.setExpirationPeriod(time::milliseconds(1500));
- options1.setFaceId(1);
+ RibEntry entry1;
+ entry1.name = "/hello/world";
+ entry1.faceId = 1;
+ entry1.origin = 20;
+ entry1.cost = 10;
+ entry1.flags = ndn::nfd::ROUTE_FLAG_CHILD_INHERIT | ndn::nfd::ROUTE_FLAG_CAPTURE;
+ entry1.expires = time::steady_clock::now() + time::milliseconds(1500);
- rib.insert(options1);
+ rib.insert(entry1);
BOOST_CHECK_EQUAL(rib.size(), 1);
- PrefixRegOptions options2;
- options2.setName("/hello/world");
- options2.setFlags(tlv::nrd::NDN_FORW_CHILD_INHERIT);
- options2.setExpirationPeriod(time::seconds(0));
- options2.setFaceId(1);
- options2.setCost(100);
-
- rib.insert(options2);
+ rib.insert(entry1);
BOOST_CHECK_EQUAL(rib.size(), 1);
- options2.setFaceId(2);
- rib.insert(options2);
+ RibEntry entry2;
+ entry2.name = "/hello/world";
+ entry2.faceId = 1;
+ entry2.origin = 20;
+ entry2.cost = 100;
+ entry2.flags = ndn::nfd::ROUTE_FLAG_CHILD_INHERIT;
+ entry2.expires = time::steady_clock::now() + time::seconds(0);
+
+ rib.insert(entry2);
+ BOOST_CHECK_EQUAL(rib.size(), 1);
+
+ entry2.faceId = 2;
+ rib.insert(entry2);
BOOST_CHECK_EQUAL(rib.size(), 2);
- options2.setName("/foo/bar");
- rib.insert(options2);
+ entry2.name = "/foo/bar";
+ rib.insert(entry2);
BOOST_CHECK_EQUAL(rib.size(), 3);
- rib.erase(options2);
+ entry2.origin = 1;
+ rib.insert(entry2);
+ BOOST_CHECK_EQUAL(rib.size(), 4);
+
+ rib.erase(entry2);
+ BOOST_CHECK_EQUAL(rib.size(), 3);
+
+ entry2.name = "/hello/world";
+ rib.erase(entry2);
+ BOOST_CHECK_EQUAL(rib.size(), 3);
+
+ entry2.origin = 20;
+ rib.erase(entry2);
BOOST_CHECK_EQUAL(rib.size(), 2);
- options2.setName("/hello/world");
- rib.erase(options2);
+ BOOST_CHECK(rib.find(entry2) == rib.end());
+ BOOST_CHECK(rib.find(entry1) != rib.end());
+
+ rib.erase(entry1);
BOOST_CHECK_EQUAL(rib.size(), 1);
-
- BOOST_CHECK(rib.find(options2) == rib.end());
- BOOST_CHECK(rib.find(options1) != rib.end());
-
- rib.erase(options1);
- BOOST_CHECK(rib.empty());
}
BOOST_AUTO_TEST_SUITE_END()