routing-table-calculator.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
23 #include "lsdb.hpp"
24 #include "map.hpp"
25 #include "lsa.hpp"
26 #include "nexthop.hpp"
27 #include "nlsr.hpp"
28 #include "logger.hpp"
29 
30 #include <iostream>
31 #include <boost/math/constants/constants.hpp>
32 #include <cmath>
33 
34 namespace nlsr {
35 
36 INIT_LOGGER("RoutingTableCalculator");
37 
38 void
40 {
41  adjMatrix = new double*[m_nRouters];
42 
43  for (size_t i = 0; i < m_nRouters; ++i) {
44  adjMatrix[i] = new double[m_nRouters];
45  }
46 }
47 
48 void
50 {
51  for (size_t i = 0; i < m_nRouters; i++) {
52  for (size_t j = 0; j < m_nRouters; j++) {
53  adjMatrix[i][j] = 0;
54  }
55  }
56 }
57 
58 void
60 {
61  std::list<AdjLsa> adjLsdb = pnlsr.getLsdb().getAdjLsdb();
62  // For each LSA represented in the map
63  for (std::list<AdjLsa>::iterator it = adjLsdb.begin(); it != adjLsdb.end() ; it++) {
64 
65 
66  ndn::optional<int32_t> row = pMap.getMappingNoByRouterName((*it).getOrigRouter());
67 
68  std::list<Adjacent> adl = (*it).getAdl().getAdjList();
69  // For each adjacency represented in the LSA
70  for (std::list<Adjacent>::iterator itAdl = adl.begin(); itAdl != adl.end() ; itAdl++) {
71 
72  ndn::optional<int32_t> col = pMap.getMappingNoByRouterName((*itAdl).getName());
73  double cost = (*itAdl).getLinkCost();
74 
75  if (row && col && *row < static_cast<int32_t>(m_nRouters)
76  && *col < static_cast<int32_t>(m_nRouters))
77  {
78  adjMatrix[*row][*col] = cost;
79  }
80  }
81  }
82 
83  // Links that do not have the same cost for both directions should
84  // have their costs corrected:
85  //
86  // If the cost of one side of the link is 0, both sides of the
87  // link should have their cost corrected to 0.
88  //
89  // Otherwise, both sides of the link should use the larger of the two costs.
90  //
91  // Additionally, this means that we can halve the amount of space
92  // that the matrix uses by only maintaining a triangle.
93  // - But that is not yet implemented.
94  for (size_t row = 0; row < m_nRouters; ++row) {
95  for (size_t col = 0; col < m_nRouters; ++col) {
96  double toCost = adjMatrix[row][col];
97  double fromCost = adjMatrix[col][row];
98 
99  if (fromCost != toCost) {
100  double correctedCost = 0.0;
101 
102  if (toCost != 0 && fromCost != 0) {
103  // If both sides of the link are up, use the larger cost
104  correctedCost = std::max(toCost, fromCost);
105  }
106 
107  NLSR_LOG_WARN("Cost between [" << row << "][" << col << "] and [" << col << "][" << row <<
108  "] are not the same (" << toCost << " != " << fromCost << "). " <<
109  "Correcting to cost: " << correctedCost);
110 
111  adjMatrix[row][col] = correctedCost;
112  adjMatrix[col][row] = correctedCost;
113  }
114  }
115  }
116 }
117 
118 void
120 {
121  for (size_t i = 0; i < m_nRouters; i++) {
122  std::string line="";
123  for (size_t j = 0; j < m_nRouters; j++) {
124  line += boost::lexical_cast<std::string>(adjMatrix[i][j]);
125  line += " ";
126  }
127  NLSR_LOG_DEBUG(line);
128  }
129 }
130 
131 void
132 RoutingTableCalculator::adjustAdMatrix(int source, int link, double linkCost)
133 {
134  for (int i = 0; i < static_cast<int>(m_nRouters); i++) {
135  if (i == link) {
136  adjMatrix[source][i] = linkCost;
137  }
138  else {
139  adjMatrix[source][i] = 0;
140  }
141  }
142 }
143 
144 int
146 {
147  int noLink = 0;
148 
149  for (size_t i = 0; i < m_nRouters; i++) {
150  if (adjMatrix[sRouter][i] > 0) {
151  noLink++;
152  }
153  }
154  return noLink;
155 }
156 
157 void
159  double* linkCosts, int source)
160 {
161  int j = 0;
162 
163  for (size_t i = 0; i < m_nRouters; i++) {
164  if (adjMatrix[source][i] > 0) {
165  links[j] = i;
166  linkCosts[j] = adjMatrix[source][i];
167  j++;
168  }
169  }
170 }
171 
172 void
174 {
175  for (size_t i = 0; i < m_nRouters; ++i) {
176  delete [] adjMatrix[i];
177  }
178  delete [] adjMatrix;
179 }
180 
181 void
183 {
184  links = new int[vNoLink];
185 }
186 
187 void
189 {
190  linkCosts = new double[vNoLink];
191 }
192 
193 
194 void
196 {
197  delete [] links;
198 }
199 void
201 {
202  delete [] linkCosts;
203 }
204 
205 void
207  RoutingTable& rt, Nlsr& pnlsr)
208 {
209  NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::calculatePath Called");
211  initMatrix();
212  makeAdjMatrix(pnlsr, pMap);
214  ndn::optional<int32_t> sourceRouter =
216  allocateParent(); // These two matrices are used in Dijkstra's algorithm.
217  allocateDistance(); //
218  // We only bother to do the calculation if we have a router by that name.
219  if (sourceRouter && pnlsr.getConfParameter().getMaxFacesPerPrefix() == 1) {
220  // In the single path case we can simply run Dijkstra's algorithm.
221  doDijkstraPathCalculation(*sourceRouter);
222  // Inform the routing table of the new next hops.
223  addAllLsNextHopsToRoutingTable(pnlsr, rt, pMap, *sourceRouter);
224  }
225  else {
226  // Multi Path
227  setNoLink(getNumOfLinkfromAdjMatrix(*sourceRouter));
228  allocateLinks();
230  // Gets a sparse listing of adjacencies for path calculation
231  getLinksFromAdjMatrix(links, linkCosts, *sourceRouter);
232  for (int i = 0 ; i < vNoLink; i++) {
233  // Simulate that only the current neighbor is accessible
234  adjustAdMatrix(*sourceRouter, links[i], linkCosts[i]);
236  // Do Dijkstra's algorithm using the current neighbor as your start.
237  doDijkstraPathCalculation(*sourceRouter);
238  // Update the routing table with the calculations.
239  addAllLsNextHopsToRoutingTable(pnlsr, rt, pMap, *sourceRouter);
240  }
241  freeLinks();
242  freeLinksCosts();
243  }
244  freeParent();
245  freeDistance();
246  freeAdjMatrix();
247 }
248 
249 void
250 LinkStateRoutingTableCalculator::doDijkstraPathCalculation(int sourceRouter)
251 {
252  int i;
253  int v, u;
254  int* Q = new int[m_nRouters]; // Each cell represents the router with that mapping no.
255  int head = 0;
256  // Initiate the parent
257  for (i = 0 ; i < static_cast<int>(m_nRouters); i++) {
258  m_parent[i] = EMPTY_PARENT;
259  // Array where the ith element is the distance to the router with mapping no i.
260  m_distance[i] = INF_DISTANCE;
261  Q[i] = i;
262  }
263  if (sourceRouter != NO_MAPPING_NUM) {
264  // Distance to source from source is always 0.
265  m_distance[sourceRouter] = 0;
266  sortQueueByDistance(Q, m_distance, head, m_nRouters);
267  // While we haven't visited every node.
268  while (head < static_cast<int>(m_nRouters)) {
269  u = Q[head]; // Set u to be the current node pointed to by head.
270  if (m_distance[u] == INF_DISTANCE) {
271  break; // This can only happen when there are no accessible nodes.
272  }
273  // Iterate over the adjacent nodes to u.
274  for (v = 0 ; v < static_cast<int>(m_nRouters); v++) {
275  // If the current node is accessible.
276  if (adjMatrix[u][v] > 0) {
277  // And we haven't visited it yet.
278  if (isNotExplored(Q, v, head + 1, m_nRouters)) {
279  // And if the distance to this node + from this node to v
280  // is less than the distance from our source node to v
281  // that we got when we built the adj LSAs
282  if (m_distance[u] + adjMatrix[u][v] < m_distance[v]) {
283  // Set the new distance
284  m_distance[v] = m_distance[u] + adjMatrix[u][v] ;
285  // Set how we get there.
286  m_parent[v] = u;
287  }
288  }
289  }
290  }
291  // Increment the head position, resort the list by distance from where we are.
292  head++;
293  sortQueueByDistance(Q, m_distance, head, m_nRouters);
294  }
295  }
296  delete [] Q;
297 }
298 
299 void
300 LinkStateRoutingTableCalculator::addAllLsNextHopsToRoutingTable(Nlsr& pnlsr, RoutingTable& rt,
301  Map& pMap, uint32_t sourceRouter)
302 {
303  NLSR_LOG_DEBUG("LinkStateRoutingTableCalculator::addAllNextHopsToRoutingTable Called");
304 
305  int nextHopRouter = 0;
306 
307  // For each router we have
308  for (size_t i = 0; i < m_nRouters ; i++) {
309  if (i != sourceRouter) {
310 
311  // Obtain the next hop that was determined by the algorithm
312  nextHopRouter = getLsNextHop(i, sourceRouter);
313 
314  // If this router is accessible at all
315  if (nextHopRouter != NO_NEXT_HOP) {
316 
317  // Fetch its distance
318  double routeCost = m_distance[i];
319  // Fetch its actual name
320  ndn::optional<ndn::Name> nextHopRouterName= pMap.getRouterNameByMappingNo(nextHopRouter);
321  if (nextHopRouterName) {
322  std::string nextHopFace =
323  pnlsr.getAdjacencyList().getAdjacent(*nextHopRouterName).getFaceUri().toString();
324  // Add next hop to routing table
325  NextHop nh(nextHopFace, routeCost);
326  rt.addNextHop(*(pMap.getRouterNameByMappingNo(i)), nh);
327 
328  }
329  }
330  }
331  }
332 }
333 
334 int
335 LinkStateRoutingTableCalculator::getLsNextHop(int dest, int source)
336 {
337  int nextHop = NO_NEXT_HOP;
338  while (m_parent[dest] != EMPTY_PARENT) {
339  nextHop = dest;
340  dest = m_parent[dest];
341  }
342  if (dest != source) {
343  nextHop = NO_NEXT_HOP;
344  }
345  return nextHop;
346 }
347 
348 void
349 LinkStateRoutingTableCalculator::sortQueueByDistance(int* Q,
350  double* dist,
351  int start, int element)
352 {
353  for (int i = start ; i < element ; i++) {
354  for (int j = i + 1; j < element; j++) {
355  if (dist[Q[j]] < dist[Q[i]]) {
356  int tempU = Q[j];
357  Q[j] = Q[i];
358  Q[i] = tempU;
359  }
360  }
361  }
362 }
363 
364 int
365 LinkStateRoutingTableCalculator::isNotExplored(int* Q,
366  int u, int start, int element)
367 {
368  int ret = 0;
369  for (int i = start; i < element; i++) {
370  if (Q[i] == u) {
371  ret = 1;
372  break;
373  }
374  }
375  return ret;
376 }
377 
378 void
379 LinkStateRoutingTableCalculator::allocateParent()
380 {
381  m_parent = new int[m_nRouters];
382 }
383 
384 void
385 LinkStateRoutingTableCalculator::allocateDistance()
386 {
387  m_distance = new double[m_nRouters];
388 }
389 
390 void
391 LinkStateRoutingTableCalculator::freeParent()
392 {
393  delete [] m_parent;
394 }
395 
396 void LinkStateRoutingTableCalculator::freeDistance()
397 {
398  delete [] m_distance;
399 }
400 
401 const double HyperbolicRoutingCalculator::MATH_PI = boost::math::constants::pi<double>();
402 
403 const double HyperbolicRoutingCalculator::UNKNOWN_DISTANCE = -1.0;
404 const double HyperbolicRoutingCalculator::UNKNOWN_RADIUS = -1.0;
405 
406 void
408  Lsdb& lsdb, AdjacencyList& adjacencies)
409 {
410  NLSR_LOG_TRACE("Calculating hyperbolic paths");
411 
412  ndn::optional<int32_t> thisRouter = map.getMappingNoByRouterName(m_thisRouterName);
413 
414  // Iterate over directly connected neighbors
415  std::list<Adjacent> neighbors = adjacencies.getAdjList();
416  for (std::list<Adjacent>::iterator adj = neighbors.begin(); adj != neighbors.end(); ++adj) {
417 
418  // Don't calculate nexthops using an inactive router
419  if (adj->getStatus() == Adjacent::STATUS_INACTIVE) {
420  NLSR_LOG_TRACE(adj->getName() << " is inactive; not using it as a nexthop");
421  continue;
422  }
423 
424  ndn::Name srcRouterName = adj->getName();
425 
426  // Don't calculate nexthops for this router to other routers
427  if (srcRouterName == m_thisRouterName) {
428  continue;
429  }
430 
431  std::string srcFaceUri = adj->getFaceUri().toString();
432 
433  // Install nexthops for this router to the neighbor; direct neighbors have a 0 cost link
434  addNextHop(srcRouterName, srcFaceUri, 0, rt);
435 
436  ndn::optional<int32_t> src = map.getMappingNoByRouterName(srcRouterName);
437 
438  if (!src) {
439  NLSR_LOG_WARN(adj->getName() << " does not exist in the router map!");
440  continue;
441  }
442 
443  // Get hyperbolic distance from direct neighbor to every other router
444  for (int dest = 0; dest < static_cast<int>(m_nRouters); ++dest) {
445  // Don't calculate nexthops to this router or from a router to itself
446  if (thisRouter && dest != *thisRouter && dest != *src) {
447 
448  ndn::optional<ndn::Name> destRouterName = map.getRouterNameByMappingNo(dest);
449  if (destRouterName) {
450  double distance = getHyperbolicDistance(map, lsdb, srcRouterName, *destRouterName);
451 
452  // Could not compute distance
453  if (distance == UNKNOWN_DISTANCE) {
454  NLSR_LOG_WARN("Could not calculate hyperbolic distance from " << srcRouterName << " to " <<
455  *destRouterName);
456  continue;
457  }
458 
459  addNextHop(*destRouterName, srcFaceUri, distance, rt);
460  }
461  }
462  }
463  }
464 }
465 
466 double
467 HyperbolicRoutingCalculator::getHyperbolicDistance(Map& map, Lsdb& lsdb,
468  ndn::Name src, ndn::Name dest)
469 {
470  NLSR_LOG_TRACE("Calculating hyperbolic distance from " << src << " to " << dest);
471 
472  double distance = UNKNOWN_DISTANCE;
473 
474  ndn::Name srcLsaKey = src;
475  srcLsaKey.append(std::to_string(Lsa::Type::COORDINATE));
476 
477  CoordinateLsa* srcLsa = lsdb.findCoordinateLsa(srcLsaKey);
478 
479  ndn::Name destLsaKey = dest;
480  destLsaKey.append(std::to_string(Lsa::Type::COORDINATE));
481 
482  CoordinateLsa* destLsa = lsdb.findCoordinateLsa(destLsaKey);
483 
484  // Coordinate LSAs do not exist for these routers
485  if (srcLsa == nullptr || destLsa == nullptr) {
486  return UNKNOWN_DISTANCE;
487  }
488 
489  std::vector<double> srcTheta = srcLsa->getCorTheta();
490  std::vector<double> destTheta = destLsa->getCorTheta();
491 
492  double srcRadius = srcLsa->getCorRadius();
493  double destRadius = destLsa->getCorRadius();
494 
495  double diffTheta = calculateAngularDistance(srcTheta, destTheta);
496 
497  if (srcRadius == UNKNOWN_RADIUS || destRadius == UNKNOWN_RADIUS ||
498  diffTheta == UNKNOWN_DISTANCE) {
499  return UNKNOWN_DISTANCE;
500  }
501 
502  // double r_i, double r_j, double delta_theta, double zeta = 1 (default)
503  distance = calculateHyperbolicDistance(srcRadius, destRadius, diffTheta);
504 
505  NLSR_LOG_TRACE("Distance from " << src << " to " << dest << " is " << distance);
506 
507  return distance;
508 }
509 
510 double
511 HyperbolicRoutingCalculator::calculateAngularDistance(std::vector<double> angleVectorI,
512  std::vector<double> angleVectorJ)
513 {
514  // It is not possible for angle vector size to be zero as ensured by conf-file-processor
515 
516  // https://en.wikipedia.org/wiki/N-sphere#Spherical_coordinates
517 
518  // Check if two vector lengths are the same
519  if (angleVectorI.size() != angleVectorJ.size()) {
520  NLSR_LOG_ERROR("Angle vector sizes do not match");
521  return UNKNOWN_DISTANCE;
522  }
523 
524  // Check if all angles are within the [0, PI] and [0, 2PI] ranges
525  if (angleVectorI.size() > 1) {
526  for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
527  if ((angleVectorI[k] > M_PI && angleVectorI[k] < 0.0) ||
528  (angleVectorJ[k] > M_PI && angleVectorJ[k] < 0.0)) {
529  NLSR_LOG_ERROR("Angle outside [0, PI]");
530  return UNKNOWN_DISTANCE;
531  }
532  }
533  }
534  if (angleVectorI[angleVectorI.size()-1] > 2.*M_PI ||
535  angleVectorI[angleVectorI.size()-1] < 0.0) {
536  NLSR_LOG_ERROR("Angle not within [0, 2PI]");
537  return UNKNOWN_DISTANCE;
538  }
539 
540  if (angleVectorI[angleVectorI.size()-1] > 2.*M_PI ||
541  angleVectorI[angleVectorI.size()-1] < 0.0) {
542  NLSR_LOG_ERROR("Angle not within [0, 2PI]");
543  return UNKNOWN_DISTANCE;
544  }
545 
546  // deltaTheta = arccos(vectorI . vectorJ) -> do the inner product
547  double innerProduct = 0.0;
548 
549  // Calculate x0 of the vectors
550  double x0i = std::cos(angleVectorI[0]);
551  double x0j = std::cos(angleVectorJ[0]);
552 
553  // Calculate xn of the vectors
554  double xni = std::sin(angleVectorI[angleVectorI.size() - 1]);
555  double xnj = std::sin(angleVectorJ[angleVectorJ.size() - 1]);
556 
557  // Do the aggregation of the (n-1) coordinates (if there is more than one angle)
558  // i.e contraction of all (n-1)-dimensional angular coordinates to one variable
559  for (unsigned int k = 0; k < angleVectorI.size() - 1; k++) {
560  xni *= std::sin(angleVectorI[k]);
561  xnj *= std::sin(angleVectorJ[k]);
562  }
563  innerProduct += (x0i * x0j) + (xni * xnj);
564 
565  // If d > 1
566  if (angleVectorI.size() > 1) {
567  for (unsigned int m = 1; m < angleVectorI.size(); m++) {
568  // calculate euclidean coordinates given the angles and assuming R_sphere = 1
569  double xmi = std::cos(angleVectorI[m]);
570  double xmj = std::cos(angleVectorJ[m]);
571  for (unsigned int l = 0; l < m; l++) {
572  xmi *= std::sin(angleVectorI[l]);
573  xmj *= std::sin(angleVectorJ[l]);
574  }
575  innerProduct += xmi * xmj;
576  }
577  }
578 
579  // ArcCos of the inner product gives the angular distance
580  // between two points on a d-dimensional sphere
581  return std::acos(innerProduct);
582 }
583 
584 double
585 HyperbolicRoutingCalculator::calculateHyperbolicDistance(double rI, double rJ,
586  double deltaTheta)
587 {
588  if (deltaTheta == UNKNOWN_DISTANCE) {
589  return UNKNOWN_DISTANCE;
590  }
591 
592  // Usually, we set zeta = 1 in all experiments
593  double zeta = 1;
594 
595  if (deltaTheta <= 0.0 || rI <= 0.0 || rJ <= 0.0) {
596  NLSR_LOG_ERROR("Delta theta or rI or rJ is <= 0");
597  return UNKNOWN_DISTANCE;
598  }
599 
600  double xij = (1. / zeta) * std::acosh(std::cosh(zeta*rI) * std::cosh(zeta*rJ) -
601  std::sinh(zeta*rI)*std::sinh(zeta*rJ)*std::cos(deltaTheta));
602  return xij;
603 }
604 
605 void
606 HyperbolicRoutingCalculator::addNextHop(ndn::Name dest, std::string faceUri,
607  double cost, RoutingTable& rt)
608 {
609  NextHop hop(faceUri, cost);
610  hop.setHyperbolic(true);
611 
612  NLSR_LOG_TRACE("Calculated " << hop << " for destination: " << dest);
613 
614  if (m_isDryRun) {
615  rt.addNextHopToDryTable(dest, hop);
616  }
617  else {
618  rt.addNextHop(dest, hop);
619  }
620 }
621 
622 } // namespace nlsr
#define NLSR_LOG_WARN(x)
Definition: logger.hpp:47
void getLinksFromAdjMatrix(int *links, double *linkCosts, int source)
Populates temp. variables with the link costs for some router.
ConfParameter & getConfParameter()
Definition: nlsr.hpp:133
const ndn::FaceUri & getFaceUri() const
Definition: adjacent.hpp:69
void makeAdjMatrix(Nlsr &pnlsr, Map pMap)
Constructs an adj. matrix to calculate with.
void allocateAdjMatrix()
Allocate the space needed for the adj. matrix.
void adjustAdMatrix(int source, int link, double linkCost)
Adjust a link cost in the adj. matrix.
ndn::optional< int32_t > getMappingNoByRouterName(const ndn::Name &rName)
Definition: map.cpp:64
ndn::optional< ndn::Name > getRouterNameByMappingNo(int32_t mn)
Definition: map.cpp:51
#define NLSR_LOG_DEBUG(x)
Definition: logger.hpp:41
const ndn::Name & getRouterPrefix() const
Copyright (c) 2014-2017, The University of Memphis, Regents of the University of California.
Adjacent getAdjacent(const ndn::Name &adjName)
#define INIT_LOGGER(name)
Definition: logger.hpp:35
AdjacencyList & getAdjacencyList()
Definition: nlsr.hpp:139
uint32_t getMaxFacesPerPrefix() const
void initMatrix()
Zero every cell of the matrix to ensure that the memory is safe.
CoordinateLsa * findCoordinateLsa(const ndn::Name &key)
Finds a cor. LSA in the LSDB.
Definition: lsdb.cpp:409
#define NLSR_LOG_ERROR(x)
Definition: logger.hpp:50
Copyright (c) 2014-2017, The University of Memphis, Regents of the University of California, Arizona Board of Regents.
Lsdb & getLsdb()
Definition: nlsr.hpp:157
const std::vector< double > getCorTheta() const
Definition: lsa.hpp:372
void addNextHopToDryTable(const ndn::Name &destRouter, NextHop &nh)
Adds a next hop to a routing table entry in a dry run scenario.
int getNumOfLinkfromAdjMatrix(int sRouter)
Returns how many links a router in the matrix has.
void calculatePath(Map &pMap, RoutingTable &rt, Nlsr &pnlsr)
void calculatePaths(Map &map, RoutingTable &rt, Lsdb &lsdb, AdjacencyList &adjacencies)
void setHyperbolic(bool b)
Definition: nexthop.hpp:86
void addNextHop(const ndn::Name &destRouter, NextHop &nh)
Adds a next hop to a routing table entry.
const std::list< AdjLsa > & getAdjLsdb() const
Definition: lsdb.cpp:809
std::list< Adjacent > & getAdjList()
#define NLSR_LOG_TRACE(x)
Definition: logger.hpp:38
double getCorRadius() const
Definition: lsa.hpp:360