/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #include #include #include "opal/constants.h" #include "opal/util/output.h" #include "opal/mca/if/if.h" static int if_solaris_ipv6_open(void); /* Discovers Solaris IPv6 interfaces */ opal_if_base_component_t mca_if_solaris_ipv6_component = { /* First, the mca_component_t struct containing meta information about the component itself */ { OPAL_IF_BASE_VERSION_2_0_0, /* Component name and version */ "solaris_ipv6", OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION, OPAL_RELEASE_VERSION, /* Component open and close functions */ if_solaris_ipv6_open, NULL }, { /* This component is checkpointable */ MCA_BASE_METADATA_PARAM_CHECKPOINT }, }; /* configure using getifaddrs(3) */ static int if_solaris_ipv6_open(void) { #if OPAL_ENABLE_IPV6 int i; int sd; int error; uint16_t kindex; struct lifnum lifnum; struct lifconf lifconf; struct lifreq *lifreq, lifquery; sd = socket (AF_INET6, SOCK_DGRAM, 0); if (sd < 0) { opal_output (0, "opal_ifinit: unable to open IPv6 socket\n"); return OPAL_ERROR; } /* we only ask for IPv6; IPv4 discovery has already been done */ lifnum.lifn_family = AF_INET6; lifnum.lifn_flags = 0; lifnum.lifn_count = 0; /* get the number of interfaces in the system */ error = ioctl (sd, SIOCGLIFNUM, &lifnum); if (error < 0) { opal_output (0, "opal_ifinit: ioctl SIOCGLIFNUM failed with errno=%d\n", errno); return OPAL_ERROR; } memset (&lifconf, 0, sizeof (struct lifconf)); memset (&lifquery, 0, sizeof (struct lifreq)); lifconf.lifc_family = AF_INET6; lifconf.lifc_flags = 0; lifconf.lifc_len = lifnum.lifn_count * sizeof (struct lifreq) * 2; lifconf.lifc_buf = malloc (lifconf.lifc_len); if (NULL == lifconf.lifc_buf) { opal_output (0, "opal_ifinit: IPv6 discovery: malloc() failed\n"); return OPAL_ERR_OUT_OF_RESOURCE; } memset (lifconf.lifc_buf, 0, lifconf.lifc_len); error = ioctl (sd, SIOCGLIFCONF, &lifconf); if (error < 0) { opal_output (0, "opal_ifinit: IPv6 SIOCGLIFCONF failed with errno=%d\n", errno); } for (i = 0; i + sizeof (struct lifreq) <= lifconf.lifc_len; i += sizeof (*lifreq)) { lifreq = (struct lifreq *)((caddr_t)lifconf.lifc_buf + i); strncpy (lifquery.lifr_name, lifreq->lifr_name, sizeof (lifquery.lifr_name)); /* lookup kernel index */ error = ioctl (sd, SIOCGLIFINDEX, &lifquery); if (error < 0) { opal_output (0, "opal_ifinit: SIOCGLIFINDEX failed with errno=%d\n", errno); return OPAL_ERROR; } kindex = lifquery.lifr_index; /* lookup interface flags */ error = ioctl (sd, SIOCGLIFFLAGS, &lifquery); if (error < 0) { opal_output (0, "opal_ifinit: SIOCGLIFFLAGS failed with errno=%d\n", errno); return OPAL_ERROR; } if (AF_INET6 == lifreq->lifr_addr.ss_family) { struct sockaddr_in6* my_addr = (struct sockaddr_in6*) &lifreq->lifr_addr; /* we surely want to check for sin6_scope_id, but Solaris does not set it correctly, so we have to look for global scope. For now, global is anything which is neither loopback nor link local. Bug, FIXME: site-local, multicast, ... missing Check for 2000::/3? */ if ( (!opal_if_retain_loopback && !IN6_IS_ADDR_LOOPBACK (&my_addr->sin6_addr)) && (! IN6_IS_ADDR_LINKLOCAL (&my_addr->sin6_addr))) { /* create interface for newly found address */ opal_if_t *intf; intf = OBJ_NEW(opal_if_t); if (NULL == intf) { opal_output (0, "opal_ifinit: unable to allocate %d bytes\n", sizeof (opal_if_t)); return OPAL_ERR_OUT_OF_RESOURCE; } intf->af_family = AF_INET6; strncpy (intf->if_name, lifreq->lifr_name, IF_NAMESIZE); intf->if_index = opal_list_get_size(&opal_if_list)+1; memcpy(&intf->if_addr, my_addr, sizeof (*my_addr)); intf->if_mask = 64; /* lifrq flags are uint64_t */ intf->if_flags = (uint32_t)(0x00000000ffffffff) & lifquery.lifr_flags; /* append to list */ opal_list_append (&opal_if_list, &(intf->super)); } } } /* for */ if (NULL != lifconf.lifc_buf) { free (lifconf.lifc_buf); } #endif /* OPAL_ENABLE_IPV6 */ return OPAL_SUCCESS; }