ecb2ffc9cc8b44dae72d7507eb27b4a0ab5e264d
[olsrd.git] / src / linux / kernel_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 "kernel_routes.h"
43 #include <assert.h>
44 #include <errno.h>
45 #include <linux/types.h>
46 #include <linux/rtnetlink.h>
47
48 #include "olsr_logging.h"
49
50 static int olsr_netlink_route_int(const struct rt_entry *, uint8_t, uint8_t, __u16, uint8_t);
51
52 /* values for control flag to handle recursive route corrections
53  *  currently only requires in linux specific kernel_routes.c */
54
55 #define RT_NONE 0
56 #define RT_ORIG_REQUEST 1
57 #define RT_RETRY_AFTER_ADD_GATEWAY 2
58 #define RT_RETRY_AFTER_DELETE_SIMILAR 3
59 #define RT_DELETE_SIMILAR_ROUTE 4
60 #define RT_AUTO_ADD_GATEWAY_ROUTE 5
61 #define RT_DELETE_SIMILAR_AUTO_ROUTE 6
62 #define RT_LO_IP 7
63
64 struct olsr_rtreq {
65   struct nlmsghdr n;
66   struct rtmsg r;
67   char buf[512];
68 };
69
70 struct olsr_ipadd_req {
71   struct nlmsghdr n;
72   struct ifaddrmsg ifa;
73   char buf[256];
74 };
75
76
77 static void
78 olsr_netlink_addreq(struct nlmsghdr *n, size_t reqSize __attribute__ ((unused)), int type, const void *data, int len)
79 {
80   struct rtattr *rta = (struct rtattr *)(ARM_NOWARN_ALIGN)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
81   n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_LENGTH(len);
82   //produces strange compile error
83   //assert(n->nlmsg_len < reqSize);
84   rta->rta_type = type;
85   rta->rta_len = RTA_LENGTH(len);
86   memcpy(RTA_DATA(rta), data, len);
87 }
88
89 /*rt_entry and nexthop and family and table must only be specified with an flag != RT_NONE  && != RT_LO_IP*/
90 static int
91 olsr_netlink_send(struct nlmsghdr *n, char *buf, size_t bufSize, uint8_t flag, const struct rt_entry *rt,
92                   const struct rt_nexthop *nexthop, uint8_t family, uint8_t rttable)
93 {
94   struct iovec iov;
95   struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK };
96   struct msghdr msg = {
97     .msg_name = &nladdr,
98     .msg_namelen = sizeof(nladdr),
99     .msg_iov = &iov,
100     .msg_iovlen = 1,
101     .msg_control = NULL,
102     .msg_controllen = 0,
103     .msg_flags = 0
104   };
105   int ret = 1;                         /* helper variable for rtnetlink_message processing */
106   int rt_ret = -2;                     /* if no response from rtnetlink it must be considered as failed! */
107
108   iov.iov_base = n;
109   iov.iov_len = n->nlmsg_len;
110   ret = sendmsg(olsr_cnf->rts_linux, &msg, 0);
111   if (0 <= ret) {
112     iov.iov_base = buf;
113     iov.iov_len = bufSize;
114     ret = recvmsg(olsr_cnf->rts_linux, &msg, 0);
115     if (0 < ret) {
116       struct nlmsghdr *h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)buf;
117       while (NLMSG_OK(h, (unsigned int)ret)) {
118         if (NLMSG_DONE == h->nlmsg_type) {
119           //seems to be never reached
120           //log this if it ever happens !!??
121           break;
122         }
123         if (NLMSG_ERROR == h->nlmsg_type) {
124           if (NLMSG_LENGTH(sizeof(struct nlmsgerr)) <= h->nlmsg_len) {
125 #ifndef REMOVE_LOG_WARN
126             struct ipaddr_str ibuf;
127             struct ipaddr_str gbuf;
128 #endif
129             const struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
130             errno = -l_err->error;
131             if (0 != errno) {
132 #if (!defined REMOVE_LOG_DEBUG) || (!defined REMOVE_LOG_ERROR) || (!defined REMOVE_LOG_WARN)
133               const char *const err_msg = strerror(errno);
134 #endif
135               ret = -1;
136               rt_ret = -1;
137               if (flag != RT_NONE) {
138                 /* debug output for various situations */
139                 if (n->nlmsg_type == RTM_NEWRULE) {
140                   OLSR_ERROR(LOG_ROUTING, "Error '%s' (%d) on inserting empty policy rule aimed to activate RtTable %u!", err_msg,
141                              errno, rttable);
142                 } else if (n->nlmsg_type == RTM_DELRULE) {
143                   OLSR_ERROR(LOG_ROUTING, "Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg,
144                              errno, rttable);
145                 } else if (flag <= RT_RETRY_AFTER_DELETE_SIMILAR) {
146                   if (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr)
147                     OLSR_WARN(LOG_ROUTING, "error '%s' (%d) %s route to %s/%d via %s dev %s", err_msg, errno,
148                                (n->nlmsg_type == RTM_NEWROUTE) ? "add" : "del", olsr_ip_to_string(&ibuf, &rt->rt_dst.prefix),
149                                rt->rt_dst.prefix_len, olsr_ip_to_string(&gbuf, &nexthop->gateway), nexthop->interface->int_name);
150                   else
151                     OLSR_WARN(LOG_ROUTING, "error '%s' (%d) %s route to %s/%d dev %s", err_msg, errno,
152                                (n->nlmsg_type == RTM_NEWROUTE) ? "add" : "del", olsr_ip_to_string(&ibuf, &rt->rt_dst.prefix),
153                                rt->rt_dst.prefix_len, nexthop->interface->int_name);
154                 } else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE)
155                   OLSR_WARN(LOG_ROUTING, ". error '%s' (%d) auto-add route to %s dev %s", err_msg, errno,
156                              olsr_ip_to_string(&ibuf, &nexthop->gateway), nexthop->interface->int_name);
157                 else if (flag == RT_DELETE_SIMILAR_ROUTE)
158                   OLSR_WARN(LOG_ROUTING, ". error '%s' (%d) auto-delete route to %s gw %s", err_msg, errno,
159                              olsr_ip_to_string(&ibuf, &rt->rt_dst.prefix), olsr_ip_to_string(&gbuf, &nexthop->gateway));
160                 else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE)
161                   OLSR_WARN(LOG_ROUTING, ". . error '%s' (%d) auto-delete similar route to %s gw %s", err_msg, errno,
162                              olsr_ip_to_string(&ibuf, &nexthop->gateway), olsr_ip_to_string(&gbuf, &nexthop->gateway));
163                 else if (flag == RT_LO_IP)
164                   OLSR_DEBUG(LOG_ROUTING, "error '%s' (%d) while %s lo:olsr", err_msg, errno, n->nlmsg_type == RTM_NEWADDR ? "adding":"deleting");
165                 else {          /* should never happen */
166                   OLSR_ERROR(LOG_ROUTING, "# invalid internal route delete/add flag (%d) used!", flag);
167                 }
168               }
169               else { /*at least give some information*/
170                 OLSR_DEBUG(LOG_NETWORKING,"rtnetlink returned: %s (%d)",err_msg,errno);
171               }
172             } else {            /* netlink acks requests with an errno=0 NLMSG_ERROR response! */
173               rt_ret = 1;
174             }
175             if (flag != RT_NONE) {
176               /* ignore file exist when inserting Addr to lo:olsr*/
177               if ((errno == 17) && (flag == RT_LO_IP)) {
178                OLSR_DEBUG(LOG_ROUTING, "ignoring 'File exists' (17) while adding addr to lo!");      
179                rt_ret = 1;
180               }
181               /* resolve "File exist" (17) propblems (on orig and autogen routes) */
182               else if ((errno == 17) && ((flag == RT_ORIG_REQUEST) || (flag == RT_AUTO_ADD_GATEWAY_ROUTE)) && (n->nlmsg_type ==
183                                                                                                        RTM_NEWROUTE)) {
184                 /* a similar route going over another gateway may be present, which has to be deleted! */
185                 OLSR_WARN(LOG_ROUTING, ". auto-deleting similar route to resolve 'File exists' (17) while adding route!");
186                 rt_ret = RT_DELETE_SIMILAR_ROUTE;       /* processing will contiune after this loop */
187               }
188               /* report success on "No such process" (3) */
189               else if ((errno == 3) && (n->nlmsg_type == RTM_DELROUTE) && (flag == RT_ORIG_REQUEST)) {
190                 /* another similar (but slightly different) route may be present at this point
191                  * , if so this will get solved when adding new route to this destination */
192                 OLSR_INFO(LOG_ROUTING, ". ignoring 'No such process' (3) while deleting route!");
193                 rt_ret = 0;
194               }
195               /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
196                * or on 2.6 kernel No such process (3), or Network unreachable (101) is reported in rtnetlink response
197                * do this only with flat metric, as using metric values inherited from
198                * a target behind the gateway is really strange, and could lead to multiple routes!
199                * anyways if invalid gateway ips may happen we are f*cked up!!
200                * but if not, these on the fly generated routes are no problem, and will only get used when needed
201                * warning currently only for ipv4 */
202               else if (((errno == 3) || (errno == 101) || (errno == 128)) && (flag == RT_ORIG_REQUEST) && (FIBM_FLAT == olsr_cnf->fib_metric)
203                        && (n->nlmsg_type == RTM_NEWROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr)) {
204                 if (errno == 128)
205                   OLSR_WARN(LOG_ROUTING, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
206                 else if (errno == 128)
207                   OLSR_WARN(LOG_ROUTING, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
208                 else
209                   OLSR_WARN(LOG_ROUTING, ". autogenerating route to handle 'No such process' (3) while adding route!");
210
211                 rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;     /* processing will contiune after this loop */
212               }
213             }
214           }
215           break;
216         }
217 /*
218  * The ARM compile complains about alignment. Copied
219  * from /usr/include/linux/netlink.h and adapted for ARM
220  */
221 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
222                                   (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
223         h = MY_NLMSG_NEXT(h, ret);
224       }
225     }
226   }
227   if (flag != RT_NONE) {
228     if (rt_ret == RT_DELETE_SIMILAR_ROUTE) {    //delete all routes that may collide
229       /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches */
230       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_DELROUTE,
231                                       flag == RT_AUTO_ADD_GATEWAY_ROUTE ? RT_DELETE_SIMILAR_AUTO_ROUTE : RT_DELETE_SIMILAR_ROUTE);
232
233       /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions */
234       if (rt_ret > 0)
235         rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
236       else
237         OLSR_WARN(LOG_ROUTING, ". failed on auto-deleting similar route conflicting with above route!");
238
239       /* set appropriate return code for original request, while returning simple -1/1 if called recursive */
240       if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
241         if (rt_ret > 0)
242           rt_ret = 0;           /* successful recovery */
243         else
244           rt_ret = -1;          /* unrecoverable error */
245       }
246     }
247     else if (rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE) {  /* autoadd route via gateway */
248       /* recursive call to invoke creation of a route to the gateway */
249       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
250
251       /* retry insert original route, if above succeeded without problems */
252       if (rt_ret > 0)
253         rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
254       else
255         OLSR_WARN(LOG_ROUTING, ". failed on inserting auto-generated route to gateway of above route!");
256
257       /* set appropriate return code for original request */
258       if (rt_ret > 0)
259         rt_ret = 0;             /* successful recovery */
260       else
261         rt_ret = -1;            /* unrecoverable error */
262     }
263     /* send ipc update on success (deprecated!?)
264     if (  ( n->nlmsg_type != RT_LO_IP ) && ( n->nlmsg_type != RTM_NEWRULE ) && ( n->nlmsg_type != RTM_DELRULE ) && (flag = RT_ORIG_REQUEST) && (0 <= rt_ret && olsr_cnf->ipc_connections > 0)) {
265       ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric, RTM_NEWROUTE == n->nlmsg_type,
266       if_ifwithindex_name(nexthop->iif_index));
267     } */
268     if (rt_ret == -2) OLSR_ERROR(LOG_ROUTING, "no rtnetlink response! (no system ressources left?, everything may happen now ...)");
269     return rt_ret;
270   } else return ret; 
271 }
272
273 //external wrapper function for above patched multi purpose rtnetlink function
274 int
275 olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd)
276 {
277   struct rt_entry rt;
278   return olsr_netlink_route_int(&rt, family, rttable, cmd, RT_ORIG_REQUEST);
279 }
280
281 /*internal wrapper function for above patched function*/
282 static int
283 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
284 {
285   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
286 }
287
288 /* returns
289  *  -1 on unrecoverable error (calling function will have to handle it)
290  *  0 on unexpected but recoverable rtnetlink behaviour
291  *  but some of the implemented recovery methods only cure symptoms,
292  *  not the cause, like unintelligent ordering of inserted routes.
293  *  1 on success */
294 static int
295 olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd, uint8_t flag)
296 {
297   int ret = 0;
298   struct olsr_rtreq req;
299   uint32_t metric = ((cmd != RTM_NEWRULE) && (cmd != RTM_DELRULE)) ?
300     FIBM_FLAT != olsr_cnf->fib_metric ? ((RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops)
301     : RT_METRIC_DEFAULT : 65535;
302   const struct rt_nexthop *nexthop = ((cmd != RTM_NEWRULE) || (cmd != RTM_DELRULE)) ?
303                                            ( ( ( (RTM_DELROUTE == cmd) && ( RT_DELETE_SIMILAR_AUTO_ROUTE == flag || RT_DELETE_SIMILAR_ROUTE == flag ) ) ) 
304                                            || (RTM_NEWROUTE == cmd) ) ? &rt->rt_best->rtp_nexthop : &rt->rt_nexthop 
305                                      : NULL;
306
307   memset(&req, 0, sizeof(req));
308   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
309   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
310   req.n.nlmsg_type = cmd;
311   req.r.rtm_family = family;
312   req.r.rtm_table = rttable;
313   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
314   req.r.rtm_type = RTN_UNICAST; /* -> olsr only adds/deletes unicast routes */
315   req.r.rtm_protocol = RTPROT_UNSPEC;   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
316   req.r.rtm_scope = RT_SCOPE_NOWHERE;   /* as wildcard for deletion */
317   
318   /* metric is specified always as we can only delete one route per iteration, and wanna hit the correct one first */
319   if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) || (cmd == RTM_NEWRULE) || (cmd == RTM_DELRULE)) {
320     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &metric, sizeof(metric));
321   }
322   /*Hint: new kernels define FRA_PRIORITY and so on, but old ones doesn`t, but till now values are the same*/
323
324   if (NULL != nexthop->interface) {
325     if ((cmd == RTM_NEWRULE) || (cmd == RTM_DELRULE)) {
326       req.r.rtm_scope = RT_SCOPE_UNIVERSE; /*required or would NOWHERE be ok too?*/
327     }
328     else {
329       req.r.rtm_dst_len = rt->rt_dst.prefix_len;
330
331       /* do not specify much as we wanna delete similar/conflicting routes */
332       if ((flag != RT_DELETE_SIMILAR_ROUTE) && (flag != RT_DELETE_SIMILAR_AUTO_ROUTE)) {
333         /* 0 gets replaced by OS-specifc default (3)
334          * 1 is reserved so we take 0 instead (this really makes some sense)
335          * other numbers are used 1:1 */
336         req.r.rtm_protocol = ((olsr_cnf->rtproto < 1) ? RTPROT_BOOT : ((olsr_cnf->rtproto == 1) ? 0 : olsr_cnf->rtproto));
337         req.r.rtm_scope = RT_SCOPE_LINK;
338
339         /*add interface */
340         olsr_netlink_addreq(&req.n, sizeof(req), RTA_OIF, &nexthop->interface->if_index, sizeof(nexthop->interface->if_index));
341
342         if (olsr_cnf->source_ip_mode) {
343           if (AF_INET == family)
344             olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, &olsr_cnf->router_id.v4, sizeof(olsr_cnf->router_id.v4));
345           else
346             olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, &olsr_cnf->router_id.v6, sizeof(&olsr_cnf->router_id.v6));
347         }
348       }
349
350       /* make sure that netmask = /32 as this is an autogenarated route */
351       if ((flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE))
352         req.r.rtm_dst_len = 32;
353
354       /* for ipv4 or ipv6 we add gateway if one is specified,
355        * or leave gateway away if we want to delete similar routes aswell,
356        * or even use the gateway as target if we add a auto-generated route,
357        * or if delete-similar to make insertion of auto-generated route possible */
358       if (AF_INET == family) {
359         if ((flag != RT_AUTO_ADD_GATEWAY_ROUTE) && (flag != RT_DELETE_SIMILAR_ROUTE) &
360             (flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr)) {
361           olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
362           req.r.rtm_scope = RT_SCOPE_UNIVERSE;
363         }
364         olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST,
365                             ((flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE)) ? 
366                             &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
367       } else {
368         if ((flag != RT_AUTO_ADD_GATEWAY_ROUTE) && (flag != RT_DELETE_SIMILAR_ROUTE) && (flag != RT_DELETE_SIMILAR_AUTO_ROUTE)
369             && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6)))) {
370           olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
371           req.r.rtm_scope = RT_SCOPE_UNIVERSE;
372         }
373         olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST,
374                             ((flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE)) ? 
375                             &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
376       }
377     }
378   } else {
379     /*
380      * No interface means: remove unspecificed default route
381      */
382     req.r.rtm_scope = RT_SCOPE_NOWHERE;
383   }
384   ret = olsr_netlink_send(&req.n, req.buf, sizeof(req.buf), flag, rt, nexthop, family, rttable);
385   return ret;
386 }
387
388 /*
389  * Insert a route in the kernel routing table
390  * @param destination the route to add
391  * @return negative on error
392  */
393 int
394 olsr_kernel_add_route(const struct rt_entry *rt, int ip_version)
395 {
396   int rttable;
397
398   OLSR_DEBUG(LOG_ROUTING, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
399
400   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
401     /*
402      * Users start whining about not having internet with policy
403      * routing activated and no static default route in table 254.
404      * We maintain a fallback defroute in the default=253 table.
405      */
406     olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
407   }
408   rttable = 0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0 ? olsr_cnf->rttable_default : olsr_cnf->rttable;
409   return olsr_netlink_route(rt, ip_version, rttable, RTM_NEWROUTE);
410 }
411
412
413 /*
414  * Remove a route from the kernel
415  * @param destination the route to remove
416  * @return negative on error
417  */
418 int
419 olsr_kernel_del_route(const struct rt_entry *rt, int ip_version)
420 {
421   int rttable;
422
423   OLSR_DEBUG(LOG_ROUTING, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
424
425   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
426     /*
427      * Also remove the fallback default route
428      */
429     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
430   }
431   rttable = 0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0 ? olsr_cnf->rttable_default : olsr_cnf->rttable;
432   return olsr_netlink_route(rt, ip_version, rttable, RTM_DELROUTE);
433 }
434
435
436 int
437 olsr_lo_interface(union olsr_ip_addr *ip, bool create)
438 {
439   struct olsr_ipadd_req req;
440   static char l[] = "lo:olsr";
441
442   memset(&req, 0, sizeof(req));
443
444   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
445   if (create) {
446    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
447    req.n.nlmsg_type = RTM_NEWADDR;
448   } else {
449    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
450    req.n.nlmsg_type = RTM_DELADDR;
451   }
452   req.ifa.ifa_family = olsr_cnf->ip_version;
453
454   olsr_netlink_addreq(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1);
455   olsr_netlink_addreq(&req.n, sizeof(req), IFA_LOCAL, ip, olsr_cnf->ipsize);
456
457   req.ifa.ifa_prefixlen = olsr_cnf->ipsize * 8;
458
459   req.ifa.ifa_index = if_nametoindex("lo");
460
461   return olsr_netlink_send(&req.n, req.buf, sizeof(req.buf), RT_LO_IP, NULL, NULL, 0, 0);
462 }
463 /*
464  * Local Variables:
465  * c-basic-offset: 2
466  * indent-tabs-mode: nil
467  * End:
468  */