9b4788d581186a4233f1dfe6946f9c8ca6a65f95
[olsrd.git] / src / process_routes.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 "process_routes.h"
43 #include "olsr_logging.h"
44 #include "os_kernel_routes.h"
45
46 #include <errno.h>
47
48 static struct list_entity chg_kernel_list;
49 static struct list_entity del_kernel_list;
50
51 /*
52  * Function hooks for plugins to intercept
53  * adding / deleting routes from the kernel
54  */
55 export_route_function olsr_add_route_function;
56 export_route_function olsr_del_route_function;
57
58
59 void
60 olsr_init_export_route(void)
61 {
62   OLSR_INFO(LOG_ROUTING, "Initialize route processing...\n");
63
64   /* the add/chg and del kernel queues */
65   list_init_head(&chg_kernel_list);
66   list_init_head(&del_kernel_list);
67
68   olsr_add_route_function = olsr_kernel_add_route;
69   olsr_del_route_function = olsr_kernel_del_route;
70 }
71
72 /**
73  * Delete all OLSR routes.
74  *
75  * This is extremely simple - Just increment the version of the
76  * tree and then olsr_update_rib_routes() will see all routes in the tree
77  * as outdated and olsr_update_kernel_routes() will finally flush it.
78  *
79  */
80 void
81 olsr_delete_all_kernel_routes(void)
82 {
83   OLSR_DEBUG(LOG_ROUTING, "Deleting all routes...\n");
84
85   olsr_bump_routingtree_version();
86   olsr_update_rib_routes();
87   olsr_update_kernel_routes();
88 }
89
90 /**
91  * Enqueue a route on a kernel chg/del queue.
92  */
93 static void
94 olsr_enqueue_rt(struct list_entity *head_node, struct rt_entry *rt)
95 {
96   const struct rt_nexthop *nh;
97
98   /* if this node is already on some changelist we are done */
99   if (list_node_added(&rt->rt_change_node)) {
100     return;
101   }
102
103   /*
104    * For easier route dependency tracking we enqueue nexthop routes
105    * at the head of the queue and non-nexthop routes at the tail of the queue.
106    */
107   nh = olsr_get_nh(rt);
108
109   if (olsr_ipcmp(&rt->rt_dst.prefix, &nh->gateway) == 0) {
110     list_add_after(head_node, &rt->rt_change_node);
111   } else {
112     list_add_before(head_node, &rt->rt_change_node);
113   }
114 }
115
116 /**
117  * Process a route from the kernel deletion list.
118  *
119  *@return nada
120  */
121 static void
122 olsr_del_route(struct rt_entry *rt)
123 {
124   int16_t error = olsr_del_route_function(rt, olsr_cnf->ip_version);
125
126   if (error < 0) {
127     OLSR_WARN(LOG_ROUTING, "KERN: ERROR deleting %s: %s\n", olsr_rt_to_string(rt), strerror(errno));
128   } else {
129
130     /* release the interface. */
131     unlock_interface(rt->rt_nexthop.interface);
132   }
133 }
134
135 /**
136  * Process a route from the kernel addition list.
137  *
138  *@return nada
139  */
140 static void
141 olsr_add_route(struct rt_entry *rt)
142 {
143   if (0 > olsr_add_route_function(rt, olsr_cnf->ip_version)) {
144     OLSR_WARN(LOG_ROUTING, "KERN: ERROR adding %s: %s\n", olsr_rtp_to_string(rt->rt_best), strerror(errno));
145   } else {
146     /* route addition has suceeded */
147
148     /* save the nexthop and metric in the route entry */
149     rt->rt_nexthop = rt->rt_best->rtp_nexthop;
150     rt->rt_metric = rt->rt_best->rtp_metric;
151
152     /* lock the interface such that it does not vanish underneath us */
153     lock_interface(rt->rt_nexthop.interface);
154   }
155 }
156
157 /**
158  * process the kernel change list.
159  * the routes are already ordered such that nexthop routes
160  * are on the head of the queue.
161  * non-nexthop routes need to be changed first and therefore
162  * the queue needs to be traversed from tail to head.
163  */
164 static void
165 olsr_chg_kernel_routes(struct list_entity *head_node)
166 {
167   struct rt_entry *rt;
168   struct list_iterator iterator;
169
170   if (list_is_empty(head_node)) {
171     return;
172   }
173
174   /*
175    * Traverse from the beginning to the end of the list,
176    * such that nexthop routes are added first.
177    */
178   OLSR_FOR_ALL_RTLIST_ENTRIES(head_node, rt, iterator) {
179
180     /*if netlink and NLFM_REPLACE is available (ipv4 only?) and used in linux/kernel_*.c no delete would be necesarry here */
181     if (rt->rt_nexthop.interface) olsr_del_route(rt); // fresh routes do not have an interface pointer
182
183     olsr_add_route(rt);
184
185     list_remove(&rt->rt_change_node);
186   }
187 }
188
189 /**
190  * process the kernel delete list.
191  * the routes are already ordered such that nexthop routes
192  * are on the head of the queue.
193  * non-nexthop routes need to be deleted first and therefore
194  * the queue needs to be traversed from tail to head.
195  */
196 static void
197 olsr_del_kernel_routes(struct list_entity *head_node)
198 {
199   struct rt_entry *rt;
200   struct list_iterator iterator;
201
202   OLSR_FOR_ALL_RTLIST_ENTRIES(head_node, rt, iterator) {
203     /*
204      * Only attempt to delete the route from kernel if it was
205      * installed previously. A reference to the interface gets
206      * set only when a route installation suceeds.
207      */
208     if (rt->rt_nexthop.interface) {
209       olsr_del_route(rt);
210     }
211
212     list_remove(&rt->rt_change_node);
213     olsr_cookie_free(rt_mem_cookie, rt);
214   }
215 }
216
217 /**
218  * Check the version number of all route paths hanging off a route entry.
219  * If a route does not match the current routing tree number, remove it
220  * from the global originator tree for that rt_entry.
221  * Reset the best route pointer.
222  */
223 static void
224 olsr_delete_outdated_routes(struct rt_entry *rt)
225 {
226   struct rt_path *rtp;
227   struct list_iterator iterator;
228
229   OLSR_FOR_ALL_RT_PATH_ENTRIES(rt, rtp, iterator) {
230     /*
231      * check the version number which gets incremented on every SPF run.
232      * comparing for unequalness avoids handling version number wraps.
233      */
234     if (routingtree_version != rtp->rtp_version) {
235
236       /* remove from the originator tree */
237       avl_delete(&rt->rt_path_tree, &rtp->rtp_tree_node);
238       rtp->rtp_rt = NULL;
239     }
240   }
241
242   /* safety measure against dangling pointers */
243   rt->rt_best = NULL;
244 }
245
246 /**
247  * Walk all the routes, remove outdated routes and run
248  * best path selection on the remaining set.
249  * Finally compare the nexthop of the route head and the best
250  * path and enqueue an add/chg operation.
251  */
252 void
253 olsr_update_rib_routes(void)
254 {
255   struct rt_entry *rt;
256   struct list_iterator iterator;
257
258   OLSR_DEBUG(LOG_ROUTING, "Updating kernel routes...\n");
259
260   /* walk all routes in the RIB. */
261
262   OLSR_FOR_ALL_RT_ENTRIES(rt, iterator) {
263
264     /* eliminate first unused routes */
265     olsr_delete_outdated_routes(rt);
266
267     if (!rt->rt_path_tree.count) {
268
269       /* oops, all routes are gone - flush the route head */
270       avl_delete(&routingtree, &rt->rt_tree_node);
271
272       olsr_enqueue_rt(&del_kernel_list, rt);
273       continue;
274     }
275
276     /* run best route election */
277     olsr_rt_best(rt);
278
279     /* nexthop or hopcount change ? */
280     if (olsr_nh_change(&rt->rt_best->rtp_nexthop, &rt->rt_nexthop) ||
281         (FIBM_CORRECT == olsr_cnf->fib_metric && olsr_hopcount_change(&rt->rt_best->rtp_metric, &rt->rt_metric))) {
282
283       olsr_enqueue_rt(&chg_kernel_list, rt);
284      
285     }
286   }
287 }
288
289 /**
290  * Propagate the accumulated changes from the last rib update to the kernel.
291  */
292 void
293 olsr_update_kernel_routes(void)
294 {
295
296   /* delete unreachable routes */
297   olsr_del_kernel_routes(&del_kernel_list);
298
299   /* route changes and additions */
300   olsr_chg_kernel_routes(&chg_kernel_list);
301
302 #ifdef DEBUG
303   olsr_print_routing_table();
304 #endif
305 }
306
307 /*
308  * Local Variables:
309  * c-basic-offset: 2
310  * indent-tabs-mode: nil
311  * End:
312  */