2005-08-02 17:20:50 +04:00
|
|
|
/*
|
2006-02-23 05:02:19 +03:00
|
|
|
* Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana
|
2005-11-05 22:57:48 +03:00
|
|
|
* University Research and Technology
|
|
|
|
* Corporation. All rights reserved.
|
2010-02-19 10:10:32 +03:00
|
|
|
* Copyright (c) 2004-2010 The University of Tennessee and The University
|
2005-11-05 22:57:48 +03:00
|
|
|
* of Tennessee Research Foundation. All rights
|
|
|
|
* reserved.
|
2005-08-02 17:20:50 +04:00
|
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
|
|
* University of Stuttgart. All rights reserved.
|
|
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
2010-04-14 18:18:35 +04:00
|
|
|
* Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved
|
As per the email discussion, revise the sparse handling of hostnames so that we avoid potential infinite loops while allowing large-scale users to improve their startup time:
* add a new MCA param orte_hostname_cutoff to specify the number of nodes at which we stop including hostnames. This defaults to INT_MAX => always include hostnames. If a value is given, then we will include hostnames for any allocation smaller than the given limit.
* remove ompi_proc_get_hostname. Replace all occurrences with a direct link to ompi_proc_t's proc_hostname, protected by appropriate "if NULL"
* modify the OMPI-ORTE integration component so that any call to modex_recv automatically loads the ompi_proc_t->proc_hostname field as well as returning the requested info. Thus, any process whose modex info you retrieve will automatically receive the hostname. Note that on-demand retrieval is still enabled - i.e., if we are running under direct launch with PMI, the hostname will be fetched upon first call to modex_recv, and then the ompi_proc_t->proc_hostname field will be loaded
* removed a stale MCA param "mpi_keep_peer_hostnames" that was no longer used anywhere in the code base
* added an envar lookup in ess/pmi for the number of nodes in the allocation. Sadly, PMI itself doesn't provide that info, so we have to get it a different way. Currently, we support PBS-based systems and SLURM - for any other, rank0 will emit a warning and we assume max number of daemons so we will always retain hostnames
This commit was SVN r29052.
2013-08-20 22:59:36 +04:00
|
|
|
* Copyright (c) 2013 Intel, Inc. All rights reserved
|
2005-08-02 17:20:50 +04:00
|
|
|
* $COPYRIGHT$
|
|
|
|
*
|
|
|
|
* Additional copyrights may follow
|
|
|
|
*
|
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ompi_config.h"
|
|
|
|
|
2006-02-23 05:02:19 +03:00
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#endif
|
2012-02-21 17:32:14 +04:00
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
2006-02-23 05:02:19 +03:00
|
|
|
|
2008-03-06 01:44:35 +03:00
|
|
|
#include "opal/class/opal_hash_table.h"
|
2005-08-02 17:20:50 +04:00
|
|
|
#include "ompi/mca/btl/base/btl_base_error.h"
|
2007-07-09 21:16:34 +04:00
|
|
|
#include "ompi/runtime/ompi_module_exchange.h"
|
2008-04-18 00:43:56 +04:00
|
|
|
#include "opal/util/arch.h"
|
2008-11-05 21:45:42 +03:00
|
|
|
#include "opal/util/argv.h"
|
2007-04-25 05:55:40 +04:00
|
|
|
#include "opal/util/if.h"
|
2007-05-17 05:17:59 +04:00
|
|
|
#include "opal/util/net.h"
|
2005-08-02 17:20:50 +04:00
|
|
|
|
|
|
|
#include "btl_tcp.h"
|
|
|
|
#include "btl_tcp_proc.h"
|
|
|
|
|
|
|
|
static void mca_btl_tcp_proc_construct(mca_btl_tcp_proc_t* proc);
|
|
|
|
static void mca_btl_tcp_proc_destruct(mca_btl_tcp_proc_t* proc);
|
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
static mca_btl_tcp_interface_t** local_interfaces = NULL;
|
|
|
|
static int local_kindex_to_index[MAX_KERNEL_INTERFACE_INDEX];
|
|
|
|
static size_t num_local_interfaces, max_local_interfaces;
|
|
|
|
static mca_btl_tcp_interface_t** peer_interfaces = NULL;
|
|
|
|
static size_t num_peer_interfaces, max_peer_interfaces;
|
|
|
|
static int peer_kindex_to_index[MAX_KERNEL_INTERFACE_INDEX];
|
|
|
|
static unsigned int *best_assignment;
|
|
|
|
static int max_assignment_weight;
|
|
|
|
static int max_assignment_cardinality;
|
|
|
|
static enum mca_btl_tcp_connection_quality **weights;
|
|
|
|
static struct mca_btl_tcp_addr_t ***best_addr;
|
2008-02-14 00:53:00 +03:00
|
|
|
|
2007-04-28 23:13:47 +04:00
|
|
|
OBJ_CLASS_INSTANCE( mca_btl_tcp_proc_t,
|
|
|
|
opal_list_item_t,
|
|
|
|
mca_btl_tcp_proc_construct,
|
|
|
|
mca_btl_tcp_proc_destruct );
|
2005-08-02 17:20:50 +04:00
|
|
|
|
2009-01-05 17:14:38 +03:00
|
|
|
void mca_btl_tcp_proc_construct(mca_btl_tcp_proc_t* tcp_proc)
|
2005-08-02 17:20:50 +04:00
|
|
|
{
|
2009-01-05 17:14:38 +03:00
|
|
|
tcp_proc->proc_ompi = 0;
|
|
|
|
tcp_proc->proc_addrs = NULL;
|
|
|
|
tcp_proc->proc_addr_count = 0;
|
|
|
|
tcp_proc->proc_endpoints = NULL;
|
|
|
|
tcp_proc->proc_endpoint_count = 0;
|
|
|
|
OBJ_CONSTRUCT(&tcp_proc->proc_lock, opal_mutex_t);
|
2005-08-02 17:20:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cleanup ib proc instance
|
|
|
|
*/
|
|
|
|
|
2009-01-05 17:14:38 +03:00
|
|
|
void mca_btl_tcp_proc_destruct(mca_btl_tcp_proc_t* tcp_proc)
|
2005-08-02 17:20:50 +04:00
|
|
|
{
|
|
|
|
/* remove from list of all proc instances */
|
|
|
|
OPAL_THREAD_LOCK(&mca_btl_tcp_component.tcp_lock);
|
2008-03-06 01:44:35 +03:00
|
|
|
opal_hash_table_remove_value_uint64(&mca_btl_tcp_component.tcp_procs,
|
2013-01-28 03:25:10 +04:00
|
|
|
ompi_rte_hash_name(&tcp_proc->proc_ompi->proc_name));
|
2005-08-02 17:20:50 +04:00
|
|
|
OPAL_THREAD_UNLOCK(&mca_btl_tcp_component.tcp_lock);
|
|
|
|
|
|
|
|
/* release resources */
|
2009-01-05 17:14:38 +03:00
|
|
|
if(NULL != tcp_proc->proc_endpoints) {
|
|
|
|
free(tcp_proc->proc_endpoints);
|
2005-08-02 17:20:50 +04:00
|
|
|
}
|
2009-01-05 17:14:38 +03:00
|
|
|
OBJ_DESTRUCT(&tcp_proc->proc_lock);
|
2005-08-02 17:20:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a TCP process structure. There is a one-to-one correspondence
|
|
|
|
* between a ompi_proc_t and a mca_btl_tcp_proc_t instance. We cache
|
|
|
|
* additional data (specifically the list of mca_btl_tcp_endpoint_t instances,
|
|
|
|
* and published addresses) associated w/ a given destination on this
|
|
|
|
* datastructure.
|
|
|
|
*/
|
|
|
|
|
|
|
|
mca_btl_tcp_proc_t* mca_btl_tcp_proc_create(ompi_proc_t* ompi_proc)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
size_t size;
|
|
|
|
mca_btl_tcp_proc_t* btl_proc;
|
2013-01-28 03:25:10 +04:00
|
|
|
uint64_t hash = ompi_rte_hash_name(&ompi_proc->proc_name);
|
2005-08-02 17:20:50 +04:00
|
|
|
|
|
|
|
OPAL_THREAD_LOCK(&mca_btl_tcp_component.tcp_lock);
|
2008-03-06 01:44:35 +03:00
|
|
|
rc = opal_hash_table_get_value_uint64(&mca_btl_tcp_component.tcp_procs,
|
|
|
|
hash, (void**)&btl_proc);
|
|
|
|
if(OMPI_SUCCESS == rc) {
|
2005-08-02 17:20:50 +04:00
|
|
|
OPAL_THREAD_UNLOCK(&mca_btl_tcp_component.tcp_lock);
|
|
|
|
return btl_proc;
|
2007-04-28 23:13:47 +04:00
|
|
|
}
|
2007-04-25 05:55:40 +04:00
|
|
|
|
2005-08-02 17:20:50 +04:00
|
|
|
btl_proc = OBJ_NEW(mca_btl_tcp_proc_t);
|
|
|
|
if(NULL == btl_proc)
|
|
|
|
return NULL;
|
|
|
|
btl_proc->proc_ompi = ompi_proc;
|
2008-03-06 01:44:35 +03:00
|
|
|
|
2005-08-02 17:20:50 +04:00
|
|
|
/* add to hash table of all proc instance */
|
2008-03-06 01:44:35 +03:00
|
|
|
opal_hash_table_set_value_uint64(&mca_btl_tcp_component.tcp_procs,
|
|
|
|
hash, btl_proc);
|
2005-08-02 17:20:50 +04:00
|
|
|
OPAL_THREAD_UNLOCK(&mca_btl_tcp_component.tcp_lock);
|
2007-04-25 05:55:40 +04:00
|
|
|
|
2005-08-02 17:20:50 +04:00
|
|
|
/* lookup tcp parameters exported by this proc */
|
2007-07-09 21:16:34 +04:00
|
|
|
rc = ompi_modex_recv( &mca_btl_tcp_component.super.btl_version,
|
2013-05-01 03:26:03 +04:00
|
|
|
ompi_proc,
|
|
|
|
(void**)&btl_proc->proc_addrs,
|
|
|
|
&size );
|
2005-08-02 17:20:50 +04:00
|
|
|
if(rc != OMPI_SUCCESS) {
|
2013-05-01 03:26:03 +04:00
|
|
|
BTL_ERROR(("ompi_modex_recv: failed with return value=%d", rc));
|
2005-08-02 17:20:50 +04:00
|
|
|
OBJ_RELEASE(btl_proc);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if(0 != (size % sizeof(mca_btl_tcp_addr_t))) {
|
2013-05-01 03:26:03 +04:00
|
|
|
BTL_ERROR(("ompi_modex_recv: invalid size %lu: btl-size: %lu\n",
|
2009-08-13 17:45:38 +04:00
|
|
|
(unsigned long) size, (unsigned long)sizeof(mca_btl_tcp_addr_t)));
|
2005-08-02 17:20:50 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
btl_proc->proc_addr_count = size / sizeof(mca_btl_tcp_addr_t);
|
2007-04-25 05:55:40 +04:00
|
|
|
|
2005-08-02 17:20:50 +04:00
|
|
|
/* allocate space for endpoint array - one for each exported address */
|
|
|
|
btl_proc->proc_endpoints = (mca_btl_base_endpoint_t**)
|
2007-04-25 05:55:40 +04:00
|
|
|
malloc((1 + btl_proc->proc_addr_count) *
|
|
|
|
sizeof(mca_btl_base_endpoint_t*));
|
2005-08-02 17:20:50 +04:00
|
|
|
if(NULL == btl_proc->proc_endpoints) {
|
|
|
|
OBJ_RELEASE(btl_proc);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-04-25 05:55:40 +04:00
|
|
|
if(NULL == mca_btl_tcp_component.tcp_local && ompi_proc == ompi_proc_local()) {
|
2005-08-02 17:20:50 +04:00
|
|
|
mca_btl_tcp_component.tcp_local = btl_proc;
|
2007-04-25 05:55:40 +04:00
|
|
|
}
|
|
|
|
{
|
|
|
|
/* convert the OMPI addr_family field to OS constants,
|
|
|
|
* so we can check for AF_INET (or AF_INET6) and don't have
|
|
|
|
* to deal with byte ordering anymore.
|
|
|
|
*/
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < btl_proc->proc_addr_count; i++) {
|
|
|
|
if (MCA_BTL_TCP_AF_INET == btl_proc->proc_addrs[i].addr_family) {
|
|
|
|
btl_proc->proc_addrs[i].addr_family = AF_INET;
|
|
|
|
}
|
|
|
|
#if OPAL_WANT_IPV6
|
|
|
|
if (MCA_BTL_TCP_AF_INET6 == btl_proc->proc_addrs[i].addr_family) {
|
|
|
|
btl_proc->proc_addrs[i].addr_family = AF_INET6;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2005-08-02 17:20:50 +04:00
|
|
|
return btl_proc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
static void evaluate_assignment(int *a) {
|
|
|
|
size_t i;
|
|
|
|
unsigned int max_interfaces = num_local_interfaces;
|
|
|
|
int assignment_weight = 0;
|
|
|
|
int assignment_cardinality = 0;
|
|
|
|
|
|
|
|
if(max_interfaces < num_peer_interfaces) {
|
|
|
|
max_interfaces = num_peer_interfaces;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < max_interfaces; ++i) {
|
|
|
|
if(0 < weights[i][a[i]-1]) {
|
|
|
|
++assignment_cardinality;
|
|
|
|
assignment_weight += weights[i][a[i]-1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check wether current solution beats all previous solutions
|
|
|
|
*/
|
|
|
|
if(assignment_cardinality > max_assignment_cardinality
|
|
|
|
|| (assignment_cardinality == max_assignment_cardinality
|
|
|
|
&& assignment_weight > max_assignment_weight)) {
|
|
|
|
|
|
|
|
for(i = 0; i < max_interfaces; ++i) {
|
|
|
|
best_assignment[i] = a[i]-1;
|
|
|
|
}
|
|
|
|
max_assignment_weight = assignment_weight;
|
|
|
|
max_assignment_cardinality = assignment_cardinality;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void visit(int k, int level, int siz, int *a)
|
|
|
|
{
|
|
|
|
level = level+1; a[k] = level;
|
|
|
|
|
|
|
|
if (level == siz) {
|
|
|
|
evaluate_assignment(a);
|
|
|
|
} else {
|
|
|
|
int i;
|
|
|
|
for ( i = 0; i < siz; i++)
|
|
|
|
if (a[i] == 0)
|
|
|
|
visit(i, level, siz, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
level = level-1; a[k] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void mca_btl_tcp_initialise_interface(mca_btl_tcp_interface_t* interface,
|
|
|
|
int ifk_index, int index)
|
|
|
|
{
|
|
|
|
interface->kernel_index = ifk_index;
|
|
|
|
interface->peer_interface = -1;
|
|
|
|
interface->ipv4_address = NULL;
|
|
|
|
interface->ipv6_address = NULL;
|
|
|
|
interface->index = index;
|
|
|
|
interface->inuse = 0;
|
|
|
|
}
|
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
static mca_btl_tcp_interface_t** mca_btl_tcp_retrieve_local_interfaces(void)
|
2005-08-02 17:20:50 +04:00
|
|
|
{
|
2010-02-19 10:10:32 +03:00
|
|
|
struct sockaddr_storage local_addr;
|
2008-11-05 21:45:42 +03:00
|
|
|
char local_if_name[IF_NAMESIZE];
|
2010-02-19 10:10:32 +03:00
|
|
|
char **include, **exclude, **argv;
|
|
|
|
int idx;
|
2008-02-14 00:53:00 +03:00
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
if( NULL != local_interfaces )
|
|
|
|
return local_interfaces;
|
2006-02-23 05:02:19 +03:00
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
max_local_interfaces = MAX_KERNEL_INTERFACES;
|
|
|
|
num_local_interfaces = 0;
|
|
|
|
local_interfaces = (mca_btl_tcp_interface_t**)calloc( max_local_interfaces, sizeof(mca_btl_tcp_interface_t*) );
|
|
|
|
if( NULL == local_interfaces )
|
|
|
|
return NULL;
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
memset(local_kindex_to_index, -1, sizeof(int)*MAX_KERNEL_INTERFACE_INDEX);
|
|
|
|
|
2008-11-05 21:45:42 +03:00
|
|
|
/* Collect up the list of included and excluded interfaces, if any */
|
|
|
|
include = opal_argv_split(mca_btl_tcp_component.tcp_if_include,',');
|
|
|
|
exclude = opal_argv_split(mca_btl_tcp_component.tcp_if_exclude,',');
|
|
|
|
|
2008-02-14 00:53:00 +03:00
|
|
|
/*
|
|
|
|
* identify all kernel interfaces and the associated addresses of
|
|
|
|
* the local node
|
|
|
|
*/
|
2010-02-19 10:10:32 +03:00
|
|
|
for( idx = opal_ifbegin(); idx >= 0; idx = opal_ifnext (idx) ) {
|
2008-02-14 00:53:00 +03:00
|
|
|
int kindex, index;
|
2010-02-26 21:08:04 +03:00
|
|
|
bool skip = false;
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
opal_ifindextoaddr (idx, (struct sockaddr*) &local_addr, sizeof (local_addr));
|
2008-11-05 21:45:42 +03:00
|
|
|
opal_ifindextoname (idx, local_if_name, sizeof (local_if_name));
|
|
|
|
|
2010-02-26 21:08:04 +03:00
|
|
|
/* If we were given a list of included interfaces, then check
|
|
|
|
* to see if the current one is a member of this set. If so,
|
|
|
|
* drop down and complete processing. If not, skip it and
|
|
|
|
* continue on to the next one. Note that providing an include
|
|
|
|
* list will override providing an exclude list as the two are
|
|
|
|
* mutually exclusive. This matches how it works in
|
|
|
|
* mca_btl_tcp_component_create_instances() which is the function
|
|
|
|
* that exports the interfaces. */
|
2008-11-05 21:45:42 +03:00
|
|
|
if(NULL != include) {
|
|
|
|
argv = include;
|
|
|
|
skip = true;
|
|
|
|
while(argv && *argv) {
|
|
|
|
/* When comparing included interfaces, we look for exact matches.
|
|
|
|
That is why we are using strcmp() here. */
|
|
|
|
if (0 == strcmp(*argv, local_if_name)) {
|
|
|
|
skip = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
argv++;
|
|
|
|
}
|
2010-02-26 21:08:04 +03:00
|
|
|
} else if (NULL != exclude) {
|
|
|
|
/* If we were given a list of excluded interfaces, then check to see if the
|
|
|
|
* current one is a member of this set. If not, drop down and complete
|
|
|
|
* processing. If so, skip it and continue on to the next one. */
|
2008-11-05 21:45:42 +03:00
|
|
|
argv = exclude;
|
|
|
|
while(argv && *argv) {
|
|
|
|
/* When looking for interfaces to exclude, we only look at
|
|
|
|
* the number of characters equal to what the user provided.
|
|
|
|
* For example, excluding "lo" excludes "lo", "lo0" and
|
|
|
|
* anything that starts with "lo" */
|
|
|
|
if(0 == strncmp(*argv, local_if_name, strlen(*argv))) {
|
|
|
|
skip = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
argv++;
|
|
|
|
}
|
2010-02-19 10:10:32 +03:00
|
|
|
}
|
|
|
|
if (true == skip) {
|
|
|
|
/* This interface is not part of the requested set, so skip it */
|
|
|
|
continue;
|
2008-11-05 21:45:42 +03:00
|
|
|
}
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
kindex = opal_ifindextokindex(idx);
|
|
|
|
index = local_kindex_to_index[kindex];
|
|
|
|
|
2008-04-16 14:14:58 +04:00
|
|
|
/* create entry for this kernel index previously not seen */
|
2008-02-14 00:53:00 +03:00
|
|
|
if(-1 == index) {
|
|
|
|
index = num_local_interfaces++;
|
|
|
|
local_kindex_to_index[kindex] = index;
|
2010-02-19 10:10:32 +03:00
|
|
|
|
|
|
|
if( num_local_interfaces == max_local_interfaces ) {
|
|
|
|
max_local_interfaces <<= 1;
|
|
|
|
local_interfaces = (mca_btl_tcp_interface_t**)realloc( local_interfaces,
|
|
|
|
max_local_interfaces * sizeof(mca_btl_tcp_interface_t*) );
|
|
|
|
if( NULL == local_interfaces )
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-09-08 19:39:30 +04:00
|
|
|
local_interfaces[index] = (mca_btl_tcp_interface_t *) malloc(sizeof(mca_btl_tcp_interface_t));
|
2008-02-14 00:53:00 +03:00
|
|
|
assert(NULL != local_interfaces[index]);
|
|
|
|
mca_btl_tcp_initialise_interface(local_interfaces[index], kindex, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(local_addr.ss_family) {
|
2010-02-19 10:10:32 +03:00
|
|
|
case AF_INET:
|
|
|
|
/* if AF is disabled, skip it completely */
|
|
|
|
if (4 == mca_btl_tcp_component.tcp_disable_family) {
|
|
|
|
continue;
|
|
|
|
}
|
2008-04-16 14:14:58 +04:00
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
local_interfaces[local_kindex_to_index[kindex]]->ipv4_address =
|
|
|
|
(struct sockaddr_storage*) malloc(sizeof(local_addr));
|
|
|
|
memcpy(local_interfaces[local_kindex_to_index[kindex]]->ipv4_address,
|
|
|
|
&local_addr, sizeof(local_addr));
|
|
|
|
opal_ifindextomask(idx,
|
|
|
|
&local_interfaces[local_kindex_to_index[kindex]]->ipv4_netmask,
|
|
|
|
sizeof(int));
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
/* if AF is disabled, skip it completely */
|
|
|
|
if (6 == mca_btl_tcp_component.tcp_disable_family) {
|
|
|
|
continue;
|
|
|
|
}
|
2008-04-16 14:14:58 +04:00
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
local_interfaces[local_kindex_to_index[kindex]]->ipv6_address
|
|
|
|
= (struct sockaddr_storage*) malloc(sizeof(local_addr));
|
|
|
|
memcpy(local_interfaces[local_kindex_to_index[kindex]]->ipv6_address,
|
|
|
|
&local_addr, sizeof(local_addr));
|
|
|
|
opal_ifindextomask(idx,
|
|
|
|
&local_interfaces[local_kindex_to_index[kindex]]->ipv6_netmask,
|
|
|
|
sizeof(int));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
opal_output(0, "unknown address family for tcp: %d\n",
|
2008-02-14 00:53:00 +03:00
|
|
|
local_addr.ss_family);
|
|
|
|
}
|
|
|
|
}
|
2008-11-05 21:45:42 +03:00
|
|
|
opal_argv_free(include);
|
|
|
|
opal_argv_free(exclude);
|
2008-02-14 00:53:00 +03:00
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
return local_interfaces;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Note that this routine must be called with the lock on the process
|
|
|
|
* already held. Insert a btl instance into the proc array and assign
|
|
|
|
* it an address.
|
|
|
|
*/
|
|
|
|
int mca_btl_tcp_proc_insert( mca_btl_tcp_proc_t* btl_proc,
|
|
|
|
mca_btl_base_endpoint_t* btl_endpoint )
|
|
|
|
{
|
|
|
|
struct sockaddr_storage endpoint_addr_ss;
|
When we direct launch an application, we rely on PMI for wireup support. In doing so, we lose the de facto data compression we get from the ORTE modex since we no longer get all the wireup info from every proc in a single blob. Instead, we have to iterate over all the procs, calling PMI_KVS_get for every value we require.
This creates a really bad scaling behavior. Users have found a nearly 20% launch time differential between mpirun and PMI, with PMI being the slower method. Some of the problem is attributable to poor exchange algorithms in RM's like Slurm and Alps, but we make things worse by calling "get" so many times.
Nathan (with a tad advice from me) has attempted to alleviate this problem by reducing the number of "get" calls. This required the following changes:
* upon first request for data, have the OPAL db pmi component fetch and decode *all* the info from a given remote proc. It turned out we weren't caching the info, so we would continually request it and only decode the piece we needed for the immediate request. We now decode all the info and push it into the db hash component for local storage - and then all subsequent retrievals are fulfilled locally
* reduced the amount of data by eliminating the exchange of the OMPI_ARCH value if heterogeneity is not enabled. This was used solely as a check so we would error out if the system wasn't actually homogeneous, which was fine when we thought there was no cost in doing the check. Unfortunately, at large scale and with direct launch, there is a non-zero cost of making this test. We are open to finding a compromise (perhaps turning the test off if requested?), if people feel strongly about performing the test
* reduced the amount of RTE data being automatically fetched, and fetched the rest only upon request. In particular, we no longer immediately fetch the hostname (which is only used for error reporting), but instead get it when needed. Likewise for the RML uri as that info is only required for some (not all) environments. In addition, we no longer fetch the locality unless required, relying instead on the PMI clique info to tell us who is on our local node (if additional info is required, the fetch is performed when a modex_recv is issued).
Again, all this only impacts direct launch - all the info is provided when launched via mpirun as there is no added cost to getting it
Barring objections, we may move this (plus any required other pieces) to the 1.7 branch once it soaks for an appropriate time.
This commit was SVN r29040.
2013-08-17 04:49:18 +04:00
|
|
|
const char *proc_hostname;
|
2010-02-19 10:10:32 +03:00
|
|
|
unsigned int perm_size;
|
|
|
|
int rc, *a = NULL;
|
|
|
|
size_t i, j;
|
|
|
|
|
As per the email discussion, revise the sparse handling of hostnames so that we avoid potential infinite loops while allowing large-scale users to improve their startup time:
* add a new MCA param orte_hostname_cutoff to specify the number of nodes at which we stop including hostnames. This defaults to INT_MAX => always include hostnames. If a value is given, then we will include hostnames for any allocation smaller than the given limit.
* remove ompi_proc_get_hostname. Replace all occurrences with a direct link to ompi_proc_t's proc_hostname, protected by appropriate "if NULL"
* modify the OMPI-ORTE integration component so that any call to modex_recv automatically loads the ompi_proc_t->proc_hostname field as well as returning the requested info. Thus, any process whose modex info you retrieve will automatically receive the hostname. Note that on-demand retrieval is still enabled - i.e., if we are running under direct launch with PMI, the hostname will be fetched upon first call to modex_recv, and then the ompi_proc_t->proc_hostname field will be loaded
* removed a stale MCA param "mpi_keep_peer_hostnames" that was no longer used anywhere in the code base
* added an envar lookup in ess/pmi for the number of nodes in the allocation. Sadly, PMI itself doesn't provide that info, so we have to get it a different way. Currently, we support PBS-based systems and SLURM - for any other, rank0 will emit a warning and we assume max number of daemons so we will always retain hostnames
This commit was SVN r29052.
2013-08-20 22:59:36 +04:00
|
|
|
if (NULL == (proc_hostname = btl_proc->proc_ompi->proc_hostname)) {
|
|
|
|
return OMPI_ERR_UNREACH;
|
|
|
|
}
|
When we direct launch an application, we rely on PMI for wireup support. In doing so, we lose the de facto data compression we get from the ORTE modex since we no longer get all the wireup info from every proc in a single blob. Instead, we have to iterate over all the procs, calling PMI_KVS_get for every value we require.
This creates a really bad scaling behavior. Users have found a nearly 20% launch time differential between mpirun and PMI, with PMI being the slower method. Some of the problem is attributable to poor exchange algorithms in RM's like Slurm and Alps, but we make things worse by calling "get" so many times.
Nathan (with a tad advice from me) has attempted to alleviate this problem by reducing the number of "get" calls. This required the following changes:
* upon first request for data, have the OPAL db pmi component fetch and decode *all* the info from a given remote proc. It turned out we weren't caching the info, so we would continually request it and only decode the piece we needed for the immediate request. We now decode all the info and push it into the db hash component for local storage - and then all subsequent retrievals are fulfilled locally
* reduced the amount of data by eliminating the exchange of the OMPI_ARCH value if heterogeneity is not enabled. This was used solely as a check so we would error out if the system wasn't actually homogeneous, which was fine when we thought there was no cost in doing the check. Unfortunately, at large scale and with direct launch, there is a non-zero cost of making this test. We are open to finding a compromise (perhaps turning the test off if requested?), if people feel strongly about performing the test
* reduced the amount of RTE data being automatically fetched, and fetched the rest only upon request. In particular, we no longer immediately fetch the hostname (which is only used for error reporting), but instead get it when needed. Likewise for the RML uri as that info is only required for some (not all) environments. In addition, we no longer fetch the locality unless required, relying instead on the PMI clique info to tell us who is on our local node (if additional info is required, the fetch is performed when a modex_recv is issued).
Again, all this only impacts direct launch - all the info is provided when launched via mpirun as there is no added cost to getting it
Barring objections, we may move this (plus any required other pieces) to the 1.7 branch once it soaks for an appropriate time.
This commit was SVN r29040.
2013-08-17 04:49:18 +04:00
|
|
|
|
2010-02-19 10:10:32 +03:00
|
|
|
#ifndef WORDS_BIGENDIAN
|
|
|
|
/* if we are little endian and our peer is not so lucky, then we
|
|
|
|
need to put all information sent to him in big endian (aka
|
|
|
|
Network Byte Order) and expect all information received to
|
|
|
|
be in NBO. Since big endian machines always send and receive
|
|
|
|
in NBO, we don't care so much about that case. */
|
|
|
|
if (btl_proc->proc_ompi->proc_arch & OPAL_ARCH_ISBIGENDIAN) {
|
|
|
|
btl_endpoint->endpoint_nbo = true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* insert into endpoint array */
|
|
|
|
btl_endpoint->endpoint_proc = btl_proc;
|
|
|
|
btl_proc->proc_endpoints[btl_proc->proc_endpoint_count++] = btl_endpoint;
|
|
|
|
|
|
|
|
/* sanity checks */
|
|
|
|
if( NULL == local_interfaces ) {
|
|
|
|
if( NULL == mca_btl_tcp_retrieve_local_interfaces() )
|
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
|
|
|
if( 0 == num_local_interfaces ) {
|
|
|
|
return OMPI_ERR_UNREACH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( NULL == peer_interfaces ) {
|
|
|
|
max_peer_interfaces = max_local_interfaces;
|
|
|
|
peer_interfaces = (mca_btl_tcp_interface_t**)malloc( max_peer_interfaces * sizeof(mca_btl_tcp_interface_t*) );
|
|
|
|
}
|
|
|
|
num_peer_interfaces = 0;
|
|
|
|
memset(peer_kindex_to_index, -1, sizeof(int)*MAX_KERNEL_INTERFACE_INDEX);
|
|
|
|
memset(peer_interfaces, 0, max_peer_interfaces * sizeof(mca_btl_tcp_interface_t*));
|
|
|
|
|
2005-08-02 17:20:50 +04:00
|
|
|
/*
|
2008-02-14 00:53:00 +03:00
|
|
|
* identify all kernel interfaces and the associated addresses of
|
|
|
|
* the peer
|
|
|
|
*/
|
|
|
|
|
2007-04-28 23:13:47 +04:00
|
|
|
for( i = 0; i < btl_proc->proc_addr_count; i++ ) {
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
int index;
|
|
|
|
|
2005-08-02 17:20:50 +04:00
|
|
|
mca_btl_tcp_addr_t* endpoint_addr = btl_proc->proc_addrs + i;
|
2008-02-14 00:53:00 +03:00
|
|
|
|
2007-04-25 05:55:40 +04:00
|
|
|
mca_btl_tcp_proc_tosocks (endpoint_addr, &endpoint_addr_ss);
|
2006-02-23 05:02:19 +03:00
|
|
|
|
2008-02-14 00:53:00 +03:00
|
|
|
index = peer_kindex_to_index[endpoint_addr->addr_ifkindex];
|
2006-02-23 05:02:19 +03:00
|
|
|
|
2008-02-14 00:53:00 +03:00
|
|
|
if(-1 == index) {
|
|
|
|
index = num_peer_interfaces++;
|
|
|
|
peer_kindex_to_index[endpoint_addr->addr_ifkindex] = index;
|
2010-02-19 10:10:32 +03:00
|
|
|
if( num_peer_interfaces == max_peer_interfaces ) {
|
|
|
|
max_peer_interfaces <<= 1;
|
|
|
|
peer_interfaces = (mca_btl_tcp_interface_t**)realloc( peer_interfaces,
|
|
|
|
max_peer_interfaces * sizeof(mca_btl_tcp_interface_t*) );
|
|
|
|
if( NULL == peer_interfaces )
|
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
2008-09-08 19:39:30 +04:00
|
|
|
peer_interfaces[index] = (mca_btl_tcp_interface_t *) malloc(sizeof(mca_btl_tcp_interface_t));
|
2008-02-14 00:53:00 +03:00
|
|
|
mca_btl_tcp_initialise_interface(peer_interfaces[index],
|
2010-02-19 10:10:32 +03:00
|
|
|
endpoint_addr->addr_ifkindex, index);
|
2008-02-14 00:53:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* in case one of the peer addresses is already in use,
|
|
|
|
* mark the complete peer interface as 'not available'
|
2007-04-25 05:55:40 +04:00
|
|
|
*/
|
2008-02-14 00:53:00 +03:00
|
|
|
if(endpoint_addr->addr_inuse) {
|
|
|
|
peer_interfaces[index]->inuse = 1;
|
2007-04-25 05:55:40 +04:00
|
|
|
}
|
|
|
|
|
2008-02-14 00:53:00 +03:00
|
|
|
switch(endpoint_addr_ss.ss_family) {
|
2010-02-19 10:10:32 +03:00
|
|
|
case AF_INET:
|
|
|
|
peer_interfaces[index]->ipv4_address = (struct sockaddr_storage*) malloc(sizeof(endpoint_addr_ss));
|
|
|
|
peer_interfaces[index]->ipv4_endpoint_addr = endpoint_addr;
|
|
|
|
memcpy(peer_interfaces[index]->ipv4_address,
|
|
|
|
&endpoint_addr_ss, sizeof(endpoint_addr_ss));
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
peer_interfaces[index]->ipv6_address = (struct sockaddr_storage*) malloc(sizeof(endpoint_addr_ss));
|
|
|
|
peer_interfaces[index]->ipv6_endpoint_addr = endpoint_addr;
|
|
|
|
memcpy(peer_interfaces[index]->ipv6_address,
|
|
|
|
&endpoint_addr_ss, sizeof(endpoint_addr_ss));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
opal_output(0, "unknown address family for tcp: %d\n",
|
|
|
|
endpoint_addr_ss.ss_family);
|
|
|
|
/*
|
|
|
|
* return OMPI_UNREACH or some error, as this is not
|
|
|
|
* good
|
|
|
|
*/
|
2008-02-14 00:53:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* assign weights to each possible pair of interfaces
|
|
|
|
*/
|
|
|
|
|
|
|
|
perm_size = num_local_interfaces;
|
|
|
|
if(num_peer_interfaces > perm_size) {
|
|
|
|
perm_size = num_peer_interfaces;
|
|
|
|
}
|
|
|
|
|
|
|
|
weights = (enum mca_btl_tcp_connection_quality**) malloc(perm_size
|
2010-02-19 10:10:32 +03:00
|
|
|
* sizeof(enum mca_btl_tcp_connection_quality*));
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
best_addr = (mca_btl_tcp_addr_t ***) malloc(perm_size
|
2010-02-19 10:10:32 +03:00
|
|
|
* sizeof(mca_btl_tcp_addr_t **));
|
2008-02-14 00:53:00 +03:00
|
|
|
for(i = 0; i < perm_size; ++i) {
|
|
|
|
weights[i] = (enum mca_btl_tcp_connection_quality*) malloc(perm_size *
|
2010-02-19 10:10:32 +03:00
|
|
|
sizeof(enum mca_btl_tcp_connection_quality));
|
2008-02-14 00:53:00 +03:00
|
|
|
memset(weights[i], 0, perm_size * sizeof(enum mca_btl_tcp_connection_quality));
|
|
|
|
|
|
|
|
best_addr[i] = (mca_btl_tcp_addr_t **) malloc(perm_size *
|
2010-02-19 10:10:32 +03:00
|
|
|
sizeof(mca_btl_tcp_addr_t *));
|
2008-02-14 00:53:00 +03:00
|
|
|
memset(best_addr[i], 0, perm_size * sizeof(mca_btl_tcp_addr_t *));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for(i=0; i<num_local_interfaces; ++i) {
|
|
|
|
for(j=0; j<num_peer_interfaces; ++j) {
|
|
|
|
|
|
|
|
/* initially, assume no connection is possible */
|
|
|
|
weights[i][j] = CQ_NO_CONNECTION;
|
|
|
|
|
|
|
|
/* check state of ipv4 address pair */
|
|
|
|
if(NULL != local_interfaces[i]->ipv4_address &&
|
|
|
|
NULL != peer_interfaces[j]->ipv4_address) {
|
|
|
|
|
2010-03-03 18:51:15 +03:00
|
|
|
/* check for loopback */
|
|
|
|
if ((opal_net_islocalhost((struct sockaddr *)local_interfaces[i]->ipv4_address)
|
|
|
|
&& !opal_net_islocalhost((struct sockaddr *)peer_interfaces[j]->ipv4_address))
|
|
|
|
|| (opal_net_islocalhost((struct sockaddr *)peer_interfaces[j]->ipv4_address)
|
|
|
|
&& !opal_net_islocalhost((struct sockaddr *)local_interfaces[i]->ipv4_address))
|
|
|
|
|| (opal_net_islocalhost((struct sockaddr *)local_interfaces[i]->ipv4_address)
|
When we direct launch an application, we rely on PMI for wireup support. In doing so, we lose the de facto data compression we get from the ORTE modex since we no longer get all the wireup info from every proc in a single blob. Instead, we have to iterate over all the procs, calling PMI_KVS_get for every value we require.
This creates a really bad scaling behavior. Users have found a nearly 20% launch time differential between mpirun and PMI, with PMI being the slower method. Some of the problem is attributable to poor exchange algorithms in RM's like Slurm and Alps, but we make things worse by calling "get" so many times.
Nathan (with a tad advice from me) has attempted to alleviate this problem by reducing the number of "get" calls. This required the following changes:
* upon first request for data, have the OPAL db pmi component fetch and decode *all* the info from a given remote proc. It turned out we weren't caching the info, so we would continually request it and only decode the piece we needed for the immediate request. We now decode all the info and push it into the db hash component for local storage - and then all subsequent retrievals are fulfilled locally
* reduced the amount of data by eliminating the exchange of the OMPI_ARCH value if heterogeneity is not enabled. This was used solely as a check so we would error out if the system wasn't actually homogeneous, which was fine when we thought there was no cost in doing the check. Unfortunately, at large scale and with direct launch, there is a non-zero cost of making this test. We are open to finding a compromise (perhaps turning the test off if requested?), if people feel strongly about performing the test
* reduced the amount of RTE data being automatically fetched, and fetched the rest only upon request. In particular, we no longer immediately fetch the hostname (which is only used for error reporting), but instead get it when needed. Likewise for the RML uri as that info is only required for some (not all) environments. In addition, we no longer fetch the locality unless required, relying instead on the PMI clique info to tell us who is on our local node (if additional info is required, the fetch is performed when a modex_recv is issued).
Again, all this only impacts direct launch - all the info is provided when launched via mpirun as there is no added cost to getting it
Barring objections, we may move this (plus any required other pieces) to the 1.7 branch once it soaks for an appropriate time.
This commit was SVN r29040.
2013-08-17 04:49:18 +04:00
|
|
|
&& !opal_ifislocal(proc_hostname))) {
|
2010-03-03 18:51:15 +03:00
|
|
|
|
|
|
|
/* No connection is possible on these interfaces */
|
|
|
|
|
2010-05-20 01:20:33 +04:00
|
|
|
/* check for RFC1918 */
|
2010-03-03 18:51:15 +03:00
|
|
|
} else if(opal_net_addr_isipv4public((struct sockaddr*) local_interfaces[i]->ipv4_address)
|
2010-05-20 01:20:33 +04:00
|
|
|
&& opal_net_addr_isipv4public((struct sockaddr*)
|
|
|
|
peer_interfaces[j]->ipv4_address)) {
|
2008-02-14 00:53:00 +03:00
|
|
|
if(opal_net_samenetwork((struct sockaddr*) local_interfaces[i]->ipv4_address,
|
2010-02-19 10:10:32 +03:00
|
|
|
(struct sockaddr*) peer_interfaces[j]->ipv4_address,
|
|
|
|
local_interfaces[i]->ipv4_netmask)) {
|
2008-02-14 00:53:00 +03:00
|
|
|
weights[i][j] = CQ_PUBLIC_SAME_NETWORK;
|
|
|
|
} else {
|
|
|
|
weights[i][j] = CQ_PUBLIC_DIFFERENT_NETWORK;
|
2007-04-25 05:55:40 +04:00
|
|
|
}
|
2008-02-14 00:53:00 +03:00
|
|
|
best_addr[i][j] = peer_interfaces[j]->ipv4_endpoint_addr;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
if(opal_net_samenetwork((struct sockaddr*) local_interfaces[i]->ipv4_address,
|
2010-02-19 10:10:32 +03:00
|
|
|
(struct sockaddr*) peer_interfaces[j]->ipv4_address,
|
|
|
|
local_interfaces[i]->ipv4_netmask)) {
|
2008-02-14 00:53:00 +03:00
|
|
|
weights[i][j] = CQ_PRIVATE_SAME_NETWORK;
|
|
|
|
} else {
|
|
|
|
weights[i][j] = CQ_PRIVATE_DIFFERENT_NETWORK;
|
|
|
|
}
|
|
|
|
best_addr[i][j] = peer_interfaces[j]->ipv4_endpoint_addr;
|
2007-04-25 05:55:40 +04:00
|
|
|
}
|
2006-02-23 05:02:19 +03:00
|
|
|
}
|
|
|
|
|
2008-02-14 00:53:00 +03:00
|
|
|
/* check state of ipv6 address pair - ipv6 is always public,
|
|
|
|
* since link-local addresses are skipped in opal_ifinit()
|
|
|
|
*/
|
|
|
|
if(NULL != local_interfaces[i]->ipv6_address &&
|
|
|
|
NULL != peer_interfaces[j]->ipv6_address) {
|
2010-03-03 18:51:15 +03:00
|
|
|
|
|
|
|
/* check for loopback */
|
|
|
|
if ((opal_net_islocalhost((struct sockaddr *)local_interfaces[i]->ipv6_address)
|
|
|
|
&& !opal_net_islocalhost((struct sockaddr *)peer_interfaces[j]->ipv6_address))
|
|
|
|
|| (opal_net_islocalhost((struct sockaddr *)peer_interfaces[j]->ipv6_address)
|
|
|
|
&& !opal_net_islocalhost((struct sockaddr *)local_interfaces[i]->ipv6_address))
|
|
|
|
|| (opal_net_islocalhost((struct sockaddr *)local_interfaces[i]->ipv6_address)
|
When we direct launch an application, we rely on PMI for wireup support. In doing so, we lose the de facto data compression we get from the ORTE modex since we no longer get all the wireup info from every proc in a single blob. Instead, we have to iterate over all the procs, calling PMI_KVS_get for every value we require.
This creates a really bad scaling behavior. Users have found a nearly 20% launch time differential between mpirun and PMI, with PMI being the slower method. Some of the problem is attributable to poor exchange algorithms in RM's like Slurm and Alps, but we make things worse by calling "get" so many times.
Nathan (with a tad advice from me) has attempted to alleviate this problem by reducing the number of "get" calls. This required the following changes:
* upon first request for data, have the OPAL db pmi component fetch and decode *all* the info from a given remote proc. It turned out we weren't caching the info, so we would continually request it and only decode the piece we needed for the immediate request. We now decode all the info and push it into the db hash component for local storage - and then all subsequent retrievals are fulfilled locally
* reduced the amount of data by eliminating the exchange of the OMPI_ARCH value if heterogeneity is not enabled. This was used solely as a check so we would error out if the system wasn't actually homogeneous, which was fine when we thought there was no cost in doing the check. Unfortunately, at large scale and with direct launch, there is a non-zero cost of making this test. We are open to finding a compromise (perhaps turning the test off if requested?), if people feel strongly about performing the test
* reduced the amount of RTE data being automatically fetched, and fetched the rest only upon request. In particular, we no longer immediately fetch the hostname (which is only used for error reporting), but instead get it when needed. Likewise for the RML uri as that info is only required for some (not all) environments. In addition, we no longer fetch the locality unless required, relying instead on the PMI clique info to tell us who is on our local node (if additional info is required, the fetch is performed when a modex_recv is issued).
Again, all this only impacts direct launch - all the info is provided when launched via mpirun as there is no added cost to getting it
Barring objections, we may move this (plus any required other pieces) to the 1.7 branch once it soaks for an appropriate time.
This commit was SVN r29040.
2013-08-17 04:49:18 +04:00
|
|
|
&& !opal_ifislocal(proc_hostname))) {
|
2010-03-03 18:51:15 +03:00
|
|
|
|
|
|
|
/* No connection is possible on these interfaces */
|
|
|
|
|
|
|
|
} else if(opal_net_samenetwork((struct sockaddr*) local_interfaces[i]->ipv6_address,
|
2010-05-20 01:20:33 +04:00
|
|
|
(struct sockaddr*) peer_interfaces[j]->ipv6_address,
|
|
|
|
local_interfaces[i]->ipv6_netmask)) {
|
2008-02-14 00:53:00 +03:00
|
|
|
weights[i][j] = CQ_PUBLIC_SAME_NETWORK;
|
|
|
|
} else {
|
|
|
|
weights[i][j] = CQ_PUBLIC_DIFFERENT_NETWORK;
|
|
|
|
}
|
|
|
|
best_addr[i][j] = peer_interfaces[j]->ipv6_endpoint_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* for each peer interface */
|
|
|
|
} /* for each local interface */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* determine the size of the set to permute (max number of
|
|
|
|
* interfaces
|
|
|
|
*/
|
|
|
|
|
2008-09-08 19:39:30 +04:00
|
|
|
best_assignment = (unsigned int *) malloc (perm_size * sizeof(int));
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
a = (int *) malloc(perm_size * sizeof(int));
|
|
|
|
if (NULL == a) {
|
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
|
|
|
|
2010-04-14 18:18:35 +04:00
|
|
|
/* Can only find the best set of connections when the number of
|
|
|
|
* interfaces is not too big. When it gets larger, we fall back
|
2010-05-13 17:55:54 +04:00
|
|
|
* to a simpler and faster (and not as optimal) algorithm.
|
|
|
|
* See ticket https://svn.open-mpi.org/trac/ompi/ticket/2031
|
|
|
|
* for more details about this issue. */
|
2010-04-14 18:18:35 +04:00
|
|
|
if (perm_size <= MAX_PERMUTATION_INTERFACES) {
|
2010-05-20 01:20:33 +04:00
|
|
|
memset(a, 0, perm_size * sizeof(int));
|
|
|
|
max_assignment_cardinality = -1;
|
|
|
|
max_assignment_weight = -1;
|
|
|
|
visit(0, -1, perm_size, a);
|
|
|
|
|
|
|
|
rc = OMPI_ERR_UNREACH;
|
|
|
|
for(i = 0; i < perm_size; ++i) {
|
|
|
|
if(best_assignment[i] > num_peer_interfaces
|
|
|
|
|| weights[i][best_assignment[i]] == CQ_NO_CONNECTION
|
|
|
|
|| peer_interfaces[best_assignment[i]]->inuse
|
|
|
|
|| NULL == peer_interfaces[best_assignment[i]]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
peer_interfaces[best_assignment[i]]->inuse++;
|
|
|
|
btl_endpoint->endpoint_addr = best_addr[i][best_assignment[i]];
|
|
|
|
btl_endpoint->endpoint_addr->addr_inuse++;
|
|
|
|
rc = OMPI_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
2010-04-14 18:18:35 +04:00
|
|
|
} else {
|
2010-05-20 01:20:33 +04:00
|
|
|
enum mca_btl_tcp_connection_quality max;
|
|
|
|
int i_max = 0, j_max = 0;
|
|
|
|
/* Find the best connection that is not in use. Save away
|
|
|
|
* the indices of the best location. */
|
|
|
|
max = CQ_NO_CONNECTION;
|
|
|
|
for(i=0; i<num_local_interfaces; ++i) {
|
|
|
|
for(j=0; j<num_peer_interfaces; ++j) {
|
|
|
|
if (!peer_interfaces[j]->inuse) {
|
|
|
|
if (weights[i][j] > max) {
|
|
|
|
max = weights[i][j];
|
|
|
|
i_max = i;
|
|
|
|
j_max = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Now see if there is a some type of connection available. */
|
|
|
|
rc = OMPI_ERR_UNREACH;
|
|
|
|
if (CQ_NO_CONNECTION != max) {
|
|
|
|
peer_interfaces[j_max]->inuse++;
|
|
|
|
btl_endpoint->endpoint_addr = best_addr[i_max][j_max];
|
|
|
|
btl_endpoint->endpoint_addr->addr_inuse++;
|
|
|
|
rc = OMPI_SUCCESS;
|
|
|
|
}
|
2005-11-12 03:31:34 +03:00
|
|
|
}
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
for(i = 0; i < perm_size; ++i) {
|
|
|
|
free(weights[i]);
|
|
|
|
free(best_addr[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < num_peer_interfaces; ++i) {
|
|
|
|
if(NULL != peer_interfaces[i]->ipv4_address) {
|
|
|
|
free(peer_interfaces[i]->ipv4_address);
|
|
|
|
}
|
|
|
|
if(NULL != peer_interfaces[i]->ipv6_address) {
|
|
|
|
free(peer_interfaces[i]->ipv6_address);
|
|
|
|
}
|
|
|
|
free(peer_interfaces[i]);
|
|
|
|
}
|
2010-02-19 10:10:32 +03:00
|
|
|
free(peer_interfaces);
|
|
|
|
peer_interfaces = NULL;
|
|
|
|
max_peer_interfaces = 0;
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
for(i = 0; i < num_local_interfaces; ++i) {
|
|
|
|
if(NULL != local_interfaces[i]->ipv4_address) {
|
|
|
|
free(local_interfaces[i]->ipv4_address);
|
|
|
|
}
|
|
|
|
if(NULL != local_interfaces[i]->ipv6_address) {
|
|
|
|
free(local_interfaces[i]->ipv6_address);
|
|
|
|
}
|
|
|
|
free(local_interfaces[i]);
|
|
|
|
}
|
2010-02-19 10:10:32 +03:00
|
|
|
free(local_interfaces);
|
|
|
|
local_interfaces = NULL;
|
|
|
|
max_local_interfaces = 0;
|
2008-02-14 00:53:00 +03:00
|
|
|
|
|
|
|
free(weights);
|
|
|
|
free(best_addr);
|
|
|
|
free(best_assignment);
|
|
|
|
free(a);
|
|
|
|
|
|
|
|
return rc;
|
2005-08-02 17:20:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove an endpoint from the proc array and indicate the address is
|
|
|
|
* no longer in use.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int mca_btl_tcp_proc_remove(mca_btl_tcp_proc_t* btl_proc, mca_btl_base_endpoint_t* btl_endpoint)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
OPAL_THREAD_LOCK(&btl_proc->proc_lock);
|
2013-01-21 15:41:08 +04:00
|
|
|
for(i = 0; i < btl_proc->proc_endpoint_count; i++) {
|
2005-08-02 17:20:50 +04:00
|
|
|
if(btl_proc->proc_endpoints[i] == btl_endpoint) {
|
|
|
|
memmove(btl_proc->proc_endpoints+i, btl_proc->proc_endpoints+i+1,
|
|
|
|
(btl_proc->proc_endpoint_count-i-1)*sizeof(mca_btl_base_endpoint_t*));
|
|
|
|
if(--btl_proc->proc_endpoint_count == 0) {
|
|
|
|
OPAL_THREAD_UNLOCK(&btl_proc->proc_lock);
|
|
|
|
OBJ_RELEASE(btl_proc);
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
2006-05-16 23:01:08 +04:00
|
|
|
/* The endpoint_addr may still be NULL if this enpoint is
|
|
|
|
being removed early in the wireup sequence (e.g., if it
|
|
|
|
is unreachable by all other procs) */
|
|
|
|
if (NULL != btl_endpoint->endpoint_addr) {
|
|
|
|
btl_endpoint->endpoint_addr->addr_inuse--;
|
|
|
|
}
|
2005-08-02 17:20:50 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OPAL_THREAD_UNLOCK(&btl_proc->proc_lock);
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for an existing TCP process instance based on the globally unique
|
|
|
|
* process identifier.
|
|
|
|
*/
|
2013-01-28 03:25:10 +04:00
|
|
|
mca_btl_tcp_proc_t* mca_btl_tcp_proc_lookup(const ompi_process_name_t *name)
|
2005-08-02 17:20:50 +04:00
|
|
|
{
|
2008-03-06 01:44:35 +03:00
|
|
|
mca_btl_tcp_proc_t* proc = NULL;
|
2005-08-02 17:20:50 +04:00
|
|
|
OPAL_THREAD_LOCK(&mca_btl_tcp_component.tcp_lock);
|
2008-03-06 01:44:35 +03:00
|
|
|
opal_hash_table_get_value_uint64(&mca_btl_tcp_component.tcp_procs,
|
2013-01-28 03:25:10 +04:00
|
|
|
ompi_rte_hash_name(name), (void**)&proc);
|
2005-08-02 17:20:50 +04:00
|
|
|
OPAL_THREAD_UNLOCK(&mca_btl_tcp_component.tcp_lock);
|
|
|
|
return proc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-04-28 23:13:47 +04:00
|
|
|
* loop through all available BTLs for one matching the source address
|
2005-08-02 17:20:50 +04:00
|
|
|
* of the request.
|
|
|
|
*/
|
2007-04-28 23:13:47 +04:00
|
|
|
bool mca_btl_tcp_proc_accept(mca_btl_tcp_proc_t* btl_proc, struct sockaddr* addr, int sd)
|
2005-08-02 17:20:50 +04:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
OPAL_THREAD_LOCK(&btl_proc->proc_lock);
|
2008-01-30 17:31:47 +03:00
|
|
|
for( i = 0; i < btl_proc->proc_endpoint_count; i++ ) {
|
|
|
|
mca_btl_base_endpoint_t* btl_endpoint = btl_proc->proc_endpoints[i];
|
2007-04-29 20:23:11 +04:00
|
|
|
/* Check all conditions before going to try to accept the connection. */
|
2008-01-30 17:31:47 +03:00
|
|
|
if( btl_endpoint->endpoint_addr->addr_family != addr->sa_family ) {
|
2007-04-29 20:23:11 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-04-23 19:26:15 +04:00
|
|
|
switch (addr->sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
if( memcmp( &btl_endpoint->endpoint_addr->addr_inet,
|
|
|
|
&(((struct sockaddr_in*)addr)->sin_addr),
|
|
|
|
sizeof(struct in_addr) ) ) {
|
2007-04-29 20:23:11 +04:00
|
|
|
continue;
|
|
|
|
}
|
2008-04-23 19:26:15 +04:00
|
|
|
break;
|
2007-04-29 20:38:34 +04:00
|
|
|
#if OPAL_WANT_IPV6
|
2008-04-23 19:26:15 +04:00
|
|
|
case AF_INET6:
|
|
|
|
if( memcmp( &btl_endpoint->endpoint_addr->addr_inet,
|
|
|
|
&(((struct sockaddr_in6*)addr)->sin6_addr),
|
|
|
|
sizeof(struct in6_addr) ) ) {
|
|
|
|
continue;
|
2008-04-16 15:24:09 +04:00
|
|
|
}
|
2008-04-23 19:26:15 +04:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
;
|
2007-04-29 20:23:11 +04:00
|
|
|
}
|
|
|
|
|
2008-01-30 17:31:47 +03:00
|
|
|
if(mca_btl_tcp_endpoint_accept(btl_endpoint, addr, sd)) {
|
2005-08-02 17:20:50 +04:00
|
|
|
OPAL_THREAD_UNLOCK(&btl_proc->proc_lock);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OPAL_THREAD_UNLOCK(&btl_proc->proc_lock);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-04-25 05:55:40 +04:00
|
|
|
/*
|
|
|
|
* convert internal data structure (mca_btl_tcp_addr_t) to sockaddr_storage
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
bool mca_btl_tcp_proc_tosocks(mca_btl_tcp_addr_t* proc_addr,
|
|
|
|
struct sockaddr_storage* output)
|
|
|
|
{
|
|
|
|
memset(output, 0, sizeof (*output));
|
|
|
|
switch (proc_addr->addr_family) {
|
2007-04-28 23:13:47 +04:00
|
|
|
case AF_INET:
|
|
|
|
output->ss_family = AF_INET;
|
|
|
|
memcpy(&((struct sockaddr_in*)output)->sin_addr,
|
|
|
|
&proc_addr->addr_inet, sizeof(struct in_addr));
|
|
|
|
((struct sockaddr_in*)output)->sin_port = proc_addr->addr_port;
|
|
|
|
break;
|
2007-04-25 05:55:40 +04:00
|
|
|
#if OPAL_WANT_IPV6
|
2007-04-28 23:13:47 +04:00
|
|
|
case AF_INET6:
|
|
|
|
{
|
|
|
|
struct sockaddr_in6* inaddr = (struct sockaddr_in6*)output;
|
|
|
|
output->ss_family = AF_INET6;
|
|
|
|
memcpy(&inaddr->sin6_addr, &proc_addr->addr_inet,
|
|
|
|
sizeof (proc_addr->addr_inet));
|
|
|
|
inaddr->sin6_port = proc_addr->addr_port;
|
|
|
|
inaddr->sin6_scope_id = 0;
|
|
|
|
inaddr->sin6_flowinfo = 0;
|
|
|
|
}
|
|
|
|
break;
|
2007-04-25 05:55:40 +04:00
|
|
|
#endif
|
2007-04-28 23:13:47 +04:00
|
|
|
default:
|
2008-06-09 18:53:58 +04:00
|
|
|
opal_output( 0, "mca_btl_tcp_proc: unknown af_family received: %d\n",
|
2007-04-28 23:13:47 +04:00
|
|
|
proc_addr->addr_family );
|
|
|
|
return false;
|
|
|
|
}
|
2007-04-25 05:55:40 +04:00
|
|
|
return true;
|
2007-04-28 23:13:47 +04:00
|
|
|
}
|
|
|
|
|