blob: 0be5e548051886ad903a7b8796db400f99084c48 [file] [log] [blame]
akmhoque3d06e792014-05-27 16:23:20 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
dmcoomescf8d0ed2017-02-21 11:39:01 -06003 * Copyright (c) 2014-2018, 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"
25#include "lsa.hpp"
26#include "nexthop.hpp"
27#include "nlsr.hpp"
akmhoque2f423352014-06-03 11:49:35 -050028#include "logger.hpp"
akmhoque53353462014-04-22 08:43:45 -050029
Nick Gordone98480b2017-05-24 11:23:03 -050030#include <iostream>
Vince Lehman9a709032014-09-13 16:28:07 -050031#include <boost/math/constants/constants.hpp>
Saurab Dulal9da6aa72018-01-12 17:25:51 +000032#include <ndn-cxx/util/logger.hpp>
Nick Gordone98480b2017-05-24 11:23:03 -050033#include <cmath>
Vince Lehman9a709032014-09-13 16:28:07 -050034
akmhoque53353462014-04-22 08:43:45 -050035namespace nlsr {
36
dmcoomescf8d0ed2017-02-21 11:39:01 -060037INIT_LOGGER(route.RoutingTableCalculator);
akmhoque53353462014-04-22 08:43:45 -050038
39void
40RoutingTableCalculator::allocateAdjMatrix()
41{
Vince Lehman9a709032014-09-13 16:28:07 -050042 adjMatrix = new double*[m_nRouters];
43
44 for (size_t i = 0; i < m_nRouters; ++i) {
45 adjMatrix[i] = new double[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -050046 }
47}
48
49void
50RoutingTableCalculator::initMatrix()
51{
Vince Lehman9a709032014-09-13 16:28:07 -050052 for (size_t i = 0; i < m_nRouters; i++) {
53 for (size_t j = 0; j < m_nRouters; j++) {
akmhoque53353462014-04-22 08:43:45 -050054 adjMatrix[i][j] = 0;
akmhoque157b0a42014-05-13 00:26:37 -050055 }
akmhoque53353462014-04-22 08:43:45 -050056 }
57}
58
59void
Saurab Dulal9da6aa72018-01-12 17:25:51 +000060RoutingTableCalculator::makeAdjMatrix(Nlsr& pnlsr, Map& pMap)
akmhoque53353462014-04-22 08:43:45 -050061{
62 std::list<AdjLsa> adjLsdb = pnlsr.getLsdb().getAdjLsdb();
Nick G97e34942016-07-11 14:46:27 -050063 // For each LSA represented in the map
Vince Lehman9a709032014-09-13 16:28:07 -050064 for (std::list<AdjLsa>::iterator it = adjLsdb.begin(); it != adjLsdb.end() ; it++) {
65
Nick G97e34942016-07-11 14:46:27 -050066
Nick Gordone40377d2017-08-11 15:10:02 -050067 ndn::optional<int32_t> row = pMap.getMappingNoByRouterName((*it).getOrigRouter());
Vince Lehman9a709032014-09-13 16:28:07 -050068
akmhoque53353462014-04-22 08:43:45 -050069 std::list<Adjacent> adl = (*it).getAdl().getAdjList();
Nick G97e34942016-07-11 14:46:27 -050070 // For each adjacency represented in the LSA
Vince Lehman9a709032014-09-13 16:28:07 -050071 for (std::list<Adjacent>::iterator itAdl = adl.begin(); itAdl != adl.end() ; itAdl++) {
72
Nick Gordone40377d2017-08-11 15:10:02 -050073 ndn::optional<int32_t> col = pMap.getMappingNoByRouterName((*itAdl).getName());
akmhoque53353462014-04-22 08:43:45 -050074 double cost = (*itAdl).getLinkCost();
Vince Lehman9a709032014-09-13 16:28:07 -050075
Nick Gordone40377d2017-08-11 15:10:02 -050076 if (row && col && *row < static_cast<int32_t>(m_nRouters)
77 && *col < static_cast<int32_t>(m_nRouters))
Vince Lehman9a709032014-09-13 16:28:07 -050078 {
Nick Gordone40377d2017-08-11 15:10:02 -050079 adjMatrix[*row][*col] = cost;
akmhoque53353462014-04-22 08:43:45 -050080 }
81 }
82 }
Vince Lehman41b173e2015-05-07 14:13:26 -050083
Nick G97e34942016-07-11 14:46:27 -050084 // Links that do not have the same cost for both directions should
85 // have their costs corrected:
Vince Lehman41b173e2015-05-07 14:13:26 -050086 //
Nick G97e34942016-07-11 14:46:27 -050087 // If the cost of one side of the link is 0, both sides of the
88 // link should have their cost corrected to 0.
Vince Lehman41b173e2015-05-07 14:13:26 -050089 //
90 // Otherwise, both sides of the link should use the larger of the two costs.
91 //
Nick G97e34942016-07-11 14:46:27 -050092 // Additionally, this means that we can halve the amount of space
93 // that the matrix uses by only maintaining a triangle.
94 // - But that is not yet implemented.
Vince Lehman41b173e2015-05-07 14:13:26 -050095 for (size_t row = 0; row < m_nRouters; ++row) {
96 for (size_t col = 0; col < m_nRouters; ++col) {
97 double toCost = adjMatrix[row][col];
98 double fromCost = adjMatrix[col][row];
99
100 if (fromCost != toCost) {
101 double correctedCost = 0.0;
102
103 if (toCost != 0 && fromCost != 0) {
104 // If both sides of the link are up, use the larger cost
105 correctedCost = std::max(toCost, fromCost);
106 }
107
dmcoomes5bcb39e2017-10-31 15:07:55 -0500108 NLSR_LOG_WARN("Cost between [" << row << "][" << col << "] and [" << col << "][" << row <<
Vince Lehman41b173e2015-05-07 14:13:26 -0500109 "] are not the same (" << toCost << " != " << fromCost << "). " <<
110 "Correcting to cost: " << correctedCost);
111
112 adjMatrix[row][col] = correctedCost;
113 adjMatrix[col][row] = correctedCost;
114 }
115 }
116 }
akmhoque53353462014-04-22 08:43:45 -0500117}
118
119void
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000120RoutingTableCalculator::writeAdjMatrixLog(const Map& map) const
akmhoque53353462014-04-22 08:43:45 -0500121{
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000122 if (!getNdnCxxLogger().isLevelEnabled(ndn::util::LogLevel::DEBUG)) {
123 return;
124 }
125
126 NLSR_LOG_DEBUG("-----------Legend (routerName -> index)------");
127 std::string routerIndex;
128 std::string indexToNameMapping;
129 std::string lengthOfDash = "--";
130
Vince Lehman9a709032014-09-13 16:28:07 -0500131 for (size_t i = 0; i < m_nRouters; i++) {
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000132 routerIndex += boost::lexical_cast<std::string>(i);
133 routerIndex += " ";
134 lengthOfDash += "--";
135 NLSR_LOG_DEBUG("Router:" + map.getRouterNameByMappingNo(i)->toUri() +
136 "Index:" + boost::lexical_cast<std::string>(i));
137 }
138 NLSR_LOG_DEBUG(" |" + routerIndex);
139 NLSR_LOG_DEBUG(lengthOfDash);
140
141 for (size_t i = 0; i < m_nRouters; i++) {
142 std::string line;
Vince Lehman9a709032014-09-13 16:28:07 -0500143 for (size_t j = 0; j < m_nRouters; j++) {
akmhoque2f423352014-06-03 11:49:35 -0500144 line += boost::lexical_cast<std::string>(adjMatrix[i][j]);
145 line += " ";
akmhoque157b0a42014-05-13 00:26:37 -0500146 }
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000147 line = boost::lexical_cast<std::string>(i) + "|" + line;
dmcoomes5bcb39e2017-10-31 15:07:55 -0500148 NLSR_LOG_DEBUG(line);
akmhoque53353462014-04-22 08:43:45 -0500149 }
150}
151
152void
153RoutingTableCalculator::adjustAdMatrix(int source, int link, double linkCost)
154{
Vince Lehman9a709032014-09-13 16:28:07 -0500155 for (int i = 0; i < static_cast<int>(m_nRouters); i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500156 if (i == link) {
akmhoque53353462014-04-22 08:43:45 -0500157 adjMatrix[source][i] = linkCost;
158 }
akmhoque157b0a42014-05-13 00:26:37 -0500159 else {
akmhoque53353462014-04-22 08:43:45 -0500160 adjMatrix[source][i] = 0;
161 }
162 }
163}
164
165int
166RoutingTableCalculator::getNumOfLinkfromAdjMatrix(int sRouter)
167{
168 int noLink = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500169
170 for (size_t i = 0; i < m_nRouters; i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500171 if (adjMatrix[sRouter][i] > 0) {
akmhoque53353462014-04-22 08:43:45 -0500172 noLink++;
173 }
174 }
175 return noLink;
176}
177
178void
179RoutingTableCalculator::getLinksFromAdjMatrix(int* links,
180 double* linkCosts, int source)
181{
182 int j = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500183
184 for (size_t i = 0; i < m_nRouters; i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500185 if (adjMatrix[source][i] > 0) {
akmhoque53353462014-04-22 08:43:45 -0500186 links[j] = i;
187 linkCosts[j] = adjMatrix[source][i];
188 j++;
189 }
190 }
191}
192
193void
194RoutingTableCalculator::freeAdjMatrix()
195{
Vince Lehman9a709032014-09-13 16:28:07 -0500196 for (size_t i = 0; i < m_nRouters; ++i) {
akmhoque53353462014-04-22 08:43:45 -0500197 delete [] adjMatrix[i];
198 }
199 delete [] adjMatrix;
200}
201
akmhoque53353462014-04-22 08:43:45 -0500202void
203RoutingTableCalculator::allocateLinks()
204{
205 links = new int[vNoLink];
206}
207
208void
209RoutingTableCalculator::allocateLinkCosts()
210{
211 linkCosts = new double[vNoLink];
212}
213
214
215void
216RoutingTableCalculator::freeLinks()
217{
218 delete [] links;
219}
220void
221RoutingTableCalculator::freeLinksCosts()
222{
223 delete [] linkCosts;
224}
225
226void
227LinkStateRoutingTableCalculator::calculatePath(Map& pMap,
228 RoutingTable& rt, Nlsr& pnlsr)
229{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500230 NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::calculatePath Called");
akmhoque53353462014-04-22 08:43:45 -0500231 allocateAdjMatrix();
232 initMatrix();
233 makeAdjMatrix(pnlsr, pMap);
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000234 writeAdjMatrixLog(pMap);
Nick Gordone40377d2017-08-11 15:10:02 -0500235 ndn::optional<int32_t> sourceRouter =
236 pMap.getMappingNoByRouterName(pnlsr.getConfParameter().getRouterPrefix());
Nick G97e34942016-07-11 14:46:27 -0500237 allocateParent(); // These two matrices are used in Dijkstra's algorithm.
238 allocateDistance(); //
Nick Gordone40377d2017-08-11 15:10:02 -0500239 // We only bother to do the calculation if we have a router by that name.
240 if (sourceRouter && pnlsr.getConfParameter().getMaxFacesPerPrefix() == 1) {
Nick G97e34942016-07-11 14:46:27 -0500241 // In the single path case we can simply run Dijkstra's algorithm.
Nick Gordone40377d2017-08-11 15:10:02 -0500242 doDijkstraPathCalculation(*sourceRouter);
Nick G97e34942016-07-11 14:46:27 -0500243 // Inform the routing table of the new next hops.
Nick Gordone40377d2017-08-11 15:10:02 -0500244 addAllLsNextHopsToRoutingTable(pnlsr, rt, pMap, *sourceRouter);
akmhoque53353462014-04-22 08:43:45 -0500245 }
akmhoque157b0a42014-05-13 00:26:37 -0500246 else {
akmhoque53353462014-04-22 08:43:45 -0500247 // Multi Path
Nick Gordone40377d2017-08-11 15:10:02 -0500248 setNoLink(getNumOfLinkfromAdjMatrix(*sourceRouter));
akmhoque53353462014-04-22 08:43:45 -0500249 allocateLinks();
250 allocateLinkCosts();
Nick G97e34942016-07-11 14:46:27 -0500251 // Gets a sparse listing of adjacencies for path calculation
Nick Gordone40377d2017-08-11 15:10:02 -0500252 getLinksFromAdjMatrix(links, linkCosts, *sourceRouter);
akmhoque157b0a42014-05-13 00:26:37 -0500253 for (int i = 0 ; i < vNoLink; i++) {
Nick G97e34942016-07-11 14:46:27 -0500254 // Simulate that only the current neighbor is accessible
Nick Gordone40377d2017-08-11 15:10:02 -0500255 adjustAdMatrix(*sourceRouter, links[i], linkCosts[i]);
Saurab Dulal9da6aa72018-01-12 17:25:51 +0000256 writeAdjMatrixLog(pMap);
Nick G97e34942016-07-11 14:46:27 -0500257 // Do Dijkstra's algorithm using the current neighbor as your start.
Nick Gordone40377d2017-08-11 15:10:02 -0500258 doDijkstraPathCalculation(*sourceRouter);
Nick G97e34942016-07-11 14:46:27 -0500259 // Update the routing table with the calculations.
Nick Gordone40377d2017-08-11 15:10:02 -0500260 addAllLsNextHopsToRoutingTable(pnlsr, rt, pMap, *sourceRouter);
akmhoque53353462014-04-22 08:43:45 -0500261 }
262 freeLinks();
263 freeLinksCosts();
264 }
265 freeParent();
266 freeDistance();
267 freeAdjMatrix();
268}
269
270void
271LinkStateRoutingTableCalculator::doDijkstraPathCalculation(int sourceRouter)
272{
273 int i;
274 int v, u;
Nick G97e34942016-07-11 14:46:27 -0500275 int* Q = new int[m_nRouters]; // Each cell represents the router with that mapping no.
akmhoque53353462014-04-22 08:43:45 -0500276 int head = 0;
Nick Gordone98480b2017-05-24 11:23:03 -0500277 // Initiate the parent
Vince Lehman9a709032014-09-13 16:28:07 -0500278 for (i = 0 ; i < static_cast<int>(m_nRouters); i++) {
akmhoque53353462014-04-22 08:43:45 -0500279 m_parent[i] = EMPTY_PARENT;
Nick G97e34942016-07-11 14:46:27 -0500280 // Array where the ith element is the distance to the router with mapping no i.
akmhoque53353462014-04-22 08:43:45 -0500281 m_distance[i] = INF_DISTANCE;
282 Q[i] = i;
283 }
akmhoque157b0a42014-05-13 00:26:37 -0500284 if (sourceRouter != NO_MAPPING_NUM) {
Nick G97e34942016-07-11 14:46:27 -0500285 // Distance to source from source is always 0.
akmhoque53353462014-04-22 08:43:45 -0500286 m_distance[sourceRouter] = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500287 sortQueueByDistance(Q, m_distance, head, m_nRouters);
Nick G97e34942016-07-11 14:46:27 -0500288 // While we haven't visited every node.
Vince Lehman9a709032014-09-13 16:28:07 -0500289 while (head < static_cast<int>(m_nRouters)) {
Nick G97e34942016-07-11 14:46:27 -0500290 u = Q[head]; // Set u to be the current node pointed to by head.
akmhoque157b0a42014-05-13 00:26:37 -0500291 if (m_distance[u] == INF_DISTANCE) {
Nick G97e34942016-07-11 14:46:27 -0500292 break; // This can only happen when there are no accessible nodes.
akmhoque53353462014-04-22 08:43:45 -0500293 }
Nick G97e34942016-07-11 14:46:27 -0500294 // Iterate over the adjacent nodes to u.
Vince Lehman9a709032014-09-13 16:28:07 -0500295 for (v = 0 ; v < static_cast<int>(m_nRouters); v++) {
Nick G97e34942016-07-11 14:46:27 -0500296 // If the current node is accessible.
akmhoque157b0a42014-05-13 00:26:37 -0500297 if (adjMatrix[u][v] > 0) {
Nick G97e34942016-07-11 14:46:27 -0500298 // And we haven't visited it yet.
Vince Lehman9a709032014-09-13 16:28:07 -0500299 if (isNotExplored(Q, v, head + 1, m_nRouters)) {
Nick G97e34942016-07-11 14:46:27 -0500300 // And if the distance to this node + from this node to v
301 // is less than the distance from our source node to v
302 // that we got when we built the adj LSAs
akmhoque157b0a42014-05-13 00:26:37 -0500303 if (m_distance[u] + adjMatrix[u][v] < m_distance[v]) {
Nick G97e34942016-07-11 14:46:27 -0500304 // Set the new distance
akmhoque53353462014-04-22 08:43:45 -0500305 m_distance[v] = m_distance[u] + adjMatrix[u][v] ;
Nick G97e34942016-07-11 14:46:27 -0500306 // Set how we get there.
akmhoque53353462014-04-22 08:43:45 -0500307 m_parent[v] = u;
308 }
309 }
310 }
311 }
Nick G97e34942016-07-11 14:46:27 -0500312 // Increment the head position, resort the list by distance from where we are.
akmhoque53353462014-04-22 08:43:45 -0500313 head++;
Vince Lehman9a709032014-09-13 16:28:07 -0500314 sortQueueByDistance(Q, m_distance, head, m_nRouters);
akmhoque53353462014-04-22 08:43:45 -0500315 }
316 }
317 delete [] Q;
318}
319
320void
Vince Lehman9a709032014-09-13 16:28:07 -0500321LinkStateRoutingTableCalculator::addAllLsNextHopsToRoutingTable(Nlsr& pnlsr, RoutingTable& rt,
322 Map& pMap, uint32_t sourceRouter)
akmhoque53353462014-04-22 08:43:45 -0500323{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500324 NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::addAllNextHopsToRoutingTable Called");
Vince Lehman9a709032014-09-13 16:28:07 -0500325
akmhoque53353462014-04-22 08:43:45 -0500326 int nextHopRouter = 0;
Vince Lehman9a709032014-09-13 16:28:07 -0500327
Nick G97e34942016-07-11 14:46:27 -0500328 // For each router we have
Vince Lehman9a709032014-09-13 16:28:07 -0500329 for (size_t i = 0; i < m_nRouters ; i++) {
akmhoque157b0a42014-05-13 00:26:37 -0500330 if (i != sourceRouter) {
Vince Lehman9a709032014-09-13 16:28:07 -0500331
Nick G97e34942016-07-11 14:46:27 -0500332 // Obtain the next hop that was determined by the algorithm
akmhoque53353462014-04-22 08:43:45 -0500333 nextHopRouter = getLsNextHop(i, sourceRouter);
Vince Lehman9a709032014-09-13 16:28:07 -0500334
Nick G97e34942016-07-11 14:46:27 -0500335 // If this router is accessible at all
akmhoque157b0a42014-05-13 00:26:37 -0500336 if (nextHopRouter != NO_NEXT_HOP) {
Vince Lehman9a709032014-09-13 16:28:07 -0500337
Nick G97e34942016-07-11 14:46:27 -0500338 // Fetch its distance
akmhoque53353462014-04-22 08:43:45 -0500339 double routeCost = m_distance[i];
Nick G97e34942016-07-11 14:46:27 -0500340 // Fetch its actual name
Nick Gordone40377d2017-08-11 15:10:02 -0500341 ndn::optional<ndn::Name> nextHopRouterName= pMap.getRouterNameByMappingNo(nextHopRouter);
342 if (nextHopRouterName) {
343 std::string nextHopFace =
344 pnlsr.getAdjacencyList().getAdjacent(*nextHopRouterName).getFaceUri().toString();
345 // Add next hop to routing table
346 NextHop nh(nextHopFace, routeCost);
347 rt.addNextHop(*(pMap.getRouterNameByMappingNo(i)), nh);
348
349 }
akmhoque53353462014-04-22 08:43:45 -0500350 }
351 }
352 }
353}
354
355int
356LinkStateRoutingTableCalculator::getLsNextHop(int dest, int source)
357{
358 int nextHop = NO_NEXT_HOP;
akmhoque157b0a42014-05-13 00:26:37 -0500359 while (m_parent[dest] != EMPTY_PARENT) {
akmhoque53353462014-04-22 08:43:45 -0500360 nextHop = dest;
361 dest = m_parent[dest];
362 }
akmhoque157b0a42014-05-13 00:26:37 -0500363 if (dest != source) {
akmhoque53353462014-04-22 08:43:45 -0500364 nextHop = NO_NEXT_HOP;
365 }
366 return nextHop;
367}
368
369void
akmhoque53353462014-04-22 08:43:45 -0500370LinkStateRoutingTableCalculator::sortQueueByDistance(int* Q,
akmhoque2f423352014-06-03 11:49:35 -0500371 double* dist,
372 int start, int element)
akmhoque53353462014-04-22 08:43:45 -0500373{
akmhoque157b0a42014-05-13 00:26:37 -0500374 for (int i = start ; i < element ; i++) {
375 for (int j = i + 1; j < element; j++) {
376 if (dist[Q[j]] < dist[Q[i]]) {
akmhoque53353462014-04-22 08:43:45 -0500377 int tempU = Q[j];
378 Q[j] = Q[i];
379 Q[i] = tempU;
380 }
381 }
382 }
383}
384
385int
386LinkStateRoutingTableCalculator::isNotExplored(int* Q,
387 int u, int start, int element)
388{
389 int ret = 0;
akmhoque157b0a42014-05-13 00:26:37 -0500390 for (int i = start; i < element; i++) {
391 if (Q[i] == u) {
akmhoque53353462014-04-22 08:43:45 -0500392 ret = 1;
393 break;
394 }
395 }
396 return ret;
397}
398
399void
400LinkStateRoutingTableCalculator::allocateParent()
401{
Vince Lehman9a709032014-09-13 16:28:07 -0500402 m_parent = new int[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -0500403}
404
405void
406LinkStateRoutingTableCalculator::allocateDistance()
407{
Vince Lehman9a709032014-09-13 16:28:07 -0500408 m_distance = new double[m_nRouters];
akmhoque53353462014-04-22 08:43:45 -0500409}
410
411void
412LinkStateRoutingTableCalculator::freeParent()
413{
414 delete [] m_parent;
415}
416
417void LinkStateRoutingTableCalculator::freeDistance()
418{
419 delete [] m_distance;
420}
421
Vince Lehman9a709032014-09-13 16:28:07 -0500422const double HyperbolicRoutingCalculator::MATH_PI = boost::math::constants::pi<double>();
akmhoque53353462014-04-22 08:43:45 -0500423
Vince Lehman9a709032014-09-13 16:28:07 -0500424const double HyperbolicRoutingCalculator::UNKNOWN_DISTANCE = -1.0;
425const double HyperbolicRoutingCalculator::UNKNOWN_RADIUS = -1.0;
426
akmhoque53353462014-04-22 08:43:45 -0500427void
Vince Lehman9a709032014-09-13 16:28:07 -0500428HyperbolicRoutingCalculator::calculatePaths(Map& map, RoutingTable& rt,
429 Lsdb& lsdb, AdjacencyList& adjacencies)
akmhoque53353462014-04-22 08:43:45 -0500430{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500431 NLSR_LOG_TRACE("Calculating hyperbolic paths");
Vince Lehman9a709032014-09-13 16:28:07 -0500432
Nick Gordone40377d2017-08-11 15:10:02 -0500433 ndn::optional<int32_t> thisRouter = map.getMappingNoByRouterName(m_thisRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500434
435 // Iterate over directly connected neighbors
436 std::list<Adjacent> neighbors = adjacencies.getAdjList();
437 for (std::list<Adjacent>::iterator adj = neighbors.begin(); adj != neighbors.end(); ++adj) {
438
439 // Don't calculate nexthops using an inactive router
440 if (adj->getStatus() == Adjacent::STATUS_INACTIVE) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500441 NLSR_LOG_TRACE(adj->getName() << " is inactive; not using it as a nexthop");
Vince Lehman9a709032014-09-13 16:28:07 -0500442 continue;
443 }
444
445 ndn::Name srcRouterName = adj->getName();
446
447 // Don't calculate nexthops for this router to other routers
448 if (srcRouterName == m_thisRouterName) {
449 continue;
450 }
451
Nick Gordone9733ed2017-04-26 10:48:39 -0500452 std::string srcFaceUri = adj->getFaceUri().toString();
Vince Lehman9a709032014-09-13 16:28:07 -0500453
454 // Install nexthops for this router to the neighbor; direct neighbors have a 0 cost link
455 addNextHop(srcRouterName, srcFaceUri, 0, rt);
456
Nick Gordone40377d2017-08-11 15:10:02 -0500457 ndn::optional<int32_t> src = map.getMappingNoByRouterName(srcRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500458
Nick Gordone40377d2017-08-11 15:10:02 -0500459 if (!src) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500460 NLSR_LOG_WARN(adj->getName() << " does not exist in the router map!");
Vince Lehman9a709032014-09-13 16:28:07 -0500461 continue;
462 }
463
464 // Get hyperbolic distance from direct neighbor to every other router
465 for (int dest = 0; dest < static_cast<int>(m_nRouters); ++dest) {
466 // Don't calculate nexthops to this router or from a router to itself
Nick Gordone40377d2017-08-11 15:10:02 -0500467 if (thisRouter && dest != *thisRouter && dest != *src) {
Vince Lehman9a709032014-09-13 16:28:07 -0500468
Nick Gordone40377d2017-08-11 15:10:02 -0500469 ndn::optional<ndn::Name> destRouterName = map.getRouterNameByMappingNo(dest);
470 if (destRouterName) {
471 double distance = getHyperbolicDistance(map, lsdb, srcRouterName, *destRouterName);
Vince Lehman9a709032014-09-13 16:28:07 -0500472
Nick Gordone40377d2017-08-11 15:10:02 -0500473 // Could not compute distance
474 if (distance == UNKNOWN_DISTANCE) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500475 NLSR_LOG_WARN("Could not calculate hyperbolic distance from " << srcRouterName << " to " <<
Nick Gordone40377d2017-08-11 15:10:02 -0500476 *destRouterName);
477 continue;
478 }
Vince Lehman9a709032014-09-13 16:28:07 -0500479
Nick Gordone40377d2017-08-11 15:10:02 -0500480 addNextHop(*destRouterName, srcFaceUri, distance, rt);
akmhoque53353462014-04-22 08:43:45 -0500481 }
Vince Lehman9a709032014-09-13 16:28:07 -0500482 }
akmhoquedcee9362014-08-05 22:58:01 -0500483 }
akmhoque53353462014-04-22 08:43:45 -0500484 }
485}
486
487double
Vince Lehman9a709032014-09-13 16:28:07 -0500488HyperbolicRoutingCalculator::getHyperbolicDistance(Map& map, Lsdb& lsdb,
489 ndn::Name src, ndn::Name dest)
akmhoque53353462014-04-22 08:43:45 -0500490{
dmcoomes5bcb39e2017-10-31 15:07:55 -0500491 NLSR_LOG_TRACE("Calculating hyperbolic distance from " << src << " to " << dest);
akmhoquedcee9362014-08-05 22:58:01 -0500492
Vince Lehman9a709032014-09-13 16:28:07 -0500493 double distance = UNKNOWN_DISTANCE;
494
495 ndn::Name srcLsaKey = src;
Nick Gordon727d4832017-10-13 18:04:25 -0500496 srcLsaKey.append(std::to_string(Lsa::Type::COORDINATE));
Vince Lehman9a709032014-09-13 16:28:07 -0500497
498 CoordinateLsa* srcLsa = lsdb.findCoordinateLsa(srcLsaKey);
499
500 ndn::Name destLsaKey = dest;
Nick Gordon727d4832017-10-13 18:04:25 -0500501 destLsaKey.append(std::to_string(Lsa::Type::COORDINATE));
Vince Lehman9a709032014-09-13 16:28:07 -0500502
503 CoordinateLsa* destLsa = lsdb.findCoordinateLsa(destLsaKey);
504
505 // Coordinate LSAs do not exist for these routers
Nick Gordone9733ed2017-04-26 10:48:39 -0500506 if (srcLsa == nullptr || destLsa == nullptr) {
Vince Lehman9a709032014-09-13 16:28:07 -0500507 return UNKNOWN_DISTANCE;
akmhoquedcee9362014-08-05 22:58:01 -0500508 }
509
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600510 std::vector<double> srcTheta = srcLsa->getCorTheta();
511 std::vector<double> destTheta = destLsa->getCorTheta();
Vince Lehman9a709032014-09-13 16:28:07 -0500512
513 double srcRadius = srcLsa->getCorRadius();
514 double destRadius = destLsa->getCorRadius();
515
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600516 double diffTheta = calculateAngularDistance(srcTheta, destTheta);
517
518 if (srcRadius == UNKNOWN_RADIUS || destRadius == UNKNOWN_RADIUS ||
519 diffTheta == UNKNOWN_DISTANCE) {
Vince Lehman9a709032014-09-13 16:28:07 -0500520 return UNKNOWN_DISTANCE;
521 }
522
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600523 // double r_i, double r_j, double delta_theta, double zeta = 1 (default)
524 distance = calculateHyperbolicDistance(srcRadius, destRadius, diffTheta);
Vince Lehman9a709032014-09-13 16:28:07 -0500525
dmcoomes5bcb39e2017-10-31 15:07:55 -0500526 NLSR_LOG_TRACE("Distance from " << src << " to " << dest << " is " << distance);
Vince Lehman9a709032014-09-13 16:28:07 -0500527
akmhoque53353462014-04-22 08:43:45 -0500528 return distance;
529}
530
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600531double
532HyperbolicRoutingCalculator::calculateAngularDistance(std::vector<double> angleVectorI,
533 std::vector<double> angleVectorJ)
534{
535 // It is not possible for angle vector size to be zero as ensured by conf-file-processor
536
537 // https://en.wikipedia.org/wiki/N-sphere#Spherical_coordinates
538
539 // Check if two vector lengths are the same
540 if (angleVectorI.size() != angleVectorJ.size()) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500541 NLSR_LOG_ERROR("Angle vector sizes do not match");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600542 return UNKNOWN_DISTANCE;
543 }
544
545 // Check if all angles are within the [0, PI] and [0, 2PI] ranges
546 if (angleVectorI.size() > 1) {
547 for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
548 if ((angleVectorI[k] > M_PI && angleVectorI[k] < 0.0) ||
549 (angleVectorJ[k] > M_PI && angleVectorJ[k] < 0.0)) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500550 NLSR_LOG_ERROR("Angle outside [0, PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600551 return UNKNOWN_DISTANCE;
552 }
553 }
554 }
555 if (angleVectorI[angleVectorI.size()-1] > 2.*M_PI ||
556 angleVectorI[angleVectorI.size()-1] < 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500557 NLSR_LOG_ERROR("Angle not within [0, 2PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600558 return UNKNOWN_DISTANCE;
559 }
560
561 if (angleVectorI[angleVectorI.size()-1] > 2.*M_PI ||
562 angleVectorI[angleVectorI.size()-1] < 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500563 NLSR_LOG_ERROR("Angle not within [0, 2PI]");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600564 return UNKNOWN_DISTANCE;
565 }
566
567 // deltaTheta = arccos(vectorI . vectorJ) -> do the inner product
568 double innerProduct = 0.0;
569
570 // Calculate x0 of the vectors
571 double x0i = std::cos(angleVectorI[0]);
572 double x0j = std::cos(angleVectorJ[0]);
573
574 // Calculate xn of the vectors
575 double xni = std::sin(angleVectorI[angleVectorI.size() - 1]);
576 double xnj = std::sin(angleVectorJ[angleVectorJ.size() - 1]);
577
578 // Do the aggregation of the (n-1) coordinates (if there is more than one angle)
579 // i.e contraction of all (n-1)-dimensional angular coordinates to one variable
580 for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
581 xni *= std::sin(angleVectorI[k]);
582 xnj *= std::sin(angleVectorJ[k]);
583 }
584 innerProduct += (x0i * x0j) + (xni * xnj);
585
586 // If d > 1
587 if (angleVectorI.size() > 1) {
588 for (unsigned int m = 1; m < angleVectorI.size(); m++) {
589 // calculate euclidean coordinates given the angles and assuming R_sphere = 1
590 double xmi = std::cos(angleVectorI[m]);
591 double xmj = std::cos(angleVectorJ[m]);
592 for (unsigned int l = 0; l < m; l++) {
593 xmi *= std::sin(angleVectorI[l]);
594 xmj *= std::sin(angleVectorJ[l]);
595 }
596 innerProduct += xmi * xmj;
597 }
598 }
599
600 // ArcCos of the inner product gives the angular distance
601 // between two points on a d-dimensional sphere
602 return std::acos(innerProduct);
603}
604
605double
606HyperbolicRoutingCalculator::calculateHyperbolicDistance(double rI, double rJ,
607 double deltaTheta)
608{
609 if (deltaTheta == UNKNOWN_DISTANCE) {
610 return UNKNOWN_DISTANCE;
611 }
612
613 // Usually, we set zeta = 1 in all experiments
614 double zeta = 1;
615
616 if (deltaTheta <= 0.0 || rI <= 0.0 || rJ <= 0.0) {
dmcoomes5bcb39e2017-10-31 15:07:55 -0500617 NLSR_LOG_ERROR("Delta theta or rI or rJ is <= 0");
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600618 return UNKNOWN_DISTANCE;
619 }
620
621 double xij = (1. / zeta) * std::acosh(std::cosh(zeta*rI) * std::cosh(zeta*rJ) -
622 std::sinh(zeta*rI)*std::sinh(zeta*rJ)*std::cos(deltaTheta));
623 return xij;
624}
625
626void
627HyperbolicRoutingCalculator::addNextHop(ndn::Name dest, std::string faceUri,
628 double cost, RoutingTable& rt)
akmhoque53353462014-04-22 08:43:45 -0500629{
Vince Lehman9a709032014-09-13 16:28:07 -0500630 NextHop hop(faceUri, cost);
Vince Lehman20fe4a92014-09-09 15:57:59 -0500631 hop.setHyperbolic(true);
akmhoque53353462014-04-22 08:43:45 -0500632
dmcoomes5bcb39e2017-10-31 15:07:55 -0500633 NLSR_LOG_TRACE("Calculated " << hop << " for destination: " << dest);
akmhoque53353462014-04-22 08:43:45 -0500634
Vince Lehman9a709032014-09-13 16:28:07 -0500635 if (m_isDryRun) {
636 rt.addNextHopToDryTable(dest, hop);
637 }
638 else {
639 rt.addNextHop(dest, hop);
640 }
akmhoque53353462014-04-22 08:43:45 -0500641}
642
Nick Gordonfad8e252016-08-11 14:21:38 -0500643} // namespace nlsr