1e9b729bca9d4ce9add77f77b357c7f96a65aadd
[olsrd.git] / src / gateway.c
1 /*
2  * gateway.c
3  *
4  *  Created on: 05.01.2010
5  *      Author: henning
6  */
7
8 #ifdef linux
9
10 #include "common/avl.h"
11 #include "defs.h"
12 #include "ipcalc.h"
13 #include "olsr.h"
14 #include "olsr_cfg.h"
15 #include "olsr_cookie.h"
16 #include "scheduler.h"
17 #include "kernel_routes.h"
18 #include "kernel_tunnel.h"
19 #include "net_os.h"
20 #include "duplicate_set.h"
21 #include "log.h"
22 #include "gateway_default_handler.h"
23 #include "gateway.h"
24
25 #include <assert.h>
26 #include <net/if.h>
27
28 /** the gateway tree */
29 struct avl_tree gateway_tree;
30
31 /** gateway cookie */
32 static struct olsr_cookie_info *gw_mem_cookie = NULL;
33
34 /** the gateway netmask for the HNA */
35 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
36
37 /** the gateway handler/plugin */
38 static struct olsr_gw_handler *gw_handler;
39
40 /** the current IPv4 gateway */
41 static struct gateway_entry *current_ipv4_gw;
42
43 /** the tunnel of the current IPv4  gateway */
44 static struct olsr_iptunnel_entry *v4gw_tunnel;
45
46 /** the current IPv6 gateway */
47 static struct gateway_entry *current_ipv6_gw;
48
49 /** the tunnel of the current IPv6  gateway */
50 static struct olsr_iptunnel_entry *v6gw_tunnel;
51
52 /*
53  * Helper Functions
54  */
55
56 #define OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen) (((uint8_t *)mask) + ((prefixlen+7)/8))
57
58 /**
59  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
60  * to an uplink/downlink speed value
61  *
62  * @param value the encoded 1 byte transport value
63  * @return the uplink/downlink speed value (in kbit/s)
64  */
65 static uint32_t deserialize_gw_speed(uint8_t value) {
66   uint32_t speed;
67   uint32_t exp;
68
69   if (!value) {
70     /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
71      * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
72     return 0;
73   }
74
75   speed = (value >> 3) + 1;
76   exp = value & 7;
77
78   while (exp-- > 0) {
79     speed *= 10;
80   }
81   return speed;
82 }
83
84 /**
85  * Convert an uplink/downlink speed value into an encoded 1 byte transport
86  * value (5 bits mantissa, 3 bits exponent)
87  *
88  * @param speed the uplink/downlink speed value (in kbit/s)
89  * @return value the encoded 1 byte transport value
90  */
91 static uint8_t serialize_gw_speed(uint32_t speed) {
92   uint8_t exp = 0;
93
94   if (speed == 0) {
95     return 0;
96   }
97
98   if (speed > 320000000) {
99     return 0xff;
100   }
101
102   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
103     speed /= 10;
104     exp++;
105   }
106   return ((speed - 1) << 3) | exp;
107 }
108
109 /*
110  * Callback Functions
111  */
112
113 /**
114  * Callback for tunnel interface monitoring which will set the route into the tunnel
115  * when the interface comes up again.
116  *
117  * @param if_index the interface index
118  * @param ifh the interface
119  * @param flag interface change flags
120  */
121 static void smartgw_tunnel_monitor(int if_index __attribute__ ((unused)),
122     struct interface *ifh __attribute__ ((unused)), enum olsr_ifchg_flag flag __attribute__ ((unused))) {
123   return;
124 }
125
126 /**
127  * Timer callback to remove and cleanup a gateway entry
128  *
129  * @param ptr
130  */
131 static void cleanup_gateway_handler(void *ptr) {
132   struct gateway_entry *gw = ptr;
133
134   if (gw->ipv4 || gw->ipv6) {
135     /* do not clean it up when it is in use */
136     return;
137   }
138
139   /* remove gateway entry */
140   avl_delete(&gateway_tree, &gw->node);
141   olsr_cookie_free(gw_mem_cookie, gw);
142 }
143
144 /*
145  * Main Interface
146  */
147
148 /**
149  * Initialize gateway system
150  */
151 int olsr_init_gateways(void) {
152   gw_mem_cookie = olsr_alloc_cookie("Gateway cookie", OLSR_COOKIE_TYPE_MEMORY);
153   olsr_cookie_set_memory_size(gw_mem_cookie, sizeof(struct gateway_entry));
154
155   avl_init(&gateway_tree, avl_comp_default);
156
157   current_ipv4_gw = NULL;
158   v4gw_tunnel = NULL;
159
160   current_ipv6_gw = NULL;
161   v6gw_tunnel = NULL;
162
163   gw_handler = NULL;
164
165   refresh_smartgw_netmask();
166
167   if (olsr_os_init_iptunnel(olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6)) {
168     return 1;
169   }
170
171   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
172
173   /* initialize default gateway handler */
174   gw_handler = &gw_def_handler;
175   gw_handler->init();
176
177   return 0;
178 }
179
180 /**
181  * Cleanup gateway tunnel system
182  */
183 void olsr_cleanup_gateways(void) {
184   if (current_ipv4_gw) {
185     olsr_os_del_ipip_tunnel(v4gw_tunnel);
186   }
187   if (current_ipv6_gw) {
188     olsr_os_del_ipip_tunnel(v6gw_tunnel);
189   }
190
191   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
192
193   assert(gw_handler);
194   gw_handler->cleanup();
195   gw_handler = NULL;
196
197   olsr_os_cleanup_iptunnel(olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
198 }
199
200 /**
201  * Triggers the first lookup of a gateway.
202  */
203 void olsr_trigger_inetgw_startup(void) {
204   assert(gw_handler);
205   gw_handler->startup();
206 }
207
208 /**
209  * Print debug information about gateway entries
210  */
211 void olsr_print_gateway_entries(void) {
212 #ifndef NODEBUG
213   struct ipaddr_str buf;
214   struct gateway_entry *gw;
215   const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
216
217   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
218   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
219       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
220
221   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
222     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
223         addrsize,
224         olsr_ip_to_string(&buf, &gw->originator),
225         gw->ipv4nat ? "" : "   ",
226         gw->ipv4 ? '4' : ' ',
227         gw->ipv4nat ? "(N)" : "",
228         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
229         gw->ipv6 ? '6' : ' ',
230         gw->uplink,
231         gw->downlink,
232         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
233   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
234 #endif
235 }
236
237 /*
238  * Tx Path Interface
239  */
240
241 /**
242  * Apply the smart gateway modifications to an outgoing HNA
243  *
244  * @param mask pointer to netmask of the HNA
245  * @param prefixlen of the HNA
246  */
247 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
248   uint8_t *ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen);
249
250   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
251   if (olsr_cnf->has_ipv4_gateway) {
252     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
253
254     if (olsr_cnf->smart_gw_uplink_nat) {
255       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
256     }
257   }
258   if (olsr_cnf->has_ipv6_gateway) {
259     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
260   }
261   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
262     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
263   }
264 }
265
266 /*
267  * SgwDynSpeed Plugin Interface
268  */
269
270 /**
271  * Setup the gateway netmask
272  */
273 void refresh_smartgw_netmask(void) {
274   uint8_t *ip;
275   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
276
277   if (olsr_cnf->smart_gw_active) {
278     ip = (uint8_t *) &smart_gateway_netmask;
279
280     if (olsr_cnf->smart_gw_uplink > 0 && olsr_cnf->smart_gw_downlink > 0) {
281       /* the link is bi-directional with a non-zero bandwidth */
282       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
283       ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
284       ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
285     }
286     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
287       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
288       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
289       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
290     }
291   }
292 }
293
294 /*
295  * TC/SPF/HNA Interface
296  */
297
298 /**
299  * Checks if a HNA prefix/netmask combination is a smart gateway
300  *
301  * @param prefix
302  * @param mask
303  * @return true if is a valid smart gateway HNA, false otherwise
304  */
305 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
306   uint8_t *ptr;
307
308   if (!is_prefix_inetgw(prefix)) {
309     return false;
310   }
311
312   ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefix->prefix_len);
313   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
314 }
315
316 /**
317  * Update a gateway_entry based on a HNA
318  *
319  * @param originator ip of the source of the HNA
320  * @param mask netmask of the HNA
321  * @param prefixlen of the HNA
322  * @param seqno the sequence number of the HNA
323  */
324 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
325   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
326   uint8_t *ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen);
327
328   if (!gw) {
329     gw = olsr_cookie_malloc(gw_mem_cookie);
330     gw->originator = *originator;
331     gw->node.key = &gw->originator;
332
333     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
334   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
335     /* ignore older HNAs */
336     return;
337   }
338
339   /* keep new HNA seqno */
340   gw->seqno = seqno;
341
342   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
343     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
344     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
345   } else {
346     gw->uplink = 0;
347     gw->downlink = 0;
348   }
349
350   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
351   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
352
353   if (olsr_cnf->ip_version == AF_INET6) {
354     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
355
356     /* do not reset prefixlength for ::ffff:0:0 HNAs */
357     if (prefixlen == ipv6_internet_route.prefix_len) {
358       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
359
360       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
361           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
362         /* this is the right prefix (2000::/3), so we can copy the prefix */
363         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
364         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
365       }
366     }
367   }
368
369   /* stop cleanup timer if necessary */
370   if (gw->cleanup_timer) {
371     olsr_stop_timer(gw->cleanup_timer);
372     gw->cleanup_timer = NULL;
373   }
374
375   /* call update handler */
376   assert(gw_handler);
377   gw_handler->update(gw);
378 }
379
380 /**
381  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
382  * Should only be called if prefix is a smart_gw prefix or if node is removed
383  * from TC set.
384  *
385  * @param originator
386  * @param prefixlen
387  */
388 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen) {
389   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
390   bool change = false;
391
392   if (gw && (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6)) {
393     /* found a gw and it wasn't deleted yet */
394
395     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
396       change = gw->ipv4;
397       gw->ipv4 = false;
398       gw->ipv4nat = false;
399     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
400       change = gw->ipv6;
401       gw->ipv6 = false;
402     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
403       change = gw->ipv4;
404       gw->ipv4 = false;
405       gw->ipv4nat = false;
406     }
407
408     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
409       /* prevent this gateway from being chosen as the new gateway */
410       gw->ipv4 = false;
411       gw->ipv4nat = false;
412       gw->ipv6 = false;
413
414       /* handle gateway loss */
415       assert(gw_handler);
416       gw_handler->delete(gw);
417
418       /* cleanup gateway if necessary */
419       if (current_ipv4_gw == gw) {
420         olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, false);
421         olsr_os_del_ipip_tunnel(v4gw_tunnel);
422
423         current_ipv4_gw = NULL;
424         v4gw_tunnel = NULL;
425       }
426       if (current_ipv6_gw == gw) {
427         olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, false);
428         olsr_os_del_ipip_tunnel(v6gw_tunnel);
429
430         current_ipv6_gw = NULL;
431         v6gw_tunnel = NULL;
432       }
433
434       /* remove gateway entry on a delayed schedule */
435       olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
436     } else if (change) {
437       assert(gw_handler);
438       gw_handler->update(gw);
439     }
440   }
441 }
442
443 /**
444  * Triggers a check if the one of the gateways have been lost or has an
445  * ETX = infinity
446  */
447 void olsr_trigger_gatewayloss_check(void) {
448   bool ipv4 = false;
449   bool ipv6 = false;
450
451   if (current_ipv4_gw) {
452     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->originator);
453     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
454   }
455   if (current_ipv6_gw) {
456     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->originator);
457     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
458   }
459
460   if (ipv4 || ipv6) {
461     assert(gw_handler);
462     gw_handler->choose(ipv4, ipv6);
463   }
464 }
465
466 /*
467  * Gateway Plugin Functions
468  */
469
470 /**
471  * Sets a new internet gateway.
472  *
473  * @param originator ip address of the node with the new gateway
474  * @param ipv4 set ipv4 gateway
475  * @param ipv6 set ipv6 gateway
476  * @return true if an error happened, false otherwise
477  */
478 bool olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6) {
479   struct gateway_entry *entry;
480   struct gateway_entry *oldV4 = current_ipv4_gw;
481   struct gateway_entry *oldV6 = current_ipv6_gw;
482   struct olsr_iptunnel_entry *tunnelV4 = v4gw_tunnel;
483   struct olsr_iptunnel_entry *tunnelV6 = v6gw_tunnel;
484
485   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
486   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
487
488   entry = node2gateway(avl_find(&gateway_tree, originator));
489   if (!entry) {
490     return true;
491   }
492
493   if (ipv4) {
494     current_ipv4_gw = NULL;
495     if (entry->ipv4 && (!entry->ipv4nat || olsr_cnf->smart_gw_allow_nat)) {
496       /* valid ipv4 gateway */
497       current_ipv4_gw = entry;
498     }
499   }
500   if (ipv6) {
501     current_ipv6_gw = NULL;
502     if (entry->ipv6) {
503       /* valid ipv6 gateway */
504       current_ipv6_gw = entry;
505     }
506   }
507
508   /* handle IPv4 */
509   if (oldV4 != current_ipv4_gw) {
510     if ((v4gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv4_gw->originator, true)) != NULL) {
511       olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, true);
512     } else {
513       /* adding the tunnel failed, we try again in the next cycle */
514       current_ipv4_gw = NULL;
515     }
516     if (oldV4 != NULL) {
517       olsr_os_del_ipip_tunnel(tunnelV4);
518     }
519   }
520   /* handle IPv6 */
521   if (oldV6 != current_ipv6_gw) {
522     if ((v6gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv6_gw->originator, false)) != NULL) {
523       olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, true);
524     } else {
525       /* adding the tunnel failed, we try again in the next cycle */
526       current_ipv6_gw = NULL;
527     }
528     if (oldV6 != NULL) {
529       olsr_os_del_ipip_tunnel(tunnelV6);
530     }
531   }
532   return (ipv4 && current_ipv4_gw == NULL) || (ipv6 && current_ipv6_gw == NULL);
533 }
534
535 /**
536  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
537  * NULL if not set.
538  */
539 struct gateway_entry *olsr_get_ipv4_inet_gateway(void) {
540   return current_ipv4_gw;
541 }
542
543 /**
544  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
545  * NULL if not set.
546  */
547 struct gateway_entry *olsr_get_ipv6_inet_gateway(void) {
548   return current_ipv6_gw;
549 }
550
551 #endif /* linux */