2 * The olsr.org Optimized Link-State Routing daemon (olsrd)
4 * (c) by the OLSR project
6 * See our Git repository to find out who worked on this file
7 * and thus is a copyright holder on it.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
21 * * Neither the name of olsr.org, olsrd nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
38 * Visit http://www.olsr.org for more information.
40 * If you find this software useful feel free to make a donation
41 * to the project. For more information see the website or contact
42 * the copyright holders.
48 #include "common/avl.h"
53 #include "olsr_cookie.h"
54 #include "scheduler.h"
55 #include "kernel_routes.h"
56 #include "kernel_tunnel.h"
58 #include "duplicate_set.h"
60 #include "gateway_default_handler.h"
61 #include "gateway_list.h"
63 #include "gateway_costs.h"
64 #include "egressTypes.h"
65 #include "egressFile.h"
69 #include <linux/rtnetlink.h>
71 #include <sys/ioctl.h>
74 * Defines for the multi-gateway script
77 #define SCRIPT_MODE_CLEANUP "cleanup"
78 #define SCRIPT_MODE_GENERIC "generic"
79 #define SCRIPT_MODE_OLSRIF "olsrif"
80 #define SCRIPT_MODE_SGWSRVTUN "sgwsrvtun"
81 #define SCRIPT_MODE_EGRESSIF "egressif"
82 #define SCRIPT_MODE_SGWTUN "sgwtun"
84 /* ipv4 prefix 0.0.0.0/0 */
85 static struct olsr_ip_prefix ipv4_slash_0_route;
87 /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
88 static struct olsr_ip_prefix ipv4_slash_1_routes[2];
90 /** the gateway tree */
91 struct avl_tree gateway_tree;
94 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
96 /** gateway container cookie */
97 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
99 /** the gateway netmask for the HNA with zero bandwidth */
100 static uint8_t smart_gateway_netmask_zero[sizeof(union olsr_ip_addr)];
102 /** the gateway netmask for the HNA */
103 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
105 /** the gateway handler/plugin */
106 static struct olsr_gw_handler *gw_handler;
108 /** the IPv4 gateway list */
109 struct gw_list gw_list_ipv4;
111 /** the IPv6 gateway list */
112 struct gw_list gw_list_ipv6;
114 /** the current IPv4 gateway */
115 static struct gw_container_entry *current_ipv4_gw;
117 /** the current IPv6 gateway */
118 static struct gw_container_entry *current_ipv6_gw;
120 /** interface names for smart gateway tunnel interfaces, IPv4 */
121 struct interfaceName * sgwTunnel4InterfaceNames;
123 /** interface names for smart gateway tunnel interfaces, IPv6 */
124 struct interfaceName * sgwTunnel6InterfaceNames;
126 /** the timer for proactive takedown */
127 static struct timer_entry *gw_takedown_timer;
129 struct BestOverallLink {
133 struct sgw_egress_if * egress;
134 struct gateway_entry * olsr;
136 int olsrTunnelIfIndex;
139 static struct sgw_egress_if * bestEgressLinkPrevious = NULL;
140 static struct sgw_egress_if * bestEgressLink = NULL;
142 struct sgw_route_info bestEgressLinkPreviousRoute;
143 struct sgw_route_info bestEgressLinkRoute;
145 struct sgw_route_info bestOverallLinkPreviousRoutes[2];
146 struct sgw_route_info bestOverallLinkRoutes[2];
148 static struct BestOverallLink bestOverallLinkPrevious;
149 static struct BestOverallLink bestOverallLink;
151 static bool olsrInterfacesAllDown = false;
154 * Forward Declarations
157 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
158 static void writeProgramStatusFile(enum sgw_multi_change_phase phase);
159 static bool isInterfaceUp(int if_index);
166 * @return true when all olsr interfaces are down
168 static bool allOlsrInterfacesDown(struct olsrd_config * cfg) {
169 struct olsr_if * ifn;
171 for (ifn = cfg->interfaces; ifn; ifn = ifn->next) {
176 if (isInterfaceUp(ifn->interf->if_index)) {
185 * @return the gateway 'server' tunnel name to use
187 static inline const char * server_tunnel_name(void) {
188 return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
192 * Convert the netmask of the HNA (in the form of an IP address) to a HNA
195 * @param mask the netmask of the HNA (in the form of an IP address)
196 * @param prefixlen the prefix length
197 * @return a pointer to the HNA
199 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
200 return (((uint8_t *)mask) + ((prefixlen+7)/8));
204 * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
205 * to an uplink/downlink speed value
207 * @param value the encoded 1 byte transport value
208 * @return the uplink/downlink speed value (in kbit/s)
210 static uint32_t deserialize_gw_speed(uint8_t value) {
218 if (value == UINT8_MAX) {
219 /* maximum value: also return maximum value */
220 return MAX_SMARTGW_SPEED;
223 speed = (value >> 3) + 1;
233 * Convert an uplink/downlink speed value into an encoded 1 byte transport
234 * value (5 bits mantissa, 3 bits exponent)
236 * A bandwidth of 1 will alias onto a bandwidth of 2.
238 * @param speed the uplink/downlink speed value (in kbit/s)
239 * @return value the encoded 1 byte transport value
241 static uint8_t serialize_gw_speed(uint32_t speed) {
252 if (speed >= MAX_SMARTGW_SPEED) {
256 while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
260 return ((speed - 1) << 3) | exp;
264 * Find an interfaceName struct corresponding to a certain gateway
265 * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
267 * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
268 * @return a pointer to the struct, or NULL when not found
270 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
271 struct interfaceName * sgwTunnelInterfaceNames;
274 if (!multi_gateway_mode()) {
278 assert(sgwTunnel4InterfaceNames);
279 assert(sgwTunnel6InterfaceNames);
281 sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
282 while (i < olsr_cnf->smart_gw_use_count) {
283 struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
294 * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
296 * @param gw pointer to the gateway
297 * @param name pointer to output buffer (length IFNAMSIZ)
298 * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
300 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
301 static uint32_t counter = 0;
305 assert(interfaceName);
307 memset(name, 0, IFNAMSIZ);
309 if (multi_gateway_mode()) {
310 struct interfaceName * ifn = find_interfaceName(NULL);
313 strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
314 *interfaceName = ifn;
319 /* do not return, fall-through to classic naming as fallback */
322 snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
323 *interfaceName = NULL;
327 * Set an olsr ipip tunnel name that is used by a certain gateway as unused
329 * @param gw pointer to the gateway
331 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
332 struct interfaceName * ifn;
334 if (!multi_gateway_mode()) {
340 ifn = find_interfaceName(gw);
348 * Run the multi-gateway script/
350 * @param mode the mode (see SCRIPT_MODE_* defines)
351 * @param addMode true to add policy routing, false to remove it
352 * @param ifname the interface name (optional)
353 * @param tableNr the routing table number (optional)
354 * @param ruleNr the IP rule number/priority (optional)
355 * @param bypassRuleNr the bypass IP rule number/priority (optional)
356 * @return true when successful
358 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
362 assert(!strcmp(mode, SCRIPT_MODE_CLEANUP) //
363 || !strcmp(mode, SCRIPT_MODE_GENERIC) //
364 || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
365 || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
366 || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
367 || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
370 assert(strcmp(mode, SCRIPT_MODE_CLEANUP) //
371 || (!strcmp(mode, SCRIPT_MODE_CLEANUP) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
373 assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
374 || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
376 assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
377 || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
379 assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
380 || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
382 assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
383 || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
385 assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
386 || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
388 abuf_init(&buf, 1024);
390 abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
392 abuf_appendf(&buf, " \"%s\"", olsr_cnf->smart_gw_instance_id);
394 abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
396 abuf_appendf(&buf, " \"%s\"", mode);
398 abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
401 abuf_appendf(&buf, " \"%s\"", ifName);
405 abuf_appendf(&buf, " \"%u\"", tableNr);
409 abuf_appendf(&buf, " \"%u\"", ruleNr);
413 abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
424 * Cleanup multi-gateway iptables and ip rules
426 * @param add true to add policy routing, false to remove it
427 * @return true when successful
429 static bool multiGwRulesCleanup(bool add) {
430 return multiGwRunScript(SCRIPT_MODE_CLEANUP, add, NULL, 0, 0, 0);
434 * Setup generic multi-gateway iptables and ip rules
436 * @param add true to add policy routing, false to remove it
437 * @return true when successful
439 static bool multiGwRulesGeneric(bool add) {
440 return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
444 * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
446 * @param add true to add policy routing, false to remove it
447 * @return true when successful
449 static bool multiGwRulesOlsrInterfaces(bool add) {
451 struct olsr_if * ifn;
454 for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
455 if (!multiGwRunScript( //
456 SCRIPT_MODE_OLSRIF,//
461 olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
474 * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
476 * @param add true to add policy routing, false to remove it
477 * @return true when successful
479 static bool multiGwRulesSgwServerTunnel(bool add) {
480 return multiGwRunScript( //
481 SCRIPT_MODE_SGWSRVTUN,//
483 server_tunnel_name(), //
484 olsr_cnf->smart_gw_offset_tables, //
485 olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
491 * Setup multi-gateway iptables and ip rules for all egress interfaces.
493 * @param add true to add policy routing, false to remove it
494 * @return true when successful
496 static bool multiGwRulesEgressInterfaces(bool add) {
499 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
501 if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
508 egress_if = egress_if->next;
515 * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
517 * @param add true to add policy routing, false to remove it
518 * @return true when successful
520 static bool multiGwRulesSgwTunnels(bool add) {
524 while (i < olsr_cnf->smart_gw_use_count) {
525 struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
526 if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
540 * Process interface up/down events for non-olsr interfaces, which are egress
543 * @param if_index the index of the interface
544 * @param flag the up/down event
546 static void doEgressInterface(int if_index, enum olsr_ifchg_flag flag) {
549 char ifname[IF_NAMESIZE];
550 struct sgw_egress_if * egress_if;
553 * we need to get the name of the interface first because the interface
554 * might be hot-plugged _after_ olsrd has started
556 if (!if_indextoname(if_index, ifname)) {
557 /* not a known OS interface */
561 egress_if = findEgressInterface(ifname);
563 /* not a known egress interface */
567 egress_if->if_index = if_index;
569 if (egress_if->upCurrent) {
570 /* interface is already up: no change */
574 egress_if->upPrevious = egress_if->upCurrent;
575 egress_if->upCurrent = true;
576 egress_if->upChanged = true;
578 egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
582 case IFCHG_IF_REMOVE: {
584 * we need to find the egress interface by if_index because we might
585 * be too late; the kernel could already have removed the interface
586 * in which case we'd get a NULL ifname here if we'd try to call
589 struct sgw_egress_if * egress_if = findEgressInterfaceByIndex(if_index);
591 /* not a known egress interface */
595 if (!egress_if->upCurrent) {
596 /* interface is already down: no change */
600 egress_if->upPrevious = egress_if->upCurrent;
601 egress_if->upCurrent = false;
602 egress_if->upChanged = true;
604 egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
608 case IFCHG_IF_UPDATE:
613 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_RUNTIME);
621 * Callback for tunnel interface monitoring which will set the route into the tunnel
622 * when the interface comes up again.
624 * @param if_index the interface index
625 * @param ifh the interface (NULL when not an olsr interface)
626 * @param flag interface change flags
628 static void smartgw_tunnel_monitor(int if_index, struct interface_olsr *ifh, enum olsr_ifchg_flag flag) {
629 if (!ifh && multi_gateway_mode()) {
630 /* non-olsr interface in multi-sgw mode */
631 doEgressInterface(if_index, flag);
635 * The best gateway must always be re-evaluated since olsr and/or egress interfaces might have
636 * changed their UP/DOWN status
638 doRoutesMultiGw(true, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
644 * Timer callback to expire a gateway entry
646 * @param ptr a pointer to the smart gateway HNA to expire (struct gateway_entry*)
648 static void expire_gateway_handler(void *ptr) {
649 struct gateway_entry *gw = ptr;
653 /* remove gateway entry */
654 olsr_delete_gateway_entry(&gw->originator, gw->external_prefix.prefix_len, false);
658 * Timer callback to remove and cleanup a gateway entry
662 static void cleanup_gateway_handler(void *ptr) {
663 struct gateway_entry *gw = ptr;
665 if (gw->ipv4 || gw->ipv6) {
666 /* do not clean it up when it is in use */
670 /* remove gateway entry */
671 avl_delete(&gateway_tree, &gw->node);
672 olsr_cookie_free(gateway_entry_mem_cookie, gw);
676 * Remove a gateway from a gateway list.
678 * @param gw_list a pointer to the gateway list
679 * @param ipv4 true when dealing with an IPv4 gateway / gateway list
680 * @param gw a pointer to the gateway to remove from the list
682 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
684 struct interfaceName * ifn = find_interfaceName(gw->gw);
686 olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
688 olsr_os_del_ipip_tunnel(gw->tunnel);
689 set_unused_iptunnel_name(gw->gw);
693 olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
697 * Remove expensive gateways from the gateway list.
698 * It uses the smart_gw_takedown_percentage configuration parameter
700 * @param gw_list a pointer to the gateway list
701 * @param ipv4 true when dealing with an IPv4 gateway / gateway list
702 * @param current_gw the current gateway
704 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
705 int64_t current_gw_cost_boundary;
708 * exit immediately when takedown is disabled, there is no current gateway, or
709 * when there is only a single gateway
711 if ((olsr_cnf->smart_gw_takedown_percentage == 0) || !current_gw || (gw_list->count <= 1)) {
715 /* get the cost boundary */
716 current_gw_cost_boundary = current_gw->gw->path_cost;
717 if (olsr_cnf->smart_gw_takedown_percentage < 100) {
718 if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
719 current_gw_cost_boundary = ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
721 /* perform scaling because otherwise the percentage calculation can overflow */
722 current_gw_cost_boundary = (((current_gw_cost_boundary ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
726 /* loop while we still have gateways */
727 while (gw_list->count > 1) {
728 /* get the worst gateway */
729 struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
736 /* exit when it's the current gateway */
737 if (worst_gw == current_gw) {
742 * exit when it (and further ones; the list is sorted on costs) has lower
743 * costs than the boundary costs
745 if (worst_gw->gw && (worst_gw->gw->path_cost < current_gw_cost_boundary)) {
749 /* it's too expensive: take it down */
750 removeGatewayFromList(gw_list, ipv4, worst_gw);
755 * Timer callback for proactive gateway takedown
757 * @param unused unused
759 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
760 takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
761 takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
769 * Initialize gateway system
771 int olsr_init_gateways(void) {
774 memset(&bestEgressLinkPreviousRoute, 0, sizeof(bestEgressLinkPreviousRoute));
775 memset(&bestEgressLinkRoute, 0, sizeof(bestEgressLinkRoute));
776 memset(bestOverallLinkPreviousRoutes, 0, sizeof(bestOverallLinkPreviousRoutes));
777 memset(bestOverallLinkRoutes, 0, sizeof(bestOverallLinkRoutes));
779 /* ipv4 prefix 0.0.0.0/0 */
780 memset(&ipv4_slash_0_route, 0, sizeof(ipv4_slash_0_route));
782 /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
783 memset(&ipv4_slash_1_routes, 0, sizeof(ipv4_slash_1_routes));
784 ipv4_slash_1_routes[0].prefix.v4.s_addr = htonl(0x00000000);
785 ipv4_slash_1_routes[0].prefix_len = 1;
786 ipv4_slash_1_routes[1].prefix.v4.s_addr = htonl(0x80000000);
787 ipv4_slash_1_routes[1].prefix_len = 1;
789 gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
790 olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
792 gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
793 olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
795 avl_init(&gateway_tree, avl_comp_default);
797 olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
798 olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
800 sgwTunnel4InterfaceNames = NULL;
801 sgwTunnel6InterfaceNames = NULL;
802 memset(&bestOverallLinkPrevious, 0, sizeof(bestOverallLinkPrevious));
803 memset(&bestOverallLink, 0, sizeof(bestOverallLink));
805 if (multi_gateway_mode()) {
807 struct sgw_egress_if * egressif;
808 unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
810 /* Initialise the egress interfaces */
811 /* setup the egress interface name/mark pairs */
813 egressif = olsr_cnf->smart_gw_egress_interfaces;
815 egressif->if_index = if_nametoindex(egressif->name);
817 egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
818 egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
819 egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
821 egressif->upPrevious = egressif->upCurrent = olsr_if_isup(egressif->name);
822 egressif->upChanged = (egressif->upPrevious != egressif->upCurrent);
824 egressBwClear(&egressif->bwPrevious, egressif->upPrevious);
825 egressBwClear(&egressif->bwCurrent, egressif->upCurrent);
826 egressif->bwCostsChanged = egressBwCostsChanged(egressif);
827 egressif->bwNetworkChanged = egressBwNetworkChanged(egressif);
828 egressif->bwGatewayChanged = egressBwGatewayChanged(egressif);
829 egressif->bwChanged = egressBwChanged(egressif);
831 egressif->inEgressFile = false;
833 egressif = egressif->next;
836 assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
838 /* setup the SGW tunnel name/mark pairs */
839 sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
840 sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
841 for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
842 struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
843 uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
844 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;
847 ifn->tableNr = tableNr;
848 ifn->ruleNr = ruleNr;
849 ifn->bypassRuleNr = 0;
850 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
852 ifn = &sgwTunnel6InterfaceNames[i];
854 ifn->tableNr = tableNr;
855 ifn->ruleNr = ruleNr;
856 ifn->bypassRuleNr = 0;
857 snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
861 current_ipv4_gw = NULL;
862 current_ipv6_gw = NULL;
866 refresh_smartgw_netmask();
868 /* initialize default gateway handler */
869 gw_handler = &gw_def_handler;
874 * There appears to be a kernel bug in some kernels (at least in the 3.0
875 * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
876 * initialising the IPIP server tunnel (loading the IPIP module), so we retry
877 * a few times before giving up
879 while (retries-- > 0) {
880 if (!olsr_os_init_iptunnel(server_tunnel_name())) {
885 olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
895 * Startup gateway system
897 int olsr_startup_gateways(void) {
900 if (!multi_gateway_mode()) {
901 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
905 ok = ok && multiGwRulesCleanup(true);
906 ok = ok && multiGwRulesGeneric(true);
907 ok = ok && multiGwRulesSgwServerTunnel(true);
908 ok = ok && multiGwRulesOlsrInterfaces(true);
909 ok = ok && multiGwRulesEgressInterfaces(true);
910 ok = ok && multiGwRulesSgwTunnels(true);
912 olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
913 olsr_shutdown_gateways();
918 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
920 olsr_add_ifchange_handler(smartgw_tunnel_monitor);
922 /* Check egress interfaces up status to compensate for a race: the interfaces
923 * can change status between initialising their data structures and
924 * registering the tunnel monitor */
926 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
928 bool upCurrent = olsr_if_isup(egress_if->name);
930 if (upCurrent != egress_if->upCurrent) {
931 int idx = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
932 enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
933 smartgw_tunnel_monitor(idx, NULL, flag);
936 egress_if = egress_if->next;
940 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
941 /* start gateway takedown timer */
942 olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
949 * Shutdown gateway tunnel system
951 void olsr_shutdown_gateways(void) {
952 if (!multi_gateway_mode()) {
953 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
957 if (olsr_cnf->smart_gw_takedown_percentage > 0) {
958 /* stop gateway takedown timer */
959 olsr_stop_timer(gw_takedown_timer);
960 gw_takedown_timer = NULL;
963 olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
967 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
969 egress_if->upPrevious = egress_if->upCurrent;
970 egress_if->upCurrent = false;
971 egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
973 egress_if->bwPrevious = egress_if->bwCurrent;
974 egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
975 egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
976 egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
977 egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
978 egress_if->bwChanged = egressBwChanged(egress_if);
980 egress_if->inEgressFile = false;
982 egress_if = egress_if->next;
985 doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
987 (void)multiGwRulesSgwTunnels(false);
988 (void)multiGwRulesEgressInterfaces(false);
989 (void)multiGwRulesOlsrInterfaces(false);
990 (void)multiGwRulesSgwServerTunnel(false);
991 (void)multiGwRulesGeneric(false);
992 (void)multiGwRulesCleanup(false);
996 * Cleanup gateway tunnel system
998 void olsr_cleanup_gateways(void) {
999 struct gateway_entry * tree_gw;
1000 struct gw_container_entry * gw;
1002 /* remove all gateways in the gateway tree that are not the active gateway */
1003 OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
1004 if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
1005 olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
1007 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
1009 /* remove all active IPv4 gateways (should be at most 1 now) */
1010 OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
1012 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
1015 OLSR_FOR_ALL_GWS_END(gw);
1017 /* remove all active IPv6 gateways (should be at most 1 now) */
1018 OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
1020 olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
1023 OLSR_FOR_ALL_GWS_END(gw);
1025 /* there should be no more gateways */
1026 assert(!avl_walk_first(&gateway_tree));
1027 assert(!current_ipv4_gw);
1028 assert(!current_ipv6_gw);
1030 olsr_os_cleanup_iptunnel(server_tunnel_name());
1033 gw_handler->cleanup();
1036 if (sgwTunnel4InterfaceNames) {
1037 free(sgwTunnel4InterfaceNames);
1038 sgwTunnel4InterfaceNames = NULL;
1040 if (sgwTunnel6InterfaceNames) {
1041 free(sgwTunnel6InterfaceNames);
1042 sgwTunnel6InterfaceNames = NULL;
1045 olsr_gw_list_cleanup(&gw_list_ipv6);
1046 olsr_gw_list_cleanup(&gw_list_ipv4);
1047 olsr_free_cookie(gw_container_entry_mem_cookie);
1048 olsr_free_cookie(gateway_entry_mem_cookie);
1052 * Triggers the first lookup of a gateway.
1054 void olsr_trigger_inetgw_startup(void) {
1056 gw_handler->startup();
1060 * Print debug information about gateway entries
1063 void olsr_print_gateway_entries(void) {
1064 struct ipaddr_str buf;
1065 struct gateway_entry *gw;
1066 const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
1068 OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
1069 OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
1070 addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
1072 OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
1073 OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
1075 olsr_ip_to_string(&buf, &gw->originator),
1076 gw->ipv4nat ? "" : " ",
1077 gw->ipv4 ? '4' : ' ',
1078 gw->ipv4nat ? "(N)" : "",
1079 (gw->ipv4 && gw->ipv6) ? ',' : ' ',
1080 gw->ipv6 ? '6' : ' ',
1083 gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
1084 } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
1086 #endif /* NODEBUG */
1093 * Apply the smart gateway modifications to an outgoing HNA
1095 * @param mask pointer to netmask of the HNA
1096 * @param prefixlen of the HNA
1097 * @param zero true to use zero bandwidth
1099 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen, bool zero) {
1100 uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1102 /* copy the current settings for uplink/downlink into the mask */
1105 zero ? &smart_gateway_netmask_zero : &smart_gateway_netmask, //
1106 (zero ? sizeof(smart_gateway_netmask_zero) : sizeof(smart_gateway_netmask)) - prefixlen / 8);
1107 if (olsr_cnf->has_ipv4_gateway) {
1108 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
1110 if (olsr_cnf->smart_gw_uplink_nat) {
1111 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
1114 if (olsr_cnf->has_ipv6_gateway) {
1115 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
1117 if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
1118 ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
1123 * SgwDynSpeed Plugin Interface
1127 * Setup the gateway netmask
1129 void refresh_smartgw_netmask(void) {
1132 /* clear the mask */
1133 memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
1135 if (olsr_cnf->smart_gw_active) {
1136 ip = (uint8_t *) &smart_gateway_netmask;
1138 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
1139 ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
1140 ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
1142 if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
1143 ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
1144 ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1145 memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1149 uint8_t *ipz = (uint8_t *) &smart_gateway_netmask_zero;
1150 memcpy(ipz, ip, sizeof(smart_gateway_netmask_zero));
1151 ipz[GW_HNA_DOWNLINK] = serialize_gw_speed(0);
1152 ipz[GW_HNA_UPLINK] = serialize_gw_speed(0);
1158 * TC/SPF/HNA Interface
1162 * Checks if a HNA prefix/netmask combination is a smart gateway
1166 * @return true if is a valid smart gateway HNA, false otherwise
1168 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1171 if (!is_prefix_inetgw(prefix)) {
1175 ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1176 return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1180 * Update a gateway_entry based on a HNA
1182 * @param originator ip of the source of the HNA
1183 * @param mask netmask of the HNA
1184 * @param prefixlen of the HNA
1185 * @param seqno the sequence number of the HNA
1186 * @param vtime the validity time of the HNA
1188 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno, olsr_reltime vtime) {
1189 struct gw_container_entry * new_gw_in_list;
1191 int64_t prev_path_cost = 0;
1192 struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1195 gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1196 gw->originator = *originator;
1197 gw->node.key = &gw->originator;
1199 avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1200 } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1201 /* ignore older HNAs */
1205 /* keep new HNA seqno */
1209 gw->path_cost = INT64_MAX;
1211 ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1212 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1213 gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1214 gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1217 gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1218 gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1221 if (olsr_cnf->ip_version == AF_INET6) {
1222 gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1224 /* do not reset prefixlength for ::ffff:0:0 HNAs */
1225 if (prefixlen == ipv6_internet_route.prefix_len) {
1226 memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1228 if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1229 && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1230 /* this is the right prefix (2000::/3), so we can copy the prefix */
1231 gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1232 memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1237 if (!gw->uplink || !gw->downlink) {
1238 olsr_delete_gateway_tree_entry(gw, FORCE_DELETE_GW_ENTRY, true);
1242 if (!gw->expire_timer) {
1243 /* start expire timer */
1244 olsr_set_timer(&gw->expire_timer, vtime, 0, false, expire_gateway_handler, gw, NULL);
1246 /* restart expire timer */
1247 olsr_change_timer(gw->expire_timer, vtime, 0, false);
1250 /* stop cleanup timer if necessary */
1251 if (gw->cleanup_timer) {
1252 olsr_stop_timer(gw->cleanup_timer);
1253 gw->cleanup_timer = NULL;
1257 prev_path_cost = gw->path_cost;
1258 gw->path_cost = gw_handler->getcosts(gw);
1260 if (prev_path_cost != gw->path_cost) {
1261 /* re-sort the gateway list when costs have changed and when it is an active gateway */
1262 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1263 if (new_gw_in_list) {
1264 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1265 assert(new_gw_in_list);
1267 if (multi_gateway_mode() && new_gw_in_list->tunnel) {
1268 /* the active gateway has changed its costs: re-evaluate egress routes */
1269 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1273 new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1274 if (new_gw_in_list) {
1275 new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1276 assert(new_gw_in_list);
1278 if (multi_gateway_mode() && new_gw_in_list->tunnel) {
1279 /* the active gateway has changed its costs: re-evaluate egress routes */
1280 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1285 /* call update handler */
1287 gw_handler->update(gw);
1291 * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1292 * Should only be called if prefix is a smart_gw prefix or if node is removed
1297 * @param immediate when set to true then the gateway is removed from the
1298 * gateway tree immediately, else it is removed on a delayed schedule.
1300 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1301 olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1305 * Delete a gateway entry .
1307 * @param gw a gateway entry from the gateway tree
1309 * @param immediate when set to true then the gateway is removed from the
1310 * gateway tree immediately, else it is removed on a delayed schedule.
1312 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1313 bool change = false;
1319 if (gw->expire_timer) {
1320 /* stop expire timer */
1321 olsr_stop_timer(gw->expire_timer);
1322 gw->expire_timer = NULL;
1325 if (immediate && gw->cleanup_timer) {
1326 /* stop timer if we have to remove immediately */
1327 olsr_stop_timer(gw->cleanup_timer);
1328 gw->cleanup_timer = NULL;
1331 if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1332 /* the gw is not scheduled for deletion */
1334 if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1337 gw->ipv4nat = false;
1338 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1341 } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1344 gw->ipv4nat = false;
1347 if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1348 bool write_status = false;
1349 struct gw_container_entry * gw_in_list;
1351 /* prevent this gateway from being chosen as the new gateway */
1353 gw->ipv4nat = false;
1356 /* handle gateway loss */
1358 gw_handler->delete(gw);
1360 /* cleanup gateway if necessary */
1361 gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1363 if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1364 olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1365 current_ipv4_gw = NULL;
1368 if (gw_in_list->tunnel) {
1369 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1371 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1373 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1374 set_unused_iptunnel_name(gw_in_list->gw);
1375 gw_in_list->tunnel = NULL;
1378 gw_in_list->gw = NULL;
1379 gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1380 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1381 write_status = true;
1384 gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1386 if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1387 olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1388 current_ipv6_gw = NULL;
1391 if (gw_in_list->tunnel) {
1392 struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1394 olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1396 olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1397 set_unused_iptunnel_name(gw_in_list->gw);
1398 gw_in_list->tunnel = NULL;
1401 gw_in_list->gw = NULL;
1402 gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1403 olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1404 write_status = true;
1408 /* remove gateway entry on a delayed schedule */
1409 olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1411 cleanup_gateway_handler(gw);
1414 /* when the current gateway was deleted, then immediately choose a new gateway */
1415 if (!current_ipv4_gw || !current_ipv6_gw) {
1417 gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1420 if (multi_gateway_mode() && write_status) {
1421 writeProgramStatusFile(GW_MULTI_CHANGE_PHASE_RUNTIME);
1423 } else if (change) {
1425 gw_handler->update(gw);
1431 * Triggers a check if the one of the gateways have been lost or has an
1434 void olsr_trigger_gatewayloss_check(void) {
1438 if (current_ipv4_gw && current_ipv4_gw->gw) {
1439 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv4_gw->gw->originator);
1440 ipv4 = (tc == NULL || tc->path_cost >= ROUTE_COST_BROKEN);
1442 if (current_ipv6_gw && current_ipv6_gw->gw) {
1443 struct tc_entry *tc = olsr_lookup_tc_entry(¤t_ipv6_gw->gw->originator);
1444 ipv6 = (tc == NULL || tc->path_cost >= ROUTE_COST_BROKEN);
1449 gw_handler->choose(ipv4, ipv6);
1454 * Gateway Plugin Functions
1458 * Sets a new internet gateway.
1460 * @param the chosen gateway
1461 * @param ipv4 set ipv4 gateway
1462 * @param ipv6 set ipv6 gateway
1463 * @return true if an error happened, false otherwise
1465 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1466 struct gateway_entry *new_gw;
1468 ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1469 ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1470 if (!ipv4 && !ipv6) {
1474 new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1476 /* the originator is not in the gateway tree, we can't set it as gateway */
1483 (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1484 (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1485 /* new gw is different than the current gw */
1487 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1488 if (new_gw_in_list) {
1489 /* new gw is already in the gw list */
1490 assert(new_gw_in_list->tunnel);
1491 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1492 current_ipv4_gw = new_gw_in_list;
1494 if (multi_gateway_mode()) {
1495 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1498 /* new gw is not yet in the gw list */
1499 char name[IFNAMSIZ];
1500 struct olsr_iptunnel_entry *new_v4gw_tunnel;
1501 struct interfaceName * interfaceName;
1503 if (olsr_gw_list_full(&gw_list_ipv4)) {
1504 /* the list is full: remove the worst active gateway */
1505 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1508 removeGatewayFromList(&gw_list_ipv4, true, worst);
1511 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1512 new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1513 if (new_v4gw_tunnel) {
1514 if (interfaceName) {
1515 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1517 olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1519 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1520 new_gw_in_list->gw = new_gw;
1521 new_gw_in_list->tunnel = new_v4gw_tunnel;
1522 current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1524 if (multi_gateway_mode()) {
1525 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1528 /* adding the tunnel failed, we try again in the next cycle */
1529 set_unused_iptunnel_name(new_gw);
1538 (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1539 /* new gw is different than the current gw */
1541 struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1542 if (new_gw_in_list) {
1543 /* new gw is already in the gw list */
1544 assert(new_gw_in_list->tunnel);
1545 olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1546 current_ipv6_gw = new_gw_in_list;
1548 if (multi_gateway_mode()) {
1549 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1552 /* new gw is not yet in the gw list */
1553 char name[IFNAMSIZ];
1554 struct olsr_iptunnel_entry *new_v6gw_tunnel;
1555 struct interfaceName * interfaceName;
1557 if (olsr_gw_list_full(&gw_list_ipv6)) {
1558 /* the list is full: remove the worst active gateway */
1559 struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1562 removeGatewayFromList(&gw_list_ipv6, false, worst);
1565 get_unused_iptunnel_name(new_gw, name, &interfaceName);
1566 new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1567 if (new_v6gw_tunnel) {
1568 if (interfaceName) {
1569 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1571 olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1573 new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1574 new_gw_in_list->gw = new_gw;
1575 new_gw_in_list->tunnel = new_v6gw_tunnel;
1576 current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1578 if (multi_gateway_mode()) {
1579 doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1582 /* adding the tunnel failed, we try again in the next cycle */
1583 set_unused_iptunnel_name(new_gw);
1589 return !ipv4 && !ipv6;
1593 * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1594 * gateway is returned
1595 * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1598 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1600 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1603 return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1607 * Process Egress Changes
1610 #define MSGW_ROUTE_ADD_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1611 #define MSGW_ROUTE_ADD_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1612 #define MSGW_ROUTE_DEL_ALLOWED(phase) ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1613 #define MSGW_ROUTE_DEL_FORCED(phase) ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1614 #define MSGW_ROUTE_FORCED(phase) ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1617 * Determine best egress link.
1618 * The list of egress interface is ordered on priority (the declaration order),
1619 * so the function will - for multiple egress links with the same costs - set the
1620 * best egress interface to the first declared one of those.
1621 * When there is no best egress interface (that is up) then the function will
1622 * set the best egress interface to NULL.
1624 * @param phase the phase of the change (startup/runtime/shutdown)
1625 * @return true when the best egress link changed or when any of its relevant
1626 * parameters has changed
1628 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1629 bool changed = false;
1630 struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1632 if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1635 struct sgw_egress_if * egress_if = bestEgress;
1637 egress_if = egress_if->next;
1640 if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs &&
1641 isInterfaceUp(egress_if->if_index))) {
1642 bestEgress = egress_if;
1645 egress_if = egress_if->next;
1648 if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1653 bestEgressLinkPrevious = bestEgressLink;
1654 bestEgressLink = bestEgress;
1656 changed = (bestEgressLinkPrevious != bestEgressLink) || //
1657 (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged));
1659 if (changed || MSGW_ROUTE_FORCED(phase)) {
1660 if (!bestEgressLink || !bestEgressLink->upCurrent) {
1661 smartgw_set_uplink(olsr_cnf, 0);
1662 smartgw_set_downlink(olsr_cnf, 0);
1664 smartgw_set_uplink(olsr_cnf, bestEgressLink->bwCurrent.egressUk);
1665 smartgw_set_downlink(olsr_cnf, bestEgressLink->bwCurrent.egressDk);
1667 refresh_smartgw_netmask();
1674 * Determine best overall link (choose egress interface over olsrd).
1676 * When there is no best overall link, the best overall link will be set to a
1677 * NULL egress interface.
1679 * @param phase the phase of the change (startup/runtime/shutdown)
1680 * @return true when the best egress link changed or when any of its relevant
1681 * parameters has changed
1683 static bool determineBestOverallLink(enum sgw_multi_change_phase phase) {
1684 struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
1685 struct gateway_entry * olsrGw = !gwContainer ? NULL : gwContainer->gw;
1687 int64_t egressCosts = !bestEgressLink ? INT64_MAX : bestEgressLink->bwCurrent.costs;
1688 int64_t olsrCosts = (!olsrGw || olsrInterfacesAllDown) ? INT64_MAX : olsrGw->path_cost;
1689 int64_t bestOverallCosts = MIN(egressCosts, olsrCosts);
1691 bestOverallLinkPrevious = bestOverallLink;
1692 if ((bestOverallCosts == INT64_MAX) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)) {
1693 bestOverallLink.valid = false;
1694 bestOverallLink.isOlsr = false;
1695 bestOverallLink.link.egress = NULL;
1696 bestOverallLink.olsrTunnelIfIndex = 0;
1697 } else if (egressCosts <= olsrCosts) {
1698 bestOverallLink.valid = bestEgressLink;
1699 bestOverallLink.isOlsr = false;
1700 bestOverallLink.link.egress = bestEgressLink;
1701 bestOverallLink.olsrTunnelIfIndex = 0;
1703 struct olsr_iptunnel_entry * tunnel;
1705 assert(gwContainer);
1707 tunnel = gwContainer->tunnel;
1709 bestOverallLink.valid = olsrGw;
1710 bestOverallLink.isOlsr = true;
1711 bestOverallLink.link.olsr = olsrGw;
1712 bestOverallLink.olsrTunnelIfIndex = !tunnel ? 0 : tunnel->if_index;
1715 return memcmp(&bestOverallLink, &bestOverallLinkPrevious, sizeof(bestOverallLink));
1718 static bool isInterfaceUp(int if_index) {
1719 char nameBuf[IF_NAMESIZE];
1723 name = if_indextoname(if_index, nameBuf);
1725 /* interface doesn't exist */
1729 if (getInterfaceLinkState(name) == LINKSTATE_DOWN) {
1733 memset(&ifr, 0, sizeof(struct ifreq));
1734 strscpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1736 /* Get flags (and check if interface exists) */
1737 if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
1741 if (ifr.ifr_flags & IFF_UP) {
1749 * Program a route (add or remove) through netlink
1751 * @param add true to add the route, false to remove it
1752 * @param route the route
1753 * @param linkName the human readable id of the route, used in error reports in
1756 static void programRoute(bool add, struct sgw_route_info * route, const char * linkName) {
1757 if (!route || !route->active) {
1761 if (!isInterfaceUp(route->route.if_index)) {
1765 if (olsr_new_netlink_route( //
1766 route->route.family, //
1767 route->route.rttable, //
1768 route->route.flags, //
1769 route->route.scope, //
1770 route->route.if_index, //
1771 route->route.metric, //
1772 route->route.protocol, //
1773 !route->route.srcSet ? NULL : &route->route.srcStore, //
1774 !route->route.gwSet ? NULL : &route->route.gwStore, //
1775 !route->route.dstSet ? NULL : &route->route.dstStore, //
1777 route->route.del_similar, //
1778 route->route.blackhole //
1780 olsr_syslog(OLSR_LOG_ERR, "Could not %s a route for the %s %s", !add ? "remove" : "add", !add ? "previous" : "current", linkName);
1781 route->active = false;
1783 route->active = add;
1788 * Determine the best overall egress/olsr interface routes.
1790 * These are a set of 2 /1 routes to override any default gateway
1791 * routes that are setup through other means such as a DHCP client.
1793 * @param routes a pointer to the array of 2 /1 routes where to store the
1794 * newly determined routes
1796 static void determineBestOverallLinkRoutes(struct sgw_route_info * routes) {
1798 union olsr_ip_addr * gw = NULL;
1800 if (!bestOverallLink.valid) {
1801 /* there is no current best overall link */
1802 } else if (!bestOverallLink.isOlsr) {
1803 /* current best overall link is an egress interface */
1804 struct sgw_egress_if * egress = bestOverallLink.link.egress;
1806 ifIndex = egress->if_index;
1807 if (egress->bwCurrent.gatewaySet) {
1808 gw = &egress->bwCurrent.gateway;
1812 /* current best overall link is an olsr tunnel interface */
1813 struct gw_container_entry * gwContainer = current_ipv4_gw;
1814 struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1817 ifIndex = tunnel->if_index;
1822 for (i = 0; i < 2; i++) {
1823 routes[i].active = false;
1828 for (i = 0; i < 2; i++) {
1829 memset(&routes[i], 0, sizeof(routes[i]));
1830 routes[i].active = true;
1831 routes[i].route.family = AF_INET;
1832 routes[i].route.rttable = olsr_cnf->rt_table;
1833 routes[i].route.flags = 0;
1834 routes[i].route.scope = !gw ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
1835 routes[i].route.if_index = ifIndex;
1836 routes[i].route.metric = 0;
1837 routes[i].route.protocol = RTPROT_STATIC;
1838 routes[i].route.srcSet = false;
1839 routes[i].route.gwSet = false;
1841 routes[i].route.gwSet = true;
1842 routes[i].route.gwStore = *gw;
1844 routes[i].route.dstSet = true;
1845 routes[i].route.dstStore = ipv4_slash_1_routes[i];
1846 routes[i].route.del_similar = false;
1847 routes[i].route.blackhole = false;
1852 * Setup default gateway override routes: a set of 2 /1 routes for the best
1855 * @param phase the phase of the change (startup/runtime/shutdown)
1857 static void setupDefaultGatewayOverrideRoutes(enum sgw_multi_change_phase phase) {
1858 bool force = MSGW_ROUTE_FORCED(phase);
1861 if (!bestOverallLinkPrevious.valid && !bestOverallLink.valid && !force) {
1865 memcpy(&bestOverallLinkPreviousRoutes, &bestOverallLinkRoutes, sizeof(bestOverallLinkPreviousRoutes));
1867 determineBestOverallLinkRoutes(bestOverallLinkRoutes);
1869 for (i = 0; i < 2; i++) {
1870 bool routeChanged = //
1871 (bestOverallLinkPreviousRoutes[i].active != bestOverallLinkRoutes[i].active) || //
1872 memcmp(&bestOverallLinkPreviousRoutes[i].route, &bestOverallLinkRoutes[i].route, sizeof(bestOverallLinkRoutes[i].route));
1874 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1875 programRoute(false, &bestOverallLinkPreviousRoutes[i], "overall best gateway");
1878 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1879 programRoute(true, &bestOverallLinkRoutes[i], "overall best gateway");
1885 * Determine the best egress interface route.
1887 * @param route a pointer to the an route where to store the
1888 * newly determined route
1889 * @param networkRoute true when the route is a network route (not an internet
1891 * @param if_index the index of the interface that the route is for
1892 * @param gw the gateway for the route
1893 * @param dst the destination for the route
1894 * @param table the routing table for the route
1896 static void determineEgressLinkRoute( //
1897 struct sgw_route_info * route, //
1898 bool networkRoute, //
1900 union olsr_ip_addr * gw, //
1901 struct olsr_ip_prefix * dst, //
1904 // ----: ip route replace|delete blackhole default table 90: !egress_if (1)
1905 // ppp0: ip route replace|delete default dev ppp0 table 90: egress_if && dst && !gw (2)
1906 // eth1: ip route replace|delete default via 192.168.0.1 dev eth1 table 90: egress_if && dst && gw (3)
1909 // eth1: ip route replace|delete to 192.168.0.0/24 dev eth1 table 90: egress_if && dst && !gw (2*)
1911 memset(route, 0, sizeof(*route));
1912 if (if_index <= 0) { /* 1 */
1913 route->active = true;
1914 route->route.family = AF_INET;
1915 route->route.rttable = table;
1916 route->route.flags = RTNH_F_ONLINK;
1917 route->route.scope = RT_SCOPE_UNIVERSE;
1918 route->route.if_index = 0;
1919 route->route.metric = 0;
1920 route->route.protocol = RTPROT_STATIC;
1921 route->route.srcSet = false;
1922 route->route.gwSet = false;
1923 route->route.dstSet = false;
1925 route->route.dstSet = true;
1926 route->route.dstStore = *dst;
1928 route->route.del_similar = false;
1929 route->route.blackhole = true;
1930 } else if (dst && !gw) { /* 2 */
1931 route->active = true;
1932 route->route.family = AF_INET;
1933 route->route.rttable = table;
1934 route->route.flags = !networkRoute ? RTNH_F_ONLINK /* 2 */ : 0 /* 2* */;
1935 route->route.scope = RT_SCOPE_LINK;
1936 route->route.if_index = if_index;
1937 route->route.metric = 0;
1938 route->route.protocol = RTPROT_STATIC;
1939 route->route.srcSet = false;
1940 route->route.gwSet = false;
1941 route->route.dstSet = true;
1942 route->route.dstStore = *dst;
1943 route->route.del_similar = false;
1944 route->route.blackhole = false;
1945 } else if (dst && gw) { /* 3 */
1946 route->active = true;
1947 route->route.family = AF_INET;
1948 route->route.rttable = table;
1949 route->route.flags = 0;
1950 route->route.scope = RT_SCOPE_UNIVERSE;
1951 route->route.if_index = if_index;
1952 route->route.metric = 0;
1953 route->route.protocol = RTPROT_STATIC;
1954 route->route.srcSet = false;
1955 route->route.gwSet = true;
1956 route->route.gwStore = *gw;
1957 route->route.dstSet = true;
1958 route->route.dstStore = *dst;
1959 route->route.del_similar = false;
1960 route->route.blackhole = false;
1962 /* no destination set */
1963 route->active = false;
1964 olsr_syslog(OLSR_LOG_ERR, "No route destination specified in %s", __FUNCTION__);
1970 * Setup default route for the best egress interface
1972 * When there is no best egress link, then a blackhole route is setup to prevent
1973 * looping smart gateway tunnel traffic.
1975 * @param phase the phase of the change (startup/runtime/shutdown)
1977 static void configureBestEgressLinkRoute(enum sgw_multi_change_phase phase) {
1978 bool force = MSGW_ROUTE_FORCED(phase);
1981 * bestEgressLinkPrevious bestEgressLink Action
1983 * NULL x add new route
1984 * x NULL remove old route
1985 * x x remove old route && add new routes
1988 if (!bestEgressLinkPrevious && !bestEgressLink && !force) {
1992 memcpy(&bestEgressLinkPreviousRoute, &bestEgressLinkRoute, sizeof(bestEgressLinkPreviousRoute));
1994 determineEgressLinkRoute( //
1995 &bestEgressLinkRoute, // route
1996 false, // networkRoute
1997 !bestEgressLink ? 0 : bestEgressLink->if_index, // if_index
1998 (!bestEgressLink || !bestEgressLink->bwCurrent.gatewaySet) ? NULL : &bestEgressLink->bwCurrent.gateway, // gw
1999 &ipv4_slash_0_route, // dst
2000 olsr_cnf->smart_gw_offset_tables // table
2004 bool routeChanged = //
2005 (bestEgressLinkPreviousRoute.active != bestEgressLinkRoute.active) || //
2006 memcmp(&bestEgressLinkPreviousRoute.route, &bestEgressLinkRoute.route, sizeof(bestEgressLinkRoute.route));
2008 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
2009 programRoute(false, &bestEgressLinkPreviousRoute, "best egress link");
2012 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
2013 programRoute(true, &bestEgressLinkRoute, "best egress link");
2019 * Setup network (when relevant) and default routes for the every egress
2022 * @param phase the phase of the change (startup/runtime/shutdown)
2024 static void configureEgressLinkRoutes(enum sgw_multi_change_phase phase) {
2025 bool force = MSGW_ROUTE_FORCED(phase);
2027 /* egress interfaces */
2028 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2030 if (!egress_if->bwNetworkChanged && !egress_if->bwGatewayChanged && !egress_if->upChanged && !force) {
2031 /* no relevant change */
2036 if (egress_if->bwNetworkChanged || force) {
2039 struct sgw_route_info networkRoutePrevious = egress_if->networkRouteCurrent;
2041 if (!egress_if->bwCurrent.networkSet || !egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
2042 memset(&egress_if->networkRouteCurrent, 0, sizeof(egress_if->networkRouteCurrent));
2043 egress_if->networkRouteCurrent.active = false;
2045 determineEgressLinkRoute( //
2046 &egress_if->networkRouteCurrent, // route
2047 true,// networkRoute
2048 egress_if->if_index, // if_index
2050 &egress_if->bwCurrent.network, // dst
2051 egress_if->tableNr // table
2056 (networkRoutePrevious.active != egress_if->networkRouteCurrent.active) || //
2057 memcmp(&networkRoutePrevious.route, &egress_if->networkRouteCurrent.route, sizeof(egress_if->networkRouteCurrent.route));
2059 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
2060 programRoute(false, &networkRoutePrevious, egress_if->name);
2063 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
2064 programRoute(true, &egress_if->networkRouteCurrent, egress_if->name);
2069 if (egress_if->bwGatewayChanged || force) {
2072 struct sgw_route_info egressRoutePrevious = egress_if->egressRouteCurrent;
2074 if (!egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
2075 memset(&egress_if->egressRouteCurrent, 0, sizeof(egress_if->egressRouteCurrent));
2076 egress_if->egressRouteCurrent.active = false;
2078 determineEgressLinkRoute( //
2079 &egress_if->egressRouteCurrent, // route
2080 false,// networkRoute
2081 egress_if->if_index, // if_index
2082 !egress_if->bwCurrent.gatewaySet ? NULL : &egress_if->bwCurrent.gateway, // gw
2083 &ipv4_slash_0_route, // dst
2084 egress_if->tableNr // table
2089 (egressRoutePrevious.active != egress_if->egressRouteCurrent.active) || //
2090 memcmp(&egressRoutePrevious, &egress_if->egressRouteCurrent, sizeof(egress_if->egressRouteCurrent));
2092 if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
2093 programRoute(false, &egressRoutePrevious, egress_if->name);
2096 if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
2097 programRoute(true, &egress_if->egressRouteCurrent, egress_if->name);
2101 next: egress_if = egress_if->next;
2106 * Multi-Smart-Gateway Status Overview
2109 #define IPNONE ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0" : "::")
2110 #define MASKNONE ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0/0" : "::/0")
2111 #define IPLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.1" : "::1")
2112 #define MASKLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.0/8" : "::1/128")
2115 * Print a timestamp to a file
2119 static void printDate(FILE * f) {
2125 tm_info = localtime(&timer);
2127 strftime(buffer, sizeof(buffer), "%B %d, %Y at %H:%M:%S", tm_info);
2128 fprintf(f, "%s", buffer);
2131 bool isEgressSelected(struct sgw_egress_if * egress_if) {
2132 return bestOverallLink.valid && !bestOverallLink.isOlsr && (bestOverallLink.link.egress == egress_if);
2136 * Write multi-smart-gateway status file
2139 * # multi-smart-gateway status overview, generated on October 10, 2014 at 08:27:15
2141 * #Originator Prefix Uplink Downlink PathCost Type Interface Gateway Cost
2142 * 127.0.0.1 127.0.0.0/8 0 0 INFINITE egress ppp0 0.0.0.0 INFINITE
2143 * 127.0.0.1 127.0.0.0/8 0 0 INFINITE egress eth1 192.168.0.1 INFINITE
2144 * *10.0.0.1 0.0.0.0/0 290 1500 0.000 olsr tnl_4096 10.0.0.1 34.325
2147 * @param phase the phase of the change (startup/runtime/shutdown)
2149 static void writeProgramStatusFile(enum sgw_multi_change_phase phase) {
2150 /* # Origi Prefx Upln Dwnl PthC Type Intfc Gtway Cost */
2151 static const char * fmt_header = "%s%-15s %-18s %-9s %-9s %-8s %-6s %-16s %-15s %s\n";
2152 static const char * fmt_values = "%s%-15s %-18s %-9u %-9u %-8s %-6s %-16s %-15s %s\n";
2154 char * fileName = olsr_cnf->smart_gw_status_file;
2157 if (!fileName || (fileName[0] == '\0')) {
2161 if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
2166 fp = fopen(fileName, "w");
2168 olsr_syslog(OLSR_LOG_ERR, "Could not write to %s", fileName);
2172 fprintf(fp, "# OLSRd Multi-Smart-Gateway Status Overview\n");
2173 fprintf(fp, "# Generated on ");
2175 fprintf(fp, "\n\n");
2178 fprintf(fp, fmt_header, "#", "Originator", "Prefix", "Uplink", "Downlink", "PathCost", "Type", "Interface", "Gateway", "Cost");
2180 /* egress interfaces */
2182 struct lqtextbuffer lnkbuf;
2183 struct gwtextbuffer gwbuf;
2184 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2186 struct ipaddr_str gwStr;
2187 const char * gw = !egress_if->bwCurrent.gatewaySet ? IPNONE : olsr_ip_to_string(&gwStr, &egress_if->bwCurrent.gateway);
2188 fprintf(fp, fmt_values, //
2189 isEgressSelected(egress_if) ? "*" : " ", //selected
2190 IPLOCAL, // Originator
2191 MASKLOCAL, // Prefix
2192 egress_if->bwCurrent.egressUk, // Uplink
2193 egress_if->bwCurrent.egressDk, // Downlink
2194 get_linkcost_text(egress_if->bwCurrent.path_cost, true, &lnkbuf), // PathCost
2196 egress_if->name, // Interface
2198 get_gwcost_text(egress_if->bwCurrent.costs, &gwbuf) // Cost
2201 egress_if = egress_if->next;
2207 struct lqtextbuffer lnkbuf;
2208 struct gwtextbuffer gwbuf;
2209 struct gateway_entry * current_gw = olsr_get_inet_gateway((olsr_cnf->ip_version == AF_INET) ? false : true);
2210 struct interfaceName * sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
2213 for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
2214 struct interfaceName * node = &sgwTunnelInterfaceNames[i];
2215 struct gateway_entry * gw = node->gw;
2218 struct tc_entry* tc = olsr_lookup_tc_entry(&gw->originator);
2220 struct ipaddr_str originatorStr;
2221 const char * originator = olsr_ip_to_string(&originatorStr, &gw->originator);
2222 struct ipaddr_str prefixIpStr;
2223 const char * prefixIPStr = olsr_ip_to_string(&prefixIpStr, &gw->external_prefix.prefix);
2224 uint8_t prefix_len = gw->external_prefix.prefix_len;
2225 struct ipaddr_str tunnelGwStr;
2226 const char * tunnelGw = olsr_ip_to_string(&tunnelGwStr, &gw->originator);
2227 bool selected = bestOverallLink.valid && bestOverallLink.isOlsr && current_gw && (current_gw == gw);
2229 char prefix[strlen(prefixIPStr) + 1 + 3 + 1];
2230 snprintf(prefix, sizeof(prefix), "%s/%d", prefixIPStr, prefix_len);
2232 fprintf(fp, fmt_values, //
2233 selected ? "*" : " ", // selected
2234 originator, // Originator
2235 prefix, // Prefix IP
2236 gw->uplink, // Uplink
2237 gw->downlink, // Downlink
2238 get_linkcost_text(!tc ? ROUTE_COST_BROKEN : tc->path_cost, true, &lnkbuf), // PathCost
2240 node->name, // Interface
2241 tunnelGw, // Gateway
2242 get_gwcost_text(gw->path_cost, &gwbuf) // Cost
2252 * Report a new gateway with its most relevant parameters in the syslog
2254 static void reportNewGateway(void) {
2255 if (!bestOverallLink.valid) {
2256 /* best overall link is invalid (none) */
2257 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: none");
2261 if (!bestOverallLink.isOlsr) {
2262 /* best overall link is an egress interface */
2263 struct lqtextbuffer lqbuf;
2264 struct ipaddr_str gwStr;
2265 const char * gw = !bestOverallLink.link.egress->bwCurrent.gatewaySet ? //
2267 olsr_ip_to_string(&gwStr, &bestOverallLink.link.egress->bwCurrent.gateway);
2268 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%s", //
2269 bestOverallLink.link.egress->name, //
2270 !gw ? "" : "via ", //
2271 !gw ? "" : gwStr.buf, //
2273 bestOverallLink.link.egress->bwCurrent.egressUk, //
2274 bestOverallLink.link.egress->bwCurrent.egressDk, //
2275 get_linkcost_text(bestOverallLink.link.egress->bwCurrent.path_cost, true, &lqbuf));
2279 /* best overall link is an olsr (tunnel) interface */
2281 struct lqtextbuffer lqbuf;
2282 struct tc_entry* tc = olsr_lookup_tc_entry(&bestOverallLink.link.olsr->originator);
2284 char ifNameBuf[IFNAMSIZ];
2285 const char * ifName = if_indextoname(bestOverallLink.olsrTunnelIfIndex, ifNameBuf);
2287 struct ipaddr_str gwStr;
2288 const char * gw = olsr_ip_to_string(&gwStr, &bestOverallLink.link.olsr->originator);
2290 olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%s", //
2291 !ifName ? "none" : ifName, //
2292 !gw ? "" : "via ", //
2293 !gw ? "" : gwStr.buf, //
2295 bestOverallLink.link.olsr->uplink, //
2296 bestOverallLink.link.olsr->downlink, //
2297 get_linkcost_text(!tc ? ROUTE_COST_BROKEN : tc->path_cost, true, &lqbuf));
2302 * Process changes that are relevant to egress interface: changes to the
2303 * egress interfaces themselves and to the smart gateway that is chosen by olsrd
2305 * @param egressChanged true when an egress interface changed
2306 * @param olsrChanged true when the smart gateway changed
2307 * @param phase the phase of the change (startup/runtime/shutdown)
2309 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
2310 bool bestEgressChanged = false;
2311 bool bestOverallChanged = false;
2312 bool force = MSGW_ROUTE_FORCED(phase);
2315 (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
2316 (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
2317 (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
2319 if (allOlsrInterfacesDown(olsr_cnf) != olsrInterfacesAllDown) {
2320 olsrInterfacesAllDown = !olsrInterfacesAllDown;
2324 if (!egressChanged && !olsrChanged && !force) {
2328 assert(multi_gateway_mode());
2330 if (egressChanged || force) {
2331 bestEgressChanged = determineBestEgressLink(phase);
2332 configureEgressLinkRoutes(phase);
2335 if (olsrChanged || bestEgressChanged || force) {
2336 bestOverallChanged = determineBestOverallLink(phase);
2339 if (bestOverallChanged || force) {
2340 setupDefaultGatewayOverrideRoutes(phase);
2343 if (bestEgressChanged || force) {
2344 configureBestEgressLinkRoute(phase);
2347 if (bestOverallChanged || force) {
2351 writeProgramStatusFile(phase);
2353 out: if (egressChanged) {
2354 /* clear the 'changed' flags of egress interfaces */
2355 struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2357 egress_if->upChanged = false;
2359 egress_if->bwCostsChanged = false;
2360 egress_if->bwNetworkChanged = false;
2361 egress_if->bwGatewayChanged = false;
2362 egress_if->bwChanged = false;
2364 egress_if = egress_if->next;
2369 #endif /* __linux__ */