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