3 * The olsr.org Optimized Link-State Routing daemon(olsrd)
4 * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
5 * IPv4 performance optimization (c) 2006, sven-ola(gmx.de)
6 * SPF implementation (c) 2007, Hannes Gredler (hannes@gredler.at)
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
19 * * Neither the name of olsr.org, olsrd nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
36 * Visit http://www.olsr.org for more information.
38 * If you find this software useful feel free to make a donation
39 * to the project. For more information see the website or contact
40 * the copyright holders.
42 * Implementation of Dijkstras algorithm. Initially all nodes
43 * are initialized to infinite cost. First we put ourselves
44 * on the heap of reachable nodes. Our heap implementation
45 * is based on an AVL tree which gives interesting performance
46 * characteristics for the frequent operations of minimum key
47 * extraction and re-keying. Next all neighbors of a node are
48 * explored and put on the heap if the cost of reaching them is
49 * better than reaching the current candidate node.
50 * The SPF calculation is terminated if there are no more nodes
58 #include "neighbor_table.h"
59 #include "two_hop_neighbor_table.h"
61 #include "routing_table.h"
64 #include "common/list.h"
65 #include "common/avl.h"
68 #include "lq_plugin.h"
71 struct timer_entry *spf_backoff_timer = NULL;
76 * compare two etx metrics.
77 * return 0 if there is an exact match and
78 * -1 / +1 depending on being smaller or bigger.
79 * note that this results in the most optimal code
80 * after compiler optimization.
83 avl_comp_etx(const void *etx1, const void *etx2)
85 if (*(const olsr_linkcost *)etx1 < *(const olsr_linkcost *)etx2) {
89 if (*(const olsr_linkcost *)etx1 > *(const olsr_linkcost *)etx2) {
97 * olsr_spf_add_cand_tree
99 * Key an existing vertex to a candidate tree.
102 olsr_spf_add_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
104 #if !defined(NODEBUG) && defined(DEBUG)
105 struct ipaddr_str buf;
106 struct lqtextbuffer lqbuffer;
107 #endif /* !defined(NODEBUG) && defined(DEBUG) */
108 tc->cand_tree_node.key = &tc->path_cost;
111 OLSR_PRINTF(2, "SPF: insert candidate %s, cost %s\n", olsr_ip_to_string(&buf, &tc->addr),
112 get_linkcost_text(tc->path_cost, true, &lqbuffer));
115 avl_insert(tree, &tc->cand_tree_node, AVL_DUP);
119 * olsr_spf_del_cand_tree
121 * Unkey an existing vertex from a candidate tree.
124 olsr_spf_del_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
129 struct ipaddr_str buf;
130 struct lqtextbuffer lqbuffer;
132 OLSR_PRINTF(2, "SPF: delete candidate %s, cost %s\n", olsr_ip_to_string(&buf, &tc->addr),
133 get_linkcost_text(tc->path_cost, true, &lqbuffer));
136 avl_delete(tree, &tc->cand_tree_node);
140 * olsr_spf_add_path_list
142 * Insert an SPF result at the end of the path list.
145 olsr_spf_add_path_list(struct list_node *head, int *path_count, struct tc_entry *tc)
147 #if !defined(NODEBUG) && defined(DEBUG)
148 struct ipaddr_str pathbuf, nbuf;
149 struct lqtextbuffer lqbuffer;
150 #endif /* !defined(NODEBUG) && defined(DEBUG) */
153 OLSR_PRINTF(2, "SPF: append path %s, cost %s, via %s\n", olsr_ip_to_string(&pathbuf, &tc->addr),
154 get_linkcost_text(tc->path_cost, true, &lqbuffer), tc->next_hop ? olsr_ip_to_string(&nbuf,
156 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 ? cand_tree2tc(node) : NULL);
179 * Explore all edges of a node and add the node
180 * to the candidate tree if the if the aggregate
181 * path cost is better.
184 olsr_spf_relax(struct avl_tree *cand_tree, struct tc_entry *tc)
186 struct avl_node *edge_node;
187 olsr_linkcost new_cost;
191 struct ipaddr_str buf, nbuf;
192 struct lqtextbuffer lqbuffer;
194 OLSR_PRINTF(2, "SPF: exploring node %s, cost %s\n", olsr_ip_to_string(&buf, &tc->addr),
195 get_linkcost_text(tc->path_cost, true, &lqbuffer));
199 * loop through all edges of this vertex.
201 for (edge_node = avl_walk_first(&tc->edge_tree); edge_node; edge_node = avl_walk_next(edge_node)) {
203 struct tc_entry *new_tc;
204 struct tc_edge_entry *tc_edge = edge_tree2tc_edge(edge_node);
207 * We are not interested in dead-end edges.
209 if (!tc_edge->edge_inv) {
211 OLSR_PRINTF(2, "SPF: ignoring edge %s\n", olsr_ip_to_string(&buf, &tc_edge->T_dest_addr));
212 if (!tc_edge->edge_inv) {
213 OLSR_PRINTF(2, "SPF: no inverse edge\n");
219 if (tc_edge->cost >= LINK_COST_BROKEN) {
221 OLSR_PRINTF(2, "SPF: ignore edge %s (broken)\n", olsr_ip_to_string(&buf, &tc_edge->T_dest_addr));
226 * total quality of the path through this vertex
227 * to the destination of this edge
229 new_cost = tc->path_cost + tc_edge->cost;
232 OLSR_PRINTF(2, "SPF: exploring edge %s, cost %s\n", olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
233 get_linkcost_text(new_cost, true, &lqbuffer));
237 * if it's better than the current path quality of this edge's
238 * destination node, then we've found a better path to this node.
240 new_tc = tc_edge->edge_inv->tc;
242 if (new_cost < new_tc->path_cost) {
244 /* if this node has been on the candidate tree delete it */
245 if (new_tc->path_cost < ROUTE_COST_BROKEN) {
246 olsr_spf_del_cand_tree(cand_tree, new_tc);
249 /* re-insert on candidate tree with the better metric */
250 new_tc->path_cost = new_cost;
251 olsr_spf_add_cand_tree(cand_tree, new_tc);
253 /* pull-up the next-hop and bump the hop count */
255 new_tc->next_hop = tc->next_hop;
257 new_tc->hops = tc->hops + 1;
260 OLSR_PRINTF(2, "SPF: better path to %s, cost %s, via %s, hops %u\n", olsr_ip_to_string(&buf, &new_tc->addr),
261 get_linkcost_text(new_cost, true, &lqbuffer), tc->next_hop ? olsr_ip_to_string(&nbuf,
262 &tc->next_hop->neighbor_iface_addr)
263 : "<none>", new_tc->hops);
273 * Run the Dijkstra algorithm.
275 * A node gets added to the candidate tree when one of its edges has
276 * an overall better root path cost than the node itself.
277 * The node with the shortest metric gets moved from the candidate to
278 * the path list every pass.
279 * The SPF computation is completed when there are no more nodes
280 * on the candidate tree.
283 olsr_spf_run_full(struct avl_tree *cand_tree, struct list_node *path_list, int *path_count)
289 while ((tc = olsr_spf_extract_best(cand_tree))) {
291 olsr_spf_relax(cand_tree, tc);
294 * move the best path from the candidate tree
297 olsr_spf_del_cand_tree(cand_tree, tc);
298 olsr_spf_add_path_list(path_list, path_count, tc);
303 * Callback for the SPF backoff timer.
306 olsr_expire_spf_backoff(void *context __attribute__ ((unused)))
308 spf_backoff_timer = NULL;
312 olsr_calculate_routing_table(bool force)
315 struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total;
316 #endif /* SPF_PROFILING */
317 struct avl_tree cand_tree;
318 struct avl_node *rtp_tree_node;
319 struct list_node path_list; /* head of the path_list */
322 struct tc_edge_entry *tc_edge;
323 struct neighbor_entry *neigh;
324 struct link_entry *link;
327 /* We are done if our backoff timer is running */
329 if (spf_backoff_timer) {
333 /* start new backoff timer */
334 spf_backoff_timer = olsr_start_timer(1000, 5, OLSR_TIMER_ONESHOT, &olsr_expire_spf_backoff, NULL, 0);
338 gettimeofday(&t1, NULL);
339 #endif /* SPF_PROFILING */
342 * Prepare the candidate tree and result list.
344 avl_init(&cand_tree, avl_comp_etx);
345 list_head_init(&path_list);
346 olsr_bump_routingtree_version();
349 * Initialize vertices in the lsdb.
351 OLSR_FOR_ALL_TC_ENTRIES(tc) {
353 tc->path_cost = ROUTE_COST_BROKEN;
356 OLSR_FOR_ALL_TC_ENTRIES_END(tc);
359 * Check if there was a change in the main IP address.
360 * Bail if there is no main IP address.
362 olsr_change_myself_tc();
366 * All gone now. Flush all routes.
368 olsr_update_rib_routes();
369 olsr_update_kernel_routes();
374 * zero ourselves and add us to the candidate tree.
376 tc_myself->path_cost = ZERO_ROUTE_COST;
377 olsr_spf_add_cand_tree(&cand_tree, tc_myself);
380 * add edges to and from our neighbours.
382 OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
384 if (neigh->status != SYM) {
385 tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
387 olsr_delete_tc_edge_entry(tc_edge);
391 tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
392 link = get_best_link_to_neighbor(&neigh->neighbor_main_addr);
393 if (!link || lookup_link_status(link) == LOST_LINK) {
396 * If there is no best link to this neighbor
397 * and we had an edge before then flush the edge.
400 olsr_delete_tc_edge_entry(tc_edge);
405 /* find the interface for the link */
407 link->inter = if_ifwithname(link->if_name);
409 link->inter = if_ifwithaddr(&link->local_iface_addr);
413 * Set the next-hops of our neighbors.
416 tc_edge = olsr_add_tc_edge_entry(tc_myself, &neigh->neighbor_main_addr, 0);
420 * Update LQ and timers, such that the edge does not get deleted.
422 olsr_copylq_link_entry_2_tc_edge_entry(tc_edge, link);
423 olsr_calc_tc_edge_entry_etx(tc_edge);
425 if (tc_edge->edge_inv) {
426 tc_edge->edge_inv->tc->next_hop = link;
430 OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
433 gettimeofday(&t2, NULL);
434 #endif /* SPF_PROFILING */
437 * Run the SPF calculation.
439 olsr_spf_run_full(&cand_tree, &path_list, &path_count);
441 OLSR_PRINTF(2, "\n--- %s ------------------------------------------------- DIJKSTRA\n\n", olsr_wallclock_string());
444 gettimeofday(&t3, NULL);
445 #endif /* SPF_PROFILING */
448 * In the path list we have all the reachable nodes in our topology.
450 for (; !list_is_empty(&path_list); list_remove(path_list.next)) {
452 tc = pathlist2tc(path_list.next);
458 * Supress the error msg when our own tc_entry
459 * does not contain a next-hop.
461 if (tc != tc_myself) {
462 struct ipaddr_str buf;
463 OLSR_PRINTF(2, "SPF: %s no next-hop\n", olsr_ip_to_string(&buf, &tc->addr));
470 * Now walk all prefixes advertised by that node.
471 * Since the node is reachable, insert the prefix into the global RIB.
472 * If the prefix is already in the RIB, refresh the entry such
473 * that olsr_delete_outdated_routes() does not purge it off.
475 for (rtp_tree_node = avl_walk_first(&tc->prefix_tree); rtp_tree_node; rtp_tree_node = avl_walk_next(rtp_tree_node)) {
477 rtp = rtp_prefix_tree2rtp(rtp_tree_node);
482 * If there is a route entry, the prefix is already in the global RIB.
484 olsr_update_rt_path(rtp, tc, link);
489 * The prefix is reachable and not yet in the global RIB.
490 * Build a rt_entry for it.
492 olsr_insert_rt_path(rtp, tc, link);
497 /* check gateway tunnels */
498 olsr_trigger_gatewayloss_check();
499 #endif /* __linux__ */
501 /* Update the RIB based on the new SPF results */
503 olsr_update_rib_routes();
506 gettimeofday(&t4, NULL);
507 #endif /* SPF_PROFILING */
509 /* move the route changes into the kernel */
511 olsr_update_kernel_routes();
514 gettimeofday(&t5, NULL);
515 #endif /* SPF_PROFILING */
518 timersub(&t2, &t1, &spf_init);
519 timersub(&t3, &t2, &spf_run);
520 timersub(&t4, &t3, &route);
521 timersub(&t5, &t4, &kernel);
522 timersub(&t5, &t1, &total);
523 OLSR_PRINTF(1, "\n--- SPF-stats for %d nodes, %d routes (total/init/run/route/kern): " "%d, %d, %d, %d, %d\n", path_count,
524 routingtree.count, (int)total.tv_usec, (int)spf_init.tv_usec, (int)spf_run.tv_usec, (int)route.tv_usec,
525 (int)kernel.tv_usec);
526 #endif /* SPF_PROFILING */
532 * indent-tabs-mode: nil