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