bugfix fpm display precicion issues
[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 /*
69  * avl_comp_etx
70  *
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.
76  */
77 static int
78 avl_comp_etx (const void *etx1, const void *etx2)
79 {       
80   if (*(const float *)etx1 < *(const float *)etx2) {
81     return -1;
82   }
83
84   if (*(const float *)etx1 > *(const float *)etx2) {
85     return +1;
86   }
87
88   return 0;
89 }
90
91 /*
92  * olsr_spf_add_cand_tree
93  *
94  * Key an existing vertex to a candidate tree.
95  */
96 static void
97 olsr_spf_add_cand_tree (struct avl_tree *tree,
98                         struct tc_entry *tc)
99 {
100 #if !defined(NODEBUG) && defined(DEBUG)
101   struct ipaddr_str buf;
102 #endif
103   tc->cand_tree_node.key = &tc->path_etx;
104   tc->cand_tree_node.data = tc;
105
106 #ifdef DEBUG
107   OLSR_PRINTF(1, "SPF: insert candidate %s, cost %s\n",
108               olsr_ip_to_string(&buf, &tc->addr),
109               etxtoa(tc->path_etx));
110 #endif
111
112   avl_insert(tree, &tc->cand_tree_node, AVL_DUP);
113 }
114
115 /*
116  * olsr_spf_del_cand_tree
117  *
118  * Unkey an existing vertex from a candidate tree.
119  */
120 static void
121 olsr_spf_del_cand_tree (struct avl_tree *tree,
122                         struct tc_entry *tc)
123 {
124
125 #ifdef DEBUG
126 #ifndef NODEBUG
127   struct ipaddr_str buf;
128 #endif
129   OLSR_PRINTF(1, "SPF: delete candidate %s, cost %s\n",
130               olsr_ip_to_string(&buf, &tc->addr),
131               etxtoa(tc->path_etx));
132 #endif
133
134   avl_delete(tree, &tc->cand_tree_node);
135 }
136
137 /*
138  * olsr_spf_add_path_list
139  *
140  * Insert an SPF result at the end of the path list.
141  */
142 static void
143 olsr_spf_add_path_list (struct list_node *head, int *path_count,
144                         struct tc_entry *tc)
145 {
146 #if !defined(NODEBUG) && defined(DEBUG)
147   struct ipaddr_str pathbuf, nbuf;
148 #endif
149   tc->path_list_node.data = tc;
150
151 #ifdef DEBUG
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) : "-");
157 #endif
158
159   list_add_before(head, &tc->path_list_node);
160   *path_count = *path_count + 1;
161 }
162
163 /*
164  * olsr_spf_extract_best
165  *
166  * return the node with the minimum pathcost.
167  */
168 static struct tc_entry *
169 olsr_spf_extract_best (struct avl_tree *tree)
170 {
171   struct avl_node *node = avl_walk_first(tree);
172
173   return (node ? node->data :  NULL);
174 }
175
176
177 /*
178  * olsr_spf_relax
179  *
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.
183  */
184 static void
185 olsr_spf_relax (struct avl_tree *cand_tree, struct tc_entry *tc)
186 {
187   struct avl_node *edge_node;
188 #ifdef USE_FPM
189   fpm new_etx;
190 #else
191   float new_etx;
192 #endif
193
194 #ifdef DEBUG
195 #ifndef NODEBUG
196   struct ipaddr_str buf, nbuf;
197 #endif
198   OLSR_PRINTF(1, "SPF: exploring node %s, cost %s\n",
199               olsr_ip_to_string(&buf, &tc->addr),
200               etxtoa(tc->path_etx));
201 #endif
202
203   /*
204    * loop through all edges of this vertex.
205    */
206   for (edge_node = avl_walk_first(&tc->edge_tree);
207        edge_node;
208        edge_node = avl_walk_next(edge_node)) {
209
210     struct tc_entry *new_tc;
211     struct tc_edge_entry *tc_edge = edge_node->data;
212
213     /*
214      * We are not interested in dead-end or dying edges.
215      */
216     if (!tc_edge->edge_inv || (tc_edge->flags & OLSR_TC_EDGE_DOWN)) {
217 #ifdef DEBUG
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");
222       }
223       if (!tc_edge->edge_inv) {
224         OLSR_PRINTF(1, "SPF:     no inverse edge\n");
225       }
226 #endif
227       continue;
228     }
229
230     /*
231      * total quality of the path through this vertex
232      * to the destination of this edge
233      */
234 #ifdef USE_FPM
235     new_etx = INFINITE_ETX <= tc->path_etx || INFINITE_ETX <= tc_edge->etx
236       ? INFINITE_ETX : fpmadd(tc->path_etx, tc_edge->etx);
237 #else
238     new_etx = tc->path_etx + tc_edge->etx;
239 #endif
240
241 #ifdef DEBUG
242       OLSR_PRINTF(1, "SPF:   exploring edge %s, cost %s\n",
243                   olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
244                   etxtoa(new_etx));
245 #endif
246
247       /* 
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.
250        */
251     new_tc = tc_edge->edge_inv->tc;
252
253     if (new_etx < new_tc->path_etx) {
254
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);
258       }
259
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);
263
264       /* pull-up the next-hop and bump the hop count */
265       if (tc->next_hop) {
266         new_tc->next_hop = tc->next_hop;
267       }
268       new_tc->hops = tc->hops + 1;
269
270 #ifdef DEBUG
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),
274                   etxtoa(new_etx),
275                   tc->next_hop ? olsr_ip_to_string(
276                     &nbuf, &tc->next_hop->neighbor_iface_addr) : "<none>",
277                   new_tc->hops);
278 #endif
279
280     }
281   }
282 }
283
284 /*
285  * olsr_spf_run_full
286  *
287  * Run the Dijkstra algorithm.
288  * 
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. 
295  */ 
296 static void
297 olsr_spf_run_full (struct avl_tree *cand_tree, struct list_node *path_list,
298                    int *path_count)
299 {
300   struct tc_entry *tc;
301
302   *path_count = 0;
303
304   while ((tc = olsr_spf_extract_best(cand_tree))) {
305
306     olsr_spf_relax(cand_tree, tc);
307
308     /*
309      * move the best path from the candidate tree
310      * to the path list.
311      */
312     olsr_spf_del_cand_tree(cand_tree, tc);
313     olsr_spf_add_path_list(path_list, path_count, tc);
314   }
315 }
316
317 void
318 olsr_calculate_routing_table (void)
319 {
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;
324   struct tc_entry *tc;
325   struct rt_path *rtp;
326   struct tc_edge_entry *tc_edge;
327   struct neighbor_entry *neigh;
328   struct link_entry *link;
329
330 #ifdef SPF_PROFILING
331   struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total;
332
333   gettimeofday(&t1, NULL);
334 #endif
335
336   /*
337    * Prepare the candidate tree and result list.
338    */
339   avl_init(&cand_tree, avl_comp_etx);
340   list_head_init(&path_list);
341   olsr_bump_routingtree_version();
342
343   /*
344    * Initialize vertices in the lsdb.
345    */
346   OLSR_FOR_ALL_TC_ENTRIES(tc) {
347     tc->next_hop = NULL;
348     tc->path_etx = INFINITE_ETX;
349     tc->hops = 0;
350   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
351
352   /*
353    * zero ourselves and add us to the candidate tree.
354    */
355   olsr_change_myself_tc();
356   tc_myself->path_etx = ZERO_ETX;
357   olsr_spf_add_cand_tree(&cand_tree, tc_myself);
358
359   /*
360    * add edges to and from our neighbours.
361    */
362   for (i = 0; i < HASHSIZE; i++)
363     for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
364          neigh = neigh->next) {
365
366       if (neigh->status == SYM) {
367
368         tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
369         link = get_best_link_to_neighbor(&neigh->neighbor_main_addr);
370         if (!link) {
371
372           /*
373            * If there is no best link to this neighbor
374            * and we had an edge before then flush the edge.
375            */
376           if (tc_edge) {
377             olsr_delete_tc_edge_entry(tc_edge);
378           }
379           continue;
380         }
381
382         /* find the interface for the link */
383         if (link->if_name) {
384           link->inter = if_ifwithname(link->if_name);
385         } else {
386           link->inter = if_ifwithaddr(&link->local_iface_addr);
387         }
388
389         /*
390          * Set the next-hops of our neighbors. 
391          */
392         if (!tc_edge) {
393           tc_edge = olsr_add_tc_edge_entry(tc_myself, &neigh->neighbor_main_addr,
394                                            0, link->vtime,
395                                            link->loss_link_quality2,
396                                            link->neigh_link_quality2);
397         } else {
398
399           /*
400            * Update LQ and timers, such that the edge does not get deleted.
401            */
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);
406         }
407         if (tc_edge->edge_inv) {
408           tc_edge->edge_inv->tc->next_hop = link;
409         }
410       }
411     }
412
413 #ifdef SPF_PROFILING
414   gettimeofday(&t2, NULL);
415 #endif
416
417   /*
418    * Run the SPF calculation.
419    */
420   olsr_spf_run_full(&cand_tree, &path_list, &path_count);
421
422   OLSR_PRINTF(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n",
423               nowtm->tm_hour,
424               nowtm->tm_min,
425               nowtm->tm_sec,
426               (int)now.tv_usec/10000);
427
428 #ifdef SPF_PROFILING
429   gettimeofday(&t3, NULL);
430 #endif
431
432   /*
433    * In the path list we have all the reachable nodes in our topology.
434    */
435   for (; !list_is_empty(&path_list); list_remove(path_list.next)) {
436
437     tc = path_list.next->data;
438     link = tc->next_hop;
439
440     if (!link) {
441 #ifdef DEBUG
442       /*
443        * Supress the error msg when our own tc_entry
444        * does not contain a next-hop.
445        */
446       if (tc != tc_myself) {
447 #ifndef NODEBUG
448         struct ipaddr_str buf;
449 #endif
450         OLSR_PRINTF(1, "SPF: %s no next-hop\n", olsr_ip_to_string(&buf, &tc->addr));
451       }
452 #endif
453       continue;
454     }
455
456     /*
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.
461      */
462     for (rtp_tree_node = avl_walk_first(&tc->prefix_tree);
463          rtp_tree_node;
464          rtp_tree_node = avl_walk_next(rtp_tree_node)) {
465
466       rtp = rtp_tree_node->data;
467
468       if (rtp->rtp_rt) {
469
470         /*
471          * If there is a route entry, the prefix is already in the global RIB.
472          */
473         olsr_update_rt_path(rtp, tc, link);
474
475       } else {
476
477         /*
478          * The prefix is reachable and not yet in the global RIB.
479          * Build a rt_entry for it.
480          */
481         olsr_insert_rt_path(rtp, tc, link);
482       }
483     }
484   }
485
486   /* Update the RIB based on the new SPF results */
487
488   olsr_update_rib_routes();
489
490 #ifdef SPF_PROFILING
491   gettimeofday(&t4, NULL);
492 #endif
493
494   /* move the route changes into the kernel */
495
496   olsr_update_kernel_routes();
497
498 #ifdef SPF_PROFILING
499   gettimeofday(&t5, NULL);
500 #endif
501
502 #ifdef SPF_PROFILING
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);
513 #endif
514 }
515
516 /*
517  * Local Variables:
518  * c-basic-offset: 2
519  * End:
520  */