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"
30 #include <linux/rtnetlink.h>
33 * Defines for the multi-gateway script
36 #define SCRIPT_MODE_GENERIC "generic"
37 #define SCRIPT_MODE_OLSRIF "olsrif"
38 #define SCRIPT_MODE_SGWSRVTUN "sgwsrvtun"
39 #define SCRIPT_MODE_EGRESSIF "egressif"
40 #define SCRIPT_MODE_SGWTUN "sgwtun"
42 /* ipv4 prefix 0.0.0.0/0 */
43 static struct olsr_ip_prefix ipv4_slash_0_route;
45 /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
46 static struct olsr_ip_prefix ipv4_slash_1_routes[2];
48 /** structure that holds an interface name, mark and a pointer to the gateway that uses it */
49 struct interfaceName {
50 char name[IFNAMSIZ]; /**< interface name */
51 uint8_t tableNr; /**< routing table number */
52 uint8_t ruleNr; /**< IP rule number */
53 uint8_t bypassRuleNr; /**< bypass IP rule number */
54 struct gateway_entry *gw; /**< gateway that uses this interface name */
57 /** the gateway tree */
58 struct avl_tree gateway_tree;
61 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
63 /** gateway container cookie */
64 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
66 /** the gateway netmask for the HNA */
67 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
69 /** the gateway handler/plugin */
70 static struct olsr_gw_handler *gw_handler;
72 /** the IPv4 gateway list */
73 struct gw_list gw_list_ipv4;
75 /** the IPv6 gateway list */
76 struct gw_list gw_list_ipv6;
78 /** the current IPv4 gateway */
79 static struct gw_container_entry *current_ipv4_gw;
81 /** the current IPv6 gateway */
82 static struct gw_container_entry *current_ipv6_gw;
84 /** interface names for smart gateway tunnel interfaces, IPv4 */
85 struct interfaceName * sgwTunnel4InterfaceNames;
87 /** interface names for smart gateway tunnel interfaces, IPv6 */
88 struct interfaceName * sgwTunnel6InterfaceNames;
90 /** the timer for proactive takedown */
91 static struct timer_entry *gw_takedown_timer;
93 struct BestOverallLink {
97 struct sgw_egress_if * egress;
98 struct gateway_entry * olsr;
100 int olsrTunnelIfIndex;
103 static struct sgw_egress_if * bestEgressLinkPrevious = NULL;
104 static struct sgw_egress_if * bestEgressLink = NULL;
106 struct sgw_route_info bestEgressLinkPreviousRoute = {0};
107 struct sgw_route_info bestEgressLinkRoute = {0};
109 struct sgw_route_info bestOverallLinkPreviousRoutes[2] = {{0}};
110 struct sgw_route_info bestOverallLinkRoutes[2] = {{0}};
112 static struct BestOverallLink bestOverallLinkPrevious;
113 static struct BestOverallLink bestOverallLink;
116 * Forward Declarations
119 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
126 * @return the gateway 'server' tunnel name to use
128 static inline const char * server_tunnel_name(void) {
129 return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
133 * Convert the netmask of the HNA (in the form of an IP address) to a HNA
136 * @param mask the netmask of the HNA (in the form of an IP address)
137 * @param prefixlen the prefix length
138 * @return a pointer to the HNA
140 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
141 return (((uint8_t *)mask) + ((prefixlen+7)/8));
145 * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
146 * to an uplink/downlink speed value
148 * @param value the encoded 1 byte transport value
149 * @return the uplink/downlink speed value (in kbit/s)
151 static uint32_t deserialize_gw_speed(uint8_t value) {
156 /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
157 * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
161 if (value == UINT8_MAX) {
162 /* maximum value: also return maximum value */
166 speed = (value >> 3) + 1;
176 * Convert an uplink/downlink speed value into an encoded 1 byte transport
177 * value (5 bits mantissa, 3 bits exponent)
179 * @param speed the uplink/downlink speed value (in kbit/s)
180 * @return value the encoded 1 byte transport value
182 static uint8_t serialize_gw_speed(uint32_t speed) {
189 if (speed > 320000000) {
193 while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
197 return ((speed - 1) << 3) | exp;
201 * Find an interfaceName struct corresponding to a certain gateway
202 * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
204 * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
205 * @return a pointer to the struct, or NULL when not found
207 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
208 struct interfaceName * sgwTunnelInterfaceNames;
211 if (!multi_gateway_mode()) {
215 assert(sgwTunnel4InterfaceNames);
216 assert(sgwTunnel6InterfaceNames);
218 sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
219 while (i < olsr_cnf->smart_gw_use_count) {
220 struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
231 * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
233 * @param gw pointer to the gateway
234 * @param name pointer to output buffer (length IFNAMSIZ)
235 * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
237 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
238 static uint32_t counter = 0;
242 assert(interfaceName);
244 memset(name, 0, IFNAMSIZ);
246 if (multi_gateway_mode()) {
247 struct interfaceName * ifn = find_interfaceName(NULL);
250 strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
251 *interfaceName = ifn;
256 /* do not return, fall-through to classic naming as fallback */
259 snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
260 *interfaceName = NULL;
264 * Set an olsr ipip tunnel name that is used by a certain gateway as unused
266 * @param gw pointer to the gateway
268 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
269 struct interfaceName * ifn;
271 if (!multi_gateway_mode()) {
277 ifn = find_interfaceName(gw);
285 * Run the multi-gateway script/
287 * @param mode the mode (see SCRIPT_MODE_* defines)
288 * @param addMode true to add policy routing, false to remove it
289 * @param ifname the interface name (optional)
290 * @param tableNr the routing table number (optional)
291 * @param ruleNr the IP rule number/priority (optional)
292 * @param bypassRuleNr the bypass IP rule number/priority (optional)
293 * @return true when successful
295 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
299 assert(!strcmp(mode, SCRIPT_MODE_GENERIC) //
300 || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
301 || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
302 || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
303 || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
306 assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
307 || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
309 assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
310 || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
312 assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
313 || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
315 assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
316 || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
318 assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
319 || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
321 abuf_init(&buf, 1024);
323 abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
325 abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
327 abuf_appendf(&buf, " \"%s\"", mode);
329 abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
332 abuf_appendf(&buf, " \"%s\"", ifName);
336 abuf_appendf(&buf, " \"%u\"", tableNr);
340 abuf_appendf(&buf, " \"%u\"", ruleNr);
344 abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
355 * Setup generic multi-gateway iptables and ip rules
357 * @param add true to add policy routing, false to remove it
358 * @return true when successful
360 static bool multiGwRulesGeneric(bool add) {
361 return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
365 * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
367 * @param add true to add policy routing, false to remove it
368 * @return true when successful
370 static bool multiGwRulesOlsrInterfaces(bool add) {
372 struct olsr_if * ifn;
375 for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
376 if (!multiGwRunScript( //
377 SCRIPT_MODE_OLSRIF,//
382 olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
395 * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
397 * @param add true to add policy routing, false to remove it
398 * @return true when successful
400 static bool multiGwRulesSgwServerTunnel(bool add) {
401 return multiGwRunScript( //
402 SCRIPT_MODE_SGWSRVTUN,//
404 server_tunnel_name(), //
405 olsr_cnf->smart_gw_offset_tables, //
406 olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
412 * Setup multi-gateway iptables and ip rules for all egress interfaces.
414 * @param add true to add policy routing, false to remove it
415 * @return true when successful
417 static bool multiGwRulesEgressInterfaces(bool add) {
421 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
423 if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
430 egress_if = egress_if->next;
437 * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
439 * @param add true to add policy routing, false to remove it
440 * @return true when successful
442 static bool multiGwRulesSgwTunnels(bool add) {
446 while (i < olsr_cnf->smart_gw_use_count) {
447 struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
448 if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
462 * Process interface up/down events for non-olsr interfaces, which are egress
465 * @param if_index the index of the interface
466 * @param flag the up/down event
468 static void doEgressInterface(int if_index, enum olsr_ifchg_flag flag) {
471 char ifname[IF_NAMESIZE];
472 struct sgw_egress_if * egress_if;
475 * we need to get the name of the interface first because the interface
476 * might be hot-plugged _after_ olsrd has started
478 if (!if_indextoname(if_index, ifname)) {
479 /* not a known OS interface */
483 egress_if = findEgressInterface(ifname);
485 /* not a known egress interface */
489 egress_if->if_index = if_index;
491 if (egress_if->upCurrent) {
492 /* interface is already up: no change */
496 egress_if->upPrevious = egress_if->upCurrent;
497 egress_if->upCurrent = true;
498 egress_if->upChanged = true;
500 egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
504 case IFCHG_IF_REMOVE: {
506 * we need to find the egress interface by if_index because we might
507 * be too late; the kernel could already have removed the interface
508 * in which case we'd get a NULL ifname here if we'd try to call
511 struct sgw_egress_if * egress_if = findEgressInterfaceByIndex(if_index);
513 /* not a known egress interface */
517 if (!egress_if->upCurrent) {
518 /* interface is already down: no change */
522 egress_if->upPrevious = egress_if->upCurrent;
523 egress_if->upCurrent = false;
524 egress_if->upChanged = true;
526 egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
530 case IFCHG_IF_UPDATE:
535 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_RUNTIME);
543 * Callback for tunnel interface monitoring which will set the route into the tunnel
544 * when the interface comes up again.
546 * @param if_index the interface index
547 * @param ifh the interface (NULL when not an olsr interface)
548 * @param flag interface change flags
550 static void smartgw_tunnel_monitor(int if_index, struct interface *ifh, enum olsr_ifchg_flag flag) {
551 if (!ifh && multi_gateway_mode()) {
552 /* non-olsr interface in multi-sgw mode */
553 doEgressInterface(if_index, flag);
560 * Timer callback to remove and cleanup a gateway entry
564 static void cleanup_gateway_handler(void *ptr) {
565 struct gateway_entry *gw = ptr;
567 if (gw->ipv4 || gw->ipv6) {
568 /* do not clean it up when it is in use */
572 /* remove gateway entry */
573 avl_delete(&gateway_tree, &gw->node);
574 olsr_cookie_free(gateway_entry_mem_cookie, gw);
578 * Remove a gateway from a gateway list.
580 * @param gw_list a pointer to the gateway list
581 * @param ipv4 true when dealing with an IPv4 gateway / gateway list
582 * @param gw a pointer to the gateway to remove from the list
584 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
586 struct interfaceName * ifn = find_interfaceName(gw->gw);
588 olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
590 olsr_os_del_ipip_tunnel(gw->tunnel);
591 set_unused_iptunnel_name(gw->gw);
595 olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
599 * Remove expensive gateways from the gateway list.
600 * It uses the smart_gw_takedown_percentage configuration parameter
602 * @param gw_list a pointer to the gateway list
603 * @param ipv4 true when dealing with an IPv4 gateway / gateway list
604 * @param current_gw the current gateway
606 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
607 int64_t current_gw_cost_boundary;
610 * exit immediately when takedown is disabled, there is no current gateway, or
611 * when there is only a single gateway
613 if ((olsr_cnf->smart_gw_takedown_percentage == 0) || (current_gw == NULL ) || (gw_list->count <= 1)) {
617 /* get the cost boundary */
618 current_gw_cost_boundary = current_gw->gw->path_cost;
619 if (olsr_cnf->smart_gw_takedown_percentage < 100) {
620 if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
621 current_gw_cost_boundary = ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
623 /* perform scaling because otherwise the percentage calculation can overflow */
624 current_gw_cost_boundary = (((current_gw_cost_boundary ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
628 /* loop while we still have gateways */
629 while (gw_list->count > 1) {
630 /* get the worst gateway */
631 struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
633 /* exit when it's the current gateway */
634 if (worst_gw == current_gw) {
639 * exit when it (and further ones; the list is sorted on costs) has lower
640 * costs than the boundary costs
642 if (worst_gw->gw->path_cost < current_gw_cost_boundary) {
646 /* it's too expensive: take it down */
647 removeGatewayFromList(gw_list, ipv4, worst_gw);
652 * Timer callback for proactive gateway takedown
654 * @param unused unused
656 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
657 takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
658 takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
666 * Initialize gateway system
668 int olsr_init_gateways(void) {
671 /* ipv4 prefix 0.0.0.0/0 */
672 memset(&ipv4_slash_0_route, 0, sizeof(ipv4_slash_0_route));
674 /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
675 memset(&ipv4_slash_1_routes, 0, sizeof(ipv4_slash_1_routes));
676 ipv4_slash_1_routes[0].prefix.v4.s_addr = htonl(0x00000000);
677 ipv4_slash_1_routes[0].prefix_len = 1;
678 ipv4_slash_1_routes[1].prefix.v4.s_addr = htonl(0x80000000);
679 ipv4_slash_1_routes[1].prefix_len = 1;
681 gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
682 olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
684 gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
685 olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
687 avl_init(&gateway_tree, avl_comp_default);
689 olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
690 olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
692 sgwTunnel4InterfaceNames = NULL;
693 sgwTunnel6InterfaceNames = NULL;
694 memset(&bestOverallLinkPrevious, 0, sizeof(bestOverallLinkPrevious));
695 memset(&bestOverallLink, 0, sizeof(bestOverallLink));
697 if (multi_gateway_mode()) {
699 struct sgw_egress_if * egressif;
700 unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
702 /* Initialise the egress interfaces */
703 /* setup the egress interface name/mark pairs */
705 egressif = olsr_cnf->smart_gw_egress_interfaces;
707 egressif->if_index = if_nametoindex(egressif->name);
709 egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
710 egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
711 egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
713 egressif->upPrevious = egressif->upCurrent = olsr_if_isup(egressif->name);
714 egressif->upChanged = (egressif->upPrevious != egressif->upCurrent);
716 egressBwClear(&egressif->bwPrevious, egressif->upPrevious);
717 egressBwClear(&egressif->bwCurrent, egressif->upCurrent);
718 egressif->bwCostsChanged = egressBwCostsChanged(egressif);
719 egressif->bwNetworkChanged = egressBwNetworkChanged(egressif);
720 egressif->bwGatewayChanged = egressBwGatewayChanged(egressif);
721 egressif->bwChanged = egressBwChanged(egressif);
723 egressif->inEgressFile = false;
725 egressif = egressif->next;
728 assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
730 /* setup the SGW tunnel name/mark pairs */
731 sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
732 sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
733 for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
734 struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
735 uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
736 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;
739 ifn->tableNr = tableNr;
740 ifn->ruleNr = ruleNr;
741 ifn->bypassRuleNr = 0;
742 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
744 ifn = &sgwTunnel6InterfaceNames[i];
746 ifn->tableNr = tableNr;
747 ifn->ruleNr = ruleNr;
748 ifn->bypassRuleNr = 0;
749 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
753 current_ipv4_gw = NULL;
754 current_ipv6_gw = NULL;
758 refresh_smartgw_netmask();
760 /* initialize default gateway handler */
761 gw_handler = &gw_def_handler;
766 * There appears to be a kernel bug in some kernels (at least in the 3.0
767 * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
768 * initialising the IPIP server tunnel (loading the IPIP module), so we retry
769 * a few times before giving up
771 while (retries-- > 0) {
772 if (!olsr_os_init_iptunnel(server_tunnel_name())) {
777 olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
787 * Startup gateway system
789 int olsr_startup_gateways(void) {
792 if (!multi_gateway_mode()) {
793 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
797 ok = ok && multiGwRulesGeneric(true);
798 ok = ok && multiGwRulesSgwServerTunnel(true);
799 ok = ok && multiGwRulesOlsrInterfaces(true);
800 ok = ok && multiGwRulesEgressInterfaces(true);
801 ok = ok && multiGwRulesSgwTunnels(true);
803 olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
804 olsr_shutdown_gateways();
809 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
811 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
813 /* Check egress interfaces up status to compensate for a race: the interfaces
814 * can change status between initialising their data structures and
815 * registering the tunnel monitor */
817 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
819 bool upCurrent = olsr_if_isup(egress_if->name);
821 if (upCurrent != egress_if->upCurrent) {
822 int index = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
823 enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
824 smartgw_tunnel_monitor(index, NULL, flag);
827 egress_if = egress_if->next;
831 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
832 /* start gateway takedown timer */
833 olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
840 * Shutdown gateway tunnel system
842 void olsr_shutdown_gateways(void) {
843 if (!multi_gateway_mode()) {
844 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
848 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
849 /* stop gateway takedown timer */
850 olsr_stop_timer(gw_takedown_timer);
851 gw_takedown_timer = NULL;
854 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
858 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
860 egress_if->upPrevious = egress_if->upCurrent;
861 egress_if->upCurrent = false;
862 egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
864 egress_if->bwPrevious = egress_if->bwCurrent;
865 egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
866 egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
867 egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
868 egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
869 egress_if->bwChanged = egressBwChanged(egress_if);
871 egress_if->inEgressFile = false;
873 egress_if = egress_if->next;
876 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
878 (void)multiGwRulesSgwTunnels(false);
879 (void)multiGwRulesEgressInterfaces(false);
880 (void)multiGwRulesOlsrInterfaces(false);
881 (void)multiGwRulesSgwServerTunnel(false);
882 (void)multiGwRulesGeneric(false);
886 * Cleanup gateway tunnel system
888 void olsr_cleanup_gateways(void) {
889 struct gateway_entry * tree_gw;
890 struct gw_container_entry * gw;
892 /* remove all gateways in the gateway tree that are not the active gateway */
893 OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
894 if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
895 olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
897 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
899 /* remove all active IPv4 gateways (should be at most 1 now) */
900 OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
902 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
905 OLSR_FOR_ALL_GWS_END(gw);
907 /* remove all active IPv6 gateways (should be at most 1 now) */
908 OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
910 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
913 OLSR_FOR_ALL_GWS_END(gw);
915 /* there should be no more gateways */
916 assert(!avl_walk_first(&gateway_tree));
917 assert(!current_ipv4_gw);
918 assert(!current_ipv6_gw);
920 olsr_os_cleanup_iptunnel(server_tunnel_name());
923 gw_handler->cleanup();
926 if (sgwTunnel4InterfaceNames) {
927 free(sgwTunnel4InterfaceNames);
928 sgwTunnel4InterfaceNames = NULL;
930 if (sgwTunnel6InterfaceNames) {
931 free(sgwTunnel6InterfaceNames);
932 sgwTunnel6InterfaceNames = NULL;
935 olsr_gw_list_cleanup(&gw_list_ipv6);
936 olsr_gw_list_cleanup(&gw_list_ipv4);
937 olsr_free_cookie(gw_container_entry_mem_cookie);
938 olsr_free_cookie(gateway_entry_mem_cookie);
942 * Triggers the first lookup of a gateway.
944 void olsr_trigger_inetgw_startup(void) {
946 gw_handler->startup();
950 * Print debug information about gateway entries
953 void olsr_print_gateway_entries(void) {
954 struct ipaddr_str buf;
955 struct gateway_entry *gw;
956 const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
958 OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
959 OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
960 addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
962 OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
963 OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
965 olsr_ip_to_string(&buf, &gw->originator),
966 gw->ipv4nat ? "" : " ",
967 gw->ipv4 ? '4' : ' ',
968 gw->ipv4nat ? "(N)" : "",
969 (gw->ipv4 && gw->ipv6) ? ',' : ' ',
970 gw->ipv6 ? '6' : ' ',
973 gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
974 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
983 * Apply the smart gateway modifications to an outgoing HNA
985 * @param mask pointer to netmask of the HNA
986 * @param prefixlen of the HNA
988 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
989 uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
991 /* copy the current settings for uplink/downlink into the mask */
992 memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
993 if (olsr_cnf->has_ipv4_gateway) {
994 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
996 if (olsr_cnf->smart_gw_uplink_nat) {
997 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
1000 if (olsr_cnf->has_ipv6_gateway) {
1001 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
1003 if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
1004 ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
1009 * SgwDynSpeed Plugin Interface
1013 * Setup the gateway netmask
1015 void refresh_smartgw_netmask(void) {
1018 /* clear the mask */
1019 memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
1021 if (olsr_cnf->smart_gw_active) {
1022 ip = (uint8_t *) &smart_gateway_netmask;
1024 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
1025 ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
1026 ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
1028 if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
1029 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
1030 ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1031 memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1037 * TC/SPF/HNA Interface
1041 * Checks if a HNA prefix/netmask combination is a smart gateway
1045 * @return true if is a valid smart gateway HNA, false otherwise
1047 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1050 if (!is_prefix_inetgw(prefix)) {
1054 ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1055 return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1059 * Update a gateway_entry based on a HNA
1061 * @param originator ip of the source of the HNA
1062 * @param mask netmask of the HNA
1063 * @param prefixlen of the HNA
1064 * @param seqno the sequence number of the HNA
1066 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
1067 struct gw_container_entry * new_gw_in_list;
1069 int64_t prev_path_cost = 0;
1070 struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1073 gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1074 gw->originator = *originator;
1075 gw->node.key = &gw->originator;
1077 avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1078 } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1079 /* ignore older HNAs */
1083 /* keep new HNA seqno */
1086 ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1087 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1088 gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1089 gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1095 gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1096 gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1099 if (olsr_cnf->ip_version == AF_INET6) {
1100 gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1102 /* do not reset prefixlength for ::ffff:0:0 HNAs */
1103 if (prefixlen == ipv6_internet_route.prefix_len) {
1104 memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1106 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1107 && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1108 /* this is the right prefix (2000::/3), so we can copy the prefix */
1109 gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1110 memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1115 /* stop cleanup timer if necessary */
1116 if (gw->cleanup_timer) {
1117 olsr_stop_timer(gw->cleanup_timer);
1118 gw->cleanup_timer = NULL;
1122 prev_path_cost = gw->path_cost;
1123 gw->path_cost = gw_handler->getcosts(gw);
1125 if (prev_path_cost != gw->path_cost) {
1126 /* re-sort the gateway list when costs have changed and when it is an active gateway */
1127 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1128 if (new_gw_in_list) {
1129 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1130 assert(new_gw_in_list);
1133 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1134 if (new_gw_in_list) {
1135 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1136 assert(new_gw_in_list);
1139 if (multi_gateway_mode() && //
1140 ((!gw->ipv6 && current_ipv4_gw && current_ipv4_gw->gw == gw) || //
1141 (gw->ipv6 && current_ipv6_gw && current_ipv6_gw->gw == gw)) //
1143 /* the active gw has changed its costs: re-evaluate egress routes */
1144 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1148 /* call update handler */
1150 gw_handler->update(gw);
1154 * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1155 * Should only be called if prefix is a smart_gw prefix or if node is removed
1160 * @param immediate when set to true then the gateway is removed from the
1161 * gateway tree immediately, else it is removed on a delayed schedule.
1163 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1164 olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1168 * Delete a gateway entry .
1170 * @param gw a gateway entry from the gateway tree
1172 * @param immediate when set to true then the gateway is removed from the
1173 * gateway tree immediately, else it is removed on a delayed schedule.
1175 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1176 bool change = false;
1182 if (immediate && gw->cleanup_timer) {
1183 /* stop timer if we have to remove immediately */
1184 olsr_stop_timer(gw->cleanup_timer);
1185 gw->cleanup_timer = NULL;
1188 if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1189 /* the gw is not scheduled for deletion */
1191 if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1194 gw->ipv4nat = false;
1195 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1198 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1201 gw->ipv4nat = false;
1204 if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1205 struct gw_container_entry * gw_in_list;
1207 /* prevent this gateway from being chosen as the new gateway */
1209 gw->ipv4nat = false;
1212 /* handle gateway loss */
1214 gw_handler->delete(gw);
1216 /* cleanup gateway if necessary */
1217 gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1219 if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1220 olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1221 current_ipv4_gw = NULL;
1224 if (gw_in_list->tunnel) {
1225 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1227 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1229 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1230 set_unused_iptunnel_name(gw_in_list->gw);
1231 gw_in_list->tunnel = NULL;
1234 gw_in_list->gw = NULL;
1235 gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1236 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1239 gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1241 if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1242 olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1243 current_ipv6_gw = NULL;
1246 if (gw_in_list->tunnel) {
1247 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1249 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1251 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1252 set_unused_iptunnel_name(gw_in_list->gw);
1253 gw_in_list->tunnel = NULL;
1256 gw_in_list->gw = NULL;
1257 gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1258 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1262 /* remove gateway entry on a delayed schedule */
1263 olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1265 cleanup_gateway_handler(gw);
1268 /* when the current gateway was deleted, then immediately choose a new gateway */
1269 if (!current_ipv4_gw || !current_ipv6_gw) {
1271 gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1274 } else if (change) {
1276 gw_handler->update(gw);
1282 * Triggers a check if the one of the gateways have been lost or has an
1285 void olsr_trigger_gatewayloss_check(void) {
1289 if (current_ipv4_gw && current_ipv4_gw->gw) {
1290 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv4_gw->gw->originator);
1291 ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1293 if (current_ipv6_gw && current_ipv6_gw->gw) {
1294 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv6_gw->gw->originator);
1295 ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1300 gw_handler->choose(ipv4, ipv6);
1305 * Gateway Plugin Functions
1309 * Sets a new internet gateway.
1311 * @param the chosen gateway
1312 * @param ipv4 set ipv4 gateway
1313 * @param ipv6 set ipv6 gateway
1314 * @return true if an error happened, false otherwise
1316 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1317 struct gateway_entry *new_gw;
1319 ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1320 ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1321 if (!ipv4 && !ipv6) {
1325 new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1327 /* the originator is not in the gateway tree, we can't set it as gateway */
1334 (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1335 (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1336 /* new gw is different than the current gw */
1338 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1339 if (new_gw_in_list) {
1340 /* new gw is already in the gw list */
1341 assert(new_gw_in_list->tunnel);
1342 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1343 current_ipv4_gw = new_gw_in_list;
1345 if (multi_gateway_mode()) {
1346 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1349 /* new gw is not yet in the gw list */
1350 char name[IFNAMSIZ];
1351 struct olsr_iptunnel_entry *new_v4gw_tunnel;
1352 struct interfaceName * interfaceName;
1354 if (olsr_gw_list_full(&gw_list_ipv4)) {
1355 /* the list is full: remove the worst active gateway */
1356 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1359 removeGatewayFromList(&gw_list_ipv4, true, worst);
1362 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1363 new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1364 if (new_v4gw_tunnel) {
1365 if (interfaceName) {
1366 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1368 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1370 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1371 new_gw_in_list->gw = new_gw;
1372 new_gw_in_list->tunnel = new_v4gw_tunnel;
1373 current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1375 if (multi_gateway_mode()) {
1376 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1379 /* adding the tunnel failed, we try again in the next cycle */
1380 set_unused_iptunnel_name(new_gw);
1389 (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1390 /* new gw is different than the current gw */
1392 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1393 if (new_gw_in_list) {
1394 /* new gw is already in the gw list */
1395 assert(new_gw_in_list->tunnel);
1396 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1397 current_ipv6_gw = new_gw_in_list;
1399 if (multi_gateway_mode()) {
1400 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1403 /* new gw is not yet in the gw list */
1404 char name[IFNAMSIZ];
1405 struct olsr_iptunnel_entry *new_v6gw_tunnel;
1406 struct interfaceName * interfaceName;
1408 if (olsr_gw_list_full(&gw_list_ipv6)) {
1409 /* the list is full: remove the worst active gateway */
1410 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1413 removeGatewayFromList(&gw_list_ipv6, false, worst);
1416 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1417 new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1418 if (new_v6gw_tunnel) {
1419 if (interfaceName) {
1420 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1422 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1424 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1425 new_gw_in_list->gw = new_gw;
1426 new_gw_in_list->tunnel = new_v6gw_tunnel;
1427 current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1429 if (multi_gateway_mode()) {
1430 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1433 /* adding the tunnel failed, we try again in the next cycle */
1434 set_unused_iptunnel_name(new_gw);
1440 return !ipv4 && !ipv6;
1444 * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1445 * gateway is returned
1446 * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1449 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1451 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1454 return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1458 * Process Egress Changes
1461 #define MSGW_ROUTE_ADD_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1462 #define MSGW_ROUTE_ADD_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1463 #define MSGW_ROUTE_DEL_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1464 #define MSGW_ROUTE_DEL_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1465 #define MSGW_ROUTE_FORCED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1468 * Determine best egress link.
1469 * The list of egress interface is ordered on priority (the declaration order),
1470 * so the function will - for multiple egress links with the same costs - set the
1471 * best egress interface to the first declared one of those.
1472 * When there is no best egress interface (that is up) then the function will
1473 * set the best egress interface to NULL.
1475 * @param phase the phase of the change (startup/runtime/shutdown)
1476 * @return true when the best egress link changed or when any of its relevant
1477 * parameters has changed
1479 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1480 struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1482 if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1485 struct sgw_egress_if * egress_if = bestEgress;
1487 egress_if = egress_if->next;
1490 if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs)) {
1491 bestEgress = egress_if;
1494 egress_if = egress_if->next;
1497 if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1502 bestEgressLinkPrevious = bestEgressLink;
1503 bestEgressLink = bestEgress;
1505 return ((bestEgressLinkPrevious != bestEgressLink) || //
1506 (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged)));
1510 * Determine best overall link (choose egress interface over olsrd).
1512 * When there is no best overall link, the best overall link will be set to a
1513 * NULL egress interface.
1515 * @param phase the phase of the change (startup/runtime/shutdown)
1516 * @return true when the best egress link changed or when any of its relevant
1517 * parameters has changed
1519 static bool determineBestOverallLink(enum sgw_multi_change_phase phase) {
1520 struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
1521 struct gateway_entry * olsrGw = !gwContainer ? NULL : gwContainer->gw;
1523 int64_t egressCosts = !bestEgressLink ? INT64_MAX : bestEgressLink->bwCurrent.costs;
1524 int64_t olsrCosts = !olsrGw ? INT64_MAX : olsrGw->path_cost;
1525 int64_t bestOverallCosts = MIN(egressCosts, olsrCosts);
1527 bestOverallLinkPrevious = bestOverallLink;
1528 if ((bestOverallCosts == INT64_MAX) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)) {
1529 bestOverallLink.valid = false;
1530 bestOverallLink.isOlsr = false;
1531 bestOverallLink.link.egress = NULL;
1532 bestOverallLink.olsrTunnelIfIndex = 0;
1533 } else if (egressCosts <= olsrCosts) {
1534 bestOverallLink.valid = bestEgressLink;
1535 bestOverallLink.isOlsr = false;
1536 bestOverallLink.link.egress = bestEgressLink;
1537 bestOverallLink.olsrTunnelIfIndex = 0;
1539 struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1541 bestOverallLink.valid = olsrGw;
1542 bestOverallLink.isOlsr = true;
1543 bestOverallLink.link.olsr = olsrGw;
1544 bestOverallLink.olsrTunnelIfIndex = !tunnel ? 0 : tunnel->if_index;
1547 return memcmp(&bestOverallLink, &bestOverallLinkPrevious, sizeof(bestOverallLink));
1551 * Program a route (add or remove) through netlink
1553 * @param add true to add the route, false to remove it
1554 * @param route the route
1555 * @param linkName the human readable id of the route, used in error reports in
1558 static void programRoute(bool add, struct sgw_route_info * route, const char * linkName) {
1559 if (!route || !route->active) {
1563 if (olsr_new_netlink_route( //
1564 route->route.family, //
1565 route->route.rttable, //
1566 route->route.flags, //
1567 route->route.scope, //
1568 route->route.if_index, //
1569 route->route.metric, //
1570 route->route.protocol, //
1571 !route->route.srcSet ? NULL : &route->route.srcStore, //
1572 !route->route.gwSet ? NULL : &route->route.gwStore, //
1573 !route->route.dstSet ? NULL : &route->route.dstStore, //
1575 route->route.del_similar, //
1576 route->route.blackhole //
1578 olsr_syslog(OLSR_LOG_ERR, "Could not %s a route for the %s %s", !add ? "remove" : "add", !add ? "previous" : "current", linkName);
1579 route->active = false;
1581 route->active = add;
1586 * Determine the best overall egress/olsr interface routes.
1588 * These are a set of 2 /1 routes to override any default gateway
1589 * routes that are setup through other means such as a DHCP client.
1591 * @param routes a pointer to the array of 2 /1 routes where to store the
1592 * newly determined routes
1594 static void determineBestOverallLinkRoutes(struct sgw_route_info * routes) {
1596 union olsr_ip_addr * gw = NULL;
1598 if (!bestOverallLink.valid) {
1599 /* there is no current best overall link */
1600 } else if (!bestOverallLink.isOlsr) {
1601 /* current best overall link is an egress interface */
1602 struct sgw_egress_if * egress = bestOverallLink.link.egress;
1604 ifIndex = egress->if_index;
1605 if (egress->bwCurrent.gatewaySet) {
1606 gw = &egress->bwCurrent.gateway;
1610 /* current best overall link is an olsr tunnel interface */
1611 struct gw_container_entry * gwContainer = current_ipv4_gw;
1612 struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1615 ifIndex = tunnel->if_index;
1620 for (i = 0; i < 2; i++) {
1621 routes[i].active = false;
1626 for (i = 0; i < 2; i++) {
1627 memset(&routes[i], 0, sizeof(routes[i]));
1628 routes[i].active = true;
1629 routes[i].route.family = AF_INET;
1630 routes[i].route.rttable = olsr_cnf->rt_table;
1631 routes[i].route.flags = 0;
1632 routes[i].route.scope = !gw ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
1633 routes[i].route.if_index = ifIndex;
1634 routes[i].route.metric = 0;
1635 routes[i].route.protocol = RTPROT_STATIC;
1636 routes[i].route.srcSet = false;
1637 routes[i].route.gwSet = false;
1639 routes[i].route.gwSet = true;
1640 routes[i].route.gwStore = *gw;
1642 routes[i].route.dstSet = true;
1643 routes[i].route.dstStore = ipv4_slash_1_routes[i];
1644 routes[i].route.del_similar = false;
1645 routes[i].route.blackhole = false;
1650 * Setup default gateway override routes: a set of 2 /1 routes for the best
1653 * @param phase the phase of the change (startup/runtime/shutdown)
1655 static void setupDefaultGatewayOverrideRoutes(enum sgw_multi_change_phase phase) {
1656 bool force = MSGW_ROUTE_FORCED(phase);
1659 if (!bestOverallLinkPrevious.valid && !bestOverallLink.valid && !force) {
1663 memcpy(&bestOverallLinkPreviousRoutes, &bestOverallLinkRoutes, sizeof(bestOverallLinkPreviousRoutes));
1665 determineBestOverallLinkRoutes(bestOverallLinkRoutes);
1667 for (i = 0; i < 2; i++) {
1668 bool routeChanged = //
1669 (bestOverallLinkPreviousRoutes[i].active != bestOverallLinkRoutes[i].active) || //
1670 memcmp(&bestOverallLinkPreviousRoutes[i].route, &bestOverallLinkRoutes[i].route, sizeof(bestOverallLinkRoutes[i].route));
1672 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1673 programRoute(false, &bestOverallLinkPreviousRoutes[i], "overall best gateway");
1676 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1677 programRoute(true, &bestOverallLinkRoutes[i], "overall best gateway");
1683 * Determine the best egress interface route.
1685 * @param route a pointer to the an route where to store the
1686 * newly determined route
1687 * @param networkRoute true when the route is a network route (not an internet
1689 * @param if_index the index of the interface that the route is for
1690 * @param gw the gateway for the route
1691 * @param dst the destination for the route
1692 * @param table the routing table for the route
1694 static void determineEgressLinkRoute( //
1695 struct sgw_route_info * route, //
1696 bool networkRoute, //
1698 union olsr_ip_addr * gw, //
1699 struct olsr_ip_prefix * dst, //
1702 // ----: ip route replace|delete blackhole default table 90: !egress_if (1)
1703 // ppp0: ip route replace|delete default dev ppp0 table 90: egress_if && dst && !gw (2)
1704 // eth1: ip route replace|delete default via 192.168.0.1 dev eth1 table 90: egress_if && dst && gw (3)
1707 // eth1: ip route replace|delete to 192.168.0.0/24 dev eth1 table 90: egress_if && dst && !gw (2*)
1709 memset(route, 0, sizeof(*route));
1710 if (if_index <= 0) { /* 1 */
1711 route->active = true;
1712 route->route.family = AF_INET;
1713 route->route.rttable = table;
1714 route->route.flags = RTNH_F_ONLINK;
1715 route->route.scope = RT_SCOPE_UNIVERSE;
1716 route->route.if_index = 0;
1717 route->route.metric = 0;
1718 route->route.protocol = RTPROT_STATIC;
1719 route->route.srcSet = false;
1720 route->route.gwSet = false;
1721 route->route.dstSet = false;
1723 route->route.dstSet = true;
1724 route->route.dstStore = *dst;
1726 route->route.del_similar = false;
1727 route->route.blackhole = true;
1728 } else if (dst && !gw) { /* 2 */
1729 route->active = true;
1730 route->route.family = AF_INET;
1731 route->route.rttable = table;
1732 route->route.flags = !networkRoute ? RTNH_F_ONLINK /* 2 */ : 0 /* 2* */;
1733 route->route.scope = RT_SCOPE_LINK;
1734 route->route.if_index = if_index;
1735 route->route.metric = 0;
1736 route->route.protocol = RTPROT_STATIC;
1737 route->route.srcSet = false;
1738 route->route.gwSet = false;
1739 route->route.dstSet = true;
1740 route->route.dstStore = *dst;
1741 route->route.del_similar = false;
1742 route->route.blackhole = false;
1743 } else if (dst && gw) { /* 3 */
1744 route->active = true;
1745 route->route.family = AF_INET;
1746 route->route.rttable = table;
1747 route->route.flags = 0;
1748 route->route.scope = RT_SCOPE_UNIVERSE;
1749 route->route.if_index = if_index;
1750 route->route.metric = 0;
1751 route->route.protocol = RTPROT_STATIC;
1752 route->route.srcSet = false;
1753 route->route.gwSet = true;
1754 route->route.gwStore = *gw;
1755 route->route.dstSet = true;
1756 route->route.dstStore = *dst;
1757 route->route.del_similar = false;
1758 route->route.blackhole = false;
1760 /* no destination set */
1761 route->active = false;
1762 olsr_syslog(OLSR_LOG_ERR, "No route destination specified in %s", __FUNCTION__);
1768 * Setup default route for the best egress interface
1770 * When there is no best egress link, then a blackhole route is setup to prevent
1771 * looping smart gateway tunnel traffic.
1773 * @param phase the phase of the change (startup/runtime/shutdown)
1775 static void configureBestEgressLinkRoute(enum sgw_multi_change_phase phase) {
1776 bool force = MSGW_ROUTE_FORCED(phase);
1779 * bestEgressLinkPrevious bestEgressLink Action
1781 * NULL x add new route
1782 * x NULL remove old route
1783 * x x remove old route && add new routes
1786 if (!bestEgressLinkPrevious && !bestEgressLink && !force) {
1790 memcpy(&bestEgressLinkPreviousRoute, &bestEgressLinkRoute, sizeof(bestEgressLinkPreviousRoute));
1792 determineEgressLinkRoute( //
1793 &bestEgressLinkRoute, // route
1794 false, // networkRoute
1795 !bestEgressLink ? 0 : bestEgressLink->if_index, // if_index
1796 (!bestEgressLink || !bestEgressLink->bwCurrent.gatewaySet) ? NULL : &bestEgressLink->bwCurrent.gateway, // gw
1797 &ipv4_slash_0_route, // dst
1798 olsr_cnf->smart_gw_offset_tables // table
1802 bool routeChanged = //
1803 (bestEgressLinkPreviousRoute.active != bestEgressLinkRoute.active) || //
1804 memcmp(&bestEgressLinkPreviousRoute.route, &bestEgressLinkRoute.route, sizeof(bestEgressLinkRoute.route));
1806 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1807 programRoute(false, &bestEgressLinkPreviousRoute, "best egress link");
1810 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1811 programRoute(true, &bestEgressLinkRoute, "best egress link");
1817 * Setup network (when relevant) and default routes for the every egress
1820 * @param phase the phase of the change (startup/runtime/shutdown)
1822 static void configureEgressLinkRoutes(enum sgw_multi_change_phase phase) {
1823 bool force = MSGW_ROUTE_FORCED(phase);
1825 /* egress interfaces */
1826 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1828 if (!egress_if->bwNetworkChanged && !egress_if->bwGatewayChanged && !egress_if->upChanged && !force) {
1829 /* no relevant change */
1834 if (egress_if->bwNetworkChanged || force) {
1837 struct sgw_route_info networkRoutePrevious = egress_if->networkRouteCurrent;
1839 if (!egress_if->bwCurrent.networkSet || !egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
1840 memset(&egress_if->networkRouteCurrent, 0, sizeof(egress_if->networkRouteCurrent));
1841 egress_if->networkRouteCurrent.active = false;
1843 determineEgressLinkRoute( //
1844 &egress_if->networkRouteCurrent, // route
1845 true,// networkRoute
1846 egress_if->if_index, // if_index
1848 &egress_if->bwCurrent.network, // dst
1849 egress_if->tableNr // table
1854 (networkRoutePrevious.active != egress_if->networkRouteCurrent.active) || //
1855 memcmp(&networkRoutePrevious.route, &egress_if->networkRouteCurrent.route, sizeof(egress_if->networkRouteCurrent.route));
1857 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1858 programRoute(false, &networkRoutePrevious, egress_if->name);
1861 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1862 programRoute(true, &egress_if->networkRouteCurrent, egress_if->name);
1867 if (egress_if->bwGatewayChanged || force) {
1870 struct sgw_route_info egressRoutePrevious = egress_if->egressRouteCurrent;
1872 if (!egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
1873 memset(&egress_if->egressRouteCurrent, 0, sizeof(egress_if->egressRouteCurrent));
1874 egress_if->egressRouteCurrent.active = false;
1876 determineEgressLinkRoute( //
1877 &egress_if->egressRouteCurrent, // route
1878 false,// networkRoute
1879 egress_if->if_index, // if_index
1880 !egress_if->bwCurrent.gatewaySet ? NULL : &egress_if->bwCurrent.gateway, // gw
1881 &ipv4_slash_0_route, // dst
1882 egress_if->tableNr // table
1887 (egressRoutePrevious.active != egress_if->egressRouteCurrent.active) || //
1888 memcmp(&egressRoutePrevious, &egress_if->egressRouteCurrent, sizeof(egress_if->egressRouteCurrent));
1890 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1891 programRoute(false, &egressRoutePrevious, egress_if->name);
1894 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1895 programRoute(true, &egress_if->egressRouteCurrent, egress_if->name);
1899 next: egress_if = egress_if->next;
1904 * Multi-Smart-Gateway Status Overview
1907 #define IPNONE ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0" : "::")
1908 #define MASKNONE ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0/0" : "::/0")
1909 #define IPLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.1" : "::1")
1910 #define MASKLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.0/8" : "::1/128")
1913 * Print a timestamp to a file
1917 static void printDate(FILE * f) {
1923 tm_info = localtime(&timer);
1925 strftime(buffer, sizeof(buffer), "%B %d, %Y at %H:%M:%S", tm_info);
1926 fprintf(f, "%s", buffer);
1930 * Write multi-smart-gateway status file
1933 * # multi-smart-gateway status overview, generated on October 10, 2014 at 08:27:15
1935 * #Originator Prefix Uplink Downlink PathCost Type Interface Gateway Cost
1936 * 127.0.0.1 127.0.0.0/8 0 0 4294967295 egress ppp0 0.0.0.0 9223372036854775807
1937 * 127.0.0.1 127.0.0.0/8 0 0 4294967295 egress eth1 192.168.0.1 9223372036854775807
1938 * *0.0.0.0 0.0.0.0/0 290 1500 1024 olsr tnl_4094 0.0.0.0 2182002287
1941 * @param phase the phase of the change (startup/runtime/shutdown)
1943 static void writeProgramStatusFile(enum sgw_multi_change_phase phase) {
1944 /* # Orig Prefx Upl Dwn PathC Type Intfc Gw Cost */
1945 static const char * fmt_header = "%s%-16s %-33s %-8s %-8s %-10s %-16s %-16s %-16s %s\n";
1946 static const char * fmt_values = "%s%-16s %-33s %-8u %-8u %-10u %-16s %-16s %-16s %llu\n";
1948 char * fileName = olsr_cnf->smart_gw_status_file;
1951 if (!fileName || (fileName[0] == '\0')) {
1955 if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1960 fp = fopen(fileName, "w");
1962 olsr_syslog(OLSR_LOG_ERR, "Could not write to %s", fileName);
1966 fprintf(fp, "# OLSRd Multi-Smart-Gateway Status Overview\n");
1967 fprintf(fp, "# Generated on ");
1969 fprintf(fp, "\n\n");
1972 fprintf(fp, fmt_header, "#", "Originator", "Prefix", "Uplink", "Downlink", "PathCost", "Type", "Interface", "Gateway", "Cost");
1974 /* egress interfaces */
1976 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1978 struct ipaddr_str gwStr;
1979 const char * gw = !egress_if->bwCurrent.gatewaySet ? IPNONE : olsr_ip_to_string(&gwStr, &egress_if->bwCurrent.gateway);
1980 bool selected = bestOverallLink.valid && !bestOverallLink.isOlsr && (bestOverallLink.link.egress == egress_if);
1982 fprintf(fp, fmt_values, //
1983 selected ? "*" : " ", //selected
1984 IPLOCAL, // Originator
1985 MASKLOCAL, // Prefix
1986 egress_if->bwCurrent.egressUk, // Uplink
1987 egress_if->bwCurrent.egressDk, // Downlink
1988 egress_if->bwCurrent.path_cost, // PathCost
1990 egress_if->name, // Interface
1992 egress_if->bwCurrent.costs // Cost
1995 egress_if = egress_if->next;
2001 struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
2002 struct gateway_entry * gw = !gwContainer ? NULL : gwContainer->gw;
2003 struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
2004 struct tc_entry* tc = !gw ? NULL : olsr_lookup_tc_entry(&gw->originator);
2006 struct ipaddr_str originatorStr;
2007 const char * originator = !gw ? IPNONE : olsr_ip_to_string(&originatorStr, &gw->originator);
2008 struct ipaddr_str prefixIpStr;
2009 const char * prefixIPStr = !gw ? IPNONE : olsr_ip_to_string(&prefixIpStr, &gw->external_prefix.prefix);
2010 uint8_t prefix_len = !gw ? 0 : gw->external_prefix.prefix_len;
2011 struct interfaceName * tunnelName = !gw ? NULL : find_interfaceName(gw);
2012 struct ipaddr_str tunnelGwStr;
2013 const char * tunnelGw = !tunnel ? IPNONE : olsr_ip_to_string(&tunnelGwStr, &tunnel->target);
2014 bool selected = bestOverallLink.valid && bestOverallLink.isOlsr;
2016 char prefix[strlen(prefixIPStr) + 1 + 3 + 1];
2017 snprintf(prefix, sizeof(prefix), "%s/%d", prefixIPStr, prefix_len);
2019 fprintf(fp, fmt_values, //
2020 selected ? "*" : " ", // selected
2021 originator, // Originator
2022 !gw ? MASKNONE : prefix, // Prefix IP
2023 !gw ? 0 : gw->uplink, // Uplink
2024 !gw ? 0 : gw->downlink, // Downlink
2025 (!gw || !tc) ? ROUTE_COST_BROKEN : tc->path_cost, // PathCost
2027 !tunnelName ? "none" : tunnelName->name, // Interface
2028 tunnelGw, // Gateway
2029 !gw ? INT64_MAX : gw->path_cost // Cost
2037 * Report a new gateway with its most relevant parameters in the syslog
2039 static void reportNewGateway(void) {
2040 if (!bestOverallLink.valid) {
2041 /* best overall link is invalid (none) */
2042 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: none");
2046 if (!bestOverallLink.isOlsr) {
2047 /* best overall link is an egress interface */
2048 struct ipaddr_str gwStr;
2049 const char * gw = !bestOverallLink.link.egress->bwCurrent.gatewaySet ? //
2051 olsr_ip_to_string(&gwStr, &bestOverallLink.link.egress->bwCurrent.gateway);
2053 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
2054 bestOverallLink.link.egress->name, //
2055 !gw ? "" : "via ", //
2056 !gw ? "" : gwStr.buf, //
2058 bestOverallLink.link.egress->bwCurrent.egressUk, //
2059 bestOverallLink.link.egress->bwCurrent.egressDk, //
2060 bestOverallLink.link.egress->bwCurrent.path_cost);
2064 /* best overall link is an olsr (tunnel) interface */
2066 struct tc_entry* tc = olsr_lookup_tc_entry(&bestOverallLink.link.olsr->originator);
2068 char ifNameBuf[IFNAMSIZ];
2069 const char * ifName = if_indextoname(bestOverallLink.olsrTunnelIfIndex, ifNameBuf);
2071 struct ipaddr_str gwStr;
2072 const char * gw = olsr_ip_to_string(&gwStr, &bestOverallLink.link.olsr->originator);
2074 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
2075 !ifName ? "none" : ifName, //
2076 !gw ? "" : "via ", //
2077 !gw ? "" : gwStr.buf, //
2079 bestOverallLink.link.olsr->uplink, //
2080 bestOverallLink.link.olsr->downlink, //
2081 !tc ? ROUTE_COST_BROKEN : tc->path_cost);
2086 * Process changes that are relevant to egress interface: changes to the
2087 * egress interfaces themselves and to the smart gateway that is chosen by olsrd
2089 * @param egressChanged true when an egress interface changed
2090 * @param olsrChanged true when the smart gateway changed
2091 * @param phase the phase of the change (startup/runtime/shutdown)
2093 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
2094 bool bestEgressChanged = false;
2095 bool bestOverallChanged = false;
2096 bool force = MSGW_ROUTE_FORCED(phase);
2099 (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
2100 (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
2101 (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
2103 if (!egressChanged && !olsrChanged && !force) {
2107 assert(multi_gateway_mode());
2109 if (egressChanged || force) {
2110 bestEgressChanged = determineBestEgressLink(phase);
2111 configureEgressLinkRoutes(phase);
2114 if (olsrChanged || bestEgressChanged || force) {
2115 bestOverallChanged = determineBestOverallLink(phase);
2118 if (!bestEgressChanged && !bestOverallChanged && !force) {
2122 if (bestOverallChanged || force) {
2123 setupDefaultGatewayOverrideRoutes(phase);
2126 if (bestEgressChanged || force) {
2127 configureBestEgressLinkRoute(phase);
2130 if (bestOverallChanged || force) {
2134 writeProgramStatusFile(phase);
2136 out: if (egressChanged) {
2137 /* clear the 'changed' flags of egress interfaces */
2138 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2140 egress_if->upChanged = false;
2142 egress_if->bwCostsChanged = false;
2143 egress_if->bwNetworkChanged = false;
2144 egress_if->bwGatewayChanged = false;
2145 egress_if->bwChanged = false;
2147 egress_if = egress_if->next;
2152 #endif /* __linux__ */