Whamcloud - gitweb
LU-10391 lnet: support updating LNet local NI settings 60/53560/12
authorJames Simmons <jsimmons@infradead.org>
Sat, 24 Feb 2024 15:15:35 +0000 (10:15 -0500)
committerOleg Drokin <green@whamcloud.com>
Mon, 4 Mar 2024 19:57:30 +0000 (19:57 +0000)
The LNet API allows updating specific settings instead of a full new
configuration for NIs. We can accomplish this using NLM_F_REPLACE with
the LNET_CMD_NETS command. The only change for the user land tools is
now you can use large NID addresses.

Another change in the user land tools is increasing intf_name field
in size from IFNAMSIZ to LNET_MAX_STR_LEN which requires increasing
err_str handling. This is because we use struct lnet_dlc_intf_descr
both to store network addresses or / and network interfaces.

Test-Parameters: trivial testlist=sanity-lnet
Change-Id: Id334ed3a73ac6ec7a342d4616e32dcfef46907a7
Signed-off-by: James Simmons <jsimmons@infradead.org>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/53560
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Chris Horn <chris.horn@hpe.com>
Reviewed-by: Frank Sehr <fsehr@whamcloud.com>
Reviewed-by: Cyril Bordage <cbordage@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lnet/klnds/o2iblnd/o2iblnd.c
lnet/klnds/socklnd/socklnd.c
lnet/lnet/api-ni.c
lnet/utils/lnetconfig/liblnetconfig.c
lnet/utils/lnetconfig/liblnetconfig.h
lnet/utils/lnetctl.c

index 1145ac1..acdd22d 100644 (file)
@@ -1298,6 +1298,7 @@ static int
 kiblnd_nl_set(int cmd, struct nlattr *attr, int type, void *data)
 {
        struct lnet_lnd_tunables *tunables = data;
+       int rc = 0;
        s64 num;
 
        if (cmd != LNET_CMD_NETS)
@@ -1333,14 +1334,16 @@ kiblnd_nl_set(int cmd, struct nlattr *attr, int type, void *data)
                break;
        case LNET_NET_O2IBLND_TUNABLES_ATTR_CONNS_PER_PEER:
                num = nla_get_s64(attr);
-               clamp_t(s64, num, 1, 127);
-               tunables->lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = num;
+               if (num > -1 || num < 128)
+                       tunables->lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = num;
+               else
+                       rc = -ERANGE;
                fallthrough;
        default:
                break;
        }
 
-       return 0;
+       return rc;
 }
 
 static void
index 9d7ad25..1947d36 100644 (file)
@@ -841,6 +841,7 @@ static int
 ksocknal_nl_set(int cmd, struct nlattr *attr, int type, void *data)
 {
        struct lnet_lnd_tunables *tunables = data;
+       int rc = 0;
        s64 num;
 
        if (cmd != LNET_CMD_NETS)
@@ -853,8 +854,10 @@ ksocknal_nl_set(int cmd, struct nlattr *attr, int type, void *data)
        case LNET_NET_SOCKLND_TUNABLES_ATTR_CONNS_PER_PEER:
                /* value values are 1 to 127. Zero mean calculate the value */
                num = nla_get_s64(attr);
-               clamp_t(s64, num, 0, 127);
-               tunables->lnd_tun_u.lnd_sock.lnd_conns_per_peer = num;
+               if (num > -1 && num < 128)
+                       tunables->lnd_tun_u.lnd_sock.lnd_conns_per_peer = num;
+               else
+                       rc = -ERANGE;
                break;
        case LNET_NET_SOCKLND_TUNABLES_ATTR_LND_TIMEOUT:
                num = nla_get_s64(attr);
@@ -864,7 +867,7 @@ ksocknal_nl_set(int cmd, struct nlattr *attr, int type, void *data)
                break;
        }
 
-       return 0;
+       return rc;
 }
 
 static int
index 6816d3f..de2c556 100644 (file)
@@ -3987,29 +3987,30 @@ __u32 lnet_get_dlc_seq_locked(void)
 }
 
 static void
-lnet_ni_set_healthv(lnet_nid_t nid, int value, bool all)
+lnet_ni_set_healthv(struct lnet_nid *nid, int value)
 {
+       bool all = nid_same(nid, &LNET_ANY_NID);
        struct lnet_net *net;
        struct lnet_ni *ni;
 
        lnet_net_lock(LNET_LOCK_EX);
        list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
                list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
-                       if (all || (nid_is_nid4(&ni->ni_nid) &&
-                                   lnet_nid_to_nid4(&ni->ni_nid) == nid)) {
-                               atomic_set(&ni->ni_healthv, value);
-                               if (list_empty(&ni->ni_recovery) &&
-                                   value < LNET_MAX_HEALTH_VALUE) {
-                                       CERROR("manually adding local NI %s to recovery\n",
-                                              libcfs_nidstr(&ni->ni_nid));
-                                       list_add_tail(&ni->ni_recovery,
-                                                     &the_lnet.ln_mt_localNIRecovq);
-                                       lnet_ni_addref_locked(ni, 0);
-                               }
-                               if (!all) {
-                                       lnet_net_unlock(LNET_LOCK_EX);
-                                       return;
-                               }
+                       if (!all && !nid_same(&ni->ni_nid, nid))
+                               continue;
+
+                       atomic_set(&ni->ni_healthv, value);
+                       if (list_empty(&ni->ni_recovery) &&
+                           value < LNET_MAX_HEALTH_VALUE) {
+                               CERROR("manually adding local NI %s to recovery\n",
+                                      libcfs_nidstr(&ni->ni_nid));
+                               list_add_tail(&ni->ni_recovery,
+                                             &the_lnet.ln_mt_localNIRecovq);
+                               lnet_ni_addref_locked(ni, 0);
+                       }
+                       if (!all) {
+                               lnet_net_unlock(LNET_LOCK_EX);
+                               return;
                        }
                }
        }
@@ -4467,11 +4468,13 @@ LNetCtl(unsigned int cmd, void *arg)
                       "local" : "peer", libcfs_nid2str(cfg->rh_nid), cfg->rh_all);
                lnet_nid4_to_nid(cfg->rh_nid, &nid);
                mutex_lock(&the_lnet.ln_api_mutex);
-               if (cfg->rh_type == LNET_HEALTH_TYPE_LOCAL_NI)
-                       lnet_ni_set_healthv(cfg->rh_nid, value,
-                                            cfg->rh_all);
-               else
+               if (cfg->rh_type == LNET_HEALTH_TYPE_LOCAL_NI) {
+                       if (cfg->rh_all)
+                               nid = LNET_ANY_NID;
+                       lnet_ni_set_healthv(&nid, value);
+               } else {
                        lnet_peer_ni_set_healthv(&nid, value, cfg->rh_all);
+               }
                mutex_unlock(&the_lnet.ln_api_mutex);
                return 0;
        }
@@ -5888,9 +5891,10 @@ lnet_genl_parse_local_ni(struct nlattr *entry, struct genl_info *info,
                         int net_id, struct lnet_ioctl_config_ni *conf,
                         bool *ni_list)
 {
-       bool create = info->nlhdr->nlmsg_flags & NLM_F_CREATE;
        struct lnet_ioctl_config_lnd_tunables *tun;
+       struct lnet_nid nid = LNET_ANY_NID;
        struct nlattr *settings;
+       int healthv = -1;
        int rem3, rc = 0;
 
        LIBCFS_ALLOC(tun, sizeof(struct lnet_ioctl_config_lnd_tunables));
@@ -5940,6 +5944,61 @@ lnet_genl_parse_local_ni(struct nlattr *entry, struct genl_info *info,
                                }
                        }
                        *ni_list = true;
+               } else if (nla_strcmp(settings, "nid") == 0 &&
+                          net_id != LNET_NET_ANY &&
+                          info->nlhdr->nlmsg_flags & NLM_F_REPLACE) {
+                       char nidstr[LNET_NIDSTR_SIZE];
+
+                       settings = nla_next(settings, &rem3);
+                       if (nla_type(settings) != LN_SCALAR_ATTR_VALUE) {
+                               GENL_SET_ERR_MSG(info, "cannot parse NID");
+                               GOTO(out, rc = -EINVAL);
+                       }
+
+                       rc = nla_strscpy(nidstr, settings, sizeof(nidstr));
+                       if (rc < 0) {
+                               GENL_SET_ERR_MSG(info,
+                                                "failed to parse NID");
+                               GOTO(out, rc);
+                       }
+
+                       CDEBUG(D_NET, "Requested NID %s\n", nidstr);
+                       rc = libcfs_strnid(&nid, strim(nidstr));
+                       if (rc < 0) {
+                               GENL_SET_ERR_MSG(info, "unsupported NID");
+                               GOTO(out, rc);
+                       }
+               } else if (nla_strcmp(settings, "health stats") == 0 &&
+                          info->nlhdr->nlmsg_flags & NLM_F_REPLACE) {
+                       struct nlattr *health;
+                       int rem4;
+
+                       settings = nla_next(settings, &rem3);
+                       if (nla_type(settings) != LN_SCALAR_ATTR_LIST) {
+                               GENL_SET_ERR_MSG(info,
+                                                "cannot parse health stats");
+                               GOTO(out, rc = -EINVAL);
+                       }
+
+                       nla_for_each_nested(health, settings, rem4) {
+                               if (nla_type(health) != LN_SCALAR_ATTR_VALUE ||
+                                   nla_strcmp(health, "health value") != 0) {
+                                       GENL_SET_ERR_MSG(info,
+                                                        "wrong health config format");
+                                       GOTO(out, rc = -EINVAL);
+                               }
+
+                               health = nla_next(health, &rem4);
+                               if (nla_type(health) !=
+                                   LN_SCALAR_ATTR_INT_VALUE) {
+                                       GENL_SET_ERR_MSG(info,
+                                                        "invalid health config format");
+                                       GOTO(out, rc = -EINVAL);
+                               }
+
+                               healthv = nla_get_s64(health);
+                               clamp_t(s64, healthv, 0, LNET_MAX_HEALTH_VALUE);
+                       }
                } else if (nla_strcmp(settings, "tunables") == 0) {
                        settings = nla_next(settings, &rem3);
                        if (nla_type(settings) !=
@@ -5958,13 +6017,6 @@ lnet_genl_parse_local_ni(struct nlattr *entry, struct genl_info *info,
                } else if ((nla_strcmp(settings, "lnd tunables") == 0)) {
                        const struct lnet_lnd *lnd;
 
-                       lnd = lnet_load_lnd(LNET_NETTYP(net_id));
-                       if (IS_ERR(lnd)) {
-                               GENL_SET_ERR_MSG(info,
-                                                "LND type not supported");
-                               GOTO(out, rc = PTR_ERR(lnd));
-                       }
-
                        settings = nla_next(settings, &rem3);
                        if (nla_type(settings) !=
                            LN_SCALAR_ATTR_LIST) {
@@ -5973,12 +6025,49 @@ lnet_genl_parse_local_ni(struct nlattr *entry, struct genl_info *info,
                                GOTO(out, rc = -EINVAL);
                        }
 
-                       rc = lnet_genl_parse_lnd_tunables(settings,
-                                                         &tun->lt_tun, lnd);
-                       if (rc < 0) {
-                               GENL_SET_ERR_MSG(info,
-                                                "failed to parse lnd tunables");
-                               GOTO(out, rc);
+                       if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE &&
+                           net_id == LNET_NET_ANY) {
+                               struct lnet_net *net;
+
+                               lnet_net_lock(LNET_LOCK_EX);
+                               list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
+                                       struct lnet_ni *ni;
+
+                                       if (!net->net_lnd)
+                                               continue;
+
+                                       list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
+                                               if (!nid_same(&nid, &LNET_ANY_NID) &&
+                                                   !nid_same(&nid, &ni->ni_nid))
+                                                       continue;
+
+                                               rc = lnet_genl_parse_lnd_tunables(settings,
+                                                                                 &ni->ni_lnd_tunables,
+                                                                                 net->net_lnd);
+                                               if (rc < 0) {
+                                                       GENL_SET_ERR_MSG(info,
+                                                                        "failed to parse lnd tunables");
+                                                       lnet_net_unlock(LNET_LOCK_EX);
+                                                       GOTO(out, rc);
+                                               }
+                                       }
+                               }
+                               lnet_net_unlock(LNET_LOCK_EX);
+                       } else {
+                               lnd = lnet_load_lnd(LNET_NETTYP(net_id));
+                               if (IS_ERR(lnd)) {
+                                       GENL_SET_ERR_MSG(info,
+                                                        "LND type not supported");
+                                       GOTO(out, rc = PTR_ERR(lnd));
+                               }
+
+                               rc = lnet_genl_parse_lnd_tunables(settings,
+                                                                 &tun->lt_tun, lnd);
+                               if (rc < 0) {
+                                       GENL_SET_ERR_MSG(info,
+                                                        "failed to parse lnd tunables");
+                                       GOTO(out, rc);
+                               }
                        }
                } else if (nla_strcmp(settings, "CPT") == 0) {
                        struct nlattr *cpt;
@@ -6014,10 +6103,36 @@ lnet_genl_parse_local_ni(struct nlattr *entry, struct genl_info *info,
                }
        }
 
-       if (!create) {
+       if (info->nlhdr->nlmsg_flags & NLM_F_CREATE) {
+               if (!strlen(conf->lic_ni_intf)) {
+                       GENL_SET_ERR_MSG(info,
+                                        "interface is missing");
+                       GOTO(out, rc);
+               }
+
+               rc = lnet_dyn_add_ni(conf, net_id, tun);
+               switch (rc) {
+               case -ENOENT:
+                       GENL_SET_ERR_MSG(info,
+                                        "cannot parse net");
+                       break;
+               case -ERANGE:
+                       GENL_SET_ERR_MSG(info,
+                                        "invalid CPT set");
+                       break;
+               default:
+                       GENL_SET_ERR_MSG(info,
+                                        "cannot add LNet NI");
+               case 0:
+                       break;
+               }
+       } else if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE && healthv != -1) {
+               lnet_ni_set_healthv(&nid, healthv);
+       } else if (!(info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_REPLACE))) {
                struct lnet_net *net;
                struct lnet_ni *ni;
 
+               /* delete case */
                rc = -ENODEV;
                if (!strlen(conf->lic_ni_intf)) {
                        GENL_SET_ERR_MSG(info,
@@ -6056,29 +6171,6 @@ lnet_genl_parse_local_ni(struct nlattr *entry, struct genl_info *info,
                                         "interface invalid for deleting LNet NI");
                        lnet_net_unlock(LNET_LOCK_EX);
                }
-       } else {
-               if (!strlen(conf->lic_ni_intf)) {
-                       GENL_SET_ERR_MSG(info,
-                                        "interface is missing");
-                       GOTO(out, rc);
-               }
-
-               rc = lnet_dyn_add_ni(conf, net_id, tun);
-               switch (rc) {
-               case -ENOENT:
-                       GENL_SET_ERR_MSG(info,
-                                        "cannot parse net");
-                       break;
-               case -ERANGE:
-                       GENL_SET_ERR_MSG(info,
-                                        "invalid CPT set");
-                       break;
-               default:
-                       GENL_SET_ERR_MSG(info,
-                                        "cannot add LNet NI");
-               case 0:
-                       break;
-               }
        }
 out:
        if (tun)
@@ -6203,7 +6295,8 @@ static int lnet_net_cmd(struct sk_buff *skb, struct genl_info *info)
                }
 
                /* Handle case of just sent NET with no list of NIDs */
-               if (!(info->nlhdr->nlmsg_flags & NLM_F_CREATE) && !ni_list) {
+               if (!(info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_REPLACE)) &&
+                   !ni_list) {
                        rc = lnet_dyn_del_net(net_id);
                        if (rc < 0) {
                                GENL_SET_ERR_MSG(info,
index 1d87f58..e2c0afe 100644 (file)
@@ -1918,7 +1918,7 @@ int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
        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] = "\"success\"";
+       char err_str[LNET_MAX_STR_LEN * 2] = "\"success\"";
        lnet_nid_t *nids = NULL;
        __u32 nnids = 0;
        size_t len;
@@ -2063,7 +2063,7 @@ int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw_descr,
 {
        struct lnet_ioctl_config_ni data;
        int rc = LUSTRE_CFG_RC_NO_ERR, i;
-       char err_str[LNET_MAX_STR_LEN] = "\"success\"";
+       char err_str[LNET_MAX_STR_LEN * 2] = "\"success\"";
        lnet_nid_t *nids = NULL;
        __u32 nnids = 0;
        struct lnet_dlc_intf_descr *intf_descr, *tmp;
index 2fc7c08..8a482a7 100644 (file)
@@ -94,7 +94,7 @@ struct lnet_dlc_network_descr {
 
 struct lnet_dlc_intf_descr {
        struct list_head intf_on_network;
-       char intf_name[IFNAMSIZ];
+       char intf_name[LNET_MAX_STR_LEN];
        struct cfs_expr_list *cpt_expr;
 };
 
index ccc65e3..97aa63d 100644 (file)
@@ -1671,7 +1671,7 @@ static int yaml_add_ni_tunables(yaml_emitter_t *output,
 {
        char num[INT_STRING_LEN];
        yaml_event_t event;
-       int rc;
+       int rc = 0;
 
        if (tunables->lt_cmn.lct_peer_timeout < 0 &&
            tunables->lt_cmn.lct_peer_tx_credits <= 0 &&
@@ -1870,7 +1870,9 @@ skip_general_settings:
                        if (rc == 0)
                                goto error;
 
-                       if (LNET_NETTYP(nw_descr->nw_id) == SOCKLND)
+                       if (nw_descr->nw_id == LNET_NET_ANY)
+                               cpp = tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer;
+                       else if (LNET_NETTYP(nw_descr->nw_id) == SOCKLND)
                                cpp = tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer;
                        else if (LNET_NETTYP(nw_descr->nw_id) == O2IBLND)
                                cpp = tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer;
@@ -1896,7 +1898,7 @@ error:
 static int yaml_lnet_config_ni(char *net_id, char *ip2net,
                               struct lnet_dlc_network_descr *nw_descr,
                               struct lnet_ioctl_config_lnd_tunables *tunables,
-                              struct cfs_expr_list *global_cpts,
+                              int healthv, struct cfs_expr_list *global_cpts,
                               int version, int flags)
 {
        struct lnet_dlc_intf_descr *intf;
@@ -1908,14 +1910,19 @@ static int yaml_lnet_config_ni(char *net_id, char *ip2net,
        int rc;
 
        if (!(flags & NLM_F_DUMP) && !ip2net && (!nw_descr || nw_descr->nw_id == 0)) {
-               fprintf(stdout, "missing mandatory parameters in NI config: '%s'",
+               fprintf(stdout, "missing mandatory parameters in NI config: '%s'\n",
                        (!nw_descr) ? "network , interface" :
                        (nw_descr->nw_id == 0) ? "network" : "interface");
                return -EINVAL;
        }
 
        if ((flags == NLM_F_CREATE) && !ip2net && list_empty(&nw_descr->nw_intflist)) {
-               fprintf(stdout, "creating a local NI needs at least one interface");
+               fprintf(stdout, "creating a local NI needs at least one interface\n");
+               return -EINVAL;
+       }
+
+       if ((flags == NLM_F_REPLACE) && list_empty(&nw_descr->nw_intflist)) {
+               fprintf(stdout, "updating a local NI needs at least one address\n");
                return -EINVAL;
        }
 
@@ -2047,44 +2054,67 @@ static int yaml_lnet_config_ni(char *net_id, char *ip2net,
                if (rc == 0)
                        goto emitter_error;
 
-               yaml_scalar_event_initialize(&event, NULL,
-                                            (yaml_char_t *)YAML_STR_TAG,
-                                            (yaml_char_t *)"interfaces",
-                                            strlen("interfaces"), 1, 0,
-                                            YAML_PLAIN_SCALAR_STYLE);
-               rc = yaml_emitter_emit(&output, &event);
-               if (rc == 0)
-                       goto emitter_error;
+               /* Use NI addresses instead of interface */
+               if ((strchr(intf->intf_name, '@') ||
+                    strcmp(intf->intf_name, "<?>") == 0) &&
+                   flags == NLM_F_REPLACE) {
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_STR_TAG,
+                                                    (yaml_char_t *)"nid",
+                                                    strlen("nid"), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
 
-               yaml_mapping_start_event_initialize(&event, NULL,
-                                                   (yaml_char_t *)YAML_MAP_TAG,
-                                                   1, YAML_ANY_MAPPING_STYLE);
-               rc = yaml_emitter_emit(&output, &event);
-               if (rc == 0)
-                       goto emitter_error;
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_STR_TAG,
+                                                    (yaml_char_t *)intf->intf_name,
+                                                    strlen(intf->intf_name), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+               } else {
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_STR_TAG,
+                                                    (yaml_char_t *)"interfaces",
+                                                    strlen("interfaces"), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
 
-               yaml_scalar_event_initialize(&event, NULL,
-                                            (yaml_char_t *)YAML_STR_TAG,
-                                            (yaml_char_t *)"0",
-                                            strlen("0"), 1, 0,
-                                            YAML_PLAIN_SCALAR_STYLE);
-               rc = yaml_emitter_emit(&output, &event);
-               if (rc == 0)
-                       goto emitter_error;
+                       yaml_mapping_start_event_initialize(&event, NULL,
+                                                           (yaml_char_t *)YAML_MAP_TAG,
+                                                           1, YAML_ANY_MAPPING_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
 
-               yaml_scalar_event_initialize(&event, NULL,
-                                            (yaml_char_t *)YAML_STR_TAG,
-                                            (yaml_char_t *)intf->intf_name,
-                                            strlen(intf->intf_name), 1, 0,
-                                            YAML_PLAIN_SCALAR_STYLE);
-               rc = yaml_emitter_emit(&output, &event);
-               if (rc == 0)
-                       goto emitter_error;
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_STR_TAG,
+                                                    (yaml_char_t *)"0",
+                                                    strlen("0"), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
 
-               yaml_mapping_end_event_initialize(&event);
-               rc = yaml_emitter_emit(&output, &event);
-               if (rc == 0)
-                       goto emitter_error;
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_STR_TAG,
+                                                    (yaml_char_t *)intf->intf_name,
+                                                    strlen(intf->intf_name), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+
+                       yaml_mapping_end_event_initialize(&event);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+               }
 
                if (tunables) {
                        rc = yaml_add_ni_tunables(&output, tunables, nw_descr);
@@ -2092,6 +2122,51 @@ static int yaml_lnet_config_ni(char *net_id, char *ip2net,
                                goto emitter_error;
                }
 
+               if (flags == NLM_F_REPLACE && healthv > -1) {
+                       char health[INT_STRING_LEN];
+
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_STR_TAG,
+                                                    (yaml_char_t *)"health stats",
+                                                    strlen("health stats"), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+
+                       /* Setup all mappings for data related to the 'health stats' */
+                       yaml_mapping_start_event_initialize(&event, NULL,
+                                                           (yaml_char_t *)YAML_MAP_TAG,
+                                                           1, YAML_BLOCK_MAPPING_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_STR_TAG,
+                                                    (yaml_char_t *)"health value",
+                                                    strlen("health value"), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+
+                       snprintf(health, sizeof(health), "%d", healthv);
+                       yaml_scalar_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_INT_TAG,
+                                                    (yaml_char_t *)health,
+                                                    strlen(health), 1, 0,
+                                                    YAML_PLAIN_SCALAR_STYLE);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+
+                       yaml_mapping_end_event_initialize(&event);
+                       rc = yaml_emitter_emit(&output, &event);
+                       if (rc == 0)
+                               goto emitter_error;
+               }
+
                if (global_cpts) {
                        __u32 *cpt_array;
                        int count, i;
@@ -2373,7 +2448,7 @@ static int jt_add_ni(int argc, char **argv)
                tunables.lt_tun.lnd_tun_u.lnd_o2ib.lnd_map_on_demand = UINT_MAX;
 
        rc = yaml_lnet_config_ni(net_id, ip2net, &nw_descr,
-                                found ? &tunables : NULL,
+                                found ? &tunables : NULL, -1,
                                 (cpt_rc == 0) ? global_cpts : NULL,
                                 LNET_GENL_VERSION, NLM_F_CREATE);
        if (rc <= 0) {
@@ -2504,7 +2579,7 @@ static int jt_del_ni(int argc, char **argv)
                }
        }
 
-       rc = yaml_lnet_config_ni(net_id, NULL, &nw_descr, NULL, NULL,
+       rc = yaml_lnet_config_ni(net_id, NULL, &nw_descr, NULL, -1, NULL,
                                 LNET_GENL_VERSION, 0);
        if (rc <= 0) {
                if (rc != -EOPNOTSUPP)
@@ -2600,19 +2675,21 @@ old_api:
        return rc;
 }
 
-static int set_value_helper(int argc, char **argv,
+static int set_value_helper(int argc, char **argv, int cmd,
                            int (*cb)(int, bool, char*, int, int, struct cYAML**))
 {
-       char *nid = NULL;
+       char *nidstr = NULL;
        long int healthv = -1;
        bool all = false;
        long int state = -1;
+       long int cpp = -1;
        int rc, opt;
        struct cYAML *err_rc = NULL;
-       const char *const short_options = "t:n:s:a";
+       const char *const short_options = "t:n:m:s:a";
        static const struct option long_options[] = {
                { .name = "nid", .has_arg = required_argument, .val = 'n' },
                { .name = "health", .has_arg = required_argument, .val = 't' },
+               { .name = "conns-per-peer", .has_arg = required_argument, .val = 'm' },
                { .name = "state", .has_arg = required_argument, .val = 's' },
                { .name = "all", .has_arg = no_argument, .val = 'a' },
                { .name = NULL }
@@ -2622,16 +2699,23 @@ static int set_value_helper(int argc, char **argv,
                                  long_options, NULL)) != -1) {
                switch (opt) {
                case 'n':
-                       nid = optarg;
+                       nidstr = optarg;
                        break;
                case 't':
                        if (parse_long(optarg, &healthv) != 0)
                                healthv = -1;
                        break;
                case 's':
-                       if (parse_long(optarg, &state) != 0)
+                       if (cmd != LNET_CMD_PEERS ||
+                           parse_long(optarg, &state) != 0)
                                state = -1;
                        break;
+               case 'm':
+                       if (cmd != LNET_CMD_NETS ||
+                           parse_long(optarg, &cpp) != 0)
+                               cpp = -1;
+                       break;
+
                case 'a':
                        all = true;
                        break;
@@ -2640,7 +2724,8 @@ static int set_value_helper(int argc, char **argv,
                }
        }
 
-       rc = cb(healthv, all, nid, state, -1, &err_rc);
+       rc = cb(healthv, all, nidstr, cmd == LNET_CMD_PEERS ? state : cpp, -1,
+               &err_rc);
        if (rc != LUSTRE_CFG_RC_NO_ERR)
                cYAML_print_tree2file(stderr, err_rc);
 
@@ -2649,70 +2734,73 @@ static int set_value_helper(int argc, char **argv,
        return rc;
 }
 
-static int jt_set_ni_value(int argc, char **argv)
+int yaml_lnet_config_ni_healthv(int healthv, bool all, char *nidstr, int cpp,
+                               int seq_no, struct cYAML **err_rc)
 {
-       char *nid = NULL;
-       long int healthv = -1, cpp = -1;
-       bool all = false;
-       int rc, opt;
-       struct cYAML *err_rc = NULL;
+       struct lnet_ioctl_config_lnd_tunables tunables;
+       struct lnet_dlc_network_descr nw_descr;
+       char *net_id = "<255:65535>"; /* LNET_NET_ANY */
+       int rc = 0;
 
-       const char *const short_options = "a:m:n:t:";
-       static const struct option long_options[] = {
-       { .name = "all",            .has_arg = no_argument,       .val = 'a' },
-       { .name = "conns-per-peer", .has_arg = required_argument, .val = 'm' },
-       { .name = "nid",            .has_arg = required_argument, .val = 'n' },
-       { .name = "health",         .has_arg = required_argument, .val = 't' },
-       { .name = NULL } };
+       /* For NI you can't have both setting all NIDs and a requested NID */
+       if (!all && !nidstr)
+               return -EINVAL;
 
-       rc = check_cmd(net_cmds, "net", "set", 0, argc, argv);
-       if (rc)
-               return rc;
+       if (cpp == -1 && healthv == -1)
+               return 0;
 
-       while ((opt = getopt_long(argc, argv, short_options,
-                                  long_options, NULL)) != -1) {
-               switch (opt) {
-               case 'a':
-                       all = true;
-                       break;
-               case 'm':
-                       rc = parse_long(optarg, &cpp);
-                       if (rc != 0) {
-                               /* ignore option */
-                               cpp = -1;
-                               continue;
-                       }
-                       break;
-               case 'n':
-                       nid = optarg;
-                       break;
-               case 't':
-                       if (parse_long(optarg, &healthv) != 0) {
-                               /* ignore option */
-                               healthv = -1;
-                               continue;
-                       }
-                       break;
-               default:
-                       return 0;
-               }
+       if (nidstr) {
+               net_id = strchr(nidstr, '@');
+               if (!net_id)
+                       return -EINVAL;
+               net_id++;
        }
 
-       if (cpp > -1)
-               rc = lustre_lnet_config_ni_conns_per_peer(cpp, all, nid,
-                                                         -1, &err_rc);
-       if (healthv > -1)
-               rc = lustre_lnet_config_ni_healthv(healthv, all, nid,
-                                                  -1, &err_rc);
+       lustre_lnet_init_nw_descr(&nw_descr);
+       nw_descr.nw_id = libcfs_str2net(net_id);
 
+       rc = lustre_lnet_parse_interfaces(nidstr ? nidstr : "<?>", &nw_descr);
        if (rc != LUSTRE_CFG_RC_NO_ERR)
-               cYAML_print_tree2file(stderr, err_rc);
+               return -EINVAL;
 
-       cYAML_free_tree(err_rc);
+       memset(&tunables, 0, sizeof(tunables));
+       tunables.lt_cmn.lct_peer_timeout = -1;
+       if (nw_descr.nw_id == LNET_NET_ANY && cpp > -1)
+               tunables.lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer = cpp;
+       else if (LNET_NETTYP(nw_descr.nw_id) == SOCKLND && (cpp > -1))
+               tunables.lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer = cpp;
+       else if (LNET_NETTYP(nw_descr.nw_id) == O2IBLND && (cpp > -1))
+               tunables.lt_tun.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = cpp;
 
+       rc = yaml_lnet_config_ni(net_id, NULL, &nw_descr,
+                                cpp != -1 ? &tunables : NULL, healthv, NULL,
+                                LNET_GENL_VERSION, NLM_F_REPLACE);
+       if (rc <= 0) {
+               if (rc == -EOPNOTSUPP)
+                       goto old_api;
+               return rc;
+       }
+old_api:
+       if (cpp > -1)
+               rc = lustre_lnet_config_ni_conns_per_peer(cpp, all, nidstr,
+                                                         -1, err_rc);
+       if (healthv > -1)
+               rc = lustre_lnet_config_ni_healthv(healthv, all, nidstr,
+                                                  -1, err_rc);
        return rc;
 }
 
+static int jt_set_ni_value(int argc, char **argv)
+{
+       int rc = check_cmd(net_cmds, "net", "set", 0, argc, argv);
+
+       if (rc < 0)
+               return rc;
+
+       return set_value_helper(argc, argv, LNET_CMD_NETS,
+                               yaml_lnet_config_ni_healthv);
+}
+
 static int yaml_lnet_peer_display(yaml_parser_t *reply, bool list_only)
 {
        yaml_emitter_t debug;
@@ -3227,10 +3315,6 @@ old_api:
                                                        seq_no, err_rc);
        else
                rc = lustre_lnet_set_peer_state(state, lpni_nid, -1, err_rc);
-       if (rc != LUSTRE_CFG_RC_NO_ERR)
-               cYAML_print_tree2file(stderr, *err_rc);
-
-       cYAML_free_tree(*err_rc);
 
        return rc;
 }
@@ -3242,7 +3326,8 @@ static int jt_set_peer_ni_value(int argc, char **argv)
        if (rc < 0)
                return rc;
 
-       return set_value_helper(argc, argv, yaml_lnet_config_peer_ni_healthv);
+       return set_value_helper(argc, argv, LNET_CMD_PEERS,
+                               yaml_lnet_config_peer_ni_healthv);
 }
 
 static int jt_show_recovery(int argc, char **argv)
@@ -3358,7 +3443,7 @@ static int jt_show_net(int argc, char **argv)
                }
        }
 
-       rc = yaml_lnet_config_ni(network, NULL, NULL, NULL, NULL,
+       rc = yaml_lnet_config_ni(network, NULL, NULL, NULL, -1, NULL,
                                 detail, NLM_F_DUMP);
        if (rc <= 0) {
                if (rc != -EOPNOTSUPP)