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-2022, 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 "nlsr.hpp"
23 #include "map.hpp"
24 #include "conf-parameter.hpp"
26 #include "routing-table-entry.hpp"
27 #include "logger.hpp"
28 #include "tlv-nlsr.hpp"
29 
30 namespace nlsr {
31 
32 INIT_LOGGER(route.RoutingTable);
33 
34 RoutingTable::RoutingTable(ndn::Scheduler& scheduler, Lsdb& lsdb, ConfParameter& confParam)
35  : m_scheduler(scheduler)
36  , m_lsdb(lsdb)
37  , m_routingCalcInterval{confParam.getRoutingCalcInterval()}
38  , m_isRoutingTableCalculating(false)
39  , m_isRouteCalculationScheduled(false)
40  , m_confParam(confParam)
41  , m_hyperbolicState(m_confParam.getHyperbolicState())
42 {
43  m_afterLsdbModified = lsdb.onLsdbModified.connect(
44  [this] (std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
45  const auto& namesToAdd, const auto& namesToRemove) {
46  auto type = lsa->getType();
47  bool updateForOwnAdjacencyLsa = lsa->getOriginRouter() == m_confParam.getRouterPrefix() &&
48  type == Lsa::Type::ADJACENCY;
49  bool scheduleCalculation = false;
50 
51  if (updateType == LsdbUpdate::REMOVED && updateForOwnAdjacencyLsa) {
52  // If own Adjacency LSA is removed then we have no ACTIVE neighbors.
53  // (Own Coordinate LSA is never removed. But routing table calculation is scheduled
54  // in HelloProtocol. The routing table calculator for HR takes into account
55  // the INACTIVE status of the link).
56  NLSR_LOG_DEBUG("No Adj LSA of router itself, routing table can not be calculated :(");
57  clearRoutingTable();
58  clearDryRoutingTable();
59  NLSR_LOG_DEBUG("Calling Update NPT With new Route");
61  NLSR_LOG_DEBUG(*this);
62  m_ownAdjLsaExist = false;
63  }
64 
65  if (updateType == LsdbUpdate::INSTALLED && updateForOwnAdjacencyLsa) {
66  m_ownAdjLsaExist = true;
67  }
68 
69  // Don;t do anything on removal, wait for HelloProtocol to confirm and then react
70  if (updateType == LsdbUpdate::INSTALLED || updateType == LsdbUpdate::UPDATED) {
71  if ((type == Lsa::Type::ADJACENCY && m_hyperbolicState != HYPERBOLIC_STATE_ON) ||
72  (type == Lsa::Type::COORDINATE && m_hyperbolicState != HYPERBOLIC_STATE_OFF)) {
73  scheduleCalculation = true;
74  }
75  }
76 
77  if (scheduleCalculation) {
79  }
80  }
81  );
82 }
83 
84 void
86 {
87  m_lsdb.writeLog();
88  NLSR_LOG_TRACE("Calculating routing table");
89 
90  if (m_isRoutingTableCalculating == false) {
91  m_isRoutingTableCalculating = true;
92 
93  if (m_hyperbolicState == HYPERBOLIC_STATE_OFF) {
94  calculateLsRoutingTable();
95  }
96  else if (m_hyperbolicState == HYPERBOLIC_STATE_DRY_RUN) {
97  calculateLsRoutingTable();
98  calculateHypRoutingTable(true);
99  }
100  else if (m_hyperbolicState == HYPERBOLIC_STATE_ON) {
101  calculateHypRoutingTable(false);
102  }
103 
104  m_isRouteCalculationScheduled = false;
105  m_isRoutingTableCalculating = false;
106  }
107  else {
109  }
110 }
111 
112 void
113 RoutingTable::calculateLsRoutingTable()
114 {
115  NLSR_LOG_TRACE("CalculateLsRoutingTable Called");
116 
117  if (m_lsdb.getIsBuildAdjLsaScheduled()) {
118  NLSR_LOG_DEBUG("Adjacency build is scheduled, routing table can not be calculated :(");
119  return;
120  }
121 
122  // We only check this in LS since we never remove our own Coordinate LSA,
123  // whereas we remove our own Adjacency LSA if we don't have any neighbors
124  if (!m_ownAdjLsaExist) {
125  return;
126  }
127 
128  clearRoutingTable();
129 
130  Map map;
131  auto lsaRange = m_lsdb.getLsdbIterator<AdjLsa>();
132  map.createFromAdjLsdb(lsaRange.first, lsaRange.second);
133  map.writeLog();
134 
135  size_t nRouters = map.getMapSize();
136 
137  LinkStateRoutingTableCalculator calculator(nRouters);
138 
139  calculator.calculatePath(map, *this, m_confParam, m_lsdb);
140 
141  NLSR_LOG_DEBUG("Calling Update NPT With new Route");
143  NLSR_LOG_DEBUG(*this);
144 }
145 
146 void
147 RoutingTable::calculateHypRoutingTable(bool isDryRun)
148 {
149  if (isDryRun) {
150  clearDryRoutingTable();
151  }
152  else {
153  clearRoutingTable();
154  }
155 
156  Map map;
157  auto lsaRange = m_lsdb.getLsdbIterator<CoordinateLsa>();
158  map.createFromCoordinateLsdb(lsaRange.first, lsaRange.second);
159  map.writeLog();
160 
161  size_t nRouters = map.getMapSize();
162 
163  HyperbolicRoutingCalculator calculator(nRouters, isDryRun, m_confParam.getRouterPrefix());
164 
165  calculator.calculatePath(map, *this, m_lsdb, m_confParam.getAdjacencyList());
166 
167  if (!isDryRun) {
168  NLSR_LOG_DEBUG("Calling Update NPT With new Route");
170  NLSR_LOG_DEBUG(*this);
171  }
172 }
173 
174 void
176 {
177  if (!m_isRouteCalculationScheduled) {
178  NLSR_LOG_DEBUG("Scheduling routing table calculation in " << m_routingCalcInterval);
179  m_scheduler.schedule(m_routingCalcInterval, [this] { calculate(); });
180  m_isRouteCalculationScheduled = true;
181  }
182 }
183 
184 static bool
185 routingTableEntryCompare(RoutingTableEntry& rte, ndn::Name& destRouter)
186 {
187  return rte.getDestination() == destRouter;
188 }
189 
190 void
191 RoutingTable::addNextHop(const ndn::Name& destRouter, NextHop& nh)
192 {
193  NLSR_LOG_DEBUG("Adding " << nh << " for destination: " << destRouter);
194 
195  RoutingTableEntry* rteChk = findRoutingTableEntry(destRouter);
196  if (rteChk == nullptr) {
197  RoutingTableEntry rte(destRouter);
198  rte.getNexthopList().addNextHop(nh);
199  m_rTable.push_back(rte);
200  }
201  else {
202  rteChk->getNexthopList().addNextHop(nh);
203  }
204  m_wire.reset();
205 }
206 
208 RoutingTable::findRoutingTableEntry(const ndn::Name& destRouter)
209 {
210  auto it = std::find_if(m_rTable.begin(), m_rTable.end(),
211  std::bind(&routingTableEntryCompare, _1, destRouter));
212  if (it != m_rTable.end()) {
213  return &(*it);
214  }
215  return nullptr;
216 }
217 
218 void
219 RoutingTable::addNextHopToDryTable(const ndn::Name& destRouter, NextHop& nh)
220 {
221  NLSR_LOG_DEBUG("Adding " << nh << " to dry table for destination: " << destRouter);
222 
223  auto it = std::find_if(m_dryTable.begin(), m_dryTable.end(),
224  std::bind(&routingTableEntryCompare, _1, destRouter));
225  if (it == m_dryTable.end()) {
226  RoutingTableEntry rte(destRouter);
227  rte.getNexthopList().addNextHop(nh);
228  m_dryTable.push_back(rte);
229  }
230  else {
231  it->getNexthopList().addNextHop(nh);
232  }
233  m_wire.reset();
234 }
235 
236 void
237 RoutingTable::clearRoutingTable()
238 {
239  m_rTable.clear();
240  m_wire.reset();
241 }
242 
243 void
244 RoutingTable::clearDryRoutingTable()
245 {
246  m_dryTable.clear();
247  m_wire.reset();
248 }
249 
250 template<ndn::encoding::Tag TAG>
251 size_t
252 RoutingTableStatus::wireEncode(ndn::EncodingImpl<TAG>& block) const
253 {
254  size_t totalLength = 0;
255 
256  for (auto it = m_dryTable.rbegin(); it != m_dryTable.rend(); ++it) {
257  totalLength += it->wireEncode(block);
258  }
259 
260  for (auto it = m_rTable.rbegin(); it != m_rTable.rend(); ++it) {
261  totalLength += it->wireEncode(block);
262  }
263 
264  totalLength += block.prependVarNumber(totalLength);
265  totalLength += block.prependVarNumber(nlsr::tlv::RoutingTable);
266 
267  return totalLength;
268 }
269 
271 
272 const ndn::Block&
274 {
275  if (m_wire.hasWire()) {
276  return m_wire;
277  }
278 
279  ndn::EncodingEstimator estimator;
280  size_t estimatedSize = wireEncode(estimator);
281 
282  ndn::EncodingBuffer buffer(estimatedSize, 0);
283  wireEncode(buffer);
284 
285  m_wire = buffer.block();
286 
287  return m_wire;
288 }
289 
290 void
291 RoutingTableStatus::wireDecode(const ndn::Block& wire)
292 {
293  m_rTable.clear();
294 
295  m_wire = wire;
296 
297  if (m_wire.type() != nlsr::tlv::RoutingTable) {
298  NDN_THROW(Error("RoutingTable", m_wire.type()));
299  }
300 
301  m_wire.parse();
302  auto val = m_wire.elements_begin();
303 
304  std::set<ndn::Name> destinations;
305  for (; val != m_wire.elements_end() && val->type() == nlsr::tlv::RoutingTableEntry; ++val) {
306  auto entry = RoutingTableEntry(*val);
307 
308  if (destinations.emplace(entry.getDestination()).second) {
309  m_rTable.push_back(entry);
310  }
311  else {
312  // If destination already exists then this is the start of dry HR table
313  m_dryTable.push_back(entry);
314  }
315  }
316 
317  if (val != m_wire.elements_end()) {
318  NDN_THROW(Error("Unrecognized TLV of type " + ndn::to_string(val->type()) + " in RoutingTable"));
319  }
320 }
321 
322 std::ostream&
323 operator<<(std::ostream& os, const RoutingTableStatus& rts)
324 {
325  os << "Routing Table:\n";
326  for (const auto& rte : rts.getRoutingTableEntry()) {
327  os << rte;
328  }
329 
330  if (!rts.getDryRoutingTableEntry().empty()) {
331  os << "Dry-Run Hyperbolic Routing Table:\n";
332  for (const auto& rte : rts.getDryRoutingTableEntry()) {
333  os << rte;
334  }
335  }
336  return os;
337 }
338 
339 } // 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:162
AfterLsdbModified onLsdbModified
Definition: lsdb.hpp:328
void writeLog() const
Definition: lsdb.cpp:136
bool getIsBuildAdjLsaScheduled() const
Definition: lsdb.hpp:103
Data abstraction for Nexthop.
Definition: nexthop.hpp:44
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)
@ HYPERBOLIC_STATE_ON
@ HYPERBOLIC_STATE_DRY_RUN
@ HYPERBOLIC_STATE_OFF
LsdbUpdate
Definition: lsdb.hpp:53
NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Adjacent)