lsdb.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 "lsdb.hpp"
23 
24 #include "logger.hpp"
25 #include "nlsr.hpp"
26 #include "utility/name-helper.hpp"
27 
28 namespace nlsr {
29 
30 INIT_LOGGER(Lsdb);
31 
32 const ndn::time::steady_clock::TimePoint Lsdb::DEFAULT_LSA_RETRIEVAL_DEADLINE =
33  ndn::time::steady_clock::TimePoint::min();
34 
35 Lsdb::Lsdb(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam,
36  NamePrefixTable& namePrefixTable, RoutingTable& routingTable)
37  : m_face(face)
38  , m_scheduler(face.getIoService())
39  , m_confParam(confParam)
40  , m_namePrefixTable(namePrefixTable)
41  , m_routingTable(routingTable)
42  , m_sync(m_face,
43  [this] (const ndn::Name& routerName, const Lsa::Type& lsaType,
44  const uint64_t& sequenceNumber) {
45  return isLsaNew(routerName, lsaType, sequenceNumber);
46  }, m_confParam)
47  , m_lsaRefreshTime(ndn::time::seconds(m_confParam.getLsaRefreshTime()))
48  , m_adjLsaBuildInterval(m_confParam.getAdjLsaBuildInterval())
49  , m_thisRouterPrefix(m_confParam.getRouterPrefix())
50  , m_sequencingManager(m_confParam.getStateFileDir(), m_confParam.getHyperbolicState())
51  , m_onNewLsaConnection(m_sync.onNewLsa->connect(
52  [this] (const ndn::Name& updateName, uint64_t sequenceNumber,
53  const ndn::Name& originRouter) {
54  ndn::Name lsaInterest{updateName};
55  lsaInterest.appendNumber(sequenceNumber);
56  expressInterest(lsaInterest, 0);
57  }))
58  , m_segmentPublisher(m_face, keyChain)
59  , m_isBuildAdjLsaSheduled(false)
60  , m_adjBuildCount(0)
61 {
62 }
63 
64 void
66 {
67  NameLsa nameLsa(m_thisRouterPrefix, m_sequencingManager.getNameLsaSeq() + 1,
68  getLsaExpirationTimePoint(), m_confParam.getNamePrefixList());
69  m_sequencingManager.increaseNameLsaSeq();
70  m_sequencingManager.writeSeqNoToFile();
71  m_sync.publishRoutingUpdate(Lsa::Type::NAME, m_sequencingManager.getNameLsaSeq());
72 
73  installLsa(std::make_shared<NameLsa>(nameLsa));
74 }
75 
76 void
78 {
79  CoordinateLsa corLsa(m_thisRouterPrefix, m_sequencingManager.getCorLsaSeq() + 1,
80  getLsaExpirationTimePoint(), m_confParam.getCorR(),
81  m_confParam.getCorTheta());
82  m_sequencingManager.increaseCorLsaSeq();
83  m_sequencingManager.writeSeqNoToFile();
84 
85  // Sync coordinate LSAs if using HR or HR dry run.
86  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
87  m_sync.publishRoutingUpdate(Lsa::Type::COORDINATE, m_sequencingManager.getCorLsaSeq());
88  }
89 
90  installLsa(std::make_shared<CoordinateLsa>(corLsa));
91 }
92 
93 void
95 {
96  m_adjBuildCount++;
97 
98  if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
99  // Don't build adjacency LSAs in hyperbolic routing
100  NLSR_LOG_DEBUG("Adjacency LSA not built. Currently in hyperbolic routing state.");
101  return;
102  }
103 
104  if (m_isBuildAdjLsaSheduled) {
105  NLSR_LOG_DEBUG("Rescheduling Adjacency LSA build in " << m_adjLsaBuildInterval);
106  }
107  else {
108  NLSR_LOG_DEBUG("Scheduling Adjacency LSA build in " << m_adjLsaBuildInterval);
109  m_isBuildAdjLsaSheduled = true;
110  }
111  m_scheduledAdjLsaBuild = m_scheduler.schedule(m_adjLsaBuildInterval, [this] { buildAdjLsa(); });
112 }
113 
114 template<typename T>
115 void
117 {
118  if ((T::type() == Lsa::Type::COORDINATE &&
119  m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_OFF) ||
120  (T::type() == Lsa::Type::ADJACENCY &&
121  m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON)) {
122  return;
123  }
124 
125  NLSR_LOG_DEBUG("---------------" << T::type() << " LSDB-------------------");
126  auto lsaRange = m_lsdb.get<byType>().equal_range(T::type());
127  for (auto lsaIt = lsaRange.first; lsaIt != lsaRange.second; ++lsaIt) {
128  auto lsaPtr = std::static_pointer_cast<T>(*lsaIt);
129  NLSR_LOG_DEBUG(lsaPtr->toString());
130  }
131 }
132 
133 void
135 {
136  writeLog<CoordinateLsa>();
137  writeLog<NameLsa>();
138  writeLog<AdjLsa>();
139 }
140 
141 void
142 Lsdb::processInterest(const ndn::Name& name, const ndn::Interest& interest)
143 {
144  ndn::Name interestName(interest.getName());
145  NLSR_LOG_DEBUG("Interest received for LSA: " << interestName);
146 
147  if (interestName[-2].isVersion()) {
148  // Interest for particular segment
149  if (m_segmentPublisher.replyFromStore(interestName)) {
150  NLSR_LOG_TRACE("Reply from SegmentPublisher storage");
151  return;
152  }
153  // Remove version and segment
154  interestName = interestName.getSubName(0, interestName.size() - 2);
155  NLSR_LOG_TRACE("Interest w/o segment and version: " << interestName);
156  }
157 
158  // increment RCV_LSA_INTEREST
160 
161  std::string chkString("LSA");
162  int32_t lsaPosition = util::getNameComponentPosition(interestName, chkString);
163 
164  // Forms the name of the router that the Interest packet came from.
165  ndn::Name originRouter = m_confParam.getNetwork();
166  originRouter.append(interestName.getSubName(lsaPosition + 1,
167  interestName.size() - lsaPosition - 3));
168 
169  // if the interest is for this router's LSA
170  if (originRouter == m_thisRouterPrefix && lsaPosition >= 0) {
171  uint64_t seqNo = interestName[-1].toNumber();
172  NLSR_LOG_DEBUG("LSA sequence number from interest: " << seqNo);
173 
174  std::string lsaType = interestName[-2].toUri();
175  Lsa::Type interestedLsType;
176  std::istringstream(lsaType) >> interestedLsType;
177  if (interestedLsType == Lsa::Type::BASE) {
178  NLSR_LOG_WARN("Received unrecognized LSA type: " << lsaType);
179  return;
180  }
181 
182  incrementInterestRcvdStats(interestedLsType);
183  if (processInterestForLsa(interest, originRouter, interestedLsType, seqNo)) {
185  }
186  }
187  // else the interest is for other router's LSA, serve signed data from LsaSegmentStorage
188  else if (auto lsaSegment = m_lsaStorage.find(interest)) {
189  NLSR_LOG_TRACE("Found data in lsa storage. Sending the data for " << interest.getName());
190  m_face.put(*lsaSegment);
191  }
192 }
193 
194 bool
195 Lsdb::processInterestForLsa(const ndn::Interest& interest, const ndn::Name& originRouter,
196  Lsa::Type lsaType, uint64_t seqNo)
197 {
198  NLSR_LOG_DEBUG(interest << " received for " << lsaType);
199  if (auto lsaPtr = findLsa(originRouter, lsaType)) {
200  NLSR_LOG_TRACE("Verifying SeqNo for " << lsaType << " is same as requested.");
201  if (lsaPtr->getSeqNo() == seqNo) {
202  m_segmentPublisher.publish(interest.getName(), interest.getName(),
203  lsaPtr->wireEncode(),
204  m_lsaRefreshTime, m_confParam.getSigningInfo());
205  incrementDataSentStats(lsaType);
206  return true;
207  }
208  }
209  else {
210  NLSR_LOG_TRACE(interest << " was not found in our LSDB");
211  }
212  return false;
213 }
214 
215 void
216 Lsdb::installLsa(shared_ptr<Lsa> lsa)
217 {
218  auto timeToExpire = m_lsaRefreshTime;
219 
220  auto chkLsa = findLsa(lsa->getOriginRouter(), lsa->getType());
221  if (chkLsa == nullptr) {
222  NLSR_LOG_DEBUG("Adding " << lsa->getType() << " LSA");
223  NLSR_LOG_DEBUG(lsa->toString());
224  ndn::time::seconds timeToExpire = m_lsaRefreshTime;
225 
226  m_lsdb.emplace(lsa);
227 
228  // Add any new name prefixes to the NPT if from another router
229  if (lsa->getOriginRouter() != m_thisRouterPrefix) {
230  // Pass the origin router as both the name to register and where it came from.
231  m_namePrefixTable.addEntry(lsa->getOriginRouter(), lsa->getOriginRouter());
232 
233  if (lsa->getType() == Lsa::Type::NAME) {
234  auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
235  for (const auto& name : nlsa->getNpl().getNames()) {
236  if (name != m_thisRouterPrefix) {
237  m_namePrefixTable.addEntry(name, nlsa->getOriginRouter());
238  }
239  }
240  }
241 
242  auto duration = lsa->getExpirationTimePoint() - ndn::time::system_clock::now();
243  if (duration > ndn::time::seconds(0)) {
244  timeToExpire = ndn::time::duration_cast<ndn::time::seconds>(duration);
245  }
246  }
247 
248  if ((lsa->getType() == Lsa::Type::ADJACENCY && m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_ON)||
249  (lsa->getType() == Lsa::Type::COORDINATE && m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF)) {
250  m_routingTable.scheduleRoutingTableCalculation();
251  }
252 
253  lsa->setExpiringEventId(scheduleLsaExpiration(lsa, timeToExpire));
254  }
255  // Else this is a known name LSA, so we are updating it.
256  else if (chkLsa->getSeqNo() < lsa->getSeqNo()) {
257  NLSR_LOG_DEBUG("Updating " << lsa->getType() << " LSA:");
258  NLSR_LOG_DEBUG(chkLsa->toString());
259  chkLsa->setSeqNo(lsa->getSeqNo());
260  chkLsa->setExpirationTimePoint(lsa->getExpirationTimePoint());
261 
262  if (lsa->getType() == Lsa::Type::NAME) {
263  auto chkNameLsa = std::static_pointer_cast<NameLsa>(chkLsa);
264  auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
265  chkNameLsa->getNpl().sort();
266  nlsa->getNpl().sort();
267  if (!chkNameLsa->isEqualContent(*nlsa)) {
268  // Obtain the set difference of the current and the incoming
269  // name prefix sets, and add those.
270  std::list<ndn::Name> newNames = nlsa->getNpl().getNames();
271  std::list<ndn::Name> oldNames = chkNameLsa->getNpl().getNames();
272  std::list<ndn::Name> namesToAdd;
273  std::set_difference(newNames.begin(), newNames.end(), oldNames.begin(), oldNames.end(),
274  std::inserter(namesToAdd, namesToAdd.begin()));
275  for (const auto& name : namesToAdd) {
276  chkNameLsa->addName(name);
277  if (nlsa->getOriginRouter() != m_thisRouterPrefix && name != m_thisRouterPrefix) {
278  m_namePrefixTable.addEntry(name, nlsa->getOriginRouter());
279  }
280  }
281 
282  chkNameLsa->getNpl().sort();
283 
284  // Also remove any names that are no longer being advertised.
285  std::list<ndn::Name> namesToRemove;
286  std::set_difference(oldNames.begin(), oldNames.end(), newNames.begin(), newNames.end(),
287  std::inserter(namesToRemove, namesToRemove.begin()));
288  for (const auto& name : namesToRemove) {
289  NLSR_LOG_DEBUG("Removing name" << name << " from Name LSA no longer advertised.");
290  chkNameLsa->removeName(name);
291  if (nlsa->getOriginRouter() != m_thisRouterPrefix && name != m_thisRouterPrefix) {
292  m_namePrefixTable.removeEntry(name, nlsa->getOriginRouter());
293  }
294  }
295  }
296  }
297  else if (lsa->getType() == Lsa::Type::ADJACENCY) {
298  auto chkAdjLsa = std::static_pointer_cast<AdjLsa>(chkLsa);
299  auto alsa = std::static_pointer_cast<AdjLsa>(lsa);
300  if (!chkAdjLsa->isEqualContent(*alsa)) {
301  chkAdjLsa->resetAdl();
302  for (const auto& adjacent : alsa->getAdl()) {
303  chkAdjLsa->addAdjacent(adjacent);
304  }
305  m_routingTable.scheduleRoutingTableCalculation();
306  }
307  }
308  else {
309  auto chkCorLsa = std::static_pointer_cast<CoordinateLsa>(chkLsa);
310  auto clsa = std::static_pointer_cast<CoordinateLsa>(lsa);
311  if (!chkCorLsa->isEqualContent(*clsa)) {
312  chkCorLsa->setCorRadius(clsa->getCorRadius());
313  chkCorLsa->setCorTheta(clsa->getCorTheta());
314  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_OFF) {
315  m_routingTable.scheduleRoutingTableCalculation();
316  }
317  }
318  }
319 
320  if (chkLsa->getOriginRouter() != m_thisRouterPrefix) {
321  auto duration = lsa->getExpirationTimePoint() - ndn::time::system_clock::now();
322  if (duration > ndn::time::seconds(0)) {
323  timeToExpire = ndn::time::duration_cast<ndn::time::seconds>(duration);
324  }
325  }
326  chkLsa->getExpiringEventId().cancel();
327  chkLsa->setExpiringEventId(scheduleLsaExpiration(chkLsa, timeToExpire));
328  NLSR_LOG_DEBUG("Updated " << lsa->getType() << " LSA:");
329  NLSR_LOG_DEBUG(chkLsa->toString());
330  }
331 }
332 
333 bool
334 Lsdb::removeLsa(const ndn::Name& router, Lsa::Type lsaType)
335 {
336  auto lsaIt = m_lsdb.get<byName>().find(std::make_tuple(router, lsaType));
337 
338  if (lsaIt != m_lsdb.end()) {
339  auto lsaPtr = *lsaIt;
340  NLSR_LOG_DEBUG("Removing " << lsaType << " LSA:");
341  NLSR_LOG_DEBUG(lsaPtr->toString());
342  // If the requested name LSA is not ours, we also need to remove
343  // its entries from the NPT.
344  if (lsaPtr->getOriginRouter() != m_thisRouterPrefix) {
345  m_namePrefixTable.removeEntry(lsaPtr->getOriginRouter(), lsaPtr->getOriginRouter());
346 
347  if (lsaType == Lsa::Type::NAME) {
348  auto nlsaPtr = std::static_pointer_cast<NameLsa>(lsaPtr);
349  for (const auto& name : nlsaPtr->getNpl().getNames()) {
350  if (name != m_thisRouterPrefix) {
351  m_namePrefixTable.removeEntry(name, nlsaPtr->getOriginRouter());
352  }
353  }
354  }
355  }
356  m_lsdb.erase(lsaIt);
357  return true;
358  }
359  return false;
360 }
361 
362 void
363 Lsdb::buildAdjLsa()
364 {
365  NLSR_LOG_TRACE("buildAdjLsa called");
366 
367  m_isBuildAdjLsaSheduled = false;
368 
369  if (m_confParam.getAdjacencyList().isAdjLsaBuildable(m_confParam.getInterestRetryNumber())) {
370 
371  int adjBuildCount = m_adjBuildCount;
372  // Only do the adjLsa build if there's one scheduled
373  if (adjBuildCount > 0) {
374  // It only makes sense to do the adjLsa build if we have neighbors
375  if (m_confParam.getAdjacencyList().getNumOfActiveNeighbor() > 0) {
376  NLSR_LOG_DEBUG("Building and installing own Adj LSA");
377  buildAndInstallOwnAdjLsa();
378  }
379  // We have no active neighbors, meaning no one can route through
380  // us. So delete our entry in the LSDB. This prevents this
381  // router from refreshing the LSA, eventually causing other
382  // routers to delete it, too.
383  else {
384  NLSR_LOG_DEBUG("Removing own Adj LSA; no ACTIVE neighbors");
385 
386  removeLsa(m_thisRouterPrefix, Lsa::Type::ADJACENCY);
387  // Recompute routing table after removal
388  m_routingTable.scheduleRoutingTableCalculation();
389  }
390  // In the case that during building the adj LSA, the FIB has to
391  // wait on an Interest response, the number of scheduled adj LSA
392  // builds could change, so we shouldn't just set it to 0.
393  m_adjBuildCount = m_adjBuildCount - adjBuildCount;
394  }
395  }
396  // We are still waiting to know the adjacency status of some
397  // neighbor, so schedule a build for later (when all that has
398  // hopefully finished)
399  else {
400  m_isBuildAdjLsaSheduled = true;
401  auto schedulingTime = ndn::time::seconds(m_confParam.getInterestRetryNumber() *
402  m_confParam.getInterestResendTime());
403  m_scheduledAdjLsaBuild = m_scheduler.schedule(schedulingTime, [this] { buildAdjLsa(); });
404  }
405 }
406 
407 void
408 Lsdb::buildAndInstallOwnAdjLsa()
409 {
410  AdjLsa adjLsa(m_thisRouterPrefix, m_sequencingManager.getAdjLsaSeq() + 1,
411  getLsaExpirationTimePoint(),
413  m_confParam.getAdjacencyList());
414  m_sequencingManager.increaseAdjLsaSeq();
415  m_sequencingManager.writeSeqNoToFile();
416 
417  //Sync adjacency LSAs if link-state or dry-run HR is enabled.
418  if (m_confParam.getHyperbolicState() != HYPERBOLIC_STATE_ON) {
419  m_sync.publishRoutingUpdate(Lsa::Type::ADJACENCY, m_sequencingManager.getAdjLsaSeq());
420  }
421 
422  installLsa(std::make_shared<AdjLsa>(adjLsa));
423 }
424 
425 void
426 Lsdb::expireOrRefreshLsa(std::shared_ptr<Lsa> lsa)
427 {
428  NLSR_LOG_DEBUG("ExpireOrRefreshLsa called for " << lsa->getType());
429  NLSR_LOG_DEBUG("OriginRouter: " << lsa->getOriginRouter() << " Seq No: " << lsa->getSeqNo());
430 
431  auto lsaIt = m_lsdb.get<byName>().find(std::make_tuple(lsa->getOriginRouter(), lsa->getType()));
432 
433  // If this name LSA exists in the LSDB
434  if (lsaIt != m_lsdb.end()) {
435  auto lsaPtr = *lsaIt;
436  NLSR_LOG_DEBUG(lsaPtr->toString());
437  NLSR_LOG_DEBUG("LSA Exists with seq no: " << lsaPtr->getSeqNo());
438  // If its seq no is the one we are expecting.
439  if (lsaPtr->getSeqNo() == lsa->getSeqNo()) {
440  if (lsaPtr->getOriginRouter() == m_thisRouterPrefix) {
441  NLSR_LOG_DEBUG("Own " << lsaPtr->getType() << " LSA, so refreshing it.");
442  NLSR_LOG_DEBUG("Current LSA:");
443  NLSR_LOG_DEBUG(lsaPtr->toString());
444  lsaPtr->setSeqNo(lsaPtr->getSeqNo() + 1);
445  m_sequencingManager.setLsaSeq(lsaPtr->getSeqNo(), lsaPtr->getType());
446  lsaPtr->setExpirationTimePoint(getLsaExpirationTimePoint());
447  NLSR_LOG_DEBUG("Updated LSA:");
448  NLSR_LOG_DEBUG(lsaPtr->toString());
449  // schedule refreshing event again
450  lsaPtr->setExpiringEventId(scheduleLsaExpiration(lsaPtr, m_lsaRefreshTime));
451  m_sequencingManager.writeSeqNoToFile();
452  m_sync.publishRoutingUpdate(lsaPtr->getType(), m_sequencingManager.getLsaSeq(lsaPtr->getType()));
453  }
454  // Since we cannot refresh other router's LSAs, our only choice is to expire.
455  else {
456  NLSR_LOG_DEBUG("Other's " << lsaPtr->getType() << " LSA, so removing from LSDB");
457  removeLsa(lsaPtr->getOriginRouter(), lsaPtr->getType());
458  }
459  }
460  }
461 }
462 
463 void
464 Lsdb::expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
465  ndn::time::steady_clock::TimePoint deadline)
466 {
467  // increment SENT_LSA_INTEREST
469 
470  if (deadline == DEFAULT_LSA_RETRIEVAL_DEADLINE) {
471  deadline = ndn::time::steady_clock::now() + ndn::time::seconds(static_cast<int>(LSA_REFRESH_TIME_MAX));
472  }
473  // The first component of the interest is the name.
474  ndn::Name lsaName = interestName.getSubName(0, interestName.size()-1);
475  // The seq no is the last
476  uint64_t seqNo = interestName[-1].toNumber();
477 
478  // If the LSA is not found in the list currently.
479  if (m_highestSeqNo.find(lsaName) == m_highestSeqNo.end()) {
480  m_highestSeqNo[lsaName] = seqNo;
481  }
482  // If the new seq no is higher, that means the LSA is valid
483  else if (seqNo > m_highestSeqNo[lsaName]) {
484  m_highestSeqNo[lsaName] = seqNo;
485  }
486  // Otherwise, its an old/invalid LSA
487  else if (seqNo < m_highestSeqNo[lsaName]) {
488  return;
489  }
490 
491  ndn::Interest interest(interestName);
492  ndn::util::SegmentFetcher::Options options;
493  options.interestLifetime = m_confParam.getLsaInterestLifetime();
494 
495  NLSR_LOG_DEBUG("Fetching Data for LSA: " << interestName << " Seq number: " << seqNo);
496  auto fetcher = ndn::util::SegmentFetcher::start(m_face, interest,
497  m_confParam.getValidator(), options);
498 
499  auto it = m_fetchers.insert(fetcher).first;
500 
501  fetcher->afterSegmentValidated.connect([this] (const ndn::Data& data) {
502  // Nlsr class subscribes to this to fetch certificates
504 
505  // If we don't do this IMS throws: std::bad_weak_ptr: bad_weak_ptr
506  auto lsaSegment = std::make_shared<const ndn::Data>(data);
507  m_lsaStorage.insert(*lsaSegment);
508  const ndn::Name& segmentName = lsaSegment->getName();
509  // Schedule deletion of the segment
510  m_scheduler.schedule(ndn::time::seconds(LSA_REFRESH_TIME_DEFAULT),
511  [this, segmentName] { m_lsaStorage.erase(segmentName); });
512  });
513 
514  fetcher->onComplete.connect([=] (const ndn::ConstBufferPtr& bufferPtr) {
515  m_lsaStorage.erase(ndn::Name(lsaName).appendNumber(seqNo - 1));
516  afterFetchLsa(bufferPtr, interestName);
517  m_fetchers.erase(it);
518  });
519 
520  fetcher->onError.connect([=] (uint32_t errorCode, const std::string& msg) {
521  onFetchLsaError(errorCode, msg, interestName, timeoutCount, deadline, lsaName, seqNo);
522  m_fetchers.erase(it);
523  });
524 
525  Lsa::Type lsaType;
526  std::istringstream(interestName[-2].toUri()) >> lsaType;
527  incrementInterestSentStats(lsaType);
528 }
529 
530 void
531 Lsdb::onFetchLsaError(uint32_t errorCode, const std::string& msg, const ndn::Name& interestName,
532  uint32_t retransmitNo, const ndn::time::steady_clock::TimePoint& deadline,
533  ndn::Name lsaName, uint64_t seqNo)
534 {
535  NLSR_LOG_DEBUG("Failed to fetch LSA: " << lsaName << ", Error code: " << errorCode
536  << ", Message: " << msg);
537 
538  if (ndn::time::steady_clock::now() < deadline) {
539  auto it = m_highestSeqNo.find(lsaName);
540  if (it != m_highestSeqNo.end() && it->second == seqNo) {
541  // If the SegmentFetcher failed due to an Interest timeout, it is safe to re-express
542  // immediately since at the least the LSA Interest lifetime has elapsed.
543  // Otherwise, it is necessary to delay the Interest re-expression to prevent
544  // the potential for constant Interest flooding.
545  ndn::time::seconds delay = m_confParam.getLsaInterestLifetime();
546 
547  if (errorCode == ndn::util::SegmentFetcher::ErrorCode::INTEREST_TIMEOUT) {
548  delay = ndn::time::seconds(0);
549  }
550  m_scheduler.schedule(delay, std::bind(&Lsdb::expressInterest, this,
551  interestName, retransmitNo + 1, deadline));
552  }
553  }
554 }
555 
556 void
557 Lsdb::afterFetchLsa(const ndn::ConstBufferPtr& bufferPtr, const ndn::Name& interestName)
558 {
559  NLSR_LOG_DEBUG("Received data for LSA interest: " << interestName);
561 
562  ndn::Name lsaName = interestName.getSubName(0, interestName.size()-1);
563  uint64_t seqNo = interestName[-1].toNumber();
564 
565  if (m_highestSeqNo.find(lsaName) == m_highestSeqNo.end()) {
566  m_highestSeqNo[lsaName] = seqNo;
567  }
568  else if (seqNo > m_highestSeqNo[lsaName]) {
569  m_highestSeqNo[lsaName] = seqNo;
570  NLSR_LOG_TRACE("SeqNo for LSA(name): " << interestName << " updated");
571  }
572  else if (seqNo < m_highestSeqNo[lsaName]) {
573  return;
574  }
575 
576  std::string chkString("LSA");
577  int32_t lsaPosition = util::getNameComponentPosition(interestName, chkString);
578 
579  if (lsaPosition >= 0) {
580  // Extracts the prefix of the originating router from the data.
581  ndn::Name originRouter = m_confParam.getNetwork();
582  originRouter.append(interestName.getSubName(lsaPosition + 1,
583  interestName.size() - lsaPosition - 3));
584 
585  try {
586  Lsa::Type interestedLsType;
587  std::istringstream(interestName[-2].toUri()) >> interestedLsType;
588 
589  if (interestedLsType == Lsa::Type::BASE) {
590  NLSR_LOG_WARN("Received unrecognized LSA Type: " << interestName[-2].toUri());
591  return;
592  }
593 
594  ndn::Block block(bufferPtr);
595  if (interestedLsType == Lsa::Type::NAME) {
597  if (isLsaNew(originRouter, interestedLsType, seqNo)) {
598  installLsa(std::make_shared<NameLsa>(block));
599  }
600  }
601  else if (interestedLsType == Lsa::Type::ADJACENCY) {
603  if (isLsaNew(originRouter, interestedLsType, seqNo)) {
604  installLsa(std::make_shared<AdjLsa>(block));
605  }
606  }
607  else if (interestedLsType == Lsa::Type::COORDINATE) {
609  if (isLsaNew(originRouter, interestedLsType, seqNo)) {
610  installLsa(std::make_shared<CoordinateLsa>(block));
611  }
612  }
613  }
614  catch (const std::exception& e) {
615  NLSR_LOG_TRACE("LSA data decoding error :( " << e.what());
616  return;
617  }
618  }
619 }
620 
621 } // namespace nlsr
Data abstraction for CoordinateLsa CoordinateLsa := COORDINATE-LSA-TYPE TLV-LENGTH Lsa HyperbolicRadi...
void setLsaSeq(uint64_t seqNo, Lsa::Type lsaType)
#define NLSR_LOG_WARN(x)
Definition: logger.hpp:40
ndn::security::ValidatorConfig & getValidator()
Data abstraction for Lsa Lsa := LSA-TYPE TLV-LENGTH Name SequenceNumber ExpirationTimePoint.
Definition: lsa.hpp:42
A class to house all the configuration parameters for NLSR.
Definition: tlv-nlsr.hpp:25
void scheduleAdjLsaBuild()
Schedules a build of this router&#39;s LSA.
Definition: lsdb.cpp:94
uint32_t getAdjLsaBuildInterval() const
uint32_t getLsaRefreshTime() const
const std::string & getStateFileDir() const
void scheduleRoutingTableCalculation()
Schedules a calculation event in the event scheduler only if one isn&#39;t already scheduled.
std::unique_ptr< OnNewLsa > onNewLsa
NamePrefixList & getNpl()
Definition: name-lsa.hpp:59
const ndn::security::SigningInfo & getSigningInfo() const
AdjacencyList & getAdjacencyList()
#define NLSR_LOG_DEBUG(x)
Definition: logger.hpp:38
const ndn::Name & getRouterPrefix() const
Lsdb(ndn::Face &face, ndn::KeyChain &keyChain, ConfParameter &confParam, NamePrefixTable &namePrefixTable, RoutingTable &routingTable)
Definition: lsdb.cpp:35
Copyright (c) 2014-2018, The University of Memphis, Regents of the University of California.
int32_t getNumOfActiveNeighbor() const
void buildAndInstallOwnNameLsa()
Builds a name LSA for this router and then installs it into the LSDB.
Definition: lsdb.cpp:65
const ndn::time::seconds & getLsaInterestLifetime() const
#define INIT_LOGGER(name)
Definition: logger.hpp:35
void removeEntry(const ndn::Name &name, const ndn::Name &destRouter)
Removes a destination from a name prefix table entry.
double getCorR() const
uint32_t getInterestRetryNumber() const
ndn::util::signal::Signal< Lsdb, const ndn::Data & > afterSegmentValidatedSignal
Definition: lsdb.hpp:329
Data abstraction for AdjLsa AdjacencyLsa := ADJACENCY-LSA-TYPE TLV-LENGTH Lsa Adjacency*.
Definition: adj-lsa.hpp:37
uint64_t getLsaSeq(Lsa::Type lsaType)
void processInterest(const ndn::Name &name, const ndn::Interest &interest)
Definition: lsdb.cpp:142
void resetAdl()
Definition: adj-lsa.hpp:69
static int32_t getNameComponentPosition(const ndn::Name &name, const std::string &searchString)
search a name component in ndn::Name and return the position of the component
Definition: name-helper.hpp:44
void buildAndInstallOwnCoordinateLsa()
Builds a cor. LSA for this router and installs it into the LSDB.
Definition: lsdb.cpp:77
const ndn::Name & getNetwork() const
int32_t getHyperbolicState() const
uint64_t getNameLsaSeq() const
Copyright (c) 2014-2020, The University of Memphis, Regents of the University of California, Arizona Board of Regents.
NamePrefixList & getNamePrefixList()
ndn::util::signal::Signal< Lsdb, Statistics::PacketType > lsaIncrementSignal
Definition: lsdb.hpp:328
void setCorRadius(double cr)
Data abstraction for NameLsa NameLsa := NAME-LSA-TYPE TLV-LENGTH Lsa Name+.
Definition: name-lsa.hpp:35
std::shared_ptr< T > findLsa(const ndn::Name &router) const
Definition: lsdb.hpp:123
bool isAdjLsaBuildable(const uint32_t interestRetryNo) const
Determines whether this list can be used to build an adj. LSA.
uint32_t getInterestResendTime() const
#define NLSR_LOG_TRACE(x)
Definition: logger.hpp:37
std::vector< double > getCorTheta() const
void publishRoutingUpdate(const Lsa::Type &type, const uint64_t &seqNo)
Instruct ChronoSync to publish an update.
void writeLog() const
Definition: lsdb.cpp:116
void addEntry(const ndn::Name &name, const ndn::Name &destRouter)
Adds a destination to the specified name prefix.