98bfbc1731d093bc4aec372e02dd0c53f8baccb0
[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
50 /*
51  * Function hooks for plugins to intercept
52  * adding / deleting routes from the kernel
53  */
54 export_route_function olsr_add_route_function;
55 export_route_function olsr_del_route_function;
56
57 #define MAX_FAILURE_COUNT 10000 //should be FAILURE_LESS_NOISE_COUNT * (int)x
58 #define FAILURE_LESS_NOISE_COUNT 100 //after x errors only every x errors this is written to log
59
60 void
61 olsr_init_export_route(void)
62 {
63   OLSR_INFO(LOG_ROUTING, "Initialize route processing...\n");
64
65   /* the add/chg and del kernel queues */
66   list_init_head(&chg_kernel_list);
67
68   olsr_add_route_function = os_route_add_rtentry;
69   olsr_del_route_function = os_route_del_rtentry;
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 deletion
118  *
119  *@return actual error count
120  */
121 static int
122 olsr_del_route(struct rt_entry *rt)
123 {
124   int16_t error;
125   if (rt->rt_nexthop.interface == NULL) return 0;
126
127   error = olsr_del_route_function(rt, olsr_cnf->ip_version);
128
129   if (error != 0) {
130     if (rt->failure_count>0) {
131       /*ignore if we failed to delete a route we never successfully created*/
132       OLSR_WARN(LOG_ROUTING, "KERN: SUCCESFULLY failed to delete unexisting %s: %s\n", olsr_rt_to_string(rt), strerror(errno));
133       rt->failure_count=0;
134     } else {
135      rt->failure_count--;
136
137      /*rate limit error messages*/
138      if ( (rt->failure_count >= -FAILURE_LESS_NOISE_COUNT ) || (rt->failure_count % FAILURE_LESS_NOISE_COUNT == 0) )
139        OLSR_ERROR(LOG_ROUTING, "KERN: ERROR on %d attempt to delete %s: %s\n", rt->failure_count*(-1), olsr_rt_to_string(rt), strerror(errno));
140
141      /*stop trying it*/
142      if (rt->failure_count <= -MAX_FAILURE_COUNT)  {
143        OLSR_ERROR(LOG_ROUTING, " WILL NOT TRY AGAIN!!\n==============\n");
144        rt->failure_count=0;
145      }
146     }
147
148   } else {
149     if (rt->failure_count > 1)
150       OLSR_WARN(LOG_ROUTING, "KERN: SUCCESS on %d attempt to delete %s: %s\n", rt->failure_count*(-1), olsr_rt_to_string(rt), strerror(errno));
151
152     rt->failure_count=0;
153     /* release the interface. */
154     unlock_interface(rt->rt_nexthop.interface);
155   }
156
157   return rt->failure_count;
158 }
159
160 /**
161  * Process a route from the kernel addition list.
162  *
163  *@return nada
164  */
165 static void
166 olsr_add_route(struct rt_entry *rt)
167 {
168   rt->failure_count++;
169
170   if (0 != olsr_add_route_function(rt, olsr_cnf->ip_version)) {
171     /*rate limit error messages*/
172     if ( (rt->failure_count <= FAILURE_LESS_NOISE_COUNT ) || (rt->failure_count % FAILURE_LESS_NOISE_COUNT == 0) )
173       OLSR_ERROR(LOG_ROUTING, "KERN: ERROR on %d attempt to add %s: %s\n", rt->failure_count, olsr_rtp_to_string(rt->rt_best), strerror(errno));
174
175     /*stop trying it*/
176     if (rt->failure_count >= MAX_FAILURE_COUNT)  {
177        OLSR_ERROR(LOG_ROUTING, " WILL NOT TRY AGAIN!!\n==============\n");
178        rt->failure_count=0;
179      }
180   } else {
181     /* route addition has suceeded */
182
183     /* save the nexthop and metric in the route entry */
184     rt->rt_nexthop = rt->rt_best->rtp_nexthop;
185     rt->rt_metric = rt->rt_best->rtp_metric;
186
187     /* lock the interface such that it does not vanish underneath us */
188     lock_interface(rt->rt_nexthop.interface);
189
190     /*reset failure_counter and print info if we needed more than once*/
191     if (rt->failure_count > 1)
192       OLSR_WARN(LOG_ROUTING, "KERN: SUCCESS on %d attmpt to add %s: %s\n", rt->failure_count, olsr_rtp_to_string(rt->rt_best), strerror(errno));
193     rt->failure_count=0;
194   }
195 }
196
197 /**
198  * process the kernel change list.
199  * the routes are already ordered such that nexthop routes
200  * are on the head of the queue.
201  * non-nexthop routes need to be changed first and therefore
202  * the queue needs to be traversed from tail to head.
203  */
204 static void
205 olsr_chg_kernel_routes(struct list_entity *head_node)
206 {
207   struct rt_entry *rt;
208   struct list_iterator iterator;
209
210   if (list_is_empty(head_node)) {
211     return;
212   }
213
214   /*
215    * Traverse from the beginning to the end of the list,
216    * such that nexthop routes are added first.
217    */
218   OLSR_FOR_ALL_RTLIST_ENTRIES(head_node, rt, iterator) {
219
220     /*if netlink and NLFM_REPLACE is available (ipv4 only?) and used in linux/kernel_*.c no delete would be necesarry here */
221     if (rt->rt_nexthop.interface) olsr_del_route(rt); // fresh routes do not have an interface pointer
222
223     olsr_add_route(rt);
224
225     list_remove(&rt->rt_change_node);
226   }
227 }
228
229 /**
230  * Check the version number of all route paths hanging off a route entry.
231  * If a route does not match the current routing tree number, remove it
232  * from the global originator tree for that rt_entry.
233  * Reset the best route pointer.
234  */
235 static void
236 olsr_delete_outdated_routes(struct rt_entry *rt)
237 {
238   struct rt_path *rtp;
239   struct list_iterator iterator;
240
241   OLSR_FOR_ALL_RT_PATH_ENTRIES(rt, rtp, iterator) {
242     /*
243      * check the version number which gets incremented on every SPF run.
244      * comparing for unequalness avoids handling version number wraps.
245      */
246     if (routingtree_version != rtp->rtp_version) {
247
248       /* remove from the originator tree */
249       avl_delete(&rt->rt_path_tree, &rtp->rtp_tree_node);
250       rtp->rtp_rt = NULL;
251     }
252   }
253
254   /* safety measure against dangling pointers */
255   rt->rt_best = NULL;
256 }
257
258 /**
259  * Walk all the routes, remove outdated routes and run
260  * best path selection on the remaining set.
261  * Finally compare the nexthop of the route head and the best
262  * path and enqueue an add/chg operation.
263  */
264 void
265 olsr_update_rib_routes(void)
266 {
267   struct rt_entry *rt;
268   struct list_iterator iterator;
269
270   OLSR_DEBUG(LOG_ROUTING, "Updating kernel routes...\n");
271
272   /* walk all routes in the RIB. */
273
274   OLSR_FOR_ALL_RT_ENTRIES(rt, iterator) {
275
276     /* eliminate first unused routes */
277     olsr_delete_outdated_routes(rt);
278
279     if (!rt->rt_path_tree.count) {
280       /* oops, all routes are gone - flush the route head */
281       if (olsr_del_route(rt) == 0) avl_delete(&routingtree, &rt->rt_tree_node);
282
283       continue;
284     }
285
286     /* run best route election */
287     olsr_rt_best(rt);
288
289     /* nexthop or hopcount change ? */
290     if (olsr_nh_change(&rt->rt_best->rtp_nexthop, &rt->rt_nexthop) ||
291         (FIBM_CORRECT == olsr_cnf->fib_metric && olsr_hopcount_change(&rt->rt_best->rtp_metric, &rt->rt_metric))) {
292
293       olsr_enqueue_rt(&chg_kernel_list, rt);
294      
295     }
296   }
297 }
298
299 /**
300  * Propagate the accumulated changes from the last rib update to the kernel.
301  */
302 void
303 olsr_update_kernel_routes(void)
304 {
305
306   /* route changes and additions */
307   olsr_chg_kernel_routes(&chg_kernel_list);
308
309 #ifdef DEBUG
310   olsr_print_routing_table();
311 #endif
312 }
313
314 /*
315  * Local Variables:
316  * c-basic-offset: 2
317  * indent-tabs-mode: nil
318  * End:
319  */