cf1e6b9606999a7116d6bd0c2c713a5db68e11a3
[olsrd.git] / src / olsr_spf.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <assert.h>
43
44 #include "olsr_spf.h"
45 #include "tc_set.h"
46 #include "neighbor_table.h"
47 #include "routing_table.h"
48 #include "lq_plugin.h"
49 #include "process_routes.h"
50 #include "olsr_logging.h"
51
52 struct olsr_timer_info *spf_backoff_timer_info = NULL;
53 struct timer_entry *spf_backoff_timer = NULL;
54
55 /*
56  * avl_comp_etx
57  *
58  * compare two etx metrics.
59  * return 0 if there is an exact match and
60  * -1 / +1 depending on being smaller or bigger.
61  * note that this results in the most optimal code
62  * after compiler optimization.
63  */
64 static int
65 avl_comp_etx(const void *etx1, const void *etx2, void *ptr __attribute__ ((unused)))
66 {
67   if (*(const olsr_linkcost *)etx1 < *(const olsr_linkcost *)etx2) {
68     return -1;
69   }
70
71   if (*(const olsr_linkcost *)etx1 > *(const olsr_linkcost *)etx2) {
72     return +1;
73   }
74
75   return 0;
76 }
77
78 /*
79  * olsr_spf_add_cand_tree
80  *
81  * Key an existing vertex to a candidate tree.
82  */
83 static void
84 olsr_spf_add_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
85 {
86 #if !defined REMOVE_LOG_DEBUG
87   struct ipaddr_str buf;
88   char lqbuffer[LQTEXT_MAXLENGTH];
89 #endif
90   tc->cand_tree_node.key = &tc->path_cost;
91
92   OLSR_DEBUG(LOG_ROUTING, "SPF: insert candidate %s, cost %s\n",
93              olsr_ip_to_string(&buf, &tc->addr), olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)));
94
95   avl_insert(tree, &tc->cand_tree_node);
96 }
97
98 /*
99  * olsr_spf_del_cand_tree
100  *
101  * Unkey an existing vertex from a candidate tree.
102  */
103 static void
104 olsr_spf_del_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
105 {
106   if (tc->cand_tree_node.key) {
107 #if !defined REMOVE_LOG_DEBUG
108     struct ipaddr_str buf;
109     char lqbuffer[LQTEXT_MAXLENGTH];
110 #endif
111     OLSR_DEBUG(LOG_ROUTING, "SPF: delete candidate %s, cost %s\n",
112         olsr_ip_to_string(&buf, &tc->addr), olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)));
113
114     avl_delete(tree, &tc->cand_tree_node);
115     tc->cand_tree_node.key = NULL;
116   }
117 }
118
119 /*
120  * olsr_spf_add_path_list
121  *
122  * Insert an SPF result at the end of the path list.
123  */
124 static void
125 olsr_spf_add_path_list(struct list_entity *head, int *path_count, struct tc_entry *tc)
126 {
127 #if !defined REMOVE_LOG_DEBUG
128   struct ipaddr_str pathbuf, nbuf;
129   char lqbuffer[LQTEXT_MAXLENGTH];
130 #endif
131
132   OLSR_DEBUG(LOG_ROUTING, "SPF: append path %s, cost %s, via %s\n",
133              olsr_ip_to_string(&pathbuf, &tc->addr),
134              olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)),
135              tc->next_hop ? olsr_ip_to_string(&nbuf, &tc->next_hop->neighbor_iface_addr) : "-");
136
137   list_add_before(head, &tc->path_list_node);
138   *path_count = *path_count + 1;
139 }
140
141 /*
142  * olsr_spf_extract_best
143  *
144  * return the node with the minimum pathcost.
145  */
146 static struct tc_entry *
147 olsr_spf_extract_best(struct avl_tree *tree)
148 {
149   struct tc_entry *tc = NULL;
150   if (tree->count) {
151     tc = avl_first_element(tree, tc, cand_tree_node);
152   }
153   return tc;
154 }
155
156
157 /*
158  * olsr_spf_relax
159  *
160  * Explore all edges of a node and add the node
161  * to the candidate tree if the if the aggregate
162  * path cost is better.
163  */
164 static void
165 olsr_spf_relax(struct avl_tree *cand_tree, struct tc_entry *tc)
166 {
167   struct tc_edge_entry *tc_edge;
168   struct list_iterator iterator;
169   olsr_linkcost new_cost;
170
171 #if !defined REMOVE_LOG_DEBUG
172   struct ipaddr_str buf, nbuf;
173   char lqbuffer[LQTEXT_MAXLENGTH];
174 #endif
175   OLSR_DEBUG(LOG_ROUTING, "SPF: exploring node %s, cost %s\n",
176              olsr_ip_to_string(&buf, &tc->addr),
177              olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)));
178
179   /*
180    * loop through all edges of this vertex.
181    */
182   OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge, iterator) {
183     struct tc_entry *new_tc;
184
185     assert (tc_edge->edge_inv);
186
187     /*
188      * total quality of the path through this vertex
189      * to the destination of this edge
190      */
191     if (tc_edge->virtual) {
192       new_cost = tc->path_cost + tc_edge->edge_inv->cost;
193     }
194     else {
195       new_cost = tc->path_cost + tc_edge->cost;
196     }
197
198     OLSR_DEBUG(LOG_ROUTING, "SPF:   exploring edge %s, cost %s\n",
199                olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
200                olsr_get_linkcost_text(new_cost, true, lqbuffer, sizeof(lqbuffer)));
201
202     /*
203      * if it's better than the current path quality of this edge's
204      * destination node, then we've found a better path to this node.
205      */
206     new_tc = tc_edge->edge_inv->tc;
207
208     if (new_cost < new_tc->path_cost) {
209
210       /* if this node has been on the candidate tree delete it */
211       if (new_tc->path_cost < ROUTE_COST_BROKEN) {
212         olsr_spf_del_cand_tree(cand_tree, new_tc);
213       }
214
215       /* remove from result list if necessary */
216       if (list_node_added(&new_tc->path_list_node)) {
217         list_remove(&new_tc->path_list_node);
218       }
219
220       /* re-insert on candidate tree with the better metric */
221       new_tc->path_cost = new_cost;
222       olsr_spf_add_cand_tree(cand_tree, new_tc);
223
224       /* pull-up the next-hop and bump the hop count */
225       if (tc->next_hop) {
226         new_tc->next_hop = tc->next_hop;
227       }
228       new_tc->hops = tc->hops + 1;
229
230       OLSR_DEBUG(LOG_ROUTING, "SPF:   better path to %s, cost %s, via %s, hops %d\n",
231                  olsr_ip_to_string(&buf, &new_tc->addr),
232                  olsr_get_linkcost_text(new_cost, true, lqbuffer, sizeof(lqbuffer)),
233                  tc->next_hop ? olsr_ip_to_string(&nbuf, &tc->next_hop->neighbor_iface_addr) : "<none>", new_tc->hops);
234     }
235   }
236 }
237
238 /*
239  * olsr_spf_run_full
240  *
241  * Run the Dijkstra algorithm.
242  *
243  * A node gets added to the candidate tree when one of its edges has
244  * an overall better root path cost than the node itself.
245  * The node with the shortest metric gets moved from the candidate to
246  * the path list every pass.
247  * The SPF computation is completed when there are no more nodes
248  * on the candidate tree.
249  */
250 static void
251 olsr_spf_run_full(struct avl_tree *cand_tree, struct list_entity *path_list, int *path_count)
252 {
253   struct tc_entry *tc;
254
255   *path_count = 0;
256
257   while ((tc = olsr_spf_extract_best(cand_tree))) {
258     olsr_spf_relax(cand_tree, tc);
259
260     /*
261      * move the best path from the candidate tree
262      * to the path list.
263      */
264     olsr_spf_del_cand_tree(cand_tree, tc);
265     olsr_spf_add_path_list(path_list, path_count, tc);
266   }
267 }
268
269 /**
270  * Callback for the SPF backoff timer.
271  */
272 static void
273 olsr_expire_spf_backoff(void *context __attribute__ ((unused)))
274 {
275   spf_backoff_timer = NULL;
276 }
277
278 void
279 olsr_init_spf(void) {
280   spf_backoff_timer_info = olsr_alloc_timerinfo("SPF backoff", olsr_expire_spf_backoff, false);
281 }
282
283 void
284 olsr_calculate_routing_table(bool force)
285 {
286 #ifdef SPF_PROFILING
287   struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total;
288 #endif
289   struct avl_tree cand_tree;
290   struct list_entity path_list;          /* head of the path_list */
291   struct tc_entry *tc;
292   struct rt_path *rtp;
293   struct tc_edge_entry *tc_edge;
294   struct nbr_entry *neigh;
295   struct link_entry *link;
296   int path_count = 0;
297   struct list_iterator iterator;
298
299   /* We are done if our backoff timer is running */
300   if (!force && spf_backoff_timer != NULL) {
301     return;
302   }
303
304   olsr_set_timer(&spf_backoff_timer, OLSR_SPF_BACKOFF_TIME, OLSR_SPF_BACKOFF_JITTER,
305       NULL, spf_backoff_timer_info);
306
307 #ifdef SPF_PROFILING
308   gettimeofday(&t1, NULL);
309 #endif
310
311   /*
312    * Prepare the candidate tree and result list.
313    */
314   avl_init(&cand_tree, avl_comp_etx, true, NULL);
315   list_init_head(&path_list);
316   olsr_bump_routingtree_version();
317
318   /*
319    * Initialize vertices in the lsdb.
320    */
321   OLSR_FOR_ALL_TC_ENTRIES(tc, iterator) {
322     tc->next_hop = NULL;
323     tc->path_cost = ROUTE_COST_BROKEN;
324     tc->hops = 0;
325     tc->cand_tree_node.key = NULL;
326     list_init_head(&tc->path_list_node);
327   }
328
329   /*
330    * Check if there was a change in the main IP address.
331    * Bail if there is no main IP address.
332    */
333   olsr_change_myself_tc();
334   if (!tc_myself) {
335
336     /*
337      * All gone now. Flush all routes.
338      */
339     olsr_update_rib_routes();
340     olsr_update_kernel_routes();
341     return;
342   }
343
344   /*
345    * zero ourselves and add us to the candidate tree.
346    */
347   tc_myself->path_cost = ZERO_ROUTE_COST;
348   olsr_spf_add_cand_tree(&cand_tree, tc_myself);
349
350   /*
351    * Set the next-hops of our neighbor link.
352    */
353   OLSR_FOR_ALL_NBR_ENTRIES(neigh, iterator) {
354     tc_edge = neigh->tc_edge;
355
356     if (neigh->is_sym) {
357       /* edges are always symmetric */
358       assert(tc_edge->edge_inv);
359
360       tc_edge->edge_inv->tc->next_hop = get_best_link_to_neighbor(neigh);
361     }
362   }
363
364 #ifdef SPF_PROFILING
365   gettimeofday(&t2, NULL);
366 #endif
367
368   /*
369    * Run the SPF calculation.
370    */
371   olsr_spf_run_full(&cand_tree, &path_list, &path_count);
372
373   OLSR_DEBUG(LOG_ROUTING, "\n--- %s ------------------------------------------------- DIJKSTRA\n\n", olsr_wallclock_string());
374
375 #ifdef SPF_PROFILING
376   gettimeofday(&t3, NULL);
377 #endif
378
379   /*
380    * In the path list we have all the reachable nodes in our topology.
381    */
382   while (!list_is_empty(&path_list)) {
383     tc = list_first_element(&path_list, tc, path_list_node);
384     list_remove(&tc->path_list_node);
385
386     link = tc->next_hop;
387
388     if (!link) {
389       /*
390        * Supress the error msg when our own tc_entry
391        * does not contain a next-hop.
392        */
393       if (tc != tc_myself) {
394 #if !defined REMOVE_LOG_DEBUG
395         struct ipaddr_str buf;
396 #endif
397         OLSR_DEBUG(LOG_ROUTING, "SPF: %s no next-hop\n", olsr_ip_to_string(&buf, &tc->addr));
398       }
399       continue;
400     }
401
402     /*
403      * Now walk all prefixes advertised by that node.
404      * Since the node is reachable, insert the prefix into the global RIB.
405      * If the prefix is already in the RIB, refresh the entry such
406      * that olsr_delete_outdated_routes() does not purge it off.
407      */
408     OLSR_FOR_ALL_PREFIX_ENTRIES(tc, rtp, iterator) {
409       if (rtp->rtp_rt) {
410
411         /*
412          * If there is a route entry, the prefix is already in the global RIB.
413          */
414         olsr_update_rt_path(rtp, tc, link);
415
416       } else {
417
418         /*
419          * The prefix is reachable and not yet in the global RIB.
420          * Build a rt_entry for it.
421          */
422         olsr_insert_rt_path(rtp, tc, link);
423       }
424     }
425   }
426
427   /* Update the RIB based on the new SPF results */
428
429   olsr_update_rib_routes();
430
431 #ifdef SPF_PROFILING
432   gettimeofday(&t4, NULL);
433 #endif
434
435   /* move the route changes into the kernel */
436
437   olsr_update_kernel_routes();
438
439 #ifdef SPF_PROFILING
440   gettimeofday(&t5, NULL);
441 #endif
442
443 #ifdef SPF_PROFILING
444   timersub(&t2, &t1, &spf_init);
445   timersub(&t3, &t2, &spf_run);
446   timersub(&t4, &t3, &route);
447   timersub(&t5, &t4, &kernel);
448   timersub(&t5, &t1, &total);
449   OLSR_DEBUG(LOG_ROUTING, "\n--- SPF-stats for %d nodes, %d routes (total/init/run/route/kern): "
450              "%d, %d, %d, %d, %d\n",
451              path_count, routingtree.count,
452              (int)total.tv_usec, (int)spf_init.tv_usec, (int)spf_run.tv_usec, (int)route.tv_usec, (int)kernel.tv_usec);
453 #endif
454 }
455
456 /*
457  * Local Variables:
458  * c-basic-offset: 2
459  * indent-tabs-mode: nil
460  * End:
461  */