4 * Created on: 05.01.2010
10 #include "common/avl.h"
15 #include "olsr_cookie.h"
16 #include "scheduler.h"
17 #include "kernel_routes.h"
18 #include "kernel_tunnel.h"
20 #include "duplicate_set.h"
22 #include "gateway_default_handler.h"
23 #include "gateway_list.h"
25 #include "egressTypes.h"
26 #include "egressFile.h"
32 * Defines for the multi-gateway script
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"
41 /** structure that holds an interface name, mark and a pointer to the gateway that uses it */
42 struct interfaceName {
43 char name[IFNAMSIZ]; /**< interface name */
44 uint8_t tableNr; /**< routing table number */
45 uint8_t ruleNr; /**< IP rule number */
46 uint8_t bypassRuleNr; /**< bypass IP rule number */
47 struct gateway_entry *gw; /**< gateway that uses this interface name */
50 /** the gateway tree */
51 struct avl_tree gateway_tree;
54 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
56 /** gateway container cookie */
57 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
59 /** the gateway netmask for the HNA */
60 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
62 /** the gateway handler/plugin */
63 static struct olsr_gw_handler *gw_handler;
65 /** the IPv4 gateway list */
66 struct gw_list gw_list_ipv4;
68 /** the IPv6 gateway list */
69 struct gw_list gw_list_ipv6;
71 /** the current IPv4 gateway */
72 static struct gw_container_entry *current_ipv4_gw;
74 /** the current IPv6 gateway */
75 static struct gw_container_entry *current_ipv6_gw;
77 /** interface names for smart gateway tunnel interfaces, IPv4 */
78 struct interfaceName * sgwTunnel4InterfaceNames;
80 /** interface names for smart gateway tunnel interfaces, IPv6 */
81 struct interfaceName * sgwTunnel6InterfaceNames;
83 /** the timer for proactive takedown */
84 static struct timer_entry *gw_takedown_timer;
86 static struct sgw_egress_if * bestEgressLinkPrevious = NULL;
87 static struct sgw_egress_if * bestEgressLink = NULL;
90 * Forward Declarations
93 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
100 * @return the gateway 'server' tunnel name to use
102 static inline const char * server_tunnel_name(void) {
103 return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
107 * Convert the netmask of the HNA (in the form of an IP address) to a HNA
110 * @param mask the netmask of the HNA (in the form of an IP address)
111 * @param prefixlen the prefix length
112 * @return a pointer to the HNA
114 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
115 return (((uint8_t *)mask) + ((prefixlen+7)/8));
119 * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
120 * to an uplink/downlink speed value
122 * @param value the encoded 1 byte transport value
123 * @return the uplink/downlink speed value (in kbit/s)
125 static uint32_t deserialize_gw_speed(uint8_t value) {
130 /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
131 * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
135 if (value == UINT8_MAX) {
136 /* maximum value: also return maximum value */
140 speed = (value >> 3) + 1;
150 * Convert an uplink/downlink speed value into an encoded 1 byte transport
151 * value (5 bits mantissa, 3 bits exponent)
153 * @param speed the uplink/downlink speed value (in kbit/s)
154 * @return value the encoded 1 byte transport value
156 static uint8_t serialize_gw_speed(uint32_t speed) {
163 if (speed > 320000000) {
167 while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
171 return ((speed - 1) << 3) | exp;
175 * Find an interfaceName struct corresponding to a certain gateway
176 * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
178 * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
179 * @return a pointer to the struct, or NULL when not found
181 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
182 struct interfaceName * sgwTunnelInterfaceNames;
185 if (!multi_gateway_mode()) {
189 assert(sgwTunnel4InterfaceNames);
190 assert(sgwTunnel6InterfaceNames);
192 sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
193 while (i < olsr_cnf->smart_gw_use_count) {
194 struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
205 * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
207 * @param gw pointer to the gateway
208 * @param name pointer to output buffer (length IFNAMSIZ)
209 * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
211 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
212 static uint32_t counter = 0;
216 assert(interfaceName);
218 memset(name, 0, IFNAMSIZ);
220 if (multi_gateway_mode()) {
221 struct interfaceName * ifn = find_interfaceName(NULL);
224 strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
225 *interfaceName = ifn;
230 /* do not return, fall-through to classic naming as fallback */
233 snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
234 *interfaceName = NULL;
238 * Set an olsr ipip tunnel name that is used by a certain gateway as unused
240 * @param gw pointer to the gateway
242 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
243 struct interfaceName * ifn;
245 if (!multi_gateway_mode()) {
251 ifn = find_interfaceName(gw);
259 * Run the multi-gateway script/
261 * @param mode the mode (see SCRIPT_MODE_* defines)
262 * @param addMode true to add policy routing, false to remove it
263 * @param ifname the interface name (optional)
264 * @param tableNr the routing table number (optional)
265 * @param ruleNr the IP rule number/priority (optional)
266 * @param bypassRuleNr the bypass IP rule number/priority (optional)
267 * @return true when successful
269 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
273 assert(!strcmp(mode, SCRIPT_MODE_GENERIC) //
274 || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
275 || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
276 || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
277 || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
280 assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
281 || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
283 assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
284 || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
286 assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
287 || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
289 assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
290 || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
292 assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
293 || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
295 abuf_init(&buf, 1024);
297 abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
299 abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
301 abuf_appendf(&buf, " \"%s\"", mode);
303 abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
306 abuf_appendf(&buf, " \"%s\"", ifName);
310 abuf_appendf(&buf, " \"%u\"", tableNr);
314 abuf_appendf(&buf, " \"%u\"", ruleNr);
318 abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
329 * Setup generic multi-gateway iptables and ip rules
331 * @param add true to add policy routing, false to remove it
332 * @return true when successful
334 static bool multiGwRulesGeneric(bool add) {
335 return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
339 * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
341 * @param add true to add policy routing, false to remove it
342 * @return true when successful
344 static bool multiGwRulesOlsrInterfaces(bool add) {
346 struct olsr_if * ifn;
349 for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
350 if (!multiGwRunScript( //
351 SCRIPT_MODE_OLSRIF,//
356 olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
369 * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
371 * @param add true to add policy routing, false to remove it
372 * @return true when successful
374 static bool multiGwRulesSgwServerTunnel(bool add) {
375 return multiGwRunScript( //
376 SCRIPT_MODE_SGWSRVTUN,//
378 server_tunnel_name(), //
379 olsr_cnf->smart_gw_offset_tables, //
380 olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
386 * Setup multi-gateway iptables and ip rules for all egress interfaces.
388 * @param add true to add policy routing, false to remove it
389 * @return true when successful
391 static bool multiGwRulesEgressInterfaces(bool add) {
395 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
397 if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
404 egress_if = egress_if->next;
411 * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
413 * @param add true to add policy routing, false to remove it
414 * @return true when successful
416 static bool multiGwRulesSgwTunnels(bool add) {
420 while (i < olsr_cnf->smart_gw_use_count) {
421 struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
422 if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
436 * Process interface up/down events for non-olsr interfaces, which are egress
439 * @param if_index the index of the interface
440 * @param flag the up/down event
442 static void doEgressInterface(int if_index, enum olsr_ifchg_flag flag) {
445 char ifname[IF_NAMESIZE];
446 struct sgw_egress_if * egress_if;
449 * we need to get the name of the interface first because the interface
450 * might be hot-plugged _after_ olsrd has started
452 if (!if_indextoname(if_index, ifname)) {
453 /* not a known OS interface */
457 egress_if = findEgressInterface(ifname);
459 /* not a known egress interface */
463 egress_if->if_index = if_index;
465 if (egress_if->upCurrent) {
466 /* interface is already up: no change */
470 egress_if->upPrevious = egress_if->upCurrent;
471 egress_if->upCurrent = true;
472 egress_if->upChanged = true;
474 egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
478 case IFCHG_IF_REMOVE: {
480 * we need to find the egress interface by if_index because we might
481 * be too late; the kernel could already have removed the interface
482 * in which case we'd get a NULL ifname here if we'd try to call
485 struct sgw_egress_if * egress_if = findEgressInterfaceByIndex(if_index);
487 /* not a known egress interface */
491 if (!egress_if->upCurrent) {
492 /* interface is already down: no change */
496 egress_if->upPrevious = egress_if->upCurrent;
497 egress_if->upCurrent = false;
498 egress_if->upChanged = true;
500 egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
504 case IFCHG_IF_UPDATE:
509 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_RUNTIME);
517 * Callback for tunnel interface monitoring which will set the route into the tunnel
518 * when the interface comes up again.
520 * @param if_index the interface index
521 * @param ifh the interface (NULL when not an olsr interface)
522 * @param flag interface change flags
524 static void smartgw_tunnel_monitor(int if_index, struct interface *ifh, enum olsr_ifchg_flag flag) {
525 if (!ifh && multi_gateway_mode()) {
526 /* non-olsr interface in multi-sgw mode */
527 doEgressInterface(if_index, flag);
534 * Timer callback to remove and cleanup a gateway entry
538 static void cleanup_gateway_handler(void *ptr) {
539 struct gateway_entry *gw = ptr;
541 if (gw->ipv4 || gw->ipv6) {
542 /* do not clean it up when it is in use */
546 /* remove gateway entry */
547 avl_delete(&gateway_tree, &gw->node);
548 olsr_cookie_free(gateway_entry_mem_cookie, gw);
552 * Remove a gateway from a gateway list.
554 * @param gw_list a pointer to the gateway list
555 * @param ipv4 true when dealing with an IPv4 gateway / gateway list
556 * @param gw a pointer to the gateway to remove from the list
558 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
560 struct interfaceName * ifn = find_interfaceName(gw->gw);
562 olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
564 olsr_os_del_ipip_tunnel(gw->tunnel);
565 set_unused_iptunnel_name(gw->gw);
569 olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
573 * Remove expensive gateways from the gateway list.
574 * It uses the smart_gw_takedown_percentage configuration parameter
576 * @param gw_list a pointer to the gateway list
577 * @param ipv4 true when dealing with an IPv4 gateway / gateway list
578 * @param current_gw the current gateway
580 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
581 int64_t current_gw_cost_boundary;
584 * exit immediately when takedown is disabled, there is no current gateway, or
585 * when there is only a single gateway
587 if ((olsr_cnf->smart_gw_takedown_percentage == 0) || (current_gw == NULL ) || (gw_list->count <= 1)) {
591 /* get the cost boundary */
592 current_gw_cost_boundary = current_gw->gw->path_cost;
593 if (olsr_cnf->smart_gw_takedown_percentage < 100) {
594 if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
595 current_gw_cost_boundary = ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
597 /* perform scaling because otherwise the percentage calculation can overflow */
598 current_gw_cost_boundary = (((current_gw_cost_boundary ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
602 /* loop while we still have gateways */
603 while (gw_list->count > 1) {
604 /* get the worst gateway */
605 struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
607 /* exit when it's the current gateway */
608 if (worst_gw == current_gw) {
613 * exit when it (and further ones; the list is sorted on costs) has lower
614 * costs than the boundary costs
616 if (worst_gw->gw->path_cost < current_gw_cost_boundary) {
620 /* it's too expensive: take it down */
621 removeGatewayFromList(gw_list, ipv4, worst_gw);
626 * Timer callback for proactive gateway takedown
628 * @param unused unused
630 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
631 takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
632 takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
640 * Initialize gateway system
642 int olsr_init_gateways(void) {
645 gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
646 olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
648 gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
649 olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
651 avl_init(&gateway_tree, avl_comp_default);
653 olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
654 olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
656 if (!multi_gateway_mode()) {
657 sgwTunnel4InterfaceNames = NULL;
658 sgwTunnel6InterfaceNames = NULL;
661 struct sgw_egress_if * egressif;
662 unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
664 /* setup the egress interface name/mark pairs */
666 egressif = olsr_cnf->smart_gw_egress_interfaces;
668 egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
669 egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
670 egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
672 egressif = egressif->next;
675 assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
677 /* setup the SGW tunnel name/mark pairs */
678 sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
679 sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
680 for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
681 struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
682 uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
683 uint32_t ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
686 ifn->tableNr = tableNr;
687 ifn->ruleNr = ruleNr;
688 ifn->bypassRuleNr = 0;
689 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
691 ifn = &sgwTunnel6InterfaceNames[i];
693 ifn->tableNr = tableNr;
694 ifn->ruleNr = ruleNr;
695 ifn->bypassRuleNr = 0;
696 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
700 current_ipv4_gw = NULL;
701 current_ipv6_gw = NULL;
705 refresh_smartgw_netmask();
707 /* initialize default gateway handler */
708 gw_handler = &gw_def_handler;
713 * There appears to be a kernel bug in some kernels (at least in the 3.0
714 * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
715 * initialising the IPIP server tunnel (loading the IPIP module), so we retry
716 * a few times before giving up
718 while (retries-- > 0) {
719 if (!olsr_os_init_iptunnel(server_tunnel_name())) {
724 olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
734 * Startup gateway system
736 int olsr_startup_gateways(void) {
739 if (!multi_gateway_mode()) {
740 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
744 /* Initialise the egress interfaces */
746 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
748 egress_if->if_index = if_nametoindex(egress_if->name);
750 egress_if->upPrevious = egress_if->upCurrent = olsr_if_isup(egress_if->name);
751 egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
753 egressBwClear(&egress_if->bwPrevious, egress_if->upPrevious);
754 egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
755 egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
756 egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
757 egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
758 egress_if->bwChanged = egressBwChanged(egress_if);
760 egress_if->inEgressFile = false;
762 egress_if = egress_if->next;
766 ok = ok && multiGwRulesGeneric(true);
767 ok = ok && multiGwRulesSgwServerTunnel(true);
768 ok = ok && multiGwRulesOlsrInterfaces(true);
769 ok = ok && multiGwRulesEgressInterfaces(true);
770 ok = ok && multiGwRulesSgwTunnels(true);
772 olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
773 olsr_shutdown_gateways();
778 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
780 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
782 /* Check egress interfaces up status to compensate for a race: the interfaces
783 * can change status between initialising their data structures and
784 * registering the tunnel monitor */
786 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
788 bool upCurrent = olsr_if_isup(egress_if->name);
790 if (upCurrent != egress_if->upCurrent) {
791 int index = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
792 enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
793 smartgw_tunnel_monitor(index, NULL, flag);
796 egress_if = egress_if->next;
800 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
801 /* start gateway takedown timer */
802 olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
809 * Shutdown gateway tunnel system
811 void olsr_shutdown_gateways(void) {
812 if (!multi_gateway_mode()) {
813 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
817 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
818 /* stop gateway takedown timer */
819 olsr_stop_timer(gw_takedown_timer);
820 gw_takedown_timer = NULL;
823 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
827 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
829 egress_if->upPrevious = egress_if->upCurrent;
830 egress_if->upCurrent = false;
831 egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
833 egress_if->bwPrevious = egress_if->bwCurrent;
834 egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
835 egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
836 egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
837 egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
838 egress_if->bwChanged = egressBwChanged(egress_if);
840 egress_if->inEgressFile = false;
842 egress_if = egress_if->next;
845 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
847 (void)multiGwRulesSgwTunnels(false);
848 (void)multiGwRulesEgressInterfaces(false);
849 (void)multiGwRulesOlsrInterfaces(false);
850 (void)multiGwRulesSgwServerTunnel(false);
851 (void)multiGwRulesGeneric(false);
855 * Cleanup gateway tunnel system
857 void olsr_cleanup_gateways(void) {
858 struct gateway_entry * tree_gw;
859 struct gw_container_entry * gw;
861 /* remove all gateways in the gateway tree that are not the active gateway */
862 OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
863 if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
864 olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
866 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
868 /* remove all active IPv4 gateways (should be at most 1 now) */
869 OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
871 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
874 OLSR_FOR_ALL_GWS_END(gw);
876 /* remove all active IPv6 gateways (should be at most 1 now) */
877 OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
879 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
882 OLSR_FOR_ALL_GWS_END(gw);
884 /* there should be no more gateways */
885 assert(!avl_walk_first(&gateway_tree));
886 assert(!current_ipv4_gw);
887 assert(!current_ipv6_gw);
889 olsr_os_cleanup_iptunnel(server_tunnel_name());
892 gw_handler->cleanup();
895 if (sgwTunnel4InterfaceNames) {
896 free(sgwTunnel4InterfaceNames);
897 sgwTunnel4InterfaceNames = NULL;
899 if (sgwTunnel6InterfaceNames) {
900 free(sgwTunnel6InterfaceNames);
901 sgwTunnel6InterfaceNames = NULL;
904 olsr_gw_list_cleanup(&gw_list_ipv6);
905 olsr_gw_list_cleanup(&gw_list_ipv4);
906 olsr_free_cookie(gw_container_entry_mem_cookie);
907 olsr_free_cookie(gateway_entry_mem_cookie);
911 * Triggers the first lookup of a gateway.
913 void olsr_trigger_inetgw_startup(void) {
915 gw_handler->startup();
919 * Print debug information about gateway entries
922 void olsr_print_gateway_entries(void) {
923 struct ipaddr_str buf;
924 struct gateway_entry *gw;
925 const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
927 OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
928 OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
929 addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
931 OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
932 OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
934 olsr_ip_to_string(&buf, &gw->originator),
935 gw->ipv4nat ? "" : " ",
936 gw->ipv4 ? '4' : ' ',
937 gw->ipv4nat ? "(N)" : "",
938 (gw->ipv4 && gw->ipv6) ? ',' : ' ',
939 gw->ipv6 ? '6' : ' ',
942 gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
943 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
952 * Apply the smart gateway modifications to an outgoing HNA
954 * @param mask pointer to netmask of the HNA
955 * @param prefixlen of the HNA
957 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
958 uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
960 /* copy the current settings for uplink/downlink into the mask */
961 memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
962 if (olsr_cnf->has_ipv4_gateway) {
963 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
965 if (olsr_cnf->smart_gw_uplink_nat) {
966 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
969 if (olsr_cnf->has_ipv6_gateway) {
970 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
972 if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
973 ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
978 * SgwDynSpeed Plugin Interface
982 * Setup the gateway netmask
984 void refresh_smartgw_netmask(void) {
988 memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
990 if (olsr_cnf->smart_gw_active) {
991 ip = (uint8_t *) &smart_gateway_netmask;
993 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
994 ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
995 ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
997 if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
998 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
999 ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1000 memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1006 * TC/SPF/HNA Interface
1010 * Checks if a HNA prefix/netmask combination is a smart gateway
1014 * @return true if is a valid smart gateway HNA, false otherwise
1016 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1019 if (!is_prefix_inetgw(prefix)) {
1023 ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1024 return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1028 * Update a gateway_entry based on a HNA
1030 * @param originator ip of the source of the HNA
1031 * @param mask netmask of the HNA
1032 * @param prefixlen of the HNA
1033 * @param seqno the sequence number of the HNA
1035 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
1036 struct gw_container_entry * new_gw_in_list;
1038 int64_t prev_path_cost = 0;
1039 struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1042 gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1043 gw->originator = *originator;
1044 gw->node.key = &gw->originator;
1046 avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1047 } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1048 /* ignore older HNAs */
1052 /* keep new HNA seqno */
1055 ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1056 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1057 gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1058 gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1064 gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1065 gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1068 if (olsr_cnf->ip_version == AF_INET6) {
1069 gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1071 /* do not reset prefixlength for ::ffff:0:0 HNAs */
1072 if (prefixlen == ipv6_internet_route.prefix_len) {
1073 memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1075 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1076 && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1077 /* this is the right prefix (2000::/3), so we can copy the prefix */
1078 gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1079 memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1084 /* stop cleanup timer if necessary */
1085 if (gw->cleanup_timer) {
1086 olsr_stop_timer(gw->cleanup_timer);
1087 gw->cleanup_timer = NULL;
1091 prev_path_cost = gw->path_cost;
1092 gw->path_cost = gw_handler->getcosts(gw);
1094 if (prev_path_cost != gw->path_cost) {
1095 /* re-sort the gateway list when costs have changed and when it is an active gateway */
1096 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1097 if (new_gw_in_list) {
1098 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1099 assert(new_gw_in_list);
1102 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1103 if (new_gw_in_list) {
1104 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1105 assert(new_gw_in_list);
1108 if (multi_gateway_mode() && //
1109 ((!gw->ipv6 && current_ipv4_gw && current_ipv4_gw->gw == gw) || //
1110 (gw->ipv6 && current_ipv6_gw && current_ipv6_gw->gw == gw)) //
1112 /* the active gw has changed its costs: re-evaluate egress routes */
1113 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1117 /* call update handler */
1119 gw_handler->update(gw);
1123 * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1124 * Should only be called if prefix is a smart_gw prefix or if node is removed
1129 * @param immediate when set to true then the gateway is removed from the
1130 * gateway tree immediately, else it is removed on a delayed schedule.
1132 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1133 olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1137 * Delete a gateway entry .
1139 * @param gw a gateway entry from the gateway tree
1141 * @param immediate when set to true then the gateway is removed from the
1142 * gateway tree immediately, else it is removed on a delayed schedule.
1144 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1145 bool change = false;
1151 if (immediate && gw->cleanup_timer) {
1152 /* stop timer if we have to remove immediately */
1153 olsr_stop_timer(gw->cleanup_timer);
1154 gw->cleanup_timer = NULL;
1157 if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1158 /* the gw is not scheduled for deletion */
1160 if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1163 gw->ipv4nat = false;
1164 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1167 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1170 gw->ipv4nat = false;
1173 if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1174 struct gw_container_entry * gw_in_list;
1176 /* prevent this gateway from being chosen as the new gateway */
1178 gw->ipv4nat = false;
1181 /* handle gateway loss */
1183 gw_handler->delete(gw);
1185 /* cleanup gateway if necessary */
1186 gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1188 if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1189 olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1190 current_ipv4_gw = NULL;
1193 if (gw_in_list->tunnel) {
1194 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1196 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1198 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1199 set_unused_iptunnel_name(gw_in_list->gw);
1200 gw_in_list->tunnel = NULL;
1203 gw_in_list->gw = NULL;
1204 gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1205 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1208 gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1210 if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1211 olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1212 current_ipv6_gw = NULL;
1215 if (gw_in_list->tunnel) {
1216 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1218 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1220 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1221 set_unused_iptunnel_name(gw_in_list->gw);
1222 gw_in_list->tunnel = NULL;
1225 gw_in_list->gw = NULL;
1226 gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1227 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1231 /* remove gateway entry on a delayed schedule */
1232 olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1234 cleanup_gateway_handler(gw);
1237 /* when the current gateway was deleted, then immediately choose a new gateway */
1238 if (!current_ipv4_gw || !current_ipv6_gw) {
1240 gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1243 } else if (change) {
1245 gw_handler->update(gw);
1251 * Triggers a check if the one of the gateways have been lost or has an
1254 void olsr_trigger_gatewayloss_check(void) {
1258 if (current_ipv4_gw && current_ipv4_gw->gw) {
1259 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv4_gw->gw->originator);
1260 ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1262 if (current_ipv6_gw && current_ipv6_gw->gw) {
1263 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv6_gw->gw->originator);
1264 ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1269 gw_handler->choose(ipv4, ipv6);
1274 * Gateway Plugin Functions
1278 * Sets a new internet gateway.
1280 * @param the chosen gateway
1281 * @param ipv4 set ipv4 gateway
1282 * @param ipv6 set ipv6 gateway
1283 * @return true if an error happened, false otherwise
1285 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1286 struct gateway_entry *new_gw;
1288 ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1289 ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1290 if (!ipv4 && !ipv6) {
1294 new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1296 /* the originator is not in the gateway tree, we can't set it as gateway */
1303 (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1304 (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1305 /* new gw is different than the current gw */
1307 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1308 if (new_gw_in_list) {
1309 /* new gw is already in the gw list */
1310 assert(new_gw_in_list->tunnel);
1311 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1312 current_ipv4_gw = new_gw_in_list;
1314 if (multi_gateway_mode()) {
1315 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1318 /* new gw is not yet in the gw list */
1319 char name[IFNAMSIZ];
1320 struct olsr_iptunnel_entry *new_v4gw_tunnel;
1321 struct interfaceName * interfaceName;
1323 if (olsr_gw_list_full(&gw_list_ipv4)) {
1324 /* the list is full: remove the worst active gateway */
1325 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1328 removeGatewayFromList(&gw_list_ipv4, true, worst);
1331 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1332 new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1333 if (new_v4gw_tunnel) {
1334 if (interfaceName) {
1335 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1337 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1339 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1340 new_gw_in_list->gw = new_gw;
1341 new_gw_in_list->tunnel = new_v4gw_tunnel;
1342 current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1344 if (multi_gateway_mode()) {
1345 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1348 /* adding the tunnel failed, we try again in the next cycle */
1349 set_unused_iptunnel_name(new_gw);
1358 (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1359 /* new gw is different than the current gw */
1361 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1362 if (new_gw_in_list) {
1363 /* new gw is already in the gw list */
1364 assert(new_gw_in_list->tunnel);
1365 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1366 current_ipv6_gw = new_gw_in_list;
1368 if (multi_gateway_mode()) {
1369 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1372 /* new gw is not yet in the gw list */
1373 char name[IFNAMSIZ];
1374 struct olsr_iptunnel_entry *new_v6gw_tunnel;
1375 struct interfaceName * interfaceName;
1377 if (olsr_gw_list_full(&gw_list_ipv6)) {
1378 /* the list is full: remove the worst active gateway */
1379 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1382 removeGatewayFromList(&gw_list_ipv6, false, worst);
1385 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1386 new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1387 if (new_v6gw_tunnel) {
1388 if (interfaceName) {
1389 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1391 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1393 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1394 new_gw_in_list->gw = new_gw;
1395 new_gw_in_list->tunnel = new_v6gw_tunnel;
1396 current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1398 if (multi_gateway_mode()) {
1399 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1402 /* adding the tunnel failed, we try again in the next cycle */
1403 set_unused_iptunnel_name(new_gw);
1409 return !ipv4 && !ipv6;
1413 * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1414 * gateway is returned
1415 * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1418 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1420 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1423 return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1427 * Process Egress Changes
1430 #define MSGW_ROUTE_ADD_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1431 #define MSGW_ROUTE_ADD_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1432 #define MSGW_ROUTE_DEL_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1433 #define MSGW_ROUTE_DEL_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1434 #define MSGW_ROUTE_FORCED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1437 * Determine best egress link.
1438 * The list of egress interface is ordered on priority (the declaration order),
1439 * so the function will - for multiple egress links with the same costs - set the
1440 * best egress interface to the first declared one of those.
1441 * When there is no best egress interface (that is up) then the function will
1442 * set the best egress interface to NULL.
1444 * @param phase the phase of the change (startup/runtime/shutdown)
1445 * @return true when the best egress link changed or when any of its relevant
1446 * parameters has changed
1448 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1449 struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1451 if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1454 struct sgw_egress_if * egress_if = bestEgress;
1456 egress_if = egress_if->next;
1459 if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs)) {
1460 bestEgress = egress_if;
1463 egress_if = egress_if->next;
1466 if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1471 bestEgressLinkPrevious = bestEgressLink;
1472 bestEgressLink = bestEgress;
1474 return ((bestEgressLinkPrevious != bestEgressLink) || //
1475 (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged)));
1479 * Process changes that are relevant to egress interface: changes to the
1480 * egress interfaces themselves and to the smart gateway that is chosen by olsrd
1482 * @param egressChanged true when an egress interface changed
1483 * @param olsrChanged true when the smart gateway changed
1484 * @param phase the phase of the change (startup/runtime/shutdown)
1486 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
1487 bool bestEgressChanged = false;
1488 bool bestOverallChanged = false;
1489 bool force = MSGW_ROUTE_FORCED(phase);
1492 (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
1493 (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
1494 (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
1496 if (!egressChanged && !olsrChanged && !force) {
1500 assert(multi_gateway_mode());
1502 if (egressChanged || force) {
1503 bestEgressChanged = determineBestEgressLink(phase);
1506 // FIXME determine best overall link
1508 if (!bestEgressChanged && !bestOverallChanged && !force) {
1512 // FIXME program routes
1514 out: if (egressChanged) {
1515 /* clear the 'changed' flags of egress interfaces */
1516 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1518 egress_if->upChanged = false;
1520 egress_if->bwCostsChanged = false;
1521 egress_if->bwNetworkChanged = false;
1522 egress_if->bwGatewayChanged = false;
1523 egress_if->bwChanged = false;
1525 egress_if = egress_if->next;
1530 #endif /* __linux__ */