diff --git a/opal/util/help-opal-util.txt b/opal/util/help-opal-util.txt index 627c50a2fb..1af117c7b0 100644 --- a/opal/util/help-opal-util.txt +++ b/opal/util/help-opal-util.txt @@ -35,3 +35,18 @@ of the form /. For example: All malformed entries will be ignored; Open MPI will attempt to continue your job. The first detected malformed entry was %s. +# +[invalid-net-mask] +We were unable to parse the provided network interface: + + Interface: %s + +The interface must be one of the following forms: + + 123.456.789.123 + 123.456/16 + 123.456.789 + +The system can parse any one of these, and will find an interface +that matches within the provided scope. Please revise your input +and try again. diff --git a/opal/util/if.c b/opal/util/if.c index 5d08310a27..5a5b6d3cf0 100644 --- a/opal/util/if.c +++ b/opal/util/if.c @@ -68,11 +68,13 @@ #ifdef HAVE_IFADDRS_H #include #endif +#include #include "opal/class/opal_list.h" #include "opal/util/if.h" #include "opal/util/output.h" #include "opal/util/argv.h" +#include "opal/util/show_help.h" #include "opal/constants.h" #include "opal/mca/if/base/base.h" @@ -601,6 +603,57 @@ bool opal_ifisloopback(int if_index) return false; } +/* Determine if an interface matches any entry in the given list, taking + * into account that the list entries could be given as named interfaces, + * IP addrs, or subnet+mask + */ +bool opal_ifmatches(int idx, char **nets) +{ + bool named_if; + int i; + size_t j; + int index; + struct sockaddr_in inaddr; + uint32_t addr, netaddr, netmask; + + /* get the address info for the given network in case we need it */ + if (OPAL_SUCCESS != opal_ifindextoaddr(idx, (struct sockaddr*)&inaddr, sizeof(inaddr))) { + return false; + } + addr = ntohl(inaddr.sin_addr.s_addr); + + for (i=0; NULL != nets[i]; i++) { + /* if the specified interface contains letters in it, then it + * was given as an interface name and not an IP tuple + */ + named_if = false; + for (j=0; j < strlen(nets[i]); j++) { + if (isalpha(nets[i][j]) && '.' != nets[i][j]) { + named_if = true; + break; + } + } + if (named_if) { + if (0 > (index = opal_ifnametoindex(nets[i]))) { + continue; + } + if (index == idx) { + return true; + } + } else { + if (OPAL_SUCCESS != opal_iftupletoaddr(nets[i], &netaddr, &netmask)) { + opal_show_help("help-opal-util.txt", "invalid-net-mask", true, nets[i]); + continue; + } + if (netaddr == (addr & netmask)) { + return true; + } + } + } + /* get here if not found */ + return false; +} + #else /* HAVE_STRUCT_SOCKADDR_IN */ @@ -693,5 +746,10 @@ opal_iftupletoaddr(char *inaddr, uint32_t *net, uint32_t *mask) return 0; } +bool opal_ifispresent(char *if) +{ + return false; +} + #endif /* HAVE_STRUCT_SOCKADDR_IN */ diff --git a/opal/util/if.h b/opal/util/if.h index 8d6ecac9b1..92b4913bd7 100644 --- a/opal/util/if.h +++ b/opal/util/if.h @@ -188,6 +188,10 @@ OPAL_DECLSPEC int opal_iftupletoaddr(const char *addr, uint32_t *net, uint32_t * */ OPAL_DECLSPEC bool opal_ifisloopback(int if_index); +/* + * Determine if a specified interface is included in a NULL-terminated argv array + */ +OPAL_DECLSPEC bool opal_ifmatches(int idx, char **nets); END_C_DECLS diff --git a/orte/mca/oob/tcp/help-oob-tcp.txt b/orte/mca/oob/tcp/help-oob-tcp.txt index 31db556f73..70a79076fc 100644 --- a/orte/mca/oob/tcp/help-oob-tcp.txt +++ b/orte/mca/oob/tcp/help-oob-tcp.txt @@ -25,4 +25,11 @@ Dynamic ports: %s Only one can be specified. Please choose either static or dynamic ports and try again. +# +[include-exclude] +Both TCP interface include and exclude lists were specified: + Include: %s + Exclude: %s + +Only one of these can be given. diff --git a/orte/mca/oob/tcp/oob_tcp.c b/orte/mca/oob/tcp/oob_tcp.c index 93541ecbb0..a8eb39223f 100644 --- a/orte/mca/oob/tcp/oob_tcp.c +++ b/orte/mca/oob/tcp/oob_tcp.c @@ -1299,39 +1299,65 @@ mca_oob_t* mca_oob_tcp_component_init(int* priority) int i; bool found_local = false; bool found_nonlocal = false; + char **interfaces = NULL; + mca_oob_tcp_device_t *dev; + bool including = true; + char name[32]; *priority = 1; /* are there any interfaces? */ - if(opal_ifcount() <= 0) + if (opal_ifcount() <= 0) { return NULL; + } - /* Which interfaces should we use? Start by building a list of - all devices that meet the requirements of the if_include and - if_exclude list. This might include local and non-local - interfaces mixed together. After that sorting is done, if there - is a mix of devices, we go through the devices that survived - the initial sort and remove all the local devices (since we - have non-local devices to use). */ + /* did someone mistakenly specify both includes AND excludes? */ + if (NULL != mca_oob_tcp_component.tcp_include && + NULL != mca_oob_tcp_component.tcp_exclude) { + orte_show_help("help-oob-tcp.txt", "include-exclude", true, + mca_oob_tcp_component.tcp_include, + mca_oob_tcp_component.tcp_exclude); + return NULL; + } + + /* if interface include was given, construct a list + * of those interfaces which match the specifications - remember, + * the includes could be given as named interfaces, IP addrs, or + * subnet+mask + */ + if (NULL != mca_oob_tcp_component.tcp_include) { + interfaces = opal_argv_split(mca_oob_tcp_component.tcp_include, ','); + including = true; + } else if (NULL != mca_oob_tcp_component.tcp_exclude) { + interfaces = opal_argv_split(mca_oob_tcp_component.tcp_exclude, ','); + including = false; + } + + /* look at all available interfaces */ for (i = opal_ifbegin() ; i > 0 ; i = opal_ifnext(i)) { - char name[32]; - mca_oob_tcp_device_t *dev; + /* get the name for diagnostic purposes */ opal_ifindextoname(i, name, sizeof(name)); - if (mca_oob_tcp_component.tcp_include != NULL && - strstr(mca_oob_tcp_component.tcp_include,name) == NULL) { - OPAL_OUTPUT_VERBOSE((1, mca_oob_tcp_output_handle, - "%s oob:tcp:init rejecting interface %s", - ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), name)); - continue; - } - if (mca_oob_tcp_component.tcp_exclude != NULL && - strstr(mca_oob_tcp_component.tcp_exclude,name) != NULL) { - OPAL_OUTPUT_VERBOSE((1, mca_oob_tcp_output_handle, - "%s oob:tcp:init rejecting interface %s", - ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), name)); - continue; + /* handle include/exclude directives */ + if (NULL != interfaces) { + /* if we are including, then ignore this if not present */ + if (including) { + if (!opal_ifmatches(i, interfaces)) { + OPAL_OUTPUT_VERBOSE((1, mca_oob_tcp_output_handle, + "%s oob:tcp:init rejecting interface %s", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), name)); + continue; + } + } else { + /* we are excluding, so ignore if present */ + if (opal_ifmatches(i, interfaces)) { + OPAL_OUTPUT_VERBOSE((1, mca_oob_tcp_output_handle, + "%s oob:tcp:init rejecting interface %s", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), name)); + continue; + } + } } dev = OBJ_NEW(mca_oob_tcp_device_t); @@ -1353,6 +1379,13 @@ mca_oob_t* mca_oob_tcp_component_init(int* priority) opal_list_append(&mca_oob_tcp_component.tcp_available_devices, &dev->super); } + + /* cleanup */ + if (NULL != interfaces) { + opal_argv_free(interfaces); + } + + /* remove all the local devices if we have non-local devices to use. */ if (found_local && found_nonlocal) { opal_list_item_t *item, *next; for (item = opal_list_get_first(&mca_oob_tcp_component.tcp_available_devices) ; @@ -1377,18 +1410,18 @@ mca_oob_t* mca_oob_tcp_component_init(int* priority) opal_hash_table_init(&mca_oob_tcp_component.tcp_peer_names, 128); opal_free_list_init(&mca_oob_tcp_component.tcp_peer_free, - sizeof(mca_oob_tcp_peer_t), - OBJ_CLASS(mca_oob_tcp_peer_t), - 8, /* initial number */ - mca_oob_tcp_component.tcp_peer_limit, /* maximum number */ - 8); /* increment to grow by */ + sizeof(mca_oob_tcp_peer_t), + OBJ_CLASS(mca_oob_tcp_peer_t), + 8, /* initial number */ + mca_oob_tcp_component.tcp_peer_limit, /* maximum number */ + 8); /* increment to grow by */ opal_free_list_init(&mca_oob_tcp_component.tcp_msgs, - sizeof(mca_oob_tcp_msg_t), - OBJ_CLASS(mca_oob_tcp_msg_t), - 8, /* initial number */ - -1, /* maximum number */ - 8); /* increment to grow by */ + sizeof(mca_oob_tcp_msg_t), + OBJ_CLASS(mca_oob_tcp_msg_t), + 8, /* initial number */ + -1, /* maximum number */ + 8); /* increment to grow by */ /* intialize event library */