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