+static lnet_nid_t *allocate_create_nid_array(char **nids, __u32 num_nids,
+ char *err_str)
+{
+ lnet_nid_t *array = NULL;
+ __u32 i;
+
+ if (!nids || num_nids == 0) {
+ snprintf(err_str, LNET_MAX_STR_LEN, "no NIDs to add");
+ return NULL;
+ }
+
+ array = calloc(sizeof(*array) * num_nids, 1);
+ if (array == NULL) {
+ snprintf(err_str, LNET_MAX_STR_LEN, "out of memory");
+ return NULL;
+ }
+
+ for (i = 0; i < num_nids; i++) {
+ array[i] = libcfs_str2nid(nids[i]);
+ if (array[i] == LNET_NID_ANY) {
+ free(array);
+ snprintf(err_str, LNET_MAX_STR_LEN,
+ "bad NID: '%s'",
+ nids[i]);
+ return NULL;
+ }
+ }
+
+ return array;
+}
+
+static int dispatch_peer_ni_cmd(lnet_nid_t pnid, lnet_nid_t nid, __u32 cmd,
+ struct lnet_ioctl_peer_cfg *data,
+ char *err_str, char *cmd_str)
+{
+ int rc;
+
+ data->prcfg_prim_nid = pnid;
+ data->prcfg_cfg_nid = nid;
+
+ rc = l_ioctl(LNET_DEV_ID, cmd, data);
+ if (rc != 0) {
+ rc = -errno;
+ snprintf(err_str,
+ LNET_MAX_STR_LEN,
+ "\"cannot %s peer ni: %s\"",
+ (cmd_str) ? cmd_str : "add", strerror(errno));
+ }
+
+ return rc;
+}
+
+static int infra_ping_nid(char *ping_nids, char *oper, int param, int ioc_call,
+ int seq_no, struct cYAML **show_rc,
+ struct cYAML **err_rc)
+{
+ void *data = NULL;
+ struct lnet_ioctl_ping_data ping;
+ struct cYAML *root = NULL, *ping_node = NULL, *item = NULL,
+ *first_seq = NULL, *tmp = NULL, *peer_ni = NULL;
+ lnet_process_id_t id;
+ char err_str[LNET_MAX_STR_LEN] = {0};
+ char *sep, *token, *end;
+ char buf[6];
+ size_t len;
+ int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+ int i;
+ bool flag = false;
+
+ len = (sizeof(lnet_process_id_t) * LNET_INTERFACES_MAX_DEFAULT);
+
+ data = calloc(1, len);
+ if (data == NULL)
+ goto out;
+
+ /* create struct cYAML root object */
+ root = cYAML_create_object(NULL, NULL);
+ if (root == NULL)
+ goto out;
+
+ ping_node = cYAML_create_seq(root, oper);
+ if (ping_node == NULL)
+ goto out;
+
+ /* tokenise each nid in string ping_nids */
+ token = strtok(ping_nids, ",");
+
+ do {
+ item = cYAML_create_seq_item(ping_node);
+ if (item == NULL)
+ goto out;
+
+ if (first_seq == NULL)
+ first_seq = item;
+
+ /* check if '-' is a part of NID, token */
+ sep = strchr(token, '-');
+ if (sep == NULL) {
+ id.pid = LNET_PID_ANY;
+ /* if no net is specified, libcfs_str2nid() will assume tcp */
+ id.nid = libcfs_str2nid(token);
+ if (id.nid == LNET_NID_ANY) {
+ snprintf(err_str, sizeof(err_str),
+ "\"cannot parse NID '%s'\"",
+ token);
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ cYAML_build_error(rc, seq_no, MANAGE_CMD,
+ oper, err_str, err_rc);
+ continue;
+ }
+ } else {
+ if (token[0] == 'u' || token[0] == 'U')
+ id.pid = (strtoul(&token[1], &end, 0) |
+ (LNET_PID_USERFLAG));
+ else
+ id.pid = strtoul(token, &end, 0);
+
+ /* assuming '-' is part of hostname */
+ if (end != sep) {
+ id.pid = LNET_PID_ANY;
+ id.nid = libcfs_str2nid(token);
+ if (id.nid == LNET_NID_ANY) {
+ snprintf(err_str, sizeof(err_str),
+ "\"cannot parse NID '%s'\"",
+ token);
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ cYAML_build_error(rc, seq_no, MANAGE_CMD,
+ oper, err_str,
+ err_rc);
+ continue;
+ }
+ } else {
+ id.nid = libcfs_str2nid(sep + 1);
+ if (id.nid == LNET_NID_ANY) {
+ snprintf(err_str, sizeof(err_str),
+ "\"cannot parse NID '%s'\"",
+ token);
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ cYAML_build_error(rc, seq_no, MANAGE_CMD,
+ oper, err_str,
+ err_rc);
+ continue;
+ }
+ }
+ }
+ LIBCFS_IOC_INIT_V2(ping, ping_hdr);
+ ping.ping_hdr.ioc_len = sizeof(ping);
+ ping.ping_id = id;
+ ping.op_param = param;
+ ping.ping_count = LNET_INTERFACES_MAX_DEFAULT;
+ ping.ping_buf = data;
+
+ rc = l_ioctl(LNET_DEV_ID, ioc_call, &ping);
+ if (rc != 0) {
+ snprintf(err_str,
+ sizeof(err_str), "failed to %s %s: %s\n", oper,
+ id.pid == LNET_PID_ANY ?
+ libcfs_nid2str(id.nid) :
+ libcfs_id2str(id), strerror(errno));
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ cYAML_build_error(rc, seq_no, MANAGE_CMD,
+ oper, err_str, err_rc);
+ continue;
+ }
+
+ if (cYAML_create_string(item, "primary nid",
+ libcfs_nid2str(ping.ping_id.nid)) == NULL)
+ goto out;
+
+ if (cYAML_create_string(item, "Multi-Rail", ping.mr_info ?
+ "True" : "False") == NULL)
+ goto out;
+
+ tmp = cYAML_create_seq(item, "peer ni");
+ if (tmp == NULL)
+ goto out;
+
+ for (i = 0; i < ping.ping_count; i++) {
+ if (!strcmp(libcfs_nid2str(ping.ping_buf[i].nid),
+ "0@lo"))
+ continue;
+ peer_ni = cYAML_create_seq_item(tmp);
+ if (peer_ni == NULL)
+ goto out;
+ memset(buf, 0, sizeof buf);
+ snprintf(buf, sizeof buf, "nid");
+ if (cYAML_create_string(peer_ni, buf,
+ libcfs_nid2str(ping.ping_buf[i].nid)) == NULL)
+ goto out;
+ }
+
+ flag = true;
+
+ } while ((token = strtok(NULL, ",")) != NULL);
+
+ if (flag)
+ rc = LUSTRE_CFG_RC_NO_ERR;
+
+out:
+ if (data)
+ free(data);
+ if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
+ cYAML_free_tree(root);
+ } else if (show_rc != NULL && *show_rc != NULL) {
+ struct cYAML *show_node;
+ show_node = cYAML_get_object_item(*show_rc, oper);
+ if (show_node != NULL && cYAML_is_sequence(show_node)) {
+ cYAML_insert_child(show_node, first_seq);
+ free(ping_node);
+ free(root);
+ } else if (show_node == NULL) {
+ cYAML_insert_sibling((*show_rc)->cy_child,
+ ping_node);
+ free(root);
+ } else {
+ cYAML_free_tree(root);
+ }
+ } else {
+ *show_rc = root;
+ }
+
+ return rc;
+}
+
+int lustre_lnet_ping_nid(char *ping_nids, int timeout, int seq_no,
+ struct cYAML **show_rc, struct cYAML **err_rc)
+{
+ int rc;
+
+ rc = infra_ping_nid(ping_nids, "ping", timeout, IOC_LIBCFS_PING_PEER,
+ seq_no, show_rc, err_rc);
+ return rc;
+}
+
+int lustre_lnet_discover_nid(char *ping_nids, int force, int seq_no,
+ struct cYAML **show_rc, struct cYAML **err_rc)
+{
+ int rc;
+
+ rc = infra_ping_nid(ping_nids, "discover", force, IOC_LIBCFS_DISCOVER,
+ seq_no, show_rc, err_rc);
+ return rc;
+}
+
+int lustre_lnet_config_peer_nid(char *pnid, char **nid, int num_nids,
+ bool mr, int seq_no, struct cYAML **err_rc)
+{
+ struct lnet_ioctl_peer_cfg data;
+ lnet_nid_t prim_nid = LNET_NID_ANY;
+ int rc = LUSTRE_CFG_RC_NO_ERR;
+ int idx = 0;
+ bool nid0_used = false;
+ char err_str[LNET_MAX_STR_LEN] = {0};
+ lnet_nid_t *nids = allocate_create_nid_array(nid, num_nids, err_str);
+
+ if (pnid) {
+ prim_nid = libcfs_str2nid(pnid);
+ if (prim_nid == LNET_NID_ANY) {
+ snprintf(err_str, sizeof(err_str),
+ "bad key NID: '%s'",
+ pnid);
+ rc = LUSTRE_CFG_RC_MISSING_PARAM;
+ goto out;
+ }
+ } else if (!nids || nids[0] == LNET_NID_ANY) {
+ snprintf(err_str, sizeof(err_str),
+ "no NIDs provided for configuration");
+ rc = LUSTRE_CFG_RC_MISSING_PARAM;
+ goto out;
+ } else {
+ prim_nid = LNET_NID_ANY;
+ }
+
+ snprintf(err_str, sizeof(err_str), "\"Success\"");
+
+ LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
+ data.prcfg_mr = mr;
+
+ /*
+ * if prim_nid is not specified use the first nid in the list of
+ * nids provided as the prim_nid. NOTE: on entering 'if' we must
+ * have at least 1 NID
+ */
+ if (prim_nid == LNET_NID_ANY) {
+ nid0_used = true;
+ prim_nid = nids[0];
+ }
+
+ /* Create the prim_nid first */
+ rc = dispatch_peer_ni_cmd(prim_nid, LNET_NID_ANY,
+ IOC_LIBCFS_ADD_PEER_NI,
+ &data, err_str, "add");
+
+ if (rc != 0)
+ goto out;
+
+ /* add the rest of the nids to the key nid if any are available */
+ for (idx = nid0_used ? 1 : 0 ; nids && idx < num_nids; idx++) {
+ /*
+ * If prim_nid is not provided then the first nid in the
+ * list becomes the prim_nid. First time round the loop use
+ * LNET_NID_ANY for the first parameter, then use nid[0]
+ * as the key nid after wards
+ */
+ rc = dispatch_peer_ni_cmd(prim_nid, nids[idx],
+ IOC_LIBCFS_ADD_PEER_NI, &data,
+ err_str, "add");
+
+ if (rc != 0)
+ goto out;
+ }
+
+out:
+ if (nids != NULL)
+ free(nids);
+ cYAML_build_error(rc, seq_no, ADD_CMD, "peer_ni", err_str, err_rc);
+ return rc;
+}
+
+int lustre_lnet_del_peer_nid(char *pnid, char **nid, int num_nids,
+ int seq_no, struct cYAML **err_rc)
+{
+ struct lnet_ioctl_peer_cfg data;
+ lnet_nid_t prim_nid;
+ int rc = LUSTRE_CFG_RC_NO_ERR;
+ int idx = 0;
+ char err_str[LNET_MAX_STR_LEN] = {0};
+ lnet_nid_t *nids = allocate_create_nid_array(nid, num_nids, err_str);
+
+ if (pnid == NULL) {
+ snprintf(err_str, sizeof(err_str),
+ "\"Primary nid is not provided\"");
+ rc = LUSTRE_CFG_RC_MISSING_PARAM;
+ goto out;
+ } else {
+ prim_nid = libcfs_str2nid(pnid);
+ if (prim_nid == LNET_NID_ANY) {
+ rc = LUSTRE_CFG_RC_BAD_PARAM;
+ snprintf(err_str, sizeof(err_str),
+ "bad key NID: '%s'",
+ pnid);
+ goto out;
+ }
+ }
+
+ snprintf(err_str, sizeof(err_str), "\"Success\"");
+
+ LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
+ if (!nids || nids[0] == LNET_NID_ANY) {
+ rc = dispatch_peer_ni_cmd(prim_nid, LNET_NID_ANY,
+ IOC_LIBCFS_DEL_PEER_NI,
+ &data, err_str, "del");
+ goto out;
+ }
+
+ for (idx = 0; nids && idx < num_nids; idx++) {
+ rc = dispatch_peer_ni_cmd(prim_nid, nids[idx],
+ IOC_LIBCFS_DEL_PEER_NI, &data,
+ err_str, "del");
+
+ if (rc != 0)
+ goto out;
+ }
+
+out:
+ if (nids != NULL)
+ free(nids);
+ cYAML_build_error(rc, seq_no, DEL_CMD, "peer_ni", err_str, err_rc);
+ return rc;
+}
+