nlsr.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2020, The University of Memphis,
4  * 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 "nlsr.hpp"
23 #include "adjacent.hpp"
24 #include "logger.hpp"
25 
26 #include <cstdlib>
27 #include <string>
28 #include <sstream>
29 #include <cstdio>
30 #include <unistd.h>
31 #include <vector>
32 
33 #include <ndn-cxx/net/face-uri.hpp>
34 #include <ndn-cxx/signature.hpp>
35 
36 namespace nlsr {
37 
38 INIT_LOGGER(Nlsr);
39 
40 const ndn::Name Nlsr::LOCALHOST_PREFIX = ndn::Name("/localhost/nlsr");
41 
42 Nlsr::Nlsr(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam)
43  : m_face(face)
44  , m_scheduler(face.getIoService())
45  , m_keyChain(keyChain)
46  , m_confParam(confParam)
47  , m_adjacencyList(confParam.getAdjacencyList())
48  , m_namePrefixList(confParam.getNamePrefixList())
49  , m_validator(m_confParam.getValidator())
50  , m_fib(m_face, m_scheduler, m_adjacencyList, m_confParam, m_keyChain)
51  , m_routingTable(m_scheduler, m_fib, m_lsdb, m_namePrefixTable, m_confParam)
52  , m_namePrefixTable(m_fib, m_routingTable, m_routingTable.afterRoutingChange)
53  , m_lsdb(m_face, m_keyChain, m_confParam, m_namePrefixTable, m_routingTable)
54  , m_helloProtocol(m_face, m_keyChain, confParam, m_routingTable, m_lsdb)
55  , m_onNewLsaConnection(m_lsdb.getSync().onNewLsa->connect(
56  [this] (const ndn::Name& updateName, uint64_t sequenceNumber,
57  const ndn::Name& originRouter) {
58  registerStrategyForCerts(originRouter);
59  }))
60  , m_onPrefixRegistrationSuccess(m_fib.onPrefixRegistrationSuccess.connect(
61  [this] (const ndn::Name& name) {
62  m_helloProtocol.sendHelloInterest(name);
63  }))
64  , m_onHelloDataValidated(m_helloProtocol.onHelloDataValidated.connect(
65  [this] (const ndn::Name& neighbor) {
66  auto it = m_adjacencyList.findAdjacent(neighbor);
67  if (it != m_adjacencyList.end()) {
68  m_fib.registerPrefix(m_confParam.getSyncPrefix(), it->getFaceUri(), it->getLinkCost(),
69  ndn::time::milliseconds::max(), ndn::nfd::ROUTE_FLAG_CAPTURE, 0);
70  }
71  }))
72  , m_dispatcher(m_face, m_keyChain)
73  , m_datasetHandler(m_dispatcher, m_lsdb, m_routingTable)
74  , m_controller(m_face, m_keyChain)
75  , m_faceDatasetController(m_face, m_keyChain)
76  , m_prefixUpdateProcessor(m_dispatcher,
77  m_confParam.getPrefixUpdateValidator(),
78  m_namePrefixList,
79  m_lsdb,
80  m_confParam.getConfFileNameDynamic())
81  , m_nfdRibCommandProcessor(m_dispatcher,
82  m_namePrefixList,
83  m_lsdb)
84  , m_statsCollector(m_lsdb, m_helloProtocol)
85  , m_faceMonitor(m_face)
86 {
87  NLSR_LOG_DEBUG("Initializing Nlsr");
88 
89  m_faceMonitor.onNotification.connect(std::bind(&Nlsr::onFaceEventNotification, this, _1));
90  m_faceMonitor.start();
91 
92  // Do key initialization and registrations first, then initialize faces
93  // which will create routes to neighbor
94 
95  setStrategies();
96 
97  NLSR_LOG_DEBUG("Default NLSR identity: " << m_confParam.getSigningInfo().getSignerName());
98 
99  // Can be moved to HelloProtocol and Lsdb ctor if initializeKey is set
100  // earlier in the Nlsr constructor so as to set m_signingInfo
101  setInfoInterestFilter();
102  setLsaInterestFilter();
103 
104  // Add top-level prefixes: router and localhost prefix
105  addDispatcherTopPrefix(ndn::Name(m_confParam.getRouterPrefix()).append("nlsr"));
106  addDispatcherTopPrefix(LOCALHOST_PREFIX);
107 
108  enableIncomingFaceIdIndication();
109 
110  registerLocalhostPrefix();
111  registerRouterPrefix();
112 
113  initializeFaces(std::bind(&Nlsr::processFaceDataset, this, _1),
114  std::bind(&Nlsr::onFaceDatasetFetchTimeout, this, _1, _2, 0));
115 
116  // Could be moved into ctor, but unit tests need to be modified
117  initialize();
118 }
119 
120 void
121 Nlsr::registerStrategyForCerts(const ndn::Name& originRouter)
122 {
123  for (const ndn::Name& router : m_strategySetOnRouters) {
124  if (router == originRouter) {
125  // Have already set strategy for this router's certs once
126  return;
127  }
128  }
129 
130  m_strategySetOnRouters.push_back(originRouter);
131 
132  ndn::Name routerKey(originRouter);
133  routerKey.append("KEY");
134  ndn::Name instanceKey(originRouter);
135  instanceKey.append("nlsr").append("KEY");
136 
137  m_fib.setStrategy(routerKey, Fib::BEST_ROUTE_V2_STRATEGY, 0);
138  m_fib.setStrategy(instanceKey, Fib::BEST_ROUTE_V2_STRATEGY, 0);
139 
140  ndn::Name siteKey;
141  for (size_t i = 0; i < originRouter.size(); ++i) {
142  if (originRouter[i].toUri() == "%C1.Router") {
143  break;
144  }
145  siteKey.append(originRouter[i]);
146  }
147  ndn::Name opPrefix(siteKey);
148  siteKey.append("KEY");
149  m_fib.setStrategy(siteKey, Fib::BEST_ROUTE_V2_STRATEGY, 0);
150 
151  opPrefix.append(std::string("%C1.Operator"));
152  m_fib.setStrategy(opPrefix, Fib::BEST_ROUTE_V2_STRATEGY, 0);
153 }
154 
155 void
156 Nlsr::registrationFailed(const ndn::Name& name)
157 {
158  NLSR_LOG_ERROR("ERROR: Failed to register prefix " << name << " in local hub's daemon");
159  BOOST_THROW_EXCEPTION(Error("Error: Prefix registration failed"));
160 }
161 
162 void
163 Nlsr::onRegistrationSuccess(const ndn::Name& name)
164 {
165  NLSR_LOG_DEBUG("Successfully registered prefix: " << name);
166 }
167 
168 void
170 {
171  ndn::Name name(m_confParam.getRouterPrefix());
172  name.append("nlsr");
173  name.append("INFO");
174 
175  NLSR_LOG_DEBUG("Setting interest filter for Hello interest: " << name);
176 
177  m_face.setInterestFilter(ndn::InterestFilter(name).allowLoopback(false),
178  std::bind(&HelloProtocol::processInterest, &m_helloProtocol, _1, _2),
179  std::bind(&Nlsr::onRegistrationSuccess, this, _1),
180  std::bind(&Nlsr::registrationFailed, this, _1),
181  m_confParam.getSigningInfo(), ndn::nfd::ROUTE_FLAG_CAPTURE);
182 }
183 
184 void
186 {
187  ndn::Name name = m_confParam.getLsaPrefix();
188 
189  NLSR_LOG_DEBUG("Setting interest filter for LsaPrefix: " << name);
190 
191  m_face.setInterestFilter(ndn::InterestFilter(name).allowLoopback(false),
192  std::bind(&Lsdb::processInterest, &m_lsdb, _1, _2),
193  std::bind(&Nlsr::onRegistrationSuccess, this, _1),
194  std::bind(&Nlsr::registrationFailed, this, _1),
195  m_confParam.getSigningInfo(), ndn::nfd::ROUTE_FLAG_CAPTURE);
196 }
197 
198 void
199 Nlsr::addDispatcherTopPrefix(const ndn::Name& topPrefix)
200 {
201  try {
202  // false since we want to have control over the registration process
203  m_dispatcher.addTopPrefix(topPrefix, false, m_confParam.getSigningInfo());
204  }
205  catch (const std::exception& e) {
206  NLSR_LOG_ERROR("Error setting top-level prefix in dispatcher: " << e.what() << "\n");
207  }
208 }
209 
210 void
212 {
213  m_fib.setStrategy(m_confParam.getLsaPrefix(), Fib::MULTICAST_STRATEGY, 0);
214  m_fib.setStrategy(m_confParam.getSyncPrefix(), Fib::MULTICAST_STRATEGY, 0);
215 }
216 
217 void
219 {
220  // Logging start
221  m_adjacencyList.writeLog();
222  NLSR_LOG_DEBUG(m_namePrefixList);
223 
224  m_lsdb.buildAndInstallOwnNameLsa();
225 
226  // Install coordinate LSAs if using HR or dry-run HR.
227  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
228  m_lsdb.buildAndInstallOwnCoordinateLsa();
229  }
230 
231  // Need to set direct neighbors' costs to 0 for hyperbolic routing
232  if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
233  for (auto&& neighbor : m_adjacencyList.getAdjList()) {
234  neighbor.setLinkCost(0);
235  }
236  }
237 }
238 
239 void
240 Nlsr::registerLocalhostPrefix()
241 {
242  m_face.registerPrefix(LOCALHOST_PREFIX,
243  std::bind(&Nlsr::onRegistrationSuccess, this, _1),
244  std::bind(&Nlsr::registrationFailed, this, _1));
245 }
246 
247 void
248 Nlsr::registerRouterPrefix()
249 {
250  m_face.registerPrefix(ndn::Name(m_confParam.getRouterPrefix()).append("nlsr"),
251  std::bind(&Nlsr::onRegistrationSuccess, this, _1),
252  std::bind(&Nlsr::registrationFailed, this, _1));
253 }
254 
255 void
256 Nlsr::onFaceEventNotification(const ndn::nfd::FaceEventNotification& faceEventNotification)
257 {
258  NLSR_LOG_TRACE("Nlsr::onFaceEventNotification called");
259 
260  switch (faceEventNotification.getKind()) {
261  case ndn::nfd::FACE_EVENT_DESTROYED: {
262  uint64_t faceId = faceEventNotification.getFaceId();
263 
264  auto adjacent = m_adjacencyList.findAdjacent(faceId);
265 
266  if (adjacent != m_adjacencyList.end()) {
267  NLSR_LOG_DEBUG("Face to " << adjacent->getName() << " with face id: " << faceId << " destroyed");
268 
269  adjacent->setFaceId(0);
270 
271  // Only trigger an Adjacency LSA build if this node is changing
272  // from ACTIVE to INACTIVE since this rebuild will effectively
273  // cancel the previous Adjacency LSA refresh event and schedule
274  // a new one further in the future.
275  //
276  // Continuously scheduling the refresh in the future will block
277  // the router from refreshing its Adjacency LSA. Since other
278  // routers' Name prefixes' expiration times are updated when
279  // this router refreshes its Adjacency LSA, the other routers'
280  // prefixes will expire and be removed from the RIB.
281  //
282  // This check is required to fix Bug #2733 for now. This check
283  // would be unnecessary to fix Bug #2733 when Issue #2732 is
284  // completed, but the check also helps with optimization so it
285  // can remain even when Issue #2732 is implemented.
286  if (adjacent->getStatus() == Adjacent::STATUS_ACTIVE) {
287  adjacent->setStatus(Adjacent::STATUS_INACTIVE);
288 
289  // A new adjacency LSA cannot be built until the neighbor is marked INACTIVE and
290  // has met the HELLO retry threshold
291  adjacent->setInterestTimedOutNo(m_confParam.getInterestRetryNumber());
292 
293  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
294  m_routingTable.scheduleRoutingTableCalculation();
295  }
296  else {
297  m_lsdb.scheduleAdjLsaBuild();
298  }
299  }
300  }
301  break;
302  }
303  case ndn::nfd::FACE_EVENT_CREATED: {
304  // Find the neighbor in our adjacency list
305  ndn::FaceUri faceUri;
306  try {
307  faceUri = ndn::FaceUri(faceEventNotification.getRemoteUri());
308  }
309  catch (const std::exception& e) {
310  NLSR_LOG_WARN(e.what());
311  return;
312  }
313  auto adjacent = m_adjacencyList.findAdjacent(faceUri);
314  uint64_t faceId = faceEventNotification.getFaceId();
315 
316  // If we have a neighbor by that FaceUri and it has no FaceId or
317  // the FaceId is different from ours, we have a match.
318  if (adjacent != m_adjacencyList.end() &&
319  (adjacent->getFaceId() == 0 || adjacent->getFaceId() != faceId))
320  {
321  NLSR_LOG_DEBUG("Face creation event matches neighbor: " << adjacent->getName()
322  << ". New Face ID: " << faceId << ". Registering prefixes.");
323  adjacent->setFaceId(faceId);
324 
325  registerAdjacencyPrefixes(*adjacent, ndn::time::milliseconds::max());
326 
327  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
328  m_routingTable.scheduleRoutingTableCalculation();
329  }
330  else {
331  m_lsdb.scheduleAdjLsaBuild();
332  }
333  }
334  break;
335  }
336  default:
337  break;
338  }
339 }
340 
341 void
343  const FetchDatasetTimeoutCallback& onFetchFailure)
344 {
345  NLSR_LOG_TRACE("Initializing Faces...");
346 
347  m_faceDatasetController.fetch<ndn::nfd::FaceDataset>(onFetchSuccess, onFetchFailure);
348 
349 }
350 
351 void
352 Nlsr::processFaceDataset(const std::vector<ndn::nfd::FaceStatus>& faces)
353 {
354  NLSR_LOG_DEBUG("Processing face dataset");
355 
356  // Iterate over each neighbor listed in nlsr.conf
357  for (auto&& adjacent : m_adjacencyList.getAdjList()) {
358 
359  const std::string& faceUriString = adjacent.getFaceUri().toString();
360  // Check the list of FaceStatus objects we got for a match
361  for (const auto& faceStatus : faces) {
362  // Set the adjacency FaceID if we find a URI match and it was
363  // previously unset. Change the boolean to true.
364  if (adjacent.getFaceId() == 0 && faceUriString == faceStatus.getRemoteUri()) {
365  NLSR_LOG_DEBUG("FaceUri: " << faceStatus.getRemoteUri() <<
366  " FaceId: "<< faceStatus.getFaceId());
367  adjacent.setFaceId(faceStatus.getFaceId());
368  // Register the prefixes for each neighbor
369  this->registerAdjacencyPrefixes(adjacent, ndn::time::milliseconds::max());
370  }
371  }
372  // If this adjacency has no information in this dataset, then one
373  // of two things is happening: 1. NFD is starting slowly and this
374  // Face wasn't ready yet, or 2. NFD is configured
375  // incorrectly and this Face isn't available.
376  if (adjacent.getFaceId() == 0) {
377  NLSR_LOG_WARN("The adjacency " << adjacent.getName() <<
378  " has no Face information in this dataset.");
379  }
380  }
381 
382  scheduleDatasetFetch();
383 }
384 
385 void
387  const ndn::time::milliseconds& timeout)
388 {
389  ndn::FaceUri faceUri = adj.getFaceUri();
390  double linkCost = adj.getLinkCost();
391  const ndn::Name& adjName = adj.getName();
392 
393  m_fib.registerPrefix(adjName, faceUri, linkCost,
394  timeout, ndn::nfd::ROUTE_FLAG_CAPTURE, 0);
395 
396  m_fib.registerPrefix(m_confParam.getLsaPrefix(),
397  faceUri, linkCost, timeout,
398  ndn::nfd::ROUTE_FLAG_CAPTURE, 0);
399 }
400 
401 void
403  const std::string& msg,
404  uint32_t nRetriesSoFar)
405 {
406  NLSR_LOG_DEBUG("onFaceDatasetFetchTimeout");
407  // If we have exceeded the maximum attempt count, do not try again.
408  if (nRetriesSoFar++ < m_confParam.getFaceDatasetFetchTries()) {
409  NLSR_LOG_DEBUG("Failed to fetch dataset: " << msg << ". Attempting retry #" << nRetriesSoFar);
410  m_faceDatasetController.fetch<ndn::nfd::FaceDataset>(std::bind(&Nlsr::processFaceDataset,
411  this, _1),
413  this, _1, _2, nRetriesSoFar));
414  }
415  else {
416  NLSR_LOG_ERROR("Failed to fetch dataset: " << msg << ". Exceeded limit of " <<
417  m_confParam.getFaceDatasetFetchTries() << ", so not trying again this time.");
418  // If we fail to fetch it, just do nothing until the next
419  // interval. Since this is a backup mechanism, we aren't as
420  // concerned with retrying.
421  scheduleDatasetFetch();
422  }
423 }
424 
425 void
426 Nlsr::scheduleDatasetFetch()
427 {
428  NLSR_LOG_DEBUG("Scheduling Dataset Fetch in " << m_confParam.getFaceDatasetFetchInterval());
429 
430  m_scheduler.schedule(m_confParam.getFaceDatasetFetchInterval(),
431  [this] {
432  this->initializeFaces(
433  [this] (const std::vector<ndn::nfd::FaceStatus>& faces) {
434  this->processFaceDataset(faces);
435  },
436  [this] (uint32_t code, const std::string& msg) {
437  this->onFaceDatasetFetchTimeout(code, msg, 0);
438  });
439  });
440 }
441 
442 void
443 Nlsr::enableIncomingFaceIdIndication()
444 {
445  NLSR_LOG_DEBUG("Enabling incoming face id indication for local face.");
446 
447  m_controller.start<ndn::nfd::FaceUpdateCommand>(
448  ndn::nfd::ControlParameters()
449  .setFlagBit(ndn::nfd::FaceFlagBit::BIT_LOCAL_FIELDS_ENABLED, true),
450  bind(&Nlsr::onFaceIdIndicationSuccess, this, _1),
451  bind(&Nlsr::onFaceIdIndicationFailure, this, _1));
452 }
453 
454 void
455 Nlsr::onFaceIdIndicationSuccess(const ndn::nfd::ControlParameters& cp)
456 {
457  NLSR_LOG_DEBUG("Successfully enabled incoming face id indication"
458  << "for face id " << cp.getFaceId());
459 }
460 
461 void
462 Nlsr::onFaceIdIndicationFailure(const ndn::nfd::ControlResponse& cr)
463 {
464  std::ostringstream os;
465  os << "Failed to enable incoming face id indication feature: " <<
466  "(code: " << cr.getCode() << ", reason: " << cr.getText() << ")";
467 
468  NLSR_LOG_DEBUG(os.str());
469 }
470 
471 } // namespace nlsr
void initializeFaces(const FetchDatasetCallback &onFetchSuccess, const FetchDatasetTimeoutCallback &onFetchFailure)
Initializes neighbors&#39; Faces using information from NFD.
Definition: nlsr.cpp:342
void onFaceDatasetFetchTimeout(uint32_t code, const std::string &reason, uint32_t nRetriesSoFar)
Definition: nlsr.cpp:402
#define NLSR_LOG_WARN(x)
Definition: logger.hpp:40
A class to house all the configuration parameters for NLSR.
Definition: tlv-nlsr.hpp:27
void initialize()
Definition: nlsr.cpp:218
const ndn::FaceUri & getFaceUri() const
Definition: adjacent.hpp:69
std::function< void(uint32_t, const std::string &)> FetchDatasetTimeoutCallback
Definition: nlsr.hpp:70
const ndn::Name & getName() const
Definition: adjacent.hpp:57
static const std::string MULTICAST_STRATEGY
Definition: fib.hpp:227
void setStrategies()
Definition: nlsr.cpp:211
void scheduleRoutingTableCalculation()
Schedules a calculation event in the event scheduler only if one isn&#39;t already scheduled.
const ndn::security::SigningInfo & getSigningInfo() const
#define NLSR_LOG_DEBUG(x)
Definition: logger.hpp:38
const ndn::Name & getRouterPrefix() const
std::function< void(const std::vector< ndn::nfd::FaceStatus > &)> FetchDatasetCallback
Definition: nlsr.hpp:69
Nlsr(ndn::Face &face, ndn::KeyChain &keyChain, ConfParameter &confParam)
Definition: nlsr.cpp:42
void setStrategy(const ndn::Name &name, const std::string &strategy, uint32_t count)
Definition: fib.cpp:293
static const std::string BEST_ROUTE_V2_STRATEGY
Definition: fib.hpp:228
Copyright (c) 2014-2018, The University of Memphis, Regents of the University of California.
void setLsaInterestFilter()
Definition: nlsr.cpp:185
void addDispatcherTopPrefix(const ndn::Name &topPrefix)
Add top level prefixes for Dispatcher.
Definition: nlsr.cpp:199
static const ndn::Name LOCALHOST_PREFIX
Definition: nlsr.hpp:206
void registerAdjacencyPrefixes(const Adjacent &adj, const ndn::time::milliseconds &timeout)
Registers NLSR-specific prefixes for a neighbor (Adjacent)
Definition: nlsr.cpp:386
#define INIT_LOGGER(name)
Definition: logger.hpp:35
uint32_t getInterestRetryNumber() const
ndn::util::Signal< HelloProtocol, const ndn::Name & > onHelloDataValidated
void onRegistrationSuccess(const ndn::Name &name)
Definition: nlsr.cpp:163
uint32_t getFaceDatasetFetchTries() const
void processInterest(const ndn::Name &name, const ndn::Interest &interest)
Processes a Hello Interest from a neighbor.
void setInfoInterestFilter()
Definition: nlsr.cpp:169
void processInterest(const ndn::Name &name, const ndn::Interest &interest)
Definition: lsdb.cpp:1008
const ndn::Name & getSyncPrefix() const
double getLinkCost() const
Definition: adjacent.hpp:81
int32_t getHyperbolicState() const
A neighbor reachable over a Face.
Definition: adjacent.hpp:38
void registerStrategyForCerts(const ndn::Name &originRouter)
Definition: nlsr.cpp:121
#define NLSR_LOG_ERROR(x)
Definition: logger.hpp:41
void registrationFailed(const ndn::Name &name)
Definition: nlsr.cpp:156
Copyright (c) 2014-2019, The University of Memphis, Regents of the University of California, Arizona Board of Regents.
AdjacencyList::iterator findAdjacent(const ndn::Name &adjName)
const ndn::time::seconds getFaceDatasetFetchInterval() const
const_iterator end() const
ndn::util::Signal< Fib, const ndn::Name & > onPrefixRegistrationSuccess
Definition: fib.hpp:229
const ndn::Name & getLsaPrefix() const
void processFaceDataset(const std::vector< ndn::nfd::FaceStatus > &faces)
Consumes a Face StatusDataset to configure NLSR neighbors.
Definition: nlsr.cpp:352
std::list< Adjacent > & getAdjList()
#define NLSR_LOG_TRACE(x)
Definition: logger.hpp:37
void registerPrefix(const ndn::Name &namePrefix, const ndn::FaceUri &faceUri, uint64_t faceCost, const ndn::time::milliseconds &timeout, uint64_t flags, uint8_t times)
Inform NFD of a next-hop.
Definition: fib.cpp:201