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 /* setup the egress interface name/mark pairs */
704 egressif = olsr_cnf->smart_gw_egress_interfaces;
706 egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
707 egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
708 egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
710 egressif = egressif->next;
713 assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
715 /* setup the SGW tunnel name/mark pairs */
716 sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
717 sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
718 for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
719 struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
720 uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
721 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;
724 ifn->tableNr = tableNr;
725 ifn->ruleNr = ruleNr;
726 ifn->bypassRuleNr = 0;
727 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
729 ifn = &sgwTunnel6InterfaceNames[i];
731 ifn->tableNr = tableNr;
732 ifn->ruleNr = ruleNr;
733 ifn->bypassRuleNr = 0;
734 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
738 current_ipv4_gw = NULL;
739 current_ipv6_gw = NULL;
743 refresh_smartgw_netmask();
745 /* initialize default gateway handler */
746 gw_handler = &gw_def_handler;
751 * There appears to be a kernel bug in some kernels (at least in the 3.0
752 * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
753 * initialising the IPIP server tunnel (loading the IPIP module), so we retry
754 * a few times before giving up
756 while (retries-- > 0) {
757 if (!olsr_os_init_iptunnel(server_tunnel_name())) {
762 olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
772 * Startup gateway system
774 int olsr_startup_gateways(void) {
777 if (!multi_gateway_mode()) {
778 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
782 /* Initialise the egress interfaces */
784 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
786 egress_if->if_index = if_nametoindex(egress_if->name);
788 egress_if->upPrevious = egress_if->upCurrent = olsr_if_isup(egress_if->name);
789 egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
791 egressBwClear(&egress_if->bwPrevious, egress_if->upPrevious);
792 egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
793 egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
794 egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
795 egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
796 egress_if->bwChanged = egressBwChanged(egress_if);
798 egress_if->inEgressFile = false;
800 egress_if = egress_if->next;
804 ok = ok && multiGwRulesGeneric(true);
805 ok = ok && multiGwRulesSgwServerTunnel(true);
806 ok = ok && multiGwRulesOlsrInterfaces(true);
807 ok = ok && multiGwRulesEgressInterfaces(true);
808 ok = ok && multiGwRulesSgwTunnels(true);
810 olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
811 olsr_shutdown_gateways();
816 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
818 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
820 /* Check egress interfaces up status to compensate for a race: the interfaces
821 * can change status between initialising their data structures and
822 * registering the tunnel monitor */
824 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
826 bool upCurrent = olsr_if_isup(egress_if->name);
828 if (upCurrent != egress_if->upCurrent) {
829 int index = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
830 enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
831 smartgw_tunnel_monitor(index, NULL, flag);
834 egress_if = egress_if->next;
838 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
839 /* start gateway takedown timer */
840 olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
847 * Shutdown gateway tunnel system
849 void olsr_shutdown_gateways(void) {
850 if (!multi_gateway_mode()) {
851 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
855 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
856 /* stop gateway takedown timer */
857 olsr_stop_timer(gw_takedown_timer);
858 gw_takedown_timer = NULL;
861 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
865 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
867 egress_if->upPrevious = egress_if->upCurrent;
868 egress_if->upCurrent = false;
869 egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
871 egress_if->bwPrevious = egress_if->bwCurrent;
872 egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
873 egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
874 egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
875 egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
876 egress_if->bwChanged = egressBwChanged(egress_if);
878 egress_if->inEgressFile = false;
880 egress_if = egress_if->next;
883 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
885 (void)multiGwRulesSgwTunnels(false);
886 (void)multiGwRulesEgressInterfaces(false);
887 (void)multiGwRulesOlsrInterfaces(false);
888 (void)multiGwRulesSgwServerTunnel(false);
889 (void)multiGwRulesGeneric(false);
893 * Cleanup gateway tunnel system
895 void olsr_cleanup_gateways(void) {
896 struct gateway_entry * tree_gw;
897 struct gw_container_entry * gw;
899 /* remove all gateways in the gateway tree that are not the active gateway */
900 OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
901 if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
902 olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
904 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
906 /* remove all active IPv4 gateways (should be at most 1 now) */
907 OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
909 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
912 OLSR_FOR_ALL_GWS_END(gw);
914 /* remove all active IPv6 gateways (should be at most 1 now) */
915 OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
917 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
920 OLSR_FOR_ALL_GWS_END(gw);
922 /* there should be no more gateways */
923 assert(!avl_walk_first(&gateway_tree));
924 assert(!current_ipv4_gw);
925 assert(!current_ipv6_gw);
927 olsr_os_cleanup_iptunnel(server_tunnel_name());
930 gw_handler->cleanup();
933 if (sgwTunnel4InterfaceNames) {
934 free(sgwTunnel4InterfaceNames);
935 sgwTunnel4InterfaceNames = NULL;
937 if (sgwTunnel6InterfaceNames) {
938 free(sgwTunnel6InterfaceNames);
939 sgwTunnel6InterfaceNames = NULL;
942 olsr_gw_list_cleanup(&gw_list_ipv6);
943 olsr_gw_list_cleanup(&gw_list_ipv4);
944 olsr_free_cookie(gw_container_entry_mem_cookie);
945 olsr_free_cookie(gateway_entry_mem_cookie);
949 * Triggers the first lookup of a gateway.
951 void olsr_trigger_inetgw_startup(void) {
953 gw_handler->startup();
957 * Print debug information about gateway entries
960 void olsr_print_gateway_entries(void) {
961 struct ipaddr_str buf;
962 struct gateway_entry *gw;
963 const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
965 OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
966 OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
967 addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
969 OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
970 OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
972 olsr_ip_to_string(&buf, &gw->originator),
973 gw->ipv4nat ? "" : " ",
974 gw->ipv4 ? '4' : ' ',
975 gw->ipv4nat ? "(N)" : "",
976 (gw->ipv4 && gw->ipv6) ? ',' : ' ',
977 gw->ipv6 ? '6' : ' ',
980 gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
981 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
990 * Apply the smart gateway modifications to an outgoing HNA
992 * @param mask pointer to netmask of the HNA
993 * @param prefixlen of the HNA
995 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
996 uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
998 /* copy the current settings for uplink/downlink into the mask */
999 memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
1000 if (olsr_cnf->has_ipv4_gateway) {
1001 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
1003 if (olsr_cnf->smart_gw_uplink_nat) {
1004 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
1007 if (olsr_cnf->has_ipv6_gateway) {
1008 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
1010 if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
1011 ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
1016 * SgwDynSpeed Plugin Interface
1020 * Setup the gateway netmask
1022 void refresh_smartgw_netmask(void) {
1025 /* clear the mask */
1026 memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
1028 if (olsr_cnf->smart_gw_active) {
1029 ip = (uint8_t *) &smart_gateway_netmask;
1031 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
1032 ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
1033 ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
1035 if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
1036 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
1037 ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1038 memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1044 * TC/SPF/HNA Interface
1048 * Checks if a HNA prefix/netmask combination is a smart gateway
1052 * @return true if is a valid smart gateway HNA, false otherwise
1054 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1057 if (!is_prefix_inetgw(prefix)) {
1061 ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1062 return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1066 * Update a gateway_entry based on a HNA
1068 * @param originator ip of the source of the HNA
1069 * @param mask netmask of the HNA
1070 * @param prefixlen of the HNA
1071 * @param seqno the sequence number of the HNA
1073 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
1074 struct gw_container_entry * new_gw_in_list;
1076 int64_t prev_path_cost = 0;
1077 struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1080 gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1081 gw->originator = *originator;
1082 gw->node.key = &gw->originator;
1084 avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1085 } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1086 /* ignore older HNAs */
1090 /* keep new HNA seqno */
1093 ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1094 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1095 gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1096 gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1102 gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1103 gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1106 if (olsr_cnf->ip_version == AF_INET6) {
1107 gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1109 /* do not reset prefixlength for ::ffff:0:0 HNAs */
1110 if (prefixlen == ipv6_internet_route.prefix_len) {
1111 memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1113 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1114 && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1115 /* this is the right prefix (2000::/3), so we can copy the prefix */
1116 gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1117 memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1122 /* stop cleanup timer if necessary */
1123 if (gw->cleanup_timer) {
1124 olsr_stop_timer(gw->cleanup_timer);
1125 gw->cleanup_timer = NULL;
1129 prev_path_cost = gw->path_cost;
1130 gw->path_cost = gw_handler->getcosts(gw);
1132 if (prev_path_cost != gw->path_cost) {
1133 /* re-sort the gateway list when costs have changed and when it is an active gateway */
1134 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1135 if (new_gw_in_list) {
1136 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1137 assert(new_gw_in_list);
1140 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1141 if (new_gw_in_list) {
1142 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1143 assert(new_gw_in_list);
1146 if (multi_gateway_mode() && //
1147 ((!gw->ipv6 && current_ipv4_gw && current_ipv4_gw->gw == gw) || //
1148 (gw->ipv6 && current_ipv6_gw && current_ipv6_gw->gw == gw)) //
1150 /* the active gw has changed its costs: re-evaluate egress routes */
1151 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1155 /* call update handler */
1157 gw_handler->update(gw);
1161 * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1162 * Should only be called if prefix is a smart_gw prefix or if node is removed
1167 * @param immediate when set to true then the gateway is removed from the
1168 * gateway tree immediately, else it is removed on a delayed schedule.
1170 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1171 olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1175 * Delete a gateway entry .
1177 * @param gw a gateway entry from the gateway tree
1179 * @param immediate when set to true then the gateway is removed from the
1180 * gateway tree immediately, else it is removed on a delayed schedule.
1182 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1183 bool change = false;
1189 if (immediate && gw->cleanup_timer) {
1190 /* stop timer if we have to remove immediately */
1191 olsr_stop_timer(gw->cleanup_timer);
1192 gw->cleanup_timer = NULL;
1195 if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1196 /* the gw is not scheduled for deletion */
1198 if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1201 gw->ipv4nat = false;
1202 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1205 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1208 gw->ipv4nat = false;
1211 if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1212 struct gw_container_entry * gw_in_list;
1214 /* prevent this gateway from being chosen as the new gateway */
1216 gw->ipv4nat = false;
1219 /* handle gateway loss */
1221 gw_handler->delete(gw);
1223 /* cleanup gateway if necessary */
1224 gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1226 if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1227 olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1228 current_ipv4_gw = NULL;
1231 if (gw_in_list->tunnel) {
1232 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1234 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1236 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1237 set_unused_iptunnel_name(gw_in_list->gw);
1238 gw_in_list->tunnel = NULL;
1241 gw_in_list->gw = NULL;
1242 gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1243 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1246 gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1248 if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1249 olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1250 current_ipv6_gw = NULL;
1253 if (gw_in_list->tunnel) {
1254 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1256 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1258 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1259 set_unused_iptunnel_name(gw_in_list->gw);
1260 gw_in_list->tunnel = NULL;
1263 gw_in_list->gw = NULL;
1264 gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1265 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1269 /* remove gateway entry on a delayed schedule */
1270 olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1272 cleanup_gateway_handler(gw);
1275 /* when the current gateway was deleted, then immediately choose a new gateway */
1276 if (!current_ipv4_gw || !current_ipv6_gw) {
1278 gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1281 } else if (change) {
1283 gw_handler->update(gw);
1289 * Triggers a check if the one of the gateways have been lost or has an
1292 void olsr_trigger_gatewayloss_check(void) {
1296 if (current_ipv4_gw && current_ipv4_gw->gw) {
1297 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv4_gw->gw->originator);
1298 ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1300 if (current_ipv6_gw && current_ipv6_gw->gw) {
1301 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv6_gw->gw->originator);
1302 ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1307 gw_handler->choose(ipv4, ipv6);
1312 * Gateway Plugin Functions
1316 * Sets a new internet gateway.
1318 * @param the chosen gateway
1319 * @param ipv4 set ipv4 gateway
1320 * @param ipv6 set ipv6 gateway
1321 * @return true if an error happened, false otherwise
1323 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1324 struct gateway_entry *new_gw;
1326 ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1327 ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1328 if (!ipv4 && !ipv6) {
1332 new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1334 /* the originator is not in the gateway tree, we can't set it as gateway */
1341 (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1342 (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1343 /* new gw is different than the current gw */
1345 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1346 if (new_gw_in_list) {
1347 /* new gw is already in the gw list */
1348 assert(new_gw_in_list->tunnel);
1349 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1350 current_ipv4_gw = new_gw_in_list;
1352 if (multi_gateway_mode()) {
1353 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1356 /* new gw is not yet in the gw list */
1357 char name[IFNAMSIZ];
1358 struct olsr_iptunnel_entry *new_v4gw_tunnel;
1359 struct interfaceName * interfaceName;
1361 if (olsr_gw_list_full(&gw_list_ipv4)) {
1362 /* the list is full: remove the worst active gateway */
1363 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1366 removeGatewayFromList(&gw_list_ipv4, true, worst);
1369 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1370 new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1371 if (new_v4gw_tunnel) {
1372 if (interfaceName) {
1373 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1375 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1377 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1378 new_gw_in_list->gw = new_gw;
1379 new_gw_in_list->tunnel = new_v4gw_tunnel;
1380 current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1382 if (multi_gateway_mode()) {
1383 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1386 /* adding the tunnel failed, we try again in the next cycle */
1387 set_unused_iptunnel_name(new_gw);
1396 (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1397 /* new gw is different than the current gw */
1399 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1400 if (new_gw_in_list) {
1401 /* new gw is already in the gw list */
1402 assert(new_gw_in_list->tunnel);
1403 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1404 current_ipv6_gw = new_gw_in_list;
1406 if (multi_gateway_mode()) {
1407 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1410 /* new gw is not yet in the gw list */
1411 char name[IFNAMSIZ];
1412 struct olsr_iptunnel_entry *new_v6gw_tunnel;
1413 struct interfaceName * interfaceName;
1415 if (olsr_gw_list_full(&gw_list_ipv6)) {
1416 /* the list is full: remove the worst active gateway */
1417 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1420 removeGatewayFromList(&gw_list_ipv6, false, worst);
1423 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1424 new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1425 if (new_v6gw_tunnel) {
1426 if (interfaceName) {
1427 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1429 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1431 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1432 new_gw_in_list->gw = new_gw;
1433 new_gw_in_list->tunnel = new_v6gw_tunnel;
1434 current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1436 if (multi_gateway_mode()) {
1437 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1440 /* adding the tunnel failed, we try again in the next cycle */
1441 set_unused_iptunnel_name(new_gw);
1447 return !ipv4 && !ipv6;
1451 * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1452 * gateway is returned
1453 * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1456 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1458 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1461 return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1465 * Process Egress Changes
1468 #define MSGW_ROUTE_ADD_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1469 #define MSGW_ROUTE_ADD_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1470 #define MSGW_ROUTE_DEL_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1471 #define MSGW_ROUTE_DEL_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1472 #define MSGW_ROUTE_FORCED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1475 * Determine best egress link.
1476 * The list of egress interface is ordered on priority (the declaration order),
1477 * so the function will - for multiple egress links with the same costs - set the
1478 * best egress interface to the first declared one of those.
1479 * When there is no best egress interface (that is up) then the function will
1480 * set the best egress interface to NULL.
1482 * @param phase the phase of the change (startup/runtime/shutdown)
1483 * @return true when the best egress link changed or when any of its relevant
1484 * parameters has changed
1486 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1487 struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1489 if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1492 struct sgw_egress_if * egress_if = bestEgress;
1494 egress_if = egress_if->next;
1497 if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs)) {
1498 bestEgress = egress_if;
1501 egress_if = egress_if->next;
1504 if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1509 bestEgressLinkPrevious = bestEgressLink;
1510 bestEgressLink = bestEgress;
1512 return ((bestEgressLinkPrevious != bestEgressLink) || //
1513 (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged)));
1517 * Determine best overall link (choose egress interface over olsrd).
1519 * When there is no best overall link, the best overall link will be set to a
1520 * NULL egress interface.
1522 * @param phase the phase of the change (startup/runtime/shutdown)
1523 * @return true when the best egress link changed or when any of its relevant
1524 * parameters has changed
1526 static bool determineBestOverallLink(enum sgw_multi_change_phase phase) {
1527 struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
1528 struct gateway_entry * olsrGw = !gwContainer ? NULL : gwContainer->gw;
1530 int64_t egressCosts = !bestEgressLink ? INT64_MAX : bestEgressLink->bwCurrent.costs;
1531 int64_t olsrCosts = !olsrGw ? INT64_MAX : olsrGw->path_cost;
1532 int64_t bestOverallCosts = MIN(egressCosts, olsrCosts);
1534 bestOverallLinkPrevious = bestOverallLink;
1535 if ((bestOverallCosts == INT64_MAX) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)) {
1536 bestOverallLink.valid = false;
1537 bestOverallLink.isOlsr = false;
1538 bestOverallLink.link.egress = NULL;
1539 bestOverallLink.olsrTunnelIfIndex = 0;
1540 } else if (egressCosts <= olsrCosts) {
1541 bestOverallLink.valid = bestEgressLink;
1542 bestOverallLink.isOlsr = false;
1543 bestOverallLink.link.egress = bestEgressLink;
1544 bestOverallLink.olsrTunnelIfIndex = 0;
1546 struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1548 bestOverallLink.valid = olsrGw;
1549 bestOverallLink.isOlsr = true;
1550 bestOverallLink.link.olsr = olsrGw;
1551 bestOverallLink.olsrTunnelIfIndex = !tunnel ? 0 : tunnel->if_index;
1554 return memcmp(&bestOverallLink, &bestOverallLinkPrevious, sizeof(bestOverallLink));
1558 * Program a route (add or remove) through netlink
1560 * @param add true to add the route, false to remove it
1561 * @param route the route
1562 * @param linkName the human readable id of the route, used in error reports in
1565 static void programRoute(bool add, struct sgw_route_info * route, const char * linkName) {
1566 if (!route || !route->active) {
1570 if (olsr_new_netlink_route( //
1571 route->route.family, //
1572 route->route.rttable, //
1573 route->route.flags, //
1574 route->route.scope, //
1575 route->route.if_index, //
1576 route->route.metric, //
1577 route->route.protocol, //
1578 !route->route.srcSet ? NULL : &route->route.srcStore, //
1579 !route->route.gwSet ? NULL : &route->route.gwStore, //
1580 !route->route.dstSet ? NULL : &route->route.dstStore, //
1582 route->route.del_similar, //
1583 route->route.blackhole //
1585 olsr_syslog(OLSR_LOG_ERR, "Could not %s a route for the %s %s", !add ? "remove" : "add", !add ? "previous" : "current", linkName);
1586 route->active = false;
1588 route->active = add;
1593 * Determine the best overall egress/olsr interface routes.
1595 * These are a set of 2 /1 routes to override any default gateway
1596 * routes that are setup through other means such as a DHCP client.
1598 * @param routes a pointer to the array of 2 /1 routes where to store the
1599 * newly determined routes
1601 static void determineBestOverallLinkRoutes(struct sgw_route_info * routes) {
1603 union olsr_ip_addr * gw = NULL;
1605 if (!bestOverallLink.valid) {
1606 /* there is no current best overall link */
1607 } else if (!bestOverallLink.isOlsr) {
1608 /* current best overall link is an egress interface */
1609 struct sgw_egress_if * egress = bestOverallLink.link.egress;
1611 ifIndex = egress->if_index;
1612 if (egress->bwCurrent.gatewaySet) {
1613 gw = &egress->bwCurrent.gateway;
1617 /* current best overall link is an olsr tunnel interface */
1618 struct gw_container_entry * gwContainer = current_ipv4_gw;
1619 struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1622 ifIndex = tunnel->if_index;
1627 for (i = 0; i < 2; i++) {
1628 routes[i].active = false;
1633 for (i = 0; i < 2; i++) {
1634 memset(&routes[i], 0, sizeof(routes[i]));
1635 routes[i].active = true;
1636 routes[i].route.family = AF_INET;
1637 routes[i].route.rttable = olsr_cnf->rt_table;
1638 routes[i].route.flags = 0;
1639 routes[i].route.scope = !gw ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
1640 routes[i].route.if_index = ifIndex;
1641 routes[i].route.metric = 0;
1642 routes[i].route.protocol = RTPROT_STATIC;
1643 routes[i].route.srcSet = false;
1644 routes[i].route.gwSet = false;
1646 routes[i].route.gwSet = true;
1647 routes[i].route.gwStore = *gw;
1649 routes[i].route.dstSet = true;
1650 routes[i].route.dstStore = ipv4_slash_1_routes[i];
1651 routes[i].route.del_similar = false;
1652 routes[i].route.blackhole = false;
1657 * Setup default gateway override routes: a set of 2 /1 routes for the best
1660 * @param phase the phase of the change (startup/runtime/shutdown)
1662 static void setupDefaultGatewayOverrideRoutes(enum sgw_multi_change_phase phase) {
1663 bool force = MSGW_ROUTE_FORCED(phase);
1666 if (!bestOverallLinkPrevious.valid && !bestOverallLink.valid && !force) {
1670 memcpy(&bestOverallLinkPreviousRoutes, &bestOverallLinkRoutes, sizeof(bestOverallLinkPreviousRoutes));
1672 determineBestOverallLinkRoutes(bestOverallLinkRoutes);
1674 for (i = 0; i < 2; i++) {
1675 bool routeChanged = //
1676 (bestOverallLinkPreviousRoutes[i].active != bestOverallLinkRoutes[i].active) || //
1677 memcmp(&bestOverallLinkPreviousRoutes[i].route, &bestOverallLinkRoutes[i].route, sizeof(bestOverallLinkRoutes[i].route));
1679 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1680 programRoute(false, &bestOverallLinkPreviousRoutes[i], "overall best gateway");
1683 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1684 programRoute(true, &bestOverallLinkRoutes[i], "overall best gateway");
1690 * Determine the best egress interface route.
1692 * @param route a pointer to the an route where to store the
1693 * newly determined route
1694 * @param networkRoute true when the route is a network route (not an internet
1696 * @param if_index the index of the interface that the route is for
1697 * @param gw the gateway for the route
1698 * @param dst the destination for the route
1699 * @param table the routing table for the route
1701 static void determineEgressLinkRoute( //
1702 struct sgw_route_info * route, //
1703 bool networkRoute, //
1705 union olsr_ip_addr * gw, //
1706 struct olsr_ip_prefix * dst, //
1709 // ----: ip route replace|delete blackhole default table 90: !egress_if (1)
1710 // ppp0: ip route replace|delete default dev ppp0 table 90: egress_if && dst && !gw (2)
1711 // eth1: ip route replace|delete default via 192.168.0.1 dev eth1 table 90: egress_if && dst && gw (3)
1714 // eth1: ip route replace|delete to 192.168.0.0/24 dev eth1 table 90: egress_if && dst && !gw (2*)
1716 memset(route, 0, sizeof(*route));
1717 if (if_index <= 0) { /* 1 */
1718 route->active = true;
1719 route->route.family = AF_INET;
1720 route->route.rttable = table;
1721 route->route.flags = RTNH_F_ONLINK;
1722 route->route.scope = RT_SCOPE_UNIVERSE;
1723 route->route.if_index = 0;
1724 route->route.metric = 0;
1725 route->route.protocol = RTPROT_STATIC;
1726 route->route.srcSet = false;
1727 route->route.gwSet = false;
1728 route->route.dstSet = false;
1730 route->route.dstSet = true;
1731 route->route.dstStore = *dst;
1733 route->route.del_similar = false;
1734 route->route.blackhole = true;
1735 } else if (dst && !gw) { /* 2 */
1736 route->active = true;
1737 route->route.family = AF_INET;
1738 route->route.rttable = table;
1739 route->route.flags = !networkRoute ? RTNH_F_ONLINK /* 2 */ : 0 /* 2* */;
1740 route->route.scope = RT_SCOPE_LINK;
1741 route->route.if_index = if_index;
1742 route->route.metric = 0;
1743 route->route.protocol = RTPROT_STATIC;
1744 route->route.srcSet = false;
1745 route->route.gwSet = false;
1746 route->route.dstSet = true;
1747 route->route.dstStore = *dst;
1748 route->route.del_similar = false;
1749 route->route.blackhole = false;
1750 } else if (dst && gw) { /* 3 */
1751 route->active = true;
1752 route->route.family = AF_INET;
1753 route->route.rttable = table;
1754 route->route.flags = 0;
1755 route->route.scope = RT_SCOPE_UNIVERSE;
1756 route->route.if_index = if_index;
1757 route->route.metric = 0;
1758 route->route.protocol = RTPROT_STATIC;
1759 route->route.srcSet = false;
1760 route->route.gwSet = true;
1761 route->route.gwStore = *gw;
1762 route->route.dstSet = true;
1763 route->route.dstStore = *dst;
1764 route->route.del_similar = false;
1765 route->route.blackhole = false;
1767 /* no destination set */
1768 route->active = false;
1769 olsr_syslog(OLSR_LOG_ERR, "No route destination specified in %s", __FUNCTION__);
1775 * Setup default route for the best egress interface
1777 * When there is no best egress link, then a blackhole route is setup to prevent
1778 * looping smart gateway tunnel traffic.
1780 * @param phase the phase of the change (startup/runtime/shutdown)
1782 static void configureBestEgressLinkRoute(enum sgw_multi_change_phase phase) {
1783 bool force = MSGW_ROUTE_FORCED(phase);
1786 * bestEgressLinkPrevious bestEgressLink Action
1788 * NULL x add new route
1789 * x NULL remove old route
1790 * x x remove old route && add new routes
1793 if (!bestEgressLinkPrevious && !bestEgressLink && !force) {
1797 memcpy(&bestEgressLinkPreviousRoute, &bestEgressLinkRoute, sizeof(bestEgressLinkPreviousRoute));
1799 determineEgressLinkRoute( //
1800 &bestEgressLinkRoute, // route
1801 false, // networkRoute
1802 !bestEgressLink ? 0 : bestEgressLink->if_index, // if_index
1803 (!bestEgressLink || !bestEgressLink->bwCurrent.gatewaySet) ? NULL : &bestEgressLink->bwCurrent.gateway, // gw
1804 &ipv4_slash_0_route, // dst
1805 olsr_cnf->smart_gw_offset_tables // table
1809 bool routeChanged = //
1810 (bestEgressLinkPreviousRoute.active != bestEgressLinkRoute.active) || //
1811 memcmp(&bestEgressLinkPreviousRoute.route, &bestEgressLinkRoute.route, sizeof(bestEgressLinkRoute.route));
1813 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1814 programRoute(false, &bestEgressLinkPreviousRoute, "best egress link");
1817 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1818 programRoute(true, &bestEgressLinkRoute, "best egress link");
1824 * Setup network (when relevant) and default routes for the every egress
1827 * @param phase the phase of the change (startup/runtime/shutdown)
1829 static void configureEgressLinkRoutes(enum sgw_multi_change_phase phase) {
1830 bool force = MSGW_ROUTE_FORCED(phase);
1832 /* egress interfaces */
1833 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1835 if (!egress_if->bwNetworkChanged && !egress_if->bwGatewayChanged && !egress_if->upChanged && !force) {
1836 /* no relevant change */
1841 if (egress_if->bwNetworkChanged || force) {
1844 struct sgw_route_info networkRoutePrevious = egress_if->networkRouteCurrent;
1846 if (!egress_if->bwCurrent.networkSet || !egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
1847 memset(&egress_if->networkRouteCurrent, 0, sizeof(egress_if->networkRouteCurrent));
1848 egress_if->networkRouteCurrent.active = false;
1850 determineEgressLinkRoute( //
1851 &egress_if->networkRouteCurrent, // route
1852 true,// networkRoute
1853 egress_if->if_index, // if_index
1855 &egress_if->bwCurrent.network, // dst
1856 egress_if->tableNr // table
1861 (networkRoutePrevious.active != egress_if->networkRouteCurrent.active) || //
1862 memcmp(&networkRoutePrevious.route, &egress_if->networkRouteCurrent.route, sizeof(egress_if->networkRouteCurrent.route));
1864 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1865 programRoute(false, &networkRoutePrevious, egress_if->name);
1868 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1869 programRoute(true, &egress_if->networkRouteCurrent, egress_if->name);
1874 if (egress_if->bwGatewayChanged || force) {
1877 struct sgw_route_info egressRoutePrevious = egress_if->egressRouteCurrent;
1879 if (!egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
1880 memset(&egress_if->egressRouteCurrent, 0, sizeof(egress_if->egressRouteCurrent));
1881 egress_if->egressRouteCurrent.active = false;
1883 determineEgressLinkRoute( //
1884 &egress_if->egressRouteCurrent, // route
1885 false,// networkRoute
1886 egress_if->if_index, // if_index
1887 !egress_if->bwCurrent.gatewaySet ? NULL : &egress_if->bwCurrent.gateway, // gw
1888 &ipv4_slash_0_route, // dst
1889 egress_if->tableNr // table
1894 (egressRoutePrevious.active != egress_if->egressRouteCurrent.active) || //
1895 memcmp(&egressRoutePrevious, &egress_if->egressRouteCurrent, sizeof(egress_if->egressRouteCurrent));
1897 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1898 programRoute(false, &egressRoutePrevious, egress_if->name);
1901 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1902 programRoute(true, &egress_if->egressRouteCurrent, egress_if->name);
1906 next: egress_if = egress_if->next;
1911 * Multi-Smart-Gateway Status Overview
1914 #define IPNONE ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0" : "::")
1915 #define MASKNONE ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0/0" : "::/0")
1916 #define IPLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.1" : "::1")
1917 #define MASKLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.0/8" : "::1/128")
1920 * Print a timestamp to a file
1924 static void printDate(FILE * f) {
1930 tm_info = localtime(&timer);
1932 strftime(buffer, sizeof(buffer), "%B %d, %Y at %H:%M:%S", tm_info);
1933 fprintf(f, "%s", buffer);
1937 * Write multi-smart-gateway status file
1940 * # multi-smart-gateway status overview, generated on October 10, 2014 at 08:27:15
1942 * #Originator Prefix Uplink Downlink PathCost Type Interface Gateway Cost
1943 * 127.0.0.1 127.0.0.0/8 0 0 4294967295 egress ppp0 0.0.0.0 9223372036854775807
1944 * 127.0.0.1 127.0.0.0/8 0 0 4294967295 egress eth1 192.168.0.1 9223372036854775807
1945 * *0.0.0.0 0.0.0.0/0 290 1500 1024 olsr tnl_4094 0.0.0.0 2182002287
1948 * @param phase the phase of the change (startup/runtime/shutdown)
1950 static void writeProgramStatusFile(enum sgw_multi_change_phase phase) {
1951 /* # Orig Prefx Upl Dwn PathC Type Intfc Gw Cost */
1952 static const char * fmt_header = "%s%-16s %-33s %-8s %-8s %-10s %-16s %-16s %-16s %s\n";
1953 static const char * fmt_values = "%s%-16s %-33s %-8u %-8u %-10u %-16s %-16s %-16s %llu\n";
1955 char * fileName = olsr_cnf->smart_gw_status_file;
1958 if (!fileName || (fileName[0] == '\0')) {
1962 if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1967 fp = fopen(fileName, "w");
1969 olsr_syslog(OLSR_LOG_ERR, "Could not write to %s", fileName);
1973 fprintf(fp, "# OLSRd Multi-Smart-Gateway Status Overview\n");
1974 fprintf(fp, "# Generated on ");
1976 fprintf(fp, "\n\n");
1979 fprintf(fp, fmt_header, "#", "Originator", "Prefix", "Uplink", "Downlink", "PathCost", "Type", "Interface", "Gateway", "Cost");
1981 /* egress interfaces */
1983 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1985 struct ipaddr_str gwStr;
1986 const char * gw = !egress_if->bwCurrent.gatewaySet ? IPNONE : olsr_ip_to_string(&gwStr, &egress_if->bwCurrent.gateway);
1987 bool selected = bestOverallLink.valid && !bestOverallLink.isOlsr && (bestOverallLink.link.egress == egress_if);
1989 fprintf(fp, fmt_values, //
1990 selected ? "*" : " ", //selected
1991 IPLOCAL, // Originator
1992 MASKLOCAL, // Prefix
1993 egress_if->bwCurrent.egressUk, // Uplink
1994 egress_if->bwCurrent.egressDk, // Downlink
1995 egress_if->bwCurrent.path_cost, // PathCost
1997 egress_if->name, // Interface
1999 egress_if->bwCurrent.costs // Cost
2002 egress_if = egress_if->next;
2008 struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
2009 struct gateway_entry * gw = !gwContainer ? NULL : gwContainer->gw;
2010 struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
2011 struct tc_entry* tc = !gw ? NULL : olsr_lookup_tc_entry(&gw->originator);
2013 struct ipaddr_str originatorStr;
2014 const char * originator = !gw ? IPNONE : olsr_ip_to_string(&originatorStr, &gw->originator);
2015 struct ipaddr_str prefixIpStr;
2016 const char * prefixIPStr = !gw ? IPNONE : olsr_ip_to_string(&prefixIpStr, &gw->external_prefix.prefix);
2017 uint8_t prefix_len = !gw ? 0 : gw->external_prefix.prefix_len;
2018 struct interfaceName * tunnelName = !gw ? NULL : find_interfaceName(gw);
2019 struct ipaddr_str tunnelGwStr;
2020 const char * tunnelGw = !tunnel ? IPNONE : olsr_ip_to_string(&tunnelGwStr, &tunnel->target);
2021 bool selected = bestOverallLink.valid && bestOverallLink.isOlsr;
2023 char prefix[strlen(prefixIPStr) + 1 + 3 + 1];
2024 snprintf(prefix, sizeof(prefix), "%s/%d", prefixIPStr, prefix_len);
2026 fprintf(fp, fmt_values, //
2027 selected ? "*" : " ", // selected
2028 originator, // Originator
2029 !gw ? MASKNONE : prefix, // Prefix IP
2030 !gw ? 0 : gw->uplink, // Uplink
2031 !gw ? 0 : gw->downlink, // Downlink
2032 (!gw || !tc) ? ROUTE_COST_BROKEN : tc->path_cost, // PathCost
2034 !tunnelName ? "none" : tunnelName->name, // Interface
2035 tunnelGw, // Gateway
2036 !gw ? INT64_MAX : gw->path_cost // Cost
2044 * Report a new gateway with its most relevant parameters in the syslog
2046 static void reportNewGateway(void) {
2047 if (!bestOverallLink.valid) {
2048 /* best overall link is invalid (none) */
2049 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: none");
2053 if (!bestOverallLink.isOlsr) {
2054 /* best overall link is an egress interface */
2055 struct ipaddr_str gwStr;
2056 const char * gw = !bestOverallLink.link.egress->bwCurrent.gatewaySet ? //
2058 olsr_ip_to_string(&gwStr, &bestOverallLink.link.egress->bwCurrent.gateway);
2060 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
2061 bestOverallLink.link.egress->name, //
2062 !gw ? "" : "via ", //
2063 !gw ? "" : gwStr.buf, //
2065 bestOverallLink.link.egress->bwCurrent.egressUk, //
2066 bestOverallLink.link.egress->bwCurrent.egressDk, //
2067 bestOverallLink.link.egress->bwCurrent.path_cost);
2071 /* best overall link is an olsr (tunnel) interface */
2073 struct tc_entry* tc = olsr_lookup_tc_entry(&bestOverallLink.link.olsr->originator);
2075 char ifNameBuf[IFNAMSIZ];
2076 const char * ifName = if_indextoname(bestOverallLink.olsrTunnelIfIndex, ifNameBuf);
2078 struct ipaddr_str gwStr;
2079 const char * gw = olsr_ip_to_string(&gwStr, &bestOverallLink.link.olsr->originator);
2081 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
2082 !ifName ? "none" : ifName, //
2083 !gw ? "" : "via ", //
2084 !gw ? "" : gwStr.buf, //
2086 bestOverallLink.link.olsr->uplink, //
2087 bestOverallLink.link.olsr->downlink, //
2088 !tc ? ROUTE_COST_BROKEN : tc->path_cost);
2093 * Process changes that are relevant to egress interface: changes to the
2094 * egress interfaces themselves and to the smart gateway that is chosen by olsrd
2096 * @param egressChanged true when an egress interface changed
2097 * @param olsrChanged true when the smart gateway changed
2098 * @param phase the phase of the change (startup/runtime/shutdown)
2100 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
2101 bool bestEgressChanged = false;
2102 bool bestOverallChanged = false;
2103 bool force = MSGW_ROUTE_FORCED(phase);
2106 (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
2107 (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
2108 (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
2110 if (!egressChanged && !olsrChanged && !force) {
2114 assert(multi_gateway_mode());
2116 if (egressChanged || force) {
2117 bestEgressChanged = determineBestEgressLink(phase);
2118 configureEgressLinkRoutes(phase);
2121 if (olsrChanged || bestEgressChanged || force) {
2122 bestOverallChanged = determineBestOverallLink(phase);
2125 if (!bestEgressChanged && !bestOverallChanged && !force) {
2129 if (bestOverallChanged || force) {
2130 setupDefaultGatewayOverrideRoutes(phase);
2133 if (bestEgressChanged || force) {
2134 configureBestEgressLinkRoute(phase);
2137 if (bestOverallChanged || force) {
2141 writeProgramStatusFile(phase);
2143 out: if (egressChanged) {
2144 /* clear the 'changed' flags of egress interfaces */
2145 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2147 egress_if->upChanged = false;
2149 egress_if->bwCostsChanged = false;
2150 egress_if->bwNetworkChanged = false;
2151 egress_if->bwGatewayChanged = false;
2152 egress_if->bwChanged = false;
2154 egress_if = egress_if->next;
2159 #endif /* __linux__ */