2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
4 * IPv4 performance optimization (c) 2006, sven-ola(gmx.de)
5 * SPF implementation (c) 2007, Hannes Gredler (hannes@gredler.at)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * * Neither the name of olsr.org, olsrd nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
35 * Visit http://www.olsr.org for more information.
37 * If you find this software useful feel free to make a donation
38 * to the project. For more information see the website or contact
39 * the copyright holders.
41 * Implementation of Dijkstras algorithm. Initially all nodes
42 * are initialized to infinite cost. First we put ourselves
43 * on the heap of reachable nodes. Our heap implementation
44 * is based on an AVL tree which gives interesting performance
45 * characteristics for the frequent operations of minimum key
46 * extraction and re-keying. Next all neighbors of a node are
47 * explored and put on the heap if the cost of reaching them is
48 * better than reaching the current candidate node.
49 * The SPF calculation is terminated if there are no more nodes
57 #include "neighbor_table.h"
58 #include "two_hop_neighbor_table.h"
60 #include "routing_table.h"
71 * compare two etx metrics.
72 * return 0 if there is an exact match and
73 * -1 / +1 depending on being smaller or bigger.
74 * note that this results in the most optimal code
75 * after compiler optimization.
78 avl_comp_etx (const void *etx1, const void *etx2)
80 if (*(const float *)etx1 < *(const float *)etx2) {
84 if (*(const float *)etx1 > *(const float *)etx2) {
92 * olsr_spf_add_cand_tree
94 * Key an existing vertex to a candidate tree.
97 olsr_spf_add_cand_tree (struct avl_tree *tree,
100 #if !defined(NODEBUG) && defined(DEBUG)
101 struct ipaddr_str buf;
103 tc->cand_tree_node.key = &tc->path_etx;
104 tc->cand_tree_node.data = tc;
107 OLSR_PRINTF(1, "SPF: insert candidate %s, cost %s\n",
108 olsr_ip_to_string(&buf, &tc->addr),
109 etxtoa(tc->path_etx));
112 avl_insert(tree, &tc->cand_tree_node, AVL_DUP);
116 * olsr_spf_del_cand_tree
118 * Unkey an existing vertex from a candidate tree.
121 olsr_spf_del_cand_tree (struct avl_tree *tree,
127 struct ipaddr_str buf;
129 OLSR_PRINTF(1, "SPF: delete candidate %s, cost %s\n",
130 olsr_ip_to_string(&buf, &tc->addr),
131 etxtoa(tc->path_etx));
134 avl_delete(tree, &tc->cand_tree_node);
138 * olsr_spf_add_path_list
140 * Insert an SPF result at the end of the path list.
143 olsr_spf_add_path_list (struct list_node *head, int *path_count,
146 #if !defined(NODEBUG) && defined(DEBUG)
147 struct ipaddr_str pathbuf, nbuf;
149 tc->path_list_node.data = tc;
152 OLSR_PRINTF(1, "SPF: append path %s, cost %s, via %s\n",
153 olsr_ip_to_string(&pathbuf, &tc->addr),
154 etxtoa(tc->path_etx),
155 tc->next_hop ? olsr_ip_to_string(
156 &nbuf, &tc->next_hop->neighbor_iface_addr) : "-");
159 list_add_before(head, &tc->path_list_node);
160 *path_count = *path_count + 1;
164 * olsr_spf_extract_best
166 * return the node with the minimum pathcost.
168 static struct tc_entry *
169 olsr_spf_extract_best (struct avl_tree *tree)
171 struct avl_node *node = avl_walk_first(tree);
173 return (node ? node->data : NULL);
180 * Explore all edges of a node and add the node
181 * to the candidate tree if the if the aggregate
182 * path cost is better.
185 olsr_spf_relax (struct avl_tree *cand_tree, struct tc_entry *tc)
187 struct avl_node *edge_node;
196 struct ipaddr_str buf, nbuf;
198 OLSR_PRINTF(1, "SPF: exploring node %s, cost %s\n",
199 olsr_ip_to_string(&buf, &tc->addr),
200 etxtoa(tc->path_etx));
204 * loop through all edges of this vertex.
206 for (edge_node = avl_walk_first(&tc->edge_tree);
208 edge_node = avl_walk_next(edge_node)) {
210 struct tc_entry *new_tc;
211 struct tc_edge_entry *tc_edge = edge_node->data;
214 * We are not interested in dead-end or dying edges.
216 if (!tc_edge->edge_inv || (tc_edge->flags & OLSR_TC_EDGE_DOWN)) {
218 OLSR_PRINTF(1, "SPF: ignoring edge %s\n",
219 olsr_ip_to_string(&buf, &tc_edge->T_dest_addr));
220 if (tc_edge->flags & OLSR_TC_EDGE_DOWN) {
221 OLSR_PRINTF(1, "SPF: edge down\n");
223 if (!tc_edge->edge_inv) {
224 OLSR_PRINTF(1, "SPF: no inverse edge\n");
231 * total quality of the path through this vertex
232 * to the destination of this edge
235 new_etx = INFINITE_ETX <= tc->path_etx || INFINITE_ETX <= tc_edge->etx
236 ? INFINITE_ETX : fpmadd(tc->path_etx, tc_edge->etx);
238 new_etx = tc->path_etx + tc_edge->etx;
242 OLSR_PRINTF(1, "SPF: exploring edge %s, cost %s\n",
243 olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
248 * if it's better than the current path quality of this edge's
249 * destination node, then we've found a better path to this node.
251 new_tc = tc_edge->edge_inv->tc;
253 if (new_etx < new_tc->path_etx) {
255 /* if this node has been on the candidate tree delete it */
256 if (new_tc->path_etx != INFINITE_ETX) {
257 olsr_spf_del_cand_tree(cand_tree, new_tc);
260 /* re-insert on candidate tree with the better metric */
261 new_tc->path_etx = new_etx;
262 olsr_spf_add_cand_tree(cand_tree, new_tc);
264 /* pull-up the next-hop and bump the hop count */
266 new_tc->next_hop = tc->next_hop;
268 new_tc->hops = tc->hops + 1;
271 OLSR_PRINTF(1, "SPF: better path to %s, cost %s -> %s, via %s, hops %u\n",
272 olsr_ip_to_string(&buf, &new_tc->addr),
273 etxtoa(new_tc->path_etx),
275 tc->next_hop ? olsr_ip_to_string(
276 &nbuf, &tc->next_hop->neighbor_iface_addr) : "<none>",
287 * Run the Dijkstra algorithm.
289 * A node gets added to the candidate tree when one of its edges has
290 * an overall better root path cost than the node itself.
291 * The node with the shortest metric gets moved from the candidate to
292 * the path list every pass.
293 * The SPF computation is completed when there are no more nodes
294 * on the candidate tree.
297 olsr_spf_run_full (struct avl_tree *cand_tree, struct list_node *path_list,
304 while ((tc = olsr_spf_extract_best(cand_tree))) {
306 olsr_spf_relax(cand_tree, tc);
309 * move the best path from the candidate tree
312 olsr_spf_del_cand_tree(cand_tree, tc);
313 olsr_spf_add_path_list(path_list, path_count, tc);
318 olsr_calculate_routing_table (void)
320 struct avl_tree cand_tree;
321 struct avl_node *rtp_tree_node;
322 struct list_node path_list; /* head of the path_list */
323 int i, path_count = 0;
326 struct tc_edge_entry *tc_edge;
327 struct neighbor_entry *neigh;
328 struct link_entry *link;
331 struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total;
333 gettimeofday(&t1, NULL);
337 * Prepare the candidate tree and result list.
339 avl_init(&cand_tree, avl_comp_etx);
340 list_head_init(&path_list);
341 olsr_bump_routingtree_version();
344 * Initialize vertices in the lsdb.
346 OLSR_FOR_ALL_TC_ENTRIES(tc) {
348 tc->path_etx = INFINITE_ETX;
350 } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
353 * zero ourselves and add us to the candidate tree.
355 olsr_change_myself_tc();
356 tc_myself->path_etx = ZERO_ETX;
357 olsr_spf_add_cand_tree(&cand_tree, tc_myself);
360 * add edges to and from our neighbours.
362 for (i = 0; i < HASHSIZE; i++)
363 for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
364 neigh = neigh->next) {
366 if (neigh->status == SYM) {
368 tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
369 link = get_best_link_to_neighbor(&neigh->neighbor_main_addr);
373 * If there is no best link to this neighbor
374 * and we had an edge before then flush the edge.
377 olsr_delete_tc_edge_entry(tc_edge);
382 /* find the interface for the link */
384 link->inter = if_ifwithname(link->if_name);
386 link->inter = if_ifwithaddr(&link->local_iface_addr);
390 * Set the next-hops of our neighbors.
393 tc_edge = olsr_add_tc_edge_entry(tc_myself, &neigh->neighbor_main_addr,
395 link->loss_link_quality2,
396 link->neigh_link_quality2);
400 * Update LQ and timers, such that the edge does not get deleted.
402 tc_edge->link_quality = link->loss_link_quality2;
403 tc_edge->inverse_link_quality = link->neigh_link_quality2;
404 olsr_set_tc_edge_timer(tc_edge, link->vtime*1000);
405 olsr_calc_tc_edge_entry_etx(tc_edge);
407 if (tc_edge->edge_inv) {
408 tc_edge->edge_inv->tc->next_hop = link;
414 gettimeofday(&t2, NULL);
418 * Run the SPF calculation.
420 olsr_spf_run_full(&cand_tree, &path_list, &path_count);
422 OLSR_PRINTF(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n",
426 (int)now.tv_usec/10000);
429 gettimeofday(&t3, NULL);
433 * In the path list we have all the reachable nodes in our topology.
435 for (; !list_is_empty(&path_list); list_remove(path_list.next)) {
437 tc = path_list.next->data;
443 * Supress the error msg when our own tc_entry
444 * does not contain a next-hop.
446 if (tc != tc_myself) {
448 struct ipaddr_str buf;
450 OLSR_PRINTF(1, "SPF: %s no next-hop\n", olsr_ip_to_string(&buf, &tc->addr));
457 * Now walk all prefixes advertised by that node.
458 * Since the node is reachable, insert the prefix into the global RIB.
459 * If the prefix is already in the RIB, refresh the entry such
460 * that olsr_delete_outdated_routes() does not purge it off.
462 for (rtp_tree_node = avl_walk_first(&tc->prefix_tree);
464 rtp_tree_node = avl_walk_next(rtp_tree_node)) {
466 rtp = rtp_tree_node->data;
471 * If there is a route entry, the prefix is already in the global RIB.
473 olsr_update_rt_path(rtp, tc, link);
478 * The prefix is reachable and not yet in the global RIB.
479 * Build a rt_entry for it.
481 olsr_insert_rt_path(rtp, tc, link);
486 /* Update the RIB based on the new SPF results */
488 olsr_update_rib_routes();
491 gettimeofday(&t4, NULL);
494 /* move the route changes into the kernel */
496 olsr_update_kernel_routes();
499 gettimeofday(&t5, NULL);
503 timersub(&t2, &t1, &spf_init);
504 timersub(&t3, &t2, &spf_run);
505 timersub(&t4, &t3, &route);
506 timersub(&t5, &t4, &kernel);
507 timersub(&t5, &t1, &total);
508 OLSR_PRINTF(1, "\n--- SPF-stats for %d nodes, %d routes (total/init/run/route/kern): "
509 "%d, %d, %d, %d, %d\n",
510 path_count, routingtree.count,
511 (int)total.tv_usec, (int)spf_init.tv_usec, (int)spf_run.tv_usec,
512 (int)route.tv_usec, (int)kernel.tv_usec);