068c86d3a3ef733a4d9457ea7e432c66026988b0
[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 "lq_plugin.h"
9
10 /* System includes */
11
12 /**
13  * Determine the speed on which a gateway is chosen
14  * @param gw the gateway entry
15  * @return the speed
16  */
17 static inline unsigned long long gw_speed(struct gateway_entry *gw) {
18         return (gw->uplink + gw->downlink);
19 }
20
21 /**
22  * Determine the best gateway for uplink: this is the cluster leader.
23  *
24  * Loop over all gateways to find the best one and return it.
25  * When no best gateway is found then we return ourselves so that the behaviour
26  * degrades gracefully.
27  *
28  * A gateway is better when the sum of its uplink and downlink are greater than
29  * the previous best gateway. In case of a tie, the lowest IP address wins.
30  *
31  * This code is copied from lib/txtinfo/src/olsrd_txtinfo.c, function ipc_print_gateway.
32  * It adjusted for best gateway selection but otherwise kept the same as much
33  * as possible.
34  *
35  * @param bestGateway
36  * a pointer to the variable in which to store the best gateway
37  */
38 void getBestUplinkGateway(union olsr_ip_addr * bestGateway) {
39         struct gateway_entry *gw_best = NULL;
40         unsigned long long gw_best_value = 0;
41         struct gateway_entry *gw;
42
43         OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
44                 bool eval4 = false;
45                 bool eval6 = false;
46
47                 struct tc_entry * tc = olsr_lookup_tc_entry(&gw->originator);
48                 if (tc == NULL) {
49                         continue;
50                 }
51
52                 /* do not consider nodes with an infinite ETX */
53                 if (tc->path_cost == ROUTE_COST_BROKEN) {
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                 *bestGateway = olsr_cnf->main_addr;
96                 return;
97         }
98
99         *bestGateway = gw_best->originator;
100 }