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