blob: b5a5f695ff15089f19cc513c1df92d9782e90f3c [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/*
Junxiao Shid6922b52024-01-14 19:50:34 +00003 * Copyright (c) 2014-2024, 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"
Junxiao Shi4eb4eae2024-02-14 12:36:57 +000022#include "name-map.hpp"
Junxiao Shiaead5882024-02-21 12:32:02 +000023#include "routing-calculator.hpp"
akmhoque53353462014-04-22 08:43:45 -050024#include "routing-table-entry.hpp"
Junxiao Shiaead5882024-02-21 12:32:02 +000025
26#include "conf-parameter.hpp"
akmhoque674b0b12014-05-20 14:33:28 -050027#include "logger.hpp"
Junxiao Shiaead5882024-02-21 12:32:02 +000028#include "nlsr.hpp"
Ashlesh Gawande0421bc62020-05-08 20:42:19 -070029#include "tlv-nlsr.hpp"
akmhoque53353462014-04-22 08:43:45 -050030
31namespace nlsr {
32
dmcoomescf8d0ed2017-02-21 11:39:01 -060033INIT_LOGGER(route.RoutingTable);
akmhoque674b0b12014-05-20 14:33:28 -050034
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070035RoutingTable::RoutingTable(ndn::Scheduler& scheduler, Lsdb& lsdb, ConfParameter& confParam)
36 : m_scheduler(scheduler)
Ashlesh Gawande85998a12017-12-07 22:22:13 -060037 , m_lsdb(lsdb)
Ashlesh Gawande85998a12017-12-07 22:22:13 -060038 , m_routingCalcInterval{confParam.getRoutingCalcInterval()}
39 , m_isRoutingTableCalculating(false)
40 , m_isRouteCalculationScheduled(false)
41 , m_confParam(confParam)
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070042 , m_hyperbolicState(m_confParam.getHyperbolicState())
Nick Gordonb7b58392017-08-17 16:29:21 -050043{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070044 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");
61 afterRoutingChange(m_rTable);
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) {
79 scheduleRoutingTableCalculation();
80 }
81 }
82 );
Nick Gordonb7b58392017-08-17 16:29:21 -050083}
84
akmhoque53353462014-04-22 08:43:45 -050085void
Ashlesh Gawande85998a12017-12-07 22:22:13 -060086RoutingTable::calculate()
akmhoque53353462014-04-22 08:43:45 -050087{
Ashlesh Gawande57a87172020-05-09 19:47:06 -070088 m_lsdb.writeLog();
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070089 NLSR_LOG_TRACE("Calculating routing table");
90
Ashlesh Gawande85998a12017-12-07 22:22:13 -060091 if (m_isRoutingTableCalculating == false) {
Ashlesh Gawande85998a12017-12-07 22:22:13 -060092 m_isRoutingTableCalculating = true;
Nick Gordone8e03ac2016-07-07 14:24:38 -050093
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070094 if (m_hyperbolicState == HYPERBOLIC_STATE_OFF) {
95 calculateLsRoutingTable();
akmhoque53353462014-04-22 08:43:45 -050096 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -070097 else if (m_hyperbolicState == HYPERBOLIC_STATE_DRY_RUN) {
98 calculateLsRoutingTable();
99 calculateHypRoutingTable(true);
akmhoque53353462014-04-22 08:43:45 -0500100 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700101 else if (m_hyperbolicState == HYPERBOLIC_STATE_ON) {
102 calculateHypRoutingTable(false);
103 }
104
105 m_isRouteCalculationScheduled = false;
106 m_isRoutingTableCalculating = false;
akmhoque53353462014-04-22 08:43:45 -0500107 }
akmhoque157b0a42014-05-13 00:26:37 -0500108 else {
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600109 scheduleRoutingTableCalculation();
akmhoque53353462014-04-22 08:43:45 -0500110 }
111}
112
akmhoque53353462014-04-22 08:43:45 -0500113void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600114RoutingTable::calculateLsRoutingTable()
akmhoque53353462014-04-22 08:43:45 -0500115{
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700116 NLSR_LOG_TRACE("CalculateLsRoutingTable Called");
Vince Lehman9a709032014-09-13 16:28:07 -0500117
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700118 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
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700131 auto lsaRange = m_lsdb.getLsdbIterator<AdjLsa>();
Junxiao Shi4eb4eae2024-02-14 12:36:57 +0000132 auto map = NameMap::createFromAdjLsdb(lsaRange.first, lsaRange.second);
Junxiao Shid6922b52024-01-14 19:50:34 +0000133 NLSR_LOG_DEBUG(map);
Vince Lehman9a709032014-09-13 16:28:07 -0500134
Junxiao Shiaead5882024-02-21 12:32:02 +0000135 calculateLinkStateRoutingPath(map, *this, m_confParam, m_lsdb);
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700136
137 NLSR_LOG_DEBUG("Calling Update NPT With new Route");
138 afterRoutingChange(m_rTable);
139 NLSR_LOG_DEBUG(*this);
akmhoque53353462014-04-22 08:43:45 -0500140}
141
142void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600143RoutingTable::calculateHypRoutingTable(bool isDryRun)
akmhoque53353462014-04-22 08:43:45 -0500144{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700145 if (isDryRun) {
146 clearDryRoutingTable();
147 }
148 else {
149 clearRoutingTable();
150 }
151
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700152 auto lsaRange = m_lsdb.getLsdbIterator<CoordinateLsa>();
Junxiao Shi4eb4eae2024-02-14 12:36:57 +0000153 auto map = NameMap::createFromCoordinateLsdb(lsaRange.first, lsaRange.second);
Junxiao Shid6922b52024-01-14 19:50:34 +0000154 NLSR_LOG_DEBUG(map);
Vince Lehman9a709032014-09-13 16:28:07 -0500155
Junxiao Shiaead5882024-02-21 12:32:02 +0000156 calculateHyperbolicRoutingPath(map, *this, m_lsdb, m_confParam.getAdjacencyList(),
157 m_confParam.getRouterPrefix(), isDryRun);
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700158
159 if (!isDryRun) {
160 NLSR_LOG_DEBUG("Calling Update NPT With new Route");
161 afterRoutingChange(m_rTable);
162 NLSR_LOG_DEBUG(*this);
163 }
akmhoque53353462014-04-22 08:43:45 -0500164}
165
166void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600167RoutingTable::scheduleRoutingTableCalculation()
akmhoque53353462014-04-22 08:43:45 -0500168{
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400169 if (!m_isRouteCalculationScheduled) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500170 NLSR_LOG_DEBUG("Scheduling routing table calculation in " << m_routingCalcInterval);
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400171 m_scheduler.schedule(m_routingCalcInterval, [this] { calculate(); });
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600172 m_isRouteCalculationScheduled = true;
akmhoque53353462014-04-22 08:43:45 -0500173 }
174}
175
176static bool
akmhoque31d1d4b2014-05-05 22:08:14 -0500177routingTableEntryCompare(RoutingTableEntry& rte, ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -0500178{
179 return rte.getDestination() == destRouter;
180}
181
akmhoque53353462014-04-22 08:43:45 -0500182void
akmhoque31d1d4b2014-05-05 22:08:14 -0500183RoutingTable::addNextHop(const ndn::Name& destRouter, NextHop& nh)
akmhoque53353462014-04-22 08:43:45 -0500184{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500185 NLSR_LOG_DEBUG("Adding " << nh << " for destination: " << destRouter);
Vince Lehman9a709032014-09-13 16:28:07 -0500186
akmhoqueb6450b12014-04-24 00:01:03 -0500187 RoutingTableEntry* rteChk = findRoutingTableEntry(destRouter);
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400188 if (rteChk == nullptr) {
akmhoque53353462014-04-22 08:43:45 -0500189 RoutingTableEntry rte(destRouter);
akmhoquefdbddb12014-05-02 18:35:19 -0500190 rte.getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500191 m_rTable.push_back(rte);
192 }
akmhoque157b0a42014-05-13 00:26:37 -0500193 else {
akmhoquefdbddb12014-05-02 18:35:19 -0500194 rteChk->getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500195 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700196 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500197}
198
akmhoqueb6450b12014-04-24 00:01:03 -0500199RoutingTableEntry*
akmhoque31d1d4b2014-05-05 22:08:14 -0500200RoutingTable::findRoutingTableEntry(const ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -0500201{
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400202 auto it = std::find_if(m_rTable.begin(), m_rTable.end(),
203 std::bind(&routingTableEntryCompare, _1, destRouter));
akmhoque157b0a42014-05-13 00:26:37 -0500204 if (it != m_rTable.end()) {
akmhoqueb6450b12014-04-24 00:01:03 -0500205 return &(*it);
akmhoque53353462014-04-22 08:43:45 -0500206 }
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400207 return nullptr;
akmhoque53353462014-04-22 08:43:45 -0500208}
209
210void
akmhoque31d1d4b2014-05-05 22:08:14 -0500211RoutingTable::addNextHopToDryTable(const ndn::Name& destRouter, NextHop& nh)
akmhoque53353462014-04-22 08:43:45 -0500212{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500213 NLSR_LOG_DEBUG("Adding " << nh << " to dry table for destination: " << destRouter);
Vince Lehman9a709032014-09-13 16:28:07 -0500214
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400215 auto it = std::find_if(m_dryTable.begin(), m_dryTable.end(),
216 std::bind(&routingTableEntryCompare, _1, destRouter));
akmhoque157b0a42014-05-13 00:26:37 -0500217 if (it == m_dryTable.end()) {
akmhoque53353462014-04-22 08:43:45 -0500218 RoutingTableEntry rte(destRouter);
akmhoquefdbddb12014-05-02 18:35:19 -0500219 rte.getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500220 m_dryTable.push_back(rte);
221 }
akmhoque157b0a42014-05-13 00:26:37 -0500222 else {
Davide Pesaventoaf7a2112019-03-19 14:55:20 -0400223 it->getNexthopList().addNextHop(nh);
akmhoque53353462014-04-22 08:43:45 -0500224 }
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700225 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500226}
227
228void
akmhoque53353462014-04-22 08:43:45 -0500229RoutingTable::clearRoutingTable()
230{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700231 m_rTable.clear();
232 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500233}
234
235void
236RoutingTable::clearDryRoutingTable()
237{
Ashlesh Gawande5d93aa52020-06-13 18:57:45 -0700238 m_dryTable.clear();
239 m_wire.reset();
akmhoque53353462014-04-22 08:43:45 -0500240}
241
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700242template<ndn::encoding::Tag TAG>
243size_t
244RoutingTableStatus::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);
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400257 totalLength += block.prependVarNumber(nlsr::tlv::RoutingTable);
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700258
259 return totalLength;
260}
261
262NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(RoutingTableStatus);
263
264const ndn::Block&
265RoutingTableStatus::wireEncode() const
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
282void
283RoutingTableStatus::wireDecode(const ndn::Block& wire)
284{
285 m_rTable.clear();
286
287 m_wire = wire;
288
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400289 if (m_wire.type() != nlsr::tlv::RoutingTable) {
Davide Pesaventod90338d2021-01-07 17:50:05 -0500290 NDN_THROW(Error("RoutingTable", m_wire.type()));
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700291 }
292
293 m_wire.parse();
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700294 auto val = m_wire.elements_begin();
295
296 std::set<ndn::Name> destinations;
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400297 for (; val != m_wire.elements_end() && val->type() == nlsr::tlv::RoutingTableEntry; ++val) {
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700298 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()) {
Davide Pesaventod90338d2021-01-07 17:50:05 -0500310 NDN_THROW(Error("Unrecognized TLV of type " + ndn::to_string(val->type()) + " in RoutingTable"));
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700311 }
312}
313
314std::ostream&
315operator<<(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
Nick Gordonfad8e252016-08-11 14:21:38 -0500331} // namespace nlsr