blob: 7fd8a7ae46b8afa45d79f63c63e0ea7ef2c3444e [file] [log] [blame]
akmhoque3d06e792014-05-27 16:23:20 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoaf7a2112019-03-19 14:55:20 -04002/*
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -04003 * Copyright (c) 2014-2022, The University of Memphis,
Nick Gordonf8b5bcd2016-08-11 15:06:50 -05004 * Regents of the University of California
akmhoque3d06e792014-05-27 16:23:20 -05005 *
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/>.
Ashlesh Gawande0421bc62020-05-08 20:42:19 -070019 */
Davide Pesaventoa08dc3f2018-05-24 00:40:28 -040020
akmhoque53353462014-04-22 08:43:45 -050021#include "routing-table.hpp"
22#include "nlsr.hpp"
23#include "map.hpp"
akmhoque157b0a42014-05-13 00:26:37 -050024#include "conf-parameter.hpp"
akmhoque53353462014-04-22 08:43:45 -050025#include "routing-table-calculator.hpp"
26#include "routing-table-entry.hpp"
akmhoque674b0b12014-05-20 14:33:28 -050027#include "logger.hpp"
Ashlesh Gawande0421bc62020-05-08 20:42:19 -070028#include "tlv-nlsr.hpp"
akmhoque53353462014-04-22 08:43:45 -050029
30namespace nlsr {
31
dmcoomescf8d0ed2017-02-21 11:39:01 -060032INIT_LOGGER(route.RoutingTable);
akmhoque674b0b12014-05-20 14:33:28 -050033
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070034RoutingTable::RoutingTable(ndn::Scheduler& scheduler, Lsdb& lsdb, ConfParameter& confParam)
35 : m_scheduler(scheduler)
Ashlesh Gawande85998a12017-12-07 22:22:13 -060036 , m_lsdb(lsdb)
Ashlesh Gawande85998a12017-12-07 22:22:13 -060037 , m_routingCalcInterval{confParam.getRoutingCalcInterval()}
38 , m_isRoutingTableCalculating(false)
39 , m_isRouteCalculationScheduled(false)
40 , m_confParam(confParam)
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070041 , m_hyperbolicState(m_confParam.getHyperbolicState())
Nick Gordonb7b58392017-08-17 16:29:21 -050042{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070043 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");
60 afterRoutingChange(m_rTable);
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) {
78 scheduleRoutingTableCalculation();
79 }
80 }
81 );
Nick Gordonb7b58392017-08-17 16:29:21 -050082}
83
akmhoque53353462014-04-22 08:43:45 -050084void
Ashlesh Gawande85998a12017-12-07 22:22:13 -060085RoutingTable::calculate()
akmhoque53353462014-04-22 08:43:45 -050086{
Ashlesh Gawande57a87172020-05-09 19:47:06 -070087 m_lsdb.writeLog();
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070088 NLSR_LOG_TRACE("Calculating routing table");
89
Ashlesh Gawande85998a12017-12-07 22:22:13 -060090 if (m_isRoutingTableCalculating == false) {
Ashlesh Gawande85998a12017-12-07 22:22:13 -060091 m_isRoutingTableCalculating = true;
Nick Gordone8e03ac2016-07-07 14:24:38 -050092
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070093 if (m_hyperbolicState == HYPERBOLIC_STATE_OFF) {
94 calculateLsRoutingTable();
akmhoque53353462014-04-22 08:43:45 -050095 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070096 else if (m_hyperbolicState == HYPERBOLIC_STATE_DRY_RUN) {
97 calculateLsRoutingTable();
98 calculateHypRoutingTable(true);
akmhoque53353462014-04-22 08:43:45 -050099 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700100 else if (m_hyperbolicState == HYPERBOLIC_STATE_ON) {
101 calculateHypRoutingTable(false);
102 }
103
104 m_isRouteCalculationScheduled = false;
105 m_isRoutingTableCalculating = false;
akmhoque53353462014-04-22 08:43:45 -0500106 }
akmhoque157b0a42014-05-13 00:26:37 -0500107 else {
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600108 scheduleRoutingTableCalculation();
akmhoque53353462014-04-22 08:43:45 -0500109 }
110}
111
akmhoque53353462014-04-22 08:43:45 -0500112void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600113RoutingTable::calculateLsRoutingTable()
akmhoque53353462014-04-22 08:43:45 -0500114{
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700115 NLSR_LOG_TRACE("CalculateLsRoutingTable Called");
Vince Lehman9a709032014-09-13 16:28:07 -0500116
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700117 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
Vince Lehman9a709032014-09-13 16:28:07 -0500130 Map map;
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700131 auto lsaRange = m_lsdb.getLsdbIterator<AdjLsa>();
132 map.createFromAdjLsdb(lsaRange.first, lsaRange.second);
Vince Lehman9a709032014-09-13 16:28:07 -0500133 map.writeLog();
134
135 size_t nRouters = map.getMapSize();
136
137 LinkStateRoutingTableCalculator calculator(nRouters);
138
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700139 calculator.calculatePath(map, *this, m_confParam, m_lsdb);
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700140
141 NLSR_LOG_DEBUG("Calling Update NPT With new Route");
142 afterRoutingChange(m_rTable);
143 NLSR_LOG_DEBUG(*this);
akmhoque53353462014-04-22 08:43:45 -0500144}
145
146void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600147RoutingTable::calculateHypRoutingTable(bool isDryRun)
akmhoque53353462014-04-22 08:43:45 -0500148{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700149 if (isDryRun) {
150 clearDryRoutingTable();
151 }
152 else {
153 clearRoutingTable();
154 }
155
Vince Lehman9a709032014-09-13 16:28:07 -0500156 Map map;
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700157 auto lsaRange = m_lsdb.getLsdbIterator<CoordinateLsa>();
158 map.createFromCoordinateLsdb(lsaRange.first, lsaRange.second);
Vince Lehman9a709032014-09-13 16:28:07 -0500159 map.writeLog();
160
161 size_t nRouters = map.getMapSize();
162
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600163 HyperbolicRoutingCalculator calculator(nRouters, isDryRun, m_confParam.getRouterPrefix());
Vince Lehman9a709032014-09-13 16:28:07 -0500164
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600165 calculator.calculatePath(map, *this, m_lsdb, m_confParam.getAdjacencyList());
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700166
167 if (!isDryRun) {
168 NLSR_LOG_DEBUG("Calling Update NPT With new Route");
169 afterRoutingChange(m_rTable);
170 NLSR_LOG_DEBUG(*this);
171 }
akmhoque53353462014-04-22 08:43:45 -0500172}
173
174void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600175RoutingTable::scheduleRoutingTableCalculation()
akmhoque53353462014-04-22 08:43:45 -0500176{
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400177 if (!m_isRouteCalculationScheduled) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500178 NLSR_LOG_DEBUG("Scheduling routing table calculation in " << m_routingCalcInterval);
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400179 m_scheduler.schedule(m_routingCalcInterval, [this] { calculate(); });
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600180 m_isRouteCalculationScheduled = true;
akmhoque53353462014-04-22 08:43:45 -0500181 }
182}
183
184static bool
akmhoque31d1d4b2014-05-05 22:08:14 -0500185routingTableEntryCompare(RoutingTableEntry& rte, ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -0500186{
187 return rte.getDestination() == destRouter;
188}
189
akmhoque53353462014-04-22 08:43:45 -0500190void
akmhoque31d1d4b2014-05-05 22:08:14 -0500191RoutingTable::addNextHop(const ndn::Name& destRouter, NextHop& nh)
akmhoque53353462014-04-22 08:43:45 -0500192{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500193 NLSR_LOG_DEBUG("Adding " << nh << " for destination: " << destRouter);
Vince Lehman9a709032014-09-13 16:28:07 -0500194
akmhoqueb6450b12014-04-24 00:01:03 -0500195 RoutingTableEntry* rteChk = findRoutingTableEntry(destRouter);
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400196 if (rteChk == nullptr) {
akmhoque53353462014-04-22 08:43:45 -0500197 RoutingTableEntry rte(destRouter);
akmhoquefdbddb12014-05-02 18:35:19 -0500198 rte.getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500199 m_rTable.push_back(rte);
200 }
akmhoque157b0a42014-05-13 00:26:37 -0500201 else {
akmhoquefdbddb12014-05-02 18:35:19 -0500202 rteChk->getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500203 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700204 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500205}
206
akmhoqueb6450b12014-04-24 00:01:03 -0500207RoutingTableEntry*
akmhoque31d1d4b2014-05-05 22:08:14 -0500208RoutingTable::findRoutingTableEntry(const ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -0500209{
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400210 auto it = std::find_if(m_rTable.begin(), m_rTable.end(),
211 std::bind(&routingTableEntryCompare, _1, destRouter));
akmhoque157b0a42014-05-13 00:26:37 -0500212 if (it != m_rTable.end()) {
akmhoqueb6450b12014-04-24 00:01:03 -0500213 return &(*it);
akmhoque53353462014-04-22 08:43:45 -0500214 }
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400215 return nullptr;
akmhoque53353462014-04-22 08:43:45 -0500216}
217
218void
akmhoque31d1d4b2014-05-05 22:08:14 -0500219RoutingTable::addNextHopToDryTable(const ndn::Name& destRouter, NextHop& nh)
akmhoque53353462014-04-22 08:43:45 -0500220{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500221 NLSR_LOG_DEBUG("Adding " << nh << " to dry table for destination: " << destRouter);
Vince Lehman9a709032014-09-13 16:28:07 -0500222
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400223 auto it = std::find_if(m_dryTable.begin(), m_dryTable.end(),
224 std::bind(&routingTableEntryCompare, _1, destRouter));
akmhoque157b0a42014-05-13 00:26:37 -0500225 if (it == m_dryTable.end()) {
akmhoque53353462014-04-22 08:43:45 -0500226 RoutingTableEntry rte(destRouter);
akmhoquefdbddb12014-05-02 18:35:19 -0500227 rte.getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500228 m_dryTable.push_back(rte);
229 }
akmhoque157b0a42014-05-13 00:26:37 -0500230 else {
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400231 it->getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500232 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700233 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500234}
235
236void
akmhoque53353462014-04-22 08:43:45 -0500237RoutingTable::clearRoutingTable()
238{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700239 m_rTable.clear();
240 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500241}
242
243void
244RoutingTable::clearDryRoutingTable()
245{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700246 m_dryTable.clear();
247 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500248}
249
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700250template<ndn::encoding::Tag TAG>
251size_t
252RoutingTableStatus::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);
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400265 totalLength += block.prependVarNumber(nlsr::tlv::RoutingTable);
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700266
267 return totalLength;
268}
269
270NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(RoutingTableStatus);
271
272const ndn::Block&
273RoutingTableStatus::wireEncode() const
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
290void
291RoutingTableStatus::wireDecode(const ndn::Block& wire)
292{
293 m_rTable.clear();
294
295 m_wire = wire;
296
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400297 if (m_wire.type() != nlsr::tlv::RoutingTable) {
Davide Pesaventod90338d2021-01-07 17:50:05 -0500298 NDN_THROW(Error("RoutingTable", m_wire.type()));
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700299 }
300
301 m_wire.parse();
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700302 auto val = m_wire.elements_begin();
303
304 std::set<ndn::Name> destinations;
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400305 for (; val != m_wire.elements_end() && val->type() == nlsr::tlv::RoutingTableEntry; ++val) {
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700306 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()) {
Davide Pesaventod90338d2021-01-07 17:50:05 -0500318 NDN_THROW(Error("Unrecognized TLV of type " + ndn::to_string(val->type()) + " in RoutingTable"));
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700319 }
320}
321
322std::ostream&
323operator<<(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
Nick Gordonfad8e252016-08-11 14:21:38 -0500339} // namespace nlsr