+ int rc;
+ int sockfd;
+
+ if (strlen(intf) >= IFNAMSIZ || ifr == NULL)
+ return LUSTRE_CFG_RC_BAD_PARAM;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0)
+ return LUSTRE_CFG_RC_BAD_PARAM;
+
+ strcpy(ifr->ifr_name, intf);
+ rc = ioctl(sockfd, request, ifr);
+ if (rc != 0)
+ return LUSTRE_CFG_RC_BAD_PARAM;
+
+ return 0;
+}
+
+/*
+ * for each interface in the array of interfaces find the IP address of
+ * that interface, create its nid and add it to an array of NIDs.
+ * Stop if any of the interfaces is down
+ */
+static int lustre_lnet_intf2nids(struct lnet_dlc_network_descr *nw,
+ lnet_nid_t **nids, __u32 *nnids)
+{
+ int i = 0, count = 0, rc;
+ struct ifreq ifr;
+ __u32 ip;
+ struct lnet_dlc_intf_descr *intf;
+
+ if (nw == NULL || nids == NULL)
+ return LUSTRE_CFG_RC_BAD_PARAM;
+
+ list_for_each_entry(intf, &nw->nw_intflist, intf_on_network)
+ count++;
+
+ *nids = calloc(count, sizeof(lnet_nid_t));
+ if (*nids == NULL)
+ return LUSTRE_CFG_RC_OUT_OF_MEM;
+
+ list_for_each_entry(intf, &nw->nw_intflist, intf_on_network) {
+ memset(&ifr, 0, sizeof(ifr));
+ rc = socket_intf_query(SIOCGIFFLAGS, intf->intf_name, &ifr);
+ if (rc != 0)
+ goto failed;
+
+ if ((ifr.ifr_flags & IFF_UP) == 0) {
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ goto failed;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ rc = socket_intf_query(SIOCGIFADDR, intf->intf_name, &ifr);
+ if (rc != 0)
+ goto failed;
+
+ ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ ip = bswap_32(ip);
+ (*nids)[i] = LNET_MKNID(nw->nw_id, ip);
+ i++;
+ }
+
+ *nnids = count;
+
+ return 0;
+
+failed:
+ free(*nids);
+ *nids = NULL;
+ return rc;
+}
+
+/*
+ * called repeatedly until a match or no more ip range
+ * What do you have?
+ * ip_range expression
+ * interface list with all the interface names.
+ * all the interfaces in the system.
+ *
+ * try to match the ip_range expr to one of the interfaces' IPs in
+ * the system. If we hit a patch for an interface. Check if that
+ * interface name is in the list.
+ *
+ * If there are more than one interface in the list, then make sure
+ * that the IPs for all of these interfaces match the ip ranges
+ * given.
+ *
+ * for each interface in intf_list
+ * look up the intf name in ifa
+ * if not there then no match
+ * check ip obtained from ifa against a match to any of the
+ * ip_ranges given.
+ * If no match, then fail
+ *
+ * The result is that all the interfaces have to match.
+ */
+int lustre_lnet_match_ip_to_intf(struct ifaddrs *ifa,
+ struct list_head *intf_list,
+ struct list_head *ip_ranges)
+{
+ int rc;
+ __u32 ip;
+ struct lnet_dlc_intf_descr *intf_descr;
+ struct ifaddrs *ifaddr = ifa;
+ struct lustre_lnet_ip_range_descr *ip_range;
+ int family;
+
+ /*
+ * if there are no explicit interfaces, and no ip ranges, then
+ * configure the first tcp interface we encounter.
+ */
+ if (list_empty(intf_list) && list_empty(ip_ranges)) {
+ for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
+ if (ifaddr->ifa_addr == NULL)
+ continue;
+
+ if ((ifaddr->ifa_flags & IFF_UP) == 0)
+ continue;
+
+ family = ifaddr->ifa_addr->sa_family;
+ if (family == AF_INET) {
+ rc = lustre_lnet_add_intf_descr
+ (intf_list, ifaddr->ifa_name,
+ strlen(ifaddr->ifa_name));
+
+ if (rc != LUSTRE_CFG_RC_NO_ERR)
+ return rc;
+
+ return LUSTRE_CFG_RC_MATCH;
+ }
+ }
+ return LUSTRE_CFG_RC_NO_MATCH;
+ }
+
+ /*
+ * First interface which matches an IP pattern will be used
+ */
+ if (list_empty(intf_list)) {
+ /*
+ * no interfaces provided in the rule, but an ip range is
+ * provided, so try and match an interface to the ip
+ * range.
+ */
+ for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
+ if (ifaddr->ifa_addr == NULL)
+ continue;
+
+ if ((ifaddr->ifa_flags & IFF_UP) == 0)
+ continue;
+
+ family = ifaddr->ifa_addr->sa_family;
+ if (family == AF_INET) {
+ ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->
+ sin_addr.s_addr;
+
+ list_for_each_entry(ip_range, ip_ranges,
+ ipr_entry) {
+ rc = cfs_ip_addr_match(bswap_32(ip),
+ &ip_range->ipr_expr);
+ if (!rc)
+ continue;
+
+ rc = lustre_lnet_add_intf_descr
+ (intf_list, ifaddr->ifa_name,
+ strlen(ifaddr->ifa_name));
+
+ if (rc != LUSTRE_CFG_RC_NO_ERR)
+ return rc;
+
+ return LUSTRE_CFG_RC_MATCH;
+ }
+ }
+ }
+ }
+
+ /*
+ * If an interface is explicitly specified the ip-range might or
+ * might not be specified. if specified the interface needs to match the
+ * ip-range. If no ip-range then the interfaces are
+ * automatically matched if they are all up.
+ * If > 1 interfaces all the interfaces must match for the NI to
+ * be configured.
+ */
+ list_for_each_entry(intf_descr, intf_list, intf_on_network) {
+ for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
+ if (ifaddr->ifa_addr == NULL)
+ continue;
+
+ family = ifaddr->ifa_addr->sa_family;
+ if (family == AF_INET &&
+ strcmp(intf_descr->intf_name,
+ ifaddr->ifa_name) == 0)
+ break;
+ }
+
+ if (ifaddr == NULL)
+ return LUSTRE_CFG_RC_NO_MATCH;
+
+ if ((ifaddr->ifa_flags & IFF_UP) == 0)
+ return LUSTRE_CFG_RC_NO_MATCH;
+
+ ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
+
+ list_for_each_entry(ip_range, ip_ranges, ipr_entry) {
+ rc = cfs_ip_addr_match(bswap_32(ip), &ip_range->ipr_expr);
+ if (rc)
+ break;
+ else
+ return LUSTRE_CFG_RC_NO_MATCH;
+ }
+ }
+
+ return LUSTRE_CFG_RC_MATCH;
+}
+
+int lustre_lnet_resolve_ip2nets_rule(struct lustre_lnet_ip2nets *ip2nets,
+ lnet_nid_t **nids, __u32 *nnids)
+{
+ struct ifaddrs *ifa;
+ int rc = LUSTRE_CFG_RC_NO_ERR;
+
+ rc = getifaddrs(&ifa);
+ if (rc < 0)
+ return -errno;
+
+ rc = lustre_lnet_match_ip_to_intf(ifa,
+ &ip2nets->ip2nets_net.nw_intflist,
+ &ip2nets->ip2nets_ip_ranges);
+ if (rc != LUSTRE_CFG_RC_MATCH) {
+ freeifaddrs(ifa);
+ return rc;
+ }
+
+ rc = lustre_lnet_intf2nids(&ip2nets->ip2nets_net, nids, nnids);
+ if (rc != LUSTRE_CFG_RC_NO_ERR) {
+ *nids = NULL;
+ *nnids = 0;
+ }
+
+ freeifaddrs(ifa);
+
+ return rc;
+}
+
+static int
+lustre_lnet_ioctl_config_ni(struct list_head *intf_list,
+ struct lnet_ioctl_config_lnd_tunables *tunables,
+ struct cfs_expr_list *global_cpts,
+ lnet_nid_t *nids, char *err_str)
+{
+ char *data;
+ struct lnet_ioctl_config_ni *conf;
+ struct lnet_ioctl_config_lnd_tunables *tun = NULL;
+ int rc = LUSTRE_CFG_RC_NO_ERR, i = 0;
+ size_t len;
+ int count;
+ struct lnet_dlc_intf_descr *intf_descr;
+ __u32 *cpt_array;
+ struct cfs_expr_list *cpt_expr;
+
+ list_for_each_entry(intf_descr, intf_list,
+ intf_on_network) {
+ if (i == 0 && tunables != NULL)
+ len = sizeof(struct lnet_ioctl_config_ni) +
+ sizeof(struct lnet_ioctl_config_lnd_tunables);
+ else
+ len = sizeof(struct lnet_ioctl_config_ni);
+
+ data = calloc(1, len);
+ conf = (struct lnet_ioctl_config_ni*) data;
+ if (i == 0 && tunables != NULL)
+ tun = (struct lnet_ioctl_config_lnd_tunables*)
+ (data + sizeof(*conf));
+
+ LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
+ conf->lic_cfg_hdr.ioc_len = len;
+ conf->lic_nid = nids[i];
+ strncpy(conf->lic_ni_intf[0], intf_descr->intf_name,
+ LNET_MAX_STR_LEN);
+
+ if (intf_descr->cpt_expr != NULL)
+ cpt_expr = intf_descr->cpt_expr;
+ else if (global_cpts != NULL)
+ cpt_expr = global_cpts;
+ else
+ cpt_expr = NULL;
+
+ if (cpt_expr != NULL) {
+ count = cfs_expr_list_values(cpt_expr,
+ LNET_MAX_SHOW_NUM_CPT,
+ &cpt_array);
+ if (count > 0) {
+ memcpy(conf->lic_cpts, cpt_array,
+ sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
+ free(cpt_array);
+ } else {
+ count = 0;
+ }
+ } else {
+ count = 0;
+ }
+
+ conf->lic_ncpts = count;
+
+ if (i == 0 && tunables != NULL)
+ /* TODO put in the LND tunables */
+ memcpy(tun, tunables, sizeof(*tunables));
+
+ rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
+ if (rc < 0) {
+ rc = -errno;
+ snprintf(err_str,
+ LNET_MAX_STR_LEN,
+ "\"cannot add network: %s\"", strerror(errno));
+ return rc;
+ }
+ i++;
+ }
+
+ return LUSTRE_CFG_RC_NO_ERR;
+}
+
+int
+lustre_lnet_config_ip2nets(struct lustre_lnet_ip2nets *ip2nets,
+ struct lnet_ioctl_config_lnd_tunables *tunables,
+ struct cfs_expr_list *global_cpts,
+ int seq_no, struct cYAML **err_rc)
+{
+ lnet_nid_t *nids = NULL;
+ __u32 nnids = 0;
+ int rc;