blob: 12900f5d73506223657961c47898e2f9abe1668a [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>
Davide Pesavento6184c202021-05-17 02:28:03 -040033#include <ndn-cxx/security/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
Davide Pesavento6184c202021-05-17 02:28:03 -0400208 ndn::security::InterestSigner signer(m_keyChain);
209 auto commandInterest = signer.makeCommandInterest(commandName,
210 ndn::security::signingByIdentity(m_keyChain.getPib().getDefaultIdentity()));
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500211 commandInterest.setMustBeFresh(true);
212
213 m_face.expressInterest(commandInterest,
Vince Lehmanc439d662015-04-27 10:56:00 -0500214 std::bind(&Nlsrc::onControlResponse, this, info, _2),
Alexander Afanasyev1de901f2017-03-09 12:43:57 -0800215 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Nack"),
Vince Lehmanc439d662015-04-27 10:56:00 -0500216 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Timeout"));
217}
218
219void
220Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
221{
Vince Lehmand33e5bc2015-06-22 15:27:50 -0500222 if (data.getMetaInfo().getType() == ndn::tlv::ContentType_Nack) {
223 std::cerr << "ERROR: Run-time advertise/withdraw disabled" << std::endl;
224 return;
225 }
226
Vince Lehmanc439d662015-04-27 10:56:00 -0500227 ndn::nfd::ControlResponse response;
228
229 try {
230 response.wireDecode(data.getContent().blockFromValue());
231 }
232 catch (const std::exception& e) {
233 std::cerr << "ERROR: Control response decoding error" << std::endl;
234 return;
235 }
236
237 uint32_t code = response.getCode();
238
Saurab Dulal7526cee2018-01-31 18:14:10 +0000239 if (code != RESPONSE_CODE_SUCCESS && code != RESPONSE_CODE_SAVE_OR_DELETE) {
240
241 std::cerr << response.getText() << std::endl;
Vince Lehmanc439d662015-04-27 10:56:00 -0500242 std::cerr << "Name prefix update error (code: " << code << ")" << std::endl;
243 return;
244 }
245
246 std::cout << "Applied Name prefix update successfully: " << info << std::endl;
247}
248
249void
250Nlsrc::fetchAdjacencyLsas()
251{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800252 fetchFromLsdb<nlsr::AdjLsa>(nlsr::dataset::ADJACENCY_COMPONENT,
253 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500254}
255
256void
257Nlsrc::fetchCoordinateLsas()
258{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800259 fetchFromLsdb<nlsr::CoordinateLsa>(nlsr::dataset::COORDINATE_COMPONENT,
260 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500261}
262
263void
264Nlsrc::fetchNameLsas()
265{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800266 fetchFromLsdb<nlsr::NameLsa>(nlsr::dataset::NAME_COMPONENT,
267 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500268}
269
laqinfan35731852017-08-08 06:17:39 -0500270void
271Nlsrc::fetchRtables()
272{
Ashlesh Gawande0af46272020-12-12 16:45:13 -0500273 fetchFromRt<nlsr::RoutingTableStatus>([this] (const auto& rts) { this->recordRtable(rts); });
laqinfan35731852017-08-08 06:17:39 -0500274}
275
Vince Lehmanc439d662015-04-27 10:56:00 -0500276template <class T>
277void
278Nlsrc::fetchFromLsdb(const ndn::Name::Component& datasetType,
279 const std::function<void(const T&)>& recordLsa)
280{
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700281 ndn::Interest interest(ndn::Name(LSDB_PREFIX).append(datasetType));
Vince Lehmanc439d662015-04-27 10:56:00 -0500282
Ashlesh Gawande05cb7282018-08-30 14:39:41 -0500283 auto fetcher = ndn::util::SegmentFetcher::start(m_face, interest, m_validator);
284 fetcher->onComplete.connect(std::bind(&Nlsrc::onFetchSuccess<T>, this, _1, recordLsa));
285 fetcher->onError.connect(std::bind(&Nlsrc::onTimeout, this, _1, _2));
Vince Lehmanc439d662015-04-27 10:56:00 -0500286}
287
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700288void
289Nlsrc::recordLsa(const nlsr::Lsa& lsa)
290{
291 Router& router = m_routers.emplace(lsa.getOriginRouter(), Router()).first->second;
292
293 if (lsa.getType() == nlsr::Lsa::Type::ADJACENCY) {
294 router.adjacencyLsaString = lsa.toString();
295 }
296 else if (lsa.getType() == nlsr::Lsa::Type::COORDINATE) {
297 router.coordinateLsaString = lsa.toString();
298 }
299 else if (lsa.getType() == nlsr::Lsa::Type::NAME) {
300 router.nameLsaString = lsa.toString();
301 }
302}
303
Vince Lehmanc439d662015-04-27 10:56:00 -0500304template <class T>
305void
laqinfan35731852017-08-08 06:17:39 -0500306Nlsrc::fetchFromRt(const std::function<void(const T&)>& recordDataset)
307{
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700308 ndn::Interest interest(RT_PREFIX);
laqinfan35731852017-08-08 06:17:39 -0500309
Ashlesh Gawande05cb7282018-08-30 14:39:41 -0500310 auto fetcher = ndn::util::SegmentFetcher::start(m_face, interest, m_validator);
311 fetcher->onComplete.connect(std::bind(&Nlsrc::onFetchSuccess<T>, this, _1, recordDataset));
312 fetcher->onError.connect(std::bind(&Nlsrc::onTimeout, this, _1, _2));
laqinfan35731852017-08-08 06:17:39 -0500313}
314
315template <class T>
316void
Vince Lehmanc439d662015-04-27 10:56:00 -0500317Nlsrc::onFetchSuccess(const ndn::ConstBufferPtr& data,
laqinfan35731852017-08-08 06:17:39 -0500318 const std::function<void(const T&)>& recordDataset)
Vince Lehmanc439d662015-04-27 10:56:00 -0500319{
320 ndn::Block block;
321 size_t offset = 0;
322
323 while (offset < data->size()) {
324 bool isOk = false;
325 std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
326
327 if (!isOk) {
328 std::cerr << "ERROR: cannot decode LSA TLV" << std::endl;
329 break;
330 }
331
332 offset += block.size();
333
laqinfan35731852017-08-08 06:17:39 -0500334 T data(block);
335 recordDataset(data);
Vince Lehmanc439d662015-04-27 10:56:00 -0500336 }
337
338 runNextStep();
339}
340
341void
342Nlsrc::onTimeout(uint32_t errorCode, const std::string& error)
343{
344 std::cerr << "Request timed out (code: " << errorCode
345 << ", error: " << error << ")" << std::endl;
346}
347
Vince Lehmanc439d662015-04-27 10:56:00 -0500348void
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700349Nlsrc::recordRtable(const nlsr::RoutingTableStatus& rts)
laqinfan35731852017-08-08 06:17:39 -0500350{
laqinfan35731852017-08-08 06:17:39 -0500351 std::ostringstream os;
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700352 os << rts;
laqinfana073e2e2018-01-15 21:17:24 +0000353 m_rtString = os.str();
laqinfan35731852017-08-08 06:17:39 -0500354}
355
356void
Vince Lehmanc439d662015-04-27 10:56:00 -0500357Nlsrc::printLsdb()
358{
Vince Lehmanc439d662015-04-27 10:56:00 -0500359 std::cout << "LSDB:" << std::endl;
360
361 for (const auto& item : m_routers) {
362 std::cout << " OriginRouter: " << item.first << std::endl;
363 std::cout << std::endl;
364
365 const Router& router = item.second;
366
367 if (!router.adjacencyLsaString.empty()) {
368 std::cout << router.adjacencyLsaString << std::endl;
369 }
370
371 if (!router.coordinateLsaString.empty()) {
372 std::cout << router.coordinateLsaString << std::endl;
373 }
374
375 if (!router.nameLsaString.empty()) {
376 std::cout << router.nameLsaString << std::endl;
377 }
378 }
379}
380
laqinfan35731852017-08-08 06:17:39 -0500381void
382Nlsrc::printRT()
383{
laqinfana073e2e2018-01-15 21:17:24 +0000384 if (!m_rtString.empty()) {
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700385 std::cout << m_rtString;
laqinfana073e2e2018-01-15 21:17:24 +0000386 }
387 else {
388 std::cout << "Routing Table is not calculated yet" << std::endl;
laqinfan35731852017-08-08 06:17:39 -0500389 }
390}
391
392void
393Nlsrc::printAll()
394{
395 std::cout << "NLSR Status" << std::endl;
396 printLsdb();
397 printRT();
398}
399
Vince Lehmanc439d662015-04-27 10:56:00 -0500400} // namespace nlsrc
401
402////////////////////////////////////////////////////////////////////////////////
403////////////////////////////////////////////////////////////////////////////////
404
405int
406main(int argc, char** argv)
407{
408 ndn::Face face;
409 nlsrc::Nlsrc nlsrc(face);
410
411 nlsrc.programName = argv[0];
412
413 if (argc < 2) {
414 nlsrc.printUsage();
415 return 0;
416 }
417
418 int opt;
419 while ((opt = ::getopt(argc, argv, "hV")) != -1) {
420 switch (opt) {
421 case 'h':
422 nlsrc.printUsage();
423 return 0;
424 case 'V':
425 std::cout << NLSR_VERSION_BUILD_STRING << std::endl;
426 return 0;
427 default:
428 nlsrc.printUsage();
429 return 1;
430 }
431 }
432
433 if (argc == ::optind) {
434 nlsrc.printUsage();
435 return 1;
436 }
437
438 try {
Saurab Dulal7526cee2018-01-31 18:14:10 +0000439 ::optind = 3; // Set ::optind to the command's index
Vince Lehmanc439d662015-04-27 10:56:00 -0500440
441 nlsrc.commandLineArguments = argv + ::optind;
442 nlsrc.nOptions = argc - ::optind;
443
444 // argv[1] points to the command, so pass it to the dispatch
445 bool isOk = nlsrc.dispatch(argv[1]);
446 if (!isOk) {
447 nlsrc.printUsage();
448 return 1;
449 }
450
451 face.processEvents();
452 }
453 catch (const std::exception& e) {
454 std::cerr << "ERROR: " << e.what() << std::endl;
455 return 2;
456 }
457 return 0;
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800458}