bf623cbe23421f79d8a1dd68363d548520828c03
[olsrd.git] / src / linux / kernel_routes.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
4  * Copyright (c) 2007, Sven-Ola for the policy routing stuff
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 "interfaces.h"
43 #include "olsr_logging.h"
44 #include "os_net.h"
45 #include "os_kernel_routes.h"
46
47 #include <assert.h>
48 #include <linux/types.h>
49 #include <linux/rtnetlink.h>
50
51 //ipip includes
52 #include <netinet/in.h>
53 #include <sys/ioctl.h>
54 #include <net/if.h>
55 #include <linux/ip.h>
56 #include <linux/if_tunnel.h>
57
58 //ifup includes
59 #include <sys/socket.h>
60 #include <sys/ioctl.h>
61 #include <sys/types.h>
62 #include <net/if.h>
63
64 /*
65  * This file contains the linux routing code. (rtnetlink based)
66  */
67 #if 1
68 /*
69  * The ARM compile complains about alignment. Copied
70  * from /usr/include/linux/netlink.h and adapted for ARM
71  */
72 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
73           (struct nlmsghdr*)ARM_NOWARN_ALIGN((((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
74
75
76 static void rtnetlink_read(int sock, void *, unsigned int);
77
78 struct olsr_rtreq {
79   struct nlmsghdr n;
80   struct rtmsg r;
81   char buf[512];
82 };
83
84 struct olsr_ipadd_req {
85   struct nlmsghdr n;
86   struct ifaddrmsg ifa;
87   char buf[256];
88 };
89
90 int rtnetlink_register_socket(int rtnl_mgrp)
91 {
92   int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
93   struct sockaddr_nl addr;
94
95   if (sock<0) {
96     OLSR_ERROR(LOG_ROUTING,"could not create rtnetlink socket! %s (%d)", strerror(errno), errno);
97     return -1;
98   }
99
100   memset(&addr, 0, sizeof(addr));
101   addr.nl_family = AF_NETLINK;
102   addr.nl_pid = 0; //kernel will assign appropiate number instead of pid (which is already used by primaray rtnetlink socket to add/delete routes)
103   addr.nl_groups = rtnl_mgrp;
104
105   if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0) {
106     OLSR_ERROR(LOG_ROUTING,"could not bind rtnetlink socket! %s (%d)",strerror(errno), errno);
107     return -1;
108   }
109
110   add_olsr_socket(sock, NULL, &rtnetlink_read, NULL, SP_IMM_READ);
111   return sock;
112 }
113
114 /* temporary disabled (no matching interface handling) */
115 #if 0
116 static void netlink_process_link(struct nlmsghdr *h)
117 {
118   struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(h);
119
120   struct interface *iface;
121   struct olsr_if *oif;
122   char namebuffer[IF_NAMESIZE];
123
124   iface = if_ifwithindex(ifi->ifi_index);
125   oif = NULL;
126
127   if (iface == NULL && (ifi->ifi_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)) {
128     if (if_indextoname(ifi->ifi_index, namebuffer)) {
129       if ((oif = if_ifwithname(namebuffer)) != NULL) {
130         /* try to take interface up, will trigger ifchange */
131         chk_if_up(oif, 3);
132       }
133     }
134   }
135
136   else if (iface != NULL && (ifi->ifi_flags & IFF_UP) == 0) {
137     /* try to take interface down, will trigger ifchange */
138     olsr_remove_interface(iface->olsr_if);
139   }
140
141   if (iface == NULL && oif == NULL) {
142     /* this is not an OLSR interface */
143     if ((ifi->ifi_flags & IFF_UP) != 0 && (ifi->ifi_flags & IFF_RUNNING) != 0) {
144       olsr_trigger_ifchange(ifi->ifi_index, NULL, IFCHG_IF_ADD);
145     }
146     else if ((ifi->ifi_flags & IFF_UP) == 0 && (ifi->ifi_flags & IFF_RUNNING) == 0){
147       olsr_trigger_ifchange(ifi->ifi_index, NULL, IFCHG_IF_REMOVE);
148     }
149   }
150 }
151 #endif
152
153 static void rtnetlink_read(int sock, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
154 {
155   int len, plen;
156   struct iovec iov;
157   struct sockaddr_nl nladdr;
158   struct msghdr msg = {
159     &nladdr,
160     sizeof(nladdr),
161     &iov,
162     1,
163     NULL,
164     0,
165     0
166   };
167
168   char buffer[4096];
169   struct nlmsghdr *nlh = (struct nlmsghdr *)ARM_NOWARN_ALIGN(buffer);
170   int ret;
171
172   iov.iov_base = (void *) buffer;
173   iov.iov_len = sizeof(buffer);
174
175   while ((ret = recvmsg(sock, &msg, MSG_DONTWAIT)) >= 0) {
176     /*check message*/
177     len = nlh->nlmsg_len;
178     plen = len - sizeof(nlh);
179     if (len > ret || plen < 0) {
180       OLSR_WARN(LOG_ROUTING,"Malformed netlink message: "
181              "len=%d left=%d plen=%d\n",
182               len, ret, plen);
183       return;
184     }
185
186     OLSR_INFO(LOG_ROUTING, "Netlink message received: type %x\n", nlh->nlmsg_type);
187     if ((nlh->nlmsg_type == RTM_NEWLINK) || ( nlh->nlmsg_type == RTM_DELLINK)) {
188       /* handle ifup/ifdown */
189       //netlink_process_link(nlh);
190     }
191   }
192
193   if (errno != EAGAIN) {
194     OLSR_WARN(LOG_ROUTING,"netlink listen error %u - %s\n",errno,strerror(errno));
195   }
196 }
197
198 static void
199 olsr_netlink_addreq(struct nlmsghdr *n, size_t reqSize __attribute__ ((unused)), int type, const void *data, int len)
200 {
201   struct rtattr *rta = (struct rtattr *)ARM_NOWARN_ALIGN(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
202   n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_LENGTH(len);
203   //produces strange compile error
204   //assert(n->nlmsg_len < reqSize);
205   rta->rta_type = type;
206   rta->rta_len = RTA_LENGTH(len);
207   memcpy(RTA_DATA(rta), data, len);
208 }
209
210 /*rt_entry and nexthop and family and table must only be specified with an flag != RT_NONE  && != RT_LO_IP*/
211 static int
212 olsr_netlink_send(struct nlmsghdr *nl_hdr)
213 {
214   char rcvbuf[1024];
215   struct iovec iov;
216   struct sockaddr_nl nladdr;
217   struct msghdr msg;
218   struct nlmsghdr *h;
219   struct nlmsgerr *l_err;
220   int ret;
221
222   memset(&nladdr, 0, sizeof(nladdr));
223   memset(&msg, 0, sizeof(msg));
224
225   nladdr.nl_family = AF_NETLINK;
226
227   msg.msg_name = &nladdr;
228   msg.msg_namelen = sizeof(nladdr);
229   msg.msg_iov = &iov;
230   msg.msg_iovlen = 1;
231
232   iov.iov_base = nl_hdr;
233   iov.iov_len = nl_hdr->nlmsg_len;
234   ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0);
235   if (ret <= 0) {
236     OLSR_ERROR(LOG_ROUTING, "Cannot send data to netlink socket (%d: %s)", errno, strerror(errno));
237     return -1;
238   }
239
240   iov.iov_base = rcvbuf;
241   iov.iov_len = sizeof(rcvbuf);
242   ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0);
243   if (ret <= 0) {
244     OLSR_ERROR(LOG_ROUTING, "Error while reading answer to netlink message (%d: %s)", errno, strerror(errno));
245     return -1;
246   }
247
248   h = (struct nlmsghdr *)ARM_NOWARN_ALIGN(rcvbuf);
249   if (!NLMSG_OK(h, (unsigned int)ret)) {
250     OLSR_ERROR(LOG_ROUTING, "Received netlink message was malformed (ret=%d, %u)", ret, h->nlmsg_len);
251     return -1;
252   }
253
254   if (h->nlmsg_type != NLMSG_ERROR) {
255     OLSR_WARN(LOG_ROUTING,
256         "Received unknown netlink response: %u bytes, type %u (not %u) with seqnr %u and flags %u from %u",
257         h->nlmsg_len, h->nlmsg_type, NLMSG_ERROR, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid);
258     return -1;
259   }
260   if (NLMSG_LENGTH(sizeof(struct nlmsgerr)) > h->nlmsg_len) {
261     OLSR_WARN(LOG_ROUTING,"Received invalid netlink message size %lu != %u",
262         (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
263     return -1;
264   }
265
266   l_err = (struct nlmsgerr *)NLMSG_DATA(h);
267
268   if (l_err->error) {
269     OLSR_WARN(LOG_ROUTING,"Received netlink error code %s (%d)", strerror(-l_err->error), l_err->error);
270   }
271   return -l_err->error;
272 }
273
274 int olsr_os_policy_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set) {
275   struct olsr_rtreq req;
276   int err;
277
278   memset(&req, 0, sizeof(req));
279
280   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
281   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
282
283   req.n.nlmsg_type = set ? RTM_NEWRULE : RTM_DELRULE;
284   req.r.rtm_family = family;
285   req.r.rtm_table = rttable;
286
287   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
288   /* -> olsr only adds deletes unicast routes */
289   req.r.rtm_type = RTN_UNICAST;
290
291   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
292   req.r.rtm_protocol = RTPROT_UNSPEC;
293
294   req.r.rtm_scope = RT_SCOPE_UNIVERSE;
295
296   olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &priority, sizeof(priority));
297
298   if (if_name != NULL) {
299     /*add interface name to rule*/
300     olsr_netlink_addreq(&req.n, sizeof(req), RTA_IIF, if_name, strlen(if_name)+1);
301   }
302
303   err = olsr_netlink_send(&req.n);
304   if (err) {
305     OLSR_ERROR(LOG_ROUTING,"Error on %s policy rule aimed to activate RtTable %u!",
306         set ? "inserting" : "deleting", rttable);
307   }
308
309   return err;
310 }
311
312 static int
313 olsr_add_ip(int ifindex, union olsr_ip_addr *ip, const char *l, bool create)
314 {
315   struct olsr_ipadd_req req;
316
317   memset(&req, 0, sizeof(req));
318
319   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
320   if (create) {
321    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
322    req.n.nlmsg_type = RTM_NEWADDR;
323   } else {
324    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
325    req.n.nlmsg_type = RTM_DELADDR;
326   }
327   req.ifa.ifa_family = olsr_cnf->ip_version;
328
329   olsr_netlink_addreq(&req.n, sizeof(req), IFA_LOCAL, ip, olsr_cnf->ipsize);
330   if (l) {
331     olsr_netlink_addreq(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1);
332   }
333
334   req.ifa.ifa_prefixlen = olsr_cnf->ipsize * 8;
335
336   req.ifa.ifa_index = ifindex;
337
338   return olsr_netlink_send(&req.n);
339 }
340
341 int
342 olsr_os_localhost_if(union olsr_ip_addr *ip, bool create)
343 {
344   static char l[] = "lo:olsr";
345   return olsr_add_ip(if_nametoindex("lo"), ip, l, create);
346 }
347
348 int olsr_os_ifip(int ifindex, union olsr_ip_addr *ip, bool create) {
349   return olsr_add_ip(ifindex, ip, NULL, create);
350 }
351
352 static int olsr_new_netlink_route(int family, int rttable, int if_index, int metric, int protocol,
353     const union olsr_ip_addr *src, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *dst,
354     bool set, bool del_similar) {
355
356   struct olsr_rtreq req;
357   int family_size;
358   int err;
359
360   if (0) {
361     struct ipaddr_str buf1, buf2;
362     struct ipprefix_str bufp;
363
364     OLSR_WARN(LOG_ROUTING, "new_netlink_route: family=%d,rttable=%d,if_index=%d,metric=%d,protocol=%d,src=%s,gw=%s,dst=%s,set=%s,del_similar=%s",
365         family, rttable, if_index, metric, protocol, src == NULL ? "" : olsr_ip_to_string(&buf1, src),
366         gw == NULL ? "" : olsr_ip_to_string(&buf2, gw), olsr_ip_prefix_to_string(&bufp, dst),
367         set ? "true" : "false", del_similar ? "true" : "false");
368   }
369   family_size = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr);
370
371   memset(&req, 0, sizeof(req));
372
373   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
374   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
375   if (set) {
376     req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
377   }
378
379   req.n.nlmsg_type = set ? RTM_NEWROUTE : RTM_DELROUTE;
380   req.r.rtm_family = family;
381   req.r.rtm_table = rttable;
382
383   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
384   /* -> olsr only adds deletes unicast routes */
385   req.r.rtm_type = RTN_UNICAST;
386
387   req.r.rtm_dst_len = dst->prefix_len;
388
389   if (set) {
390     /* add protocol for setting a route */
391     req.r.rtm_protocol = protocol;
392   }
393
394   /* calculate scope of operation */
395   if (!set && del_similar) {
396     /* as wildcard for fuzzy deletion */
397     req.r.rtm_scope = RT_SCOPE_NOWHERE;
398   }
399   else if (gw) {
400     /* for multihop routes */
401     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
402   }
403   else {
404     /* for link neighbor routes */
405     req.r.rtm_scope = RT_SCOPE_LINK;
406   }
407
408   if (set || !del_similar) {
409     /* add interface*/
410     olsr_netlink_addreq(&req.n, sizeof(req), RTA_OIF, &if_index, sizeof(if_index));
411   }
412
413   if (set && src != NULL) {
414     /* add src-ip */
415     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, src, family_size);
416   }
417
418   if (metric != -1) {
419     /* add metric */
420     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &metric, sizeof(metric));
421   }
422
423   if (gw) {
424     /* add gateway */
425     olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, gw, family_size);
426   }
427
428   /* add destination */
429   olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST, &dst->prefix, family_size);
430
431   err = olsr_netlink_send(&req.n);
432   if (err) {
433     struct ipprefix_str bufp;
434     if (gw) {
435       struct ipaddr_str buf;
436       OLSR_ERROR(LOG_ROUTING, ". error: %s route to %s via %s dev %s (%s %d)",
437           set ? "add" : "del",
438           olsr_ip_prefix_to_string(&bufp, dst), olsr_ip_to_string(&buf, gw),
439           if_ifwithindex_name(if_index), strerror(errno), errno);
440     }
441     else {
442       OLSR_ERROR(LOG_ROUTING, ". error: %s route to %s dev %s (%s %d)",
443           set ? "add" : "del",
444           olsr_ip_prefix_to_string(&bufp, dst), if_ifwithindex_name(if_index),
445           strerror(errno), errno);
446     }
447   }
448
449   return err;
450 }
451
452 void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6, bool set) {
453   if (olsr_new_netlink_route(AF_INET6,
454       ip_prefix_is_mappedv4_inetgw(dst_v6) ? olsr_cnf->rt_table_default : olsr_cnf->rt_table,
455       olsr_cnf->niit6to4_if_index,
456       RT_METRIC_DEFAULT, olsr_cnf->rt_proto, NULL, NULL, dst_v6, set, false)) {
457     struct ipprefix_str bufp;
458     OLSR_ERROR(LOG_ROUTING, ". error while %s static niit route to %s",
459         set ? "setting" : "removing", olsr_ip_prefix_to_string(&bufp, dst_v6));
460   }
461 }
462
463 void olsr_os_niit_4to6_route(const struct olsr_ip_prefix *dst_v4, bool set) {
464   if (olsr_new_netlink_route(AF_INET,
465       ip_prefix_is_v4_inetgw(dst_v4) ? olsr_cnf->rt_table_default : olsr_cnf->rt_table,
466       olsr_cnf->niit4to6_if_index,
467       RT_METRIC_DEFAULT, olsr_cnf->rt_proto, NULL, NULL, dst_v4, set, false)) {
468     struct ipprefix_str bufp;
469     OLSR_ERROR(LOG_ROUTING, ". error while %s niit route to %s",
470         set ? "setting" : "removing", olsr_ip_prefix_to_string(&bufp, dst_v4));
471   }
472 }
473
474 void olsr_os_inetgw_tunnel_route(uint32_t if_idx, bool ipv4, bool set) {
475   const struct olsr_ip_prefix *dst;
476
477   assert(olsr_cnf->ip_version == AF_INET6 || ipv4);
478
479   dst = ipv4 ? &ipv4_internet_route : &ipv6_internet_route;
480
481   if (olsr_new_netlink_route(ipv4 ? AF_INET : AF_INET6, olsr_cnf->rt_table_tunnel,
482       if_idx, RT_METRIC_DEFAULT, olsr_cnf->rt_proto, NULL, NULL, dst, set, false)) {
483     struct ipprefix_str bufp;
484     OLSR_ERROR(LOG_ROUTING, ". error while %s inetgw tunnel route to %s for if %d",
485         set ? "setting" : "removing", olsr_ip_prefix_to_string(&bufp, dst), if_idx);
486   }
487 }
488
489 static int olsr_os_process_rt_entry(int af_family, const struct rt_entry *rt, bool set) {
490   int metric, table;
491   const struct rt_nexthop *nexthop;
492   union olsr_ip_addr *src;
493   bool hostRoute;
494   int err;
495
496   /* calculate metric */
497   if (FIBM_FLAT == olsr_cnf->fib_metric) {
498     metric = RT_METRIC_DEFAULT;
499   }
500   else {
501     metric = set ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
502   }
503
504   if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&rt->rt_dst)) {
505     /* make space for the tunnel gateway route */
506     metric += 2;
507   }
508
509   /* get table */
510   table = is_prefix_inetgw(&rt->rt_dst)
511       ? olsr_cnf->rt_table_default : olsr_cnf->rt_table;
512
513   /* get next hop */
514   if (rt->rt_best && set) {
515     nexthop = &rt->rt_best->rtp_nexthop;
516   }
517   else {
518     nexthop = &rt->rt_nexthop;
519   }
520
521   /* detect 1-hop hostroute */
522   hostRoute = rt->rt_dst.prefix_len == olsr_cnf->ipsize * 8
523       && (!olsr_ipcmp(&nexthop->gateway, &rt->rt_dst.prefix));
524
525 #if 0
526   {
527     struct ipaddr_str buf1, buf2;
528     OLSR_WARN(LOG_ROUTING, "hostroute (%s) = %d == %d && %s == %s",
529         hostRoute ? "true" : "false",
530         rt->rt_dst.prefix_len, (int)(olsr_cnf->ipsize * 8),
531         olsr_ip_to_string(&buf1, &nexthop->gateway),
532         olsr_ip_to_string(&buf2, &rt->rt_dst.prefix));
533   }
534 #endif
535
536   /* get src ip */
537   if (olsr_cnf->use_src_ip_routes) {
538     src = &olsr_cnf->unicast_src_ip;
539   }
540   else {
541     src = NULL;
542   }
543
544   /* create route */
545   err = olsr_new_netlink_route(af_family, table, nexthop->interface->if_index, metric, olsr_cnf->rt_proto,
546       src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
547
548   /* resolve "File exist" (17) propblems (on orig and autogen routes)*/
549   if (set && err == 17) {
550     /* a similar route going over another gateway may be present, which has to be deleted! */
551     OLSR_ERROR(LOG_ROUTING, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
552
553     /* erase similar rule */
554     err = olsr_new_netlink_route(af_family, table, 0, 0, -1, NULL, NULL, &rt->rt_dst, false, true);
555
556     if (!err) {
557       /* create this rule a second time if delete worked*/
558       err = olsr_new_netlink_route(af_family, table, nexthop->interface->if_index, metric, olsr_cnf->rt_proto,
559           src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
560     }
561     OLSR_ERROR(LOG_ROUTING, ". %s (%d)", err == 0 ? "successful" : "failed", err);
562   }
563
564   /* report success on "No such process" (3) */
565   else if (!set && err == 3) {
566     /* another similar (but slightly different) route may be present at this point,
567      * if so this will get solved when adding new route to this destination */
568     OLSR_ERROR(LOG_ROUTING, ". ignoring 'No such process' (3) while deleting route!");
569     err = 0;
570   }
571   /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
572    * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
573    * do this only with flat metric, as using metric values inherited from
574    * a target behind the gateway is really strange, and could lead to multiple routes!
575    * anyways if invalid gateway ips may happen we are f*cked up!!
576    * but if not, these on the fly generated routes are no problem, and will only get used when needed */
577   else if (!hostRoute && olsr_cnf->fib_metric == FIBM_FLAT
578       && (err == 128 || err == 101 || err == 3)) {
579     struct olsr_ip_prefix hostPrefix;
580
581     if (err == 128)  {
582       OLSR_ERROR(LOG_ROUTING, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
583     }
584     else if (err == 101) {
585       OLSR_ERROR(LOG_ROUTING, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
586     }
587     else {
588       OLSR_ERROR(LOG_ROUTING, ". autogenerating route to handle 'No such process' (3) while adding route!");
589     }
590
591     /* create hostroute */
592     hostPrefix.prefix = nexthop->gateway;
593     hostPrefix.prefix_len = olsr_cnf->ipsize * 8;
594
595     err = olsr_new_netlink_route(af_family, olsr_cnf->rt_table, nexthop->interface->if_index,
596         metric, olsr_cnf->rt_proto, src, NULL, &hostPrefix, true, false);
597     if (err == 0) {
598       /* create this rule a second time if hostrule generation was successful */
599       err = olsr_new_netlink_route(af_family, table, nexthop->interface->if_index, metric, olsr_cnf->rt_proto,
600           src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
601     }
602     OLSR_ERROR(LOG_ROUTING, ". %s (%d)", err == 0 ? "successful" : "failed", err);
603   }
604
605   return err;
606 }
607
608 /**
609  * Insert a route in the kernel routing table
610  *
611  * @param destination the route to add
612  *
613  * @return negative on error
614  */
615 int
616 olsr_kernel_add_route(const struct rt_entry *rt, int ip_version)
617 {
618   OLSR_INFO(LOG_ROUTING, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
619   return olsr_os_process_rt_entry(ip_version, rt, true);
620 }
621
622 /**
623  *Remove a route from the kernel
624  *
625  *@param destination the route to remove
626  *
627  *@return negative on error
628  */
629 int
630 olsr_kernel_del_route(const struct rt_entry *rt, int ip_version)
631 {
632   OLSR_INFO(LOG_ROUTING, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
633   return olsr_os_process_rt_entry(ip_version, rt, false);
634 }
635
636 #endif
637 /*
638  * Local Variables:
639  * c-basic-offset: 2
640  * indent-tabs-mode: nil
641  * End:
642  */