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

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