Bugfixes for IPv6 smartgw tunnel
[olsrd.git] / src / gateway_default_handler.c
1 /*
2  * gateway_default_handler.c
3  *
4  *  Created on: Jan 29, 2010
5  *      Author: rogge
6  */
7
8 #include "defs.h"
9 #include "gateway.h"
10 #include "gateway_default_handler.h"
11 #include "scheduler.h"
12 #include "tc_set.h"
13 #include "log.h"
14
15 #include "assert.h"
16
17 #ifndef WIN32
18 static uint32_t gw_def_nodecount, gw_def_stablecount;
19 static bool gw_def_finished_ipv4, gw_def_finished_ipv6;
20
21 static struct timer_entry *gw_def_timer;
22
23 static void gw_default_startup_handler(void);
24 static void gw_default_choosegw_handler(bool ipv4, bool ipv6);
25 static void gw_default_update_handler(struct gateway_entry *);
26 static void gw_default_delete_handler(struct gateway_entry *);
27
28 static struct olsr_gw_handler gw_def_handler = {
29   &gw_default_startup_handler,
30   &gw_default_choosegw_handler,
31   &gw_default_update_handler,
32   &gw_default_delete_handler
33 };
34
35 /**
36  * Look through the gateway list and select the best gateway
37  * depending on the distance to this router
38  */
39 static void gw_default_choose_gateway(void) {
40   struct tc_entry *tc;
41   struct gateway_entry *inet_ipv4, *inet_ipv6;
42   olsr_linkcost cost_ipv4, cost_ipv6;
43   struct gateway_entry *gw;
44   bool dual;
45
46   cost_ipv4 = UINT32_MAX;
47   cost_ipv6 = UINT32_MAX;
48
49   inet_ipv4 = NULL;
50   inet_ipv6 = NULL;
51
52   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
53     /* gateways should not exist without tc entry */
54     if ((tc = olsr_lookup_tc_entry(&gw->originator)) == NULL) {
55       continue;
56     }
57
58     if (!gw_def_finished_ipv4 && gw->ipv4 && gw->ipv4nat == olsr_cnf->smart_gw_allow_nat && tc->path_cost < cost_ipv4) {
59       inet_ipv4 = gw;
60       cost_ipv4 = tc->path_cost;
61     }
62     if (!gw_def_finished_ipv6 && gw->ipv6 && tc->path_cost < cost_ipv6) {
63       inet_ipv6 = gw;
64       cost_ipv6 = tc->path_cost;
65     }
66   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
67
68   /* found an IPv4 gateway ? */
69   gw_def_finished_ipv4 |= inet_ipv4 != NULL;
70   gw_def_finished_ipv6 |= inet_ipv6 != NULL;
71   dual = inet_ipv4 == inet_ipv6;
72   if (inet_ipv4) {
73     olsr_set_inet_gateway(&inet_ipv4->originator, true, dual, false);
74   }
75   if (inet_ipv6 && !dual) {
76     olsr_set_inet_gateway(&inet_ipv6->originator, false, true, false);
77   }
78
79   /* finished ? */
80   if (gw_def_finished_ipv4 && gw_def_finished_ipv6) {
81     olsr_stop_timer(gw_def_timer);
82     gw_def_timer = NULL;
83   }
84 }
85
86 /* timer for laze gateway selection */
87 static void gw_default_timer(void *unused __attribute__ ((unused))) {
88   /* accept a 10% increase without trigger a stablecount reset */
89   if (tc_tree.count * 10 <= gw_def_nodecount * 11) {
90     gw_def_nodecount = tc_tree.count;
91   }
92   if (tc_tree.count <= gw_def_nodecount) {
93     gw_def_stablecount++;
94   }
95   else {
96     gw_def_nodecount = tc_tree.count;
97     gw_def_stablecount = 0;
98   }
99
100   if (gw_def_stablecount >= GW_DEFAULT_STABLE_COUNT) {
101     gw_default_choose_gateway();
102   }
103 }
104
105 /* gateway handler callbacks */
106 static void gw_default_startup_handler(void) {
107   /* reset node count */
108   gw_def_nodecount = tc_tree.count;
109   gw_def_stablecount = 0;
110
111   /* get new ipv4 GW if we use OLSRv4 or NIIT */
112   gw_def_finished_ipv4 = olsr_cnf->ip_version == AF_INET6 && !olsr_cnf->use_niit;
113
114   /* get new ipv6 GW if we use OLSRv6 */
115   gw_def_finished_ipv6 = olsr_cnf->ip_version == AF_INET;
116
117   /* keep in mind we might be a gateway ourself */
118   gw_def_finished_ipv4 |= olsr_cnf->has_ipv4_gateway;
119   gw_def_finished_ipv6 |= olsr_cnf->has_ipv6_gateway;
120
121   /* start gateway selection timer */
122   olsr_set_timer(&gw_def_timer, GW_DEFAULT_TIMER_INTERVAL, 0, true, &gw_default_timer, NULL, 0);
123 }
124
125 static void gw_default_update_handler(struct gateway_entry *gw) {
126   bool v4changed, v6changed;
127
128   v4changed = (gw == olsr_get_inet_gateway(false))
129       && (!gw->ipv4 || (gw->ipv4nat && !olsr_cnf->smart_gw_allow_nat));
130   v6changed = (gw == olsr_get_inet_gateway(true)) && !gw->ipv6;
131
132   if (v4changed || v6changed) {
133     olsr_gw_default_lookup_gateway(v4changed, v6changed);
134   }
135 }
136
137 static void gw_default_delete_handler(struct gateway_entry *gw) {
138   bool isv4, isv6;
139
140   isv4 = gw == olsr_get_inet_gateway(false);
141   isv6 = gw == olsr_get_inet_gateway(true);
142
143   if (gw != NULL && (isv4 || isv6)) {
144     olsr_gw_default_lookup_gateway(isv4, isv6);
145   }
146 }
147
148 static void gw_default_choosegw_handler(bool ipv4, bool ipv6) {
149   olsr_gw_default_lookup_gateway(ipv4, ipv6);
150
151   if (!(gw_def_finished_ipv4 && gw_def_finished_ipv6)) {
152     gw_default_startup_handler();
153   }
154 }
155
156 /**
157  * initialization of default gateway handler
158  */
159 void olsr_gw_default_init(void) {
160   /* initialize values */
161   gw_def_timer = NULL;
162   gw_def_finished_ipv4 = false;
163   gw_def_finished_ipv6 = false;
164   gw_def_nodecount = 0;
165   gw_def_stablecount = 0;
166   gw_def_timer = NULL;
167
168   /* setup default handler */
169   olsr_set_inetgw_handler(&gw_def_handler);
170 }
171
172 /**
173  * Lookup a new gateway based on distance metric
174  *
175  * @param ipv4 lookup new v4 gateway
176  * @param ipv6 lookup new v6 gateway
177  */
178 void olsr_gw_default_lookup_gateway(bool ipv4, bool ipv6) {
179   if (ipv4) {
180     /* get new ipv4 GW if we use OLSRv4 or NIIT */
181     gw_def_finished_ipv4 = olsr_cnf->ip_version == AF_INET6 && !olsr_cnf->use_niit;
182   }
183   if (ipv6) {
184     /* get new ipv6 GW if we use OLSRv6 */
185     gw_def_finished_ipv6 = olsr_cnf->ip_version == AF_INET;
186   }
187
188   if (!(gw_def_finished_ipv4 && gw_def_finished_ipv6)) {
189     gw_default_choose_gateway();
190   }
191 }
192 #endif