Loading...
Searching...
No Matches
routing-calculator-link-state.cpp
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2024, The University of Memphis,
4 * Regents of the University of California,
5 * Arizona Board of Regents.
6 *
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/>.
20 */
21
23#include "name-map.hpp"
24#include "nexthop.hpp"
25
26#include "adjacent.hpp"
27#include "logger.hpp"
28#include "nlsr.hpp"
29
30#include <boost/multi_array.hpp>
31
32namespace nlsr {
33namespace {
34
35INIT_LOGGER(route.RoutingCalculatorLinkState);
36
37constexpr int EMPTY_PARENT = -12345;
38constexpr double INF_DISTANCE = 2147483647;
39constexpr int NO_NEXT_HOP = -12345;
40
47using AdjMatrix = boost::multi_array<double, 2>;
48
49struct PrintAdjMatrix
50{
51 const AdjMatrix& matrix;
52 const NameMap& map;
53};
54
58std::ostream&
59operator<<(std::ostream& os, const PrintAdjMatrix& p)
60{
61 size_t nRouters = p.map.size();
62
63 os << "-----------Legend (routerName -> index)------\n";
64 for (size_t i = 0; i < nRouters; ++i) {
65 os << "Router:" << *p.map.getRouterNameByMappingNo(i)
66 << " Index:" << i << "\n";
67 }
68 os << " |";
69 for (size_t i = 0; i < nRouters; ++i) {
70 os << i << " ";
71 }
72 os << "\n";
73 os << "--";
74 for (size_t i = 0; i < nRouters; ++i) {
75 os << "--";
76 }
77 os << "\n";
78
79 for (size_t i = 0; i < nRouters; i++) {
80 os << i << "|";
81 for (size_t j = 0; j < nRouters; j++) {
82 double cost = p.matrix[i][j];
83 if (cost == NO_NEXT_HOP) {
84 os << "0 ";
85 }
86 else {
87 os << cost << " ";
88 }
89 }
90 os << "\n";
91 }
92
93 return os;
94}
95
104AdjMatrix
105makeAdjMatrix(const Lsdb& lsdb, NameMap& map)
106{
107 // Create the matrix to have N rows and N columns, where N is number of routers.
108 size_t nRouters = map.size();
109 AdjMatrix matrix(boost::extents[nRouters][nRouters]);
110
111 // Initialize all elements to NON_ADJACENT_COST.
112 std::fill_n(matrix.origin(), matrix.num_elements(), Adjacent::NON_ADJACENT_COST);
113
114 // For each LSA represented in the map
115 auto lsaRange = lsdb.getLsdbIterator<AdjLsa>();
116 for (auto lsaIt = lsaRange.first; lsaIt != lsaRange.second; ++lsaIt) {
117 auto adjLsa = std::static_pointer_cast<AdjLsa>(*lsaIt);
118 auto row = map.getMappingNoByRouterName(adjLsa->getOriginRouter());
119
120 std::list<Adjacent> adl = adjLsa->getAdl().getAdjList();
121 // For each adjacency represented in the LSA
122 for (const auto& adjacent : adl) {
123 auto col = map.getMappingNoByRouterName(adjacent.getName());
124 double cost = adjacent.getLinkCost();
125
126 if (row && col && *row < static_cast<int32_t>(nRouters)
127 && *col < static_cast<int32_t>(nRouters)) {
128 matrix[*row][*col] = cost;
129 }
130 }
131 }
132
133 // Links that do not have the same cost for both directions should
134 // have their costs corrected:
135 //
136 // If the cost of one side of the link is NON_ADJACENT_COST (i.e. broken) or negative,
137 // both direction of the link should have their cost corrected to NON_ADJACENT_COST.
138 //
139 // Otherwise, both sides of the link should use the larger of the two costs.
140 //
141 // Additionally, this means that we can halve the amount of space
142 // that the matrix uses by only maintaining a triangle.
143 // - But that is not yet implemented.
144 for (size_t row = 0; row < nRouters; ++row) {
145 for (size_t col = 0; col < nRouters; ++col) {
146 double& toCost = matrix[row][col];
147 double& fromCost = matrix[col][row];
148
149 if (fromCost == toCost) {
150 continue;
151 }
152
153 // If both sides of the link are up, use the larger cost else break the link
154 double correctedCost = Adjacent::NON_ADJACENT_COST;
155 if (toCost >= 0 && fromCost >= 0) {
156 correctedCost = std::max(toCost, fromCost);
157 }
158
159 NLSR_LOG_WARN("Cost between [" << row << "][" << col << "] and [" << col << "][" << row <<
160 "] are not the same (" << toCost << " != " << fromCost << "). " <<
161 "Correcting to cost: " << correctedCost);
162
163 toCost = correctedCost;
164 fromCost = correctedCost;
165 }
166 }
167
168 return matrix;
169}
170
171void
172sortQueueByDistance(std::vector<int>& q, const std::vector<double>& dist, size_t start)
173{
174 for (size_t i = start; i < q.size(); ++i) {
175 for (size_t j = i + 1; j < q.size(); ++j) {
176 if (dist[q[j]] < dist[q[i]]) {
177 std::swap(q[i], q[j]);
178 }
179 }
180 }
181}
182
183bool
184isNotExplored(std::vector<int>& q, int u, size_t start)
185{
186 for (size_t i = start; i < q.size(); i++) {
187 if (q[i] == u) {
188 return true;
189 }
190 }
191 return false;
192}
193
194struct Link
195{
196 size_t index;
197 double cost;
198};
199
203std::vector<Link>
204gatherLinks(const AdjMatrix& matrix, int sourceRouter)
205{
206 size_t nRouters = matrix.size();
207 std::vector<Link> result;
208 result.reserve(nRouters);
209 for (size_t i = 0; i < nRouters; ++i) {
210 if (i == static_cast<size_t>(sourceRouter)) {
211 continue;
212 }
213 double cost = matrix[sourceRouter][i];
214 if (cost >= 0.0) {
215 result.emplace_back(Link{i, cost});
216 }
217 }
218 return result;
219}
220
224void
225simulateOneNeighbor(AdjMatrix& matrix, int sourceRouter, const Link& accessibleNeighbor)
226{
227 size_t nRouters = matrix.size();
228 for (size_t i = 0; i < nRouters; ++i) {
229 if (i == accessibleNeighbor.index) {
230 matrix[sourceRouter][i] = accessibleNeighbor.cost;
231 }
232 else {
233 // if "i" is not a link to the source, set its cost to a non adjacent value.
234 matrix[sourceRouter][i] = Adjacent::NON_ADJACENT_COST;
235 }
236 }
237}
238
239class DijkstraResult
240{
241public:
242 int
243 getNextHop(int dest, int source) const
244 {
245 int nextHop = NO_NEXT_HOP;
246 while (parent[dest] != EMPTY_PARENT) {
247 nextHop = dest;
248 dest = parent[dest];
249 }
250 if (dest != source) {
251 nextHop = NO_NEXT_HOP;
252 }
253 return nextHop;
254 }
255
256public:
257 std::vector<int> parent;
258 std::vector<double> distance;
259};
260
264DijkstraResult
265calculateDijkstraPath(const AdjMatrix& matrix, int sourceRouter)
266{
267 size_t nRouters = matrix.size();
268 std::vector<int> parent(nRouters, EMPTY_PARENT);
269 // Array where the ith element is the distance to the router with mapping no i.
270 std::vector<double> distance(nRouters, INF_DISTANCE);
271 // Each cell represents the router with that mapping no.
272 std::vector<int> q(nRouters);
273 for (size_t i = 0 ; i < nRouters; ++i) {
274 q[i] = static_cast<int>(i);
275 }
276
277 size_t head = 0;
278 // Distance to source from source is always 0.
279 distance[sourceRouter] = 0;
280 sortQueueByDistance(q, distance, head);
281 // While we haven't visited every node.
282 while (head < nRouters) {
283 int u = q[head]; // Set u to be the current node pointed to by head.
284 if (distance[u] == INF_DISTANCE) {
285 break; // This can only happen when there are no accessible nodes.
286 }
287 // Iterate over the adjacent nodes to u.
288 for (size_t v = 0; v < nRouters; ++v) {
289 // If the current node is accessible and we haven't visited it yet.
290 if (matrix[u][v] >= 0 && isNotExplored(q, v, head + 1)) {
291 // And if the distance to this node + from this node to v
292 // is less than the distance from our source node to v
293 // that we got when we built the adj LSAs
294 double newDistance = distance[u] + matrix[u][v];
295 if (newDistance < distance[v]) {
296 // Set the new distance
297 distance[v] = newDistance;
298 // Set how we get there.
299 parent[v] = u;
300 }
301 }
302 }
303 // Increment the head position, resort the list by distance from where we are.
304 ++head;
305 sortQueueByDistance(q, distance, head);
306 }
307
308 return DijkstraResult{std::move(parent), std::move(distance)};
309}
310
314void
315addNextHopsToRoutingTable(RoutingTable& rt, const NameMap& map, int sourceRouter,
316 const AdjacencyList& adjacencies, const DijkstraResult& dr)
317{
318 NLSR_LOG_DEBUG("addNextHopsToRoutingTable Called");
319 int nRouters = static_cast<int>(map.size());
320
321 // For each router we have
322 for (int i = 0; i < nRouters; ++i) {
323 if (i == sourceRouter) {
324 continue;
325 }
326
327 // Obtain the next hop that was determined by the algorithm
328 int nextHopRouter = dr.getNextHop(i, sourceRouter);
329 if (nextHopRouter == NO_NEXT_HOP) {
330 continue;
331 }
332 // If this router is accessible at all
333
334 // Fetch its distance
335 double routeCost = dr.distance[i];
336 // Fetch its actual name
337 auto nextHopRouterName = map.getRouterNameByMappingNo(nextHopRouter);
338 BOOST_ASSERT(nextHopRouterName.has_value());
339 auto nextHopFace = adjacencies.getAdjacent(*nextHopRouterName).getFaceUri();
340 // Add next hop to routing table
341 NextHop nh(nextHopFace, routeCost);
342 rt.addNextHop(*map.getRouterNameByMappingNo(i), nh);
343 }
344}
345
346} // anonymous namespace
347
348void
350 const Lsdb& lsdb)
351{
352 NLSR_LOG_DEBUG("calculateLinkStateRoutingPath called");
353
354 auto sourceRouter = map.getMappingNoByRouterName(confParam.getRouterPrefix());
355 if (!sourceRouter) {
356 NLSR_LOG_DEBUG("Source router is absent, nothing to do");
357 return;
358 }
359
360 AdjMatrix matrix = makeAdjMatrix(lsdb, map);
361 NLSR_LOG_DEBUG((PrintAdjMatrix{matrix, map}));
362
363 if (confParam.getMaxFacesPerPrefix() == 1) {
364 // In the single path case we can simply run Dijkstra's algorithm.
365 auto dr = calculateDijkstraPath(matrix, *sourceRouter);
366 // Inform the routing table of the new next hops.
367 addNextHopsToRoutingTable(rt, map, *sourceRouter, confParam.getAdjacencyList(), dr);
368 }
369 else {
370 // Multi Path
371 // Gets a sparse listing of adjacencies for path calculation
372 auto links = gatherLinks(matrix, *sourceRouter);
373 for (const auto& link : links) {
374 // Simulate that only the current neighbor is accessible
375 simulateOneNeighbor(matrix, *sourceRouter, link);
376 NLSR_LOG_DEBUG((PrintAdjMatrix{matrix, map}));
377 // Do Dijkstra's algorithm using the current neighbor as your start.
378 auto dr = calculateDijkstraPath(matrix, *sourceRouter);
379 // Update the routing table with the calculations.
380 addNextHopsToRoutingTable(rt, map, *sourceRouter, confParam.getAdjacencyList(), dr);
381 }
382 }
383}
384
385} // namespace nlsr
static constexpr double NON_ADJACENT_COST
Definition adjacent.hpp:187
A class to house all the configuration parameters for NLSR.
const ndn::Name & getRouterPrefix() const
uint32_t getMaxFacesPerPrefix() const
AdjacencyList & getAdjacencyList()
Assigning numbers to router names.
Definition name-map.hpp:46
std::optional< ndn::Name > getRouterNameByMappingNo(int32_t mn) const
Find router name by its mapping number.
Definition name-map.cpp:37
std::optional< int32_t > getMappingNoByRouterName(const ndn::Name &rtrName) const
Find mapping number of a router name.
Definition name-map.cpp:47
size_t size() const
Return number of entries in this container.
Definition name-map.hpp:120
Copyright (c) 2014-2018, The University of Memphis, Regents of the University of California.
#define NLSR_LOG_DEBUG(x)
Definition logger.hpp:38
#define INIT_LOGGER(name)
Definition logger.hpp:35
#define NLSR_LOG_WARN(x)
Definition logger.hpp:40
Copyright (c) 2014-2020, The University of Memphis, Regents of the University of California.
std::ostream & operator<<(std::ostream &os, const Adjacent &adjacent)
Definition adjacent.cpp:176
void calculateLinkStateRoutingPath(NameMap &map, RoutingTable &rt, ConfParameter &confParam, const Lsdb &lsdb)