f314a6b98e592e07d15ea2ba0ca90dbc36601442
[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 #include "lq_plugin.h"
15
16 #include "assert.h"
17
18 #ifdef linux
19 static uint32_t gw_def_nodecount, gw_def_stablecount;
20 static bool gw_def_finished_ipv4, gw_def_finished_ipv6;
21
22 static struct timer_entry *gw_def_timer;
23
24 static void gw_default_startup_handler(void);
25 static void gw_default_choosegw_handler(bool ipv4, bool ipv6);
26 static void gw_default_update_handler(struct gateway_entry *);
27 static void gw_default_delete_handler(struct gateway_entry *);
28
29 static struct olsr_gw_handler gw_def_handler = {
30   &gw_default_startup_handler,
31   &gw_default_choosegw_handler,
32   &gw_default_update_handler,
33   &gw_default_delete_handler
34 };
35
36 /*
37  * Helper functions
38  */
39
40 /**
41  * Look through the gateway list and select the best gateway
42  * depending on the distance to this router
43  */
44 static void gw_default_choose_gateway(void) {
45   struct tc_entry *tc;
46   struct gateway_entry *inet_ipv4, *inet_ipv6;
47   olsr_linkcost cost_ipv4, cost_ipv6;
48   struct gateway_entry *gw;
49   bool dual;
50   olsr_linkcost path_cost_times_threshold;
51
52   cost_ipv4 = ROUTE_COST_BROKEN;
53   cost_ipv6 = ROUTE_COST_BROKEN;
54
55   inet_ipv4 = NULL;
56   inet_ipv6 = NULL;
57
58   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
59     /* gateways should not exist without tc entry */
60     if ((tc = olsr_lookup_tc_entry(&gw->originator)) == NULL) {
61       continue;
62     }
63
64     if (olsr_cnf->smart_gw_thresh == 0) {
65       path_cost_times_threshold = tc->path_cost;
66     } else {
67       path_cost_times_threshold = ((long long)tc->path_cost * (long long)olsr_cnf->smart_gw_thresh + 50LL) / 100LL;
68     }
69     if (!gw_def_finished_ipv4 && gw->ipv4 && gw->ipv4nat == olsr_cnf->smart_gw_allow_nat && path_cost_times_threshold < cost_ipv4) {
70       inet_ipv4 = gw;
71       cost_ipv4 = path_cost_times_threshold;
72     }
73     if (!gw_def_finished_ipv6 && gw->ipv6 && path_cost_times_threshold < cost_ipv6) {
74       inet_ipv6 = gw;
75       cost_ipv6 = path_cost_times_threshold;
76     }
77   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
78
79   /* found an IPv4 gateway ? */
80   gw_def_finished_ipv4 |= inet_ipv4 != NULL;
81   gw_def_finished_ipv6 |= inet_ipv6 != NULL;
82   dual = inet_ipv4 == inet_ipv6;
83   if (inet_ipv4) {
84     olsr_set_inet_gateway(&inet_ipv4->originator, true, dual, false);
85   }
86   if (inet_ipv6 && !dual) {
87     olsr_set_inet_gateway(&inet_ipv6->originator, false, true, false);
88   }
89
90   /* finished ? */
91   if ((olsr_cnf->smart_gw_thresh == 0) && gw_def_finished_ipv4 && gw_def_finished_ipv6) {
92     olsr_stop_timer(gw_def_timer);
93     gw_def_timer = NULL;
94   }
95 }
96
97 /**
98  * Timer callback for lazy gateway selection
99  *
100  * @param unused unused
101  */
102 static void gw_default_timer(void *unused __attribute__ ((unused))) {
103   /* accept a 10% increase/decrease in the number of gateway nodes without triggering a stablecount reset */
104   if (((tc_tree.count * 10) <= (gw_def_nodecount * 11)) ||
105       ((tc_tree.count * 10) >= (gw_def_nodecount *  9))) {
106     gw_def_nodecount = tc_tree.count;
107   }
108
109   if (tc_tree.count == gw_def_nodecount) {
110     /* the number of gateway nodes is 'stable' */
111     gw_def_stablecount++;
112   }
113   else {
114     /* there was a significant change in the number of gateway nodes */
115     gw_def_nodecount = tc_tree.count;
116     gw_def_stablecount = 0;
117   }
118
119   if (gw_def_stablecount >= olsr_cnf->smart_gw_stablecount) {
120     /* the number of gateway nodes is stable enough, so we should select a new gateway now */
121     gw_default_choose_gateway();
122   }
123 }
124
125 /*
126  * Exported functions
127  */
128
129 /**
130  * initialization of default gateway handler
131  */
132 void olsr_gw_default_init(void) {
133   /* initialize values */
134   gw_def_timer = NULL;
135   gw_def_finished_ipv4 = false;
136   gw_def_finished_ipv6 = false;
137   gw_def_nodecount = 0;
138   gw_def_stablecount = 0;
139   gw_def_timer = NULL;
140
141   /* setup default handler */
142   olsr_set_inetgw_handler(&gw_def_handler);
143 }
144
145 /**
146  * Lookup a new gateway based on distance metric
147  *
148  * @param ipv4 lookup new v4 gateway
149  * @param ipv6 lookup new v6 gateway
150  */
151 void olsr_gw_default_lookup_gateway(bool ipv4, bool ipv6) {
152   if (ipv4) {
153     /* get new ipv4 GW if we use OLSRv4 or NIIT */
154     gw_def_finished_ipv4 = !(olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
155   }
156   if (ipv6) {
157     /* get new ipv6 GW if we use OLSRv6 */
158     gw_def_finished_ipv6 = !(olsr_cnf->ip_version == AF_INET6);
159   }
160
161   if (!(gw_def_finished_ipv4 && gw_def_finished_ipv6)) {
162     gw_default_choose_gateway();
163   }
164 }
165
166 /*
167  * Handler functions
168  */
169
170 /* gateway handler callbacks */
171 static void gw_default_startup_handler(void) {
172   /* reset node count */
173   gw_def_nodecount = tc_tree.count;
174   gw_def_stablecount = 0;
175
176   /* get new ipv4 GW if we use OLSRv4 or NIIT */
177   gw_def_finished_ipv4 = !(olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
178
179   /* get new ipv6 GW if we use OLSRv6 */
180   gw_def_finished_ipv6 = !(olsr_cnf->ip_version == AF_INET6);
181
182   /* keep in mind we might be a gateway ourself */
183   gw_def_finished_ipv4 |= olsr_cnf->has_ipv4_gateway;
184   gw_def_finished_ipv6 |= olsr_cnf->has_ipv6_gateway;
185
186   /* start gateway selection timer */
187   olsr_set_timer(&gw_def_timer, olsr_cnf->smart_gw_period, 0, true, &gw_default_timer, NULL, 0);
188 }
189
190 static void gw_default_choosegw_handler(bool ipv4, bool ipv6) {
191   olsr_gw_default_lookup_gateway(ipv4, ipv6);
192
193   if (!(gw_def_finished_ipv4 && gw_def_finished_ipv6)) {
194     gw_default_startup_handler();
195   }
196 }
197
198 static void gw_default_update_handler(struct gateway_entry *gw) {
199   bool v4changed, v6changed;
200
201   v4changed = (gw == olsr_get_ipv4_inet_gateway(NULL))
202       && (!gw->ipv4 || (gw->ipv4nat && !olsr_cnf->smart_gw_allow_nat));
203   v6changed = (gw == olsr_get_ipv6_inet_gateway(NULL)) && !gw->ipv6;
204
205   if (v4changed || v6changed) {
206     olsr_gw_default_lookup_gateway(v4changed, v6changed);
207   }
208 }
209
210 static void gw_default_delete_handler(struct gateway_entry *gw) {
211   bool isv4, isv6;
212
213   isv4 = gw == olsr_get_ipv4_inet_gateway(NULL);
214   isv6 = gw == olsr_get_ipv6_inet_gateway(NULL);
215
216   if (gw != NULL && (isv4 || isv6)) {
217     olsr_gw_default_lookup_gateway(isv4, isv6);
218   }
219 }
220 #endif