gateway: proactively take down 'expensive' gateways
[olsrd.git] / src / gateway.c
1 /*
2  * gateway.c
3  *
4  *  Created on: 05.01.2010
5  *      Author: henning
6  */
7
8 #ifdef __linux__
9
10 #include "common/avl.h"
11 #include "defs.h"
12 #include "ipcalc.h"
13 #include "olsr.h"
14 #include "olsr_cfg.h"
15 #include "olsr_cookie.h"
16 #include "scheduler.h"
17 #include "kernel_routes.h"
18 #include "kernel_tunnel.h"
19 #include "net_os.h"
20 #include "duplicate_set.h"
21 #include "log.h"
22 #include "gateway_default_handler.h"
23 #include "gateway_list.h"
24 #include "gateway.h"
25
26 #include <assert.h>
27 #include <net/if.h>
28
29 /*
30  * Defines for the multi-gateway script
31  */
32
33 #define SCRIPT_MODE_GENERIC   "generic"
34 #define SCRIPT_MODE_OLSRIF    "olsrif"
35 #define SCRIPT_MODE_SGWSRVTUN "sgwsrvtun"
36 #define SCRIPT_MODE_EGRESSIF  "egressif"
37 #define SCRIPT_MODE_SGWTUN    "sgwtun"
38
39 /** structure that holds an interface name, mark and a pointer to the gateway that uses it */
40 struct interfaceName {
41   char name[IFNAMSIZ]; /**< interface name */
42   uint8_t mark; /**< marking */
43   struct gateway_entry *gw; /**< gateway that uses this interface name */
44 };
45
46 /** the gateway tree */
47 struct avl_tree gateway_tree;
48
49 /** gateway cookie */
50 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
51
52 /** gateway container cookie */
53 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
54
55 /** the gateway netmask for the HNA */
56 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
57
58 /** the gateway handler/plugin */
59 static struct olsr_gw_handler *gw_handler;
60
61 /** the IPv4 gateway list */
62 static struct gw_list gw_list_ipv4;
63
64 /** the IPv6 gateway list */
65 static struct gw_list gw_list_ipv6;
66
67 /** the current IPv4 gateway */
68 static struct gw_container_entry *current_ipv4_gw;
69
70 /** the current IPv6 gateway */
71 static struct gw_container_entry *current_ipv6_gw;
72
73 /** interface names for smart gateway egress interfaces */
74 struct interfaceName * sgwEgressInterfaceNames;
75
76 /** interface names for smart gateway tunnel interfaces, IPv4 */
77 struct interfaceName * sgwTunnel4InterfaceNames;
78
79 /** interface names for smart gateway tunnel interfaces, IPv6 */
80 struct interfaceName * sgwTunnel6InterfaceNames;
81
82 /** the timer for proactive takedown */
83 static struct timer_entry *gw_takedown_timer;
84
85 /*
86  * Forward Declarations
87  */
88
89 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
90
91 /*
92  * Helper Functions
93  */
94
95 /**
96  * @return the gateway 'server' tunnel name to use
97  */
98 static inline const char * server_tunnel_name(void) {
99   return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
100 }
101
102 /**
103  * Convert the netmask of the HNA (in the form of an IP address) to a HNA
104  * pointer.
105  *
106  * @param mask the netmask of the HNA (in the form of an IP address)
107  * @param prefixlen the prefix length
108  * @return a pointer to the HNA
109  */
110 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
111   return (((uint8_t *)mask) + ((prefixlen+7)/8));
112 }
113
114 /**
115  * @return true if multi-gateway mode is enabled
116  */
117 static inline bool multi_gateway_mode(void) {
118   return (olsr_cnf->smart_gw_use_count > 1);
119 }
120
121 /**
122  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
123  * to an uplink/downlink speed value
124  *
125  * @param value the encoded 1 byte transport value
126  * @return the uplink/downlink speed value (in kbit/s)
127  */
128 static uint32_t deserialize_gw_speed(uint8_t value) {
129   uint32_t speed;
130   uint32_t exp;
131
132   if (!value) {
133     /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
134      * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
135     return 0;
136   }
137
138   speed = (value >> 3) + 1;
139   exp = value & 7;
140
141   while (exp-- > 0) {
142     speed *= 10;
143   }
144   return speed;
145 }
146
147 /**
148  * Convert an uplink/downlink speed value into an encoded 1 byte transport
149  * value (5 bits mantissa, 3 bits exponent)
150  *
151  * @param speed the uplink/downlink speed value (in kbit/s)
152  * @return value the encoded 1 byte transport value
153  */
154 static uint8_t serialize_gw_speed(uint32_t speed) {
155   uint8_t exp = 0;
156
157   if (speed == 0) {
158     return 0;
159   }
160
161   if (speed > 320000000) {
162     return 0xff;
163   }
164
165   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
166     speed /= 10;
167     exp++;
168   }
169   return ((speed - 1) << 3) | exp;
170 }
171
172 /**
173  * Find an interfaceName struct corresponding to a certain gateway
174  * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
175  *
176  * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
177  * @return a pointer to the struct, or NULL when not found
178  */
179 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
180   struct interfaceName * sgwTunnelInterfaceNames;
181   uint8_t i = 0;
182
183   if (!multi_gateway_mode()) {
184     return NULL;
185   }
186
187   assert(sgwTunnel4InterfaceNames);
188   assert(sgwTunnel6InterfaceNames);
189
190   sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
191   while (i < olsr_cnf->smart_gw_use_count) {
192     struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
193     if (ifn->gw == gw) {
194       return ifn;
195     }
196     i++;
197   }
198
199   return NULL;
200 }
201
202 /**
203  * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
204  *
205  * @param gw pointer to the gateway
206  * @param name pointer to output buffer (length IFNAMSIZ)
207  * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
208  */
209 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
210   static uint32_t counter = 0;
211
212   assert(gw);
213   assert(name);
214   assert(interfaceName);
215
216   memset(name, 0, IFNAMSIZ);
217
218   if (multi_gateway_mode()) {
219     struct interfaceName * ifn = find_interfaceName(NULL);
220
221     if (ifn) {
222       strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
223       *interfaceName = ifn;
224       ifn->gw = gw;
225       return;
226     }
227
228     /* do not return, fall-through to classic naming as fallback */
229   }
230
231   snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
232   *interfaceName = NULL;
233 }
234
235 /**
236  * Set an olsr ipip tunnel name that is used by a certain gateway as unused
237  *
238  * @param gw pointer to the gateway
239  */
240 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
241   struct interfaceName * ifn;
242
243   if (!multi_gateway_mode()) {
244     return;
245   }
246
247   assert(gw);
248
249   ifn = find_interfaceName(gw);
250   if (ifn) {
251     ifn->gw = NULL;
252     return;
253   }
254 }
255
256 /**
257  * Run the multi-gateway script/
258  *
259  * @param mode the mode (see SCRIPT_MODE_* defines)
260  * @param add true to add policy routing, false to remove it
261  * @param ifname the interface name (optional)
262  * @param ifmark the interface mark (optional
263  * @return true when successful
264  */
265 static bool multiGwRunScript(const char * mode, bool add, const char * ifname, uint8_t * ifmark) {
266   struct autobuf buf;
267   int r;
268
269   abuf_init(&buf, 1024);
270
271   abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
272
273   abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
274
275   assert(!strcmp(mode, SCRIPT_MODE_GENERIC) || !strcmp(mode, SCRIPT_MODE_OLSRIF) ||
276       !strcmp(mode, SCRIPT_MODE_SGWSRVTUN) || !strcmp(mode, SCRIPT_MODE_EGRESSIF) ||
277       !strcmp(mode, SCRIPT_MODE_SGWTUN));
278   abuf_appendf(&buf, " \"%s\"", mode);
279
280   abuf_appendf(&buf, " \"%s\"", add ? "add" : "del");
281
282   if (ifname) {
283     assert(!strcmp(mode, SCRIPT_MODE_OLSRIF) || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN) ||
284         !strcmp(mode, SCRIPT_MODE_EGRESSIF) || !strcmp(mode, SCRIPT_MODE_SGWTUN));
285     abuf_appendf(&buf, " \"%s\"", ifname);
286   } else {
287     assert(!strcmp(mode, SCRIPT_MODE_GENERIC));
288   }
289   if (ifmark) {
290     assert(!strcmp(mode, SCRIPT_MODE_EGRESSIF) || !strcmp(mode, SCRIPT_MODE_SGWTUN));
291     assert(ifname);
292     abuf_appendf(&buf, " \"%u\"", *ifmark);
293   } else {
294     assert(!strcmp(mode, SCRIPT_MODE_GENERIC) || !strcmp(mode, SCRIPT_MODE_OLSRIF) ||
295       !strcmp(mode, SCRIPT_MODE_SGWSRVTUN));
296   }
297
298   r = system(buf.buf);
299
300   abuf_free(&buf);
301
302   return (r == 0);
303 }
304
305 /**
306  * Setup generic multi-gateway iptables and ip rules
307  *
308  * - generic (on olsrd start/stop)
309  * iptablesExecutable -t mangle -A OUTPUT -j CONNMARK --restore-mark
310  *
311  * @param add true to add policy routing, false to remove it
312  * @return true when successful
313  */
314 static bool multiGwRulesGeneric(bool add) {
315   return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, NULL);
316 }
317
318 /**
319  * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
320  *
321  * - olsr interfaces (on olsrd start/stop)
322  * iptablesExecutable -t mangle -A PREROUTING -i ${olsrInterface} -j CONNMARK --restore-mark
323  *
324  * @param add true to add policy routing, false to remove it
325  * @return true when successful
326  */
327 static bool multiGwRulesOlsrInterfaces(bool add) {
328   bool ok = true;
329   struct interface * ifn;
330
331   for (ifn = ifnet; ifn; ifn = ifn->int_next) {
332     if (!multiGwRunScript(SCRIPT_MODE_OLSRIF, add, ifn->int_name, NULL)) {
333       ok = false;
334       if (add) {
335         return ok;
336       }
337     }
338   }
339
340   return ok;
341 }
342
343 /**
344  * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
345  *
346  * - sgw server tunnel interface (on olsrd start/stop)
347  * iptablesExecutable -t mangle -A PREROUTING  -i tunl0 -j CONNMARK --restore-mark
348  *
349  * @param add true to add policy routing, false to remove it
350  * @return true when successful
351  */
352 static bool multiGwRulesSgwServerTunnel(bool add) {
353   return multiGwRunScript(SCRIPT_MODE_SGWSRVTUN, add, server_tunnel_name(), NULL);
354 }
355
356 /**
357  * Setup multi-gateway iptables and ip rules for all egress interfaces.
358  *
359  * - egress interfaces (on interface start/stop)
360  * iptablesExecutable -t mangle -A POSTROUTING -m conntrack --ctstate NEW -o ${egressInterface} -j CONNMARK --set-mark ${egressInterfaceMark}
361  * iptablesExecutable -t mangle -A INPUT       -m conntrack --ctstate NEW -i ${egressInterface} -j CONNMARK --set-mark ${egressInterfaceMark}
362  * ip rule add fwmark ${egressInterfaceMark} table ${egressInterfaceMark} pref ${egressInterfaceMark}
363  *
364  * like table:
365  * ppp0 91
366  * eth0 92
367  *
368  * @param add true to add policy routing, false to remove it
369  * @return true when successful
370  */
371 static bool multiGwRulesEgressInterfaces(bool add) {
372   bool ok = true;
373   unsigned int i = 0;
374
375   for (i = 0; i < olsr_cnf->smart_gw_egress_interfaces_count; i++) {
376     struct interfaceName * ifn = &sgwEgressInterfaceNames[i];
377     if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, ifn->name, &ifn->mark)) {
378       ok = false;
379       if (add) {
380         return ok;
381       }
382     }
383   }
384
385   return ok;
386 }
387
388 /**
389  * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
390  *
391  * - sgw tunnels (on sgw tunnel start/stop)
392  * iptablesExecutable -t mangle -A POSTROUTING -m conntrack --ctstate NEW -o ${sgwTunnelInterface} -j CONNMARK --set-mark ${sgwTunnelInterfaceMark}
393  * ip rule add fwmark ${sgwTunnelInterfaceMark} table ${sgwTunnelInterfaceMark} pref ${sgwTunnelInterfaceMark}
394  *
395  * like table:
396  * tnl_101 101
397  * tnl_102 102
398  * tnl_103 103
399  * tnl_104 104
400  * tnl_105 105
401  * tnl_106 106
402  * tnl_107 107
403  * tnl_108 108
404  */
405 static bool multiGwRulesSgwTunnels(bool add) {
406   bool ok = true;
407   unsigned int i = 0;
408
409   while (i < olsr_cnf->smart_gw_use_count) {
410     struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
411     if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, &ifn->mark)) {
412       ok = false;
413       if (add) {
414         return ok;
415       }
416     }
417
418     i++;
419   }
420
421   return ok;
422 }
423
424 /*
425  * Callback Functions
426  */
427
428 /**
429  * Callback for tunnel interface monitoring which will set the route into the tunnel
430  * when the interface comes up again.
431  *
432  * @param if_index the interface index
433  * @param ifh the interface
434  * @param flag interface change flags
435  */
436 static void smartgw_tunnel_monitor(int if_index __attribute__ ((unused)),
437     struct interface *ifh __attribute__ ((unused)), enum olsr_ifchg_flag flag __attribute__ ((unused))) {
438   return;
439 }
440
441 /**
442  * Timer callback to remove and cleanup a gateway entry
443  *
444  * @param ptr
445  */
446 static void cleanup_gateway_handler(void *ptr) {
447   struct gateway_entry *gw = ptr;
448
449   if (gw->ipv4 || gw->ipv6) {
450     /* do not clean it up when it is in use */
451     return;
452   }
453
454   /* remove gateway entry */
455   avl_delete(&gateway_tree, &gw->node);
456   olsr_cookie_free(gateway_entry_mem_cookie, gw);
457 }
458
459 /**
460  * Remove a gateway from a gateway list.
461  *
462  * @param gw_list a pointer to the gateway list
463  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
464  * @param gw a pointer to the gateway to remove from the list
465  */
466 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
467   if (gw->tunnel) {
468     struct interfaceName * ifn = find_interfaceName(gw->gw);
469     if (ifn) {
470       olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->mark);
471     }
472     olsr_os_del_ipip_tunnel(gw->tunnel);
473     set_unused_iptunnel_name(gw->gw);
474     gw->tunnel = NULL;
475   }
476   gw->gw = NULL;
477   olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
478 }
479
480 /**
481  * Remove expensive gateways from the gateway list.
482  * It uses the smart_gw_takedown_percentage configuration parameter
483  *
484  * @param gw_list a pointer to the gateway list
485  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
486  * @param current_gw the current gateway
487  */
488 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
489   uint64_t current_gw_cost_boundary;
490
491   /*
492    * exit immediately when takedown is disabled, there is no current gateway, or
493    * when there is only a single gateway
494    */
495   if ((olsr_cnf->smart_gw_takedown_percentage == 0) || (current_gw == NULL ) || (gw_list->count <= 1)) {
496     return;
497   }
498
499   /* get the cost boundary */
500
501   /* scale down because otherwise the percentage calculation can overflow */
502   current_gw_cost_boundary = (current_gw->path_cost >> 2);
503
504   if (olsr_cnf->smart_gw_takedown_percentage < 100) {
505     current_gw_cost_boundary = (current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage;
506   }
507
508   /* loop while we still have gateways */
509   while (gw_list->count > 1) {
510     /* get the worst gateway */
511     struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
512
513     /* exit when it's the current gateway */
514     if (worst_gw == current_gw) {
515       return;
516     }
517
518     /*
519      * exit when it (and further ones; the list is sorted on costs) has lower
520      * costs than the boundary costs
521      */
522     if ((worst_gw->path_cost >> 2) < current_gw_cost_boundary) {
523       return;
524     }
525
526     /* it's is too expensive: take it down */
527     removeGatewayFromList(gw_list, ipv4, worst_gw);
528   }
529 }
530
531 /**
532  * Timer callback for proactive gateway takedown
533  *
534  * @param unused unused
535  */
536 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
537   takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
538   takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
539 }
540
541 /*
542  * Main Interface
543  */
544
545 /**
546  * Initialize gateway system
547  */
548 int olsr_init_gateways(void) {
549   int retries = 5;
550
551   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
552   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
553
554   gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
555   olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
556
557   avl_init(&gateway_tree, avl_comp_default);
558
559   olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
560   olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
561
562   if (!multi_gateway_mode()) {
563     sgwEgressInterfaceNames = NULL;
564     sgwTunnel4InterfaceNames = NULL;
565     sgwTunnel6InterfaceNames = NULL;
566   } else {
567     uint8_t i;
568     struct sgw_egress_if * egressif;
569
570     /* setup the egress interface name/mark pairs */
571     sgwEgressInterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_egress_interfaces_count, "sgwEgressInterfaceNames");
572     i = 0;
573     egressif = olsr_cnf->smart_gw_egress_interfaces;
574     while (egressif) {
575       struct interfaceName * ifn = &sgwEgressInterfaceNames[i];
576       ifn->gw = NULL;
577       ifn->mark = i + olsr_cnf->smart_gw_mark_offset_egress;
578       egressif->mark = ifn->mark;
579       snprintf(&ifn->name[0], sizeof(ifn->name), egressif->name, egressif->mark);
580
581       egressif = egressif->next;
582       i++;
583     }
584     assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
585
586     /* setup the SGW tunnel name/mark pairs */
587     sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
588     sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
589     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
590       struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
591       ifn->gw = NULL;
592       ifn->mark = i + olsr_cnf->smart_gw_mark_offset_tunnels;
593       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->mark);
594
595       ifn = &sgwTunnel6InterfaceNames[i];
596       ifn->gw = NULL;
597       ifn->mark = i + olsr_cnf->smart_gw_mark_offset_tunnels;
598       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->mark);
599     }
600   }
601
602   current_ipv4_gw = NULL;
603   current_ipv6_gw = NULL;
604
605   gw_handler = NULL;
606
607   refresh_smartgw_netmask();
608
609   /* initialize default gateway handler */
610   gw_handler = &gw_def_handler;
611   gw_handler->init();
612
613
614   /*
615    * There appears to be a kernel bug in some kernels (at least in the 3.0
616    * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
617    * initialising the IPIP server tunnel (loading the IPIP module), so we retry
618    * a few times before giving up
619    */
620   while (retries-- > 0) {
621     if (!olsr_os_init_iptunnel(server_tunnel_name())) {
622       retries = 5;
623       break;
624     }
625
626     olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
627   }
628   if (retries <= 0) {
629     return 1;
630   }
631
632   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
633
634   return 0;
635 }
636
637 /**
638  * Startup gateway system
639  */
640 int olsr_startup_gateways(void) {
641   bool ok = true;
642
643   if (!multi_gateway_mode()) {
644     return 0;
645   }
646
647   ok = ok && multiGwRulesGeneric(true);
648   ok = ok && multiGwRulesSgwServerTunnel(true);
649   ok = ok && multiGwRulesOlsrInterfaces(true);
650   ok = ok && multiGwRulesEgressInterfaces(true);
651   ok = ok && multiGwRulesSgwTunnels(true);
652   if (!ok) {
653     olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
654     olsr_shutdown_gateways();
655     return 1;
656   }
657
658   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
659     /* start gateway takedown timer */
660     olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
661   }
662
663   return 0;
664 }
665
666 /**
667  * Shutdown gateway tunnel system
668  */
669 void olsr_shutdown_gateways(void) {
670   if (!multi_gateway_mode()) {
671     return;
672   }
673
674   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
675     /* stop gateway takedown timer */
676     olsr_stop_timer(gw_takedown_timer);
677     gw_takedown_timer = NULL;
678   }
679
680   (void)multiGwRulesSgwTunnels(false);
681   (void)multiGwRulesEgressInterfaces(false);
682   (void)multiGwRulesOlsrInterfaces(false);
683   (void)multiGwRulesSgwServerTunnel(false);
684   (void)multiGwRulesGeneric(false);
685 }
686
687 /**
688  * Cleanup gateway tunnel system
689  */
690 void olsr_cleanup_gateways(void) {
691   struct gateway_entry * tree_gw;
692   struct gw_container_entry * gw;
693
694   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
695
696   /* remove all gateways in the gateway tree that are not the active gateway */
697   OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
698     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
699       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
700     }
701   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
702
703   /* remove all active IPv4 gateways (should be at most 1 now) */
704   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
705     if (gw && gw->gw) {
706       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
707     }
708   }
709   OLSR_FOR_ALL_GWS_END(gw);
710
711   /* remove all active IPv6 gateways (should be at most 1 now) */
712   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
713     if (gw && gw->gw) {
714       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
715     }
716   }
717   OLSR_FOR_ALL_GWS_END(gw);
718
719   /* there should be no more gateways */
720   assert(!avl_walk_first(&gateway_tree));
721   assert(!current_ipv4_gw);
722   assert(!current_ipv6_gw);
723
724   olsr_os_cleanup_iptunnel(server_tunnel_name());
725
726   assert(gw_handler);
727   gw_handler->cleanup();
728   gw_handler = NULL;
729
730   if (sgwEgressInterfaceNames) {
731     free(sgwEgressInterfaceNames);
732     sgwEgressInterfaceNames = NULL;
733   }
734   if (sgwTunnel4InterfaceNames) {
735     free(sgwTunnel4InterfaceNames);
736     sgwTunnel4InterfaceNames = NULL;
737   }
738   if (sgwTunnel6InterfaceNames) {
739     free(sgwTunnel6InterfaceNames);
740     sgwTunnel6InterfaceNames = NULL;
741   }
742
743   olsr_gw_list_cleanup(&gw_list_ipv6);
744   olsr_gw_list_cleanup(&gw_list_ipv4);
745   olsr_free_cookie(gw_container_entry_mem_cookie);
746   olsr_free_cookie(gateway_entry_mem_cookie);
747 }
748
749 /**
750  * Triggers the first lookup of a gateway.
751  */
752 void olsr_trigger_inetgw_startup(void) {
753   assert(gw_handler);
754   gw_handler->startup();
755 }
756
757 /**
758  * Print debug information about gateway entries
759  */
760 #ifndef NODEBUG
761 void olsr_print_gateway_entries(void) {
762   struct ipaddr_str buf;
763   struct gateway_entry *gw;
764   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
765
766   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
767   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
768       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
769
770   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
771     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
772         addrsize,
773         olsr_ip_to_string(&buf, &gw->originator),
774         gw->ipv4nat ? "" : "   ",
775         gw->ipv4 ? '4' : ' ',
776         gw->ipv4nat ? "(N)" : "",
777         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
778         gw->ipv6 ? '6' : ' ',
779         gw->uplink,
780         gw->downlink,
781         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
782   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
783 }
784 #endif /* NODEBUG */
785
786 /*
787  * Tx Path Interface
788  */
789
790 /**
791  * Apply the smart gateway modifications to an outgoing HNA
792  *
793  * @param mask pointer to netmask of the HNA
794  * @param prefixlen of the HNA
795  */
796 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
797   uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
798
799   /* copy the current settings for uplink/downlink into the mask */
800   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
801   if (olsr_cnf->has_ipv4_gateway) {
802     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
803
804     if (olsr_cnf->smart_gw_uplink_nat) {
805       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
806     }
807   }
808   if (olsr_cnf->has_ipv6_gateway) {
809     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
810   }
811   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
812     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
813   }
814 }
815
816 /*
817  * SgwDynSpeed Plugin Interface
818  */
819
820 /**
821  * Setup the gateway netmask
822  */
823 void refresh_smartgw_netmask(void) {
824   uint8_t *ip;
825
826   /* clear the mask */
827   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
828
829   if (olsr_cnf->smart_gw_active) {
830     ip = (uint8_t *) &smart_gateway_netmask;
831
832     ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
833     ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
834     ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
835
836     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
837       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
838       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
839       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
840     }
841   }
842 }
843
844 /*
845  * TC/SPF/HNA Interface
846  */
847
848 /**
849  * Checks if a HNA prefix/netmask combination is a smart gateway
850  *
851  * @param prefix
852  * @param mask
853  * @return true if is a valid smart gateway HNA, false otherwise
854  */
855 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
856   uint8_t *ptr;
857
858   if (!is_prefix_inetgw(prefix)) {
859     return false;
860   }
861
862   ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
863   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
864 }
865
866 /**
867  * Update a gateway_entry based on a HNA
868  *
869  * @param originator ip of the source of the HNA
870  * @param mask netmask of the HNA
871  * @param prefixlen of the HNA
872  * @param seqno the sequence number of the HNA
873  */
874 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
875   struct gw_container_entry * new_gw_in_list;
876   uint8_t *ptr;
877   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
878
879   if (!gw) {
880     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
881     gw->originator = *originator;
882     gw->node.key = &gw->originator;
883
884     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
885   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
886     /* ignore older HNAs */
887     return;
888   }
889
890   /* keep new HNA seqno */
891   gw->seqno = seqno;
892
893   ptr = hna_mask_to_hna_pointer(mask, prefixlen);
894   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
895     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
896     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
897   } else {
898     gw->uplink = 0;
899     gw->downlink = 0;
900   }
901
902   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
903   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
904
905   if (olsr_cnf->ip_version == AF_INET6) {
906     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
907
908     /* do not reset prefixlength for ::ffff:0:0 HNAs */
909     if (prefixlen == ipv6_internet_route.prefix_len) {
910       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
911
912       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
913           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
914         /* this is the right prefix (2000::/3), so we can copy the prefix */
915         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
916         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
917       }
918     }
919   }
920
921   /* stop cleanup timer if necessary */
922   if (gw->cleanup_timer) {
923     olsr_stop_timer(gw->cleanup_timer);
924     gw->cleanup_timer = NULL;
925   }
926
927   /* update the costs of the gateway when it is an active gateway */
928   new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
929   if (new_gw_in_list) {
930     assert(gw_handler);
931     new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, gw_handler->getcosts(new_gw_in_list->gw));
932     assert(new_gw_in_list);
933   }
934
935   new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
936   if (new_gw_in_list) {
937     assert(gw_handler);
938     new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list, gw_handler->getcosts(new_gw_in_list->gw));
939     assert(new_gw_in_list);
940   }
941
942   /* call update handler */
943   assert(gw_handler);
944   gw_handler->update(gw);
945 }
946
947 /**
948  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
949  * Should only be called if prefix is a smart_gw prefix or if node is removed
950  * from TC set.
951  *
952  * @param originator
953  * @param prefixlen
954  * @param immediate when set to true then the gateway is removed from the
955  * gateway tree immediately, else it is removed on a delayed schedule.
956  */
957 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
958   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
959 }
960
961 /**
962  * Delete a gateway entry .
963  *
964  * @param gw a gateway entry from the gateway tree
965  * @param prefixlen
966  * @param immediate when set to true then the gateway is removed from the
967  * gateway tree immediately, else it is removed on a delayed schedule.
968  */
969 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
970   bool change = false;
971
972   if (!gw) {
973     return;
974   }
975
976   if (immediate && gw->cleanup_timer) {
977     /* stop timer if we have to remove immediately */
978     olsr_stop_timer(gw->cleanup_timer);
979     gw->cleanup_timer = NULL;
980   }
981
982   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
983     /* the gw  is not scheduled for deletion */
984
985     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
986       change = gw->ipv4;
987       gw->ipv4 = false;
988       gw->ipv4nat = false;
989     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
990       change = gw->ipv6;
991       gw->ipv6 = false;
992     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
993       change = gw->ipv4;
994       gw->ipv4 = false;
995       gw->ipv4nat = false;
996     }
997
998     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
999       struct gw_container_entry * gw_in_list;
1000
1001       /* prevent this gateway from being chosen as the new gateway */
1002       gw->ipv4 = false;
1003       gw->ipv4nat = false;
1004       gw->ipv6 = false;
1005
1006       /* handle gateway loss */
1007       assert(gw_handler);
1008       gw_handler->delete(gw);
1009
1010       /* cleanup gateway if necessary */
1011       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1012       if (gw_in_list) {
1013         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1014           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1015           current_ipv4_gw = NULL;
1016         }
1017
1018         if (gw_in_list->tunnel) {
1019           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1020           if (ifn) {
1021             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->mark);
1022           }
1023           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1024           set_unused_iptunnel_name(gw_in_list->gw);
1025           gw_in_list->tunnel = NULL;
1026         }
1027
1028         gw_in_list->gw = NULL;
1029         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1030         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1031       }
1032
1033       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1034       if (gw_in_list) {
1035         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1036           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1037           current_ipv6_gw = NULL;
1038         }
1039
1040         if (gw_in_list->tunnel) {
1041           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1042           if (ifn) {
1043             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->mark);
1044           }
1045           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1046           set_unused_iptunnel_name(gw_in_list->gw);
1047           gw_in_list->tunnel = NULL;
1048         }
1049
1050         gw_in_list->gw = NULL;
1051         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1052         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1053       }
1054
1055       if (!immediate) {
1056         /* remove gateway entry on a delayed schedule */
1057         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1058       } else {
1059         cleanup_gateway_handler(gw);
1060       }
1061
1062       /* when the current gateway was deleted, then immediately choose a new gateway */
1063       if (!current_ipv4_gw || !current_ipv6_gw) {
1064         assert(gw_handler);
1065         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1066       }
1067
1068     } else if (change) {
1069       assert(gw_handler);
1070       gw_handler->update(gw);
1071     }
1072   }
1073 }
1074
1075 /**
1076  * Triggers a check if the one of the gateways have been lost or has an
1077  * ETX = infinity
1078  */
1079 void olsr_trigger_gatewayloss_check(void) {
1080   bool ipv4 = false;
1081   bool ipv6 = false;
1082
1083   if (current_ipv4_gw && current_ipv4_gw->gw) {
1084     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
1085     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1086   }
1087   if (current_ipv6_gw && current_ipv6_gw->gw) {
1088     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
1089     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1090   }
1091
1092   if (ipv4 || ipv6) {
1093     assert(gw_handler);
1094     gw_handler->choose(ipv4, ipv6);
1095   }
1096 }
1097
1098 /*
1099  * Gateway Plugin Functions
1100  */
1101
1102 /**
1103  * Sets a new internet gateway.
1104  *
1105  * @param originator ip address of the node with the new gateway
1106  * @param path_cost the path cost
1107  * @param ipv4 set ipv4 gateway
1108  * @param ipv6 set ipv6 gateway
1109  * @return true if an error happened, false otherwise
1110  */
1111 bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, bool ipv4, bool ipv6) {
1112   struct gateway_entry *new_gw;
1113
1114   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1115   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1116   if (!ipv4 && !ipv6) {
1117     return true;
1118   }
1119
1120   new_gw = node2gateway(avl_find(&gateway_tree, originator));
1121   if (!new_gw) {
1122     /* the originator is not in the gateway tree, we can't set it as gateway */
1123     return true;
1124   }
1125
1126   /* handle IPv4 */
1127   if (ipv4 &&
1128       new_gw->ipv4 &&
1129       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1130       (!current_ipv4_gw || current_ipv4_gw->gw != new_gw || current_ipv4_gw->path_cost != path_cost)) {
1131     /* new gw is different than the current gw, or costs have changed */
1132
1133     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1134     if (new_gw_in_list) {
1135       /* new gw is already in the gw list */
1136       assert(new_gw_in_list->tunnel);
1137       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1138       current_ipv4_gw = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, path_cost);
1139     } else {
1140       /* new gw is not yet in the gw list */
1141       char name[IFNAMSIZ];
1142       struct olsr_iptunnel_entry *new_v4gw_tunnel;
1143       struct interfaceName * interfaceName;
1144
1145       if (olsr_gw_list_full(&gw_list_ipv4)) {
1146         /* the list is full: remove the worst active gateway */
1147         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1148         assert(worst);
1149
1150         removeGatewayFromList(&gw_list_ipv4, true, worst);
1151       }
1152
1153       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1154       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1155       if (new_v4gw_tunnel) {
1156         if (interfaceName) {
1157           olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->mark);
1158         }
1159         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1160
1161         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1162         new_gw_in_list->gw = new_gw;
1163         new_gw_in_list->tunnel = new_v4gw_tunnel;
1164         new_gw_in_list->path_cost = path_cost;
1165         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1166       } else {
1167         /* adding the tunnel failed, we try again in the next cycle */
1168         set_unused_iptunnel_name(new_gw);
1169         ipv4 = false;
1170       }
1171     }
1172   }
1173
1174   /* handle IPv6 */
1175   if (ipv6 &&
1176       new_gw->ipv6 &&
1177       (!current_ipv6_gw || current_ipv6_gw->gw != new_gw || current_ipv6_gw->path_cost != path_cost)) {
1178     /* new gw is different than the current gw, or costs have changed */
1179
1180         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1181     if (new_gw_in_list) {
1182       /* new gw is already in the gw list */
1183       assert(new_gw_in_list->tunnel);
1184       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1185       current_ipv6_gw = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list, path_cost);
1186     } else {
1187       /* new gw is not yet in the gw list */
1188       char name[IFNAMSIZ];
1189       struct olsr_iptunnel_entry *new_v6gw_tunnel;
1190       struct interfaceName * interfaceName;
1191
1192       if (olsr_gw_list_full(&gw_list_ipv6)) {
1193         /* the list is full: remove the worst active gateway */
1194         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1195         assert(worst);
1196
1197         removeGatewayFromList(&gw_list_ipv6, false, worst);
1198       }
1199
1200       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1201       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1202       if (new_v6gw_tunnel) {
1203         if (interfaceName) {
1204           olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->mark);
1205         }
1206         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1207
1208         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1209         new_gw_in_list->gw = new_gw;
1210         new_gw_in_list->tunnel = new_v6gw_tunnel;
1211         new_gw_in_list->path_cost = path_cost;
1212         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1213       } else {
1214         /* adding the tunnel failed, we try again in the next cycle */
1215         set_unused_iptunnel_name(new_gw);
1216         ipv6 = false;
1217       }
1218     }
1219   }
1220
1221   return !ipv4 && !ipv6;
1222 }
1223
1224 /**
1225  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1226  * gateway is returned
1227  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1228  * NULL if not set.
1229  */
1230 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1231         if (ipv6) {
1232                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1233         }
1234
1235         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1236 }
1237
1238 #endif /* __linux__ */