7ed9ef4d17c27bdf51a26de1481517cb36e1e846
[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 #include "egressTypes.h"
26 #include "egressFile.h"
27
28 #include <assert.h>
29 #include <net/if.h>
30
31 /*
32  * Defines for the multi-gateway script
33  */
34
35 #define SCRIPT_MODE_GENERIC   "generic"
36 #define SCRIPT_MODE_OLSRIF    "olsrif"
37 #define SCRIPT_MODE_SGWSRVTUN "sgwsrvtun"
38 #define SCRIPT_MODE_EGRESSIF  "egressif"
39 #define SCRIPT_MODE_SGWTUN    "sgwtun"
40
41 /** structure that holds an interface name, mark and a pointer to the gateway that uses it */
42 struct interfaceName {
43   char name[IFNAMSIZ]; /**< interface name */
44   uint8_t tableNr; /**< routing table number */
45   uint8_t ruleNr; /**< IP rule number */
46   uint8_t bypassRuleNr; /**< bypass IP rule number */
47   struct gateway_entry *gw; /**< gateway that uses this interface name */
48 };
49
50 /** the gateway tree */
51 struct avl_tree gateway_tree;
52
53 /** gateway cookie */
54 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
55
56 /** gateway container cookie */
57 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
58
59 /** the gateway netmask for the HNA */
60 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
61
62 /** the gateway handler/plugin */
63 static struct olsr_gw_handler *gw_handler;
64
65 /** the IPv4 gateway list */
66 struct gw_list gw_list_ipv4;
67
68 /** the IPv6 gateway list */
69 struct gw_list gw_list_ipv6;
70
71 /** the current IPv4 gateway */
72 static struct gw_container_entry *current_ipv4_gw;
73
74 /** the current IPv6 gateway */
75 static struct gw_container_entry *current_ipv6_gw;
76
77 /** interface names for smart gateway tunnel interfaces, IPv4 */
78 struct interfaceName * sgwTunnel4InterfaceNames;
79
80 /** interface names for smart gateway tunnel interfaces, IPv6 */
81 struct interfaceName * sgwTunnel6InterfaceNames;
82
83 /** the timer for proactive takedown */
84 static struct timer_entry *gw_takedown_timer;
85
86 static struct sgw_egress_if * bestEgressLinkPrevious = NULL;
87 static struct sgw_egress_if * bestEgressLink = NULL;
88
89 /*
90  * Forward Declarations
91  */
92
93 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
94
95 /*
96  * Helper Functions
97  */
98
99 /**
100  * @return the gateway 'server' tunnel name to use
101  */
102 static inline const char * server_tunnel_name(void) {
103   return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
104 }
105
106 /**
107  * Convert the netmask of the HNA (in the form of an IP address) to a HNA
108  * pointer.
109  *
110  * @param mask the netmask of the HNA (in the form of an IP address)
111  * @param prefixlen the prefix length
112  * @return a pointer to the HNA
113  */
114 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
115   return (((uint8_t *)mask) + ((prefixlen+7)/8));
116 }
117
118 /**
119  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
120  * to an uplink/downlink speed value
121  *
122  * @param value the encoded 1 byte transport value
123  * @return the uplink/downlink speed value (in kbit/s)
124  */
125 static uint32_t deserialize_gw_speed(uint8_t value) {
126   uint32_t speed;
127   uint32_t exp;
128
129   if (!value) {
130     /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
131      * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
132     return 0;
133   }
134
135   if (value == UINT8_MAX) {
136     /* maximum value: also return maximum value */
137     return 320000000;
138   }
139
140   speed = (value >> 3) + 1;
141   exp = value & 7;
142
143   while (exp-- > 0) {
144     speed *= 10;
145   }
146   return speed;
147 }
148
149 /**
150  * Convert an uplink/downlink speed value into an encoded 1 byte transport
151  * value (5 bits mantissa, 3 bits exponent)
152  *
153  * @param speed the uplink/downlink speed value (in kbit/s)
154  * @return value the encoded 1 byte transport value
155  */
156 static uint8_t serialize_gw_speed(uint32_t speed) {
157   uint8_t exp = 0;
158
159   if (speed == 0) {
160     return 0;
161   }
162
163   if (speed > 320000000) {
164     return UINT8_MAX;
165   }
166
167   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
168     speed /= 10;
169     exp++;
170   }
171   return ((speed - 1) << 3) | exp;
172 }
173
174 /**
175  * Find an interfaceName struct corresponding to a certain gateway
176  * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
177  *
178  * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
179  * @return a pointer to the struct, or NULL when not found
180  */
181 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
182   struct interfaceName * sgwTunnelInterfaceNames;
183   uint8_t i = 0;
184
185   if (!multi_gateway_mode()) {
186     return NULL;
187   }
188
189   assert(sgwTunnel4InterfaceNames);
190   assert(sgwTunnel6InterfaceNames);
191
192   sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
193   while (i < olsr_cnf->smart_gw_use_count) {
194     struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
195     if (ifn->gw == gw) {
196       return ifn;
197     }
198     i++;
199   }
200
201   return NULL;
202 }
203
204 /**
205  * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
206  *
207  * @param gw pointer to the gateway
208  * @param name pointer to output buffer (length IFNAMSIZ)
209  * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
210  */
211 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
212   static uint32_t counter = 0;
213
214   assert(gw);
215   assert(name);
216   assert(interfaceName);
217
218   memset(name, 0, IFNAMSIZ);
219
220   if (multi_gateway_mode()) {
221     struct interfaceName * ifn = find_interfaceName(NULL);
222
223     if (ifn) {
224       strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
225       *interfaceName = ifn;
226       ifn->gw = gw;
227       return;
228     }
229
230     /* do not return, fall-through to classic naming as fallback */
231   }
232
233   snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
234   *interfaceName = NULL;
235 }
236
237 /**
238  * Set an olsr ipip tunnel name that is used by a certain gateway as unused
239  *
240  * @param gw pointer to the gateway
241  */
242 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
243   struct interfaceName * ifn;
244
245   if (!multi_gateway_mode()) {
246     return;
247   }
248
249   assert(gw);
250
251   ifn = find_interfaceName(gw);
252   if (ifn) {
253     ifn->gw = NULL;
254     return;
255   }
256 }
257
258 /**
259  * Run the multi-gateway script/
260  *
261  * @param mode the mode (see SCRIPT_MODE_* defines)
262  * @param addMode true to add policy routing, false to remove it
263  * @param ifname the interface name (optional)
264  * @param tableNr the routing table number (optional)
265  * @param ruleNr the IP rule number/priority (optional)
266  * @param bypassRuleNr the bypass IP rule number/priority (optional)
267  * @return true when successful
268  */
269 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
270   struct autobuf buf;
271   int r;
272
273   assert(!strcmp(mode, SCRIPT_MODE_GENERIC) //
274       || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
275       || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
276       || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
277       || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
278       );
279
280   assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
281       || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
282
283   assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
284       || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
285
286   assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
287       || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
288
289   assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
290       || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
291
292   assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
293       || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
294
295   abuf_init(&buf, 1024);
296
297   abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
298
299   abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
300
301   abuf_appendf(&buf, " \"%s\"", mode);
302
303   abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
304
305   if (ifName) {
306     abuf_appendf(&buf, " \"%s\"", ifName);
307   }
308
309   if (tableNr) {
310     abuf_appendf(&buf, " \"%u\"", tableNr);
311   }
312
313   if (ruleNr) {
314     abuf_appendf(&buf, " \"%u\"", ruleNr);
315   }
316
317   if (bypassRuleNr) {
318     abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
319   }
320
321   r = system(buf.buf);
322
323   abuf_free(&buf);
324
325   return (r == 0);
326 }
327
328 /**
329  * Setup generic multi-gateway iptables and ip rules
330  *
331  * @param add true to add policy routing, false to remove it
332  * @return true when successful
333  */
334 static bool multiGwRulesGeneric(bool add) {
335   return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
336 }
337
338 /**
339  * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
340  *
341  * @param add true to add policy routing, false to remove it
342  * @return true when successful
343  */
344 static bool multiGwRulesOlsrInterfaces(bool add) {
345   bool ok = true;
346   struct olsr_if * ifn;
347   unsigned int i = 0;
348
349   for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
350     if (!multiGwRunScript( //
351         SCRIPT_MODE_OLSRIF,//
352         add, //
353         ifn->name, //
354         0, //
355         0, //
356         olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
357             )) {
358       ok = false;
359       if (add) {
360         return ok;
361       }
362     }
363   }
364
365   return ok;
366 }
367
368 /**
369  * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
370  *
371  * @param add true to add policy routing, false to remove it
372  * @return true when successful
373  */
374 static bool multiGwRulesSgwServerTunnel(bool add) {
375   return multiGwRunScript( //
376       SCRIPT_MODE_SGWSRVTUN,//
377       add, //
378       server_tunnel_name(), //
379       olsr_cnf->smart_gw_offset_tables, //
380       olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
381       0 //
382       );
383 }
384
385 /**
386  * Setup multi-gateway iptables and ip rules for all egress interfaces.
387  *
388  * @param add true to add policy routing, false to remove it
389  * @return true when successful
390  */
391 static bool multiGwRulesEgressInterfaces(bool add) {
392   bool ok = true;
393   unsigned int i = 0;
394
395   struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
396   while (egress_if) {
397     if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
398       ok = false;
399       if (add) {
400         return ok;
401       }
402     }
403
404     egress_if = egress_if->next;
405   }
406
407   return ok;
408 }
409
410 /**
411  * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
412  *
413  * @param add true to add policy routing, false to remove it
414  * @return true when successful
415  */
416 static bool multiGwRulesSgwTunnels(bool add) {
417   bool ok = true;
418   unsigned int i = 0;
419
420   while (i < olsr_cnf->smart_gw_use_count) {
421     struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
422     if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
423       ok = false;
424       if (add) {
425         return ok;
426       }
427     }
428
429     i++;
430   }
431
432   return ok;
433 }
434
435 /**
436  * Process interface up/down events for non-olsr interfaces, which are egress
437  * interfaces
438  *
439  * @param if_index the index of the interface
440  * @param flag the up/down event
441  */
442 static void doEgressInterface(int if_index, enum olsr_ifchg_flag flag) {
443   switch (flag) {
444     case IFCHG_IF_ADD: {
445       char ifname[IF_NAMESIZE];
446       struct sgw_egress_if * egress_if;
447
448       /*
449        * we need to get the name of the interface first because the interface
450        * might be hot-plugged _after_ olsrd has started
451        */
452       if (!if_indextoname(if_index, ifname)) {
453         /* not a known OS interface */
454         return;
455       }
456
457       egress_if = findEgressInterface(ifname);
458       if (!egress_if) {
459         /* not a known egress interface */
460         return;
461       }
462
463       egress_if->if_index = if_index;
464
465       if (egress_if->upCurrent) {
466         /* interface is already up: no change */
467         return;
468       }
469
470       egress_if->upPrevious = egress_if->upCurrent;
471       egress_if->upCurrent = true;
472       egress_if->upChanged = true;
473
474       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
475     }
476       break;
477
478     case IFCHG_IF_REMOVE: {
479       /*
480        * we need to find the egress interface by if_index because we might
481        * be too late; the kernel could already have removed the interface
482        * in which case we'd get a NULL ifname here if we'd try to call
483        * if_indextoname
484        */
485       struct sgw_egress_if * egress_if = findEgressInterfaceByIndex(if_index);
486       if (!egress_if) {
487         /* not a known egress interface */
488         return;
489       }
490
491       if (!egress_if->upCurrent) {
492         /* interface is already down: no change */
493         return;
494       }
495
496       egress_if->upPrevious = egress_if->upCurrent;
497       egress_if->upCurrent = false;
498       egress_if->upChanged = true;
499
500       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
501     }
502       break;
503
504     case IFCHG_IF_UPDATE:
505     default:
506       return;
507   }
508
509   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_RUNTIME);
510 }
511
512 /*
513  * Callback Functions
514  */
515
516 /**
517  * Callback for tunnel interface monitoring which will set the route into the tunnel
518  * when the interface comes up again.
519  *
520  * @param if_index the interface index
521  * @param ifh the interface (NULL when not an olsr interface)
522  * @param flag interface change flags
523  */
524 static void smartgw_tunnel_monitor(int if_index, struct interface *ifh, enum olsr_ifchg_flag flag) {
525   if (!ifh && multi_gateway_mode()) {
526     /* non-olsr interface in multi-sgw mode */
527     doEgressInterface(if_index, flag);
528   }
529
530   return;
531 }
532
533 /**
534  * Timer callback to remove and cleanup a gateway entry
535  *
536  * @param ptr
537  */
538 static void cleanup_gateway_handler(void *ptr) {
539   struct gateway_entry *gw = ptr;
540
541   if (gw->ipv4 || gw->ipv6) {
542     /* do not clean it up when it is in use */
543     return;
544   }
545
546   /* remove gateway entry */
547   avl_delete(&gateway_tree, &gw->node);
548   olsr_cookie_free(gateway_entry_mem_cookie, gw);
549 }
550
551 /**
552  * Remove a gateway from a gateway list.
553  *
554  * @param gw_list a pointer to the gateway list
555  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
556  * @param gw a pointer to the gateway to remove from the list
557  */
558 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
559   if (gw->tunnel) {
560     struct interfaceName * ifn = find_interfaceName(gw->gw);
561     if (ifn) {
562       olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
563     }
564     olsr_os_del_ipip_tunnel(gw->tunnel);
565     set_unused_iptunnel_name(gw->gw);
566     gw->tunnel = NULL;
567   }
568   gw->gw = NULL;
569   olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
570 }
571
572 /**
573  * Remove expensive gateways from the gateway list.
574  * It uses the smart_gw_takedown_percentage configuration parameter
575  *
576  * @param gw_list a pointer to the gateway list
577  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
578  * @param current_gw the current gateway
579  */
580 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
581   int64_t current_gw_cost_boundary;
582
583   /*
584    * exit immediately when takedown is disabled, there is no current gateway, or
585    * when there is only a single gateway
586    */
587   if ((olsr_cnf->smart_gw_takedown_percentage == 0) || (current_gw == NULL ) || (gw_list->count <= 1)) {
588     return;
589   }
590
591   /* get the cost boundary */
592   current_gw_cost_boundary = current_gw->gw->path_cost;
593   if (olsr_cnf->smart_gw_takedown_percentage < 100) {
594     if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
595       current_gw_cost_boundary =  ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
596     } else {
597       /* perform scaling because otherwise the percentage calculation can overflow */
598       current_gw_cost_boundary = (((current_gw_cost_boundary      ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
599     }
600   }
601
602   /* loop while we still have gateways */
603   while (gw_list->count > 1) {
604     /* get the worst gateway */
605     struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
606
607     /* exit when it's the current gateway */
608     if (worst_gw == current_gw) {
609       return;
610     }
611
612     /*
613      * exit when it (and further ones; the list is sorted on costs) has lower
614      * costs than the boundary costs
615      */
616     if (worst_gw->gw->path_cost < current_gw_cost_boundary) {
617       return;
618     }
619
620     /* it's too expensive: take it down */
621     removeGatewayFromList(gw_list, ipv4, worst_gw);
622   }
623 }
624
625 /**
626  * Timer callback for proactive gateway takedown
627  *
628  * @param unused unused
629  */
630 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
631   takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
632   takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
633 }
634
635 /*
636  * Main Interface
637  */
638
639 /**
640  * Initialize gateway system
641  */
642 int olsr_init_gateways(void) {
643   int retries = 5;
644
645   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
646   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
647
648   gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
649   olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
650
651   avl_init(&gateway_tree, avl_comp_default);
652
653   olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
654   olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
655
656   if (!multi_gateway_mode()) {
657     sgwTunnel4InterfaceNames = NULL;
658     sgwTunnel6InterfaceNames = NULL;
659   } else {
660     uint8_t i;
661     struct sgw_egress_if * egressif;
662     unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
663
664     /* setup the egress interface name/mark pairs */
665     i = 0;
666     egressif = olsr_cnf->smart_gw_egress_interfaces;
667     while (egressif) {
668       egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
669       egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
670       egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
671
672       egressif = egressif->next;
673       i++;
674     }
675     assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
676
677     /* setup the SGW tunnel name/mark pairs */
678     sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
679     sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
680     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
681       struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
682       uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
683       uint32_t ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
684
685       ifn->gw = NULL;
686       ifn->tableNr = tableNr;
687       ifn->ruleNr = ruleNr;
688       ifn->bypassRuleNr = 0;
689       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
690
691       ifn = &sgwTunnel6InterfaceNames[i];
692       ifn->gw = NULL;
693       ifn->tableNr = tableNr;
694       ifn->ruleNr = ruleNr;
695       ifn->bypassRuleNr = 0;
696       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
697     }
698   }
699
700   current_ipv4_gw = NULL;
701   current_ipv6_gw = NULL;
702
703   gw_handler = NULL;
704
705   refresh_smartgw_netmask();
706
707   /* initialize default gateway handler */
708   gw_handler = &gw_def_handler;
709   gw_handler->init();
710
711
712   /*
713    * There appears to be a kernel bug in some kernels (at least in the 3.0
714    * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
715    * initialising the IPIP server tunnel (loading the IPIP module), so we retry
716    * a few times before giving up
717    */
718   while (retries-- > 0) {
719     if (!olsr_os_init_iptunnel(server_tunnel_name())) {
720       retries = 5;
721       break;
722     }
723
724     olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
725   }
726   if (retries <= 0) {
727     return 1;
728   }
729
730   return 0;
731 }
732
733 /**
734  * Startup gateway system
735  */
736 int olsr_startup_gateways(void) {
737   bool ok = true;
738
739   if (!multi_gateway_mode()) {
740     olsr_add_ifchange_handler(smartgw_tunnel_monitor);
741     return 0;
742   }
743
744   /* Initialise the egress interfaces */
745   {
746     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
747     while (egress_if) {
748       egress_if->if_index = if_nametoindex(egress_if->name);
749
750       egress_if->upPrevious = egress_if->upCurrent = olsr_if_isup(egress_if->name);
751       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
752
753       egressBwClear(&egress_if->bwPrevious, egress_if->upPrevious);
754       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
755       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
756       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
757       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
758       egress_if->bwChanged = egressBwChanged(egress_if);
759
760       egress_if->inEgressFile = false;
761
762       egress_if = egress_if->next;
763     }
764   }
765
766   ok = ok && multiGwRulesGeneric(true);
767   ok = ok && multiGwRulesSgwServerTunnel(true);
768   ok = ok && multiGwRulesOlsrInterfaces(true);
769   ok = ok && multiGwRulesEgressInterfaces(true);
770   ok = ok && multiGwRulesSgwTunnels(true);
771   if (!ok) {
772     olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
773     olsr_shutdown_gateways();
774     return 1;
775   }
776
777   startEgressFile();
778   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
779
780   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
781
782   /* Check egress interfaces up status to compensate for a race: the interfaces
783    * can change status between initialising their data structures and
784    * registering the tunnel monitor */
785   {
786     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
787     while (egress_if) {
788       bool upCurrent = olsr_if_isup(egress_if->name);
789
790       if (upCurrent != egress_if->upCurrent) {
791         int index = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
792         enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
793         smartgw_tunnel_monitor(index, NULL, flag);
794       }
795
796       egress_if = egress_if->next;
797     }
798   }
799
800   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
801     /* start gateway takedown timer */
802     olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
803   }
804
805   return 0;
806 }
807
808 /**
809  * Shutdown gateway tunnel system
810  */
811 void olsr_shutdown_gateways(void) {
812   if (!multi_gateway_mode()) {
813     olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
814     return;
815   }
816
817   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
818     /* stop gateway takedown timer */
819     olsr_stop_timer(gw_takedown_timer);
820     gw_takedown_timer = NULL;
821   }
822
823   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
824
825   stopEgressFile();
826   {
827     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
828     while (egress_if) {
829       egress_if->upPrevious = egress_if->upCurrent;
830       egress_if->upCurrent = false;
831       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
832
833       egress_if->bwPrevious = egress_if->bwCurrent;
834       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
835       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
836       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
837       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
838       egress_if->bwChanged = egressBwChanged(egress_if);
839
840       egress_if->inEgressFile = false;
841
842       egress_if = egress_if->next;
843     }
844   }
845   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
846
847   (void)multiGwRulesSgwTunnels(false);
848   (void)multiGwRulesEgressInterfaces(false);
849   (void)multiGwRulesOlsrInterfaces(false);
850   (void)multiGwRulesSgwServerTunnel(false);
851   (void)multiGwRulesGeneric(false);
852 }
853
854 /**
855  * Cleanup gateway tunnel system
856  */
857 void olsr_cleanup_gateways(void) {
858   struct gateway_entry * tree_gw;
859   struct gw_container_entry * gw;
860
861   /* remove all gateways in the gateway tree that are not the active gateway */
862   OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
863     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
864       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
865     }
866   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
867
868   /* remove all active IPv4 gateways (should be at most 1 now) */
869   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
870     if (gw && gw->gw) {
871       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
872     }
873   }
874   OLSR_FOR_ALL_GWS_END(gw);
875
876   /* remove all active IPv6 gateways (should be at most 1 now) */
877   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
878     if (gw && gw->gw) {
879       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
880     }
881   }
882   OLSR_FOR_ALL_GWS_END(gw);
883
884   /* there should be no more gateways */
885   assert(!avl_walk_first(&gateway_tree));
886   assert(!current_ipv4_gw);
887   assert(!current_ipv6_gw);
888
889   olsr_os_cleanup_iptunnel(server_tunnel_name());
890
891   assert(gw_handler);
892   gw_handler->cleanup();
893   gw_handler = NULL;
894
895   if (sgwTunnel4InterfaceNames) {
896     free(sgwTunnel4InterfaceNames);
897     sgwTunnel4InterfaceNames = NULL;
898   }
899   if (sgwTunnel6InterfaceNames) {
900     free(sgwTunnel6InterfaceNames);
901     sgwTunnel6InterfaceNames = NULL;
902   }
903
904   olsr_gw_list_cleanup(&gw_list_ipv6);
905   olsr_gw_list_cleanup(&gw_list_ipv4);
906   olsr_free_cookie(gw_container_entry_mem_cookie);
907   olsr_free_cookie(gateway_entry_mem_cookie);
908 }
909
910 /**
911  * Triggers the first lookup of a gateway.
912  */
913 void olsr_trigger_inetgw_startup(void) {
914   assert(gw_handler);
915   gw_handler->startup();
916 }
917
918 /**
919  * Print debug information about gateway entries
920  */
921 #ifndef NODEBUG
922 void olsr_print_gateway_entries(void) {
923   struct ipaddr_str buf;
924   struct gateway_entry *gw;
925   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
926
927   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
928   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
929       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
930
931   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
932     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
933         addrsize,
934         olsr_ip_to_string(&buf, &gw->originator),
935         gw->ipv4nat ? "" : "   ",
936         gw->ipv4 ? '4' : ' ',
937         gw->ipv4nat ? "(N)" : "",
938         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
939         gw->ipv6 ? '6' : ' ',
940         gw->uplink,
941         gw->downlink,
942         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
943   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
944 }
945 #endif /* NODEBUG */
946
947 /*
948  * Tx Path Interface
949  */
950
951 /**
952  * Apply the smart gateway modifications to an outgoing HNA
953  *
954  * @param mask pointer to netmask of the HNA
955  * @param prefixlen of the HNA
956  */
957 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
958   uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
959
960   /* copy the current settings for uplink/downlink into the mask */
961   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
962   if (olsr_cnf->has_ipv4_gateway) {
963     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
964
965     if (olsr_cnf->smart_gw_uplink_nat) {
966       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
967     }
968   }
969   if (olsr_cnf->has_ipv6_gateway) {
970     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
971   }
972   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
973     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
974   }
975 }
976
977 /*
978  * SgwDynSpeed Plugin Interface
979  */
980
981 /**
982  * Setup the gateway netmask
983  */
984 void refresh_smartgw_netmask(void) {
985   uint8_t *ip;
986
987   /* clear the mask */
988   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
989
990   if (olsr_cnf->smart_gw_active) {
991     ip = (uint8_t *) &smart_gateway_netmask;
992
993     ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
994     ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
995     ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
996
997     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
998       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
999       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1000       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1001     }
1002   }
1003 }
1004
1005 /*
1006  * TC/SPF/HNA Interface
1007  */
1008
1009 /**
1010  * Checks if a HNA prefix/netmask combination is a smart gateway
1011  *
1012  * @param prefix
1013  * @param mask
1014  * @return true if is a valid smart gateway HNA, false otherwise
1015  */
1016 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1017   uint8_t *ptr;
1018
1019   if (!is_prefix_inetgw(prefix)) {
1020     return false;
1021   }
1022
1023   ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1024   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1025 }
1026
1027 /**
1028  * Update a gateway_entry based on a HNA
1029  *
1030  * @param originator ip of the source of the HNA
1031  * @param mask netmask of the HNA
1032  * @param prefixlen of the HNA
1033  * @param seqno the sequence number of the HNA
1034  */
1035 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
1036   struct gw_container_entry * new_gw_in_list;
1037   uint8_t *ptr;
1038   int64_t prev_path_cost = 0;
1039   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1040
1041   if (!gw) {
1042     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1043     gw->originator = *originator;
1044     gw->node.key = &gw->originator;
1045
1046     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1047   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1048     /* ignore older HNAs */
1049     return;
1050   }
1051
1052   /* keep new HNA seqno */
1053   gw->seqno = seqno;
1054
1055   ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1056   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1057     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1058     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1059   } else {
1060     gw->uplink = 0;
1061     gw->downlink = 0;
1062   }
1063
1064   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1065   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1066   gw->ipv6 = false;
1067
1068   if (olsr_cnf->ip_version == AF_INET6) {
1069     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1070
1071     /* do not reset prefixlength for ::ffff:0:0 HNAs */
1072     if (prefixlen == ipv6_internet_route.prefix_len) {
1073       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1074
1075       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1076           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1077         /* this is the right prefix (2000::/3), so we can copy the prefix */
1078         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1079         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1080       }
1081     }
1082   }
1083
1084   /* stop cleanup timer if necessary */
1085   if (gw->cleanup_timer) {
1086     olsr_stop_timer(gw->cleanup_timer);
1087     gw->cleanup_timer = NULL;
1088   }
1089
1090   assert(gw_handler);
1091   prev_path_cost = gw->path_cost;
1092   gw->path_cost = gw_handler->getcosts(gw);
1093
1094   if (prev_path_cost != gw->path_cost) {
1095     /* re-sort the gateway list when costs have changed and when it is an active gateway */
1096     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1097     if (new_gw_in_list) {
1098       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1099       assert(new_gw_in_list);
1100     }
1101
1102     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1103     if (new_gw_in_list) {
1104       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1105       assert(new_gw_in_list);
1106     }
1107
1108     if (multi_gateway_mode() && //
1109         ((!gw->ipv6 && current_ipv4_gw && current_ipv4_gw->gw == gw) || //
1110          (gw->ipv6 && current_ipv6_gw && current_ipv6_gw->gw == gw)) //
1111         ) {
1112       /* the active gw has changed its costs: re-evaluate egress routes */
1113       doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1114     }
1115   }
1116
1117   /* call update handler */
1118   assert(gw_handler);
1119   gw_handler->update(gw);
1120 }
1121
1122 /**
1123  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1124  * Should only be called if prefix is a smart_gw prefix or if node is removed
1125  * from TC set.
1126  *
1127  * @param originator
1128  * @param prefixlen
1129  * @param immediate when set to true then the gateway is removed from the
1130  * gateway tree immediately, else it is removed on a delayed schedule.
1131  */
1132 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1133   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1134 }
1135
1136 /**
1137  * Delete a gateway entry .
1138  *
1139  * @param gw a gateway entry from the gateway tree
1140  * @param prefixlen
1141  * @param immediate when set to true then the gateway is removed from the
1142  * gateway tree immediately, else it is removed on a delayed schedule.
1143  */
1144 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1145   bool change = false;
1146
1147   if (!gw) {
1148     return;
1149   }
1150
1151   if (immediate && gw->cleanup_timer) {
1152     /* stop timer if we have to remove immediately */
1153     olsr_stop_timer(gw->cleanup_timer);
1154     gw->cleanup_timer = NULL;
1155   }
1156
1157   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1158     /* the gw  is not scheduled for deletion */
1159
1160     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1161       change = gw->ipv4;
1162       gw->ipv4 = false;
1163       gw->ipv4nat = false;
1164     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1165       change = gw->ipv6;
1166       gw->ipv6 = false;
1167     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1168       change = gw->ipv4;
1169       gw->ipv4 = false;
1170       gw->ipv4nat = false;
1171     }
1172
1173     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1174       struct gw_container_entry * gw_in_list;
1175
1176       /* prevent this gateway from being chosen as the new gateway */
1177       gw->ipv4 = false;
1178       gw->ipv4nat = false;
1179       gw->ipv6 = false;
1180
1181       /* handle gateway loss */
1182       assert(gw_handler);
1183       gw_handler->delete(gw);
1184
1185       /* cleanup gateway if necessary */
1186       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1187       if (gw_in_list) {
1188         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1189           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1190           current_ipv4_gw = NULL;
1191         }
1192
1193         if (gw_in_list->tunnel) {
1194           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1195           if (ifn) {
1196             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1197           }
1198           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1199           set_unused_iptunnel_name(gw_in_list->gw);
1200           gw_in_list->tunnel = NULL;
1201         }
1202
1203         gw_in_list->gw = NULL;
1204         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1205         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1206       }
1207
1208       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1209       if (gw_in_list) {
1210         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1211           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1212           current_ipv6_gw = NULL;
1213         }
1214
1215         if (gw_in_list->tunnel) {
1216           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1217           if (ifn) {
1218             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1219           }
1220           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1221           set_unused_iptunnel_name(gw_in_list->gw);
1222           gw_in_list->tunnel = NULL;
1223         }
1224
1225         gw_in_list->gw = NULL;
1226         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1227         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1228       }
1229
1230       if (!immediate) {
1231         /* remove gateway entry on a delayed schedule */
1232         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1233       } else {
1234         cleanup_gateway_handler(gw);
1235       }
1236
1237       /* when the current gateway was deleted, then immediately choose a new gateway */
1238       if (!current_ipv4_gw || !current_ipv6_gw) {
1239         assert(gw_handler);
1240         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1241       }
1242
1243     } else if (change) {
1244       assert(gw_handler);
1245       gw_handler->update(gw);
1246     }
1247   }
1248 }
1249
1250 /**
1251  * Triggers a check if the one of the gateways have been lost or has an
1252  * ETX = infinity
1253  */
1254 void olsr_trigger_gatewayloss_check(void) {
1255   bool ipv4 = false;
1256   bool ipv6 = false;
1257
1258   if (current_ipv4_gw && current_ipv4_gw->gw) {
1259     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
1260     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1261   }
1262   if (current_ipv6_gw && current_ipv6_gw->gw) {
1263     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
1264     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1265   }
1266
1267   if (ipv4 || ipv6) {
1268     assert(gw_handler);
1269     gw_handler->choose(ipv4, ipv6);
1270   }
1271 }
1272
1273 /*
1274  * Gateway Plugin Functions
1275  */
1276
1277 /**
1278  * Sets a new internet gateway.
1279  *
1280  * @param the chosen gateway
1281  * @param ipv4 set ipv4 gateway
1282  * @param ipv6 set ipv6 gateway
1283  * @return true if an error happened, false otherwise
1284  */
1285 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1286   struct gateway_entry *new_gw;
1287
1288   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1289   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1290   if (!ipv4 && !ipv6) {
1291     return true;
1292   }
1293
1294   new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1295   if (!new_gw) {
1296     /* the originator is not in the gateway tree, we can't set it as gateway */
1297     return true;
1298   }
1299
1300   /* handle IPv4 */
1301   if (ipv4 &&
1302       new_gw->ipv4 &&
1303       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1304       (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1305     /* new gw is different than the current gw */
1306
1307     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1308     if (new_gw_in_list) {
1309       /* new gw is already in the gw list */
1310       assert(new_gw_in_list->tunnel);
1311       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1312       current_ipv4_gw = new_gw_in_list;
1313
1314       if (multi_gateway_mode()) {
1315         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1316       }
1317     } else {
1318       /* new gw is not yet in the gw list */
1319       char name[IFNAMSIZ];
1320       struct olsr_iptunnel_entry *new_v4gw_tunnel;
1321       struct interfaceName * interfaceName;
1322
1323       if (olsr_gw_list_full(&gw_list_ipv4)) {
1324         /* the list is full: remove the worst active gateway */
1325         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1326         assert(worst);
1327
1328         removeGatewayFromList(&gw_list_ipv4, true, worst);
1329       }
1330
1331       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1332       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1333       if (new_v4gw_tunnel) {
1334         if (interfaceName) {
1335           olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1336         }
1337         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1338
1339         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1340         new_gw_in_list->gw = new_gw;
1341         new_gw_in_list->tunnel = new_v4gw_tunnel;
1342         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1343
1344         if (multi_gateway_mode()) {
1345           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1346         }
1347       } else {
1348         /* adding the tunnel failed, we try again in the next cycle */
1349         set_unused_iptunnel_name(new_gw);
1350         ipv4 = false;
1351       }
1352     }
1353   }
1354
1355   /* handle IPv6 */
1356   if (ipv6 &&
1357       new_gw->ipv6 &&
1358       (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1359     /* new gw is different than the current gw */
1360
1361         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1362     if (new_gw_in_list) {
1363       /* new gw is already in the gw list */
1364       assert(new_gw_in_list->tunnel);
1365       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1366       current_ipv6_gw = new_gw_in_list;
1367
1368       if (multi_gateway_mode()) {
1369         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1370       }
1371     } else {
1372       /* new gw is not yet in the gw list */
1373       char name[IFNAMSIZ];
1374       struct olsr_iptunnel_entry *new_v6gw_tunnel;
1375       struct interfaceName * interfaceName;
1376
1377       if (olsr_gw_list_full(&gw_list_ipv6)) {
1378         /* the list is full: remove the worst active gateway */
1379         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1380         assert(worst);
1381
1382         removeGatewayFromList(&gw_list_ipv6, false, worst);
1383       }
1384
1385       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1386       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1387       if (new_v6gw_tunnel) {
1388         if (interfaceName) {
1389           olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1390         }
1391         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1392
1393         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1394         new_gw_in_list->gw = new_gw;
1395         new_gw_in_list->tunnel = new_v6gw_tunnel;
1396         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1397
1398         if (multi_gateway_mode()) {
1399           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1400         }
1401       } else {
1402         /* adding the tunnel failed, we try again in the next cycle */
1403         set_unused_iptunnel_name(new_gw);
1404         ipv6 = false;
1405       }
1406     }
1407   }
1408
1409   return !ipv4 && !ipv6;
1410 }
1411
1412 /**
1413  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1414  * gateway is returned
1415  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1416  * NULL if not set.
1417  */
1418 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1419         if (ipv6) {
1420                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1421         }
1422
1423         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1424 }
1425
1426 /*
1427  * Process Egress Changes
1428  */
1429
1430 #define MSGW_ROUTE_ADD_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1431 #define MSGW_ROUTE_ADD_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1432 #define MSGW_ROUTE_DEL_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1433 #define MSGW_ROUTE_DEL_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1434 #define MSGW_ROUTE_FORCED(phase)        ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1435
1436 /**
1437  * Determine best egress link.
1438  * The list of egress interface is ordered on priority (the declaration order),
1439  * so the function will - for multiple egress links with the same costs - set the
1440  * best egress interface to the first declared one of those.
1441  * When there is no best egress interface (that is up) then the function will
1442  * set the best egress interface to NULL.
1443  *
1444  * @param phase the phase of the change (startup/runtime/shutdown)
1445  * @return true when the best egress link changed or when any of its relevant
1446  * parameters has changed
1447  */
1448 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1449   struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1450
1451   if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1452     bestEgress = NULL;
1453   } else {
1454     struct sgw_egress_if * egress_if = bestEgress;
1455     if (egress_if) {
1456       egress_if = egress_if->next;
1457     }
1458     while (egress_if) {
1459       if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs)) {
1460         bestEgress = egress_if;
1461       }
1462
1463       egress_if = egress_if->next;
1464     }
1465
1466     if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1467       bestEgress = NULL;
1468     }
1469   }
1470
1471   bestEgressLinkPrevious = bestEgressLink;
1472   bestEgressLink = bestEgress;
1473
1474   return ((bestEgressLinkPrevious != bestEgressLink) || //
1475       (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged)));
1476 }
1477
1478 /**
1479  * Process changes that are relevant to egress interface: changes to the
1480  * egress interfaces themselves and to the smart gateway that is chosen by olsrd
1481  *
1482  * @param egressChanged true when an egress interface changed
1483  * @param olsrChanged true when the smart gateway changed
1484  * @param phase the phase of the change (startup/runtime/shutdown)
1485  */
1486 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
1487   bool bestEgressChanged = false;
1488   bool bestOverallChanged = false;
1489   bool force = MSGW_ROUTE_FORCED(phase);
1490
1491   assert( //
1492       (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
1493       (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
1494       (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
1495
1496   if (!egressChanged && !olsrChanged && !force) {
1497     goto out;
1498   }
1499
1500   assert(multi_gateway_mode());
1501
1502   if (egressChanged || force) {
1503     bestEgressChanged = determineBestEgressLink(phase);
1504   }
1505
1506   // FIXME determine best overall link
1507
1508   if (!bestEgressChanged && !bestOverallChanged && !force) {
1509     goto out;
1510   }
1511
1512   // FIXME program routes
1513
1514   out: if (egressChanged) {
1515     /* clear the 'changed' flags of egress interfaces */
1516     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1517     while (egress_if) {
1518       egress_if->upChanged = false;
1519
1520       egress_if->bwCostsChanged = false;
1521       egress_if->bwNetworkChanged = false;
1522       egress_if->bwGatewayChanged = false;
1523       egress_if->bwChanged = false;
1524
1525       egress_if = egress_if->next;
1526     }
1527   }
1528 }
1529
1530 #endif /* __linux__ */