+ /*
+ * 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_safe(intf_descr, tmp, 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) {
+ list_del(&intf_descr->intf_on_network);
+ free_intf_descr(intf_descr);
+ continue;
+ }
+
+ if ((ifaddr->ifa_flags & IFF_UP) == 0) {
+ list_del(&intf_descr->intf_on_network);
+ free_intf_descr(intf_descr);
+ continue;
+ }
+
+ ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
+
+ rc = 1;
+ 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;
+ }
+
+ if (!rc) {
+ /* no match for this interface */
+ list_del(&intf_descr->intf_on_network);
+ free_intf_descr(intf_descr);
+ }
+ }
+
+ 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*)
+ conf->lic_bulk;
+
+ 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;
+ char err_str[LNET_MAX_STR_LEN];
+
+ snprintf(err_str, sizeof(err_str), "\"success\"");
+
+ if (!ip2nets) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"incomplete ip2nets information\"");
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ goto out;
+ }
+
+ rc = lustre_lnet_resolve_ip2nets_rule(ip2nets, &nids, &nnids);
+ if (rc != LUSTRE_CFG_RC_NO_ERR && rc != LUSTRE_CFG_RC_MATCH) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"cannot resolve ip2nets rule\"");
+ goto out;
+ }
+
+ if (list_empty(&ip2nets->ip2nets_net.nw_intflist)) {
+ snprintf(err_str, sizeof(err_str),
+ "\"no interfaces match ip2nets rules\"");
+ goto out;
+ }
+
+ rc = lustre_lnet_ioctl_config_ni(&ip2nets->ip2nets_net.nw_intflist,
+ tunables, global_cpts, nids,
+ err_str);
+ if (rc != LUSTRE_CFG_RC_NO_ERR)
+ free(nids);
+
+out:
+ cYAML_build_error(rc, seq_no, ADD_CMD, "ip2nets", err_str, err_rc);
+ return rc;
+}
+
+int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
+ struct cfs_expr_list *global_cpts,
+ char *ip2net,
+ struct lnet_ioctl_config_lnd_tunables *tunables,
+ int seq_no, struct cYAML **err_rc)
+{
+ char *data = NULL;
+ struct lnet_ioctl_config_ni *conf;
+ struct lnet_ioctl_config_lnd_tunables *tun = NULL;
+ char buf[LNET_MAX_STR_LEN];
+ int rc = LUSTRE_CFG_RC_NO_ERR;
+ char err_str[LNET_MAX_STR_LEN];
+ lnet_nid_t *nids = NULL;
+ __u32 nnids = 0;
+ size_t len;
+ int count;
+ struct lnet_dlc_intf_descr *intf_descr, *tmp;
+ __u32 *cpt_array;
+
+ snprintf(err_str, sizeof(err_str), "\"success\"");
+
+ if (ip2net == NULL && nw_descr == NULL) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"mandatory parameters not specified.\"");
+ rc = LUSTRE_CFG_RC_MISSING_PARAM;
+ goto out;
+ }
+
+ if (ip2net != NULL && strlen(ip2net) >= sizeof(buf)) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"ip2net string too long %d\"",
+ (int)strlen(ip2net));
+ rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+ goto out;
+ }
+
+ if (ip2net != NULL) {
+ if (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 (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;
+ strncpy(conf->lic_legacy_ip2nets, ip2net,
+ LNET_MAX_STR_LEN);
+
+ if (global_cpts != NULL) {
+ count = cfs_expr_list_values(global_cpts,
+ 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 (tunables != NULL)
+ 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,
+ sizeof(err_str),
+ "\"cannot add network: %s\"", strerror(errno));
+ goto out;
+ }
+
+ goto out;
+ }
+
+ if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
+ return LUSTRE_CFG_RC_NO_ERR;
+
+ if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"cannot parse net '%s'\"",
+ libcfs_net2str(nw_descr->nw_id));
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ goto out;
+ }
+
+ if (list_empty(&nw_descr->nw_intflist)) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"no interface name provided\"");
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ goto out;
+ }
+
+ rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
+ if (rc != 0) {
+ snprintf(err_str, sizeof(err_str),
+ "\"bad parameter\"");
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ goto out;
+ }
+
+ rc = lustre_lnet_ioctl_config_ni(&nw_descr->nw_intflist,
+ tunables, global_cpts, nids,
+ err_str);
+
+out:
+ if (nw_descr != NULL) {
+ list_for_each_entry_safe(intf_descr, tmp,
+ &nw_descr->nw_intflist,
+ intf_on_network) {
+ list_del(&intf_descr->intf_on_network);
+ free_intf_descr(intf_descr);
+ }
+ }
+
+ cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
+
+ if (nids)
+ free(nids);
+
+ if (data)
+ free(data);
+
+ return rc;
+}
+
+int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw_descr,
+ int seq_no, struct cYAML **err_rc)
+{
+ struct lnet_ioctl_config_ni data;
+ int rc = LUSTRE_CFG_RC_NO_ERR, i;
+ char err_str[LNET_MAX_STR_LEN];
+ lnet_nid_t *nids = NULL;
+ __u32 nnids = 0;
+ struct lnet_dlc_intf_descr *intf_descr, *tmp;
+
+ if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
+ return LUSTRE_CFG_RC_NO_ERR;
+
+ snprintf(err_str, sizeof(err_str), "\"success\"");
+
+ if (nw_descr == NULL) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"missing mandatory parameter\"");
+ rc = LUSTRE_CFG_RC_MISSING_PARAM;
+ goto out;
+ }
+
+ if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"cannot parse net '%s'\"",
+ libcfs_net2str(nw_descr->nw_id));
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ goto out;
+ }
+
+ rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
+ if (rc != 0) {
+ snprintf(err_str, sizeof(err_str),
+ "\"bad parameter\"");
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ goto out;
+ }
+
+ /*
+ * no interfaces just the nw_id is specified
+ */
+ if (nnids == 0) {
+ nids = calloc(1, sizeof(*nids));
+ if (nids == NULL) {
+ snprintf(err_str, sizeof(err_str),
+ "\"out of memory\"");
+ rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+ goto out;
+ }
+ nids[0] = LNET_MKNID(nw_descr->nw_id, 0);
+ nnids = 1;
+ }
+
+ for (i = 0; i < nnids; i++) {
+ LIBCFS_IOC_INIT_V2(data, lic_cfg_hdr);
+ data.lic_nid = nids[i];
+
+ rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_LOCAL_NI, &data);
+ if (rc < 0) {
+ rc = -errno;
+ snprintf(err_str,
+ sizeof(err_str),
+ "\"cannot del network: %s\"", strerror(errno));
+ }
+ }
+
+ list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
+ intf_on_network) {
+ list_del(&intf_descr->intf_on_network);
+ free_intf_descr(intf_descr);
+ }
+
+out:
+ cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
+
+ if (nids != NULL)
+ free(nids);
+
+ return rc;
+}