blob: 68a7ca288b25e8e30a0ae2402eb9fcbc6ad63459 [file] [log] [blame]
akmhoque3d06e792014-05-27 16:23:20 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Saurab Dulal72b2b252019-01-22 16:58:08 -06003 * Copyright (c) 2014-2019, 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/>.
akmhoque3d06e792014-05-27 16:23:20 -050020 **/
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"
akmhoque53353462014-04-22 08:43:45 -050028
Nick Gordone98480b2017-05-24 11:23:03 -050029#include <iostream>
Vince Lehman9a709032014-09-13 16:28:07 -050030#include <boost/math/constants/constants.hpp>
Saurab Dulal9da6aa72018-01-12 17:25:51 +000031#include <ndn-cxx/util/logger.hpp>
Nick Gordone98480b2017-05-24 11:23:03 -050032#include <cmath>
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
38void
39RoutingTableCalculator::allocateAdjMatrix()
40{
Vince Lehman9a709032014-09-13 16:28:07 -050041 adjMatrix = new double*[m_nRouters];
42
43 for (size_t i = 0; i < m_nRouters; ++i) {
44 adjMatrix[i] = new double[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -050045 }
46}
47
48void
49RoutingTableCalculator::initMatrix()
50{
Vince Lehman9a709032014-09-13 16:28:07 -050051 for (size_t i = 0; i < m_nRouters; i++) {
52 for (size_t j = 0; j < m_nRouters; j++) {
akmhoque53353462014-04-22 08:43:45 -050053 adjMatrix[i][j] = 0;
akmhoque157b0a42014-05-13 00:26:37 -050054 }
akmhoque53353462014-04-22 08:43:45 -050055 }
56}
57
58void
Ashlesh Gawande85998a12017-12-07 22:22:13 -060059RoutingTableCalculator::makeAdjMatrix(const std::list<AdjLsa>& adjLsaList, Map& pMap)
akmhoque53353462014-04-22 08:43:45 -050060{
Nick G97e34942016-07-11 14:46:27 -050061 // For each LSA represented in the map
Ashlesh Gawande85998a12017-12-07 22:22:13 -060062 for (const auto& adjLsa : adjLsaList) {
63 ndn::optional<int32_t> row = pMap.getMappingNoByRouterName(adjLsa.getOrigRouter());
Vince Lehman9a709032014-09-13 16:28:07 -050064
Ashlesh Gawande85998a12017-12-07 22:22:13 -060065 std::list<Adjacent> adl = adjLsa.getAdl().getAdjList();
Nick G97e34942016-07-11 14:46:27 -050066 // For each adjacency represented in the LSA
Ashlesh Gawande85998a12017-12-07 22:22:13 -060067 for (const auto& adjacent : adl) {
68 ndn::optional<int32_t> col = pMap.getMappingNoByRouterName(adjacent.getName());
69 double cost = adjacent.getLinkCost();
Vince Lehman9a709032014-09-13 16:28:07 -050070
Nick Gordone40377d2017-08-11 15:10:02 -050071 if (row && col && *row < static_cast<int32_t>(m_nRouters)
72 && *col < static_cast<int32_t>(m_nRouters))
Vince Lehman9a709032014-09-13 16:28:07 -050073 {
Nick Gordone40377d2017-08-11 15:10:02 -050074 adjMatrix[*row][*col] = cost;
akmhoque53353462014-04-22 08:43:45 -050075 }
76 }
77 }
Vince Lehman41b173e2015-05-07 14:13:26 -050078
Nick G97e34942016-07-11 14:46:27 -050079 // Links that do not have the same cost for both directions should
80 // have their costs corrected:
Vince Lehman41b173e2015-05-07 14:13:26 -050081 //
Nick G97e34942016-07-11 14:46:27 -050082 // If the cost of one side of the link is 0, both sides of the
83 // link should have their cost corrected to 0.
Vince Lehman41b173e2015-05-07 14:13:26 -050084 //
85 // Otherwise, both sides of the link should use the larger of the two costs.
86 //
Nick G97e34942016-07-11 14:46:27 -050087 // Additionally, this means that we can halve the amount of space
88 // that the matrix uses by only maintaining a triangle.
89 // - But that is not yet implemented.
Vince Lehman41b173e2015-05-07 14:13:26 -050090 for (size_t row = 0; row < m_nRouters; ++row) {
91 for (size_t col = 0; col < m_nRouters; ++col) {
92 double toCost = adjMatrix[row][col];
93 double fromCost = adjMatrix[col][row];
94
95 if (fromCost != toCost) {
96 double correctedCost = 0.0;
97
98 if (toCost != 0 && fromCost != 0) {
99 // If both sides of the link are up, use the larger cost
100 correctedCost = std::max(toCost, fromCost);
101 }
102
dmcoomes5bcb39e2017-10-31 15:07:55 -0500103 NLSR_LOG_WARN("Cost between [" << row << "][" << col << "] and [" << col << "][" << row <<
Vince Lehman41b173e2015-05-07 14:13:26 -0500104 "] are not the same (" << toCost << " != " << fromCost << "). " <<
105 "Correcting to cost: " << correctedCost);
106
107 adjMatrix[row][col] = correctedCost;
108 adjMatrix[col][row] = correctedCost;
109 }
110 }
111 }
akmhoque53353462014-04-22 08:43:45 -0500112}
113
114void
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000115RoutingTableCalculator::writeAdjMatrixLog(const Map& map) const
akmhoque53353462014-04-22 08:43:45 -0500116{
Ashlesh Gawandecba0ae22018-03-27 17:57:56 -0500117 if (!ndn_cxx_getLogger().isLevelEnabled(ndn::util::LogLevel::DEBUG)) {
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000118 return;
119 }
120
121 NLSR_LOG_DEBUG("-----------Legend (routerName -> index)------");
122 std::string routerIndex;
123 std::string indexToNameMapping;
124 std::string lengthOfDash = "--";
125
Vince Lehman9a709032014-09-13 16:28:07 -0500126 for (size_t i = 0; i < m_nRouters; i++) {
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000127 routerIndex += boost::lexical_cast<std::string>(i);
128 routerIndex += " ";
129 lengthOfDash += "--";
130 NLSR_LOG_DEBUG("Router:" + map.getRouterNameByMappingNo(i)->toUri() +
Ashlesh Gawandecba0ae22018-03-27 17:57:56 -0500131 " Index:" + boost::lexical_cast<std::string>(i));
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000132 }
133 NLSR_LOG_DEBUG(" |" + routerIndex);
134 NLSR_LOG_DEBUG(lengthOfDash);
135
136 for (size_t i = 0; i < m_nRouters; i++) {
137 std::string line;
Vince Lehman9a709032014-09-13 16:28:07 -0500138 for (size_t j = 0; j < m_nRouters; j++) {
akmhoque2f423352014-06-03 11:49:35 -0500139 line += boost::lexical_cast<std::string>(adjMatrix[i][j]);
140 line += " ";
akmhoque157b0a42014-05-13 00:26:37 -0500141 }
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000142 line = boost::lexical_cast<std::string>(i) + "|" + line;
dmcoomes5bcb39e2017-10-31 15:07:55 -0500143 NLSR_LOG_DEBUG(line);
akmhoque53353462014-04-22 08:43:45 -0500144 }
145}
146
147void
148RoutingTableCalculator::adjustAdMatrix(int source, int link, double linkCost)
149{
Vince Lehman9a709032014-09-13 16:28:07 -0500150 for (int i = 0; i < static_cast<int>(m_nRouters); i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500151 if (i == link) {
akmhoque53353462014-04-22 08:43:45 -0500152 adjMatrix[source][i] = linkCost;
153 }
akmhoque157b0a42014-05-13 00:26:37 -0500154 else {
akmhoque53353462014-04-22 08:43:45 -0500155 adjMatrix[source][i] = 0;
156 }
157 }
158}
159
160int
161RoutingTableCalculator::getNumOfLinkfromAdjMatrix(int sRouter)
162{
163 int noLink = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500164
165 for (size_t i = 0; i < m_nRouters; i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500166 if (adjMatrix[sRouter][i] > 0) {
akmhoque53353462014-04-22 08:43:45 -0500167 noLink++;
168 }
169 }
170 return noLink;
171}
172
173void
174RoutingTableCalculator::getLinksFromAdjMatrix(int* links,
175 double* linkCosts, int source)
176{
177 int j = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500178
179 for (size_t i = 0; i < m_nRouters; i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500180 if (adjMatrix[source][i] > 0) {
akmhoque53353462014-04-22 08:43:45 -0500181 links[j] = i;
182 linkCosts[j] = adjMatrix[source][i];
183 j++;
184 }
185 }
186}
187
188void
189RoutingTableCalculator::freeAdjMatrix()
190{
Vince Lehman9a709032014-09-13 16:28:07 -0500191 for (size_t i = 0; i < m_nRouters; ++i) {
akmhoque53353462014-04-22 08:43:45 -0500192 delete [] adjMatrix[i];
193 }
194 delete [] adjMatrix;
195}
196
akmhoque53353462014-04-22 08:43:45 -0500197void
198RoutingTableCalculator::allocateLinks()
199{
200 links = new int[vNoLink];
201}
202
203void
204RoutingTableCalculator::allocateLinkCosts()
205{
206 linkCosts = new double[vNoLink];
207}
208
209
210void
211RoutingTableCalculator::freeLinks()
212{
213 delete [] links;
214}
215void
216RoutingTableCalculator::freeLinksCosts()
217{
218 delete [] linkCosts;
219}
220
221void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600222LinkStateRoutingTableCalculator::calculatePath(Map& pMap, RoutingTable& rt,
223 ConfParameter& confParam,
224 const std::list<AdjLsa>& adjLsaList)
akmhoque53353462014-04-22 08:43:45 -0500225{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500226 NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::calculatePath Called");
akmhoque53353462014-04-22 08:43:45 -0500227 allocateAdjMatrix();
228 initMatrix();
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600229 makeAdjMatrix(adjLsaList, pMap);
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000230 writeAdjMatrixLog(pMap);
Nick Gordone40377d2017-08-11 15:10:02 -0500231 ndn::optional<int32_t> sourceRouter =
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600232 pMap.getMappingNoByRouterName(confParam.getRouterPrefix());
Nick G97e34942016-07-11 14:46:27 -0500233 allocateParent(); // These two matrices are used in Dijkstra's algorithm.
234 allocateDistance(); //
Nick Gordone40377d2017-08-11 15:10:02 -0500235 // We only bother to do the calculation if we have a router by that name.
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600236 if (sourceRouter && confParam.getMaxFacesPerPrefix() == 1) {
Nick G97e34942016-07-11 14:46:27 -0500237 // In the single path case we can simply run Dijkstra's algorithm.
Nick Gordone40377d2017-08-11 15:10:02 -0500238 doDijkstraPathCalculation(*sourceRouter);
Nick G97e34942016-07-11 14:46:27 -0500239 // Inform the routing table of the new next hops.
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600240 addAllLsNextHopsToRoutingTable(confParam.getAdjacencyList(), rt, pMap, *sourceRouter);
akmhoque53353462014-04-22 08:43:45 -0500241 }
akmhoque157b0a42014-05-13 00:26:37 -0500242 else {
akmhoque53353462014-04-22 08:43:45 -0500243 // Multi Path
Nick Gordone40377d2017-08-11 15:10:02 -0500244 setNoLink(getNumOfLinkfromAdjMatrix(*sourceRouter));
akmhoque53353462014-04-22 08:43:45 -0500245 allocateLinks();
246 allocateLinkCosts();
Nick G97e34942016-07-11 14:46:27 -0500247 // Gets a sparse listing of adjacencies for path calculation
Nick Gordone40377d2017-08-11 15:10:02 -0500248 getLinksFromAdjMatrix(links, linkCosts, *sourceRouter);
akmhoque157b0a42014-05-13 00:26:37 -0500249 for (int i = 0 ; i < vNoLink; i++) {
Nick G97e34942016-07-11 14:46:27 -0500250 // Simulate that only the current neighbor is accessible
Nick Gordone40377d2017-08-11 15:10:02 -0500251 adjustAdMatrix(*sourceRouter, links[i], linkCosts[i]);
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000252 writeAdjMatrixLog(pMap);
Nick G97e34942016-07-11 14:46:27 -0500253 // Do Dijkstra's algorithm using the current neighbor as your start.
Nick Gordone40377d2017-08-11 15:10:02 -0500254 doDijkstraPathCalculation(*sourceRouter);
Nick G97e34942016-07-11 14:46:27 -0500255 // Update the routing table with the calculations.
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600256 addAllLsNextHopsToRoutingTable(confParam.getAdjacencyList(), rt, pMap, *sourceRouter);
akmhoque53353462014-04-22 08:43:45 -0500257 }
258 freeLinks();
259 freeLinksCosts();
260 }
261 freeParent();
262 freeDistance();
263 freeAdjMatrix();
264}
265
266void
267LinkStateRoutingTableCalculator::doDijkstraPathCalculation(int sourceRouter)
268{
269 int i;
270 int v, u;
Nick G97e34942016-07-11 14:46:27 -0500271 int* Q = new int[m_nRouters]; // Each cell represents the router with that mapping no.
akmhoque53353462014-04-22 08:43:45 -0500272 int head = 0;
Nick Gordone98480b2017-05-24 11:23:03 -0500273 // Initiate the parent
Vince Lehman9a709032014-09-13 16:28:07 -0500274 for (i = 0 ; i < static_cast<int>(m_nRouters); i++) {
akmhoque53353462014-04-22 08:43:45 -0500275 m_parent[i] = EMPTY_PARENT;
Nick G97e34942016-07-11 14:46:27 -0500276 // Array where the ith element is the distance to the router with mapping no i.
akmhoque53353462014-04-22 08:43:45 -0500277 m_distance[i] = INF_DISTANCE;
278 Q[i] = i;
279 }
akmhoque157b0a42014-05-13 00:26:37 -0500280 if (sourceRouter != NO_MAPPING_NUM) {
Nick G97e34942016-07-11 14:46:27 -0500281 // Distance to source from source is always 0.
akmhoque53353462014-04-22 08:43:45 -0500282 m_distance[sourceRouter] = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500283 sortQueueByDistance(Q, m_distance, head, m_nRouters);
Nick G97e34942016-07-11 14:46:27 -0500284 // While we haven't visited every node.
Vince Lehman9a709032014-09-13 16:28:07 -0500285 while (head < static_cast<int>(m_nRouters)) {
Nick G97e34942016-07-11 14:46:27 -0500286 u = Q[head]; // Set u to be the current node pointed to by head.
akmhoque157b0a42014-05-13 00:26:37 -0500287 if (m_distance[u] == INF_DISTANCE) {
Nick G97e34942016-07-11 14:46:27 -0500288 break; // This can only happen when there are no accessible nodes.
akmhoque53353462014-04-22 08:43:45 -0500289 }
Nick G97e34942016-07-11 14:46:27 -0500290 // Iterate over the adjacent nodes to u.
Vince Lehman9a709032014-09-13 16:28:07 -0500291 for (v = 0 ; v < static_cast<int>(m_nRouters); v++) {
Nick G97e34942016-07-11 14:46:27 -0500292 // If the current node is accessible.
akmhoque157b0a42014-05-13 00:26:37 -0500293 if (adjMatrix[u][v] > 0) {
Nick G97e34942016-07-11 14:46:27 -0500294 // And we haven't visited it yet.
Vince Lehman9a709032014-09-13 16:28:07 -0500295 if (isNotExplored(Q, v, head + 1, m_nRouters)) {
Nick G97e34942016-07-11 14:46:27 -0500296 // And if the distance to this node + from this node to v
297 // is less than the distance from our source node to v
298 // that we got when we built the adj LSAs
akmhoque157b0a42014-05-13 00:26:37 -0500299 if (m_distance[u] + adjMatrix[u][v] < m_distance[v]) {
Nick G97e34942016-07-11 14:46:27 -0500300 // Set the new distance
akmhoque53353462014-04-22 08:43:45 -0500301 m_distance[v] = m_distance[u] + adjMatrix[u][v] ;
Nick G97e34942016-07-11 14:46:27 -0500302 // Set how we get there.
akmhoque53353462014-04-22 08:43:45 -0500303 m_parent[v] = u;
304 }
305 }
306 }
307 }
Nick G97e34942016-07-11 14:46:27 -0500308 // Increment the head position, resort the list by distance from where we are.
akmhoque53353462014-04-22 08:43:45 -0500309 head++;
Vince Lehman9a709032014-09-13 16:28:07 -0500310 sortQueueByDistance(Q, m_distance, head, m_nRouters);
akmhoque53353462014-04-22 08:43:45 -0500311 }
312 }
313 delete [] Q;
314}
315
316void
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600317LinkStateRoutingTableCalculator::addAllLsNextHopsToRoutingTable(AdjacencyList& adjacencies,
318 RoutingTable& rt, Map& pMap,
319 uint32_t sourceRouter)
akmhoque53353462014-04-22 08:43:45 -0500320{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500321 NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::addAllNextHopsToRoutingTable Called");
Vince Lehman9a709032014-09-13 16:28:07 -0500322
akmhoque53353462014-04-22 08:43:45 -0500323 int nextHopRouter = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500324
Nick G97e34942016-07-11 14:46:27 -0500325 // For each router we have
Vince Lehman9a709032014-09-13 16:28:07 -0500326 for (size_t i = 0; i < m_nRouters ; i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500327 if (i != sourceRouter) {
Vince Lehman9a709032014-09-13 16:28:07 -0500328
Nick G97e34942016-07-11 14:46:27 -0500329 // Obtain the next hop that was determined by the algorithm
akmhoque53353462014-04-22 08:43:45 -0500330 nextHopRouter = getLsNextHop(i, sourceRouter);
Vince Lehman9a709032014-09-13 16:28:07 -0500331
Nick G97e34942016-07-11 14:46:27 -0500332 // If this router is accessible at all
akmhoque157b0a42014-05-13 00:26:37 -0500333 if (nextHopRouter != NO_NEXT_HOP) {
Vince Lehman9a709032014-09-13 16:28:07 -0500334
Nick G97e34942016-07-11 14:46:27 -0500335 // Fetch its distance
akmhoque53353462014-04-22 08:43:45 -0500336 double routeCost = m_distance[i];
Nick G97e34942016-07-11 14:46:27 -0500337 // Fetch its actual name
Nick Gordone40377d2017-08-11 15:10:02 -0500338 ndn::optional<ndn::Name> nextHopRouterName= pMap.getRouterNameByMappingNo(nextHopRouter);
339 if (nextHopRouterName) {
340 std::string nextHopFace =
Ashlesh Gawande85998a12017-12-07 22:22:13 -0600341 adjacencies.getAdjacent(*nextHopRouterName).getFaceUri().toString();
Nick Gordone40377d2017-08-11 15:10:02 -0500342 // Add next hop to routing table
343 NextHop nh(nextHopFace, routeCost);
344 rt.addNextHop(*(pMap.getRouterNameByMappingNo(i)), nh);
345
346 }
akmhoque53353462014-04-22 08:43:45 -0500347 }
348 }
349 }
350}
351
352int
353LinkStateRoutingTableCalculator::getLsNextHop(int dest, int source)
354{
355 int nextHop = NO_NEXT_HOP;
akmhoque157b0a42014-05-13 00:26:37 -0500356 while (m_parent[dest] != EMPTY_PARENT) {
akmhoque53353462014-04-22 08:43:45 -0500357 nextHop = dest;
358 dest = m_parent[dest];
359 }
akmhoque157b0a42014-05-13 00:26:37 -0500360 if (dest != source) {
akmhoque53353462014-04-22 08:43:45 -0500361 nextHop = NO_NEXT_HOP;
362 }
363 return nextHop;
364}
365
366void
akmhoque53353462014-04-22 08:43:45 -0500367LinkStateRoutingTableCalculator::sortQueueByDistance(int* Q,
akmhoque2f423352014-06-03 11:49:35 -0500368 double* dist,
369 int start, int element)
akmhoque53353462014-04-22 08:43:45 -0500370{
akmhoque157b0a42014-05-13 00:26:37 -0500371 for (int i = start ; i < element ; i++) {
372 for (int j = i + 1; j < element; j++) {
373 if (dist[Q[j]] < dist[Q[i]]) {
akmhoque53353462014-04-22 08:43:45 -0500374 int tempU = Q[j];
375 Q[j] = Q[i];
376 Q[i] = tempU;
377 }
378 }
379 }
380}
381
382int
383LinkStateRoutingTableCalculator::isNotExplored(int* Q,
384 int u, int start, int element)
385{
386 int ret = 0;
akmhoque157b0a42014-05-13 00:26:37 -0500387 for (int i = start; i < element; i++) {
388 if (Q[i] == u) {
akmhoque53353462014-04-22 08:43:45 -0500389 ret = 1;
390 break;
391 }
392 }
393 return ret;
394}
395
396void
397LinkStateRoutingTableCalculator::allocateParent()
398{
Vince Lehman9a709032014-09-13 16:28:07 -0500399 m_parent = new int[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -0500400}
401
402void
403LinkStateRoutingTableCalculator::allocateDistance()
404{
Vince Lehman9a709032014-09-13 16:28:07 -0500405 m_distance = new double[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -0500406}
407
408void
409LinkStateRoutingTableCalculator::freeParent()
410{
411 delete [] m_parent;
412}
413
414void LinkStateRoutingTableCalculator::freeDistance()
415{
416 delete [] m_distance;
417}
418
Vince Lehman9a709032014-09-13 16:28:07 -0500419const double HyperbolicRoutingCalculator::MATH_PI = boost::math::constants::pi<double>();
akmhoque53353462014-04-22 08:43:45 -0500420
Vince Lehman9a709032014-09-13 16:28:07 -0500421const double HyperbolicRoutingCalculator::UNKNOWN_DISTANCE = -1.0;
422const double HyperbolicRoutingCalculator::UNKNOWN_RADIUS = -1.0;
423
akmhoque53353462014-04-22 08:43:45 -0500424void
Saurab Dulal72b2b252019-01-22 16:58:08 -0600425HyperbolicRoutingCalculator::calculatePath(Map& map, RoutingTable& rt,
426 Lsdb& lsdb, AdjacencyList& adjacencies)
akmhoque53353462014-04-22 08:43:45 -0500427{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500428 NLSR_LOG_TRACE("Calculating hyperbolic paths");
Vince Lehman9a709032014-09-13 16:28:07 -0500429
Nick Gordone40377d2017-08-11 15:10:02 -0500430 ndn::optional<int32_t> thisRouter = map.getMappingNoByRouterName(m_thisRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500431
432 // Iterate over directly connected neighbors
433 std::list<Adjacent> neighbors = adjacencies.getAdjList();
434 for (std::list<Adjacent>::iterator adj = neighbors.begin(); adj != neighbors.end(); ++adj) {
435
436 // Don't calculate nexthops using an inactive router
437 if (adj->getStatus() == Adjacent::STATUS_INACTIVE) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500438 NLSR_LOG_TRACE(adj->getName() << " is inactive; not using it as a nexthop");
Vince Lehman9a709032014-09-13 16:28:07 -0500439 continue;
440 }
441
442 ndn::Name srcRouterName = adj->getName();
443
444 // Don't calculate nexthops for this router to other routers
445 if (srcRouterName == m_thisRouterName) {
446 continue;
447 }
448
Nick Gordone9733ed2017-04-26 10:48:39 -0500449 std::string srcFaceUri = adj->getFaceUri().toString();
Vince Lehman9a709032014-09-13 16:28:07 -0500450
451 // Install nexthops for this router to the neighbor; direct neighbors have a 0 cost link
452 addNextHop(srcRouterName, srcFaceUri, 0, rt);
453
Nick Gordone40377d2017-08-11 15:10:02 -0500454 ndn::optional<int32_t> src = map.getMappingNoByRouterName(srcRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500455
Nick Gordone40377d2017-08-11 15:10:02 -0500456 if (!src) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500457 NLSR_LOG_WARN(adj->getName() << " does not exist in the router map!");
Vince Lehman9a709032014-09-13 16:28:07 -0500458 continue;
459 }
460
461 // Get hyperbolic distance from direct neighbor to every other router
462 for (int dest = 0; dest < static_cast<int>(m_nRouters); ++dest) {
463 // Don't calculate nexthops to this router or from a router to itself
Nick Gordone40377d2017-08-11 15:10:02 -0500464 if (thisRouter && dest != *thisRouter && dest != *src) {
Vince Lehman9a709032014-09-13 16:28:07 -0500465
Nick Gordone40377d2017-08-11 15:10:02 -0500466 ndn::optional<ndn::Name> destRouterName = map.getRouterNameByMappingNo(dest);
467 if (destRouterName) {
Saurab Dulal72b2b252019-01-22 16:58:08 -0600468 double distance = getHyperbolicDistance(lsdb, srcRouterName, *destRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500469
Nick Gordone40377d2017-08-11 15:10:02 -0500470 // Could not compute distance
471 if (distance == UNKNOWN_DISTANCE) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500472 NLSR_LOG_WARN("Could not calculate hyperbolic distance from " << srcRouterName << " to " <<
Saurab Dulal72b2b252019-01-22 16:58:08 -0600473 *destRouterName);
Nick Gordone40377d2017-08-11 15:10:02 -0500474 continue;
475 }
Vince Lehman9a709032014-09-13 16:28:07 -0500476
Nick Gordone40377d2017-08-11 15:10:02 -0500477 addNextHop(*destRouterName, srcFaceUri, 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
491 ndn::Name srcLsaKey = src;
Nick Gordon727d4832017-10-13 18:04:25 -0500492 srcLsaKey.append(std::to_string(Lsa::Type::COORDINATE));
Vince Lehman9a709032014-09-13 16:28:07 -0500493
494 CoordinateLsa* srcLsa = lsdb.findCoordinateLsa(srcLsaKey);
495
496 ndn::Name destLsaKey = dest;
Nick Gordon727d4832017-10-13 18:04:25 -0500497 destLsaKey.append(std::to_string(Lsa::Type::COORDINATE));
Vince Lehman9a709032014-09-13 16:28:07 -0500498
499 CoordinateLsa* destLsa = lsdb.findCoordinateLsa(destLsaKey);
500
501 // Coordinate LSAs do not exist for these routers
Nick Gordone9733ed2017-04-26 10:48:39 -0500502 if (srcLsa == nullptr || destLsa == nullptr) {
Vince Lehman9a709032014-09-13 16:28:07 -0500503 return UNKNOWN_DISTANCE;
akmhoquedcee9362014-08-05 22:58:01 -0500504 }
505
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600506 std::vector<double> srcTheta = srcLsa->getCorTheta();
507 std::vector<double> destTheta = destLsa->getCorTheta();
Vince Lehman9a709032014-09-13 16:28:07 -0500508
509 double srcRadius = srcLsa->getCorRadius();
510 double destRadius = destLsa->getCorRadius();
511
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600512 double diffTheta = calculateAngularDistance(srcTheta, destTheta);
513
514 if (srcRadius == UNKNOWN_RADIUS || destRadius == UNKNOWN_RADIUS ||
515 diffTheta == UNKNOWN_DISTANCE) {
Vince Lehman9a709032014-09-13 16:28:07 -0500516 return UNKNOWN_DISTANCE;
517 }
518
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600519 // double r_i, double r_j, double delta_theta, double zeta = 1 (default)
520 distance = calculateHyperbolicDistance(srcRadius, destRadius, diffTheta);
Vince Lehman9a709032014-09-13 16:28:07 -0500521
dmcoomes5bcb39e2017-10-31 15:07:55 -0500522 NLSR_LOG_TRACE("Distance from " << src << " to " << dest << " is " << distance);
Vince Lehman9a709032014-09-13 16:28:07 -0500523
akmhoque53353462014-04-22 08:43:45 -0500524 return distance;
525}
526
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600527double
528HyperbolicRoutingCalculator::calculateAngularDistance(std::vector<double> angleVectorI,
529 std::vector<double> angleVectorJ)
530{
531 // It is not possible for angle vector size to be zero as ensured by conf-file-processor
532
533 // https://en.wikipedia.org/wiki/N-sphere#Spherical_coordinates
534
535 // Check if two vector lengths are the same
536 if (angleVectorI.size() != angleVectorJ.size()) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500537 NLSR_LOG_ERROR("Angle vector sizes do not match");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600538 return UNKNOWN_DISTANCE;
539 }
540
541 // Check if all angles are within the [0, PI] and [0, 2PI] ranges
542 if (angleVectorI.size() > 1) {
543 for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
544 if ((angleVectorI[k] > M_PI && angleVectorI[k] < 0.0) ||
545 (angleVectorJ[k] > M_PI && angleVectorJ[k] < 0.0)) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500546 NLSR_LOG_ERROR("Angle outside [0, PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600547 return UNKNOWN_DISTANCE;
548 }
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 if (angleVectorI[angleVectorI.size()-1] > 2.*M_PI ||
558 angleVectorI[angleVectorI.size()-1] < 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500559 NLSR_LOG_ERROR("Angle not within [0, 2PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600560 return UNKNOWN_DISTANCE;
561 }
562
563 // deltaTheta = arccos(vectorI . vectorJ) -> do the inner product
564 double innerProduct = 0.0;
565
566 // Calculate x0 of the vectors
567 double x0i = std::cos(angleVectorI[0]);
568 double x0j = std::cos(angleVectorJ[0]);
569
570 // Calculate xn of the vectors
571 double xni = std::sin(angleVectorI[angleVectorI.size() - 1]);
572 double xnj = std::sin(angleVectorJ[angleVectorJ.size() - 1]);
573
574 // Do the aggregation of the (n-1) coordinates (if there is more than one angle)
575 // i.e contraction of all (n-1)-dimensional angular coordinates to one variable
576 for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
577 xni *= std::sin(angleVectorI[k]);
578 xnj *= std::sin(angleVectorJ[k]);
579 }
580 innerProduct += (x0i * x0j) + (xni * xnj);
581
582 // If d > 1
583 if (angleVectorI.size() > 1) {
584 for (unsigned int m = 1; m < angleVectorI.size(); m++) {
585 // calculate euclidean coordinates given the angles and assuming R_sphere = 1
586 double xmi = std::cos(angleVectorI[m]);
587 double xmj = std::cos(angleVectorJ[m]);
588 for (unsigned int l = 0; l < m; l++) {
589 xmi *= std::sin(angleVectorI[l]);
590 xmj *= std::sin(angleVectorJ[l]);
591 }
592 innerProduct += xmi * xmj;
593 }
594 }
595
596 // ArcCos of the inner product gives the angular distance
597 // between two points on a d-dimensional sphere
598 return std::acos(innerProduct);
599}
600
601double
602HyperbolicRoutingCalculator::calculateHyperbolicDistance(double rI, double rJ,
603 double deltaTheta)
604{
605 if (deltaTheta == UNKNOWN_DISTANCE) {
606 return UNKNOWN_DISTANCE;
607 }
608
609 // Usually, we set zeta = 1 in all experiments
610 double zeta = 1;
611
612 if (deltaTheta <= 0.0 || rI <= 0.0 || rJ <= 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500613 NLSR_LOG_ERROR("Delta theta or rI or rJ is <= 0");
Ashlesh Gawandee8d8bd52018-08-09 17:18:51 -0500614 NLSR_LOG_ERROR("Please make sure that no two nodes have the exact same HR coordinates");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600615 return UNKNOWN_DISTANCE;
616 }
617
618 double xij = (1. / zeta) * std::acosh(std::cosh(zeta*rI) * std::cosh(zeta*rJ) -
619 std::sinh(zeta*rI)*std::sinh(zeta*rJ)*std::cos(deltaTheta));
620 return xij;
621}
622
623void
624HyperbolicRoutingCalculator::addNextHop(ndn::Name dest, std::string faceUri,
625 double cost, RoutingTable& rt)
akmhoque53353462014-04-22 08:43:45 -0500626{
Vince Lehman9a709032014-09-13 16:28:07 -0500627 NextHop hop(faceUri, cost);
Vince Lehman20fe4a92014-09-09 15:57:59 -0500628 hop.setHyperbolic(true);
akmhoque53353462014-04-22 08:43:45 -0500629
dmcoomes5bcb39e2017-10-31 15:07:55 -0500630 NLSR_LOG_TRACE("Calculated " << hop << " for destination: " << dest);
akmhoque53353462014-04-22 08:43:45 -0500631
Vince Lehman9a709032014-09-13 16:28:07 -0500632 if (m_isDryRun) {
633 rt.addNextHopToDryTable(dest, hop);
634 }
635 else {
636 rt.addNextHop(dest, hop);
637 }
akmhoque53353462014-04-22 08:43:45 -0500638}
639
Nick Gordonfad8e252016-08-11 14:21:38 -0500640} // namespace nlsr