tools: Add nlsrc command line tool

refs: #1834

Change-Id: Ifbe75a3f49e2689930e61ebfd348d9932b04c975
This commit is contained in:
Vince Lehman committed 2015-04-27 15:49:04 -05:00
1 parent d6bb3fa306
commit c439d66728
6 files changed
+647 -1

No files matched your search

+2 -1
View File
@@ -59,7 +59,7 @@ master_doc = 'index'
# General information about the project.
project = u'NLSR - Named Data Link State Routing Protocol'
copyright = u'2014, Named Data Networking Project'
copyright = u'2014-2015, Named Data Networking Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -239,6 +239,7 @@ latex_documents = [
man_pages = [
('manpages/nlsr', 'nlsr', u'Named Data Link State Routing Protocol Daemon', None, 1),
('manpages/nlsr.conf', 'nlsr.conf', u'Named Data Link State Routing Protocol Daemon config file', None, 5),
('manpages/nlsrc', 'nlsrc', u'Command-line utility to interact with and collect statistics from NLSR', None, 1),
]
+1
View File
@@ -6,4 +6,5 @@ Manpages
.. toctree::
manpages/nlsr
manpages/nlsr.conf
manpages/nlsrc
:maxdepth: 1
+55
View File
@@ -0,0 +1,55 @@
nlsrc
=====
Usage
-----
::
nlsrc [-h] [-V] COMMAND [<Command Options>]
Description
-----------
``nlsrc`` is a tool to retrieve link-state database (LSDB) status information from NLSR and
announce/withdraw Name prefixes advertised by NLSR.
Options
-------
``-h``
Print usage information
``-V``
Show NLSRC version information
``COMMAND``
``status``
Retrieve LSDB status information
``advertise``
Add a Name prefix to be advertised by NLSR
``advertise <name>``
``name``
The Name prefix to be advertised
``withdraw``
Remove a Name prefix advertised through NLSR
``withdraw <name>``
``name``
The Name prefix to be withdrawn
Exit Status
-----------
nlsrc exits with one of the following values:
::
0 nlsrc exited successfully
>0 An error occurred
+412
View File
@@ -0,0 +1,412 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, The University of Memphis,
* Regents of the University of California,
* Arizona Board of Regents.
*
* This file is part of NLSR (Named-data Link State Routing).
* See AUTHORS.md for complete list of NLSR authors and contributors.
*
* NLSR is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
**/
#include "nlsrc.hpp"
#include "version.hpp"
#include "src/publisher/lsa-publisher.hpp"
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/data.hpp>
#include <ndn-cxx/interest.hpp>
#include <ndn-cxx/encoding/block.hpp>
#include <ndn-cxx/management/nfd-control-parameters.hpp>
#include <ndn-cxx/management/nfd-control-response.hpp>
#include <ndn-cxx/util/segment-fetcher.hpp>
#include <iostream>
namespace nlsrc {
const ndn::Name Nlsrc::LOCALHOST_PREFIX = ndn::Name("/localhost/nlsr");
const ndn::Name Nlsrc::LSDB_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("lsdb");
const ndn::Name Nlsrc::NAME_UPDATE_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("prefix-update");
const uint32_t Nlsrc::ERROR_CODE_TIMEOUT = 10060;
const uint32_t Nlsrc::RESPONSE_CODE_SUCCESS = 200;
Nlsrc::Nlsrc(ndn::Face& face)
: m_face(face)
{
}
void
Nlsrc::printUsage()
{
std::cout << "Usage:\n" << programName << " [-h] [-V] COMMAND [<Command Options>]\n"
" -h print usage and exit\n"
" -V print version and exit\n"
"\n"
" COMMAND can be one of the following:\n"
" status\n"
" display NLSR status\n"
" advertise name\n"
" advertise a name prefix through NLSR\n"
" withdraw name\n"
" remove a name prefix advertised through NLSR"
<< std::endl;
}
void
Nlsrc::getStatus()
{
m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
m_fetchSteps.push_back(std::bind(&Nlsrc::printLsdb, this));
runNextStep();
}
bool
Nlsrc::dispatch(const std::string& command)
{
if (command == "advertise") {
if (nOptions != 1) {
return false;
}
advertiseName();
return true;
}
else if (command == "withdraw") {
if (nOptions != 1) {
return false;
}
withdrawName();
return true;
}
else if (command == "status") {
if (nOptions != 0) {
return false;
}
getStatus();
return true;
}
return false;
}
void
Nlsrc::runNextStep()
{
if (m_fetchSteps.empty()) {
return;
}
std::function<void()> nextStep = m_fetchSteps.front();
m_fetchSteps.pop_front();
nextStep();
}
void
Nlsrc::advertiseName()
{
ndn::Name name = commandLineArguments[0];
ndn::Name::Component verb("advertise");
std::string info = "(Advertise: " + name.toUri() + ")";
sendNamePrefixUpdate(name, verb, info);
}
void
Nlsrc::withdrawName()
{
ndn::Name name = commandLineArguments[0];
ndn::Name::Component verb("withdraw");
std::string info = "(Withdraw: " + name.toUri() + ")";
sendNamePrefixUpdate(name, verb, info);
}
void
Nlsrc::sendNamePrefixUpdate(const ndn::Name& name,
const ndn::Name::Component& verb,
const std::string& info)
{
ndn::nfd::ControlParameters parameters;
parameters.setName(name);
ndn::Name commandName = NAME_UPDATE_PREFIX;
commandName.append(verb);
ndn::Interest interest(commandName.append(parameters.wireEncode()));
interest.setMustBeFresh(true);
m_keyChain.sign(interest);
m_face.expressInterest(interest,
std::bind(&Nlsrc::onControlResponse, this, info, _2),
std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Timeout"));
}
void
Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
{
ndn::nfd::ControlResponse response;
try {
response.wireDecode(data.getContent().blockFromValue());
}
catch (const std::exception& e) {
std::cerr << "ERROR: Control response decoding error" << std::endl;
return;
}
uint32_t code = response.getCode();
if (code != RESPONSE_CODE_SUCCESS) {
std::cerr << "Name prefix update error (code: " << code << ")" << std::endl;
return;
}
std::cout << "Applied Name prefix update successfully: " << info << std::endl;
}
void
Nlsrc::fetchAdjacencyLsas()
{
fetchFromLsdb<nlsr::tlv::AdjacencyLsa>(nlsr::AdjacencyLsaPublisher::DATASET_COMPONENT,
std::bind(&Nlsrc::recordAdjacencyLsa, this, _1));
}
void
Nlsrc::fetchCoordinateLsas()
{
fetchFromLsdb<nlsr::tlv::CoordinateLsa>(nlsr::CoordinateLsaPublisher::DATASET_COMPONENT,
std::bind(&Nlsrc::recordCoordinateLsa, this, _1));
}
void
Nlsrc::fetchNameLsas()
{
fetchFromLsdb<nlsr::tlv::NameLsa>(nlsr::NameLsaPublisher::DATASET_COMPONENT,
std::bind(&Nlsrc::recordNameLsa, this, _1));
}
template <class T>
void
Nlsrc::fetchFromLsdb(const ndn::Name::Component& datasetType,
const std::function<void(const T&)>& recordLsa)
{
ndn::Name command = LSDB_PREFIX;
command.append(datasetType);
ndn::Interest interest(command);
ndn::util::SegmentFetcher::fetch(m_face,
interest,
ndn::util::DontVerifySegment(),
std::bind(&Nlsrc::onFetchSuccess<T>,
this, _1, recordLsa),
std::bind(&Nlsrc::onTimeout, this, _1, _2));
}
template <class T>
void
Nlsrc::onFetchSuccess(const ndn::ConstBufferPtr& data,
const std::function<void(const T&)>& recordLsa)
{
ndn::Block block;
size_t offset = 0;
while (offset < data->size()) {
bool isOk = false;
std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode LSA TLV" << std::endl;
break;
}
offset += block.size();
T lsa(block);
recordLsa(lsa);
}
runNextStep();
}
void
Nlsrc::onTimeout(uint32_t errorCode, const std::string& error)
{
std::cerr << "Request timed out (code: " << errorCode
<< ", error: " << error << ")" << std::endl;
}
std::string
Nlsrc::getLsaInfoString(const nlsr::tlv::LsaInfo& info)
{
std::ostringstream os;
os << " info=" << info;
return os.str();
}
void
Nlsrc::recordAdjacencyLsa(const nlsr::tlv::AdjacencyLsa& lsa)
{
Router& router = getRouter(lsa.getLsaInfo());
std::ostringstream os;
os << " AdjacencyLsa:" << std::endl;
os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
for (const auto& adjacency : lsa.getAdjacencies()) {
os << " adjacency=" << adjacency << std::endl;
}
router.adjacencyLsaString = os.str();
}
void
Nlsrc::recordCoordinateLsa(const nlsr::tlv::CoordinateLsa& lsa)
{
Router& router = getRouter(lsa.getLsaInfo());
std::ostringstream os;
os << " Coordinate LSA:" << std::endl;
os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
os << " angle=" << lsa.getHyperbolicAngle() << std::endl;
os << " radius=" << lsa.getHyperbolicRadius() << std::endl;
router.coordinateLsaString = os.str();
}
void
Nlsrc::recordNameLsa(const nlsr::tlv::NameLsa& lsa)
{
Router& router = getRouter(lsa.getLsaInfo());
std::ostringstream os;
os << " Name LSA:" << std::endl;
os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
for (const auto& name : lsa.getNames()) {
os << " name=" << name << std::endl;
}
router.nameLsaString = os.str();
}
void
Nlsrc::printLsdb()
{
std::cout << "NLSR Status" << std::endl;
std::cout << "LSDB:" << std::endl;
for (const auto& item : m_routers) {
std::cout << " OriginRouter: " << item.first << std::endl;
std::cout << std::endl;
const Router& router = item.second;
if (!router.adjacencyLsaString.empty()) {
std::cout << router.adjacencyLsaString << std::endl;
}
if (!router.coordinateLsaString.empty()) {
std::cout << router.coordinateLsaString << std::endl;
}
if (!router.nameLsaString.empty()) {
std::cout << router.nameLsaString << std::endl;
}
}
}
Nlsrc::Router&
Nlsrc::getRouter(const nlsr::tlv::LsaInfo& info)
{
const ndn::Name& originRouterName = info.getOriginRouter();
const auto& pair =
m_routers.insert(std::make_pair(originRouterName, std::move(Router())));
return pair.first->second;
}
} // namespace nlsrc
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
int
main(int argc, char** argv)
{
ndn::Face face;
nlsrc::Nlsrc nlsrc(face);
nlsrc.programName = argv[0];
if (argc < 2) {
nlsrc.printUsage();
return 0;
}
int opt;
while ((opt = ::getopt(argc, argv, "hV")) != -1) {
switch (opt) {
case 'h':
nlsrc.printUsage();
return 0;
case 'V':
std::cout << NLSR_VERSION_BUILD_STRING << std::endl;
return 0;
default:
nlsrc.printUsage();
return 1;
}
}
if (argc == ::optind) {
nlsrc.printUsage();
return 1;
}
try {
::optind = 2; // Set ::optind to the command's index
nlsrc.commandLineArguments = argv + ::optind;
nlsrc.nOptions = argc - ::optind;
// argv[1] points to the command, so pass it to the dispatch
bool isOk = nlsrc.dispatch(argv[1]);
if (!isOk) {
nlsrc.printUsage();
return 1;
}
face.processEvents();
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
return 0;
}
+162
View File
@@ -0,0 +1,162 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, The University of Memphis,
* Regents of the University of California,
* Arizona Board of Regents.
*
* This file is part of NLSR (Named-data Link State Routing).
* See AUTHORS.md for complete list of NLSR authors and contributors.
*
* NLSR is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
**/
#include "tlv/adjacency-lsa.hpp"
#include "tlv/coordinate-lsa.hpp"
#include "tlv/name-lsa.hpp"
#include <boost/noncopyable.hpp>
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/security/key-chain.hpp>
#include <deque>
#include <map>
#include <stdexcept>
#ifndef NLSR_TOOLS_NLSRC_HPP
#define NLSR_TOOLS_NLSRC_HPP
namespace nlsrc {
class Nlsrc : boost::noncopyable
{
public:
explicit
Nlsrc(ndn::Face& face);
void
printUsage();
void
getStatus();
bool
dispatch(const std::string& cmd);
private:
void
runNextStep();
/**
* \brief Adds a name prefix to be advertised in NLSR's Name LSA
*
* cmd format:
* name
*
*/
void
advertiseName();
/**
* \brief Removes a name prefix from NLSR's Name LSA
*
* cmd format:
* name
*
*/
void
withdrawName();
void
sendNamePrefixUpdate(const ndn::Name& name,
const ndn::Name::Component& verb,
const std::string& info);
void
onControlResponse(const std::string& info, const ndn::Data& data);
private:
void
fetchAdjacencyLsas();
void
fetchCoordinateLsas();
void
fetchNameLsas();
template <class T>
void
fetchFromLsdb(const ndn::Name::Component& datasetType,
const std::function<void(const T&)>& recordLsa);
template <class T>
void
onFetchSuccess(const ndn::ConstBufferPtr& data,
const std::function<void(const T&)>& recordLsa);
void
onTimeout(uint32_t errorCode, const std::string& error);
private:
std::string
getLsaInfoString(const nlsr::tlv::LsaInfo& info);
void
recordAdjacencyLsa(const nlsr::tlv::AdjacencyLsa& lsa);
void
recordCoordinateLsa(const nlsr::tlv::CoordinateLsa& lsa);
void
recordNameLsa(const nlsr::tlv::NameLsa& lsa);
void
printLsdb();
public:
const char* programName;
// command parameters without leading 'cmd' component
const char* const* commandLineArguments;
int nOptions;
private:
struct Router
{
std::string adjacencyLsaString;
std::string coordinateLsaString;
std::string nameLsaString;
};
Router&
getRouter(const nlsr::tlv::LsaInfo& info);
typedef std::map<const ndn::Name, Router> RouterMap;
RouterMap m_routers;
private:
ndn::KeyChain m_keyChain;
ndn::Face& m_face;
std::deque<std::function<void()>> m_fetchSteps;
static const ndn::Name LOCALHOST_PREFIX;
static const ndn::Name LSDB_PREFIX;
static const ndn::Name NAME_UPDATE_PREFIX;
static const uint32_t ERROR_CODE_TIMEOUT;
static const uint32_t RESPONSE_CODE_SUCCESS;
};
} // namespace nlsrc
#endif // NLSR_TOOLS_NLSRC_HPP
+15
View File
@@ -128,10 +128,25 @@ def build(bld):
use='nlsr-objects',
)
nlsrc = bld(
target='bin/nlsrc',
features='cxx cxxprogram',
source='tools/nlsrc.cpp',
use='nlsr-objects BOOST',
)
if bld.env['WITH_TESTS']:
bld.recurse('tests')
bld.recurse('tests-integrated')
if bld.env['SPHINX_BUILD']:
bld(features="sphinx",
builder="man",
outdir="docs/manpages",
config="docs/conf.py",
source=bld.path.ant_glob('docs/manpages/**/*.rst'),
install_path="${MANDIR}/",
VERSION=VERSION)
def docs(bld):
from waflib import Options