c87769273aa001bfe92b03073cbbb604c6455ebd
[olsrd.git] / lib / pud / src / uplinkGateway.c
1 #include "uplinkGateway.h"
2
3 /* Plugin includes */
4
5 /* OLSRD includes */
6 #include "gateway.h"
7 #include "tc_set.h"
8 #include "ipcalc.h"
9 #include "olsr_types.h"
10
11 /* System includes */
12 #include <stddef.h>
13 #include <stdbool.h>
14 #include <sys/socket.h>
15
16 /**
17  * Determine the best gateway for uplink: this is the cluster leader.
18  *
19  * Loop over all gateways to find the best one and return it.
20  * When no best gateway is found then we return ourselves so that the behaviour
21  * degrades gracefully.
22  *
23  * A gateway is better when the sum of its uplink and downlink are greater than
24  * the previous best gateway. In case of a tie, the lowest IP address wins.
25  *
26  * This code is copied from lib/txtinfo/src/olsrd_txtinfo.c::ipc_print_gateway.
27  * It adjusted for best gateway selection but otherwise kept the same as much
28  * as possible.
29  *
30  * @return
31  * a pointer to the IP address of the best gateway
32  */
33 union olsr_ip_addr * getBestUplinkGateway(void) {
34         struct gateway_entry *gw_best = NULL;
35         unsigned long long gw_best_value = 0;
36         struct gateway_entry *gw;
37
38         OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
39                 bool eval4 = false;
40                 bool eval6 = false;
41
42                 struct tc_entry * tc = olsr_lookup_tc_entry(&gw->originator);
43                 if (tc == NULL) {
44                         continue;
45                 }
46
47                 if (gw == olsr_get_ipv4_inet_gateway(NULL)) {
48                         eval4 = true;
49                 } else if (gw->ipv4
50                                 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)
51                                 && (olsr_cnf->smart_gw_allow_nat || !gw->ipv4nat)) {
52                         eval4 = true;
53                 }
54
55                 if (gw == olsr_get_ipv6_inet_gateway(NULL)) {
56                         eval6 = true;
57                 } else if (gw->ipv6 && olsr_cnf->ip_version == AF_INET6) {
58                         eval6 = true;
59                 }
60
61                 if (eval4 || eval6) {
62                         unsigned long long gw_value = gw->uplink + gw->downlink;
63                         if (gw_value > gw_best_value) {
64                                 gw_best = gw;
65                                 gw_best_value = gw_value;
66                         } else if (gw_value == gw_best_value) {
67                                 bool gwHaslowerIpAddress = false;
68                                 if (eval4) {
69                                         gwHaslowerIpAddress = (ip4cmp(&gw->originator.v4,
70                                                         &gw_best->originator.v4) < 0);
71                                 } else /* eval6 */{
72                                         gwHaslowerIpAddress = (ip6cmp(&gw->originator.v6,
73                                                         &gw_best->originator.v6) < 0);
74                                 }
75                                 if (gwHaslowerIpAddress) {
76                                         gw_best = gw;
77                                         gw_best_value = gw_value;
78                                 }
79                         }
80                 }
81         } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
82
83         if (!gw_best) {
84                 /* degrade gracefully */
85                 return &olsr_cnf->main_addr;
86         }
87
88         return &gw_best->originator;
89 }