pud: minor update to getBestUplinkGateway
[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  * @param bestGateway
32  * a pointer to the variable in which to store the best gateway
33  */
34 void getBestUplinkGateway(union olsr_ip_addr * bestGateway) {
35         struct gateway_entry *gw_best = NULL;
36         unsigned long long gw_best_value = 0;
37         struct gateway_entry *gw;
38
39         OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
40                 bool eval4 = false;
41                 bool eval6 = false;
42
43                 struct tc_entry * tc = olsr_lookup_tc_entry(&gw->originator);
44                 if (!tc || (tc->path_cost == ROUTE_COST_BROKEN) || (!gw->uplink || !gw->downlink)) {
45                         /* gateways should not exist without tc entry */
46                         /* do not consider nodes with an infinite ETX */
47                         /* do not consider nodes without bandwidth or with a uni-directional link */
48                         continue;
49                 }
50
51                 if (gw == olsr_get_inet_gateway(false)) {
52                         eval4 = true;
53                 } else if (gw->ipv4
54                                 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)
55                                 && (olsr_cnf->smart_gw_allow_nat || !gw->ipv4nat)) {
56                         eval4 = true;
57                 }
58
59                 if (gw == olsr_get_inet_gateway(true)) {
60                         eval6 = true;
61                 } else if (gw->ipv6 && olsr_cnf->ip_version == AF_INET6) {
62                         eval6 = true;
63                 }
64
65                 if (eval4 || eval6) {
66                         unsigned long long gw_value = gw_speed(gw);
67                         if (!gw_best || (gw_value > gw_best_value)) {
68                                 gw_best = gw;
69                                 gw_best_value = gw_value;
70                         } else if (gw_value == gw_best_value) {
71                                 bool gwHaslowerIpAddress = false;
72                                 if (eval4) {
73                                         gwHaslowerIpAddress = (ip4cmp(&gw->originator.v4,
74                                                         &gw_best->originator.v4) < 0);
75                                 } else /* eval6 */{
76                                         gwHaslowerIpAddress = (ip6cmp(&gw->originator.v6,
77                                                         &gw_best->originator.v6) < 0);
78                                 }
79                                 if (gwHaslowerIpAddress) {
80                                         gw_best = gw;
81                                         gw_best_value = gw_value;
82                                 }
83                         }
84                 }
85         } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
86
87         if (!gw_best) {
88                 /* degrade gracefully */
89                 *bestGateway = olsr_cnf->main_addr;
90                 return;
91         }
92
93         *bestGateway = gw_best->originator;
94 }