deba8aa525c867b05b16aed8e78cef5284ef5013
[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 speed on which a gateway is chosen
18  * @param uplink the uplink speed of the gateway
19  * @param downlink the downlink speed of the gateway
20  * @return the speed
21  */
22 static inline unsigned long long gw_speed(struct gateway_entry *gw) {
23         return (gw->uplink + gw->downlink);
24 }
25
26 /**
27  * Determine the best gateway for uplink: this is the cluster leader.
28  *
29  * Loop over all gateways to find the best one and return it.
30  * When no best gateway is found then we return ourselves so that the behaviour
31  * degrades gracefully.
32  *
33  * A gateway is better when the sum of its uplink and downlink are greater than
34  * the previous best gateway. In case of a tie, the lowest IP address wins.
35  *
36  * This code is copied from lib/txtinfo/src/olsrd_txtinfo.c, function ipc_print_gateway.
37  * It adjusted for best gateway selection but otherwise kept the same as much
38  * as possible.
39  *
40  * @return
41  * a pointer to the IP address of the best gateway
42  */
43 union olsr_ip_addr * getBestUplinkGateway(void) {
44         struct gateway_entry *gw_best = NULL;
45         unsigned long long gw_best_value = 0;
46         struct gateway_entry *gw;
47
48         OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
49                 bool eval4 = false;
50                 bool eval6 = false;
51
52                 struct tc_entry * tc = olsr_lookup_tc_entry(&gw->originator);
53                 if (tc == NULL) {
54                         continue;
55                 }
56
57                 if (gw == olsr_get_ipv4_inet_gateway(NULL)) {
58                         eval4 = true;
59                 } else if (gw->ipv4
60                                 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)
61                                 && (olsr_cnf->smart_gw_allow_nat || !gw->ipv4nat)) {
62                         eval4 = true;
63                 }
64
65                 if (gw == olsr_get_ipv6_inet_gateway(NULL)) {
66                         eval6 = true;
67                 } else if (gw->ipv6 && olsr_cnf->ip_version == AF_INET6) {
68                         eval6 = true;
69                 }
70
71                 if (eval4 || eval6) {
72                         unsigned long long gw_value = gw_speed(gw);
73                         if (gw_value > gw_best_value) {
74                                 gw_best = gw;
75                                 gw_best_value = gw_value;
76                         } else if (gw_value == gw_best_value) {
77                                 bool gwHaslowerIpAddress = false;
78                                 if (eval4) {
79                                         gwHaslowerIpAddress = (ip4cmp(&gw->originator.v4,
80                                                         &gw_best->originator.v4) < 0);
81                                 } else /* eval6 */{
82                                         gwHaslowerIpAddress = (ip6cmp(&gw->originator.v6,
83                                                         &gw_best->originator.v6) < 0);
84                                 }
85                                 if (gwHaslowerIpAddress) {
86                                         gw_best = gw;
87                                         gw_best_value = gw_value;
88                                 }
89                         }
90                 }
91         } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
92
93         if (!gw_best) {
94                 /* degrade gracefully */
95                 return &olsr_cnf->main_addr;
96         }
97
98         return &gw_best->originator;
99 }