routing-table.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2024, The University of Memphis,
4  * Regents of the University of California
5  *
6  * This file is part of NLSR (Named-data Link State Routing).
7  * See AUTHORS.md for complete list of NLSR authors and contributors.
8  *
9  * NLSR is free software: you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License as published by the Free Software Foundation,
11  * either version 3 of the License, or (at your option) any later version.
12  *
13  * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
14  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "routing-table.hpp"
22 #include "name-map.hpp"
23 #include "routing-calculator.hpp"
24 #include "routing-table-entry.hpp"
25 
26 #include "conf-parameter.hpp"
27 #include "logger.hpp"
28 #include "nlsr.hpp"
29 #include "tlv-nlsr.hpp"
30 
31 namespace nlsr {
32 
33 INIT_LOGGER(route.RoutingTable);
34 
35 RoutingTable::RoutingTable(ndn::Scheduler& scheduler, Lsdb& lsdb, ConfParameter& confParam)
36  : m_scheduler(scheduler)
37  , m_lsdb(lsdb)
38  , m_routingCalcInterval{confParam.getRoutingCalcInterval()}
39  , m_isRoutingTableCalculating(false)
40  , m_isRouteCalculationScheduled(false)
41  , m_confParam(confParam)
42  , m_hyperbolicState(m_confParam.getHyperbolicState())
43 {
44  m_afterLsdbModified = lsdb.onLsdbModified.connect(
45  [this] (std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
46  const auto& namesToAdd, const auto& namesToRemove) {
47  auto type = lsa->getType();
48  bool updateForOwnAdjacencyLsa = lsa->getOriginRouter() == m_confParam.getRouterPrefix() &&
49  type == Lsa::Type::ADJACENCY;
50  bool scheduleCalculation = false;
51 
52  if (updateType == LsdbUpdate::REMOVED && updateForOwnAdjacencyLsa) {
53  // If own Adjacency LSA is removed then we have no ACTIVE neighbors.
54  // (Own Coordinate LSA is never removed. But routing table calculation is scheduled
55  // in HelloProtocol. The routing table calculator for HR takes into account
56  // the INACTIVE status of the link).
57  NLSR_LOG_DEBUG("No Adj LSA of router itself, routing table can not be calculated :(");
58  clearRoutingTable();
59  clearDryRoutingTable();
60  NLSR_LOG_DEBUG("Calling Update NPT With new Route");
62  NLSR_LOG_DEBUG(*this);
63  m_ownAdjLsaExist = false;
64  }
65 
66  if (updateType == LsdbUpdate::INSTALLED && updateForOwnAdjacencyLsa) {
67  m_ownAdjLsaExist = true;
68  }
69 
70  // Don;t do anything on removal, wait for HelloProtocol to confirm and then react
71  if (updateType == LsdbUpdate::INSTALLED || updateType == LsdbUpdate::UPDATED) {
72  if ((type == Lsa::Type::ADJACENCY && m_hyperbolicState != HYPERBOLIC_STATE_ON) ||
73  (type == Lsa::Type::COORDINATE && m_hyperbolicState != HYPERBOLIC_STATE_OFF)) {
74  scheduleCalculation = true;
75  }
76  }
77 
78  if (scheduleCalculation) {
80  }
81  }
82  );
83 }
84 
85 void
87 {
88  m_lsdb.writeLog();
89  NLSR_LOG_TRACE("Calculating routing table");
90 
91  if (m_isRoutingTableCalculating == false) {
92  m_isRoutingTableCalculating = true;
93 
94  if (m_hyperbolicState == HYPERBOLIC_STATE_OFF) {
95  calculateLsRoutingTable();
96  }
97  else if (m_hyperbolicState == HYPERBOLIC_STATE_DRY_RUN) {
98  calculateLsRoutingTable();
99  calculateHypRoutingTable(true);
100  }
101  else if (m_hyperbolicState == HYPERBOLIC_STATE_ON) {
102  calculateHypRoutingTable(false);
103  }
104 
105  m_isRouteCalculationScheduled = false;
106  m_isRoutingTableCalculating = false;
107  }
108  else {
110  }
111 }
112 
113 void
114 RoutingTable::calculateLsRoutingTable()
115 {
116  NLSR_LOG_TRACE("CalculateLsRoutingTable Called");
117 
118  if (m_lsdb.getIsBuildAdjLsaScheduled()) {
119  NLSR_LOG_DEBUG("Adjacency build is scheduled, routing table can not be calculated :(");
120  return;
121  }
122 
123  // We only check this in LS since we never remove our own Coordinate LSA,
124  // whereas we remove our own Adjacency LSA if we don't have any neighbors
125  if (!m_ownAdjLsaExist) {
126  return;
127  }
128 
129  clearRoutingTable();
130 
131  auto lsaRange = m_lsdb.getLsdbIterator<AdjLsa>();
132  auto map = NameMap::createFromAdjLsdb(lsaRange.first, lsaRange.second);
134 
135  calculateLinkStateRoutingPath(map, *this, m_confParam, m_lsdb);
136 
137  NLSR_LOG_DEBUG("Calling Update NPT With new Route");
139  NLSR_LOG_DEBUG(*this);
140 }
141 
142 void
143 RoutingTable::calculateHypRoutingTable(bool isDryRun)
144 {
145  if (isDryRun) {
146  clearDryRoutingTable();
147  }
148  else {
149  clearRoutingTable();
150  }
151 
152  auto lsaRange = m_lsdb.getLsdbIterator<CoordinateLsa>();
153  auto map = NameMap::createFromCoordinateLsdb(lsaRange.first, lsaRange.second);
155 
156  calculateHyperbolicRoutingPath(map, *this, m_lsdb, m_confParam.getAdjacencyList(),
157  m_confParam.getRouterPrefix(), isDryRun);
158 
159  if (!isDryRun) {
160  NLSR_LOG_DEBUG("Calling Update NPT With new Route");
162  NLSR_LOG_DEBUG(*this);
163  }
164 }
165 
166 void
168 {
169  if (!m_isRouteCalculationScheduled) {
170  NLSR_LOG_DEBUG("Scheduling routing table calculation in " << m_routingCalcInterval);
171  m_scheduler.schedule(m_routingCalcInterval, [this] { calculate(); });
172  m_isRouteCalculationScheduled = true;
173  }
174 }
175 
176 static bool
177 routingTableEntryCompare(RoutingTableEntry& rte, ndn::Name& destRouter)
178 {
179  return rte.getDestination() == destRouter;
180 }
181 
182 void
183 RoutingTable::addNextHop(const ndn::Name& destRouter, NextHop& nh)
184 {
185  NLSR_LOG_DEBUG("Adding " << nh << " for destination: " << destRouter);
186 
187  RoutingTableEntry* rteChk = findRoutingTableEntry(destRouter);
188  if (rteChk == nullptr) {
189  RoutingTableEntry rte(destRouter);
190  rte.getNexthopList().addNextHop(nh);
191  m_rTable.push_back(rte);
192  }
193  else {
194  rteChk->getNexthopList().addNextHop(nh);
195  }
196  m_wire.reset();
197 }
198 
200 RoutingTable::findRoutingTableEntry(const ndn::Name& destRouter)
201 {
202  auto it = std::find_if(m_rTable.begin(), m_rTable.end(),
203  std::bind(&routingTableEntryCompare, _1, destRouter));
204  if (it != m_rTable.end()) {
205  return &(*it);
206  }
207  return nullptr;
208 }
209 
210 void
211 RoutingTable::addNextHopToDryTable(const ndn::Name& destRouter, NextHop& nh)
212 {
213  NLSR_LOG_DEBUG("Adding " << nh << " to dry table for destination: " << destRouter);
214 
215  auto it = std::find_if(m_dryTable.begin(), m_dryTable.end(),
216  std::bind(&routingTableEntryCompare, _1, destRouter));
217  if (it == m_dryTable.end()) {
218  RoutingTableEntry rte(destRouter);
219  rte.getNexthopList().addNextHop(nh);
220  m_dryTable.push_back(rte);
221  }
222  else {
223  it->getNexthopList().addNextHop(nh);
224  }
225  m_wire.reset();
226 }
227 
228 void
229 RoutingTable::clearRoutingTable()
230 {
231  m_rTable.clear();
232  m_wire.reset();
233 }
234 
235 void
236 RoutingTable::clearDryRoutingTable()
237 {
238  m_dryTable.clear();
239  m_wire.reset();
240 }
241 
242 template<ndn::encoding::Tag TAG>
243 size_t
244 RoutingTableStatus::wireEncode(ndn::EncodingImpl<TAG>& block) const
245 {
246  size_t totalLength = 0;
247 
248  for (auto it = m_dryTable.rbegin(); it != m_dryTable.rend(); ++it) {
249  totalLength += it->wireEncode(block);
250  }
251 
252  for (auto it = m_rTable.rbegin(); it != m_rTable.rend(); ++it) {
253  totalLength += it->wireEncode(block);
254  }
255 
256  totalLength += block.prependVarNumber(totalLength);
257  totalLength += block.prependVarNumber(nlsr::tlv::RoutingTable);
258 
259  return totalLength;
260 }
261 
263 
264 const ndn::Block&
266 {
267  if (m_wire.hasWire()) {
268  return m_wire;
269  }
270 
271  ndn::EncodingEstimator estimator;
272  size_t estimatedSize = wireEncode(estimator);
273 
274  ndn::EncodingBuffer buffer(estimatedSize, 0);
275  wireEncode(buffer);
276 
277  m_wire = buffer.block();
278 
279  return m_wire;
280 }
281 
282 void
283 RoutingTableStatus::wireDecode(const ndn::Block& wire)
284 {
285  m_rTable.clear();
286 
287  m_wire = wire;
288 
289  if (m_wire.type() != nlsr::tlv::RoutingTable) {
290  NDN_THROW(Error("RoutingTable", m_wire.type()));
291  }
292 
293  m_wire.parse();
294  auto val = m_wire.elements_begin();
295 
296  std::set<ndn::Name> destinations;
297  for (; val != m_wire.elements_end() && val->type() == nlsr::tlv::RoutingTableEntry; ++val) {
298  auto entry = RoutingTableEntry(*val);
299 
300  if (destinations.emplace(entry.getDestination()).second) {
301  m_rTable.push_back(entry);
302  }
303  else {
304  // If destination already exists then this is the start of dry HR table
305  m_dryTable.push_back(entry);
306  }
307  }
308 
309  if (val != m_wire.elements_end()) {
310  NDN_THROW(Error("Unrecognized TLV of type " + ndn::to_string(val->type()) + " in RoutingTable"));
311  }
312 }
313 
314 std::ostream&
315 operator<<(std::ostream& os, const RoutingTableStatus& rts)
316 {
317  os << "Routing Table:\n";
318  for (const auto& rte : rts.getRoutingTableEntry()) {
319  os << rte;
320  }
321 
322  if (!rts.getDryRoutingTableEntry().empty()) {
323  os << "Dry-Run Hyperbolic Routing Table:\n";
324  for (const auto& rte : rts.getDryRoutingTableEntry()) {
325  os << rte;
326  }
327  }
328  return os;
329 }
330 
331 } // namespace nlsr
A class to house all the configuration parameters for NLSR.
const ndn::Name & getRouterPrefix() const
AdjacencyList & getAdjacencyList()
std::pair< LsaContainer::index< Lsdb::byType >::type::iterator, LsaContainer::index< Lsdb::byType >::type::iterator > getLsdbIterator() const
Definition: lsdb.hpp:173
AfterLsdbModified onLsdbModified
Definition: lsdb.hpp:339
void writeLog() const
Definition: lsdb.cpp:143
bool getIsBuildAdjLsaScheduled() const
Definition: lsdb.hpp:103
static NameMap createFromCoordinateLsdb(IteratorType first, IteratorType last)
Create a NameMap populated with router names in Coordinate LSAs.
Definition: name-map.hpp:82
static NameMap createFromAdjLsdb(IteratorType first, IteratorType last)
Create a NameMap populated with router names in Adjacency LSAs.
Definition: name-map.hpp:58
Data abstraction for Nexthop.
Definition: nexthop.hpp:47
void addNextHop(const NextHop &nh)
Adds a next hop to the list.
Data abstraction for RouteTableInfo.
const ndn::Name & getDestination() const
NexthopList & getNexthopList()
void calculate()
Calculates a list of next hops for each router in the network.
void scheduleRoutingTableCalculation()
Schedules a calculation event in the event scheduler only if one isn't already scheduled.
AfterRoutingChange afterRoutingChange
void addNextHopToDryTable(const ndn::Name &destRouter, NextHop &nh)
Adds a next hop to a routing table entry in a dry run scenario.
void addNextHop(const ndn::Name &destRouter, NextHop &nh)
Adds a next hop to a routing table entry.
RoutingTable(ndn::Scheduler &scheduler, Lsdb &lsdb, ConfParameter &confParam)
RoutingTableEntry * findRoutingTableEntry(const ndn::Name &destRouter)
Data abstraction for routing table status.
const std::list< RoutingTableEntry > & getDryRoutingTableEntry() const
std::list< RoutingTableEntry > m_dryTable
std::list< RoutingTableEntry > m_rTable
const ndn::Block & wireEncode() const
const std::list< RoutingTableEntry > & getRoutingTableEntry() const
Copyright (c) 2014-2018, The University of Memphis, Regents of the University of California.
#define NLSR_LOG_DEBUG(x)
Definition: logger.hpp:38
#define INIT_LOGGER(name)
Definition: logger.hpp:35
#define NLSR_LOG_TRACE(x)
Definition: logger.hpp:37
@ RoutingTable
Definition: tlv-nlsr.hpp:47
@ CoordinateLsa
Definition: tlv-nlsr.hpp:37
@ RoutingTableEntry
Definition: tlv-nlsr.hpp:48
Copyright (c) 2014-2020, The University of Memphis, Regents of the University of California.
std::ostream & operator<<(std::ostream &os, const Adjacent &adjacent)
Definition: adjacent.cpp:176
static bool routingTableEntryCompare(RoutingTableEntry &rte, ndn::Name &destRouter)
void calculateHyperbolicRoutingPath(NameMap &map, RoutingTable &rt, Lsdb &lsdb, AdjacencyList &adjacencies, ndn::Name thisRouterName, bool isDryRun)
@ HYPERBOLIC_STATE_ON
@ HYPERBOLIC_STATE_DRY_RUN
@ HYPERBOLIC_STATE_OFF
LsdbUpdate
Definition: lsdb.hpp:53
NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Adjacent)
void calculateLinkStateRoutingPath(NameMap &map, RoutingTable &rt, ConfParameter &confParam, const Lsdb &lsdb)