gateway: introduce and use removeGatewayFromList function
[olsrd.git] / src / olsr_spf.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
5  * IPv4 performance optimization (c) 2006, sven-ola(gmx.de)
6  * SPF implementation (c) 2007, Hannes Gredler (hannes@gredler.at)
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  *   notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above copyright
16  *   notice, this list of conditions and the following disclaimer in
17  *   the documentation and/or other materials provided with the
18  *   distribution.
19  * * Neither the name of olsr.org, olsrd nor the names of its
20  *   contributors may be used to endorse or promote products derived
21  *   from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * Visit http://www.olsr.org for more information.
37  *
38  * If you find this software useful feel free to make a donation
39  * to the project. For more information see the website or contact
40  * the copyright holders.
41  *
42  * Implementation of Dijkstras algorithm. Initially all nodes
43  * are initialized to infinite cost. First we put ourselves
44  * on the heap of reachable nodes. Our heap implementation
45  * is based on an AVL tree which gives interesting performance
46  * characteristics for the frequent operations of minimum key
47  * extraction and re-keying. Next all neighbors of a node are
48  * explored and put on the heap if the cost of reaching them is
49  * better than reaching the current candidate node.
50  * The SPF calculation is terminated if there are no more nodes
51  * on the heap.
52  */
53
54 #include "ipcalc.h"
55 #include "defs.h"
56 #include "olsr.h"
57 #include "tc_set.h"
58 #include "neighbor_table.h"
59 #include "two_hop_neighbor_table.h"
60 #include "link_set.h"
61 #include "routing_table.h"
62 #include "mid_set.h"
63 #include "hna_set.h"
64 #include "common/list.h"
65 #include "common/avl.h"
66 #include "olsr_spf.h"
67 #include "net_olsr.h"
68 #include "lq_plugin.h"
69 #include "gateway.h"
70
71 struct timer_entry *spf_backoff_timer = NULL;
72
73 /*
74  * avl_comp_etx
75  *
76  * compare two etx metrics.
77  * return 0 if there is an exact match and
78  * -1 / +1 depending on being smaller or bigger.
79  * note that this results in the most optimal code
80  * after compiler optimization.
81  */
82 static int
83 avl_comp_etx(const void *etx1, const void *etx2)
84 {
85   if (*(const olsr_linkcost *)etx1 < *(const olsr_linkcost *)etx2) {
86     return -1;
87   }
88
89   if (*(const olsr_linkcost *)etx1 > *(const olsr_linkcost *)etx2) {
90     return +1;
91   }
92
93   return 0;
94 }
95
96 /*
97  * olsr_spf_add_cand_tree
98  *
99  * Key an existing vertex to a candidate tree.
100  */
101 static void
102 olsr_spf_add_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
103 {
104 #if !defined(NODEBUG) && defined(DEBUG)
105   struct ipaddr_str buf;
106   struct lqtextbuffer lqbuffer;
107 #endif /* !defined(NODEBUG) && defined(DEBUG) */
108   tc->cand_tree_node.key = &tc->path_cost;
109
110 #ifdef DEBUG
111   OLSR_PRINTF(2, "SPF: insert candidate %s, cost %s\n", olsr_ip_to_string(&buf, &tc->addr),
112               get_linkcost_text(tc->path_cost, false, &lqbuffer));
113 #endif /* DEBUG */
114
115   avl_insert(tree, &tc->cand_tree_node, AVL_DUP);
116 }
117
118 /*
119  * olsr_spf_del_cand_tree
120  *
121  * Unkey an existing vertex from a candidate tree.
122  */
123 static void
124 olsr_spf_del_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
125 {
126
127 #ifdef DEBUG
128 #ifndef NODEBUG
129   struct ipaddr_str buf;
130   struct lqtextbuffer lqbuffer;
131 #endif /* NODEBUG */
132   OLSR_PRINTF(2, "SPF: delete candidate %s, cost %s\n", olsr_ip_to_string(&buf, &tc->addr),
133               get_linkcost_text(tc->path_cost, false, &lqbuffer));
134 #endif /* DEBUG */
135
136   avl_delete(tree, &tc->cand_tree_node);
137 }
138
139 /*
140  * olsr_spf_add_path_list
141  *
142  * Insert an SPF result at the end of the path list.
143  */
144 static void
145 olsr_spf_add_path_list(struct list_node *head, int *path_count, struct tc_entry *tc)
146 {
147 #if !defined(NODEBUG) && defined(DEBUG)
148   struct ipaddr_str pathbuf, nbuf;
149   struct lqtextbuffer lqbuffer;
150 #endif /* !defined(NODEBUG) && defined(DEBUG) */
151
152 #ifdef DEBUG
153   OLSR_PRINTF(2, "SPF: append path %s, cost %s, via %s\n", olsr_ip_to_string(&pathbuf, &tc->addr),
154               get_linkcost_text(tc->path_cost, false, &lqbuffer), tc->next_hop ? olsr_ip_to_string(&nbuf,
155                                                                                                    &tc->next_hop->
156                                                                                                    neighbor_iface_addr) : "-");
157 #endif /* DEBUG */
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 ? cand_tree2tc(node) : NULL);
174 }
175
176 /*
177  * olsr_spf_relax
178  *
179  * Explore all edges of a node and add the node
180  * to the candidate tree if the if the aggregate
181  * path cost is better.
182  */
183 static void
184 olsr_spf_relax(struct avl_tree *cand_tree, struct tc_entry *tc)
185 {
186   struct avl_node *edge_node;
187   olsr_linkcost new_cost;
188
189 #ifdef DEBUG
190 #ifndef NODEBUG
191   struct ipaddr_str buf, nbuf;
192   struct lqtextbuffer lqbuffer;
193 #endif /* NODEBUG */
194   OLSR_PRINTF(2, "SPF: exploring node %s, cost %s\n", olsr_ip_to_string(&buf, &tc->addr),
195               get_linkcost_text(tc->path_cost, false, &lqbuffer));
196 #endif /* DEBUG */
197
198   /*
199    * loop through all edges of this vertex.
200    */
201   for (edge_node = avl_walk_first(&tc->edge_tree); edge_node; edge_node = avl_walk_next(edge_node)) {
202
203     struct tc_entry *new_tc;
204     struct tc_edge_entry *tc_edge = edge_tree2tc_edge(edge_node);
205
206     /*
207      * We are not interested in dead-end edges.
208      */
209     if (!tc_edge->edge_inv) {
210 #ifdef DEBUG
211       OLSR_PRINTF(2, "SPF:   ignoring edge %s\n", 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 /* DEBUG */
216       continue;
217     }
218
219     if (tc_edge->cost == LINK_COST_BROKEN) {
220 #ifdef DEBUG
221       OLSR_PRINTF(2, "SPF:   ignore edge %s (broken)\n", olsr_ip_to_string(&buf, &tc_edge->T_dest_addr));
222 #endif /* DEBUG */
223       continue;
224     }
225     /*
226      * total quality of the path through this vertex
227      * to the destination of this edge
228      */
229     new_cost = tc->path_cost + tc_edge->cost;
230
231 #ifdef DEBUG
232     OLSR_PRINTF(2, "SPF:   exploring edge %s, cost %s\n", olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
233                 get_linkcost_text(new_cost, true, &lqbuffer));
234 #endif /* DEBUG */
235
236     /*
237      * if it's better than the current path quality of this edge's
238      * destination node, then we've found a better path to this node.
239      */
240     new_tc = tc_edge->edge_inv->tc;
241
242     if (new_cost < new_tc->path_cost) {
243
244       /* if this node has been on the candidate tree delete it */
245       if (new_tc->path_cost < ROUTE_COST_BROKEN) {
246         olsr_spf_del_cand_tree(cand_tree, new_tc);
247       }
248
249       /* re-insert on candidate tree with the better metric */
250       new_tc->path_cost = new_cost;
251       olsr_spf_add_cand_tree(cand_tree, new_tc);
252
253       /* pull-up the next-hop and bump the hop count */
254       if (tc->next_hop) {
255         new_tc->next_hop = tc->next_hop;
256       }
257       new_tc->hops = tc->hops + 1;
258
259 #ifdef DEBUG
260       OLSR_PRINTF(2, "SPF:   better path to %s, cost %s, via %s, hops %u\n", olsr_ip_to_string(&buf, &new_tc->addr),
261                   get_linkcost_text(new_cost, true, &lqbuffer), tc->next_hop ? olsr_ip_to_string(&nbuf,
262                                                                                                  &tc->next_hop->neighbor_iface_addr)
263                   : "<none>", new_tc->hops);
264 #endif /* DEBUG */
265
266     }
267   }
268 }
269
270 /*
271  * olsr_spf_run_full
272  *
273  * Run the Dijkstra algorithm.
274  *
275  * A node gets added to the candidate tree when one of its edges has
276  * an overall better root path cost than the node itself.
277  * The node with the shortest metric gets moved from the candidate to
278  * the path list every pass.
279  * The SPF computation is completed when there are no more nodes
280  * on the candidate tree.
281  */
282 static void
283 olsr_spf_run_full(struct avl_tree *cand_tree, struct list_node *path_list, int *path_count)
284 {
285   struct tc_entry *tc;
286
287   *path_count = 0;
288
289   while ((tc = olsr_spf_extract_best(cand_tree))) {
290
291     olsr_spf_relax(cand_tree, tc);
292
293     /*
294      * move the best path from the candidate tree
295      * to the path list.
296      */
297     olsr_spf_del_cand_tree(cand_tree, tc);
298     olsr_spf_add_path_list(path_list, path_count, tc);
299   }
300 }
301
302 /**
303  * Callback for the SPF backoff timer.
304  */
305 static void
306 olsr_expire_spf_backoff(void *context __attribute__ ((unused)))
307 {
308   spf_backoff_timer = NULL;
309 }
310
311 void
312 olsr_calculate_routing_table(bool force)
313 {
314 #ifdef SPF_PROFILING
315   struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total;
316 #endif /* SPF_PROFILING */
317   struct avl_tree cand_tree;
318   struct avl_node *rtp_tree_node;
319   struct list_node path_list;          /* head of the path_list */
320   struct tc_entry *tc;
321   struct rt_path *rtp;
322   struct tc_edge_entry *tc_edge;
323   struct neighbor_entry *neigh;
324   struct link_entry *link;
325   int path_count = 0;
326
327   /* We are done if our backoff timer is running */
328   if (!force) {
329     if (spf_backoff_timer) {
330       return;
331     }
332
333     /* start new backoff timer */
334     spf_backoff_timer = olsr_start_timer(1000, 5, OLSR_TIMER_ONESHOT, &olsr_expire_spf_backoff, NULL, 0);
335   }
336
337 #ifdef SPF_PROFILING
338   gettimeofday(&t1, NULL);
339 #endif /* SPF_PROFILING */
340
341   /*
342    * Prepare the candidate tree and result list.
343    */
344   avl_init(&cand_tree, avl_comp_etx);
345   list_head_init(&path_list);
346   olsr_bump_routingtree_version();
347
348   /*
349    * Initialize vertices in the lsdb.
350    */
351   OLSR_FOR_ALL_TC_ENTRIES(tc) {
352     tc->next_hop = NULL;
353     tc->path_cost = ROUTE_COST_BROKEN;
354     tc->hops = 0;
355   }
356   OLSR_FOR_ALL_TC_ENTRIES_END(tc);
357
358   /*
359    * Check if there was a change in the main IP address.
360    * Bail if there is no main IP address.
361    */
362   olsr_change_myself_tc();
363   if (!tc_myself) {
364
365     /*
366      * All gone now. Flush all routes.
367      */
368     olsr_update_rib_routes();
369     olsr_update_kernel_routes();
370     return;
371   }
372
373   /*
374    * zero ourselves and add us to the candidate tree.
375    */
376   tc_myself->path_cost = ZERO_ROUTE_COST;
377   olsr_spf_add_cand_tree(&cand_tree, tc_myself);
378
379   /*
380    * add edges to and from our neighbours.
381    */
382   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
383
384     if (neigh->status != SYM) {
385       tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
386       if (tc_edge) {
387         olsr_delete_tc_edge_entry(tc_edge);
388       }
389     }
390     else {
391       tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
392       link = get_best_link_to_neighbor(&neigh->neighbor_main_addr);
393       if (!link || lookup_link_status(link) == LOST_LINK) {
394
395         /*
396          * If there is no best link to this neighbor
397          * and we had an edge before then flush the edge.
398          */
399         if (tc_edge) {
400           olsr_delete_tc_edge_entry(tc_edge);
401         }
402         continue;
403       }
404
405       /* find the interface for the link */
406       if (link->if_name) {
407         link->inter = if_ifwithname(link->if_name);
408       } else {
409         link->inter = if_ifwithaddr(&link->local_iface_addr);
410       }
411
412       /*
413        * Set the next-hops of our neighbors.
414        */
415       if (!tc_edge) {
416         tc_edge = olsr_add_tc_edge_entry(tc_myself, &neigh->neighbor_main_addr, 0);
417       } else {
418
419         /*
420          * Update LQ and timers, such that the edge does not get deleted.
421          */
422         olsr_copylq_link_entry_2_tc_edge_entry(tc_edge, link);
423         olsr_calc_tc_edge_entry_etx(tc_edge);
424       }
425       if (tc_edge->edge_inv) {
426         tc_edge->edge_inv->tc->next_hop = link;
427       }
428     }
429   }
430   OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
431
432 #ifdef SPF_PROFILING
433   gettimeofday(&t2, NULL);
434 #endif /* SPF_PROFILING */
435
436   /*
437    * Run the SPF calculation.
438    */
439   olsr_spf_run_full(&cand_tree, &path_list, &path_count);
440
441   OLSR_PRINTF(2, "\n--- %s ------------------------------------------------- DIJKSTRA\n\n", olsr_wallclock_string());
442
443 #ifdef SPF_PROFILING
444   gettimeofday(&t3, NULL);
445 #endif /* SPF_PROFILING */
446
447   /*
448    * In the path list we have all the reachable nodes in our topology.
449    */
450   for (; !list_is_empty(&path_list); list_remove(path_list.next)) {
451
452     tc = pathlist2tc(path_list.next);
453     link = tc->next_hop;
454
455     if (!link) {
456 #ifdef DEBUG
457       /*
458        * Supress the error msg when our own tc_entry
459        * does not contain a next-hop.
460        */
461       if (tc != tc_myself) {
462         struct ipaddr_str buf;
463         OLSR_PRINTF(2, "SPF: %s no next-hop\n", olsr_ip_to_string(&buf, &tc->addr));
464       }
465 #endif /* DEBUG */
466       continue;
467     }
468
469     /*
470      * Now walk all prefixes advertised by that node.
471      * Since the node is reachable, insert the prefix into the global RIB.
472      * If the prefix is already in the RIB, refresh the entry such
473      * that olsr_delete_outdated_routes() does not purge it off.
474      */
475     for (rtp_tree_node = avl_walk_first(&tc->prefix_tree); rtp_tree_node; rtp_tree_node = avl_walk_next(rtp_tree_node)) {
476
477       rtp = rtp_prefix_tree2rtp(rtp_tree_node);
478
479       if (rtp->rtp_rt) {
480
481         /*
482          * If there is a route entry, the prefix is already in the global RIB.
483          */
484         olsr_update_rt_path(rtp, tc, link);
485
486       } else {
487
488         /*
489          * The prefix is reachable and not yet in the global RIB.
490          * Build a rt_entry for it.
491          */
492         olsr_insert_rt_path(rtp, tc, link);
493       }
494     }
495   }
496 #ifdef __linux__
497   /* check gateway tunnels */
498   olsr_trigger_gatewayloss_check();
499 #endif /* __linux__ */
500
501   /* Update the RIB based on the new SPF results */
502
503   olsr_update_rib_routes();
504
505 #ifdef SPF_PROFILING
506   gettimeofday(&t4, NULL);
507 #endif /* SPF_PROFILING */
508
509   /* move the route changes into the kernel */
510
511   olsr_update_kernel_routes();
512
513 #ifdef SPF_PROFILING
514   gettimeofday(&t5, NULL);
515 #endif /* SPF_PROFILING */
516
517 #ifdef SPF_PROFILING
518   timersub(&t2, &t1, &spf_init);
519   timersub(&t3, &t2, &spf_run);
520   timersub(&t4, &t3, &route);
521   timersub(&t5, &t4, &kernel);
522   timersub(&t5, &t1, &total);
523   OLSR_PRINTF(1, "\n--- SPF-stats for %d nodes, %d routes (total/init/run/route/kern): " "%d, %d, %d, %d, %d\n", path_count,
524               routingtree.count, (int)total.tv_usec, (int)spf_init.tv_usec, (int)spf_run.tv_usec, (int)route.tv_usec,
525               (int)kernel.tv_usec);
526 #endif /* SPF_PROFILING */
527 }
528
529 /*
530  * Local Variables:
531  * c-basic-offset: 2
532  * indent-tabs-mode: nil
533  * End:
534  */