8232d8a612838a25770173a06d1bf2a926866e53
[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 me;
45         struct gateway_entry *gw_best = NULL;
46         unsigned long long gw_best_value = 0;
47         struct gateway_entry *gw;
48
49         /* First we start with ourselves as best gateway and then determine whether there is a better one.
50          *
51          * The usage of the uplink and downlink speed is the same as in gateway.c,
52          * function refresh_smartgw_netmask. If that should change, then this must change as well.
53          * Might be better to obtain a pointer to the last HNA that was sent and then to deserialize
54          * that HNA. Or when the olsr_cnf->smart_gw_uplink/downlink fields are modified directly then
55          * obtaining such a pointer is not needed */
56         me.originator = olsr_cnf->main_addr;
57         me.uplink = olsr_cnf->smart_gw_uplink;
58         me.downlink = olsr_cnf->smart_gw_downlink;
59         gw_best = &me;
60         gw_best_value = gw_speed(&me);
61
62         OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
63                 bool eval4 = false;
64                 bool eval6 = false;
65
66                 struct tc_entry * tc = olsr_lookup_tc_entry(&gw->originator);
67                 if (tc == NULL) {
68                         continue;
69                 }
70
71                 if (gw == olsr_get_ipv4_inet_gateway(NULL)) {
72                         eval4 = true;
73                 } else if (gw->ipv4
74                                 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)
75                                 && (olsr_cnf->smart_gw_allow_nat || !gw->ipv4nat)) {
76                         eval4 = true;
77                 }
78
79                 if (gw == olsr_get_ipv6_inet_gateway(NULL)) {
80                         eval6 = true;
81                 } else if (gw->ipv6 && olsr_cnf->ip_version == AF_INET6) {
82                         eval6 = true;
83                 }
84
85                 if (eval4 || eval6) {
86                         unsigned long long gw_value = gw_speed(gw);
87                         if (gw_value > gw_best_value) {
88                                 gw_best = gw;
89                                 gw_best_value = gw_value;
90                         } else if (gw_value == gw_best_value) {
91                                 bool gwHaslowerIpAddress = false;
92                                 if (eval4) {
93                                         gwHaslowerIpAddress = (ip4cmp(&gw->originator.v4,
94                                                         &gw_best->originator.v4) < 0);
95                                 } else /* eval6 */{
96                                         gwHaslowerIpAddress = (ip6cmp(&gw->originator.v6,
97                                                         &gw_best->originator.v6) < 0);
98                                 }
99                                 if (gwHaslowerIpAddress) {
100                                         gw_best = gw;
101                                         gw_best_value = gw_value;
102                                 }
103                         }
104                 }
105         } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
106
107         if (gw_best == &me) {
108                 /* I'm the chosen gateway */
109                 return &olsr_cnf->main_addr;
110         }
111
112         /* the chosen gateway is better */
113         return &gw_best->originator;
114 }