blob: 474604a3440112819c3a34300acdf9d53589d3d4 [file] [log] [blame]
akmhoque3d06e792014-05-27 16:23:20 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande57a87172020-05-09 19:47:06 -07002/*
Davide Pesavento658fd852023-05-10 22:15:03 -04003 * Copyright (c) 2014-2023, The University of Memphis,
Vince Lehman41b173e2015-05-07 14:13:26 -05004 * Regents of the University of California,
5 * Arizona Board of Regents.
akmhoque3d06e792014-05-27 16:23:20 -05006 *
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/>.
Ashlesh Gawande57a87172020-05-09 19:47:06 -070020 */
Nick Gordone40377d2017-08-11 15:10:02 -050021
akmhoque53353462014-04-22 08:43:45 -050022#include "routing-table-calculator.hpp"
Nick Gordone98480b2017-05-24 11:23:03 -050023#include "lsdb.hpp"
akmhoque53353462014-04-22 08:43:45 -050024#include "map.hpp"
akmhoque53353462014-04-22 08:43:45 -050025#include "nexthop.hpp"
26#include "nlsr.hpp"
akmhoque2f423352014-06-03 11:49:35 -050027#include "logger.hpp"
dulalsaurabd0816a32019-07-26 13:11:24 +000028#include "adjacent.hpp"
akmhoque53353462014-04-22 08:43:45 -050029
Nick Gordone98480b2017-05-24 11:23:03 -050030#include <cmath>
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -040031#include <boost/lexical_cast.hpp>
32#include <ndn-cxx/util/logger.hpp>
Vince Lehman9a709032014-09-13 16:28:07 -050033
akmhoque53353462014-04-22 08:43:45 -050034namespace nlsr {
35
dmcoomescf8d0ed2017-02-21 11:39:01 -060036INIT_LOGGER(route.RoutingTableCalculator);
akmhoque53353462014-04-22 08:43:45 -050037
Davide Pesavento658fd852023-05-10 22:15:03 -040038constexpr int EMPTY_PARENT = -12345;
39constexpr double INF_DISTANCE = 2147483647;
40constexpr int NO_MAPPING_NUM = -1;
41constexpr int NO_NEXT_HOP = -12345;
42constexpr double UNKNOWN_DISTANCE = -1.0;
43constexpr double UNKNOWN_RADIUS = -1.0;
dulalsaurabd0816a32019-07-26 13:11:24 +000044
akmhoque53353462014-04-22 08:43:45 -050045void
46RoutingTableCalculator::allocateAdjMatrix()
47{
Vince Lehman9a709032014-09-13 16:28:07 -050048 adjMatrix = new double*[m_nRouters];
49
50 for (size_t i = 0; i < m_nRouters; ++i) {
51 adjMatrix[i] = new double[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -050052 }
53}
54
55void
56RoutingTableCalculator::initMatrix()
57{
Vince Lehman9a709032014-09-13 16:28:07 -050058 for (size_t i = 0; i < m_nRouters; i++) {
59 for (size_t j = 0; j < m_nRouters; j++) {
dulalsaurabd0816a32019-07-26 13:11:24 +000060 adjMatrix[i][j] = Adjacent::NON_ADJACENT_COST;
akmhoque157b0a42014-05-13 00:26:37 -050061 }
akmhoque53353462014-04-22 08:43:45 -050062 }
63}
64
65void
Ashlesh Gawande57a87172020-05-09 19:47:06 -070066RoutingTableCalculator::makeAdjMatrix(const Lsdb& lsdb, Map& pMap)
akmhoque53353462014-04-22 08:43:45 -050067{
Nick G97e34942016-07-11 14:46:27 -050068 // For each LSA represented in the map
Ashlesh Gawande57a87172020-05-09 19:47:06 -070069 auto lsaRange = lsdb.getLsdbIterator<AdjLsa>();
70 for (auto lsaIt = lsaRange.first; lsaIt != lsaRange.second; ++lsaIt) {
71 auto adjLsa = std::static_pointer_cast<AdjLsa>(*lsaIt);
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -040072 auto row = pMap.getMappingNoByRouterName(adjLsa->getOriginRouter());
Vince Lehman9a709032014-09-13 16:28:07 -050073
Ashlesh Gawande57a87172020-05-09 19:47:06 -070074 std::list<Adjacent> adl = adjLsa->getAdl().getAdjList();
Nick G97e34942016-07-11 14:46:27 -050075 // For each adjacency represented in the LSA
Ashlesh Gawande85998a12017-12-07 22:22:13 -060076 for (const auto& adjacent : adl) {
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -040077 auto col = pMap.getMappingNoByRouterName(adjacent.getName());
Ashlesh Gawande85998a12017-12-07 22:22:13 -060078 double cost = adjacent.getLinkCost();
Vince Lehman9a709032014-09-13 16:28:07 -050079
Nick Gordone40377d2017-08-11 15:10:02 -050080 if (row && col && *row < static_cast<int32_t>(m_nRouters)
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -040081 && *col < static_cast<int32_t>(m_nRouters)) {
Nick Gordone40377d2017-08-11 15:10:02 -050082 adjMatrix[*row][*col] = cost;
akmhoque53353462014-04-22 08:43:45 -050083 }
84 }
85 }
Vince Lehman41b173e2015-05-07 14:13:26 -050086
Nick G97e34942016-07-11 14:46:27 -050087 // Links that do not have the same cost for both directions should
88 // have their costs corrected:
Vince Lehman41b173e2015-05-07 14:13:26 -050089 //
dulalsaurabd0816a32019-07-26 13:11:24 +000090 // If the cost of one side of the link is NON_ADJACENT_COST (i.e. broken) or negative,
91 // both direction of the link should have their cost corrected to NON_ADJACENT_COST.
Vince Lehman41b173e2015-05-07 14:13:26 -050092 //
93 // Otherwise, both sides of the link should use the larger of the two costs.
94 //
Nick G97e34942016-07-11 14:46:27 -050095 // Additionally, this means that we can halve the amount of space
96 // that the matrix uses by only maintaining a triangle.
97 // - But that is not yet implemented.
Vince Lehman41b173e2015-05-07 14:13:26 -050098 for (size_t row = 0; row < m_nRouters; ++row) {
99 for (size_t col = 0; col < m_nRouters; ++col) {
100 double toCost = adjMatrix[row][col];
101 double fromCost = adjMatrix[col][row];
102
103 if (fromCost != toCost) {
dulalsaurabd0816a32019-07-26 13:11:24 +0000104 double correctedCost = Adjacent::NON_ADJACENT_COST;
Vince Lehman41b173e2015-05-07 14:13:26 -0500105
dulalsaurabd0816a32019-07-26 13:11:24 +0000106 if (toCost >= 0 && fromCost >= 0) {
107 // If both sides of the link are up, use the larger cost else break the link
Vince Lehman41b173e2015-05-07 14:13:26 -0500108 correctedCost = std::max(toCost, fromCost);
109 }
110
dmcoomes5bcb39e2017-10-31 15:07:55 -0500111 NLSR_LOG_WARN("Cost between [" << row << "][" << col << "] and [" << col << "][" << row <<
Vince Lehman41b173e2015-05-07 14:13:26 -0500112 "] are not the same (" << toCost << " != " << fromCost << "). " <<
113 "Correcting to cost: " << correctedCost);
114
115 adjMatrix[row][col] = correctedCost;
116 adjMatrix[col][row] = correctedCost;
117 }
118 }
119 }
akmhoque53353462014-04-22 08:43:45 -0500120}
121
122void
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000123RoutingTableCalculator::writeAdjMatrixLog(const Map& map) const
akmhoque53353462014-04-22 08:43:45 -0500124{
Ashlesh Gawandecba0ae22018-03-27 17:57:56 -0500125 if (!ndn_cxx_getLogger().isLevelEnabled(ndn::util::LogLevel::DEBUG)) {
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000126 return;
127 }
128
129 NLSR_LOG_DEBUG("-----------Legend (routerName -> index)------");
130 std::string routerIndex;
131 std::string indexToNameMapping;
132 std::string lengthOfDash = "--";
133
Vince Lehman9a709032014-09-13 16:28:07 -0500134 for (size_t i = 0; i < m_nRouters; i++) {
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000135 routerIndex += boost::lexical_cast<std::string>(i);
136 routerIndex += " ";
137 lengthOfDash += "--";
138 NLSR_LOG_DEBUG("Router:" + map.getRouterNameByMappingNo(i)->toUri() +
Ashlesh Gawandecba0ae22018-03-27 17:57:56 -0500139 " Index:" + boost::lexical_cast<std::string>(i));
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000140 }
141 NLSR_LOG_DEBUG(" |" + routerIndex);
142 NLSR_LOG_DEBUG(lengthOfDash);
143
144 for (size_t i = 0; i < m_nRouters; i++) {
145 std::string line;
Vince Lehman9a709032014-09-13 16:28:07 -0500146 for (size_t j = 0; j < m_nRouters; j++) {
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400147 if (adjMatrix[i][j] == NO_NEXT_HOP) {
Ashlesh Gawande6b388fc2019-09-30 10:14:41 -0500148 line += "0 ";
149 }
150 else {
151 line += boost::lexical_cast<std::string>(adjMatrix[i][j]);
152 line += " ";
153 }
akmhoque157b0a42014-05-13 00:26:37 -0500154 }
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000155 line = boost::lexical_cast<std::string>(i) + "|" + line;
dmcoomes5bcb39e2017-10-31 15:07:55 -0500156 NLSR_LOG_DEBUG(line);
akmhoque53353462014-04-22 08:43:45 -0500157 }
158}
159
160void
161RoutingTableCalculator::adjustAdMatrix(int source, int link, double linkCost)
162{
Vince Lehman9a709032014-09-13 16:28:07 -0500163 for (int i = 0; i < static_cast<int>(m_nRouters); i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500164 if (i == link) {
akmhoque53353462014-04-22 08:43:45 -0500165 adjMatrix[source][i] = linkCost;
166 }
akmhoque157b0a42014-05-13 00:26:37 -0500167 else {
dulalsaurabd0816a32019-07-26 13:11:24 +0000168 // if "i" is not a link to the source, set it's cost to a non adjacent value.
169 adjMatrix[source][i] = Adjacent::NON_ADJACENT_COST;
akmhoque53353462014-04-22 08:43:45 -0500170 }
171 }
172}
173
174int
175RoutingTableCalculator::getNumOfLinkfromAdjMatrix(int sRouter)
176{
177 int noLink = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500178
179 for (size_t i = 0; i < m_nRouters; i++) {
dulalsaurabd0816a32019-07-26 13:11:24 +0000180 if (adjMatrix[sRouter][i] >= 0 && i != static_cast<size_t>(sRouter)) { // make sure "i" is not self
akmhoque53353462014-04-22 08:43:45 -0500181 noLink++;
182 }
183 }
184 return noLink;
185}
186
187void
188RoutingTableCalculator::getLinksFromAdjMatrix(int* links,
189 double* linkCosts, int source)
190{
191 int j = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500192
193 for (size_t i = 0; i < m_nRouters; i++) {
dulalsaurabd0816a32019-07-26 13:11:24 +0000194 if (adjMatrix[source][i] >= 0 && i != static_cast<size_t>(source)) {// make sure "i" is not self
akmhoque53353462014-04-22 08:43:45 -0500195 links[j] = i;
196 linkCosts[j] = adjMatrix[source][i];
197 j++;
198 }
199 }
200}
201
202void
203RoutingTableCalculator::freeAdjMatrix()
204{
Vince Lehman9a709032014-09-13 16:28:07 -0500205 for (size_t i = 0; i < m_nRouters; ++i) {
akmhoque53353462014-04-22 08:43:45 -0500206 delete [] adjMatrix[i];
207 }
208 delete [] adjMatrix;
209}
210
akmhoque53353462014-04-22 08:43:45 -0500211void
212RoutingTableCalculator::allocateLinks()
213{
214 links = new int[vNoLink];
215}
216
217void
218RoutingTableCalculator::allocateLinkCosts()
219{
220 linkCosts = new double[vNoLink];
221}
222
akmhoque53353462014-04-22 08:43:45 -0500223void
224RoutingTableCalculator::freeLinks()
225{
226 delete [] links;
227}
228void
229RoutingTableCalculator::freeLinksCosts()
230{
231 delete [] linkCosts;
232}
233
234void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600235LinkStateRoutingTableCalculator::calculatePath(Map& pMap, RoutingTable& rt,
236 ConfParameter& confParam,
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700237 const Lsdb& lsdb)
akmhoque53353462014-04-22 08:43:45 -0500238{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500239 NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::calculatePath Called");
akmhoque53353462014-04-22 08:43:45 -0500240 allocateAdjMatrix();
241 initMatrix();
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700242 makeAdjMatrix(lsdb, pMap);
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000243 writeAdjMatrixLog(pMap);
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400244 auto sourceRouter = pMap.getMappingNoByRouterName(confParam.getRouterPrefix());
Nick G97e34942016-07-11 14:46:27 -0500245 allocateParent(); // These two matrices are used in Dijkstra's algorithm.
246 allocateDistance(); //
Nick Gordone40377d2017-08-11 15:10:02 -0500247 // We only bother to do the calculation if we have a router by that name.
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600248 if (sourceRouter && confParam.getMaxFacesPerPrefix() == 1) {
Nick G97e34942016-07-11 14:46:27 -0500249 // In the single path case we can simply run Dijkstra's algorithm.
Nick Gordone40377d2017-08-11 15:10:02 -0500250 doDijkstraPathCalculation(*sourceRouter);
Nick G97e34942016-07-11 14:46:27 -0500251 // Inform the routing table of the new next hops.
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600252 addAllLsNextHopsToRoutingTable(confParam.getAdjacencyList(), rt, pMap, *sourceRouter);
akmhoque53353462014-04-22 08:43:45 -0500253 }
akmhoque157b0a42014-05-13 00:26:37 -0500254 else {
akmhoque53353462014-04-22 08:43:45 -0500255 // Multi Path
Nick Gordone40377d2017-08-11 15:10:02 -0500256 setNoLink(getNumOfLinkfromAdjMatrix(*sourceRouter));
akmhoque53353462014-04-22 08:43:45 -0500257 allocateLinks();
258 allocateLinkCosts();
Nick G97e34942016-07-11 14:46:27 -0500259 // Gets a sparse listing of adjacencies for path calculation
Nick Gordone40377d2017-08-11 15:10:02 -0500260 getLinksFromAdjMatrix(links, linkCosts, *sourceRouter);
akmhoque157b0a42014-05-13 00:26:37 -0500261 for (int i = 0 ; i < vNoLink; i++) {
Nick G97e34942016-07-11 14:46:27 -0500262 // Simulate that only the current neighbor is accessible
Nick Gordone40377d2017-08-11 15:10:02 -0500263 adjustAdMatrix(*sourceRouter, links[i], linkCosts[i]);
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000264 writeAdjMatrixLog(pMap);
Nick G97e34942016-07-11 14:46:27 -0500265 // Do Dijkstra's algorithm using the current neighbor as your start.
Nick Gordone40377d2017-08-11 15:10:02 -0500266 doDijkstraPathCalculation(*sourceRouter);
Nick G97e34942016-07-11 14:46:27 -0500267 // Update the routing table with the calculations.
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600268 addAllLsNextHopsToRoutingTable(confParam.getAdjacencyList(), rt, pMap, *sourceRouter);
akmhoque53353462014-04-22 08:43:45 -0500269 }
270 freeLinks();
271 freeLinksCosts();
272 }
273 freeParent();
274 freeDistance();
275 freeAdjMatrix();
276}
277
278void
279LinkStateRoutingTableCalculator::doDijkstraPathCalculation(int sourceRouter)
280{
281 int i;
282 int v, u;
Nick G97e34942016-07-11 14:46:27 -0500283 int* Q = new int[m_nRouters]; // Each cell represents the router with that mapping no.
akmhoque53353462014-04-22 08:43:45 -0500284 int head = 0;
Nick Gordone98480b2017-05-24 11:23:03 -0500285 // Initiate the parent
Vince Lehman9a709032014-09-13 16:28:07 -0500286 for (i = 0 ; i < static_cast<int>(m_nRouters); i++) {
akmhoque53353462014-04-22 08:43:45 -0500287 m_parent[i] = EMPTY_PARENT;
Nick G97e34942016-07-11 14:46:27 -0500288 // Array where the ith element is the distance to the router with mapping no i.
akmhoque53353462014-04-22 08:43:45 -0500289 m_distance[i] = INF_DISTANCE;
290 Q[i] = i;
291 }
akmhoque157b0a42014-05-13 00:26:37 -0500292 if (sourceRouter != NO_MAPPING_NUM) {
Nick G97e34942016-07-11 14:46:27 -0500293 // Distance to source from source is always 0.
akmhoque53353462014-04-22 08:43:45 -0500294 m_distance[sourceRouter] = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500295 sortQueueByDistance(Q, m_distance, head, m_nRouters);
Nick G97e34942016-07-11 14:46:27 -0500296 // While we haven't visited every node.
Vince Lehman9a709032014-09-13 16:28:07 -0500297 while (head < static_cast<int>(m_nRouters)) {
Nick G97e34942016-07-11 14:46:27 -0500298 u = Q[head]; // Set u to be the current node pointed to by head.
akmhoque157b0a42014-05-13 00:26:37 -0500299 if (m_distance[u] == INF_DISTANCE) {
Nick G97e34942016-07-11 14:46:27 -0500300 break; // This can only happen when there are no accessible nodes.
akmhoque53353462014-04-22 08:43:45 -0500301 }
Nick G97e34942016-07-11 14:46:27 -0500302 // Iterate over the adjacent nodes to u.
Vince Lehman9a709032014-09-13 16:28:07 -0500303 for (v = 0 ; v < static_cast<int>(m_nRouters); v++) {
Nick G97e34942016-07-11 14:46:27 -0500304 // If the current node is accessible.
dulalsaurabd0816a32019-07-26 13:11:24 +0000305 if (adjMatrix[u][v] >= 0) {
Nick G97e34942016-07-11 14:46:27 -0500306 // And we haven't visited it yet.
Vince Lehman9a709032014-09-13 16:28:07 -0500307 if (isNotExplored(Q, v, head + 1, m_nRouters)) {
Nick G97e34942016-07-11 14:46:27 -0500308 // And if the distance to this node + from this node to v
309 // is less than the distance from our source node to v
310 // that we got when we built the adj LSAs
akmhoque157b0a42014-05-13 00:26:37 -0500311 if (m_distance[u] + adjMatrix[u][v] < m_distance[v]) {
Nick G97e34942016-07-11 14:46:27 -0500312 // Set the new distance
akmhoque53353462014-04-22 08:43:45 -0500313 m_distance[v] = m_distance[u] + adjMatrix[u][v] ;
Nick G97e34942016-07-11 14:46:27 -0500314 // Set how we get there.
akmhoque53353462014-04-22 08:43:45 -0500315 m_parent[v] = u;
316 }
317 }
318 }
319 }
Nick G97e34942016-07-11 14:46:27 -0500320 // Increment the head position, resort the list by distance from where we are.
akmhoque53353462014-04-22 08:43:45 -0500321 head++;
Vince Lehman9a709032014-09-13 16:28:07 -0500322 sortQueueByDistance(Q, m_distance, head, m_nRouters);
akmhoque53353462014-04-22 08:43:45 -0500323 }
324 }
325 delete [] Q;
326}
327
328void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600329LinkStateRoutingTableCalculator::addAllLsNextHopsToRoutingTable(AdjacencyList& adjacencies,
330 RoutingTable& rt, Map& pMap,
331 uint32_t sourceRouter)
akmhoque53353462014-04-22 08:43:45 -0500332{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500333 NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::addAllNextHopsToRoutingTable Called");
Vince Lehman9a709032014-09-13 16:28:07 -0500334
akmhoque53353462014-04-22 08:43:45 -0500335 int nextHopRouter = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500336
Nick G97e34942016-07-11 14:46:27 -0500337 // For each router we have
Vince Lehman9a709032014-09-13 16:28:07 -0500338 for (size_t i = 0; i < m_nRouters ; i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500339 if (i != sourceRouter) {
Vince Lehman9a709032014-09-13 16:28:07 -0500340
Nick G97e34942016-07-11 14:46:27 -0500341 // Obtain the next hop that was determined by the algorithm
akmhoque53353462014-04-22 08:43:45 -0500342 nextHopRouter = getLsNextHop(i, sourceRouter);
Nick G97e34942016-07-11 14:46:27 -0500343 // If this router is accessible at all
akmhoque157b0a42014-05-13 00:26:37 -0500344 if (nextHopRouter != NO_NEXT_HOP) {
Vince Lehman9a709032014-09-13 16:28:07 -0500345
Nick G97e34942016-07-11 14:46:27 -0500346 // Fetch its distance
akmhoque53353462014-04-22 08:43:45 -0500347 double routeCost = m_distance[i];
Nick G97e34942016-07-11 14:46:27 -0500348 // Fetch its actual name
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400349 auto nextHopRouterName = pMap.getRouterNameByMappingNo(nextHopRouter);
Nick Gordone40377d2017-08-11 15:10:02 -0500350 if (nextHopRouterName) {
Junxiao Shi6593a432023-08-21 10:50:28 +0000351 auto nextHopFace = adjacencies.getAdjacent(*nextHopRouterName).getFaceUri();
Nick Gordone40377d2017-08-11 15:10:02 -0500352 // Add next hop to routing table
353 NextHop nh(nextHopFace, routeCost);
354 rt.addNextHop(*(pMap.getRouterNameByMappingNo(i)), nh);
Nick Gordone40377d2017-08-11 15:10:02 -0500355 }
akmhoque53353462014-04-22 08:43:45 -0500356 }
357 }
358 }
359}
360
361int
362LinkStateRoutingTableCalculator::getLsNextHop(int dest, int source)
363{
364 int nextHop = NO_NEXT_HOP;
akmhoque157b0a42014-05-13 00:26:37 -0500365 while (m_parent[dest] != EMPTY_PARENT) {
akmhoque53353462014-04-22 08:43:45 -0500366 nextHop = dest;
367 dest = m_parent[dest];
368 }
akmhoque157b0a42014-05-13 00:26:37 -0500369 if (dest != source) {
akmhoque53353462014-04-22 08:43:45 -0500370 nextHop = NO_NEXT_HOP;
371 }
372 return nextHop;
373}
374
375void
akmhoque53353462014-04-22 08:43:45 -0500376LinkStateRoutingTableCalculator::sortQueueByDistance(int* Q,
akmhoque2f423352014-06-03 11:49:35 -0500377 double* dist,
378 int start, int element)
akmhoque53353462014-04-22 08:43:45 -0500379{
akmhoque157b0a42014-05-13 00:26:37 -0500380 for (int i = start ; i < element ; i++) {
381 for (int j = i + 1; j < element; j++) {
382 if (dist[Q[j]] < dist[Q[i]]) {
akmhoque53353462014-04-22 08:43:45 -0500383 int tempU = Q[j];
384 Q[j] = Q[i];
385 Q[i] = tempU;
386 }
387 }
388 }
389}
390
391int
392LinkStateRoutingTableCalculator::isNotExplored(int* Q,
393 int u, int start, int element)
394{
395 int ret = 0;
akmhoque157b0a42014-05-13 00:26:37 -0500396 for (int i = start; i < element; i++) {
397 if (Q[i] == u) {
akmhoque53353462014-04-22 08:43:45 -0500398 ret = 1;
399 break;
400 }
401 }
402 return ret;
403}
404
405void
406LinkStateRoutingTableCalculator::allocateParent()
407{
Vince Lehman9a709032014-09-13 16:28:07 -0500408 m_parent = new int[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -0500409}
410
411void
412LinkStateRoutingTableCalculator::allocateDistance()
413{
Vince Lehman9a709032014-09-13 16:28:07 -0500414 m_distance = new double[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -0500415}
416
417void
418LinkStateRoutingTableCalculator::freeParent()
419{
420 delete [] m_parent;
421}
422
423void LinkStateRoutingTableCalculator::freeDistance()
424{
425 delete [] m_distance;
426}
427
akmhoque53353462014-04-22 08:43:45 -0500428void
Saurab Dulal72b2b252019-01-22 16:58:08 -0600429HyperbolicRoutingCalculator::calculatePath(Map& map, RoutingTable& rt,
430 Lsdb& lsdb, AdjacencyList& adjacencies)
akmhoque53353462014-04-22 08:43:45 -0500431{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500432 NLSR_LOG_TRACE("Calculating hyperbolic paths");
Vince Lehman9a709032014-09-13 16:28:07 -0500433
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400434 auto thisRouter = map.getMappingNoByRouterName(m_thisRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500435
436 // Iterate over directly connected neighbors
437 std::list<Adjacent> neighbors = adjacencies.getAdjList();
Davide Pesaventofd1e9402023-11-13 15:40:41 -0500438 for (auto adj = neighbors.begin(); adj != neighbors.end(); ++adj) {
Vince Lehman9a709032014-09-13 16:28:07 -0500439
440 // Don't calculate nexthops using an inactive router
441 if (adj->getStatus() == Adjacent::STATUS_INACTIVE) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500442 NLSR_LOG_TRACE(adj->getName() << " is inactive; not using it as a nexthop");
Vince Lehman9a709032014-09-13 16:28:07 -0500443 continue;
444 }
445
446 ndn::Name srcRouterName = adj->getName();
447
448 // Don't calculate nexthops for this router to other routers
449 if (srcRouterName == m_thisRouterName) {
450 continue;
451 }
452
Vince Lehman9a709032014-09-13 16:28:07 -0500453 // Install nexthops for this router to the neighbor; direct neighbors have a 0 cost link
Junxiao Shi6593a432023-08-21 10:50:28 +0000454 addNextHop(srcRouterName, adj->getFaceUri(), 0, rt);
Vince Lehman9a709032014-09-13 16:28:07 -0500455
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400456 auto src = map.getMappingNoByRouterName(srcRouterName);
Nick Gordone40377d2017-08-11 15:10:02 -0500457 if (!src) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500458 NLSR_LOG_WARN(adj->getName() << " does not exist in the router map!");
Vince Lehman9a709032014-09-13 16:28:07 -0500459 continue;
460 }
461
462 // Get hyperbolic distance from direct neighbor to every other router
463 for (int dest = 0; dest < static_cast<int>(m_nRouters); ++dest) {
464 // Don't calculate nexthops to this router or from a router to itself
Nick Gordone40377d2017-08-11 15:10:02 -0500465 if (thisRouter && dest != *thisRouter && dest != *src) {
Vince Lehman9a709032014-09-13 16:28:07 -0500466
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400467 auto destRouterName = map.getRouterNameByMappingNo(dest);
Nick Gordone40377d2017-08-11 15:10:02 -0500468 if (destRouterName) {
Saurab Dulal72b2b252019-01-22 16:58:08 -0600469 double distance = getHyperbolicDistance(lsdb, srcRouterName, *destRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500470
Nick Gordone40377d2017-08-11 15:10:02 -0500471 // Could not compute distance
472 if (distance == UNKNOWN_DISTANCE) {
dulalsaurabd0816a32019-07-26 13:11:24 +0000473 NLSR_LOG_WARN("Could not calculate hyperbolic distance from " << srcRouterName
474 << " to " << *destRouterName);
Nick Gordone40377d2017-08-11 15:10:02 -0500475 continue;
476 }
Junxiao Shi6593a432023-08-21 10:50:28 +0000477 addNextHop(*destRouterName, adj->getFaceUri(), distance, rt);
akmhoque53353462014-04-22 08:43:45 -0500478 }
Vince Lehman9a709032014-09-13 16:28:07 -0500479 }
akmhoquedcee9362014-08-05 22:58:01 -0500480 }
akmhoque53353462014-04-22 08:43:45 -0500481 }
482}
483
484double
Saurab Dulal72b2b252019-01-22 16:58:08 -0600485HyperbolicRoutingCalculator::getHyperbolicDistance(Lsdb& lsdb, ndn::Name src, ndn::Name dest)
akmhoque53353462014-04-22 08:43:45 -0500486{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500487 NLSR_LOG_TRACE("Calculating hyperbolic distance from " << src << " to " << dest);
akmhoquedcee9362014-08-05 22:58:01 -0500488
Vince Lehman9a709032014-09-13 16:28:07 -0500489 double distance = UNKNOWN_DISTANCE;
490
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700491 auto srcLsa = lsdb.findLsa<CoordinateLsa>(src);
492 auto destLsa = lsdb.findLsa<CoordinateLsa>(dest);
Vince Lehman9a709032014-09-13 16:28:07 -0500493
494 // Coordinate LSAs do not exist for these routers
Nick Gordone9733ed2017-04-26 10:48:39 -0500495 if (srcLsa == nullptr || destLsa == nullptr) {
Vince Lehman9a709032014-09-13 16:28:07 -0500496 return UNKNOWN_DISTANCE;
akmhoquedcee9362014-08-05 22:58:01 -0500497 }
498
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600499 std::vector<double> srcTheta = srcLsa->getCorTheta();
500 std::vector<double> destTheta = destLsa->getCorTheta();
Vince Lehman9a709032014-09-13 16:28:07 -0500501
502 double srcRadius = srcLsa->getCorRadius();
503 double destRadius = destLsa->getCorRadius();
504
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600505 double diffTheta = calculateAngularDistance(srcTheta, destTheta);
506
507 if (srcRadius == UNKNOWN_RADIUS || destRadius == UNKNOWN_RADIUS ||
508 diffTheta == UNKNOWN_DISTANCE) {
Vince Lehman9a709032014-09-13 16:28:07 -0500509 return UNKNOWN_DISTANCE;
510 }
511
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600512 // double r_i, double r_j, double delta_theta, double zeta = 1 (default)
513 distance = calculateHyperbolicDistance(srcRadius, destRadius, diffTheta);
Vince Lehman9a709032014-09-13 16:28:07 -0500514
dmcoomes5bcb39e2017-10-31 15:07:55 -0500515 NLSR_LOG_TRACE("Distance from " << src << " to " << dest << " is " << distance);
Vince Lehman9a709032014-09-13 16:28:07 -0500516
akmhoque53353462014-04-22 08:43:45 -0500517 return distance;
518}
519
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600520double
521HyperbolicRoutingCalculator::calculateAngularDistance(std::vector<double> angleVectorI,
522 std::vector<double> angleVectorJ)
523{
524 // It is not possible for angle vector size to be zero as ensured by conf-file-processor
525
526 // https://en.wikipedia.org/wiki/N-sphere#Spherical_coordinates
527
528 // Check if two vector lengths are the same
529 if (angleVectorI.size() != angleVectorJ.size()) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500530 NLSR_LOG_ERROR("Angle vector sizes do not match");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600531 return UNKNOWN_DISTANCE;
532 }
533
534 // Check if all angles are within the [0, PI] and [0, 2PI] ranges
535 if (angleVectorI.size() > 1) {
536 for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
537 if ((angleVectorI[k] > M_PI && angleVectorI[k] < 0.0) ||
538 (angleVectorJ[k] > M_PI && angleVectorJ[k] < 0.0)) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500539 NLSR_LOG_ERROR("Angle outside [0, PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600540 return UNKNOWN_DISTANCE;
541 }
542 }
543 }
Davide Pesaventoc1d0e8e2022-06-15 14:26:02 -0400544
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600545 if (angleVectorI[angleVectorI.size()-1] > 2.*M_PI ||
546 angleVectorI[angleVectorI.size()-1] < 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500547 NLSR_LOG_ERROR("Angle not within [0, 2PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600548 return UNKNOWN_DISTANCE;
549 }
550
551 if (angleVectorI[angleVectorI.size()-1] > 2.*M_PI ||
552 angleVectorI[angleVectorI.size()-1] < 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500553 NLSR_LOG_ERROR("Angle not within [0, 2PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600554 return UNKNOWN_DISTANCE;
555 }
556
557 // deltaTheta = arccos(vectorI . vectorJ) -> do the inner product
558 double innerProduct = 0.0;
559
560 // Calculate x0 of the vectors
561 double x0i = std::cos(angleVectorI[0]);
562 double x0j = std::cos(angleVectorJ[0]);
563
564 // Calculate xn of the vectors
565 double xni = std::sin(angleVectorI[angleVectorI.size() - 1]);
566 double xnj = std::sin(angleVectorJ[angleVectorJ.size() - 1]);
567
568 // Do the aggregation of the (n-1) coordinates (if there is more than one angle)
569 // i.e contraction of all (n-1)-dimensional angular coordinates to one variable
570 for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
571 xni *= std::sin(angleVectorI[k]);
572 xnj *= std::sin(angleVectorJ[k]);
573 }
574 innerProduct += (x0i * x0j) + (xni * xnj);
575
576 // If d > 1
577 if (angleVectorI.size() > 1) {
578 for (unsigned int m = 1; m < angleVectorI.size(); m++) {
579 // calculate euclidean coordinates given the angles and assuming R_sphere = 1
580 double xmi = std::cos(angleVectorI[m]);
581 double xmj = std::cos(angleVectorJ[m]);
582 for (unsigned int l = 0; l < m; l++) {
583 xmi *= std::sin(angleVectorI[l]);
584 xmj *= std::sin(angleVectorJ[l]);
585 }
586 innerProduct += xmi * xmj;
587 }
588 }
589
590 // ArcCos of the inner product gives the angular distance
591 // between two points on a d-dimensional sphere
592 return std::acos(innerProduct);
593}
594
595double
596HyperbolicRoutingCalculator::calculateHyperbolicDistance(double rI, double rJ,
597 double deltaTheta)
598{
599 if (deltaTheta == UNKNOWN_DISTANCE) {
600 return UNKNOWN_DISTANCE;
601 }
602
603 // Usually, we set zeta = 1 in all experiments
604 double zeta = 1;
605
606 if (deltaTheta <= 0.0 || rI <= 0.0 || rJ <= 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500607 NLSR_LOG_ERROR("Delta theta or rI or rJ is <= 0");
Ashlesh Gawandee8d8bd52018-08-09 17:18:51 -0500608 NLSR_LOG_ERROR("Please make sure that no two nodes have the exact same HR coordinates");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600609 return UNKNOWN_DISTANCE;
610 }
611
612 double xij = (1. / zeta) * std::acosh(std::cosh(zeta*rI) * std::cosh(zeta*rJ) -
613 std::sinh(zeta*rI)*std::sinh(zeta*rJ)*std::cos(deltaTheta));
614 return xij;
615}
616
617void
Junxiao Shi6593a432023-08-21 10:50:28 +0000618HyperbolicRoutingCalculator::addNextHop(const ndn::Name& dest, const ndn::FaceUri& faceUri,
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600619 double cost, RoutingTable& rt)
akmhoque53353462014-04-22 08:43:45 -0500620{
Vince Lehman9a709032014-09-13 16:28:07 -0500621 NextHop hop(faceUri, cost);
Vince Lehman20fe4a92014-09-09 15:57:59 -0500622 hop.setHyperbolic(true);
akmhoque53353462014-04-22 08:43:45 -0500623
dmcoomes5bcb39e2017-10-31 15:07:55 -0500624 NLSR_LOG_TRACE("Calculated " << hop << " for destination: " << dest);
akmhoque53353462014-04-22 08:43:45 -0500625
Vince Lehman9a709032014-09-13 16:28:07 -0500626 if (m_isDryRun) {
627 rt.addNextHopToDryTable(dest, hop);
628 }
629 else {
630 rt.addNextHop(dest, hop);
631 }
akmhoque53353462014-04-22 08:43:45 -0500632}
633
Nick Gordonfad8e252016-08-11 14:21:38 -0500634} // namespace nlsr