Remove the olsr-specific duplicated types
[olsrd.git] / src / olsr_spf.c
1 /*
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)
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions 
10  * are met:
11  *
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 
17  *   distribution.
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.
21  *
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.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
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.
40  *
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
50  * on the heap.
51  */
52
53 #include "olsr_spf.h"
54 #include "tc_set.h"
55 #include "neighbor_table.h"
56 #include "routing_table.h"
57 #include "lq_plugin.h"
58 #include "process_routes.h"
59
60 static struct timer_entry *spf_backoff_timer = NULL;
61
62 /*
63  * avl_comp_etx
64  *
65  * compare two etx metrics.
66  * return 0 if there is an exact match and
67  * -1 / +1 depending on being smaller or bigger.
68  * note that this results in the most optimal code
69  * after compiler optimization.
70  */
71 static int
72 avl_comp_etx (const void *etx1, const void *etx2)
73 {       
74   if (*(const olsr_linkcost *)etx1 < *(const olsr_linkcost *)etx2) {
75     return -1;
76   }
77
78   if (*(const olsr_linkcost *)etx1 > *(const olsr_linkcost *)etx2) {
79     return +1;
80   }
81
82   return 0;
83 }
84
85 /*
86  * olsr_spf_add_cand_tree
87  *
88  * Key an existing vertex to a candidate tree.
89  */
90 static void
91 olsr_spf_add_cand_tree (struct avl_tree *tree,
92                         struct tc_entry *tc)
93 {
94 #if !defined(NODEBUG) && defined(DEBUG)
95   struct ipaddr_str buf;
96   struct lqtextbuffer lqbuffer;
97 #endif
98   tc->cand_tree_node.key = &tc->path_cost;
99
100 #ifdef DEBUG
101   OLSR_PRINTF(2, "SPF: insert candidate %s, cost %s\n",
102               olsr_ip_to_string(&buf, &tc->addr),
103               get_linkcost_text(tc->path_cost, false, &lqbuffer));
104 #endif
105
106   avl_insert(tree, &tc->cand_tree_node, AVL_DUP);
107 }
108
109 /*
110  * olsr_spf_del_cand_tree
111  *
112  * Unkey an existing vertex from a candidate tree.
113  */
114 static void
115 olsr_spf_del_cand_tree (struct avl_tree *tree,
116                         struct tc_entry *tc)
117 {
118
119 #ifdef DEBUG
120 #ifndef NODEBUG
121   struct ipaddr_str buf;
122   struct lqtextbuffer lqbuffer;
123 #endif
124   OLSR_PRINTF(2, "SPF: delete candidate %s, cost %s\n",
125               olsr_ip_to_string(&buf, &tc->addr),
126               get_linkcost_text(tc->path_cost, false, &lqbuffer));
127 #endif
128
129   avl_delete(tree, &tc->cand_tree_node);
130 }
131
132 /*
133  * olsr_spf_add_path_list
134  *
135  * Insert an SPF result at the end of the path list.
136  */
137 static void
138 olsr_spf_add_path_list (struct list_node *head, int *path_count,
139                         struct tc_entry *tc)
140 {
141 #if !defined(NODEBUG) && defined(DEBUG)
142   struct ipaddr_str pathbuf, nbuf;
143   struct lqtextbuffer lqbuffer;
144 #endif
145
146 #ifdef DEBUG
147   OLSR_PRINTF(2, "SPF: append path %s, cost %s, via %s\n",
148               olsr_ip_to_string(&pathbuf, &tc->addr),
149               get_linkcost_text(tc->path_cost, false, &lqbuffer),
150               tc->next_hop ? olsr_ip_to_string(
151                 &nbuf, &tc->next_hop->neighbor_iface_addr) : "-");
152 #endif
153
154   list_add_before(head, &tc->path_list_node);
155   *path_count = *path_count + 1;
156 }
157
158 /*
159  * olsr_spf_extract_best
160  *
161  * return the node with the minimum pathcost.
162  */
163 static struct tc_entry *
164 olsr_spf_extract_best (struct avl_tree *tree)
165 {
166   struct avl_node *node = avl_walk_first(tree);
167
168   return (node ? cand_tree2tc(node) :  NULL);
169 }
170
171
172 /*
173  * olsr_spf_relax
174  *
175  * Explore all edges of a node and add the node
176  * to the candidate tree if the if the aggregate
177  * path cost is better.
178  */
179 static void
180 olsr_spf_relax (struct avl_tree *cand_tree, struct tc_entry *tc)
181 {
182   struct avl_node *edge_node;
183   olsr_linkcost new_cost;
184
185 #ifdef DEBUG
186 #ifndef NODEBUG
187   struct ipaddr_str buf, nbuf;
188   struct lqtextbuffer lqbuffer;
189 #endif
190   OLSR_PRINTF(2, "SPF: exploring node %s, cost %s\n",
191               olsr_ip_to_string(&buf, &tc->addr),
192               get_linkcost_text(tc->path_cost, false, &lqbuffer));
193 #endif
194
195   /*
196    * loop through all edges of this vertex.
197    */
198   for (edge_node = avl_walk_first(&tc->edge_tree);
199        edge_node;
200        edge_node = avl_walk_next(edge_node)) {
201
202     struct tc_entry *new_tc;
203     struct tc_edge_entry *tc_edge = edge_tree2tc_edge(edge_node);
204
205     /*
206      * We are not interested in dead-end edges.
207      */
208     if (!tc_edge->edge_inv) {
209 #ifdef DEBUG
210       OLSR_PRINTF(2, "SPF:   ignoring edge %s\n",
211                   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");
214       }
215 #endif
216       continue;
217     }
218
219     /*
220      * total quality of the path through this vertex
221      * to the destination of this edge
222      */
223     new_cost = tc->path_cost + tc_edge->cost;
224
225 #ifdef DEBUG
226     OLSR_PRINTF(2, "SPF:   exploring edge %s, cost %s\n",
227                 olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
228                 get_linkcost_text(new_cost, true, &lqbuffer));
229 #endif
230
231     /* 
232      * if it's better than the current path quality of this edge's
233      * destination node, then we've found a better path to this node.
234      */
235     new_tc = tc_edge->edge_inv->tc;
236
237     if (new_cost < new_tc->path_cost) {
238
239       /* if this node has been on the candidate tree delete it */
240       if (new_tc->path_cost < ROUTE_COST_BROKEN) {
241         olsr_spf_del_cand_tree(cand_tree, new_tc);
242       }
243
244       /* re-insert on candidate tree with the better metric */
245       new_tc->path_cost = new_cost;
246       olsr_spf_add_cand_tree(cand_tree, new_tc);
247
248       /* pull-up the next-hop and bump the hop count */
249       if (tc->next_hop) {
250         new_tc->next_hop = tc->next_hop;
251       }
252       new_tc->hops = tc->hops + 1;
253
254 #ifdef DEBUG
255       OLSR_PRINTF(2, "SPF:   better path to %s, cost %s, via %s, hops %u\n",
256                   olsr_ip_to_string(&buf, &new_tc->addr),
257                   get_linkcost_text(new_cost, true, &lqbuffer),
258                   tc->next_hop ? olsr_ip_to_string(
259                     &nbuf, &tc->next_hop->neighbor_iface_addr) : "<none>",
260                   new_tc->hops);
261 #endif
262
263     }
264   }
265 }
266
267 /*
268  * olsr_spf_run_full
269  *
270  * Run the Dijkstra algorithm.
271  * 
272  * A node gets added to the candidate tree when one of its edges has
273  * an overall better root path cost than the node itself.
274  * The node with the shortest metric gets moved from the candidate to
275  * the path list every pass.
276  * The SPF computation is completed when there are no more nodes
277  * on the candidate tree. 
278  */ 
279 static void
280 olsr_spf_run_full (struct avl_tree *cand_tree, struct list_node *path_list,
281                    int *path_count)
282 {
283   struct tc_entry *tc;
284
285   *path_count = 0;
286
287   while ((tc = olsr_spf_extract_best(cand_tree))) {
288
289     olsr_spf_relax(cand_tree, tc);
290
291     /*
292      * move the best path from the candidate tree
293      * to the path list.
294      */
295     olsr_spf_del_cand_tree(cand_tree, tc);
296     olsr_spf_add_path_list(path_list, path_count, tc);
297   }
298 }
299
300 /**
301  * Callback for the SPF backoff timer.
302  */
303 static void
304 olsr_expire_spf_backoff(void *context __attribute__((unused)))
305 {
306   spf_backoff_timer = NULL;
307 }
308
309 void
310 olsr_calculate_routing_table (void)
311 {
312 #ifdef SPF_PROFILING
313   struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total;
314 #endif
315   struct avl_tree cand_tree;
316   struct avl_node *rtp_tree_node;
317   struct list_node path_list; /* head of the path_list */
318   struct tc_entry *tc;
319   struct rt_path *rtp;
320   struct tc_edge_entry *tc_edge;
321   struct neighbor_entry *neigh;
322   struct link_entry *link;
323   int path_count = 0;
324
325   /* We are done if our backoff timer is running */
326   if (spf_backoff_timer) {
327     return;
328   }
329   spf_backoff_timer = 
330       olsr_start_timer(OLSR_SPF_BACKOFF_TIME, OLSR_SPF_BACKOFF_JITTER,
331                        OLSR_TIMER_ONESHOT, &olsr_expire_spf_backoff,
332                        NULL, spf_backoff_timer_cookie->ci_id);
333
334 #ifdef SPF_PROFILING
335   gettimeofday(&t1, NULL);
336 #endif
337
338   /*
339    * Prepare the candidate tree and result list.
340    */
341   avl_init(&cand_tree, avl_comp_etx);
342   list_head_init(&path_list);
343   olsr_bump_routingtree_version();
344
345   /*
346    * Initialize vertices in the lsdb.
347    */
348   OLSR_FOR_ALL_TC_ENTRIES(tc) {
349     tc->next_hop = NULL;
350     tc->path_cost = ROUTE_COST_BROKEN;
351     tc->hops = 0;
352   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
353
354
355   /*
356    * Check if there was a change in the main IP address.
357    * Bail if there is no main IP address.
358    */
359   olsr_change_myself_tc();
360   if (!tc_myself) {
361
362     /*
363      * All gone now. Flush all routes.
364      */
365     olsr_update_rib_routes();
366     olsr_update_kernel_routes();
367     return;
368   }
369
370   /*
371    * zero ourselves and add us to the candidate tree.
372    */
373   tc_myself->path_cost = ZERO_ROUTE_COST;
374   olsr_spf_add_cand_tree(&cand_tree, tc_myself);
375
376   /*
377    * add edges to and from our neighbours.
378    */
379   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
380
381     if (neigh->status == SYM) {
382
383       tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
384       link = get_best_link_to_neighbor(&neigh->neighbor_main_addr);
385       if (!link) {
386
387         /*
388          * If there is no best link to this neighbor
389          * and we had an edge before then flush the edge.
390          */
391         if (tc_edge) {
392           olsr_delete_tc_edge_entry(tc_edge);
393         }
394         continue;
395       }
396
397       /* find the interface for the link */
398       if (link->if_name) {
399         link->inter = if_ifwithname(link->if_name);
400       } else {
401         link->inter = if_ifwithaddr(&link->local_iface_addr);
402       }
403
404       /*
405        * Set the next-hops of our neighbors. 
406        */
407       if (!tc_edge) {
408         tc_edge = olsr_add_tc_edge_entry(tc_myself, &neigh->neighbor_main_addr,
409                                          0);
410       } else {
411
412         /*
413          * Update LQ and timers, such that the edge does not get deleted.
414          */
415         olsr_copylq_link_entry_2_tc_edge_entry(tc_edge, link);
416         olsr_calc_tc_edge_entry_etx(tc_edge);
417       }
418       if (tc_edge->edge_inv) {
419         tc_edge->edge_inv->tc->next_hop = link;
420       }
421     }
422   } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
423
424 #ifdef SPF_PROFILING
425   gettimeofday(&t2, NULL);
426 #endif
427
428   /*
429    * Run the SPF calculation.
430    */
431   olsr_spf_run_full(&cand_tree, &path_list, &path_count);
432
433   OLSR_PRINTF(2, "\n--- %s ------------------------------------------------- DIJKSTRA\n\n",
434               olsr_wallclock_string());
435
436 #ifdef SPF_PROFILING
437   gettimeofday(&t3, NULL);
438 #endif
439
440   /*
441    * In the path list we have all the reachable nodes in our topology.
442    */
443   for (; !list_is_empty(&path_list); list_remove(path_list.next)) {
444
445     tc = pathlist2tc(path_list.next);
446     link = tc->next_hop;
447
448     if (!link) {
449 #ifdef DEBUG
450       /*
451        * Supress the error msg when our own tc_entry
452        * does not contain a next-hop.
453        */
454       if (tc != tc_myself) {
455         struct ipaddr_str buf;
456         OLSR_PRINTF(2, "SPF: %s no next-hop\n", olsr_ip_to_string(&buf, &tc->addr));
457       }
458 #endif
459       continue;
460     }
461
462     /*
463      * Now walk all prefixes advertised by that node.
464      * Since the node is reachable, insert the prefix into the global RIB.
465      * If the prefix is already in the RIB, refresh the entry such
466      * that olsr_delete_outdated_routes() does not purge it off.
467      */
468     for (rtp_tree_node = avl_walk_first(&tc->prefix_tree);
469          rtp_tree_node;
470          rtp_tree_node = avl_walk_next(rtp_tree_node)) {
471
472       rtp = rtp_prefix_tree2rtp(rtp_tree_node);
473
474       if (rtp->rtp_rt) {
475
476         /*
477          * If there is a route entry, the prefix is already in the global RIB.
478          */
479         olsr_update_rt_path(rtp, tc, link);
480
481       } else {
482
483         /*
484          * The prefix is reachable and not yet in the global RIB.
485          * Build a rt_entry for it.
486          */
487         olsr_insert_rt_path(rtp, tc, link);
488       }
489     }
490   }
491
492   /* Update the RIB based on the new SPF results */
493
494   olsr_update_rib_routes();
495
496 #ifdef SPF_PROFILING
497   gettimeofday(&t4, NULL);
498 #endif
499
500   /* move the route changes into the kernel */
501
502   olsr_update_kernel_routes();
503
504 #ifdef SPF_PROFILING
505   gettimeofday(&t5, NULL);
506 #endif
507
508 #ifdef SPF_PROFILING
509   timersub(&t2, &t1, &spf_init);
510   timersub(&t3, &t2, &spf_run);
511   timersub(&t4, &t3, &route);
512   timersub(&t5, &t4, &kernel);
513   timersub(&t5, &t1, &total);
514   OLSR_PRINTF(1, "\n--- SPF-stats for %d nodes, %d routes (total/init/run/route/kern): "
515               "%d, %d, %d, %d, %d\n",
516               path_count, routingtree.count,
517               (int)total.tv_usec, (int)spf_init.tv_usec, (int)spf_run.tv_usec,
518               (int)route.tv_usec, (int)kernel.tv_usec);
519 #endif
520 }
521
522 /*
523  * Local Variables:
524  * c-basic-offset: 2
525  * indent-tabs-mode: nil
526  * End:
527  */