sgw: implement HNA expiry
[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 <linux/rtnetlink.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 /* ipv4 prefix 0.0.0.0/0 */
42 static struct olsr_ip_prefix ipv4_slash_0_route;
43
44 /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
45 static struct olsr_ip_prefix ipv4_slash_1_routes[2];
46
47 /** the gateway tree */
48 struct avl_tree gateway_tree;
49
50 /** gateway cookie */
51 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
52
53 /** gateway container cookie */
54 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
55
56 /** the gateway netmask for the HNA with zero bandwidth */
57 static uint8_t smart_gateway_netmask_zero[sizeof(union olsr_ip_addr)];
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 struct BestOverallLink {
87   bool valid;
88   bool isOlsr;
89   union {
90     struct sgw_egress_if * egress;
91     struct gateway_entry * olsr;
92   } link;
93   int olsrTunnelIfIndex;
94 };
95
96 static struct sgw_egress_if * bestEgressLinkPrevious = NULL;
97 static struct sgw_egress_if * bestEgressLink = NULL;
98
99 struct sgw_route_info bestEgressLinkPreviousRoute;
100 struct sgw_route_info bestEgressLinkRoute;
101
102 struct sgw_route_info bestOverallLinkPreviousRoutes[2];
103 struct sgw_route_info bestOverallLinkRoutes[2];
104
105 static struct BestOverallLink bestOverallLinkPrevious;
106 static struct BestOverallLink bestOverallLink;
107
108 /*
109  * Forward Declarations
110  */
111
112 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
113
114 /*
115  * Helper Functions
116  */
117
118 /**
119  * @return the gateway 'server' tunnel name to use
120  */
121 static inline const char * server_tunnel_name(void) {
122   return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
123 }
124
125 /**
126  * Convert the netmask of the HNA (in the form of an IP address) to a HNA
127  * pointer.
128  *
129  * @param mask the netmask of the HNA (in the form of an IP address)
130  * @param prefixlen the prefix length
131  * @return a pointer to the HNA
132  */
133 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
134   return (((uint8_t *)mask) + ((prefixlen+7)/8));
135 }
136
137 /**
138  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
139  * to an uplink/downlink speed value
140  *
141  * @param value the encoded 1 byte transport value
142  * @return the uplink/downlink speed value (in kbit/s)
143  */
144 static uint32_t deserialize_gw_speed(uint8_t value) {
145   uint32_t speed;
146   uint32_t exp;
147
148   if (!value) {
149     return 0;
150   }
151
152   if (value == UINT8_MAX) {
153     /* maximum value: also return maximum value */
154     return MAX_SMARTGW_SPEED;
155   }
156
157   speed = (value >> 3) + 1;
158   exp = value & 7;
159
160   while (exp-- > 0) {
161     speed *= 10;
162   }
163   return speed;
164 }
165
166 /**
167  * Convert an uplink/downlink speed value into an encoded 1 byte transport
168  * value (5 bits mantissa, 3 bits exponent)
169  *
170  * A bandwidth of 1 will alias onto a bandwidth of 2.
171  *
172  * @param speed the uplink/downlink speed value (in kbit/s)
173  * @return value the encoded 1 byte transport value
174  */
175 static uint8_t serialize_gw_speed(uint32_t speed) {
176   uint8_t exp = 0;
177
178   if (speed == 0) {
179     return 0;
180   }
181
182   if (speed == 1) {
183     speed++;
184   }
185
186   if (speed >= MAX_SMARTGW_SPEED) {
187     return UINT8_MAX;
188   }
189
190   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
191     speed /= 10;
192     exp++;
193   }
194   return ((speed - 1) << 3) | exp;
195 }
196
197 /**
198  * Find an interfaceName struct corresponding to a certain gateway
199  * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
200  *
201  * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
202  * @return a pointer to the struct, or NULL when not found
203  */
204 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
205   struct interfaceName * sgwTunnelInterfaceNames;
206   uint8_t i = 0;
207
208   if (!multi_gateway_mode()) {
209     return NULL;
210   }
211
212   assert(sgwTunnel4InterfaceNames);
213   assert(sgwTunnel6InterfaceNames);
214
215   sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
216   while (i < olsr_cnf->smart_gw_use_count) {
217     struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
218     if (ifn->gw == gw) {
219       return ifn;
220     }
221     i++;
222   }
223
224   return NULL;
225 }
226
227 /**
228  * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
229  *
230  * @param gw pointer to the gateway
231  * @param name pointer to output buffer (length IFNAMSIZ)
232  * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
233  */
234 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
235   static uint32_t counter = 0;
236
237   assert(gw);
238   assert(name);
239   assert(interfaceName);
240
241   memset(name, 0, IFNAMSIZ);
242
243   if (multi_gateway_mode()) {
244     struct interfaceName * ifn = find_interfaceName(NULL);
245
246     if (ifn) {
247       strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
248       *interfaceName = ifn;
249       ifn->gw = gw;
250       return;
251     }
252
253     /* do not return, fall-through to classic naming as fallback */
254   }
255
256   snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
257   *interfaceName = NULL;
258 }
259
260 /**
261  * Set an olsr ipip tunnel name that is used by a certain gateway as unused
262  *
263  * @param gw pointer to the gateway
264  */
265 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
266   struct interfaceName * ifn;
267
268   if (!multi_gateway_mode()) {
269     return;
270   }
271
272   assert(gw);
273
274   ifn = find_interfaceName(gw);
275   if (ifn) {
276     ifn->gw = NULL;
277     return;
278   }
279 }
280
281 /**
282  * Run the multi-gateway script/
283  *
284  * @param mode the mode (see SCRIPT_MODE_* defines)
285  * @param addMode true to add policy routing, false to remove it
286  * @param ifname the interface name (optional)
287  * @param tableNr the routing table number (optional)
288  * @param ruleNr the IP rule number/priority (optional)
289  * @param bypassRuleNr the bypass IP rule number/priority (optional)
290  * @return true when successful
291  */
292 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
293   struct autobuf buf;
294   int r;
295
296   assert(!strcmp(mode, SCRIPT_MODE_GENERIC) //
297       || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
298       || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
299       || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
300       || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
301       );
302
303   assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
304       || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
305
306   assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
307       || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
308
309   assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
310       || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
311
312   assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
313       || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
314
315   assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
316       || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
317
318   abuf_init(&buf, 1024);
319
320   abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
321
322   abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
323
324   abuf_appendf(&buf, " \"%s\"", mode);
325
326   abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
327
328   if (ifName) {
329     abuf_appendf(&buf, " \"%s\"", ifName);
330   }
331
332   if (tableNr) {
333     abuf_appendf(&buf, " \"%u\"", tableNr);
334   }
335
336   if (ruleNr) {
337     abuf_appendf(&buf, " \"%u\"", ruleNr);
338   }
339
340   if (bypassRuleNr) {
341     abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
342   }
343
344   r = system(buf.buf);
345
346   abuf_free(&buf);
347
348   return (r == 0);
349 }
350
351 /**
352  * Setup generic multi-gateway iptables and ip rules
353  *
354  * @param add true to add policy routing, false to remove it
355  * @return true when successful
356  */
357 static bool multiGwRulesGeneric(bool add) {
358   return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
359 }
360
361 /**
362  * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
363  *
364  * @param add true to add policy routing, false to remove it
365  * @return true when successful
366  */
367 static bool multiGwRulesOlsrInterfaces(bool add) {
368   bool ok = true;
369   struct olsr_if * ifn;
370   unsigned int i = 0;
371
372   for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
373     if (!multiGwRunScript( //
374         SCRIPT_MODE_OLSRIF,//
375         add, //
376         ifn->name, //
377         0, //
378         0, //
379         olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
380             )) {
381       ok = false;
382       if (add) {
383         return ok;
384       }
385     }
386   }
387
388   return ok;
389 }
390
391 /**
392  * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
393  *
394  * @param add true to add policy routing, false to remove it
395  * @return true when successful
396  */
397 static bool multiGwRulesSgwServerTunnel(bool add) {
398   return multiGwRunScript( //
399       SCRIPT_MODE_SGWSRVTUN,//
400       add, //
401       server_tunnel_name(), //
402       olsr_cnf->smart_gw_offset_tables, //
403       olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
404       0 //
405       );
406 }
407
408 /**
409  * Setup multi-gateway iptables and ip rules for all egress interfaces.
410  *
411  * @param add true to add policy routing, false to remove it
412  * @return true when successful
413  */
414 static bool multiGwRulesEgressInterfaces(bool add) {
415   bool ok = true;
416
417   struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
418   while (egress_if) {
419     if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
420       ok = false;
421       if (add) {
422         return ok;
423       }
424     }
425
426     egress_if = egress_if->next;
427   }
428
429   return ok;
430 }
431
432 /**
433  * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
434  *
435  * @param add true to add policy routing, false to remove it
436  * @return true when successful
437  */
438 static bool multiGwRulesSgwTunnels(bool add) {
439   bool ok = true;
440   unsigned int i = 0;
441
442   while (i < olsr_cnf->smart_gw_use_count) {
443     struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
444     if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
445       ok = false;
446       if (add) {
447         return ok;
448       }
449     }
450
451     i++;
452   }
453
454   return ok;
455 }
456
457 /**
458  * Process interface up/down events for non-olsr interfaces, which are egress
459  * interfaces
460  *
461  * @param if_index the index of the interface
462  * @param flag the up/down event
463  */
464 static void doEgressInterface(int if_index, enum olsr_ifchg_flag flag) {
465   switch (flag) {
466     case IFCHG_IF_ADD: {
467       char ifname[IF_NAMESIZE];
468       struct sgw_egress_if * egress_if;
469
470       /*
471        * we need to get the name of the interface first because the interface
472        * might be hot-plugged _after_ olsrd has started
473        */
474       if (!if_indextoname(if_index, ifname)) {
475         /* not a known OS interface */
476         return;
477       }
478
479       egress_if = findEgressInterface(ifname);
480       if (!egress_if) {
481         /* not a known egress interface */
482         return;
483       }
484
485       egress_if->if_index = if_index;
486
487       if (egress_if->upCurrent) {
488         /* interface is already up: no change */
489         return;
490       }
491
492       egress_if->upPrevious = egress_if->upCurrent;
493       egress_if->upCurrent = true;
494       egress_if->upChanged = true;
495
496       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
497     }
498       break;
499
500     case IFCHG_IF_REMOVE: {
501       /*
502        * we need to find the egress interface by if_index because we might
503        * be too late; the kernel could already have removed the interface
504        * in which case we'd get a NULL ifname here if we'd try to call
505        * if_indextoname
506        */
507       struct sgw_egress_if * egress_if = findEgressInterfaceByIndex(if_index);
508       if (!egress_if) {
509         /* not a known egress interface */
510         return;
511       }
512
513       if (!egress_if->upCurrent) {
514         /* interface is already down: no change */
515         return;
516       }
517
518       egress_if->upPrevious = egress_if->upCurrent;
519       egress_if->upCurrent = false;
520       egress_if->upChanged = true;
521
522       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
523     }
524       break;
525
526     case IFCHG_IF_UPDATE:
527     default:
528       return;
529   }
530
531   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_RUNTIME);
532 }
533
534 /*
535  * Callback Functions
536  */
537
538 /**
539  * Callback for tunnel interface monitoring which will set the route into the tunnel
540  * when the interface comes up again.
541  *
542  * @param if_index the interface index
543  * @param ifh the interface (NULL when not an olsr interface)
544  * @param flag interface change flags
545  */
546 static void smartgw_tunnel_monitor(int if_index, struct interface_olsr *ifh, enum olsr_ifchg_flag flag) {
547   if (!ifh && multi_gateway_mode()) {
548     /* non-olsr interface in multi-sgw mode */
549     doEgressInterface(if_index, flag);
550   }
551
552   return;
553 }
554
555 /**
556  * Timer callback to expire a gateway entry
557  *
558  * @param ptr a pointer to the smart gateway HNA to expire (struct gateway_entry*)
559  */
560 static void expire_gateway_handler(void *ptr) {
561   struct gateway_entry *gw = ptr;
562
563   assert(gw);
564
565   /* remove gateway entry */
566   olsr_delete_gateway_entry(&gw->originator, gw->external_prefix.prefix_len, false);
567 }
568
569 /**
570  * Timer callback to remove and cleanup a gateway entry
571  *
572  * @param ptr
573  */
574 static void cleanup_gateway_handler(void *ptr) {
575   struct gateway_entry *gw = ptr;
576
577   if (gw->ipv4 || gw->ipv6) {
578     /* do not clean it up when it is in use */
579     return;
580   }
581
582   /* remove gateway entry */
583   avl_delete(&gateway_tree, &gw->node);
584   olsr_cookie_free(gateway_entry_mem_cookie, gw);
585 }
586
587 /**
588  * Remove a gateway from a gateway list.
589  *
590  * @param gw_list a pointer to the gateway list
591  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
592  * @param gw a pointer to the gateway to remove from the list
593  */
594 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
595   if (gw->tunnel) {
596     struct interfaceName * ifn = find_interfaceName(gw->gw);
597     if (ifn) {
598       olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
599     }
600     olsr_os_del_ipip_tunnel(gw->tunnel);
601     set_unused_iptunnel_name(gw->gw);
602     gw->tunnel = NULL;
603   }
604   gw->gw = NULL;
605   olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
606 }
607
608 /**
609  * Remove expensive gateways from the gateway list.
610  * It uses the smart_gw_takedown_percentage configuration parameter
611  *
612  * @param gw_list a pointer to the gateway list
613  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
614  * @param current_gw the current gateway
615  */
616 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
617   int64_t current_gw_cost_boundary;
618
619   /*
620    * exit immediately when takedown is disabled, there is no current gateway, or
621    * when there is only a single gateway
622    */
623   if ((olsr_cnf->smart_gw_takedown_percentage == 0) || !current_gw || (gw_list->count <= 1)) {
624     return;
625   }
626
627   /* get the cost boundary */
628   current_gw_cost_boundary = current_gw->gw->path_cost;
629   if (olsr_cnf->smart_gw_takedown_percentage < 100) {
630     if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
631       current_gw_cost_boundary =  ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
632     } else {
633       /* perform scaling because otherwise the percentage calculation can overflow */
634       current_gw_cost_boundary = (((current_gw_cost_boundary      ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
635     }
636   }
637
638   /* loop while we still have gateways */
639   while (gw_list->count > 1) {
640     /* get the worst gateway */
641     struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
642
643     /* exit when it's the current gateway */
644     if (worst_gw == current_gw) {
645       return;
646     }
647
648     /*
649      * exit when it (and further ones; the list is sorted on costs) has lower
650      * costs than the boundary costs
651      */
652     if (worst_gw->gw->path_cost < current_gw_cost_boundary) {
653       return;
654     }
655
656     /* it's too expensive: take it down */
657     removeGatewayFromList(gw_list, ipv4, worst_gw);
658   }
659 }
660
661 /**
662  * Timer callback for proactive gateway takedown
663  *
664  * @param unused unused
665  */
666 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
667   takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
668   takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
669 }
670
671 /*
672  * Main Interface
673  */
674
675 /**
676  * Initialize gateway system
677  */
678 int olsr_init_gateways(void) {
679   int retries = 5;
680
681   memset(&bestEgressLinkPreviousRoute, 0, sizeof(bestEgressLinkPreviousRoute));
682   memset(&bestEgressLinkRoute, 0, sizeof(bestEgressLinkRoute));
683   memset(bestOverallLinkPreviousRoutes, 0, sizeof(bestOverallLinkPreviousRoutes));
684   memset(bestOverallLinkRoutes, 0, sizeof(bestOverallLinkRoutes));
685
686   /* ipv4 prefix 0.0.0.0/0 */
687   memset(&ipv4_slash_0_route, 0, sizeof(ipv4_slash_0_route));
688
689   /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
690   memset(&ipv4_slash_1_routes, 0, sizeof(ipv4_slash_1_routes));
691   ipv4_slash_1_routes[0].prefix.v4.s_addr = htonl(0x00000000);
692   ipv4_slash_1_routes[0].prefix_len = 1;
693   ipv4_slash_1_routes[1].prefix.v4.s_addr = htonl(0x80000000);
694   ipv4_slash_1_routes[1].prefix_len = 1;
695
696   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
697   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
698
699   gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
700   olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
701
702   avl_init(&gateway_tree, avl_comp_default);
703
704   olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
705   olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
706
707   sgwTunnel4InterfaceNames = NULL;
708   sgwTunnel6InterfaceNames = NULL;
709   memset(&bestOverallLinkPrevious, 0, sizeof(bestOverallLinkPrevious));
710   memset(&bestOverallLink, 0, sizeof(bestOverallLink));
711
712   if (multi_gateway_mode()) {
713     uint8_t i;
714     struct sgw_egress_if * egressif;
715     unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
716
717     /* Initialise the egress interfaces */
718     /* setup the egress interface name/mark pairs */
719     i = 0;
720     egressif = olsr_cnf->smart_gw_egress_interfaces;
721     while (egressif) {
722       egressif->if_index = if_nametoindex(egressif->name);
723
724       egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
725       egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
726       egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
727
728       egressif->upPrevious = egressif->upCurrent = olsr_if_isup(egressif->name);
729       egressif->upChanged = (egressif->upPrevious != egressif->upCurrent);
730
731       egressBwClear(&egressif->bwPrevious, egressif->upPrevious);
732       egressBwClear(&egressif->bwCurrent, egressif->upCurrent);
733       egressif->bwCostsChanged = egressBwCostsChanged(egressif);
734       egressif->bwNetworkChanged = egressBwNetworkChanged(egressif);
735       egressif->bwGatewayChanged = egressBwGatewayChanged(egressif);
736       egressif->bwChanged = egressBwChanged(egressif);
737
738       egressif->inEgressFile = false;
739
740       egressif = egressif->next;
741       i++;
742     }
743     assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
744
745     /* setup the SGW tunnel name/mark pairs */
746     sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
747     sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
748     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
749       struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
750       uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
751       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;
752
753       ifn->gw = NULL;
754       ifn->tableNr = tableNr;
755       ifn->ruleNr = ruleNr;
756       ifn->bypassRuleNr = 0;
757       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
758
759       ifn = &sgwTunnel6InterfaceNames[i];
760       ifn->gw = NULL;
761       ifn->tableNr = tableNr;
762       ifn->ruleNr = ruleNr;
763       ifn->bypassRuleNr = 0;
764       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
765     }
766   }
767
768   current_ipv4_gw = NULL;
769   current_ipv6_gw = NULL;
770
771   gw_handler = NULL;
772
773   refresh_smartgw_netmask();
774
775   /* initialize default gateway handler */
776   gw_handler = &gw_def_handler;
777   gw_handler->init();
778
779
780   /*
781    * There appears to be a kernel bug in some kernels (at least in the 3.0
782    * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
783    * initialising the IPIP server tunnel (loading the IPIP module), so we retry
784    * a few times before giving up
785    */
786   while (retries-- > 0) {
787     if (!olsr_os_init_iptunnel(server_tunnel_name())) {
788       retries = 5;
789       break;
790     }
791
792     olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
793   }
794   if (retries <= 0) {
795     return 1;
796   }
797
798   return 0;
799 }
800
801 /**
802  * Startup gateway system
803  */
804 int olsr_startup_gateways(void) {
805   bool ok = true;
806
807   if (!multi_gateway_mode()) {
808     olsr_add_ifchange_handler(smartgw_tunnel_monitor);
809     return 0;
810   }
811
812   ok = ok && multiGwRulesGeneric(true);
813   ok = ok && multiGwRulesSgwServerTunnel(true);
814   ok = ok && multiGwRulesOlsrInterfaces(true);
815   ok = ok && multiGwRulesEgressInterfaces(true);
816   ok = ok && multiGwRulesSgwTunnels(true);
817   if (!ok) {
818     olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
819     olsr_shutdown_gateways();
820     return 1;
821   }
822
823   startEgressFile();
824   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
825
826   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
827
828   /* Check egress interfaces up status to compensate for a race: the interfaces
829    * can change status between initialising their data structures and
830    * registering the tunnel monitor */
831   {
832     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
833     while (egress_if) {
834       bool upCurrent = olsr_if_isup(egress_if->name);
835
836       if (upCurrent != egress_if->upCurrent) {
837         int idx = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
838         enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
839         smartgw_tunnel_monitor(idx, NULL, flag);
840       }
841
842       egress_if = egress_if->next;
843     }
844   }
845
846   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
847     /* start gateway takedown timer */
848     olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
849   }
850
851   return 0;
852 }
853
854 /**
855  * Shutdown gateway tunnel system
856  */
857 void olsr_shutdown_gateways(void) {
858   if (!multi_gateway_mode()) {
859     olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
860     return;
861   }
862
863   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
864     /* stop gateway takedown timer */
865     olsr_stop_timer(gw_takedown_timer);
866     gw_takedown_timer = NULL;
867   }
868
869   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
870
871   stopEgressFile();
872   {
873     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
874     while (egress_if) {
875       egress_if->upPrevious = egress_if->upCurrent;
876       egress_if->upCurrent = false;
877       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
878
879       egress_if->bwPrevious = egress_if->bwCurrent;
880       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
881       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
882       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
883       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
884       egress_if->bwChanged = egressBwChanged(egress_if);
885
886       egress_if->inEgressFile = false;
887
888       egress_if = egress_if->next;
889     }
890   }
891   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
892
893   (void)multiGwRulesSgwTunnels(false);
894   (void)multiGwRulesEgressInterfaces(false);
895   (void)multiGwRulesOlsrInterfaces(false);
896   (void)multiGwRulesSgwServerTunnel(false);
897   (void)multiGwRulesGeneric(false);
898 }
899
900 /**
901  * Cleanup gateway tunnel system
902  */
903 void olsr_cleanup_gateways(void) {
904   struct gateway_entry * tree_gw;
905   struct gw_container_entry * gw;
906
907   /* remove all gateways in the gateway tree that are not the active gateway */
908   OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
909     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
910       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
911     }
912   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
913
914   /* remove all active IPv4 gateways (should be at most 1 now) */
915   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
916     if (gw && gw->gw) {
917       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
918     }
919   }
920   OLSR_FOR_ALL_GWS_END(gw);
921
922   /* remove all active IPv6 gateways (should be at most 1 now) */
923   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
924     if (gw && gw->gw) {
925       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
926     }
927   }
928   OLSR_FOR_ALL_GWS_END(gw);
929
930   /* there should be no more gateways */
931   assert(!avl_walk_first(&gateway_tree));
932   assert(!current_ipv4_gw);
933   assert(!current_ipv6_gw);
934
935   olsr_os_cleanup_iptunnel(server_tunnel_name());
936
937   assert(gw_handler);
938   gw_handler->cleanup();
939   gw_handler = NULL;
940
941   if (sgwTunnel4InterfaceNames) {
942     free(sgwTunnel4InterfaceNames);
943     sgwTunnel4InterfaceNames = NULL;
944   }
945   if (sgwTunnel6InterfaceNames) {
946     free(sgwTunnel6InterfaceNames);
947     sgwTunnel6InterfaceNames = NULL;
948   }
949
950   olsr_gw_list_cleanup(&gw_list_ipv6);
951   olsr_gw_list_cleanup(&gw_list_ipv4);
952   olsr_free_cookie(gw_container_entry_mem_cookie);
953   olsr_free_cookie(gateway_entry_mem_cookie);
954 }
955
956 /**
957  * Triggers the first lookup of a gateway.
958  */
959 void olsr_trigger_inetgw_startup(void) {
960   assert(gw_handler);
961   gw_handler->startup();
962 }
963
964 /**
965  * Print debug information about gateway entries
966  */
967 #ifndef NODEBUG
968 void olsr_print_gateway_entries(void) {
969   struct ipaddr_str buf;
970   struct gateway_entry *gw;
971   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
972
973   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
974   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
975       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
976
977   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
978     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
979         addrsize,
980         olsr_ip_to_string(&buf, &gw->originator),
981         gw->ipv4nat ? "" : "   ",
982         gw->ipv4 ? '4' : ' ',
983         gw->ipv4nat ? "(N)" : "",
984         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
985         gw->ipv6 ? '6' : ' ',
986         gw->uplink,
987         gw->downlink,
988         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
989   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
990 }
991 #endif /* NODEBUG */
992
993 /*
994  * Tx Path Interface
995  */
996
997 /**
998  * Apply the smart gateway modifications to an outgoing HNA
999  *
1000  * @param mask pointer to netmask of the HNA
1001  * @param prefixlen of the HNA
1002  * @param zero true to use zero bandwidth
1003  */
1004 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen, bool zero) {
1005   uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1006
1007   /* copy the current settings for uplink/downlink into the mask */
1008   memcpy( //
1009       ptr, //
1010       zero ? &smart_gateway_netmask_zero : &smart_gateway_netmask, //
1011       (zero ? sizeof(smart_gateway_netmask_zero) : sizeof(smart_gateway_netmask)) - prefixlen / 8);
1012   if (olsr_cnf->has_ipv4_gateway) {
1013     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
1014
1015     if (olsr_cnf->smart_gw_uplink_nat) {
1016       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
1017     }
1018   }
1019   if (olsr_cnf->has_ipv6_gateway) {
1020     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
1021   }
1022   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
1023     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
1024   }
1025 }
1026
1027 /*
1028  * SgwDynSpeed Plugin Interface
1029  */
1030
1031 /**
1032  * Setup the gateway netmask
1033  */
1034 void refresh_smartgw_netmask(void) {
1035   uint8_t *ip;
1036
1037   /* clear the mask */
1038   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
1039
1040   if (olsr_cnf->smart_gw_active) {
1041     ip = (uint8_t *) &smart_gateway_netmask;
1042
1043     ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
1044     ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
1045     ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
1046
1047     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
1048       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
1049       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1050       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1051     }
1052
1053     {
1054       uint8_t *ipz = (uint8_t *) &smart_gateway_netmask_zero;
1055       memcpy(ipz, ip, sizeof(smart_gateway_netmask_zero));
1056       ipz[GW_HNA_DOWNLINK] = serialize_gw_speed(0);
1057       ipz[GW_HNA_UPLINK] = serialize_gw_speed(0);
1058     }
1059   }
1060 }
1061
1062 /*
1063  * TC/SPF/HNA Interface
1064  */
1065
1066 /**
1067  * Checks if a HNA prefix/netmask combination is a smart gateway
1068  *
1069  * @param prefix
1070  * @param mask
1071  * @return true if is a valid smart gateway HNA, false otherwise
1072  */
1073 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1074   uint8_t *ptr;
1075
1076   if (!is_prefix_inetgw(prefix)) {
1077     return false;
1078   }
1079
1080   ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1081   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1082 }
1083
1084 /**
1085  * Update a gateway_entry based on a HNA
1086  *
1087  * @param originator ip of the source of the HNA
1088  * @param mask netmask of the HNA
1089  * @param prefixlen of the HNA
1090  * @param seqno the sequence number of the HNA
1091  * @param vtime the validity time of the HNA
1092  */
1093 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno, olsr_reltime vtime) {
1094   struct gw_container_entry * new_gw_in_list;
1095   uint8_t *ptr;
1096   int64_t prev_path_cost = 0;
1097   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1098
1099   if (!gw) {
1100     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1101     gw->originator = *originator;
1102     gw->node.key = &gw->originator;
1103
1104     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1105   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1106     /* ignore older HNAs */
1107     return;
1108   }
1109
1110   /* keep new HNA seqno */
1111   gw->seqno = seqno;
1112
1113   ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1114   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1115     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1116     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1117   } else {
1118     gw->uplink = 0;
1119     gw->downlink = 0;
1120   }
1121
1122   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1123   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1124   gw->ipv6 = false;
1125
1126   if (olsr_cnf->ip_version == AF_INET6) {
1127     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1128
1129     /* do not reset prefixlength for ::ffff:0:0 HNAs */
1130     if (prefixlen == ipv6_internet_route.prefix_len) {
1131       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1132
1133       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1134           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1135         /* this is the right prefix (2000::/3), so we can copy the prefix */
1136         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1137         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1138       }
1139     }
1140   }
1141
1142   if (!gw->expire_timer) {
1143     /* start expire timer */
1144     olsr_set_timer(&gw->expire_timer, vtime, 0, false, expire_gateway_handler, gw, NULL);
1145   } else {
1146     /* restart expire timer */
1147     olsr_change_timer(gw->expire_timer, vtime, 0, false);
1148   }
1149
1150   /* stop cleanup timer if necessary */
1151   if (gw->cleanup_timer) {
1152     olsr_stop_timer(gw->cleanup_timer);
1153     gw->cleanup_timer = NULL;
1154   }
1155
1156   assert(gw_handler);
1157   prev_path_cost = gw->path_cost;
1158   gw->path_cost = gw_handler->getcosts(gw);
1159
1160   if (prev_path_cost != gw->path_cost) {
1161     /* re-sort the gateway list when costs have changed and when it is an active gateway */
1162     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1163     if (new_gw_in_list) {
1164       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1165       assert(new_gw_in_list);
1166
1167       if (multi_gateway_mode() && new_gw_in_list->tunnel) {
1168         /* the active gateway has changed its costs: re-evaluate egress routes */
1169         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1170       }
1171     }
1172
1173     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1174     if (new_gw_in_list) {
1175       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1176       assert(new_gw_in_list);
1177
1178       if (multi_gateway_mode() && new_gw_in_list->tunnel) {
1179         /* the active gateway has changed its costs: re-evaluate egress routes */
1180         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1181       }
1182     }
1183   }
1184
1185   /* call update handler */
1186   assert(gw_handler);
1187   gw_handler->update(gw);
1188 }
1189
1190 /**
1191  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1192  * Should only be called if prefix is a smart_gw prefix or if node is removed
1193  * from TC set.
1194  *
1195  * @param originator
1196  * @param prefixlen
1197  * @param immediate when set to true then the gateway is removed from the
1198  * gateway tree immediately, else it is removed on a delayed schedule.
1199  */
1200 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1201   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1202 }
1203
1204 /**
1205  * Delete a gateway entry .
1206  *
1207  * @param gw a gateway entry from the gateway tree
1208  * @param prefixlen
1209  * @param immediate when set to true then the gateway is removed from the
1210  * gateway tree immediately, else it is removed on a delayed schedule.
1211  */
1212 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1213   bool change = false;
1214
1215   if (!gw) {
1216     return;
1217   }
1218
1219   if (gw->expire_timer) {
1220     /* stop expire timer */
1221     olsr_stop_timer(gw->expire_timer);
1222     gw->expire_timer = NULL;
1223   }
1224
1225   if (immediate && gw->cleanup_timer) {
1226     /* stop timer if we have to remove immediately */
1227     olsr_stop_timer(gw->cleanup_timer);
1228     gw->cleanup_timer = NULL;
1229   }
1230
1231   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1232     /* the gw  is not scheduled for deletion */
1233
1234     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1235       change = gw->ipv4;
1236       gw->ipv4 = false;
1237       gw->ipv4nat = false;
1238     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1239       change = gw->ipv6;
1240       gw->ipv6 = false;
1241     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1242       change = gw->ipv4;
1243       gw->ipv4 = false;
1244       gw->ipv4nat = false;
1245     }
1246
1247     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1248       struct gw_container_entry * gw_in_list;
1249
1250       /* prevent this gateway from being chosen as the new gateway */
1251       gw->ipv4 = false;
1252       gw->ipv4nat = false;
1253       gw->ipv6 = false;
1254
1255       /* handle gateway loss */
1256       assert(gw_handler);
1257       gw_handler->delete(gw);
1258
1259       /* cleanup gateway if necessary */
1260       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1261       if (gw_in_list) {
1262         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1263           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1264           current_ipv4_gw = NULL;
1265         }
1266
1267         if (gw_in_list->tunnel) {
1268           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1269           if (ifn) {
1270             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1271           }
1272           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1273           set_unused_iptunnel_name(gw_in_list->gw);
1274           gw_in_list->tunnel = NULL;
1275         }
1276
1277         gw_in_list->gw = NULL;
1278         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1279         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1280       }
1281
1282       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1283       if (gw_in_list) {
1284         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1285           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1286           current_ipv6_gw = NULL;
1287         }
1288
1289         if (gw_in_list->tunnel) {
1290           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1291           if (ifn) {
1292             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1293           }
1294           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1295           set_unused_iptunnel_name(gw_in_list->gw);
1296           gw_in_list->tunnel = NULL;
1297         }
1298
1299         gw_in_list->gw = NULL;
1300         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1301         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1302       }
1303
1304       if (!immediate) {
1305         /* remove gateway entry on a delayed schedule */
1306         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1307       } else {
1308         cleanup_gateway_handler(gw);
1309       }
1310
1311       /* when the current gateway was deleted, then immediately choose a new gateway */
1312       if (!current_ipv4_gw || !current_ipv6_gw) {
1313         assert(gw_handler);
1314         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1315       }
1316
1317     } else if (change) {
1318       assert(gw_handler);
1319       gw_handler->update(gw);
1320     }
1321   }
1322 }
1323
1324 /**
1325  * Triggers a check if the one of the gateways have been lost or has an
1326  * ETX = infinity
1327  */
1328 void olsr_trigger_gatewayloss_check(void) {
1329   bool ipv4 = false;
1330   bool ipv6 = false;
1331
1332   if (current_ipv4_gw && current_ipv4_gw->gw) {
1333     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
1334     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1335   }
1336   if (current_ipv6_gw && current_ipv6_gw->gw) {
1337     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
1338     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1339   }
1340
1341   if (ipv4 || ipv6) {
1342     assert(gw_handler);
1343     gw_handler->choose(ipv4, ipv6);
1344   }
1345 }
1346
1347 /*
1348  * Gateway Plugin Functions
1349  */
1350
1351 /**
1352  * Sets a new internet gateway.
1353  *
1354  * @param the chosen gateway
1355  * @param ipv4 set ipv4 gateway
1356  * @param ipv6 set ipv6 gateway
1357  * @return true if an error happened, false otherwise
1358  */
1359 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1360   struct gateway_entry *new_gw;
1361
1362   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1363   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1364   if (!ipv4 && !ipv6) {
1365     return true;
1366   }
1367
1368   new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1369   if (!new_gw) {
1370     /* the originator is not in the gateway tree, we can't set it as gateway */
1371     return true;
1372   }
1373
1374   /* handle IPv4 */
1375   if (ipv4 &&
1376       new_gw->ipv4 &&
1377       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1378       (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1379     /* new gw is different than the current gw */
1380
1381     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1382     if (new_gw_in_list) {
1383       /* new gw is already in the gw list */
1384       assert(new_gw_in_list->tunnel);
1385       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1386       current_ipv4_gw = new_gw_in_list;
1387
1388       if (multi_gateway_mode()) {
1389         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1390       }
1391     } else {
1392       /* new gw is not yet in the gw list */
1393       char name[IFNAMSIZ];
1394       struct olsr_iptunnel_entry *new_v4gw_tunnel;
1395       struct interfaceName * interfaceName;
1396
1397       if (olsr_gw_list_full(&gw_list_ipv4)) {
1398         /* the list is full: remove the worst active gateway */
1399         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1400         assert(worst);
1401
1402         removeGatewayFromList(&gw_list_ipv4, true, worst);
1403       }
1404
1405       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1406       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1407       if (new_v4gw_tunnel) {
1408         if (interfaceName) {
1409           olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1410         }
1411         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1412
1413         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1414         new_gw_in_list->gw = new_gw;
1415         new_gw_in_list->tunnel = new_v4gw_tunnel;
1416         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1417
1418         if (multi_gateway_mode()) {
1419           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1420         }
1421       } else {
1422         /* adding the tunnel failed, we try again in the next cycle */
1423         set_unused_iptunnel_name(new_gw);
1424         ipv4 = false;
1425       }
1426     }
1427   }
1428
1429   /* handle IPv6 */
1430   if (ipv6 &&
1431       new_gw->ipv6 &&
1432       (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1433     /* new gw is different than the current gw */
1434
1435         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1436     if (new_gw_in_list) {
1437       /* new gw is already in the gw list */
1438       assert(new_gw_in_list->tunnel);
1439       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1440       current_ipv6_gw = new_gw_in_list;
1441
1442       if (multi_gateway_mode()) {
1443         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1444       }
1445     } else {
1446       /* new gw is not yet in the gw list */
1447       char name[IFNAMSIZ];
1448       struct olsr_iptunnel_entry *new_v6gw_tunnel;
1449       struct interfaceName * interfaceName;
1450
1451       if (olsr_gw_list_full(&gw_list_ipv6)) {
1452         /* the list is full: remove the worst active gateway */
1453         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1454         assert(worst);
1455
1456         removeGatewayFromList(&gw_list_ipv6, false, worst);
1457       }
1458
1459       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1460       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1461       if (new_v6gw_tunnel) {
1462         if (interfaceName) {
1463           olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1464         }
1465         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1466
1467         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1468         new_gw_in_list->gw = new_gw;
1469         new_gw_in_list->tunnel = new_v6gw_tunnel;
1470         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1471
1472         if (multi_gateway_mode()) {
1473           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1474         }
1475       } else {
1476         /* adding the tunnel failed, we try again in the next cycle */
1477         set_unused_iptunnel_name(new_gw);
1478         ipv6 = false;
1479       }
1480     }
1481   }
1482
1483   return !ipv4 && !ipv6;
1484 }
1485
1486 /**
1487  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1488  * gateway is returned
1489  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1490  * NULL if not set.
1491  */
1492 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1493         if (ipv6) {
1494                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1495         }
1496
1497         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1498 }
1499
1500 /*
1501  * Process Egress Changes
1502  */
1503
1504 #define MSGW_ROUTE_ADD_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1505 #define MSGW_ROUTE_ADD_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1506 #define MSGW_ROUTE_DEL_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1507 #define MSGW_ROUTE_DEL_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1508 #define MSGW_ROUTE_FORCED(phase)        ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1509
1510 /**
1511  * Determine best egress link.
1512  * The list of egress interface is ordered on priority (the declaration order),
1513  * so the function will - for multiple egress links with the same costs - set the
1514  * best egress interface to the first declared one of those.
1515  * When there is no best egress interface (that is up) then the function will
1516  * set the best egress interface to NULL.
1517  *
1518  * @param phase the phase of the change (startup/runtime/shutdown)
1519  * @return true when the best egress link changed or when any of its relevant
1520  * parameters has changed
1521  */
1522 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1523   bool changed = false;
1524   struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1525
1526   if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1527     bestEgress = NULL;
1528   } else {
1529     struct sgw_egress_if * egress_if = bestEgress;
1530     if (egress_if) {
1531       egress_if = egress_if->next;
1532     }
1533     while (egress_if) {
1534       if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs)) {
1535         bestEgress = egress_if;
1536       }
1537
1538       egress_if = egress_if->next;
1539     }
1540
1541     if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1542       bestEgress = NULL;
1543     }
1544   }
1545
1546   bestEgressLinkPrevious = bestEgressLink;
1547   bestEgressLink = bestEgress;
1548
1549   changed = (bestEgressLinkPrevious != bestEgressLink) || //
1550       (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged));
1551
1552   if (changed || MSGW_ROUTE_FORCED(phase)) {
1553     if (!bestEgressLink || !bestEgressLink->upCurrent) {
1554       olsr_cnf->smart_gw_uplink = 0;
1555       olsr_cnf->smart_gw_downlink = 0;
1556     } else {
1557       olsr_cnf->smart_gw_uplink = bestEgressLink->bwCurrent.egressUk;
1558       olsr_cnf->smart_gw_downlink = bestEgressLink->bwCurrent.egressDk;
1559     }
1560     refresh_smartgw_netmask();
1561   }
1562
1563   return changed;
1564 }
1565
1566 /**
1567  * Determine best overall link (choose egress interface over olsrd).
1568  *
1569  * When there is no best overall link, the best overall link will be set to a
1570  * NULL egress interface.
1571  *
1572  * @param phase the phase of the change (startup/runtime/shutdown)
1573  * @return true when the best egress link changed or when any of its relevant
1574  * parameters has changed
1575  */
1576 static bool determineBestOverallLink(enum sgw_multi_change_phase phase) {
1577   struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
1578   struct gateway_entry * olsrGw = !gwContainer ? NULL : gwContainer->gw;
1579
1580   int64_t egressCosts = !bestEgressLink ? INT64_MAX : bestEgressLink->bwCurrent.costs;
1581   int64_t olsrCosts = !olsrGw ? INT64_MAX : olsrGw->path_cost;
1582   int64_t bestOverallCosts = MIN(egressCosts, olsrCosts);
1583
1584   bestOverallLinkPrevious = bestOverallLink;
1585   if ((bestOverallCosts == INT64_MAX) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)) {
1586     bestOverallLink.valid = false;
1587     bestOverallLink.isOlsr = false;
1588     bestOverallLink.link.egress = NULL;
1589     bestOverallLink.olsrTunnelIfIndex = 0;
1590   } else if (egressCosts <= olsrCosts) {
1591     bestOverallLink.valid = bestEgressLink;
1592     bestOverallLink.isOlsr = false;
1593     bestOverallLink.link.egress = bestEgressLink;
1594     bestOverallLink.olsrTunnelIfIndex = 0;
1595   } else {
1596     struct olsr_iptunnel_entry * tunnel;
1597
1598     assert(gwContainer);
1599
1600     tunnel = gwContainer->tunnel;
1601
1602     bestOverallLink.valid = olsrGw;
1603     bestOverallLink.isOlsr = true;
1604     bestOverallLink.link.olsr = olsrGw;
1605     bestOverallLink.olsrTunnelIfIndex = !tunnel ? 0 : tunnel->if_index;
1606   }
1607
1608   return memcmp(&bestOverallLink, &bestOverallLinkPrevious, sizeof(bestOverallLink));
1609 }
1610
1611 /**
1612  * Program a route (add or remove) through netlink
1613  *
1614  * @param add true to add the route, false to remove it
1615  * @param route the route
1616  * @param linkName the human readable id of the route, used in error reports in
1617  * the syslog
1618  */
1619 static void programRoute(bool add, struct sgw_route_info * route, const char * linkName) {
1620   if (!route || !route->active) {
1621     return;
1622   }
1623
1624   if (olsr_new_netlink_route( //
1625       route->route.family, //
1626       route->route.rttable, //
1627       route->route.flags, //
1628       route->route.scope, //
1629       route->route.if_index, //
1630       route->route.metric, //
1631       route->route.protocol, //
1632       !route->route.srcSet ? NULL : &route->route.srcStore, //
1633       !route->route.gwSet ? NULL : &route->route.gwStore, //
1634       !route->route.dstSet ? NULL : &route->route.dstStore, //
1635       add, //
1636       route->route.del_similar, //
1637       route->route.blackhole //
1638       )) {
1639     olsr_syslog(OLSR_LOG_ERR, "Could not %s a route for the %s %s", !add ? "remove" : "add", !add ? "previous" : "current", linkName);
1640     route->active = false;
1641   } else {
1642     route->active = add;
1643   }
1644 }
1645
1646 /**
1647  * Determine the best overall egress/olsr interface routes.
1648  *
1649  * These are a set of 2 /1 routes to override any default gateway
1650  * routes that are setup through other means such as a DHCP client.
1651  *
1652  * @param routes a pointer to the array of 2 /1 routes where to store the
1653  * newly determined routes
1654  */
1655 static void determineBestOverallLinkRoutes(struct sgw_route_info * routes) {
1656   int ifIndex = 0;
1657   union olsr_ip_addr * gw = NULL;
1658   int i;
1659   if (!bestOverallLink.valid) {
1660     /* there is no current best overall link */
1661   } else if (!bestOverallLink.isOlsr) {
1662     /* current best overall link is an egress interface */
1663     struct sgw_egress_if * egress = bestOverallLink.link.egress;
1664     if (egress) {
1665       ifIndex = egress->if_index;
1666       if (egress->bwCurrent.gatewaySet) {
1667         gw = &egress->bwCurrent.gateway;
1668       }
1669     }
1670   } else {
1671     /* current best overall link is an olsr tunnel interface */
1672     struct gw_container_entry * gwContainer = current_ipv4_gw;
1673     struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1674
1675     if (tunnel) {
1676       ifIndex = tunnel->if_index;
1677     }
1678   }
1679
1680   if (!ifIndex) {
1681     for (i = 0; i < 2; i++) {
1682       routes[i].active = false;
1683     }
1684     return;
1685   }
1686
1687   for (i = 0; i < 2; i++) {
1688     memset(&routes[i], 0, sizeof(routes[i]));
1689     routes[i].active = true;
1690     routes[i].route.family = AF_INET;
1691     routes[i].route.rttable = olsr_cnf->rt_table;
1692     routes[i].route.flags = 0;
1693     routes[i].route.scope = !gw ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
1694     routes[i].route.if_index = ifIndex;
1695     routes[i].route.metric = 0;
1696     routes[i].route.protocol = RTPROT_STATIC;
1697     routes[i].route.srcSet = false;
1698     routes[i].route.gwSet = false;
1699     if (gw) {
1700       routes[i].route.gwSet = true;
1701       routes[i].route.gwStore = *gw;
1702     }
1703     routes[i].route.dstSet = true;
1704     routes[i].route.dstStore = ipv4_slash_1_routes[i];
1705     routes[i].route.del_similar = false;
1706     routes[i].route.blackhole = false;
1707   }
1708 }
1709
1710 /**
1711  * Setup default gateway override routes: a set of 2 /1 routes for the best
1712  * overall link
1713  *
1714  * @param phase the phase of the change (startup/runtime/shutdown)
1715  */
1716 static void setupDefaultGatewayOverrideRoutes(enum sgw_multi_change_phase phase) {
1717   bool force = MSGW_ROUTE_FORCED(phase);
1718   int i;
1719
1720   if (!bestOverallLinkPrevious.valid && !bestOverallLink.valid && !force) {
1721     return;
1722   }
1723
1724   memcpy(&bestOverallLinkPreviousRoutes, &bestOverallLinkRoutes, sizeof(bestOverallLinkPreviousRoutes));
1725
1726   determineBestOverallLinkRoutes(bestOverallLinkRoutes);
1727
1728   for (i = 0; i < 2; i++) {
1729     bool routeChanged = //
1730         (bestOverallLinkPreviousRoutes[i].active != bestOverallLinkRoutes[i].active) || //
1731         memcmp(&bestOverallLinkPreviousRoutes[i].route, &bestOverallLinkRoutes[i].route, sizeof(bestOverallLinkRoutes[i].route));
1732
1733     if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1734       programRoute(false, &bestOverallLinkPreviousRoutes[i], "overall best gateway");
1735     }
1736
1737     if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1738       programRoute(true, &bestOverallLinkRoutes[i], "overall best gateway");
1739     }
1740   }
1741 }
1742
1743 /**
1744  * Determine the best egress interface route.
1745  *
1746  * @param route a pointer to the an route where to store the
1747  * newly determined route
1748  * @param networkRoute true when the route is a network route (not an internet
1749  * route)
1750  * @param if_index the index of the interface that the route is for
1751  * @param gw the gateway for the route
1752  * @param dst the destination for the route
1753  * @param table the routing table for the route
1754  */
1755 static void determineEgressLinkRoute( //
1756     struct sgw_route_info * route, //
1757     bool networkRoute, //
1758     int if_index, //
1759     union olsr_ip_addr * gw, //
1760     struct olsr_ip_prefix * dst, //
1761     int table) {
1762   // default route
1763   // ----: ip route replace|delete blackhole default                          table 90: !egress_if               (1)
1764   // ppp0: ip route replace|delete           default                 dev ppp0 table 90:  egress_if && dst && !gw (2)
1765   // eth1: ip route replace|delete           default via 192.168.0.1 dev eth1 table 90:  egress_if && dst &&  gw (3)
1766
1767   // network route
1768   // eth1: ip route replace|delete to 192.168.0.0/24                 dev eth1 table 90:  egress_if && dst && !gw (2*)
1769
1770   memset(route, 0, sizeof(*route));
1771   if (if_index <= 0) { /* 1 */
1772     route->active = true;
1773     route->route.family = AF_INET;
1774     route->route.rttable = table;
1775     route->route.flags = RTNH_F_ONLINK;
1776     route->route.scope = RT_SCOPE_UNIVERSE;
1777     route->route.if_index = 0;
1778     route->route.metric = 0;
1779     route->route.protocol = RTPROT_STATIC;
1780     route->route.srcSet = false;
1781     route->route.gwSet = false;
1782     route->route.dstSet = false;
1783     if (dst) {
1784       route->route.dstSet = true;
1785       route->route.dstStore = *dst;
1786     }
1787     route->route.del_similar = false;
1788     route->route.blackhole = true;
1789   } else if (dst && !gw) { /* 2 */
1790     route->active = true;
1791     route->route.family = AF_INET;
1792     route->route.rttable = table;
1793     route->route.flags = !networkRoute ? RTNH_F_ONLINK /* 2 */ : 0 /* 2* */;
1794     route->route.scope = RT_SCOPE_LINK;
1795     route->route.if_index = if_index;
1796     route->route.metric = 0;
1797     route->route.protocol = RTPROT_STATIC;
1798     route->route.srcSet = false;
1799     route->route.gwSet = false;
1800     route->route.dstSet = true;
1801     route->route.dstStore = *dst;
1802     route->route.del_similar = false;
1803     route->route.blackhole = false;
1804   } else if (dst && gw) { /* 3 */
1805     route->active = true;
1806     route->route.family = AF_INET;
1807     route->route.rttable = table;
1808     route->route.flags = 0;
1809     route->route.scope = RT_SCOPE_UNIVERSE;
1810     route->route.if_index = if_index;
1811     route->route.metric = 0;
1812     route->route.protocol = RTPROT_STATIC;
1813     route->route.srcSet = false;
1814     route->route.gwSet = true;
1815     route->route.gwStore = *gw;
1816     route->route.dstSet = true;
1817     route->route.dstStore = *dst;
1818     route->route.del_similar = false;
1819     route->route.blackhole = false;
1820   } else {
1821     /* no destination set */
1822     route->active = false;
1823     olsr_syslog(OLSR_LOG_ERR, "No route destination specified in %s", __FUNCTION__);
1824     return;
1825   }
1826 }
1827
1828 /**
1829  * Setup default route for the best egress interface
1830  *
1831  * When there is no best egress link, then a blackhole route is setup to prevent
1832  * looping smart gateway tunnel traffic.
1833  *
1834  * @param phase the phase of the change (startup/runtime/shutdown)
1835  */
1836 static void configureBestEgressLinkRoute(enum sgw_multi_change_phase phase) {
1837   bool force = MSGW_ROUTE_FORCED(phase);
1838
1839   /*
1840    * bestEgressLinkPrevious  bestEgressLink  Action
1841    *                   NULL            NULL  -
1842    *                   NULL               x  add new route
1843    *                      x            NULL  remove old route
1844    *                      x               x  remove old route && add new routes
1845    */
1846
1847   if (!bestEgressLinkPrevious && !bestEgressLink && !force) {
1848     return;
1849   }
1850
1851   memcpy(&bestEgressLinkPreviousRoute, &bestEgressLinkRoute, sizeof(bestEgressLinkPreviousRoute));
1852
1853   determineEgressLinkRoute( //
1854       &bestEgressLinkRoute, // route
1855       false, // networkRoute
1856       !bestEgressLink ? 0 : bestEgressLink->if_index, // if_index
1857       (!bestEgressLink || !bestEgressLink->bwCurrent.gatewaySet) ? NULL : &bestEgressLink->bwCurrent.gateway, // gw
1858       &ipv4_slash_0_route, // dst
1859       olsr_cnf->smart_gw_offset_tables // table
1860       );
1861
1862   {
1863     bool routeChanged = //
1864         (bestEgressLinkPreviousRoute.active != bestEgressLinkRoute.active) || //
1865         memcmp(&bestEgressLinkPreviousRoute.route, &bestEgressLinkRoute.route, sizeof(bestEgressLinkRoute.route));
1866
1867     if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1868       programRoute(false, &bestEgressLinkPreviousRoute, "best egress link");
1869     }
1870
1871     if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1872       programRoute(true, &bestEgressLinkRoute, "best egress link");
1873     }
1874   }
1875 }
1876
1877 /**
1878  * Setup network (when relevant) and default routes for the every egress
1879  * interface
1880  *
1881  * @param phase the phase of the change (startup/runtime/shutdown)
1882  */
1883 static void configureEgressLinkRoutes(enum sgw_multi_change_phase phase) {
1884   bool force = MSGW_ROUTE_FORCED(phase);
1885
1886   /* egress interfaces */
1887   struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1888   while (egress_if) {
1889     if (!egress_if->bwNetworkChanged && !egress_if->bwGatewayChanged && !egress_if->upChanged && !force) {
1890       /* no relevant change */
1891       goto next;
1892     }
1893
1894     /* network route */
1895     if (egress_if->bwNetworkChanged || force) {
1896       bool routeChanged;
1897
1898       struct sgw_route_info networkRoutePrevious = egress_if->networkRouteCurrent;
1899
1900       if (!egress_if->bwCurrent.networkSet || !egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
1901         memset(&egress_if->networkRouteCurrent, 0, sizeof(egress_if->networkRouteCurrent));
1902         egress_if->networkRouteCurrent.active = false;
1903       } else {
1904         determineEgressLinkRoute( //
1905             &egress_if->networkRouteCurrent, // route
1906             true,// networkRoute
1907             egress_if->if_index, // if_index
1908             NULL, // gw
1909             &egress_if->bwCurrent.network, // dst
1910             egress_if->tableNr // table
1911             );
1912       }
1913
1914       routeChanged = //
1915           (networkRoutePrevious.active != egress_if->networkRouteCurrent.active) || //
1916           memcmp(&networkRoutePrevious.route, &egress_if->networkRouteCurrent.route, sizeof(egress_if->networkRouteCurrent.route));
1917
1918       if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1919         programRoute(false, &networkRoutePrevious, egress_if->name);
1920       }
1921
1922       if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1923         programRoute(true, &egress_if->networkRouteCurrent, egress_if->name);
1924       }
1925     }
1926
1927     /* default route */
1928     if (egress_if->bwGatewayChanged || force) {
1929       bool routeChanged;
1930
1931       struct sgw_route_info egressRoutePrevious = egress_if->egressRouteCurrent;
1932
1933       if (!egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
1934         memset(&egress_if->egressRouteCurrent, 0, sizeof(egress_if->egressRouteCurrent));
1935         egress_if->egressRouteCurrent.active = false;
1936       } else {
1937         determineEgressLinkRoute( //
1938             &egress_if->egressRouteCurrent, // route
1939             false,// networkRoute
1940             egress_if->if_index, // if_index
1941             !egress_if->bwCurrent.gatewaySet ? NULL : &egress_if->bwCurrent.gateway, // gw
1942             &ipv4_slash_0_route, // dst
1943             egress_if->tableNr // table
1944             );
1945       }
1946
1947       routeChanged = //
1948           (egressRoutePrevious.active != egress_if->egressRouteCurrent.active) || //
1949           memcmp(&egressRoutePrevious, &egress_if->egressRouteCurrent, sizeof(egress_if->egressRouteCurrent));
1950
1951        if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1952          programRoute(false, &egressRoutePrevious, egress_if->name);
1953        }
1954
1955        if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1956          programRoute(true, &egress_if->egressRouteCurrent, egress_if->name);
1957        }
1958     }
1959
1960     next: egress_if = egress_if->next;
1961   }
1962 }
1963
1964 /*
1965  * Multi-Smart-Gateway Status Overview
1966  */
1967
1968 #define IPNONE    ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0"     : "::")
1969 #define MASKNONE  ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0/0"   : "::/0")
1970 #define IPLOCAL   ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.1"   : "::1")
1971 #define MASKLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.0/8" : "::1/128")
1972
1973 /**
1974  * Print a timestamp to a file
1975  *
1976  * @param f the file
1977  */
1978 static void printDate(FILE * f) {
1979   time_t timer;
1980   struct tm* tm_info;
1981   char buffer[64];
1982
1983   time(&timer);
1984   tm_info = localtime(&timer);
1985
1986   strftime(buffer, sizeof(buffer), "%B %d, %Y at %H:%M:%S", tm_info);
1987   fprintf(f, "%s", buffer);
1988 }
1989
1990 /**
1991  * Write multi-smart-gateway status file
1992  *
1993  * <pre>
1994  * # multi-smart-gateway status overview, generated on October 10, 2014 at 08:27:15
1995  *
1996  * #Originator Prefix      Uplink Downlink PathCost   Type   Interface Gateway     Cost
1997  *  127.0.0.1  127.0.0.0/8 0      0        4294967295 egress ppp0      0.0.0.0     9223372036854775807
1998  *  127.0.0.1  127.0.0.0/8 0      0        4294967295 egress eth1      192.168.0.1 9223372036854775807
1999  * *0.0.0.0    0.0.0.0/0   290    1500     1024       olsr   tnl_4094  0.0.0.0     2182002287
2000  * </pre>
2001  *
2002  * @param phase the phase of the change (startup/runtime/shutdown)
2003  */
2004 static void writeProgramStatusFile(enum sgw_multi_change_phase phase) {
2005   /*                                # Origi Prefx Upln Dwnl PathC Type Intfc Gtway Cost */
2006   static const char * fmt_header = "%s%-15s %-18s %-9s %-9s %-10s %-6s %-16s %-15s %s\n";
2007   static const char * fmt_values = "%s%-15s %-18s %-9u %-9u %-10u %-6s %-16s %-15s %lld\n";
2008
2009   char * fileName = olsr_cnf->smart_gw_status_file;
2010   FILE * fp = NULL;
2011
2012   if (!fileName || (fileName[0] == '\0')) {
2013     return;
2014   }
2015
2016   if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
2017     remove(fileName);
2018     return;
2019   }
2020
2021   fp = fopen(fileName, "w");
2022   if (!fp) {
2023     olsr_syslog(OLSR_LOG_ERR, "Could not write to %s", fileName);
2024     return;
2025   }
2026
2027   fprintf(fp, "# OLSRd Multi-Smart-Gateway Status Overview\n");
2028   fprintf(fp, "# Generated on ");
2029   printDate(fp);
2030   fprintf(fp, "\n\n");
2031
2032   /* header */
2033   fprintf(fp, fmt_header, "#", "Originator", "Prefix", "Uplink", "Downlink", "PathCost", "Type", "Interface", "Gateway", "Cost");
2034
2035   /* egress interfaces */
2036   {
2037     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2038     while (egress_if) {
2039       struct ipaddr_str gwStr;
2040       const char * gw = !egress_if->bwCurrent.gatewaySet ? IPNONE : olsr_ip_to_string(&gwStr, &egress_if->bwCurrent.gateway);
2041       bool selected = bestOverallLink.valid && !bestOverallLink.isOlsr && (bestOverallLink.link.egress == egress_if);
2042
2043       fprintf(fp, fmt_values, //
2044           selected ? "*" : " ", //selected
2045           IPLOCAL, // Originator
2046           MASKLOCAL, // Prefix
2047           egress_if->bwCurrent.egressUk, // Uplink
2048           egress_if->bwCurrent.egressDk, // Downlink
2049           egress_if->bwCurrent.path_cost, // PathCost
2050           "egress", // Type
2051           egress_if->name, // Interface
2052           gw, // Gateway
2053           egress_if->bwCurrent.costs // Cost
2054           );
2055
2056       egress_if = egress_if->next;
2057     }
2058   }
2059
2060   /* olsr */
2061   {
2062     struct gateway_entry * current_gw = olsr_get_inet_gateway((olsr_cnf->ip_version == AF_INET) ? false : true);
2063     struct interfaceName * sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
2064
2065     int i = 0;
2066     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
2067       struct interfaceName * node = &sgwTunnelInterfaceNames[i];
2068       struct gateway_entry * gw = node->gw;
2069       struct tc_entry* tc = !gw ? NULL : olsr_lookup_tc_entry(&gw->originator);
2070
2071       struct ipaddr_str originatorStr;
2072       const char * originator = !gw ? IPNONE : olsr_ip_to_string(&originatorStr, &gw->originator);
2073       struct ipaddr_str prefixIpStr;
2074       const char * prefixIPStr = !gw ? IPNONE : olsr_ip_to_string(&prefixIpStr, &gw->external_prefix.prefix);
2075       uint8_t prefix_len = !gw ? 0 : gw->external_prefix.prefix_len;
2076       struct ipaddr_str tunnelGwStr;
2077       const char * tunnelGw = !gw ? IPNONE : olsr_ip_to_string(&tunnelGwStr, &gw->originator);
2078       bool selected = bestOverallLink.valid && bestOverallLink.isOlsr && current_gw && (current_gw == gw);
2079
2080       char prefix[strlen(prefixIPStr) + 1 + 3 + 1];
2081       snprintf(prefix, sizeof(prefix), "%s/%d", prefixIPStr, prefix_len);
2082
2083       fprintf(fp, fmt_values, //
2084           selected ? "*" : " ", // selected
2085           originator, // Originator
2086           !gw ? MASKNONE : prefix, // Prefix IP
2087           !gw ? 0 : gw->uplink, // Uplink
2088           !gw ? 0 : gw->downlink, // Downlink
2089           (!gw || !tc) ? ROUTE_COST_BROKEN : tc->path_cost, // PathCost
2090           "olsr", // Type
2091           node->name, // Interface
2092           tunnelGw, // Gateway
2093           !gw ? INT64_MAX : gw->path_cost // Cost
2094       );
2095     }
2096   }
2097
2098   fclose(fp);
2099 }
2100
2101 /**
2102  * Report a new gateway with its most relevant parameters in the syslog
2103  */
2104 static void reportNewGateway(void) {
2105   if (!bestOverallLink.valid) {
2106     /* best overall link is invalid (none) */
2107     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: none");
2108     return;
2109   }
2110
2111   if (!bestOverallLink.isOlsr) {
2112     /* best overall link is an egress interface */
2113     struct ipaddr_str gwStr;
2114     const char * gw = !bestOverallLink.link.egress->bwCurrent.gatewaySet ? //
2115         NULL : //
2116         olsr_ip_to_string(&gwStr, &bestOverallLink.link.egress->bwCurrent.gateway);
2117
2118     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
2119         bestOverallLink.link.egress->name, //
2120         !gw ? "" : "via ", //
2121         !gw ? "" : gwStr.buf, //
2122         !gw ? "" : " ", //
2123         bestOverallLink.link.egress->bwCurrent.egressUk, //
2124         bestOverallLink.link.egress->bwCurrent.egressDk, //
2125         bestOverallLink.link.egress->bwCurrent.path_cost);
2126     return;
2127   }
2128
2129   /* best overall link is an olsr (tunnel) interface */
2130   {
2131     struct tc_entry* tc = olsr_lookup_tc_entry(&bestOverallLink.link.olsr->originator);
2132
2133     char ifNameBuf[IFNAMSIZ];
2134     const char * ifName = if_indextoname(bestOverallLink.olsrTunnelIfIndex, ifNameBuf);
2135
2136     struct ipaddr_str gwStr;
2137     const char * gw = olsr_ip_to_string(&gwStr, &bestOverallLink.link.olsr->originator);
2138
2139     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
2140         !ifName ? "none" : ifName, //
2141         !gw ? "" : "via ", //
2142         !gw ? "" : gwStr.buf, //
2143         !gw ? "" : " ", //
2144         bestOverallLink.link.olsr->uplink, //
2145         bestOverallLink.link.olsr->downlink, //
2146         !tc ? ROUTE_COST_BROKEN : tc->path_cost);
2147   }
2148 }
2149
2150 /**
2151  * Process changes that are relevant to egress interface: changes to the
2152  * egress interfaces themselves and to the smart gateway that is chosen by olsrd
2153  *
2154  * @param egressChanged true when an egress interface changed
2155  * @param olsrChanged true when the smart gateway changed
2156  * @param phase the phase of the change (startup/runtime/shutdown)
2157  */
2158 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
2159   bool bestEgressChanged = false;
2160   bool bestOverallChanged = false;
2161   bool force = MSGW_ROUTE_FORCED(phase);
2162
2163   assert( //
2164       (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
2165       (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
2166       (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
2167
2168   if (!egressChanged && !olsrChanged && !force) {
2169     goto out;
2170   }
2171
2172   assert(multi_gateway_mode());
2173
2174   if (egressChanged || force) {
2175     bestEgressChanged = determineBestEgressLink(phase);
2176     configureEgressLinkRoutes(phase);
2177   }
2178
2179   if (olsrChanged || bestEgressChanged || force) {
2180     bestOverallChanged = determineBestOverallLink(phase);
2181   }
2182
2183   if (bestOverallChanged || force) {
2184     setupDefaultGatewayOverrideRoutes(phase);
2185   }
2186
2187   if (bestEgressChanged || force) {
2188     configureBestEgressLinkRoute(phase);
2189   }
2190
2191   if (bestOverallChanged || force) {
2192     reportNewGateway();
2193   }
2194
2195   writeProgramStatusFile(phase);
2196
2197   out: if (egressChanged) {
2198     /* clear the 'changed' flags of egress interfaces */
2199     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2200     while (egress_if) {
2201       egress_if->upChanged = false;
2202
2203       egress_if->bwCostsChanged = false;
2204       egress_if->bwNetworkChanged = false;
2205       egress_if->bwGatewayChanged = false;
2206       egress_if->bwChanged = false;
2207
2208       egress_if = egress_if->next;
2209     }
2210   }
2211 }
2212
2213 #endif /* __linux__ */