root/opal/mca/reachable/netlink/reachable_netlink_module.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. netlink_init
  2. netlink_fini
  3. netlink_reachable
  4. get_weights
  5. calculate_weight

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2014-2015 Intel, Inc.  All rights reserved.
   4  * Copyright (c) 2015 Cisco Systems.  All rights reserved.
   5  * Copyright (c) 2017 Amazon.com, Inc. or its affiliates.
   6  *                    All Rights reserved.
   7  * $COPYRIGHT$
   8  *
   9  * Additional copyrights may follow
  10  *
  11  * $HEADER$
  12  */
  13 
  14 #include "opal_config.h"
  15 #include "opal/constants.h"
  16 #include "opal/types.h"
  17 
  18 #ifdef HAVE_MATH_H
  19 #include <math.h>
  20 #endif
  21 
  22 #include "opal/util/net.h"
  23 #include "opal/util/string_copy.h"
  24 #include "opal/mca/reachable/base/base.h"
  25 #include "reachable_netlink.h"
  26 #include "libnl_utils.h"
  27 
  28 enum connection_quality {
  29     CQ_NO_CONNECTION = 0,
  30     CQ_DIFFERENT_NETWORK = 50,
  31     CQ_SAME_NETWORK = 100
  32 };
  33 
  34 /* Local variables */
  35 static int init_counter = 0;
  36 
  37 static int get_weights(opal_if_t *local_if, opal_if_t *remote_if);
  38 static int calculate_weight(int bandwidth_local, int bandwidth_remote,
  39                             int connection_quality);
  40 
  41 static int netlink_init(void)
  42 {
  43     ++init_counter;
  44 
  45     return OPAL_SUCCESS;
  46 }
  47 
  48 static int netlink_fini(void)
  49 {
  50     --init_counter;
  51 
  52     return OPAL_SUCCESS;
  53 }
  54 
  55 /*
  56  * Determines whether a connection is possible between
  57  * pairs of local and remote interfaces. To determine
  58  * reachability, the kernel's routing table is queried.
  59  * Higher weightings are given to connections on the same
  60  * network.
  61  */
  62 static opal_reachable_t* netlink_reachable(opal_list_t *local_if,
  63                                            opal_list_t *remote_if)
  64 {
  65     opal_reachable_t *reachable_results = NULL;
  66     int i, j;
  67     opal_if_t *local_iter, *remote_iter;
  68 
  69     reachable_results = opal_reachable_allocate(local_if->opal_list_length,
  70                                                 remote_if->opal_list_length);
  71     if (NULL == reachable_results) {
  72         return NULL;
  73     }
  74 
  75     i = 0;
  76     OPAL_LIST_FOREACH(local_iter, local_if, opal_if_t) {
  77         j = 0;
  78         OPAL_LIST_FOREACH(remote_iter, remote_if, opal_if_t) {
  79             reachable_results->weights[i][j] = get_weights(local_iter, remote_iter);
  80             j++;
  81         }
  82         i++;
  83     }
  84 
  85     return reachable_results;
  86 }
  87 
  88 
  89 static int get_weights(opal_if_t *local_if, opal_if_t *remote_if)
  90 {
  91     char str_local[128], str_remote[128], *conn_type;
  92     int outgoing_interface, ret, weight, has_gateway;
  93 
  94     /* opal_net_get_hostname returns a static buffer.  Great for
  95        single address printfs, need to copy in this case */
  96     opal_string_copy(str_local,
  97             opal_net_get_hostname((struct sockaddr *)&local_if->if_addr),
  98             sizeof(str_local));
  99     str_local[sizeof(str_local) - 1] = '\0';
 100     opal_string_copy(str_remote,
 101             opal_net_get_hostname((struct sockaddr *)&remote_if->if_addr),
 102             sizeof(str_remote));
 103     str_remote[sizeof(str_remote) - 1] = '\0';
 104 
 105     /*  initially, assume no connection is possible */
 106     weight = calculate_weight(0, 0, CQ_NO_CONNECTION);
 107 
 108     if (AF_INET == local_if->af_family && AF_INET == remote_if->af_family) {
 109         uint32_t local_ip, remote_ip;
 110 
 111         local_ip = (uint32_t)((struct sockaddr_in *)&(local_if->if_addr))->sin_addr.s_addr;
 112         remote_ip = (uint32_t)((struct sockaddr_in *)&(remote_if->if_addr))->sin_addr.s_addr;
 113         outgoing_interface = local_if->if_kernel_index;
 114 
 115         ret = opal_reachable_netlink_rt_lookup(local_ip,
 116                                                remote_ip,
 117                                                outgoing_interface,
 118                                                &has_gateway);
 119         if (0 == ret) {
 120             if (0 == has_gateway) {
 121                 conn_type = "IPv4 SAME NETWORK";
 122                 weight = calculate_weight(local_if->if_bandwidth,
 123                                           remote_if->if_bandwidth,
 124                                           CQ_SAME_NETWORK);
 125             } else {
 126                 conn_type = "IPv4 DIFFERENT NETWORK";
 127                 weight = calculate_weight(local_if->if_bandwidth,
 128                                           remote_if->if_bandwidth,
 129                                           CQ_DIFFERENT_NETWORK);
 130             }
 131         } else {
 132             conn_type = "IPv4 NO CONNECTION";
 133             weight = calculate_weight(0, 0, CQ_NO_CONNECTION);
 134         }
 135 
 136 #if OPAL_ENABLE_IPV6
 137     } else if (AF_INET6 == local_if->af_family && AF_INET6 == remote_if->af_family) {
 138         struct in6_addr *local_ip, *remote_ip;
 139 
 140         local_ip = &((struct sockaddr_in6 *)&(local_if->if_addr))->sin6_addr;
 141         remote_ip = &((struct sockaddr_in6 *)&(remote_if->if_addr))->sin6_addr;
 142         outgoing_interface = local_if->if_kernel_index;
 143 
 144         ret = opal_reachable_netlink_rt_lookup6(local_ip,
 145                                                 remote_ip,
 146                                                 outgoing_interface,
 147                                                 &has_gateway);
 148 
 149         if (0 == ret) {
 150             if (0 == has_gateway) {
 151                 conn_type = "IPv6 SAME NETWORK";
 152                 weight = calculate_weight(local_if->if_bandwidth,
 153                                           remote_if->if_bandwidth,
 154                                           CQ_SAME_NETWORK);
 155             } else {
 156                 conn_type = "IPv6 DIFFERENT NETWORK";
 157                 weight = calculate_weight(local_if->if_bandwidth,
 158                                           remote_if->if_bandwidth,
 159                                           CQ_DIFFERENT_NETWORK);
 160             }
 161         } else {
 162             conn_type = "IPv6 NO CONNECTION";
 163             weight = calculate_weight(0, 0, CQ_NO_CONNECTION);
 164         }
 165 #endif /* #if OPAL_ENABLE_IPV6 */
 166 
 167     } else {
 168         /* we don't have an address family match, so assume no
 169            connection */
 170         conn_type = "Address type mismatch";
 171         weight = calculate_weight(0, 0, CQ_NO_CONNECTION);
 172     }
 173 
 174     opal_output_verbose(20, opal_reachable_base_framework.framework_output,
 175                         "reachable:netlink: path from %s to %s: %s",
 176                         str_local, str_remote, conn_type);
 177 
 178     return weight;
 179 }
 180 
 181 
 182 const opal_reachable_base_module_t opal_reachable_netlink_module = {
 183     netlink_init,
 184     netlink_fini,
 185     netlink_reachable
 186 };
 187 
 188 
 189 /*
 190  * Weights determined by bandwidth between
 191  * interfaces (limited by lower bandwidth
 192  * interface).  A penalty is added to minimize
 193  * the discrepancy in bandwidth.  This helps
 194  * prevent pairing of fast and slow interfaces
 195  *
 196  * Formula: connection_quality * (min(a,b) + 1/(1 + |a-b|))
 197  *
 198  * Examples: a     b     f(a,b)
 199  *           0     0     1
 200  *           0     1     0.5
 201  *           1     1     2
 202  *           1     2     1.5
 203  *           1     3     1.33
 204  *           1     10    1.1
 205  *           10    10    11
 206  *           10    14    10.2
 207  *           11    14    11.25
 208  *           11    15    11.2
 209  *
 210  * NOTE: connection_quality of 1 is assumed for examples.
 211  * In reality, since we're using integers, we need
 212  * connection_quality to be large enough
 213  * to capture decimals
 214  */
 215 static int calculate_weight(int bandwidth_local, int bandwidth_remote,
 216                             int connection_quality)
 217 {
 218     int weight = connection_quality * (MIN(bandwidth_local, bandwidth_remote) +
 219                                        1.0/(1.0 + (double)abs(bandwidth_local - bandwidth_remote)));
 220     return weight;
 221 }

/* [<][>][^][v][top][bottom][index][help] */