blob: db2de6a2dd158b0f6f2cfb7c3ca8999498dfbfd6 [file] [log] [blame]
Vince Lehmanc439d662015-04-27 10:56:00 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
laqinfan35731852017-08-08 06:17:39 -05003 * Copyright (c) 2014-2018, The University of Memphis,
Vince Lehmanc439d662015-04-27 10:56:00 -05004 * Regents of the University of California,
5 * Arizona Board of Regents.
6 *
7 * This file is part of NLSR (Named-data Link State Routing).
8 * See AUTHORS.md for complete list of NLSR authors and contributors.
9 *
10 * NLSR is free software: you can redistribute it and/or modify it under the terms
11 * of the GNU General Public License as published by the Free Software Foundation,
12 * either version 3 of the License, or (at your option) any later version.
13 *
14 * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
20 **/
21
22#include "nlsrc.hpp"
23
24#include "version.hpp"
laqinfan35731852017-08-08 06:17:39 -050025#include "src/publisher/dataset-interest-handler.hpp"
Vince Lehmanc439d662015-04-27 10:56:00 -050026
27#include <ndn-cxx/face.hpp>
28#include <ndn-cxx/data.hpp>
29#include <ndn-cxx/interest.hpp>
30#include <ndn-cxx/encoding/block.hpp>
Junxiao Shi3e5120c2016-09-10 16:58:34 +000031#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
32#include <ndn-cxx/mgmt/nfd/control-response.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050033#include <ndn-cxx/util/segment-fetcher.hpp>
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050034#include <ndn-cxx/security/key-chain.hpp>
35#include <ndn-cxx/security/command-interest-signer.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050036
37#include <iostream>
38
39namespace nlsrc {
40
41const ndn::Name Nlsrc::LOCALHOST_PREFIX = ndn::Name("/localhost/nlsr");
42const ndn::Name Nlsrc::LSDB_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("lsdb");
43const ndn::Name Nlsrc::NAME_UPDATE_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("prefix-update");
44
laqinfan35731852017-08-08 06:17:39 -050045const ndn::Name Nlsrc::RT_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("routing-table");
46
Vince Lehmanc439d662015-04-27 10:56:00 -050047const uint32_t Nlsrc::ERROR_CODE_TIMEOUT = 10060;
48const uint32_t Nlsrc::RESPONSE_CODE_SUCCESS = 200;
49
50Nlsrc::Nlsrc(ndn::Face& face)
51 : m_face(face)
52{
53}
54
55void
56Nlsrc::printUsage()
57{
58 std::cout << "Usage:\n" << programName << " [-h] [-V] COMMAND [<Command Options>]\n"
59 " -h print usage and exit\n"
60 " -V print version and exit\n"
61 "\n"
62 " COMMAND can be one of the following:\n"
laqinfan35731852017-08-08 06:17:39 -050063 " lsdb\n"
64 " display NLSR lsdb status\n"
65 " routing\n"
66 " display routing table status\n"
Vince Lehmanc439d662015-04-27 10:56:00 -050067 " status\n"
laqinfan35731852017-08-08 06:17:39 -050068 " display all NLSR status (lsdb & routingtable)\n"
Vince Lehmanc439d662015-04-27 10:56:00 -050069 " advertise name\n"
70 " advertise a name prefix through NLSR\n"
71 " withdraw name\n"
72 " remove a name prefix advertised through NLSR"
73 << std::endl;
74}
75
76void
laqinfan35731852017-08-08 06:17:39 -050077Nlsrc::getStatus(const std::string& command)
Vince Lehmanc439d662015-04-27 10:56:00 -050078{
laqinfan35731852017-08-08 06:17:39 -050079 if (command == "lsdb") {
80 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
81 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
82 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
83 m_fetchSteps.push_back(std::bind(&Nlsrc::printLsdb, this));
84 }
85 else if (command == "routing") {
86 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchRtables, this));
87 m_fetchSteps.push_back(std::bind(&Nlsrc::printRT, this));
88 }
89 else if(command == "status") {
90 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
91 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
92 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
93 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchRtables, this));
94 m_fetchSteps.push_back(std::bind(&Nlsrc::printAll, this));
95 }
Vince Lehmanc439d662015-04-27 10:56:00 -050096 runNextStep();
97}
98
99bool
100Nlsrc::dispatch(const std::string& command)
101{
102 if (command == "advertise") {
103 if (nOptions != 1) {
104 return false;
105 }
106
107 advertiseName();
108 return true;
109 }
110 else if (command == "withdraw") {
111 if (nOptions != 1) {
112 return false;
113 }
114
115 withdrawName();
116 return true;
117 }
laqinfan35731852017-08-08 06:17:39 -0500118 else if ((command == "lsdb")|| (command == "routing")||(command == "status")) {
Vince Lehmanc439d662015-04-27 10:56:00 -0500119 if (nOptions != 0) {
120 return false;
121 }
laqinfan35731852017-08-08 06:17:39 -0500122 commandString = command;
Vince Lehmanc439d662015-04-27 10:56:00 -0500123
laqinfan35731852017-08-08 06:17:39 -0500124 getStatus(command);
Vince Lehmanc439d662015-04-27 10:56:00 -0500125 return true;
126 }
127
128 return false;
129}
130
131void
132Nlsrc::runNextStep()
133{
134 if (m_fetchSteps.empty()) {
135 return;
136 }
137
138 std::function<void()> nextStep = m_fetchSteps.front();
139 m_fetchSteps.pop_front();
140
141 nextStep();
142}
143
144void
145Nlsrc::advertiseName()
146{
147 ndn::Name name = commandLineArguments[0];
148 ndn::Name::Component verb("advertise");
149 std::string info = "(Advertise: " + name.toUri() + ")";
150
151 sendNamePrefixUpdate(name, verb, info);
152}
153
154void
155Nlsrc::withdrawName()
156{
157 ndn::Name name = commandLineArguments[0];
158 ndn::Name::Component verb("withdraw");
159 std::string info = "(Withdraw: " + name.toUri() + ")";
160
161 sendNamePrefixUpdate(name, verb, info);
162}
163
164void
165Nlsrc::sendNamePrefixUpdate(const ndn::Name& name,
166 const ndn::Name::Component& verb,
167 const std::string& info)
168{
169 ndn::nfd::ControlParameters parameters;
170 parameters.setName(name);
171
172 ndn::Name commandName = NAME_UPDATE_PREFIX;
173 commandName.append(verb);
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500174 commandName.append(parameters.wireEncode());
Vince Lehmanc439d662015-04-27 10:56:00 -0500175
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500176 ndn::security::CommandInterestSigner cis(m_keyChain);
Vince Lehmanc439d662015-04-27 10:56:00 -0500177
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500178 ndn::Interest commandInterest =
179 cis.makeCommandInterest(commandName,
180 ndn::security::signingByIdentity(m_keyChain.getPib().
181 getDefaultIdentity()));
182
183 commandInterest.setMustBeFresh(true);
184
185 m_face.expressInterest(commandInterest,
Vince Lehmanc439d662015-04-27 10:56:00 -0500186 std::bind(&Nlsrc::onControlResponse, this, info, _2),
Alexander Afanasyev1de901f2017-03-09 12:43:57 -0800187 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Nack"),
Vince Lehmanc439d662015-04-27 10:56:00 -0500188 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Timeout"));
189}
190
191void
192Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
193{
Vince Lehmand33e5bc2015-06-22 15:27:50 -0500194 if (data.getMetaInfo().getType() == ndn::tlv::ContentType_Nack) {
195 std::cerr << "ERROR: Run-time advertise/withdraw disabled" << std::endl;
196 return;
197 }
198
Vince Lehmanc439d662015-04-27 10:56:00 -0500199 ndn::nfd::ControlResponse response;
200
201 try {
202 response.wireDecode(data.getContent().blockFromValue());
203 }
204 catch (const std::exception& e) {
205 std::cerr << "ERROR: Control response decoding error" << std::endl;
206 return;
207 }
208
209 uint32_t code = response.getCode();
210
211 if (code != RESPONSE_CODE_SUCCESS) {
212 std::cerr << "Name prefix update error (code: " << code << ")" << std::endl;
213 return;
214 }
215
216 std::cout << "Applied Name prefix update successfully: " << info << std::endl;
217}
218
219void
220Nlsrc::fetchAdjacencyLsas()
221{
Nick Gordon114537f2017-08-09 14:51:37 -0500222 fetchFromLsdb<nlsr::tlv::AdjacencyLsa>(nlsr::dataset::ADJACENCY_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500223 std::bind(&Nlsrc::recordAdjacencyLsa, this, _1));
224}
225
226void
227Nlsrc::fetchCoordinateLsas()
228{
Nick Gordon114537f2017-08-09 14:51:37 -0500229 fetchFromLsdb<nlsr::tlv::CoordinateLsa>(nlsr::dataset::COORDINATE_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500230 std::bind(&Nlsrc::recordCoordinateLsa, this, _1));
231}
232
233void
234Nlsrc::fetchNameLsas()
235{
Nick Gordon114537f2017-08-09 14:51:37 -0500236 fetchFromLsdb<nlsr::tlv::NameLsa>(nlsr::dataset::NAME_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500237 std::bind(&Nlsrc::recordNameLsa, this, _1));
238}
239
laqinfan35731852017-08-08 06:17:39 -0500240void
241Nlsrc::fetchRtables()
242{
243 fetchFromRt<nlsr::tlv::RoutingTable>(
244 [this] (const nlsr::tlv::RoutingTable& rts) {
245 recordRtable(rts);
246 });
247}
248
Vince Lehmanc439d662015-04-27 10:56:00 -0500249template <class T>
250void
251Nlsrc::fetchFromLsdb(const ndn::Name::Component& datasetType,
252 const std::function<void(const T&)>& recordLsa)
253{
254 ndn::Name command = LSDB_PREFIX;
255 command.append(datasetType);
256
257 ndn::Interest interest(command);
258
259 ndn::util::SegmentFetcher::fetch(m_face,
260 interest,
Muktadir R Chowdhury4c7caad2015-09-03 15:49:22 -0500261 m_validator,
Vince Lehmanc439d662015-04-27 10:56:00 -0500262 std::bind(&Nlsrc::onFetchSuccess<T>,
263 this, _1, recordLsa),
264 std::bind(&Nlsrc::onTimeout, this, _1, _2));
265}
266
267template <class T>
268void
laqinfan35731852017-08-08 06:17:39 -0500269Nlsrc::fetchFromRt(const std::function<void(const T&)>& recordDataset)
270{
271 ndn::Name command = RT_PREFIX;
272
273 ndn::Interest interest(command);
274
275 ndn::util::SegmentFetcher::fetch(m_face,
276 interest,
277 m_validator,
278 std::bind(&Nlsrc::onFetchSuccess<T>,
279 this, _1, recordDataset),
280 std::bind(&Nlsrc::onTimeout, this, _1, _2));
281}
282
283template <class T>
284void
Vince Lehmanc439d662015-04-27 10:56:00 -0500285Nlsrc::onFetchSuccess(const ndn::ConstBufferPtr& data,
laqinfan35731852017-08-08 06:17:39 -0500286 const std::function<void(const T&)>& recordDataset)
Vince Lehmanc439d662015-04-27 10:56:00 -0500287{
288 ndn::Block block;
289 size_t offset = 0;
290
291 while (offset < data->size()) {
292 bool isOk = false;
293 std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
294
295 if (!isOk) {
296 std::cerr << "ERROR: cannot decode LSA TLV" << std::endl;
297 break;
298 }
299
300 offset += block.size();
301
laqinfan35731852017-08-08 06:17:39 -0500302 T data(block);
303 recordDataset(data);
Vince Lehmanc439d662015-04-27 10:56:00 -0500304 }
305
306 runNextStep();
307}
308
309void
310Nlsrc::onTimeout(uint32_t errorCode, const std::string& error)
311{
312 std::cerr << "Request timed out (code: " << errorCode
313 << ", error: " << error << ")" << std::endl;
314}
315
316std::string
317Nlsrc::getLsaInfoString(const nlsr::tlv::LsaInfo& info)
318{
319 std::ostringstream os;
320 os << " info=" << info;
321
322 return os.str();
323}
324
laqinfan35731852017-08-08 06:17:39 -0500325std::string
326Nlsrc::getDesString(const nlsr::tlv::Destination& des)
327{
328 std::ostringstream os;
329 os << " " << des;
330
331 return os.str();
332}
333
Vince Lehmanc439d662015-04-27 10:56:00 -0500334void
335Nlsrc::recordAdjacencyLsa(const nlsr::tlv::AdjacencyLsa& lsa)
336{
laqinfan35731852017-08-08 06:17:39 -0500337 Router& router = getRouterLsdb(lsa.getLsaInfo());
Vince Lehmanc439d662015-04-27 10:56:00 -0500338
339 std::ostringstream os;
340 os << " AdjacencyLsa:" << std::endl;
341
342 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
343
344 for (const auto& adjacency : lsa.getAdjacencies()) {
345 os << " adjacency=" << adjacency << std::endl;
346 }
347
348 router.adjacencyLsaString = os.str();
349}
350
351void
352Nlsrc::recordCoordinateLsa(const nlsr::tlv::CoordinateLsa& lsa)
353{
laqinfan35731852017-08-08 06:17:39 -0500354 Router& router = getRouterLsdb(lsa.getLsaInfo());
Vince Lehmanc439d662015-04-27 10:56:00 -0500355
356 std::ostringstream os;
357 os << " Coordinate LSA:" << std::endl;
358
359 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
360
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600361 int i = 0;
362 for (auto const& value: lsa.getHyperbolicAngle()) {
363 os << " Hyp Angle " << i++ << ": "<< value << " ";
364 }
365 os << "\n radius=" << lsa.getHyperbolicRadius() << std::endl;
Vince Lehmanc439d662015-04-27 10:56:00 -0500366
367 router.coordinateLsaString = os.str();
368}
369
370void
371Nlsrc::recordNameLsa(const nlsr::tlv::NameLsa& lsa)
372{
laqinfan35731852017-08-08 06:17:39 -0500373 Router& router = getRouterLsdb(lsa.getLsaInfo());
Vince Lehmanc439d662015-04-27 10:56:00 -0500374
375 std::ostringstream os;
376 os << " Name LSA:" << std::endl;
377
378 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
379
380 for (const auto& name : lsa.getNames()) {
381 os << " name=" << name << std::endl;
382 }
383
384 router.nameLsaString = os.str();
385}
386
387void
laqinfan35731852017-08-08 06:17:39 -0500388Nlsrc::recordRtable(const nlsr::tlv::RoutingTable& rt)
389{
390 Router& router = getRouterRT(rt.getDestination());
391
392 std::ostringstream os;
393
394 os << getDesString(rt.getDestination()) << std::endl;
395
396 os << " NextHopList: " <<std::endl;
397 for (const auto& nhs : rt.getNextHops()) {
398 os << " " << nhs;
399 }
400
401 router.rtString = os.str();
402}
403
404void
Vince Lehmanc439d662015-04-27 10:56:00 -0500405Nlsrc::printLsdb()
406{
Vince Lehmanc439d662015-04-27 10:56:00 -0500407 std::cout << "LSDB:" << std::endl;
408
409 for (const auto& item : m_routers) {
410 std::cout << " OriginRouter: " << item.first << std::endl;
411 std::cout << std::endl;
412
413 const Router& router = item.second;
414
415 if (!router.adjacencyLsaString.empty()) {
416 std::cout << router.adjacencyLsaString << std::endl;
417 }
418
419 if (!router.coordinateLsaString.empty()) {
420 std::cout << router.coordinateLsaString << std::endl;
421 }
422
423 if (!router.nameLsaString.empty()) {
424 std::cout << router.nameLsaString << std::endl;
425 }
426 }
427}
428
laqinfan35731852017-08-08 06:17:39 -0500429void
430Nlsrc::printRT()
431{
432 std::cout << "Routing Table Status:" << std::endl;
433
434 for (const auto& item : m_routers) {
435
436 const Router& router = item.second;
437
438 if (!router.rtString.empty()) {
439 std::cout << router.rtString << std::endl;
440 }
441 }
442}
443
444void
445Nlsrc::printAll()
446{
447 std::cout << "NLSR Status" << std::endl;
448 printLsdb();
449 printRT();
450}
451
Vince Lehmanc439d662015-04-27 10:56:00 -0500452Nlsrc::Router&
laqinfan35731852017-08-08 06:17:39 -0500453Nlsrc::getRouterLsdb(const nlsr::tlv::LsaInfo& info)
Vince Lehmanc439d662015-04-27 10:56:00 -0500454{
455 const ndn::Name& originRouterName = info.getOriginRouter();
456
457 const auto& pair =
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800458 m_routers.insert(std::make_pair(originRouterName, Router()));
Vince Lehmanc439d662015-04-27 10:56:00 -0500459
460 return pair.first->second;
461}
462
laqinfan35731852017-08-08 06:17:39 -0500463Nlsrc::Router&
464Nlsrc::getRouterRT(const nlsr::tlv::Destination& des)
465{
466 const ndn::Name& desName = des.getName();
467
468 const auto& pair =
469 m_routers.insert(std::make_pair(desName, Router()));
470
471 return pair.first->second;
472}
473
Vince Lehmanc439d662015-04-27 10:56:00 -0500474} // namespace nlsrc
475
476////////////////////////////////////////////////////////////////////////////////
477////////////////////////////////////////////////////////////////////////////////
478
479int
480main(int argc, char** argv)
481{
482 ndn::Face face;
483 nlsrc::Nlsrc nlsrc(face);
484
485 nlsrc.programName = argv[0];
486
487 if (argc < 2) {
488 nlsrc.printUsage();
489 return 0;
490 }
491
492 int opt;
493 while ((opt = ::getopt(argc, argv, "hV")) != -1) {
494 switch (opt) {
495 case 'h':
496 nlsrc.printUsage();
497 return 0;
498 case 'V':
499 std::cout << NLSR_VERSION_BUILD_STRING << std::endl;
500 return 0;
501 default:
502 nlsrc.printUsage();
503 return 1;
504 }
505 }
506
507 if (argc == ::optind) {
508 nlsrc.printUsage();
509 return 1;
510 }
511
512 try {
513 ::optind = 2; // Set ::optind to the command's index
514
515 nlsrc.commandLineArguments = argv + ::optind;
516 nlsrc.nOptions = argc - ::optind;
517
518 // argv[1] points to the command, so pass it to the dispatch
519 bool isOk = nlsrc.dispatch(argv[1]);
520 if (!isOk) {
521 nlsrc.printUsage();
522 return 1;
523 }
524
525 face.processEvents();
526 }
527 catch (const std::exception& e) {
528 std::cerr << "ERROR: " << e.what() << std::endl;
529 return 2;
530 }
531 return 0;
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800532}