root/opal/mca/pmix/pmix4x/pmix/src/mca/pif/posix_ipv4/pif_posix.c

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

DEFINITIONS

This source file includes following definitions.
  1. prefix
  2. if_posix_open

   1 /*
   2  * Copyright (c) 2010-2013 Cisco Systems, Inc.  All rights reserved.
   3  * Copyright (c) 2010      Oracle and/or its affiliates.  All rights reserved.
   4  * Copyright (c) 2013      The University of Tennessee and The University
   5  *                         of Tennessee Research Foundation.  All rights
   6  *                         reserved.
   7  * Copyright (c) 2015-2018 Intel, Inc. All rights reserved.
   8  * $COPYRIGHT$
   9  *
  10  * Additional copyrights may follow
  11  *
  12  * $HEADER$
  13  */
  14 
  15 #include "pmix_config.h"
  16 #include "pmix_common.h"
  17 
  18 #include <string.h>
  19 #ifdef HAVE_UNISTD_H
  20 #include <unistd.h>
  21 #endif
  22 #include <errno.h>
  23 #ifdef HAVE_SYS_TYPES_H
  24 #include <sys/types.h>
  25 #endif
  26 #ifdef HAVE_SYS_SOCKET_H
  27 #include <sys/socket.h>
  28 #endif
  29 #ifdef HAVE_SYS_SOCKIO_H
  30 #include <sys/sockio.h>
  31 #endif
  32 #ifdef HAVE_SYS_IOCTL_H
  33 #include <sys/ioctl.h>
  34 #endif
  35 #ifdef HAVE_NETINET_IN_H
  36 #include <netinet/in.h>
  37 #endif
  38 #ifdef HAVE_ARPA_INET_H
  39 #include <arpa/inet.h>
  40 #endif
  41 #ifdef HAVE_NET_IF_H
  42 #include <net/if.h>
  43 #endif
  44 #ifdef HAVE_NETDB_H
  45 #include <netdb.h>
  46 #endif
  47 #ifdef HAVE_IFADDRS_H
  48 #include <ifaddrs.h>
  49 #endif
  50 
  51 #include "src/util/output.h"
  52 #include "src/util/pif.h"
  53 #include "src/mca/pif/pif.h"
  54 #include "src/mca/pif/base/base.h"
  55 
  56 static int if_posix_open(void);
  57 
  58 /* Supports all flavors of posix except those
  59  * BSD-flavors supported elsewhere
  60  */
  61 pmix_pif_base_component_t mca_pif_posix_ipv4_component = {
  62     /* First, the mca_component_t struct containing meta information
  63        about the component itself */
  64     .base = {
  65         PMIX_PIF_BASE_VERSION_2_0_0,
  66 
  67         /* Component name and version */
  68         "posix_ipv4",
  69         PMIX_MAJOR_VERSION,
  70         PMIX_MINOR_VERSION,
  71         PMIX_RELEASE_VERSION,
  72 
  73         /* Component open and close functions */
  74         if_posix_open,
  75         NULL
  76     },
  77     .data = {
  78         /* This component is checkpointable */
  79         PMIX_MCA_BASE_METADATA_PARAM_CHECKPOINT
  80     },
  81 };
  82 
  83 /* convert a netmask (in network byte order) to CIDR notation */
  84 static int prefix (uint32_t netmask)
  85 {
  86     uint32_t mask = ntohl(netmask);
  87     int plen = 0;
  88 
  89     if (0 == mask) {
  90         plen = 32;
  91     } else {
  92         while ((mask % 2) == 0) {
  93             plen += 1;
  94             mask /= 2;
  95         }
  96     }
  97 
  98     return (32 - plen);
  99 }
 100 
 101 /* configure using getifaddrs(3) */
 102 static int if_posix_open(void)
 103 {
 104     int sd;
 105     int lastlen, rem;
 106     char *ptr;
 107     struct ifconf ifconf;
 108     int ifc_len;
 109     bool successful_locate = false;
 110 
 111     /* Create the internet socket to test with.  Must use AF_INET;
 112        using AF_UNSPEC or AF_INET6 will cause everything to
 113        fail. */
 114     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 115         pmix_output(0, "pmix_ifinit: socket() failed with errno=%d\n",
 116                     errno);
 117         return PMIX_ERROR;
 118     }
 119 
 120     /*
 121      * Get Network Interface configuration
 122      *
 123      * Some notes on the behavior of ioctl(..., SIOCGIFCONF,...)
 124      * when not enough space is allocated for all the entries.
 125      *
 126      * - Solaris returns -1, errno EINVAL if there is not enough
 127      *   space
 128      * - OS X returns 0, sets .ifc_len to the space used by the
 129      *   by the entries that did fit.
 130      * - Linux returns 0, sets .ifc_len to the space required to
 131      *   hold all the entries (although it only writes what will
 132      *   fit in the buffer of .ifc_len passed to the function).
 133      * - FreeBSD returns 0, sets .ifc_len to 0.
 134      *
 135      * Everyone else seems to do one of the four.
 136      */
 137     lastlen = 0;
 138     ifc_len = sizeof(struct ifreq) * DEFAULT_NUMBER_INTERFACES;
 139     do {
 140         ifconf.ifc_len = ifc_len;
 141         ifconf.ifc_req = malloc(ifc_len);
 142         if (NULL == ifconf.ifc_req) {
 143             close(sd);
 144             return PMIX_ERROR;
 145         }
 146 
 147         /* initialize the memory so valgrind and purify won't
 148          * complain.  Since this isn't performance critical, just
 149          * always memset.
 150          */
 151         memset(ifconf.ifc_req, 0, ifconf.ifc_len);
 152 
 153         if (ioctl(sd, SIOCGIFCONF, &ifconf) < 0) {
 154             /* if we got an einval, we probably don't have enough
 155                space.  so we'll fall down and try to expand our
 156                space */
 157             if (errno != EINVAL && lastlen != 0) {
 158                 pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFCONF) \
 159                             failed with errno=%d",
 160                             errno);
 161                 free(ifconf.ifc_req);
 162                 close(sd);
 163                 return PMIX_ERROR;
 164             }
 165         } else {
 166             /* if ifc_len is 0 or different than what we set it to
 167                at call to ioctl, try again with a bigger buffer.
 168                else stop */
 169             if (ifconf.ifc_len == lastlen && ifconf.ifc_len > 0) {
 170                 /* we didn't expand.  we're done */
 171                 successful_locate = true;
 172                 break;
 173             }
 174             lastlen = ifconf.ifc_len;
 175         }
 176 
 177         /* Yes, we overflowed (or had an EINVAL on the ioctl).
 178            Loop back around and try again with a bigger buffer */
 179         free(ifconf.ifc_req);
 180         ifc_len = (ifc_len == 0) ? 1 : ifc_len * 2;
 181     } while (ifc_len < MAX_PIFCONF_SIZE);
 182     if (!successful_locate) {
 183         pmix_output(0, "pmix_ifinit: unable to find network interfaces.");
 184         close(sd);
 185         return PMIX_ERROR;
 186     }
 187 
 188     /*
 189      * Setup indexes
 190      */
 191     ptr = (char*) ifconf.ifc_req;
 192     rem = ifconf.ifc_len;
 193 
 194     /* loop through all interfaces */
 195     while (rem > 0) {
 196         struct ifreq* ifr = (struct ifreq*) ptr;
 197         pmix_pif_t *intf;
 198         int length;
 199 
 200         /* compute offset for entries */
 201 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
 202         length = sizeof(struct sockaddr);
 203 
 204         if (ifr->ifr_addr.sa_len > length) {
 205             length = ifr->ifr_addr.sa_len;
 206         }
 207 
 208         length += sizeof(ifr->ifr_name);
 209 #else
 210         length = sizeof(struct ifreq);
 211 #endif
 212 
 213         rem -= length;
 214         ptr += length;
 215 
 216         /* see if we like this entry */
 217         if (AF_INET != ifr->ifr_addr.sa_family) {
 218             continue;
 219         }
 220 
 221         if (ioctl(sd, SIOCGIFFLAGS, ifr) < 0) {
 222             pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFFLAGS) failed with errno=%d", errno);
 223             continue;
 224         }
 225         if ((ifr->ifr_flags & IFF_UP) == 0) {
 226             continue;
 227         }
 228 #ifdef IFF_SLAVE
 229         /* Is this a slave to a load balancer or bonded channel?
 230            If so, don't use it -- pick up the master instead */
 231         if ((ifr->ifr_flags & IFF_SLAVE) != 0) {
 232             continue;
 233         }
 234 #endif
 235 #if 0
 236         if (!pmix_if_retain_loopback && (ifr->ifr_flags & IFF_LOOPBACK) != 0) {
 237             continue;
 238         }
 239 #endif
 240 
 241         intf = PMIX_NEW(pmix_pif_t);
 242         if (NULL == intf) {
 243             pmix_output(0, "pmix_ifinit: unable to allocated %lu bytes\n", (unsigned long)sizeof(pmix_pif_t));
 244             free(ifconf.ifc_req);
 245             close(sd);
 246             return PMIX_ERR_OUT_OF_RESOURCE;
 247         }
 248         intf->af_family = AF_INET;
 249 
 250         /* copy entry over into our data structure */
 251         memset(intf->if_name, 0, sizeof(intf->if_name));
 252         pmix_strncpy(intf->if_name, ifr->ifr_name, sizeof(intf->if_name) - 1);
 253         intf->if_flags = ifr->ifr_flags;
 254 
 255         /* every new address gets its own internal if_index */
 256         intf->if_index = pmix_list_get_size(&pmix_if_list)+1;
 257 
 258         pmix_output_verbose(1, pmix_pif_base_framework.framework_output,
 259                             "found interface %s", intf->if_name);
 260 
 261         /* assign the kernel index to distinguish different NICs */
 262 #ifndef SIOCGIFINDEX
 263         intf->if_kernel_index = intf->if_index;
 264 #else
 265         if (ioctl(sd, SIOCGIFINDEX, ifr) < 0) {
 266             pmix_output(0,"pmix_ifinit: ioctl(SIOCGIFINDEX) failed with errno=%d", errno);
 267             PMIX_RELEASE(intf);
 268             continue;
 269         }
 270 #if defined(ifr_ifindex)
 271         intf->if_kernel_index = ifr->ifr_ifindex;
 272 #elif defined(ifr_index)
 273         intf->if_kernel_index = ifr->ifr_index;
 274 #else
 275         intf->if_kernel_index = -1;
 276 #endif
 277 #endif /* SIOCGIFINDEX */
 278 
 279         /* This call returns IPv4 addresses only. Use SIOCGLIFADDR
 280            instead */
 281         if (ioctl(sd, SIOCGIFADDR, ifr) < 0) {
 282             pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFADDR) failed with errno=%d", errno);
 283             PMIX_RELEASE(intf);
 284             break;
 285         }
 286         if (AF_INET != ifr->ifr_addr.sa_family) {
 287             PMIX_RELEASE(intf);
 288             continue;
 289         }
 290 
 291         /* based on above, we know this is an IPv4 address... */
 292         memcpy(&intf->if_addr, &ifr->ifr_addr, sizeof(struct sockaddr_in));
 293 
 294         if (ioctl(sd, SIOCGIFNETMASK, ifr) < 0) {
 295             pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFNETMASK) failed with errno=%d", errno);
 296             PMIX_RELEASE(intf);
 297             continue;
 298         }
 299 
 300         /* generate CIDR and assign to netmask */
 301         intf->if_mask = prefix(((struct sockaddr_in*) &ifr->ifr_addr)->sin_addr.s_addr);
 302 
 303 #if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_HWADDR)
 304         /* get the MAC address */
 305         if (ioctl(sd, SIOCGIFHWADDR, ifr) < 0) {
 306             pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFHWADDR) failed with errno=%d", errno);
 307             break;
 308         }
 309         memcpy(intf->if_mac, ifr->ifr_hwaddr.sa_data, 6);
 310 #endif
 311 
 312 #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU)
 313         /* get the MTU */
 314         if (ioctl(sd, SIOCGIFMTU, ifr) < 0) {
 315             pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFMTU) failed with errno=%d", errno);
 316             break;
 317         }
 318         intf->ifmtu = ifr->ifr_mtu;
 319 #endif
 320         pmix_output_verbose(1, pmix_pif_base_framework.framework_output,
 321                             "adding interface %s", intf->if_name);
 322         pmix_list_append(&pmix_if_list, &(intf->super));
 323     }
 324     free(ifconf.ifc_req);
 325     close(sd);
 326 
 327     return PMIX_SUCCESS;
 328 }

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