static int usdf_getinfo(uint32_t version, const char *node, const char *service, uint64_t flags, struct fi_info *hints, struct fi_info **info) { struct usdf_usnic_info *dp; struct usdf_dev_entry *dep; struct usd_device_attrs *dap; struct fi_info *fi_first; struct fi_info *fi_last; struct addrinfo *ai; struct sockaddr_in *src; struct sockaddr_in *dest; enum fi_ep_type ep_type; int metric; int d; int ret; USDF_TRACE("\n"); fi_first = NULL; fi_last = NULL; ai = NULL; src = NULL; dest = NULL; /* * Get and cache usNIC device info */ if (__usdf_devinfo == NULL) { ret = usdf_get_devinfo(); if (ret != 0) { USDF_WARN("failed to usdf_get_devinfo, ret=%d (%s)\n", ret, fi_strerror(-ret)); if (ret == -FI_ENODEV) ret = -FI_ENODATA; goto fail; } } dp = __usdf_devinfo; if (node != NULL || service != NULL) { ret = getaddrinfo(node, service, NULL, &ai); if (ret != 0) { USDF_DBG("getaddrinfo failed, likely bad node/service specified (%s:%s)\n", node, service); ret = -errno; goto fail; } if (flags & FI_SOURCE) { src = (struct sockaddr_in *)ai->ai_addr; } else { dest = (struct sockaddr_in *)ai->ai_addr; } } if (hints != NULL) { if (dest == NULL && hints->dest_addr != NULL) { dest = hints->dest_addr; } if (src == NULL && hints->src_addr != NULL) { src = hints->src_addr; } } for (d = 0; d < dp->uu_num_devs; ++d) { dep = &dp->uu_info[d]; dap = &dep->ue_dattr; /* skip this device if it has some problem */ if (!dep->ue_dev_ok) { USDF_DBG("skipping %s/%s\n", dap->uda_devname, dap->uda_ifname); continue; } /* See if dest is reachable from this device */ if (dest != NULL && dest->sin_addr.s_addr != INADDR_ANY) { ret = usdf_get_distance(dap, dest->sin_addr.s_addr, &metric); if (ret != 0) { goto fail; } if (metric == -1) { USDF_DBG("dest %s unreachable from %s/%s, skipping\n", inet_ntoa(dest->sin_addr), dap->uda_devname, dap->uda_ifname); continue; } } /* Does this device match requested attributes? */ if (hints != NULL) { ret = usdf_validate_hints(hints, dap); if (ret != 0) { USDF_DBG("hints do not match for %s/%s, skipping\n", dap->uda_devname, dap->uda_ifname); continue; } ep_type = hints->ep_attr ? hints->ep_attr->type : FI_EP_UNSPEC; } else { ep_type = FI_EP_UNSPEC; } if (ep_type == FI_EP_DGRAM || ep_type == FI_EP_UNSPEC) { ret = usdf_fill_info_dgram(version, hints, src, dest, dap, &fi_first, &fi_last); if (ret != 0 && ret != -FI_ENODATA) { goto fail; } } if (ep_type == FI_EP_MSG || ep_type == FI_EP_UNSPEC) { ret = usdf_fill_info_msg(hints, src, dest, dap, &fi_first, &fi_last); if (ret != 0 && ret != -FI_ENODATA) { goto fail; } } if (ep_type == FI_EP_RDM || ep_type == FI_EP_UNSPEC) { ret = usdf_fill_info_rdm(hints, src, dest, dap, &fi_first, &fi_last); if (ret != 0 && ret != -FI_ENODATA) { goto fail; } } } if (fi_first != NULL) { *info = fi_first; ret = 0; } else { ret = -FI_ENODATA; } fail: if (ret != 0) { fi_freeinfo(fi_first); } if (ai != NULL) { freeaddrinfo(ai); } if (ret != 0) { USDF_INFO("returning %d (%s)\n", ret, fi_strerror(-ret)); } return ret; }
/* Check all things related to a device. Make sure it's okay, the source address * matches the requested address, the destination is reachable from the device, * the device fabric name matches the requested fabric name, and the device * domain name matches the requested domain name. * * @param version Libfabric API version used to verify the domain / fabric name. * @param hints Hints passed to fi_getinfo. * @param src Source address being requested. * @param dest Destination address to communicate with. * @param dep usNIC device entry being checked. * * @return true on success, false on failure. For debug logging can be enabled * to see why a device was disqualified. */ static bool usdf_check_device(uint32_t version, const struct fi_info *hints, void *src, void *dest, struct usdf_dev_entry *dep) { char dest_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN]; char dev_str[INET_ADDRSTRLEN]; struct usd_device_attrs *dap; struct sockaddr_in *sin; int reachable; int ret; reachable = -1; dap = &dep->ue_dattr; /* Skip the device if it has problems. */ if (!dep->ue_dev_ok) { USDF_WARN_SYS(FABRIC, "skipping %s/%s device not ok\n", dap->uda_devname, dap->uda_ifname); return false; } /* If the given source address is not INADDR_ANY, compare against the * device. */ if (src) { sin = usdf_format_to_sin(hints, src); if (sin->sin_addr.s_addr != INADDR_ANY) { if (sin->sin_addr.s_addr != dap->uda_ipaddr_be) { inet_ntop(AF_INET, &sin->sin_addr.s_addr, src_str, sizeof(src_str)); inet_ntop(AF_INET, &dap->uda_ipaddr_be, dev_str, sizeof(dev_str)); USDF_WARN_SYS(FABRIC, "src addr<%s> != dev addr<%s>\n", src_str, dev_str); goto fail; } } usdf_free_sin_if_needed(hints, sin); } /* Check that the given destination address is reachable from the * interface. */ if (dest) { sin = usdf_format_to_sin(hints, dest); if (sin->sin_addr.s_addr != INADDR_ANY) { ret = usdf_get_distance(dap, sin->sin_addr.s_addr, &reachable); if (ret) { inet_ntop(AF_INET, &sin->sin_addr.s_addr, dest_str, sizeof(dest_str)); USDF_WARN_SYS(FABRIC, "get_distance failed @ %s\n", dest_str); goto fail; } } if (reachable == -1) { inet_ntop(AF_INET, &sin->sin_addr.s_addr, dest_str, sizeof(dest_str)); USDF_WARN_SYS(FABRIC, "dest %s unreachable from %s/%s, skipping\n", dest_str, dap->uda_devname, dap->uda_ifname); goto fail; } usdf_free_sin_if_needed(hints, sin); } /* Checks that the fabric name is correct for the given interface. The * fabric name contains the CIDR notation for the interface. */ if (hints && hints->fabric_attr && hints->fabric_attr->name) { if (!usdf_fabric_checkname(version, dap, hints->fabric_attr->name)) return false; } /* Check that the domain name is correct for the given interface. The * domain name is the device name. */ if (hints && hints->domain_attr && hints->domain_attr->name) { if (!usdf_domain_checkname(version, dap, hints->domain_attr->name)) return false; } return true; fail: usdf_free_sin_if_needed(hints, sin); return false; }