blob: 6c1f0647b9bf397d08ec2167141fb06d6c315faa [file] [log] [blame]
Vince Lehmanc439d662015-04-27 10:56:00 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande0421bc62020-05-08 20:42:19 -07002/*
Ashlesh Gawande30d96e42021-03-21 19:15:33 -07003 * Copyright (c) 2014-2021, 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/>.
Ashlesh Gawande0421bc62020-05-08 20:42:19 -070020 */
Vince Lehmanc439d662015-04-27 10:56:00 -050021
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
Vince Lehmanc439d662015-04-27 10:56:00 -050027#include <ndn-cxx/data.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050028#include <ndn-cxx/encoding/block.hpp>
Ashlesh Gawande30d96e42021-03-21 19:15:33 -070029#include <ndn-cxx/face.hpp>
30#include <ndn-cxx/interest.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>
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050033#include <ndn-cxx/security/command-interest-signer.hpp>
Ashlesh Gawande30d96e42021-03-21 19:15:33 -070034#include <ndn-cxx/security/key-chain.hpp>
35#include <ndn-cxx/security/signing-helpers.hpp>
36#include <ndn-cxx/util/segment-fetcher.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050037
38#include <iostream>
39
40namespace nlsrc {
41
42const ndn::Name Nlsrc::LOCALHOST_PREFIX = ndn::Name("/localhost/nlsr");
43const ndn::Name Nlsrc::LSDB_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("lsdb");
44const ndn::Name Nlsrc::NAME_UPDATE_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("prefix-update");
45
laqinfan35731852017-08-08 06:17:39 -050046const ndn::Name Nlsrc::RT_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("routing-table");
47
Vince Lehmanc439d662015-04-27 10:56:00 -050048const uint32_t Nlsrc::ERROR_CODE_TIMEOUT = 10060;
49const uint32_t Nlsrc::RESPONSE_CODE_SUCCESS = 200;
Saurab Dulal7526cee2018-01-31 18:14:10 +000050const uint32_t Nlsrc::RESPONSE_CODE_SAVE_OR_DELETE = 205;
Vince Lehmanc439d662015-04-27 10:56:00 -050051
52Nlsrc::Nlsrc(ndn::Face& face)
53 : m_face(face)
54{
55}
56
57void
58Nlsrc::printUsage()
59{
60 std::cout << "Usage:\n" << programName << " [-h] [-V] COMMAND [<Command Options>]\n"
61 " -h print usage and exit\n"
62 " -V print version and exit\n"
63 "\n"
64 " COMMAND can be one of the following:\n"
laqinfan35731852017-08-08 06:17:39 -050065 " lsdb\n"
66 " display NLSR lsdb status\n"
67 " routing\n"
68 " display routing table status\n"
Vince Lehmanc439d662015-04-27 10:56:00 -050069 " status\n"
laqinfan35731852017-08-08 06:17:39 -050070 " display all NLSR status (lsdb & routingtable)\n"
Vince Lehmanc439d662015-04-27 10:56:00 -050071 " advertise name\n"
72 " advertise a name prefix through NLSR\n"
Saurab Dulal7526cee2018-01-31 18:14:10 +000073 " advertise name save\n"
74 " advertise and save the name prefix to the conf file\n"
Vince Lehmanc439d662015-04-27 10:56:00 -050075 " withdraw name\n"
Saurab Dulal7526cee2018-01-31 18:14:10 +000076 " remove a name prefix advertised through NLSR\n"
77 " withdraw name delete\n"
78 " withdraw and delete the name prefix from the conf file"
Vince Lehmanc439d662015-04-27 10:56:00 -050079 << std::endl;
80}
81
82void
laqinfan35731852017-08-08 06:17:39 -050083Nlsrc::getStatus(const std::string& command)
Vince Lehmanc439d662015-04-27 10:56:00 -050084{
laqinfan35731852017-08-08 06:17:39 -050085 if (command == "lsdb") {
86 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
87 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
88 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
89 m_fetchSteps.push_back(std::bind(&Nlsrc::printLsdb, this));
90 }
91 else if (command == "routing") {
92 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchRtables, this));
93 m_fetchSteps.push_back(std::bind(&Nlsrc::printRT, this));
94 }
95 else if(command == "status") {
96 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
97 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
98 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
99 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchRtables, this));
100 m_fetchSteps.push_back(std::bind(&Nlsrc::printAll, this));
101 }
Vince Lehmanc439d662015-04-27 10:56:00 -0500102 runNextStep();
103}
104
105bool
106Nlsrc::dispatch(const std::string& command)
107{
108 if (command == "advertise") {
Saurab Dulal7526cee2018-01-31 18:14:10 +0000109 if (nOptions < 0) {
Vince Lehmanc439d662015-04-27 10:56:00 -0500110 return false;
111 }
Saurab Dulal7526cee2018-01-31 18:14:10 +0000112 else if (nOptions == 1) {
113 std::string saveFlag = commandLineArguments[0];
114 if (saveFlag != "save") {
115 return false;
116 }
117 }
Vince Lehmanc439d662015-04-27 10:56:00 -0500118
119 advertiseName();
120 return true;
121 }
122 else if (command == "withdraw") {
Saurab Dulal7526cee2018-01-31 18:14:10 +0000123 if (nOptions < 0) {
Vince Lehmanc439d662015-04-27 10:56:00 -0500124 return false;
125 }
Saurab Dulal7526cee2018-01-31 18:14:10 +0000126 else if (nOptions == 1) {
127 std::string saveFlag = commandLineArguments[0];
128 if (saveFlag != "delete") {
129 return false;
130 }
131 }
Vince Lehmanc439d662015-04-27 10:56:00 -0500132
133 withdrawName();
134 return true;
135 }
Saurab Dulal7526cee2018-01-31 18:14:10 +0000136 else if ((command == "lsdb") || (command == "routing") || (command == "status")) {
137 if (nOptions != -1) {
Vince Lehmanc439d662015-04-27 10:56:00 -0500138 return false;
139 }
laqinfan35731852017-08-08 06:17:39 -0500140 commandString = command;
Vince Lehmanc439d662015-04-27 10:56:00 -0500141
laqinfan35731852017-08-08 06:17:39 -0500142 getStatus(command);
Vince Lehmanc439d662015-04-27 10:56:00 -0500143 return true;
144 }
145
146 return false;
147}
148
149void
150Nlsrc::runNextStep()
151{
152 if (m_fetchSteps.empty()) {
153 return;
154 }
155
156 std::function<void()> nextStep = m_fetchSteps.front();
157 m_fetchSteps.pop_front();
158
159 nextStep();
160}
161
162void
163Nlsrc::advertiseName()
164{
Saurab Dulal7526cee2018-01-31 18:14:10 +0000165 ndn::Name name = commandLineArguments[-1];
Vince Lehmanc439d662015-04-27 10:56:00 -0500166
Saurab Dulal7526cee2018-01-31 18:14:10 +0000167 bool saveFlag = false;
168 std::string info = "(Advertise: " + name.toUri() + ")";
169 if (commandLineArguments[0]) {
170 saveFlag = true;
171 info = "(Save: " + name.toUri() + ")";
172 }
173 ndn::Name::Component verb("advertise");
174 sendNamePrefixUpdate(name, verb, info, saveFlag);
Vince Lehmanc439d662015-04-27 10:56:00 -0500175}
176
177void
178Nlsrc::withdrawName()
179{
Saurab Dulal7526cee2018-01-31 18:14:10 +0000180 ndn::Name name = commandLineArguments[-1];
Vince Lehmanc439d662015-04-27 10:56:00 -0500181
Saurab Dulal7526cee2018-01-31 18:14:10 +0000182 bool deleteFlag = false;
183 std::string info = "(Withdraw: " + name.toUri() + ")";
184 if (commandLineArguments[0]) {
185 deleteFlag = true;
186 info = "(Delete: " + name.toUri() + ")";
187 }
188 ndn::Name::Component verb("withdraw");
189 sendNamePrefixUpdate(name, verb, info, deleteFlag);
Vince Lehmanc439d662015-04-27 10:56:00 -0500190}
191
192void
193Nlsrc::sendNamePrefixUpdate(const ndn::Name& name,
194 const ndn::Name::Component& verb,
Saurab Dulal7526cee2018-01-31 18:14:10 +0000195 const std::string& info,
196 bool flag)
Vince Lehmanc439d662015-04-27 10:56:00 -0500197{
198 ndn::nfd::ControlParameters parameters;
199 parameters.setName(name);
Saurab Dulal7526cee2018-01-31 18:14:10 +0000200 if (flag) {
201 parameters.setFlags(1);
202 }
Vince Lehmanc439d662015-04-27 10:56:00 -0500203
204 ndn::Name commandName = NAME_UPDATE_PREFIX;
205 commandName.append(verb);
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500206 commandName.append(parameters.wireEncode());
Vince Lehmanc439d662015-04-27 10:56:00 -0500207
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500208 ndn::security::CommandInterestSigner cis(m_keyChain);
Vince Lehmanc439d662015-04-27 10:56:00 -0500209
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500210 ndn::Interest commandInterest =
211 cis.makeCommandInterest(commandName,
212 ndn::security::signingByIdentity(m_keyChain.getPib().
213 getDefaultIdentity()));
214
215 commandInterest.setMustBeFresh(true);
216
217 m_face.expressInterest(commandInterest,
Vince Lehmanc439d662015-04-27 10:56:00 -0500218 std::bind(&Nlsrc::onControlResponse, this, info, _2),
Alexander Afanasyev1de901f2017-03-09 12:43:57 -0800219 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Nack"),
Vince Lehmanc439d662015-04-27 10:56:00 -0500220 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Timeout"));
221}
222
223void
224Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
225{
Vince Lehmand33e5bc2015-06-22 15:27:50 -0500226 if (data.getMetaInfo().getType() == ndn::tlv::ContentType_Nack) {
227 std::cerr << "ERROR: Run-time advertise/withdraw disabled" << std::endl;
228 return;
229 }
230
Vince Lehmanc439d662015-04-27 10:56:00 -0500231 ndn::nfd::ControlResponse response;
232
233 try {
234 response.wireDecode(data.getContent().blockFromValue());
235 }
236 catch (const std::exception& e) {
237 std::cerr << "ERROR: Control response decoding error" << std::endl;
238 return;
239 }
240
241 uint32_t code = response.getCode();
242
Saurab Dulal7526cee2018-01-31 18:14:10 +0000243 if (code != RESPONSE_CODE_SUCCESS && code != RESPONSE_CODE_SAVE_OR_DELETE) {
244
245 std::cerr << response.getText() << std::endl;
Vince Lehmanc439d662015-04-27 10:56:00 -0500246 std::cerr << "Name prefix update error (code: " << code << ")" << std::endl;
247 return;
248 }
249
250 std::cout << "Applied Name prefix update successfully: " << info << std::endl;
251}
252
253void
254Nlsrc::fetchAdjacencyLsas()
255{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800256 fetchFromLsdb<nlsr::AdjLsa>(nlsr::dataset::ADJACENCY_COMPONENT,
257 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500258}
259
260void
261Nlsrc::fetchCoordinateLsas()
262{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800263 fetchFromLsdb<nlsr::CoordinateLsa>(nlsr::dataset::COORDINATE_COMPONENT,
264 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500265}
266
267void
268Nlsrc::fetchNameLsas()
269{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800270 fetchFromLsdb<nlsr::NameLsa>(nlsr::dataset::NAME_COMPONENT,
271 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500272}
273
laqinfan35731852017-08-08 06:17:39 -0500274void
275Nlsrc::fetchRtables()
276{
Ashlesh Gawande0af46272020-12-12 16:45:13 -0500277 fetchFromRt<nlsr::RoutingTableStatus>([this] (const auto& rts) { this->recordRtable(rts); });
laqinfan35731852017-08-08 06:17:39 -0500278}
279
Vince Lehmanc439d662015-04-27 10:56:00 -0500280template <class T>
281void
282Nlsrc::fetchFromLsdb(const ndn::Name::Component& datasetType,
283 const std::function<void(const T&)>& recordLsa)
284{
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700285 ndn::Interest interest(ndn::Name(LSDB_PREFIX).append(datasetType));
Vince Lehmanc439d662015-04-27 10:56:00 -0500286
Ashlesh Gawande05cb7282018-08-30 14:39:41 -0500287 auto fetcher = ndn::util::SegmentFetcher::start(m_face, interest, m_validator);
288 fetcher->onComplete.connect(std::bind(&Nlsrc::onFetchSuccess<T>, this, _1, recordLsa));
289 fetcher->onError.connect(std::bind(&Nlsrc::onTimeout, this, _1, _2));
Vince Lehmanc439d662015-04-27 10:56:00 -0500290}
291
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700292void
293Nlsrc::recordLsa(const nlsr::Lsa& lsa)
294{
295 Router& router = m_routers.emplace(lsa.getOriginRouter(), Router()).first->second;
296
297 if (lsa.getType() == nlsr::Lsa::Type::ADJACENCY) {
298 router.adjacencyLsaString = lsa.toString();
299 }
300 else if (lsa.getType() == nlsr::Lsa::Type::COORDINATE) {
301 router.coordinateLsaString = lsa.toString();
302 }
303 else if (lsa.getType() == nlsr::Lsa::Type::NAME) {
304 router.nameLsaString = lsa.toString();
305 }
306}
307
Vince Lehmanc439d662015-04-27 10:56:00 -0500308template <class T>
309void
laqinfan35731852017-08-08 06:17:39 -0500310Nlsrc::fetchFromRt(const std::function<void(const T&)>& recordDataset)
311{
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700312 ndn::Interest interest(RT_PREFIX);
laqinfan35731852017-08-08 06:17:39 -0500313
Ashlesh Gawande05cb7282018-08-30 14:39:41 -0500314 auto fetcher = ndn::util::SegmentFetcher::start(m_face, interest, m_validator);
315 fetcher->onComplete.connect(std::bind(&Nlsrc::onFetchSuccess<T>, this, _1, recordDataset));
316 fetcher->onError.connect(std::bind(&Nlsrc::onTimeout, this, _1, _2));
laqinfan35731852017-08-08 06:17:39 -0500317}
318
319template <class T>
320void
Vince Lehmanc439d662015-04-27 10:56:00 -0500321Nlsrc::onFetchSuccess(const ndn::ConstBufferPtr& data,
laqinfan35731852017-08-08 06:17:39 -0500322 const std::function<void(const T&)>& recordDataset)
Vince Lehmanc439d662015-04-27 10:56:00 -0500323{
324 ndn::Block block;
325 size_t offset = 0;
326
327 while (offset < data->size()) {
328 bool isOk = false;
329 std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
330
331 if (!isOk) {
332 std::cerr << "ERROR: cannot decode LSA TLV" << std::endl;
333 break;
334 }
335
336 offset += block.size();
337
laqinfan35731852017-08-08 06:17:39 -0500338 T data(block);
339 recordDataset(data);
Vince Lehmanc439d662015-04-27 10:56:00 -0500340 }
341
342 runNextStep();
343}
344
345void
346Nlsrc::onTimeout(uint32_t errorCode, const std::string& error)
347{
348 std::cerr << "Request timed out (code: " << errorCode
349 << ", error: " << error << ")" << std::endl;
350}
351
Vince Lehmanc439d662015-04-27 10:56:00 -0500352void
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700353Nlsrc::recordRtable(const nlsr::RoutingTableStatus& rts)
laqinfan35731852017-08-08 06:17:39 -0500354{
laqinfan35731852017-08-08 06:17:39 -0500355 std::ostringstream os;
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700356 os << rts;
laqinfana073e2e2018-01-15 21:17:24 +0000357 m_rtString = os.str();
laqinfan35731852017-08-08 06:17:39 -0500358}
359
360void
Vince Lehmanc439d662015-04-27 10:56:00 -0500361Nlsrc::printLsdb()
362{
Vince Lehmanc439d662015-04-27 10:56:00 -0500363 std::cout << "LSDB:" << std::endl;
364
365 for (const auto& item : m_routers) {
366 std::cout << " OriginRouter: " << item.first << std::endl;
367 std::cout << std::endl;
368
369 const Router& router = item.second;
370
371 if (!router.adjacencyLsaString.empty()) {
372 std::cout << router.adjacencyLsaString << std::endl;
373 }
374
375 if (!router.coordinateLsaString.empty()) {
376 std::cout << router.coordinateLsaString << std::endl;
377 }
378
379 if (!router.nameLsaString.empty()) {
380 std::cout << router.nameLsaString << std::endl;
381 }
382 }
383}
384
laqinfan35731852017-08-08 06:17:39 -0500385void
386Nlsrc::printRT()
387{
laqinfana073e2e2018-01-15 21:17:24 +0000388 if (!m_rtString.empty()) {
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700389 std::cout << m_rtString;
laqinfana073e2e2018-01-15 21:17:24 +0000390 }
391 else {
392 std::cout << "Routing Table is not calculated yet" << std::endl;
laqinfan35731852017-08-08 06:17:39 -0500393 }
394}
395
396void
397Nlsrc::printAll()
398{
399 std::cout << "NLSR Status" << std::endl;
400 printLsdb();
401 printRT();
402}
403
Vince Lehmanc439d662015-04-27 10:56:00 -0500404} // namespace nlsrc
405
406////////////////////////////////////////////////////////////////////////////////
407////////////////////////////////////////////////////////////////////////////////
408
409int
410main(int argc, char** argv)
411{
412 ndn::Face face;
413 nlsrc::Nlsrc nlsrc(face);
414
415 nlsrc.programName = argv[0];
416
417 if (argc < 2) {
418 nlsrc.printUsage();
419 return 0;
420 }
421
422 int opt;
423 while ((opt = ::getopt(argc, argv, "hV")) != -1) {
424 switch (opt) {
425 case 'h':
426 nlsrc.printUsage();
427 return 0;
428 case 'V':
429 std::cout << NLSR_VERSION_BUILD_STRING << std::endl;
430 return 0;
431 default:
432 nlsrc.printUsage();
433 return 1;
434 }
435 }
436
437 if (argc == ::optind) {
438 nlsrc.printUsage();
439 return 1;
440 }
441
442 try {
Saurab Dulal7526cee2018-01-31 18:14:10 +0000443 ::optind = 3; // Set ::optind to the command's index
Vince Lehmanc439d662015-04-27 10:56:00 -0500444
445 nlsrc.commandLineArguments = argv + ::optind;
446 nlsrc.nOptions = argc - ::optind;
447
448 // argv[1] points to the command, so pass it to the dispatch
449 bool isOk = nlsrc.dispatch(argv[1]);
450 if (!isOk) {
451 nlsrc.printUsage();
452 return 1;
453 }
454
455 face.processEvents();
456 }
457 catch (const std::exception& e) {
458 std::cerr << "ERROR: " << e.what() << std::endl;
459 return 2;
460 }
461 return 0;
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800462}