Whamcloud - gitweb
0dbb8d2e77f9df1d74c46d099c4567e797877d57
[fs/lustre-release.git] / lnet / utils / lnetconfig / liblnetconfig.c
1 // SPDX-License-Identifier: LGPL-2.0
2
3 /*
4  * Copyright (c) 2014, 2017, Intel Corporation.
5  */
6
7 /*
8  * This file is part of Lustre, http://www.lustre.org/
9  *
10  * There are two APIs:
11  *  1. APIs that take the actual parameters expanded.  This is for other
12  *  entities that would like to link against the library and call the APIs
13  *  directly without having to form an intermediate representation.
14  *  2. APIs that take a YAML file and parses out the information there and
15  *  calls the APIs mentioned in 1
16  *
17  * Author: Amir Shehata <amir.shehata@intel.com>
18  */
19
20 #include <ctype.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <byteswap.h>
24 #include <netdb.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/ioctl.h>
30 #include <net/if.h>
31 #include <libcfs/util/ioctl.h>
32 #include <libcfs/util/hash.h>
33 #include <linux/lnet/lnetctl.h>
34 #include "liblnd.h"
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <ifaddrs.h>
39 #include <rdma/rdma_user_cm.h>
40 #include "liblnetconfig.h"
41 #include <glob.h>
42 #include <libcfs/util/param.h>
43
44 #ifndef HAVE_USRSPC_RDMA_PS_TCP
45 #define RDMA_PS_TCP 0x0106
46 #endif
47
48 #define cxi_nic_addr_path "/sys/class/cxi/cxi%u/device/properties/"
49 const char *gmsg_stat_names[] = {"sent_stats", "received_stats",
50                                  "dropped_stats"};
51
52 /*
53  * lustre_lnet_ip_range_descr
54  *      Describes an IP range.
55  *      Each octect is an expression
56  */
57 struct lustre_lnet_ip_range_descr {
58         struct list_head ipr_entry;
59         struct list_head ipr_expr;
60 };
61
62 /*
63  * lustre_lnet_ip2nets
64  *      Describes an ip2nets rule. This can be on a list of rules.
65  */
66 struct lustre_lnet_ip2nets {
67         struct lnet_dlc_network_descr ip2nets_net;
68         struct list_head ip2nets_ip_ranges;
69 };
70
71 static int open_sysfs_file(const char *path, const char *attr, const int mode)
72 {
73         int fd;
74         char filename[LNET_MAX_STR_LEN];
75         size_t size = sizeof(filename);
76         int namelen;
77
78         namelen = snprintf(filename, size, "%s%s", path, attr);
79         if (namelen >= size)
80                 filename[size - 1] = '\0';
81
82         fd = open(filename, mode);
83
84         return fd;
85 }
86
87 static int read_sysfs_file(const char *path, const char *attr,
88                            void *val, const size_t size, const int nelem)
89 {
90         int fd;
91         int rc = LUSTRE_CFG_RC_GENERIC_ERR;
92
93         fd = open_sysfs_file(path, attr, O_RDONLY);
94         if (fd == -1)
95                 return LUSTRE_CFG_RC_NO_MATCH;
96
97         if (read(fd, val, size * nelem) == -1)
98                 goto close_fd;
99
100         rc = LUSTRE_CFG_RC_NO_ERR;
101
102 close_fd:
103         close(fd);
104         return rc;
105 }
106
107 static int write_sysfs_file(const char *path, const char *attr,
108                             void *val, const size_t size, const int nelem)
109 {
110         int fd;
111         int rc = LUSTRE_CFG_RC_GENERIC_ERR;
112
113         fd = open_sysfs_file(path, attr, O_WRONLY | O_TRUNC);
114         if (fd == -1)
115                 return LUSTRE_CFG_RC_NO_MATCH;
116
117         if (write(fd, val, size * nelem) == -1)
118                 goto close_fd;
119
120         rc = LUSTRE_CFG_RC_NO_ERR;
121
122 close_fd:
123         close(fd);
124         return rc;
125 }
126
127 /*
128  * free_intf_descr
129  *      frees the memory allocated for an intf descriptor.
130  */
131 static void free_intf_descr(struct lnet_dlc_intf_descr *intf_descr)
132 {
133         if (!intf_descr)
134                 return;
135
136         if (intf_descr->cpt_expr != NULL)
137                 cfs_expr_list_free(intf_descr->cpt_expr);
138         free(intf_descr);
139 }
140
141 /*
142  * lustre_lnet_add_ip_range
143  * Formatting:
144  *      given a string of the format:
145  *      <expr.expr.expr.expr> parse each expr into
146  *      a lustre_lnet_ip_range_descr structure and insert on the list.
147  *
148  *      This function is called from
149  *              YAML on each ip-range.
150  *              As a result of lnetctl command
151  *              When building a NID or P2P selection rules
152  */
153 static int lustre_lnet_add_ip_range(struct list_head *list, char *str_ip_range)
154 {
155         struct lustre_lnet_ip_range_descr *ip_range;
156         int rc;
157
158         ip_range = calloc(1, sizeof(*ip_range));
159         if (ip_range == NULL)
160                 return LUSTRE_CFG_RC_OUT_OF_MEM;
161
162         INIT_LIST_HEAD(&ip_range->ipr_entry);
163         INIT_LIST_HEAD(&ip_range->ipr_expr);
164
165         rc = cfs_ip_addr_parse(str_ip_range, strlen(str_ip_range),
166                                &ip_range->ipr_expr);
167         if (rc != 0)
168                 return LUSTRE_CFG_RC_BAD_PARAM;
169
170         list_add_tail(&ip_range->ipr_entry, list);
171
172         return LUSTRE_CFG_RC_NO_ERR;
173 }
174
175 static int lustre_lnet_add_intf_descr(struct list_head *list, char *intf,
176                                       int len)
177 {
178         char *open_sq_bracket = NULL, *close_sq_bracket = NULL,
179              *intf_name;
180         struct lnet_dlc_intf_descr *intf_descr = NULL;
181         int rc;
182         char intf_string[LNET_MAX_STR_LEN];
183
184         if (len >= LNET_MAX_STR_LEN)
185                 return LUSTRE_CFG_RC_BAD_PARAM;
186
187         strncpy(intf_string, intf, len);
188         intf_string[len] = '\0';
189
190         intf_descr = calloc(1, sizeof(*intf_descr));
191         if (intf_descr == NULL)
192                 return LUSTRE_CFG_RC_OUT_OF_MEM;
193
194         INIT_LIST_HEAD(&intf_descr->intf_on_network);
195
196         intf_name = intf_string;
197         open_sq_bracket = strchr(intf_string, '[');
198         if (open_sq_bracket != NULL) {
199                 close_sq_bracket = strchr(intf_string, ']');
200                 if (close_sq_bracket == NULL) {
201                         free(intf_descr);
202                         return LUSTRE_CFG_RC_BAD_PARAM;
203                 }
204                 rc = cfs_expr_list_parse(open_sq_bracket,
205                                          strlen(open_sq_bracket), 0, UINT_MAX,
206                                          &intf_descr->cpt_expr);
207                 if (rc < 0) {
208                         free(intf_descr);
209                         return LUSTRE_CFG_RC_BAD_PARAM;
210                 }
211                 strncpy(intf_descr->intf_name, intf_name,
212                         open_sq_bracket - intf_name);
213                 intf_descr->intf_name[open_sq_bracket - intf_name] = '\0';
214         } else {
215                 strcpy(intf_descr->intf_name, intf_name);
216                 intf_descr->cpt_expr = NULL;
217         }
218
219         list_add_tail(&intf_descr->intf_on_network, list);
220
221         return LUSTRE_CFG_RC_NO_ERR;
222 }
223
224 void lustre_lnet_init_nw_descr(struct lnet_dlc_network_descr *nw_descr)
225 {
226         if (nw_descr != NULL) {
227                 nw_descr->nw_id = 0;
228                 INIT_LIST_HEAD(&nw_descr->network_on_rule);
229                 INIT_LIST_HEAD(&nw_descr->nw_intflist);
230         }
231 }
232
233 int lustre_lnet_parse_nidstr(char *nidstr, lnet_nid_t *lnet_nidlist,
234                              int max_nids, char *err_str)
235 {
236         int rc, num_nids = 0;
237         struct list_head nidlist;
238
239         if (!nidstr) {
240                 snprintf(err_str, LNET_MAX_STR_LEN, "supplied nidstr is NULL");
241                 return LUSTRE_CFG_RC_BAD_PARAM;
242         }
243
244         if (strchr(nidstr, '*')) {
245                 snprintf(err_str, LNET_MAX_STR_LEN,
246                          "asterisk not allowed in nidstring \"%s\"", nidstr);
247                 return LUSTRE_CFG_RC_BAD_PARAM;
248         }
249
250         INIT_LIST_HEAD(&nidlist);
251         rc = cfs_parse_nidlist(nidstr, strlen(nidstr), &nidlist);
252         if (rc == 0) {
253                 snprintf(err_str, LNET_MAX_STR_LEN,
254                          "Unable to parse nidlist from: %s\n", nidstr);
255                 return LUSTRE_CFG_RC_BAD_PARAM;
256         }
257
258         if (list_empty(&nidlist)) {
259                 snprintf(err_str, LNET_MAX_STR_LEN,
260                          "\"%s\" does not specify any valid nid lists", nidstr);
261                 return LUSTRE_CFG_RC_BAD_PARAM;
262         }
263
264         num_nids = cfs_expand_nidlist(&nidlist, lnet_nidlist, max_nids);
265         cfs_free_nidlist(&nidlist);
266
267         if (num_nids == -1) {
268                 snprintf(err_str, LNET_MAX_STR_LEN,
269                          "\"%s\" specifies more than the %d NIDs allowed by this operation.",
270                          nidstr, max_nids);
271                 return LUSTRE_CFG_RC_BAD_PARAM;
272         }
273
274         if (num_nids < 0) {
275                 snprintf(err_str, LNET_MAX_STR_LEN,
276                          "Failed to expand nidstr: %s", strerror(num_nids));
277                 return LUSTRE_CFG_RC_OUT_OF_MEM;
278         }
279
280         if (num_nids == 0) {
281                 snprintf(err_str, LNET_MAX_STR_LEN,
282                          "\"%s\" did not expand to any nids", nidstr);
283                 return LUSTRE_CFG_RC_BAD_PARAM;
284         }
285
286         return num_nids;
287 }
288
289 /*
290  * format expected:
291  *      <intf>[<expr>], <intf>[<expr>],..
292  */
293 int lustre_lnet_parse_interfaces(char *intf_str,
294                                  struct lnet_dlc_network_descr *nw_descr)
295 {
296         char *open_square;
297         char *close_square;
298         char *comma;
299         char *cur = intf_str, *next = NULL;
300         char *end = intf_str + strlen(intf_str);
301         int rc, len;
302         struct lnet_dlc_intf_descr *intf_descr, *tmp;
303
304         if (nw_descr == NULL)
305                 return LUSTRE_CFG_RC_BAD_PARAM;
306
307         while (cur < end) {
308                 char *net;
309
310                 open_square = strchr(cur, '[');
311                 if (open_square != NULL) {
312                         close_square = strchr(cur, ']');
313                         if (close_square == NULL) {
314                                 rc = LUSTRE_CFG_RC_BAD_PARAM;
315                                 goto failed;
316                         }
317
318                         comma = strchr(cur, ',');
319                         if (comma != NULL && comma > close_square) {
320                                 next = comma + 1;
321                                 len = next - close_square;
322                         } else {
323                                 len = strlen(cur);
324                                 next = cur + len;
325                         }
326                 } else {
327                         comma = strchr(cur, ',');
328                         if (comma != NULL) {
329                                 next = comma + 1;
330                                 len = comma - cur;
331                         } else {
332                                 len = strlen(cur);
333                                 next = cur + len;
334                         }
335                 }
336
337                 /* Extract net id if its a NID string */
338                 net = strchr(cur, '@');
339                 if (net)
340                         nw_descr->nw_id = libcfs_str2net(net + 1);
341                 rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist, cur, len);
342                 if (rc != LUSTRE_CFG_RC_NO_ERR)
343                         goto failed;
344
345                 cur = next;
346         }
347
348         return LUSTRE_CFG_RC_NO_ERR;
349
350 failed:
351         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
352                                  intf_on_network) {
353                 list_del(&intf_descr->intf_on_network);
354                 free_intf_descr(intf_descr);
355         }
356
357         return rc;
358 }
359
360 int lustre_lnet_config_lib_init(void)
361 {
362         return register_ioc_dev(LNET_DEV_ID, LNET_DEV_PATH);
363 }
364
365 void lustre_lnet_config_lib_uninit(void)
366 {
367         unregister_ioc_dev(LNET_DEV_ID);
368 }
369
370 int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
371                                  int seq_no, struct cYAML **err_rc)
372 {
373         struct libcfs_ioctl_data data;
374         unsigned int opc;
375         int rc;
376         char err_str[LNET_MAX_STR_LEN] = "\"Success\"";
377
378         LIBCFS_IOC_INIT(data);
379
380         /* Reverse logic is used here in order not to change
381          * the lctl utility */
382         data.ioc_flags = load_ni_from_mod ? 0 : 1;
383
384         opc = up ? IOC_LIBCFS_CONFIGURE : IOC_LIBCFS_UNCONFIGURE;
385
386         rc = l_ioctl(LNET_DEV_ID, opc, &data);
387         if (rc != 0) {
388                 snprintf(err_str,
389                         sizeof(err_str),
390                         "\"LNet %s error: %s\"", (up) ? "configure" :
391                         "unconfigure", strerror(errno));
392                 rc = -errno;
393         }
394
395         cYAML_build_error(rc, seq_no, (up) ? CONFIG_CMD : UNCONFIG_CMD,
396                           "lnet", err_str, err_rc);
397
398         return rc;
399 }
400
401 int yaml_lnet_configure(int flags, const char **msg)
402 {
403         char *err = "lnet configure: ";
404         yaml_parser_t setup, reply;
405         char *config = "net:\n";
406         yaml_document_t results;
407         yaml_emitter_t request;
408         struct nl_sock *sk;
409         int rc;
410
411         /* Initialize configuration parser */
412         rc = yaml_parser_initialize(&setup);
413         if (rc == 0) {
414                 yaml_parser_log_error(&setup, stderr, err);
415                 yaml_parser_delete(&setup);
416                 return -EOPNOTSUPP;
417         }
418
419         yaml_parser_set_input_string(&setup, (unsigned char *)config,
420                                      strlen(config));
421         rc = yaml_parser_load(&setup, &results);
422         if (rc == 0) {
423                 yaml_parser_log_error(&setup, stderr, err);
424                 yaml_parser_delete(&setup);
425                 return -EOPNOTSUPP;
426         }
427         yaml_parser_delete(&setup);
428
429         /* Create Netlink emitter to send request to kernel */
430         sk = nl_socket_alloc();
431         if (!sk) {
432                 yaml_document_delete(&results);
433                 return -EOPNOTSUPP;
434         }
435
436         /* Setup parser to recieve Netlink packets */
437         rc = yaml_parser_initialize(&reply);
438         if (rc == 0) {
439                 yaml_document_delete(&results);
440                 nl_socket_free(sk);
441                 return -EOPNOTSUPP;
442         }
443
444         rc = yaml_parser_set_input_netlink(&reply, sk, false);
445         if (rc == 0)
446                 goto free_reply;
447
448         yaml_emitter_initialize(&request);
449         rc = yaml_emitter_set_output_netlink(&request, sk, LNET_GENL_NAME,
450                                              LNET_GENL_VERSION,
451                                              LNET_CMD_CONFIGURE, flags);
452         if (rc == 1) /* 1 is success */
453                 rc = yaml_emitter_dump(&request, &results);
454         if (rc == 0) {
455                 yaml_emitter_log_error(&request, stderr);
456                 rc = -EINVAL;
457         } else {
458                 yaml_document_t errmsg;
459
460                 rc = yaml_parser_load(&reply, &errmsg);
461         }
462         yaml_emitter_delete(&request);
463 free_reply:
464         if (rc == 0) {
465                 *msg = yaml_parser_get_reader_error(&reply);
466                 rc = errno;
467         }
468
469         yaml_parser_delete(&reply);
470         yaml_document_delete(&results);
471         nl_socket_free(sk);
472
473         return rc == 1 ? 0 : rc;
474 }
475
476 static int dispatch_peer_ni_cmd(__u32 cmd, struct lnet_ioctl_peer_cfg *data,
477                                 char *err_str, char *cmd_str)
478 {
479         int rc;
480
481         rc = l_ioctl(LNET_DEV_ID, cmd, data);
482         if (rc) {
483                 rc = -errno;
484                 snprintf(err_str, LNET_MAX_STR_LEN,
485                          "\"%s peer ni operation failed: %s\"",
486                          cmd_str, strerror(errno));
487         }
488
489         return rc;
490 }
491
492 static int infra_ping_nid(char *ping_nids, char *src_nidstr, char *oper,
493                           int param, int ioc_call, int seq_no,
494                           struct cYAML **show_rc, struct cYAML **err_rc)
495 {
496         void *data = NULL;
497         struct lnet_ioctl_ping_data ping;
498         struct cYAML *root = NULL, *ping_node = NULL, *item = NULL,
499                      *first_seq = NULL, *tmp = NULL, *peer_ni = NULL;
500         struct lnet_process_id id;
501         char err_str[LNET_MAX_STR_LEN] = {0};
502         char *sep, *token, *end;
503         char buf[6];
504         size_t len;
505         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
506         int i;
507         bool flag = false;
508         lnet_nid_t src;
509
510         len = (sizeof(struct lnet_process_id) * LNET_INTERFACES_MAX_DEFAULT);
511
512         data = calloc(1, len);
513         if (data == NULL)
514                 goto out;
515
516         /* create struct cYAML root object */
517         root = cYAML_create_object(NULL, NULL);
518         if (root == NULL)
519                 goto out;
520
521         ping_node = cYAML_create_seq(root, oper);
522         if (ping_node == NULL)
523                 goto out;
524
525         if (src_nidstr) {
526                 src = libcfs_str2nid(src_nidstr);
527                 if (src == LNET_NID_ANY) {
528                         snprintf(err_str, sizeof(err_str),
529                                  "\"cannot parse source NID '%s'\"",
530                                  src_nidstr);
531                         rc = LUSTRE_CFG_RC_BAD_PARAM;
532                         cYAML_build_error(rc, seq_no, MANAGE_CMD,
533                                           oper, err_str, err_rc);
534                         goto out;
535                 }
536         } else {
537                 src = LNET_NID_ANY;
538         }
539
540         /* tokenise each nid in string ping_nids */
541         token = strtok(ping_nids, ",");
542
543         do {
544                 item = cYAML_create_seq_item(ping_node);
545                 if (item == NULL)
546                         goto out;
547
548                 if (first_seq == NULL)
549                         first_seq = item;
550
551                 /* check if '-' is a part of NID, token */
552                 sep = strchr(token, '-');
553                 if (sep == NULL) {
554                         id.pid = LNET_PID_ANY;
555                         /* if no net is specified, libcfs_str2nid() will assume tcp */
556                         id.nid = libcfs_str2nid(token);
557                         if (id.nid == LNET_NID_ANY) {
558                                 snprintf(err_str, sizeof(err_str),
559                                          "\"cannot parse NID '%s'\"",
560                                          token);
561                                 rc = LUSTRE_CFG_RC_BAD_PARAM;
562                                 cYAML_build_error(rc, seq_no, MANAGE_CMD,
563                                                   oper, err_str, err_rc);
564                                 continue;
565                         }
566                 } else {
567                         if (token[0] == 'u' || token[0] == 'U')
568                                 id.pid = (strtoul(&token[1], &end, 0) |
569                                           (LNET_PID_USERFLAG));
570                         else
571                                 id.pid = strtoul(token, &end, 0);
572
573                         /* assuming '-' is part of hostname */
574                         if (end != sep) {
575                                 id.pid = LNET_PID_ANY;
576                                 id.nid = libcfs_str2nid(token);
577                                 if (id.nid == LNET_NID_ANY) {
578                                         snprintf(err_str, sizeof(err_str),
579                                                  "\"cannot parse NID '%s'\"",
580                                                  token);
581                                         rc = LUSTRE_CFG_RC_BAD_PARAM;
582                                         cYAML_build_error(rc, seq_no, MANAGE_CMD,
583                                                           oper, err_str,
584                                                           err_rc);
585                                         continue;
586                                 }
587                         } else {
588                                 id.nid = libcfs_str2nid(sep + 1);
589                                 if (id.nid == LNET_NID_ANY) {
590                                         snprintf(err_str, sizeof(err_str),
591                                                  "\"cannot parse NID '%s'\"",
592                                                  token);
593                                         rc = LUSTRE_CFG_RC_BAD_PARAM;
594                                         cYAML_build_error(rc, seq_no, MANAGE_CMD,
595                                                           oper, err_str,
596                                                           err_rc);
597                                         continue;
598                                 }
599                         }
600                 }
601                 LIBCFS_IOC_INIT_V2(ping, ping_hdr);
602                 ping.ping_hdr.ioc_len = sizeof(ping);
603                 ping.ping_id          = id;
604                 ping.ping_src         = src;
605                 ping.op_param         = param;
606                 ping.ping_count       = LNET_INTERFACES_MAX_DEFAULT;
607                 ping.ping_buf         = data;
608
609                 rc = l_ioctl(LNET_DEV_ID, ioc_call, &ping);
610                 if (rc != 0) {
611                         snprintf(err_str,
612                                  sizeof(err_str), "failed to %s %s: %s\n", oper,
613                                  id.pid == LNET_PID_ANY ?
614                                  libcfs_nid2str(id.nid) :
615                                  libcfs_id2str(id), strerror(errno));
616                         rc = LUSTRE_CFG_RC_BAD_PARAM;
617                         cYAML_build_error(rc, seq_no, MANAGE_CMD,
618                                           oper, err_str, err_rc);
619                         continue;
620                 }
621
622                 if (cYAML_create_string(item, "primary nid",
623                                         libcfs_nid2str(ping.ping_id.nid)) == NULL)
624                         goto out;
625
626                 if (cYAML_create_string(item, "Multi-Rail", ping.mr_info ?
627                                         "True" : "False") == NULL)
628                         goto out;
629
630                 tmp = cYAML_create_seq(item, "peer ni");
631                 if (tmp == NULL)
632                         goto out;
633
634                 for (i = 0; i < ping.ping_count; i++) {
635                         if (ping.ping_buf[i].nid == LNET_NID_LO_0)
636                                 continue;
637                         peer_ni = cYAML_create_seq_item(tmp);
638                         if (peer_ni == NULL)
639                                 goto out;
640                         memset(buf, 0, sizeof buf);
641                         snprintf(buf, sizeof buf, "nid");
642                         if (cYAML_create_string(peer_ni, buf,
643                                                 libcfs_nid2str(ping.ping_buf[i].nid)) == NULL)
644                                 goto out;
645                 }
646
647                 flag = true;
648
649         } while ((token = strtok(NULL, ",")) != NULL);
650
651         if (flag)
652                 rc = LUSTRE_CFG_RC_NO_ERR;
653
654 out:
655         if (data)
656                 free(data);
657         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
658                 cYAML_free_tree(root);
659         } else if (show_rc != NULL && *show_rc != NULL) {
660                 struct cYAML *show_node;
661                 show_node = cYAML_get_object_item(*show_rc, oper);
662                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
663                         cYAML_insert_child(show_node, first_seq);
664                         free(ping_node);
665                         free(root);
666                 } else if (show_node == NULL) {
667                         cYAML_insert_sibling((*show_rc)->cy_child,
668                                              ping_node);
669                         free(root);
670                 } else {
671                         cYAML_free_tree(root);
672                 }
673         } else {
674                 *show_rc = root;
675         }
676
677         return rc;
678 }
679
680 int lustre_lnet_ping_nid(char *ping_nids, char *src_nidstr, int timeout,
681                          int seq_no, struct cYAML **show_rc,
682                          struct cYAML **err_rc)
683 {
684         int rc;
685
686         rc = infra_ping_nid(ping_nids, src_nidstr, "ping", timeout,
687                             IOC_LIBCFS_PING_PEER, seq_no, show_rc, err_rc);
688         return rc;
689 }
690
691 int lustre_lnet_discover_nid(char *ping_nids, int force, int seq_no,
692                          struct cYAML **show_rc, struct cYAML **err_rc)
693 {
694         int rc;
695
696         rc = infra_ping_nid(ping_nids, NULL, "discover", force,
697                             IOC_LIBCFS_DISCOVER, seq_no, show_rc, err_rc);
698         return rc;
699 }
700
701 static int lustre_lnet_handle_peer_nidlist(lnet_nid_t *nidlist, int num_nids,
702                                            bool is_mr, int option, __u32 cmd,
703                                            char *cmd_type, char *err_str)
704 {
705         struct lnet_ioctl_peer_cfg data;
706         int rc, nid_idx;
707
708         if (cmd == IOC_LIBCFS_ADD_PEER_NI) {
709                 /* When adding a peer we first need to create the peer using the
710                  * specified (or implied) primary nid. Then we can add
711                  * additional nids to this peer using the primary nid as a key
712                  */
713                 LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
714                 data.prcfg_mr = is_mr;
715                 data.prcfg_prim_nid = nidlist[0];
716                 data.prcfg_cfg_nid = LNET_NID_ANY;
717                 data.prcfg_count = option;
718
719                 rc = dispatch_peer_ni_cmd(cmd, &data, err_str, cmd_type);
720
721                 if (rc)
722                         return rc;
723         }
724
725         /* Add or delete any specified NIs associated with the specified
726          * (or implied) primary nid
727          */
728         for (nid_idx = 1; nid_idx < num_nids; nid_idx++) {
729                 LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
730                 data.prcfg_mr = is_mr;
731                 data.prcfg_prim_nid = nidlist[0];
732                 data.prcfg_cfg_nid = nidlist[nid_idx];
733                 data.prcfg_count = option;
734
735                 rc = dispatch_peer_ni_cmd(cmd, &data, err_str, cmd_type);
736
737                 if (rc)
738                         return rc;
739         }
740
741         if (cmd == IOC_LIBCFS_DEL_PEER_NI && num_nids == 1) {
742                 /* In the delete case we may have been given just the
743                  * primary nid of the peer. This tells us to delete the peer
744                  * completely (rather than just delete some of its NIs)
745                  */
746                 LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
747                 data.prcfg_prim_nid = nidlist[0];
748                 data.prcfg_cfg_nid = LNET_NID_ANY;
749                 data.prcfg_count = option;
750
751                 rc = dispatch_peer_ni_cmd(cmd, &data, err_str, cmd_type);
752         }
753
754         return rc;
755 }
756
757 static int
758 lustre_lnet_mod_peer_nidlist(lnet_nid_t pnid, lnet_nid_t *lnet_nidlist,
759                              int cmd, int num_nids, bool is_mr, int option,
760                              int seq_no, struct cYAML **err_rc)
761 {
762         int rc = LUSTRE_CFG_RC_NO_ERR;
763         char err_str[LNET_MAX_STR_LEN];
764         lnet_nid_t *lnet_nidlist2 = NULL;
765         int ioc_cmd = (cmd == LNETCTL_ADD_CMD) ? IOC_LIBCFS_ADD_PEER_NI :
766                 IOC_LIBCFS_DEL_PEER_NI;
767         char *cmd_str = (cmd == LNETCTL_ADD_CMD) ? ADD_CMD : DEL_CMD;
768
769         num_nids++;
770         lnet_nidlist2 = calloc(sizeof(*lnet_nidlist2), num_nids);
771         if (!lnet_nidlist2) {
772                 snprintf(err_str, LNET_MAX_STR_LEN, "out of memory");
773                 rc = LUSTRE_CFG_RC_OUT_OF_MEM;
774                 goto out;
775         }
776         lnet_nidlist2[0] = pnid;
777         memcpy(&lnet_nidlist2[1], lnet_nidlist, sizeof(*lnet_nidlist) *
778                                                 (num_nids - 1));
779
780         rc = lustre_lnet_handle_peer_nidlist(lnet_nidlist2,
781                                              num_nids, is_mr, option,
782                                              ioc_cmd, cmd_str, err_str);
783 out:
784         if (lnet_nidlist2)
785                 free(lnet_nidlist2);
786
787         cYAML_build_error(rc, seq_no, cmd_str, "peer_ni", err_str, err_rc);
788         return rc;
789 }
790
791 static void
792 replace_sep(char *str, char sep, char newsep)
793 {
794         int bracket = 0;
795         int i;
796         if (!str)
797                 return;
798         for (i = 0; i < strlen(str); i++) {
799                 /* don't replace ',' within [] */
800                 if (str[i] == '[')
801                         bracket++;
802                 else if (str[i] == ']')
803                         bracket--;
804                 else if (str[i] == sep && bracket == 0)
805                         str[i] = newsep;
806         }
807 }
808
809 int lustre_lnet_modify_peer(char *prim_nid, char *nids, bool is_mr, int cmd,
810                             int option, int seq_no, struct cYAML **err_rc)
811 {
812         int num_nids, rc;
813         char err_str[LNET_MAX_STR_LEN] = "Error";
814         lnet_nid_t lnet_nidlist[LNET_MAX_NIDS_PER_PEER];
815         lnet_nid_t pnid = LNET_NID_ANY;
816
817         if (!prim_nid) {
818                 rc = LUSTRE_CFG_RC_BAD_PARAM;
819                 snprintf(err_str, LNET_MAX_STR_LEN,
820                          "--prim_nid must be specified");
821                 goto out;
822         }
823
824         pnid = libcfs_str2nid(prim_nid);
825         if (pnid == LNET_NID_ANY) {
826                 rc = LUSTRE_CFG_RC_BAD_PARAM;
827                 snprintf(err_str, LNET_MAX_STR_LEN,
828                         "badly formatted primary NID: %s", prim_nid);
829                 goto out;
830         }
831
832         num_nids = 0;
833         if (nids) {
834                 /*
835                 * if there is no primary nid we need to make the first nid in the
836                 * nids list the primary nid
837                 */
838                 replace_sep(nids, ',', ' ');
839                 rc = lustre_lnet_parse_nidstr(nids, lnet_nidlist,
840                                         LNET_MAX_NIDS_PER_PEER, err_str);
841                 if (rc < 0)
842                         goto out;
843
844                 num_nids = rc;
845         }
846
847         rc = lustre_lnet_mod_peer_nidlist(pnid, lnet_nidlist,
848                                           cmd, num_nids, is_mr,
849                                           option, -1, err_rc);
850
851 out:
852         if (rc != LUSTRE_CFG_RC_NO_ERR)
853                 cYAML_build_error(rc, -1, "peer",
854                                 cmd == LNETCTL_ADD_CMD ? "add" : "del",
855                                 err_str, err_rc);
856
857         return rc;
858 }
859
860 static int lustre_lnet_route_common(char *nw, char *nidstr, int hops, int prio,
861                                     int sen, int seq_no, struct cYAML **err_rc,
862                                     int cmd)
863 {
864         int rc, num_nids, idx;
865         __u32 rnet;
866         char err_str[LNET_MAX_STR_LEN] = "\"generic error\"";
867         struct lnet_ioctl_config_data data;
868         lnet_nid_t lnet_nidlist[LNET_MAX_NIDS_PER_PEER];
869
870         if (nw == NULL || nidstr == NULL) {
871                 snprintf(err_str, LNET_MAX_STR_LEN,
872                          "\"missing mandatory parameter:'%s'\"",
873                          (nw == NULL && nidstr == NULL) ? "network, gateway" :
874                          (nw == NULL) ? "network" : "gateway");
875                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
876                 goto out;
877         }
878
879         rnet = libcfs_str2net(nw);
880         if (rnet == LNET_NET_ANY) {
881                 snprintf(err_str, LNET_MAX_STR_LEN,
882                          "\"cannot parse remote net %s\"", nw);
883                 rc = LUSTRE_CFG_RC_BAD_PARAM;
884                 goto out;
885         }
886
887         replace_sep(nidstr, ',', ' ');
888         rc = lustre_lnet_parse_nidstr(nidstr, lnet_nidlist,
889                                       LNET_MAX_NIDS_PER_PEER, err_str);
890         if (rc < 0)
891                 goto out;
892
893         num_nids = rc;
894
895         for (idx = 0; idx < num_nids; idx++) {
896                 LIBCFS_IOC_INIT_V2(data, cfg_hdr);
897                 data.cfg_net = rnet;
898                 if (cmd == LNETCTL_ADD_CMD) {
899                         data.cfg_config_u.cfg_route.rtr_hop = hops;
900                         data.cfg_config_u.cfg_route.rtr_priority = prio;
901                         data.cfg_config_u.cfg_route.rtr_sensitivity = sen;
902                 }
903
904                 data.cfg_nid = lnet_nidlist[idx];
905
906                 if (cmd == LNETCTL_ADD_CMD)
907                         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_ROUTE,
908                                         &data);
909                 else
910                         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_ROUTE,
911                                         &data);
912
913                 if (rc != 0 && errno != EEXIST &&
914                         errno != EHOSTUNREACH) {
915                         rc = -errno;
916                         snprintf(err_str, LNET_MAX_STR_LEN,
917                                         "route operation failed: %s",
918                                         strerror(errno));
919                         goto out;
920                 } else if (errno == EEXIST) {
921                         /*
922                          * continue chugging along if one of the
923                          * routes already exists
924                          */
925                         rc = 0;
926                 }
927         }
928
929 out:
930         cYAML_build_error(rc, seq_no,
931                           cmd == LNETCTL_ADD_CMD ? ADD_CMD : DEL_CMD, "route",
932                           err_str, err_rc);
933
934         return rc;
935 }
936
937 int lustre_lnet_config_route(char *nw, char *nidstr, int hops, int prio,
938                              int sen, int seq_no, struct cYAML **err_rc)
939 {
940         int rc;
941         char err_str[LNET_MAX_STR_LEN] = "\"generic error\"";
942
943         if (hops == -1) {
944                 hops = LNET_UNDEFINED_HOPS;
945         } else if (hops < 1 || hops > 255) {
946                 snprintf(err_str, LNET_MAX_STR_LEN,
947                          "\"invalid hop count %d, must be between 1 and 255\"",
948                          hops);
949                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
950                 goto out;
951         }
952
953         if (prio == -1) {
954                 prio = 0;
955         } else if (prio < 0) {
956                 snprintf(err_str, LNET_MAX_STR_LEN,
957                          "\"invalid priority %d, must be greater than 0\"",
958                          prio);
959                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
960                 goto out;
961         }
962
963         if (sen == -1) {
964                 sen = 1;
965         } else if (sen < 1) {
966                 snprintf(err_str, LNET_MAX_STR_LEN,
967                          "\"invalid health sensitivity %d, must be 1 or greater\"",
968                          sen);
969                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
970                 goto out;
971         }
972
973         rc = lustre_lnet_route_common(nw, nidstr, hops, prio, sen, seq_no,
974                                       err_rc, LNETCTL_ADD_CMD);
975         return rc;
976 out:
977         cYAML_build_error(rc, seq_no, ADD_CMD, "route", err_str, err_rc);
978
979         return rc;
980 }
981
982 int lustre_lnet_del_route(char *nw, char *nidstr, int seq_no,
983                           struct cYAML **err_rc)
984 {
985         return lustre_lnet_route_common(nw, nidstr, 0, 0, 0, seq_no, err_rc,
986                                         LNETCTL_DEL_CMD);
987 }
988
989 int lustre_lnet_show_route(char *nw, char *gw, int hops, int prio, int detail,
990                            int seq_no, struct cYAML **show_rc,
991                            struct cYAML **err_rc, bool backup)
992 {
993         struct lnet_ioctl_config_data data;
994         lnet_nid_t gateway_nid;
995         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
996         int l_errno = 0;
997         __u32 net = LNET_NET_ANY;
998         int i;
999         struct cYAML *root = NULL, *route = NULL, *item = NULL;
1000         struct cYAML *first_seq = NULL;
1001         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
1002         bool exist = false;
1003
1004         if (nw != NULL) {
1005                 net = libcfs_str2net(nw);
1006                 if (net == LNET_NET_ANY) {
1007                         snprintf(err_str,
1008                                  sizeof(err_str),
1009                                  "\"cannot parse net '%s'\"", nw);
1010                         rc = LUSTRE_CFG_RC_BAD_PARAM;
1011                         goto out;
1012                 }
1013
1014         } else {
1015                 /* show all routes without filtering on net */
1016                 net = LNET_NET_ANY;
1017         }
1018
1019         if (gw != NULL) {
1020                 gateway_nid = libcfs_str2nid(gw);
1021                 if (gateway_nid == LNET_NID_ANY) {
1022                         snprintf(err_str,
1023                                  sizeof(err_str),
1024                                  "\"cannot parse gateway NID '%s'\"", gw);
1025                         rc = LUSTRE_CFG_RC_BAD_PARAM;
1026                         goto out;
1027                 }
1028         } else
1029                 /* show all routes with out filtering on gateway */
1030                 gateway_nid = LNET_NID_ANY;
1031
1032         if ((hops < 1 && hops != -1) || hops > 255) {
1033                 snprintf(err_str,
1034                          sizeof(err_str),
1035                          "\"invalid hop count %d, must be between 0 and 256\"",
1036                          hops);
1037                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1038                 goto out;
1039         }
1040
1041         /* create struct cYAML root object */
1042         root = cYAML_create_object(NULL, NULL);
1043         if (root == NULL)
1044                 goto out;
1045
1046         route = cYAML_create_seq(root, "route");
1047         if (route == NULL)
1048                 goto out;
1049
1050         for (i = 0;; i++) {
1051                 __u32 rt_alive;
1052                 __u32 rt_multi_hop;
1053
1054                 LIBCFS_IOC_INIT_V2(data, cfg_hdr);
1055                 data.cfg_count = i;
1056
1057                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_ROUTE, &data);
1058                 if (rc != 0) {
1059                         l_errno = errno;
1060                         break;
1061                 }
1062
1063                 /* filter on provided data */
1064                 if (net != LNET_NET_ANY &&
1065                     net != data.cfg_net)
1066                         continue;
1067
1068                 if (gateway_nid != LNET_NID_ANY &&
1069                     gateway_nid != data.cfg_nid)
1070                         continue;
1071
1072                 if (hops != -1 &&
1073                     hops != data.cfg_config_u.cfg_route.rtr_hop)
1074                         continue;
1075
1076                 if (prio != -1 &&
1077                     prio != data.cfg_config_u.cfg_route.rtr_priority)
1078                         continue;
1079
1080                 /* default rc to -1 incase we hit the goto */
1081                 rc = -1;
1082                 exist = true;
1083
1084                 item = cYAML_create_seq_item(route);
1085                 if (item == NULL)
1086                         goto out;
1087
1088                 if (first_seq == NULL)
1089                         first_seq = item;
1090
1091                 if (cYAML_create_string(item, "net",
1092                                         libcfs_net2str(data.cfg_net)) == NULL)
1093                         goto out;
1094
1095                 if (cYAML_create_string(item, "gateway",
1096                                         libcfs_nid2str(data.cfg_nid)) == NULL)
1097                         goto out;
1098
1099                 if (detail) {
1100                         if (cYAML_create_number(item, "hop",
1101                                                 (int) data.cfg_config_u.
1102                                                 cfg_route.rtr_hop) ==
1103                             NULL)
1104                                 goto out;
1105
1106                         if (cYAML_create_number(item, "priority",
1107                                                 data.cfg_config_u.
1108                                                 cfg_route.rtr_priority) == NULL)
1109                                 goto out;
1110
1111                         if (cYAML_create_number(item, "health_sensitivity",
1112                                                 data.cfg_config_u.
1113                                                 cfg_route.rtr_sensitivity) == NULL)
1114                                 goto out;
1115
1116                         rt_alive = data.cfg_config_u.cfg_route.rtr_flags &
1117                                         LNET_RT_ALIVE;
1118                         rt_multi_hop = data.cfg_config_u.cfg_route.rtr_flags &
1119                                         LNET_RT_MULTI_HOP;
1120
1121                         if (!backup &&
1122                             cYAML_create_string(item, "state",
1123                                                 rt_alive ?
1124                                                 "up" : "down") == NULL)
1125                                 goto out;
1126
1127                         if (!backup &&
1128                             cYAML_create_string(item, "type",
1129                                                 rt_multi_hop?
1130                                                 "multi-hop" : "single-hop") == NULL)
1131                                 goto out;
1132                 }
1133         }
1134
1135         /* print output iff show_rc is not provided */
1136         if (show_rc == NULL)
1137                 cYAML_print_tree(root);
1138
1139         if (l_errno != ENOENT) {
1140                 snprintf(err_str,
1141                          sizeof(err_str),
1142                          "\"cannot get routes: %s\"",
1143                          strerror(l_errno));
1144                 rc = -l_errno;
1145                 goto out;
1146         } else
1147                 rc = LUSTRE_CFG_RC_NO_ERR;
1148
1149         snprintf(err_str, sizeof(err_str), "\"success\"");
1150 out:
1151         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1152                 cYAML_free_tree(root);
1153         } else if (show_rc != NULL && *show_rc != NULL) {
1154                 struct cYAML *show_node;
1155                 /* find the route node, if one doesn't exist then
1156                  * insert one.  Otherwise add to the one there
1157                  */
1158                 show_node = cYAML_get_object_item(*show_rc, "route");
1159                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
1160                         cYAML_insert_child(show_node, first_seq);
1161                         free(route);
1162                         free(root);
1163                 } else if (show_node == NULL) {
1164                         cYAML_insert_sibling((*show_rc)->cy_child,
1165                                                 route);
1166                         free(root);
1167                 } else {
1168                         cYAML_free_tree(root);
1169                 }
1170         } else {
1171                 *show_rc = root;
1172         }
1173
1174         cYAML_build_error(rc, seq_no, SHOW_CMD, "route", err_str, err_rc);
1175
1176         return rc;
1177 }
1178
1179 static int socket_intf_query(int request, char *intf,
1180                              struct ifreq *ifr)
1181 {
1182         int rc = 0;
1183         int sockfd;
1184
1185         if (strlen(intf) >= IFNAMSIZ || ifr == NULL)
1186                 return LUSTRE_CFG_RC_BAD_PARAM;
1187
1188         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1189         if (sockfd < 0)
1190                 return LUSTRE_CFG_RC_BAD_PARAM;
1191
1192         strcpy(ifr->ifr_name, intf);
1193         rc = ioctl(sockfd, request, ifr);
1194         if (rc != 0)
1195                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1196
1197         close(sockfd);
1198
1199         return rc;
1200 }
1201
1202 static int lustre_lnet_queryip(struct lnet_dlc_intf_descr *intf, __u32 *ip)
1203 {
1204         struct ifreq ifr;
1205         int rc;
1206
1207         memset(&ifr, 0, sizeof(ifr));
1208         rc = socket_intf_query(SIOCGIFFLAGS, intf->intf_name, &ifr);
1209         if (rc != 0)
1210                 return LUSTRE_CFG_RC_BAD_PARAM;
1211
1212         if ((ifr.ifr_flags & IFF_UP) == 0)
1213                 return LUSTRE_CFG_RC_BAD_PARAM;
1214
1215         memset(&ifr, 0, sizeof(ifr));
1216         rc = socket_intf_query(SIOCGIFADDR, intf->intf_name, &ifr);
1217         if (rc != 0)
1218                 return LUSTRE_CFG_RC_BAD_PARAM;
1219
1220         *ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
1221         *ip = bswap_32(*ip);
1222
1223         return LUSTRE_CFG_RC_NO_ERR;
1224 }
1225
1226 static int lustre_lnet_kfi_intf2nid(struct lnet_dlc_intf_descr *intf,
1227                                     __u32 *nid_addr)
1228 {
1229         unsigned int nic_index;
1230         int rc;
1231         char *nic_addr_path;
1232         char val[128];
1233         int size;
1234         long int addr;
1235
1236         rc = sscanf(intf->intf_name, "cxi%u", &nic_index);
1237         if (rc != 1)
1238                 return LUSTRE_CFG_RC_NO_MATCH;
1239
1240         size = snprintf(NULL, 0, cxi_nic_addr_path, nic_index) + 1;
1241         nic_addr_path = malloc(size);
1242         if (!nic_addr_path)
1243                 return LUSTRE_CFG_RC_OUT_OF_MEM;
1244         sprintf(nic_addr_path, cxi_nic_addr_path, nic_index);
1245
1246         rc = read_sysfs_file(nic_addr_path, "nic_addr", val, 1, sizeof(val));
1247         free(nic_addr_path);
1248         if (rc)
1249                 return LUSTRE_CFG_RC_NO_MATCH;
1250
1251         addr = strtol(val, NULL, 16);
1252         if (addr == LONG_MIN || addr == LONG_MAX)
1253                 return LUSTRE_CFG_RC_NO_MATCH;
1254
1255         *nid_addr = addr;
1256
1257         return LUSTRE_CFG_RC_NO_ERR;
1258 }
1259
1260 /*
1261  * for each interface in the array of interfaces find the IP address of
1262  * that interface, create its nid and add it to an array of NIDs.
1263  * Stop if any of the interfaces is down
1264  */
1265 static int lustre_lnet_intf2nids(struct lnet_dlc_network_descr *nw,
1266                                  lnet_nid_t **nids, __u32 *nnids,
1267                                  char *err_str, size_t str_len)
1268 {
1269         int i = 0, count = 0, rc;
1270         struct lnet_dlc_intf_descr *intf;
1271         char val[LNET_MAX_STR_LEN];
1272         __u32 ip;
1273         __u32 nic_addr;
1274         int gni_num;
1275         char *endp;
1276         unsigned int num;
1277
1278
1279         if (nw == NULL || nids == NULL) {
1280                 snprintf(err_str, str_len,
1281                          "\"unexpected parameters to lustre_lnet_intf2nids()\"");
1282                 return LUSTRE_CFG_RC_BAD_PARAM;
1283         }
1284
1285         if (LNET_NETTYP(nw->nw_id) == GNILND) {
1286                 count = 1;
1287         } else {
1288                 list_for_each_entry(intf, &nw->nw_intflist, intf_on_network)
1289                         count++;
1290         }
1291
1292         *nids = calloc(count, sizeof(lnet_nid_t));
1293         if (*nids == NULL) {
1294                 snprintf(err_str, str_len,
1295                          "\"out of memory\"");
1296                 return LUSTRE_CFG_RC_OUT_OF_MEM;
1297         }
1298         /*
1299          * special case the GNI interface since it doesn't have an IP
1300          * address. The assumption is that there can only be one GNI
1301          * interface in the system. No interface name is provided.
1302          */
1303         if (LNET_NETTYP(nw->nw_id) == GNILND) {
1304                 rc = read_sysfs_file(gni_nid_path, "nid", val,
1305                                 1, sizeof(val));
1306                 if (rc) {
1307                         snprintf(err_str, str_len,
1308                                  "\"cannot read gni nid\"");
1309                         goto failed;
1310                 }
1311                 gni_num = atoi(val);
1312
1313                 (*nids)[i] = LNET_MKNID(nw->nw_id, gni_num);
1314
1315                 goto out;
1316         } else if (LNET_NETTYP(nw->nw_id) == KFILND) {
1317                 list_for_each_entry(intf, &nw->nw_intflist, intf_on_network) {
1318                         rc = lustre_lnet_kfi_intf2nid(intf, &nic_addr);
1319                         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1320                                 snprintf(err_str, str_len,
1321                                         "\"couldn't query kfi intf %s\"",
1322                                         intf->intf_name);
1323                                 err_str[str_len - 1] = '\0';
1324                                 goto failed;
1325                         }
1326
1327                         (*nids)[i] = LNET_MKNID(nw->nw_id, nic_addr);
1328                         i++;
1329                 }
1330                 goto out;
1331         }
1332
1333         /* look at the other interfaces */
1334         list_for_each_entry(intf, &nw->nw_intflist, intf_on_network) {
1335                 if (LNET_NETTYP(nw->nw_id) == PTL4LND) {
1336                         /* handle LNDs with numeric interface name */
1337                         num = strtoul(intf->intf_name, &endp, 0);
1338                         if (endp == intf->intf_name || *endp != '\0') {
1339                                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1340                                 snprintf(err_str, str_len,
1341                                          "\"couldn't query intf %s\"",
1342                                          intf->intf_name);
1343                                 goto failed;
1344                         }
1345                         (*nids)[i] = LNET_MKNID(nw->nw_id, num);
1346                         i++;
1347                 } else {
1348                         /* handle LNDs with ip interface name */
1349                         rc = lustre_lnet_queryip(intf, &ip);
1350                         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1351                                 snprintf(err_str, str_len,
1352                                          "\"couldn't query intf %s\"",
1353                                          intf->intf_name);
1354                                 goto failed;
1355                         }
1356                         (*nids)[i] = LNET_MKNID(nw->nw_id, ip);
1357                         i++;
1358                 }
1359         }
1360
1361 out:
1362         *nnids = count;
1363
1364         return 0;
1365
1366 failed:
1367         free(*nids);
1368         *nids = NULL;
1369         return rc;
1370 }
1371
1372 /*
1373  * called repeatedly until a match or no more ip range
1374  * What do you have?
1375  *      ip_range expression
1376  *      interface list with all the interface names.
1377  *      all the interfaces in the system.
1378  *
1379  *      try to match the ip_range expr to one of the interfaces' IPs in
1380  *      the system. If we hit a patch for an interface. Check if that
1381  *      interface name is in the list.
1382  *
1383  *      If there are more than one interface in the list, then make sure
1384  *      that the IPs for all of these interfaces match the ip ranges
1385  *      given.
1386  *
1387  *      for each interface in intf_list
1388  *              look up the intf name in ifa
1389  *              if not there then no match
1390  *              check ip obtained from ifa against a match to any of the
1391  *              ip_ranges given.
1392  *              If no match, then fail
1393  *
1394  *      The result is that all the interfaces have to match.
1395  */
1396 static int lustre_lnet_match_ip_to_intf(struct ifaddrs *ifa,
1397                                         struct list_head *intf_list,
1398                                         struct list_head *ip_ranges)
1399 {
1400         int rc;
1401         __u32 ip;
1402         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1403         struct ifaddrs *ifaddr = ifa;
1404         struct lustre_lnet_ip_range_descr *ip_range;
1405         int family;
1406
1407         /*
1408          * if there are no explicit interfaces, and no ip ranges, then
1409          * configure the first tcp interface we encounter.
1410          */
1411         if (list_empty(intf_list) && list_empty(ip_ranges)) {
1412                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1413                         if (ifaddr->ifa_addr == NULL)
1414                                 continue;
1415
1416                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
1417                                 continue;
1418
1419                         family = ifaddr->ifa_addr->sa_family;
1420                         if (family == AF_INET &&
1421                             strcmp(ifaddr->ifa_name, "lo") != 0) {
1422                                 rc = lustre_lnet_add_intf_descr
1423                                         (intf_list, ifaddr->ifa_name,
1424                                         strlen(ifaddr->ifa_name));
1425
1426                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
1427                                         return rc;
1428
1429                                 return LUSTRE_CFG_RC_MATCH;
1430                         }
1431                 }
1432                 return LUSTRE_CFG_RC_NO_MATCH;
1433         }
1434
1435         /*
1436          * First interface which matches an IP pattern will be used
1437          */
1438         if (list_empty(intf_list)) {
1439                 /*
1440                  * no interfaces provided in the rule, but an ip range is
1441                  * provided, so try and match an interface to the ip
1442                  * range.
1443                  */
1444                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1445                         if (ifaddr->ifa_addr == NULL)
1446                                 continue;
1447
1448                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
1449                                 continue;
1450
1451                         family = ifaddr->ifa_addr->sa_family;
1452                         if (family == AF_INET) {
1453                                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->
1454                                         sin_addr.s_addr;
1455
1456                                 list_for_each_entry(ip_range, ip_ranges,
1457                                                     ipr_entry) {
1458                                         rc = cfs_ip_addr_match(bswap_32(ip),
1459                                                         &ip_range->ipr_expr);
1460                                         if (!rc)
1461                                                 continue;
1462
1463                                         rc = lustre_lnet_add_intf_descr
1464                                           (intf_list, ifaddr->ifa_name,
1465                                            strlen(ifaddr->ifa_name));
1466
1467                                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1468                                                 return rc;
1469                                 }
1470                         }
1471                 }
1472
1473                 if (!list_empty(intf_list))
1474                         return LUSTRE_CFG_RC_MATCH;
1475
1476                 return LUSTRE_CFG_RC_NO_MATCH;
1477         }
1478
1479         /*
1480          * If an interface is explicitly specified the ip-range might or
1481          * might not be specified. if specified the interface needs to match the
1482          * ip-range. If no ip-range then the interfaces are
1483          * automatically matched if they are all up.
1484          * If > 1 interfaces all the interfaces must match for the NI to
1485          * be configured.
1486          */
1487         list_for_each_entry_safe(intf_descr, tmp, intf_list, intf_on_network) {
1488                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1489                         if (ifaddr->ifa_addr == NULL)
1490                                 continue;
1491
1492                         family = ifaddr->ifa_addr->sa_family;
1493                         if (family == AF_INET &&
1494                             strcmp(intf_descr->intf_name,
1495                                    ifaddr->ifa_name) == 0)
1496                                 break;
1497                 }
1498
1499                 if (ifaddr == NULL) {
1500                         list_del(&intf_descr->intf_on_network);
1501                         free_intf_descr(intf_descr);
1502                         continue;
1503                 }
1504
1505                 if ((ifaddr->ifa_flags & IFF_UP) == 0) {
1506                         list_del(&intf_descr->intf_on_network);
1507                         free_intf_descr(intf_descr);
1508                         continue;
1509                 }
1510
1511                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
1512
1513                 rc = 1;
1514                 list_for_each_entry(ip_range, ip_ranges, ipr_entry) {
1515                         rc = cfs_ip_addr_match(bswap_32(ip), &ip_range->ipr_expr);
1516                         if (rc)
1517                                 break;
1518                 }
1519
1520                 if (!rc) {
1521                         /* no match for this interface */
1522                         list_del(&intf_descr->intf_on_network);
1523                         free_intf_descr(intf_descr);
1524                 }
1525         }
1526
1527         return LUSTRE_CFG_RC_MATCH;
1528 }
1529
1530 static int lustre_lnet_resolve_ip2nets_rule(struct lustre_lnet_ip2nets *ip2nets,
1531                                             lnet_nid_t **nids, __u32 *nnids,
1532                                             char *err_str, size_t str_len)
1533 {
1534         struct ifaddrs *ifa;
1535         int rc = LUSTRE_CFG_RC_NO_ERR;
1536
1537         rc = getifaddrs(&ifa);
1538         if (rc < 0) {
1539                 snprintf(err_str, str_len,
1540                          "\"failed to get interface addresses: %d\"", -errno);
1541                 return -errno;
1542         }
1543
1544         rc = lustre_lnet_match_ip_to_intf(ifa,
1545                                           &ip2nets->ip2nets_net.nw_intflist,
1546                                           &ip2nets->ip2nets_ip_ranges);
1547         if (rc != LUSTRE_CFG_RC_MATCH) {
1548                 snprintf(err_str, str_len,
1549                          "\"couldn't match ip to existing interfaces\"");
1550                 freeifaddrs(ifa);
1551                 return rc;
1552         }
1553
1554         rc = lustre_lnet_intf2nids(&ip2nets->ip2nets_net, nids, nnids,
1555                                    err_str, str_len);
1556         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1557                 *nids = NULL;
1558                 *nnids = 0;
1559         }
1560
1561         freeifaddrs(ifa);
1562
1563         return rc;
1564 }
1565
1566 void lustre_lnet_free_list(struct nid_node *head)
1567 {
1568         struct nid_node *entry, *tmp;
1569
1570         nl_list_for_each_entry_safe(entry, tmp, &head->children, list) {
1571                 nl_list_del(&entry->list);
1572                 free(entry);
1573         }
1574 }
1575
1576 static int unroll_nid_range_scan(struct nid_node *list, const char *nid,
1577                                  char *tmp, char *tmp2, char *nidstr,
1578                                  const char **errmsg)
1579 {
1580         unsigned int first = 0, last = 0, off = 0, inc = 1;
1581         bool slash = false, hyphen = false;
1582         char num[INT_STRING_LEN] = "";
1583         char *range = tmp + 1;
1584         int base = 10;
1585         int rc;
1586
1587         if (!tmp && !tmp2) {
1588                 *errmsg = "Unable to parse nidlist: [] are missing";
1589                 return -ERANGE;
1590         }
1591
1592         if ((tmp && !tmp2) || (!tmp && tmp2)) {
1593                 *errmsg = "Unable to parse nidlist: incomplete bracket set";
1594                 return -EINVAL;
1595         }
1596
1597         if (range > tmp2) {
1598                 *errmsg = "Unable to parse nidlist: improper bracket ordering";
1599                 return -EINVAL;
1600         }
1601
1602         if (strchr(nid, ':'))
1603                 base = 16;
1604
1605         while (range < tmp2) {
1606                 if (isxdigit(*range)) {
1607                         if (off > INT_STRING_LEN)
1608                                 return -E2BIG;
1609                         num[off++] = *range++;
1610                 } else if (*range == ':') {
1611                         /* skip ':' for IPv6 and IB GUID */
1612                         range++;
1613                 } else if (*range == '-') {
1614                         range++;
1615                         if (!isxdigit(*range)) {
1616                                 *errmsg = "Unable to parse nidlist: range needs number after -";
1617                                 return -ERANGE;
1618                         }
1619
1620                         first = strtoul(num, NULL, base);
1621                         memset(num, 0, sizeof(num));
1622                         hyphen = true;
1623                         off = 0;
1624                 } else if (*range == '/') {
1625                         range++;
1626                         if (!isdigit(*range)) {
1627                                 *errmsg = "Unable to parse nidlist: range needs number after /";
1628                                 return -ERANGE;
1629                         }
1630
1631                         /* Don't lose last number. This should be the very last item */
1632                         if (strlen(num)) {
1633                                 last = strtoul(num, NULL, base);
1634                                 memset(num, 0, sizeof(num));
1635                                 slash = true;
1636                                 off = 0;
1637                         }
1638                 } else if (*range == ',') {
1639                         char *end = strchr(nidstr, ',');
1640                         int count = strlen(tmp2 + 1);
1641                         struct nid_node *item;
1642                         int len = tmp - nid;
1643
1644                         range++;
1645                         if (!isxdigit(*range)) {
1646                                 *errmsg = "Unable to parse nidlist: range needs number after ,";
1647                                 return -ERANGE;
1648                         }
1649
1650                         /* If hyphen is true then we have the foramt '[first - last],' format.
1651                          * The other format is just x, y, z, ... format.
1652                          */
1653                         if (hyphen) {
1654                                 if (slash)
1655                                         inc = strtoul(num, NULL, base);
1656                                 else
1657                                         last = strtoul(num, NULL, base);
1658
1659                                 if (first > last) {
1660                                         *errmsg = "Unable to parse nidlist: range is wrong order";
1661                                         return -ERANGE;
1662                                 }
1663
1664                                 while (last >= first) {
1665                                         char hdr[LNET_MAX_STR_LEN], *next;
1666
1667                                         snprintf(hdr, sizeof(hdr), "%.*s%d%.*s",
1668                                                  len, nid, first, count,
1669                                                  tmp2 + 1);
1670                                         next = strchr(hdr, '[');
1671                                         if (next && strchr(next, ']')) {
1672                                                 rc = unroll_nid_range_scan(list, hdr, next,
1673                                                                            strchr(next, ']'),
1674                                                                            nidstr, errmsg);
1675                                                 if (rc < 0)
1676                                                         return rc;
1677                                         } else {
1678                                                 item = calloc(1, sizeof(struct nid_node));
1679                                                 if (!item) {
1680                                                         *errmsg = "Unable to parse nidlist: allocation failed";
1681                                                         return -ENOMEM;
1682                                                 }
1683                                                 snprintf(item->nidstr, sizeof(item->nidstr),
1684                                                          "%s@%s", hdr, nidstr);
1685                                                 nl_init_list_head(&item->list);
1686                                                 nl_list_add_tail(&item->list, &list->children);
1687                                         }
1688                                         first += inc;
1689                                 }
1690                                 /* reset slash / hyphen handing */
1691                                 hyphen = false;
1692                                 slash = false;
1693                                 inc = 1;
1694                         } else {
1695                                 int end_len = end ? end - nidstr : strlen(nidstr);
1696
1697                                 item = calloc(1, sizeof(struct nid_node));
1698                                 if (!item) {
1699                                         *errmsg = "Unable to parse nidlist: allocation failed";
1700                                         return -ENOMEM;
1701                                 }
1702                                 snprintf(item->nidstr, sizeof(item->nidstr),
1703                                          "%.*s%s%.*s@%.*s", len, nid, num,
1704                                          count, tmp2 + 1, end_len, nidstr);
1705                                 nl_init_list_head(&item->list);
1706                                 nl_list_add_tail(&item->list, &list->children);
1707                         }
1708
1709                         memset(num, 0, sizeof(num));
1710                         off = 0;
1711                 } else {
1712                         *errmsg = "Unable to parse nidlist: invalid character in range";
1713                         return -EINVAL;
1714                 }
1715         }
1716
1717         if (strlen(num)) {
1718                 if (slash)
1719                         inc = strtoul(num, NULL, base);
1720                 else
1721                         last = strtoul(num, NULL, base);
1722                 memset(num, 0, sizeof(num));
1723         }
1724
1725         if (!hyphen)
1726                 first = last;
1727
1728         /* This is the last set of [ first - last ]. We reach this point because
1729          * the above loop reached the end of the range and no ',' was found so
1730          * the final set of number range wasn't processed. Do that handling here.
1731          */
1732         if (first || last) {
1733                 char *next = tmp2 + 1;
1734                 int len = strlen(nid);
1735
1736                 if (first > last) {
1737                         *errmsg = "Unable to parse nidlist: range is wrong order";
1738                         return -ERANGE;
1739                 }
1740
1741                 if (strchr(nid, '['))
1742                         len = strchr(nid, '[') - nid;
1743
1744                 tmp = strchr(tmp2, '[');
1745                 if (tmp)
1746                         tmp2 = strchr(tmp, ']');
1747
1748                 while (last >= first) {
1749                         char str[LNET_MAX_STR_LEN];
1750
1751                         snprintf(str, sizeof(str), "%.*s%u%.*s",
1752                                  len, nid, first, (int)(tmp - next), next);
1753                         if (tmp && tmp2) {
1754                                 rc = unroll_nid_range_scan(list, str, tmp, tmp2,
1755                                                            nidstr, errmsg);
1756                                 if (rc < 0)
1757                                         return rc;
1758                         } else {
1759                                 char *end = strchr(nidstr, ',');
1760                                 int count = end ? end - nidstr : strlen(nidstr);
1761                                 struct nid_node *item;
1762
1763                                 item = calloc(1, sizeof(struct nid_node));
1764                                 if (!item) {
1765                                         *errmsg = "Unable to parse nidlist: allocation failed";
1766                                         return -ENOMEM;
1767                                 }
1768                                 snprintf(item->nidstr, sizeof(item->nidstr),
1769                                          "%s@%.*s", str, count, nidstr);
1770                                 nl_init_list_head(&item->list);
1771                                 nl_list_add_tail(&item->list, &list->children);
1772                         }
1773                         first += inc;
1774                 }
1775         }
1776
1777         return 0;
1778 }
1779
1780 int lustre_lnet_parse_nid_range(struct nid_node *head, char *nidstr,
1781                                 const char **errmsg)
1782 {
1783         int rc = 0;
1784         char *nid;
1785
1786         if (!nidstr) {
1787                 *errmsg = "supplied nidstr is NULL";
1788                 return -EINVAL;
1789         }
1790
1791         if (strchr(nidstr, '*')) {
1792                 *errmsg = "asterisk not allowed in nidstring";
1793                 return -EINVAL;
1794         }
1795
1796         if (strstr(nidstr, "<?>")) {
1797                 *errmsg = "Unable to parse nidlist: LNET_ANY_NID is unsupported";
1798                 return -EINVAL;
1799         }
1800
1801         if (strchr(nidstr, '@') == NULL) {
1802                 *errmsg = "Unable to parse nidlist: no valid NIDs in string";
1803                 return -EINVAL;
1804         }
1805
1806         while ((nid = strsep(&nidstr, "@")) != NULL) {
1807                 char *tmp = NULL, *tmp2 = NULL, *end = NULL;
1808
1809                 tmp = strchr(nid, '[');
1810                 tmp2 = strchr(nid, ']');
1811
1812                 if (!tmp && !tmp2) {
1813                         char *end = strchr(nidstr, ',');
1814                         struct nid_node *item;
1815                         int count;
1816
1817                         item = calloc(1, sizeof(struct nid_node));
1818                         if (!item) {
1819                                 *errmsg = "Unable to parse nidlist: allocation failed";
1820                                 rc = -ENOMEM;
1821                                 goto err;
1822                         }
1823
1824                         count = end ? end - nidstr : strlen(nidstr);
1825                         snprintf(item->nidstr, sizeof(item->nidstr),
1826                                  "%s@%.*s", nid, count, nidstr);
1827                         nl_init_list_head(&item->list);
1828                         nl_list_add_tail(&item->list, &head->children);
1829                 } else {
1830                         rc = unroll_nid_range_scan(head, nid, tmp, tmp2,
1831                                                    nidstr, errmsg);
1832                         if (rc < 0)
1833                                 goto err;
1834                 }
1835
1836                 if (nidstr) {
1837                         end = strchr(nidstr, ',');
1838                         if (end)
1839                                 nidstr = end + 1;
1840                         else
1841                                 nidstr = NULL;
1842                 }
1843         }
1844 err:
1845         return rc;
1846 }
1847
1848 static int
1849 lustre_lnet_ioctl_config_ni(struct list_head *intf_list,
1850                             struct lnet_ioctl_config_lnd_tunables *tunables,
1851                             struct cfs_expr_list *global_cpts,
1852                             lnet_nid_t *nids, char *err_str)
1853 {
1854         char *data;
1855         struct lnet_ioctl_config_ni *conf;
1856         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1857         int rc = LUSTRE_CFG_RC_NO_ERR, i = 0;
1858         size_t len;
1859         int count;
1860         struct lnet_dlc_intf_descr *intf_descr;
1861         __u32 *cpt_array;
1862         struct cfs_expr_list *cpt_expr;
1863
1864         list_for_each_entry(intf_descr, intf_list,
1865                             intf_on_network) {
1866                 if (tunables != NULL)
1867                         len = sizeof(struct lnet_ioctl_config_ni) +
1868                               sizeof(struct lnet_ioctl_config_lnd_tunables);
1869                 else
1870                         len = sizeof(struct lnet_ioctl_config_ni);
1871
1872                 data = calloc(1, len);
1873                 if (!data)
1874                         return LUSTRE_CFG_RC_OUT_OF_MEM;
1875                 conf = (struct lnet_ioctl_config_ni*) data;
1876                 if (tunables != NULL)
1877                         tun = (struct lnet_ioctl_config_lnd_tunables*)
1878                                 conf->lic_bulk;
1879
1880                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
1881                 conf->lic_cfg_hdr.ioc_len = len;
1882                 conf->lic_nid = nids[i];
1883                 strncpy(conf->lic_ni_intf, intf_descr->intf_name,
1884                         LNET_MAX_STR_LEN);
1885
1886                 if (intf_descr->cpt_expr != NULL)
1887                         cpt_expr = intf_descr->cpt_expr;
1888                 else if (global_cpts != NULL)
1889                         cpt_expr = global_cpts;
1890                 else
1891                         cpt_expr = NULL;
1892
1893                 if (cpt_expr != NULL) {
1894                         count = cfs_expr_list_values(cpt_expr,
1895                                                      LNET_MAX_SHOW_NUM_CPT,
1896                                                      &cpt_array);
1897                         if (count > 0) {
1898                                 memcpy(conf->lic_cpts, cpt_array,
1899                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
1900                                 free(cpt_array);
1901                         } else {
1902                                 count = 0;
1903                         }
1904                 } else {
1905                         count = 0;
1906                 }
1907
1908                 conf->lic_ncpts = count;
1909
1910                 if (tunables != NULL)
1911                         memcpy(tun, tunables, sizeof(*tunables));
1912
1913                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
1914                 if (rc < 0) {
1915                         rc = -errno;
1916                         snprintf(err_str,
1917                                  LNET_MAX_STR_LEN,
1918                                  "\"cannot add network: %s\"", strerror(errno));
1919                         free(data);
1920                         return rc;
1921                 }
1922                 free(data);
1923                 i++;
1924         }
1925
1926         return LUSTRE_CFG_RC_NO_ERR;
1927 }
1928
1929 static int
1930 lustre_lnet_config_ip2nets(struct lustre_lnet_ip2nets *ip2nets,
1931                            struct lnet_ioctl_config_lnd_tunables *tunables,
1932                            struct cfs_expr_list *global_cpts,
1933                            int seq_no, struct cYAML **err_rc)
1934 {
1935         lnet_nid_t *nids = NULL;
1936         __u32 nnids = 0;
1937         int rc;
1938         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
1939
1940         if (!ip2nets) {
1941                 snprintf(err_str,
1942                          sizeof(err_str),
1943                          "\"incomplete ip2nets information\"");
1944                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1945                 goto out;
1946         }
1947
1948         /*
1949          * call below function to resolve the rules into a list of nids.
1950          * The memory is allocated in that function then freed here when
1951          * it's no longer needed.
1952          */
1953         rc = lustre_lnet_resolve_ip2nets_rule(ip2nets, &nids, &nnids, err_str,
1954                                               sizeof(err_str));
1955         if (rc != LUSTRE_CFG_RC_NO_ERR && rc != LUSTRE_CFG_RC_MATCH)
1956                 goto out;
1957
1958         if (list_empty(&ip2nets->ip2nets_net.nw_intflist)) {
1959                 snprintf(err_str, sizeof(err_str),
1960                          "\"no interfaces match ip2nets rules\"");
1961                 goto free_nids_out;
1962         }
1963
1964         rc = lustre_lnet_ioctl_config_ni(&ip2nets->ip2nets_net.nw_intflist,
1965                                          tunables, global_cpts, nids,
1966                                          err_str);
1967
1968 free_nids_out:
1969         free(nids);
1970
1971 out:
1972         cYAML_build_error(rc, seq_no, ADD_CMD, "ip2nets", err_str, err_rc);
1973         return rc;
1974 }
1975
1976 int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
1977                           struct cfs_expr_list *global_cpts,
1978                           char *ip2net,
1979                           struct lnet_ioctl_config_lnd_tunables *tunables,
1980                           int seq_no, struct cYAML **err_rc)
1981 {
1982         char *data = NULL;
1983         struct lnet_ioctl_config_ni *conf;
1984         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1985         char buf[LNET_MAX_STR_LEN];
1986         int rc = LUSTRE_CFG_RC_NO_ERR;
1987         char err_str[LNET_MAX_STR_LEN * 2] = "\"success\"";
1988         lnet_nid_t *nids = NULL;
1989         __u32 nnids = 0;
1990         size_t len;
1991         int count;
1992         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1993         __u32 *cpt_array;
1994
1995         if (ip2net == NULL && (nw_descr == NULL || nw_descr->nw_id == 0 ||
1996             (list_empty(&nw_descr->nw_intflist) &&
1997              LNET_NETTYP(nw_descr->nw_id) != GNILND))) {
1998                 snprintf(err_str,
1999                          sizeof(err_str),
2000                          "\"missing mandatory parameters in NI config: '%s'\"",
2001                          (nw_descr == NULL) ? "network , interface" :
2002                          (nw_descr->nw_id == 0) ? "network" : "interface");
2003                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
2004                 goto out;
2005         }
2006
2007         if (ip2net != NULL && strlen(ip2net) >= sizeof(buf)) {
2008                 snprintf(err_str,
2009                          sizeof(err_str),
2010                          "\"ip2net string too long %d\"",
2011                                 (int)strlen(ip2net));
2012                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
2013                 goto out;
2014         }
2015
2016         if (ip2net != NULL) {
2017                 if (tunables != NULL)
2018                         len = sizeof(struct lnet_ioctl_config_ni) +
2019                               sizeof(struct lnet_ioctl_config_lnd_tunables);
2020                 else
2021                         len = sizeof(struct lnet_ioctl_config_ni);
2022                 data = calloc(1, len);
2023                 if (!data) {
2024                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2025                         goto out;
2026                 }
2027                 conf = (struct lnet_ioctl_config_ni*) data;
2028                 if (tunables != NULL)
2029                         tun = (struct lnet_ioctl_config_lnd_tunables*)
2030                                 (data + sizeof(*conf));
2031
2032                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
2033                 conf->lic_cfg_hdr.ioc_len = len;
2034                 strncpy(conf->lic_legacy_ip2nets, ip2net,
2035                         LNET_MAX_STR_LEN);
2036
2037                 if (global_cpts != NULL) {
2038                         count = cfs_expr_list_values(global_cpts,
2039                                                      LNET_MAX_SHOW_NUM_CPT,
2040                                                      &cpt_array);
2041                         if (count > 0) {
2042                                 memcpy(conf->lic_cpts, cpt_array,
2043                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
2044                                 free(cpt_array);
2045                         } else {
2046                                 count = 0;
2047                         }
2048                 } else {
2049                         count = 0;
2050                 }
2051
2052                 conf->lic_ncpts = count;
2053
2054                 if (tunables != NULL)
2055                         memcpy(tun, tunables, sizeof(*tunables));
2056
2057                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
2058                 if (rc < 0) {
2059                         rc = -errno;
2060                         snprintf(err_str,
2061                                 sizeof(err_str),
2062                                 "\"cannot add network: %s\"", strerror(errno));
2063                         goto out;
2064                 }
2065
2066                 goto out;
2067         }
2068
2069         if (LNET_NETTYP(nw_descr->nw_id) == LOLND) {
2070                 rc = LUSTRE_CFG_RC_NO_ERR;
2071                 goto out;
2072         }
2073
2074         if (nw_descr->nw_id == LNET_NET_ANY) {
2075                 snprintf(err_str,
2076                         sizeof(err_str),
2077                         "\"cannot parse net '%s'\"",
2078                         libcfs_net2str(nw_descr->nw_id));
2079                 rc = LUSTRE_CFG_RC_BAD_PARAM;
2080                 goto out;
2081         }
2082
2083         /*
2084          * special case the GNI since no interface name is expected
2085          */
2086         if (list_empty(&nw_descr->nw_intflist) &&
2087             (LNET_NETTYP(nw_descr->nw_id) != GNILND)) {
2088                 snprintf(err_str,
2089                         sizeof(err_str),
2090                         "\"no interface name provided\"");
2091                 rc = LUSTRE_CFG_RC_BAD_PARAM;
2092                 goto out;
2093         }
2094
2095         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids,
2096                                    err_str, sizeof(err_str));
2097         if (rc != 0) {
2098                 rc = LUSTRE_CFG_RC_BAD_PARAM;
2099                 goto out;
2100         }
2101
2102         rc = lustre_lnet_ioctl_config_ni(&nw_descr->nw_intflist,
2103                                          tunables, global_cpts, nids,
2104                                          err_str);
2105
2106 out:
2107         if (nw_descr != NULL) {
2108                 list_for_each_entry_safe(intf_descr, tmp,
2109                                          &nw_descr->nw_intflist,
2110                                          intf_on_network) {
2111                         list_del(&intf_descr->intf_on_network);
2112                         free_intf_descr(intf_descr);
2113                 }
2114         }
2115
2116         cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
2117
2118         if (nids)
2119                 free(nids);
2120
2121         if (data)
2122                 free(data);
2123
2124         return rc;
2125 }
2126
2127 int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw_descr,
2128                        int seq_no, struct cYAML **err_rc)
2129 {
2130         struct lnet_ioctl_config_ni data;
2131         int rc = LUSTRE_CFG_RC_NO_ERR, i;
2132         char err_str[LNET_MAX_STR_LEN * 2] = "\"success\"";
2133         lnet_nid_t *nids = NULL;
2134         __u32 nnids = 0;
2135         struct lnet_dlc_intf_descr *intf_descr, *tmp;
2136
2137         if (nw_descr == NULL || nw_descr->nw_id == 0) {
2138                 snprintf(err_str,
2139                          sizeof(err_str),
2140                          "\"missing mandatory parameter in deleting NI: '%s'\"",
2141                          (nw_descr == NULL) ? "network , interface" :
2142                          (nw_descr->nw_id == 0) ? "network" : "interface");
2143                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
2144                 goto out;
2145         }
2146
2147         if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
2148                 return LUSTRE_CFG_RC_NO_ERR;
2149
2150         if (nw_descr->nw_id == LNET_NET_ANY) {
2151                 snprintf(err_str,
2152                          sizeof(err_str),
2153                          "\"cannot parse net '%s'\"",
2154                          libcfs_net2str(nw_descr->nw_id));
2155                 rc = LUSTRE_CFG_RC_BAD_PARAM;
2156                 goto out;
2157         }
2158
2159         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids,
2160                                    err_str, sizeof(err_str));
2161         if (rc != 0) {
2162                 rc = LUSTRE_CFG_RC_BAD_PARAM;
2163                 goto out;
2164         }
2165
2166         /*
2167          * no interfaces just the nw_id is specified
2168          */
2169         if (nnids == 0) {
2170                 nids = calloc(1, sizeof(*nids));
2171                 if (nids == NULL) {
2172                         snprintf(err_str, sizeof(err_str),
2173                                 "\"out of memory\"");
2174                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2175                         goto out;
2176                 }
2177                 nids[0] = LNET_MKNID(nw_descr->nw_id, 0);
2178                 nnids = 1;
2179         }
2180
2181         for (i = 0; i < nnids; i++) {
2182                 LIBCFS_IOC_INIT_V2(data, lic_cfg_hdr);
2183                 data.lic_nid = nids[i];
2184
2185                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_LOCAL_NI, &data);
2186                 if (rc < 0) {
2187                         rc = -errno;
2188                         snprintf(err_str,
2189                                 sizeof(err_str),
2190                                 "\"cannot del network: %s\"", strerror(errno));
2191                 }
2192         }
2193
2194         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
2195                                  intf_on_network) {
2196                 list_del(&intf_descr->intf_on_network);
2197                 free_intf_descr(intf_descr);
2198         }
2199
2200 out:
2201         cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
2202
2203         if (nids != NULL)
2204                 free(nids);
2205
2206         return rc;
2207 }
2208
2209 static int
2210 lustre_lnet_config_healthv(int value, bool all, lnet_nid_t nid,
2211                            enum lnet_health_type type, char *name,
2212                            int seq_no, struct cYAML **err_rc)
2213 {
2214         struct lnet_ioctl_reset_health_cfg data;
2215         int rc = LUSTRE_CFG_RC_NO_ERR;
2216         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2217
2218         LIBCFS_IOC_INIT_V2(data, rh_hdr);
2219         data.rh_type = type;
2220         data.rh_all = all;
2221         data.rh_value = value;
2222         data.rh_nid = nid;
2223
2224         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_SET_HEALHV, &data);
2225         if (rc != 0) {
2226                 rc = -errno;
2227                 snprintf(err_str,
2228                          sizeof(err_str), "Can not configure health value: %s",
2229                          strerror(errno));
2230         }
2231
2232         cYAML_build_error(rc, seq_no, ADD_CMD, name, err_str, err_rc);
2233
2234         return rc;
2235 }
2236
2237 static int
2238 lustre_lnet_config_peer(int state, lnet_nid_t nid, char *name,
2239                         int seq_no, struct cYAML **err_rc)
2240 {
2241         struct lnet_ioctl_peer_cfg data;
2242         int rc = LUSTRE_CFG_RC_NO_ERR;
2243         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2244
2245         LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
2246         data.prcfg_state = state;
2247         data.prcfg_prim_nid = nid;
2248         data.prcfg_cfg_nid = LNET_NID_ANY;
2249
2250         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_SET_PEER, &data);
2251         if (rc != 0) {
2252                 rc = -errno;
2253                 snprintf(err_str,
2254                          sizeof(err_str), "Can not set peer property: %s",
2255                          strerror(errno));
2256         }
2257
2258         cYAML_build_error(rc, seq_no, ADD_CMD, name, err_str, err_rc);
2259
2260         return rc;
2261 }
2262
2263 static int
2264 lustre_lnet_config_conns_per_peer(int value, bool all, lnet_nid_t nid,
2265                                   char *name, int seq_no,
2266                                   struct cYAML **err_rc)
2267 {
2268         struct lnet_ioctl_reset_conns_per_peer_cfg data;
2269         int rc = LUSTRE_CFG_RC_NO_ERR;
2270         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2271
2272         LIBCFS_IOC_INIT_V2(data, rcpp_hdr);
2273         data.rcpp_all = all;
2274         data.rcpp_value = value;
2275         data.rcpp_nid = nid;
2276
2277         if (value < 0 || value > 127) {
2278                 rc = LUSTRE_CFG_RC_BAD_PARAM;
2279                 snprintf(err_str, sizeof(err_str),
2280                          "\"Valid values are: 0-127\"");
2281         } else {
2282
2283                 rc = l_ioctl(LNET_DEV_ID,
2284                              IOC_LIBCFS_SET_CONNS_PER_PEER, &data);
2285                 if (rc != 0) {
2286                         rc = -errno;
2287                         snprintf(err_str,
2288                                  sizeof(err_str),
2289                                  "Can not configure conns_per_peer value: %s",
2290                                  strerror(errno));
2291                 }
2292         }
2293         cYAML_build_error(rc, seq_no, ADD_CMD, name, err_str, err_rc);
2294
2295         return rc;
2296 }
2297
2298 int lustre_lnet_config_ni_healthv(int value, bool all, char *ni_nid, int seq_no,
2299                                   struct cYAML **err_rc)
2300 {
2301         lnet_nid_t nid;
2302         if (ni_nid)
2303                 nid = libcfs_str2nid(ni_nid);
2304         else
2305                 nid = LNET_NID_ANY;
2306         return lustre_lnet_config_healthv(value, all, nid,
2307                                           LNET_HEALTH_TYPE_LOCAL_NI,
2308                                           "ni healthv", seq_no, err_rc);
2309 }
2310
2311 int lustre_lnet_config_peer_ni_healthv(int value, bool all, char *lpni_nid,
2312                                        int seq_no, struct cYAML **err_rc)
2313 {
2314         lnet_nid_t nid;
2315         if (lpni_nid)
2316                 nid = libcfs_str2nid(lpni_nid);
2317         else
2318                 nid = LNET_NID_ANY;
2319         return lustre_lnet_config_healthv(value, all, nid,
2320                                           LNET_HEALTH_TYPE_PEER_NI,
2321                                           "peer_ni healthv", seq_no, err_rc);
2322 }
2323
2324 int lustre_lnet_set_peer_state(int state, char *lpni_nid, int seq_no,
2325                                struct cYAML **err_rc)
2326 {
2327         lnet_nid_t nid;
2328
2329         if (lpni_nid)
2330                 nid = libcfs_str2nid(lpni_nid);
2331         else
2332                 nid = LNET_NID_ANY;
2333         return lustre_lnet_config_peer(state, nid, "peer state", seq_no,
2334                                        err_rc);
2335 }
2336
2337 int lustre_lnet_config_ni_conns_per_peer(int value, bool all, char *ni_nid,
2338                                          int seq_no, struct cYAML **err_rc)
2339 {
2340         lnet_nid_t nid;
2341
2342         if (ni_nid)
2343                 nid = libcfs_str2nid(ni_nid);
2344         else
2345                 nid = LNET_NID_ANY;
2346         return lustre_lnet_config_conns_per_peer(value, all, nid,
2347                                                  "ni conns_per_peer",
2348                                                  seq_no, err_rc);
2349 }
2350
2351 static bool
2352 add_msg_stats_to_yaml_blk(struct cYAML *yaml,
2353                           struct lnet_ioctl_comm_count *counts)
2354 {
2355         if (cYAML_create_number(yaml, "put",
2356                                 counts->ico_put_count)
2357                                         == NULL)
2358                 return false;
2359         if (cYAML_create_number(yaml, "get",
2360                                 counts->ico_get_count)
2361                                         == NULL)
2362                 return false;
2363         if (cYAML_create_number(yaml, "reply",
2364                                 counts->ico_reply_count)
2365                                         == NULL)
2366                 return false;
2367         if (cYAML_create_number(yaml, "ack",
2368                                 counts->ico_ack_count)
2369                                         == NULL)
2370                 return false;
2371         if (cYAML_create_number(yaml, "hello",
2372                                 counts->ico_hello_count)
2373                                         == NULL)
2374                 return false;
2375
2376         return true;
2377 }
2378
2379 static struct lnet_ioctl_comm_count *
2380 get_counts(struct lnet_ioctl_element_msg_stats *msg_stats, int idx)
2381 {
2382         if (idx == 0)
2383                 return &msg_stats->im_send_stats;
2384         if (idx == 1)
2385                 return &msg_stats->im_recv_stats;
2386         if (idx == 2)
2387                 return &msg_stats->im_drop_stats;
2388
2389         return NULL;
2390 }
2391
2392 static int
2393 create_local_udsp_info(struct lnet_ioctl_construct_udsp_info *udsp_info,
2394                        struct cYAML *net_node)
2395 {
2396         char tmp[LNET_MAX_STR_LEN];
2397         struct cYAML *udsp_net;
2398         bool created = false;
2399         struct cYAML *pref;
2400         int i;
2401
2402         /* add the UDSP info */
2403         udsp_net = cYAML_create_object(net_node, "udsp info");
2404         if (!udsp_net)
2405                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2406
2407         if (!cYAML_create_number(udsp_net, "net priority",
2408                                  (int) udsp_info->cud_net_priority))
2409                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2410
2411         if (!cYAML_create_number(udsp_net, "nid priority",
2412                                  (int)udsp_info->cud_nid_priority))
2413                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2414
2415         pref = udsp_net;
2416
2417         for (i = 0; i < LNET_MAX_SHOW_NUM_NID; i++) {
2418                 memset(tmp, 0, LNET_MAX_STR_LEN);
2419                 if (udsp_info->cud_pref_rtr_nid[i] == 0)
2420                         break;
2421                 if (!created) {
2422                         pref = cYAML_create_object(udsp_net,
2423                                         "Preferred gateway NIDs");
2424                         if (!pref)
2425                                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2426                         created = true;
2427                 }
2428                 snprintf(tmp, sizeof(tmp), "NID-%d", i);
2429                 if (!cYAML_create_string(pref, tmp,
2430                         libcfs_nid2str(udsp_info->cud_pref_rtr_nid[i])))
2431                         return LUSTRE_CFG_RC_OUT_OF_MEM;
2432         }
2433
2434         return LUSTRE_CFG_RC_NO_ERR;
2435 }
2436
2437 static int
2438 create_remote_udsp_info(struct lnet_ioctl_construct_udsp_info *udsp_info,
2439                         struct cYAML *nid_node)
2440 {
2441         char tmp[LNET_MAX_STR_LEN];
2442         struct cYAML *udsp_nid;
2443         bool created = false;
2444         struct cYAML *pref;
2445         int i;
2446
2447         /* add the UDSP info */
2448         udsp_nid = cYAML_create_object(nid_node, "udsp info");
2449         if (!udsp_nid)
2450                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2451
2452         if (!cYAML_create_number(udsp_nid, "net priority",
2453                                  (int) udsp_info->cud_net_priority))
2454                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2455
2456         if (!cYAML_create_number(udsp_nid, "nid priority",
2457                                  (int) udsp_info->cud_nid_priority))
2458                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2459
2460         pref = udsp_nid;
2461         for (i = 0; i < LNET_MAX_SHOW_NUM_NID; i++) {
2462                 memset(tmp, 0, LNET_MAX_STR_LEN);
2463                 if (udsp_info->cud_pref_rtr_nid[i] == 0)
2464                         break;
2465                 if (!created) {
2466                         pref = cYAML_create_object(udsp_nid,
2467                                         "Preferred gateway NIDs");
2468                         if (!pref)
2469                                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2470                         created = true;
2471                 }
2472                 snprintf(tmp, sizeof(tmp), "NID-%d", i);
2473                 if (!cYAML_create_string(pref, tmp,
2474                         libcfs_nid2str(udsp_info->cud_pref_rtr_nid[i])))
2475                         return LUSTRE_CFG_RC_OUT_OF_MEM;
2476         }
2477
2478         pref = udsp_nid;
2479         created = false;
2480         for (i = 0; i < LNET_MAX_SHOW_NUM_NID; i++) {
2481                 memset(tmp, 0, LNET_MAX_STR_LEN);
2482                 if (udsp_info->cud_pref_nid[i] == 0)
2483                         break;
2484                 if (!created) {
2485                         pref = cYAML_create_object(udsp_nid,
2486                                         "Preferred source NIDs");
2487                         if (!pref)
2488                                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2489                         created = true;
2490                 }
2491                 snprintf(tmp, sizeof(tmp), "NID-%d", i);
2492                 if (!cYAML_create_string(pref, tmp,
2493                         libcfs_nid2str(udsp_info->cud_pref_nid[i])))
2494                         return LUSTRE_CFG_RC_OUT_OF_MEM;
2495         }
2496
2497         return LUSTRE_CFG_RC_NO_ERR;
2498 }
2499
2500 int lustre_lnet_show_net(char *nw, int detail, int seq_no,
2501                          struct cYAML **show_rc, struct cYAML **err_rc,
2502                          bool backup)
2503 {
2504         char *buf;
2505         struct lnet_ioctl_config_ni *ni_data;
2506         struct lnet_ioctl_config_lnd_tunables *lnd;
2507         struct lnet_ioctl_element_stats *stats;
2508         struct lnet_ioctl_element_msg_stats msg_stats;
2509         struct lnet_ioctl_local_ni_hstats hstats;
2510         struct lnet_ioctl_construct_udsp_info udsp_info;
2511         __u32 net = LNET_NET_ANY;
2512         __u32 prev_net = LNET_NET_ANY;
2513         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
2514         int l_errno = 0;
2515         struct cYAML *root = NULL, *tunables = NULL,
2516                 *net_node = NULL, *interfaces = NULL,
2517                 *item = NULL, *first_seq = NULL,
2518                 *tmp = NULL, *statistics = NULL,
2519                 *yhstats = NULL;
2520         int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
2521         char str_buf[str_buf_len];
2522         char *pos;
2523         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
2524         bool exist = false, new_net = true;
2525         int net_num = 0;
2526         size_t buf_size = sizeof(*ni_data) + sizeof(*lnd) + sizeof(*stats);
2527
2528         buf = calloc(1, buf_size);
2529         if (buf == NULL)
2530                 goto out;
2531
2532         ni_data = (struct lnet_ioctl_config_ni *)buf;
2533
2534         if (nw != NULL) {
2535                 net = libcfs_str2net(nw);
2536                 if (net == LNET_NET_ANY) {
2537                         snprintf(err_str,
2538                                  sizeof(err_str),
2539                                  "\"cannot parse net '%s'\"", nw);
2540                         rc = LUSTRE_CFG_RC_BAD_PARAM;
2541                         goto out;
2542                 }
2543         }
2544
2545         root = cYAML_create_object(NULL, NULL);
2546         if (root == NULL)
2547                 goto out;
2548
2549         net_node = cYAML_create_seq(root, "net");
2550         if (net_node == NULL)
2551                 goto out;
2552
2553         for (i = 0;; i++) {
2554                 __u32 rc_net;
2555
2556                 memset(buf, 0, buf_size);
2557
2558                 LIBCFS_IOC_INIT_V2(*ni_data, lic_cfg_hdr);
2559                 /*
2560                  * set the ioc_len to the proper value since INIT assumes
2561                  * size of data
2562                  */
2563                 ni_data->lic_cfg_hdr.ioc_len = buf_size;
2564                 ni_data->lic_idx = i;
2565
2566                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LOCAL_NI, ni_data);
2567                 if (rc != 0) {
2568                         l_errno = errno;
2569                         break;
2570                 }
2571
2572                 rc_net = LNET_NIDNET(ni_data->lic_nid);
2573
2574                 /* filter on provided data */
2575                 if (net != LNET_NET_ANY &&
2576                     net != rc_net)
2577                         continue;
2578
2579                 /* if we're backing up don't store lo */
2580                 if (backup && LNET_NETTYP(rc_net) == LOLND)
2581                         continue;
2582
2583                 /* default rc to -1 in case we hit the goto */
2584                 rc = -1;
2585                 exist = true;
2586
2587                 stats = (struct lnet_ioctl_element_stats *)ni_data->lic_bulk;
2588                 lnd = (struct lnet_ioctl_config_lnd_tunables *)
2589                         (ni_data->lic_bulk + sizeof(*stats));
2590
2591                 if (rc_net != prev_net) {
2592                         prev_net = rc_net;
2593                         new_net = true;
2594                         net_num++;
2595                 }
2596
2597                 if (new_net) {
2598                         tmp = cYAML_create_string(net_node, "net type", libcfs_net2str(rc_net));
2599                         if (tmp == NULL)
2600                                 goto out;
2601
2602                         if (first_seq == NULL)
2603                                 first_seq = tmp;
2604
2605                         tmp = cYAML_create_seq(net_node, "local NI(s)");
2606                         if (tmp == NULL)
2607                                 goto out;
2608                         new_net = false;
2609                 }
2610
2611                 /* create the tree to be printed. */
2612                 item = cYAML_create_seq_item(tmp);
2613                 if (item == NULL)
2614                         goto out;
2615
2616                 if (!backup &&
2617                     cYAML_create_string(item, "nid",
2618                                         libcfs_nid2str(ni_data->lic_nid)) == NULL)
2619                         goto out;
2620
2621                 if (!backup &&
2622                     cYAML_create_string(item,
2623                                         "status",
2624                                         (ni_data->lic_status ==
2625                                           LNET_NI_STATUS_UP) ?
2626                                             "up" : "down") == NULL)
2627                         goto out;
2628
2629                 /* don't add interfaces unless there is at least one
2630                  * interface */
2631                 if (strlen(ni_data->lic_ni_intf) > 0) {
2632                         interfaces = cYAML_create_object(item, "interfaces");
2633                         if (interfaces == NULL)
2634                                 goto out;
2635
2636                         snprintf(str_buf, sizeof(str_buf), "%d", 0);
2637                         if (cYAML_create_string(interfaces, str_buf,
2638                                                 ni_data->lic_ni_intf) == NULL)
2639                                 goto out;
2640                 }
2641
2642                 if (detail) {
2643                         char *limit;
2644                         int k;
2645
2646                         if (backup)
2647                                 goto continue_without_msg_stats;
2648
2649                         statistics = cYAML_create_object(item, "statistics");
2650                         if (statistics == NULL)
2651                                 goto out;
2652
2653                         if (cYAML_create_number(statistics, "send_count",
2654                                                 stats->iel_send_count)
2655                                                         == NULL)
2656                                 goto out;
2657
2658                         if (cYAML_create_number(statistics, "recv_count",
2659                                                 stats->iel_recv_count)
2660                                                         == NULL)
2661                                 goto out;
2662
2663                         if (cYAML_create_number(statistics, "drop_count",
2664                                                 stats->iel_drop_count)
2665                                                         == NULL)
2666                                 goto out;
2667
2668                         if (detail < 4)
2669                                 goto continue_without_udsp_info;
2670
2671                         LIBCFS_IOC_INIT_V2(udsp_info, cud_hdr);
2672                         udsp_info.cud_nid = ni_data->lic_nid;
2673                         udsp_info.cud_peer = false;
2674                         rc = l_ioctl(LNET_DEV_ID,
2675                                      IOC_LIBCFS_GET_CONST_UDSP_INFO,
2676                                      &udsp_info);
2677                         if (rc != 0) {
2678                                 l_errno = errno;
2679                                 goto continue_without_udsp_info;
2680                         }
2681
2682                         rc = create_local_udsp_info(&udsp_info, item);
2683                         if (rc) {
2684                                 l_errno = errno;
2685                                 goto out;
2686                         }
2687
2688 continue_without_udsp_info:
2689                         if (detail < 2)
2690                                 goto continue_without_msg_stats;
2691
2692                         LIBCFS_IOC_INIT_V2(msg_stats, im_hdr);
2693                         msg_stats.im_hdr.ioc_len = sizeof(msg_stats);
2694                         msg_stats.im_idx = i;
2695
2696                         rc = l_ioctl(LNET_DEV_ID,
2697                                      IOC_LIBCFS_GET_LOCAL_NI_MSG_STATS,
2698                                      &msg_stats);
2699                         if (rc != 0) {
2700                                 l_errno = errno;
2701                                 goto continue_without_msg_stats;
2702                         }
2703
2704                         for (k = 0; k < 3; k++) {
2705                                 struct lnet_ioctl_comm_count *counts;
2706                                 struct cYAML *msg_statistics = NULL;
2707
2708                                 msg_statistics = cYAML_create_object(item,
2709                                                  (char *)gmsg_stat_names[k]);
2710                                 if (msg_statistics == NULL)
2711                                         goto out;
2712
2713                                 counts = get_counts(&msg_stats, k);
2714                                 if (counts == NULL)
2715                                         goto out;
2716
2717                                 if (!add_msg_stats_to_yaml_blk(msg_statistics,
2718                                                                counts))
2719                                         goto out;
2720                         }
2721
2722                         LIBCFS_IOC_INIT_V2(hstats, hlni_hdr);
2723                         hstats.hlni_nid = ni_data->lic_nid;
2724                         /* grab health stats */
2725                         rc = l_ioctl(LNET_DEV_ID,
2726                                      IOC_LIBCFS_GET_LOCAL_HSTATS,
2727                                      &hstats);
2728                         if (rc != 0) {
2729                                 l_errno = errno;
2730                                 goto continue_without_msg_stats;
2731                         }
2732                         yhstats = cYAML_create_object(item, "health stats");
2733                         if (!yhstats)
2734                                 goto out;
2735                         if (cYAML_create_number(yhstats, "fatal_error",
2736                                                 hstats.hlni_fatal_error)
2737                                                         == NULL)
2738                                 goto out;
2739                         if (cYAML_create_number(yhstats, "health value",
2740                                                 hstats.hlni_health_value)
2741                                                         == NULL)
2742                                 goto out;
2743                         if (cYAML_create_number(yhstats, "interrupts",
2744                                                 hstats.hlni_local_interrupt)
2745                                                         == NULL)
2746                                 goto out;
2747                         if (cYAML_create_number(yhstats, "dropped",
2748                                                 hstats.hlni_local_dropped)
2749                                                         == NULL)
2750                                 goto out;
2751                         if (cYAML_create_number(yhstats, "aborted",
2752                                                 hstats.hlni_local_aborted)
2753                                                         == NULL)
2754                                 goto out;
2755                         if (cYAML_create_number(yhstats, "no route",
2756                                                 hstats.hlni_local_no_route)
2757                                                         == NULL)
2758                                 goto out;
2759                         if (cYAML_create_number(yhstats, "timeouts",
2760                                                 hstats.hlni_local_timeout)
2761                                                         == NULL)
2762                                 goto out;
2763                         if (cYAML_create_number(yhstats, "error",
2764                                                 hstats.hlni_local_error)
2765                                                         == NULL)
2766                                 goto out;
2767                         if (cYAML_create_number(yhstats, "ping_count",
2768                                                 hstats.hlni_ping_count)
2769                                                         == NULL)
2770                                 goto out;
2771                         if (cYAML_create_number(yhstats, "next_ping",
2772                                                 hstats.hlni_next_ping)
2773                                                         == NULL)
2774                                 goto out;
2775
2776 continue_without_msg_stats:
2777                         tunables = cYAML_create_object(item, "tunables");
2778                         if (!tunables)
2779                                 goto out;
2780
2781                         rc = lustre_net_show_tunables(tunables, &lnd->lt_cmn);
2782                         if (rc != LUSTRE_CFG_RC_NO_ERR)
2783                                 goto out;
2784
2785                         if (rc != LUSTRE_CFG_RC_NO_MATCH) {
2786                                 tunables = cYAML_create_object(item,
2787                                                                "lnd tunables");
2788                                 if (tunables == NULL)
2789                                         goto out;
2790                         }
2791
2792                         rc = lustre_ni_show_tunables(tunables,
2793                                                      LNET_NETTYP(rc_net),
2794                                                      &lnd->lt_tun, backup);
2795                         if (rc != LUSTRE_CFG_RC_NO_ERR &&
2796                             rc != LUSTRE_CFG_RC_NO_MATCH)
2797                                 goto out;
2798
2799                         if (!backup &&
2800                             cYAML_create_number(item, "dev cpt",
2801                                                 ni_data->lic_dev_cpt) == NULL)
2802                                 goto out;
2803
2804                         /* out put the CPTs in the format: "[x,x,x,...]" */
2805                         pos = str_buf;
2806                         limit = str_buf + str_buf_len - 3;
2807                         pos += scnprintf(pos, limit - pos, "\"[");
2808                         for (j = 0 ; ni_data->lic_ncpts >= 1 &&
2809                                 j < ni_data->lic_ncpts &&
2810                                 pos < limit; j++) {
2811                                 pos += scnprintf(pos, limit - pos,
2812                                                  "%d", ni_data->lic_cpts[j]);
2813                                 if ((j + 1) < ni_data->lic_ncpts)
2814                                         pos += scnprintf(pos, limit - pos, ",");
2815                         }
2816                         snprintf(pos, 3, "]\"");
2817
2818                         if (ni_data->lic_ncpts >= 1 &&
2819                             cYAML_create_string(item, "CPT",
2820                                                 str_buf) == NULL)
2821                                 goto out;
2822                 }
2823         }
2824
2825         /* Print out the net information only if show_rc is not provided */
2826         if (show_rc == NULL)
2827                 cYAML_print_tree(root);
2828
2829         if (l_errno != ENOENT) {
2830                 snprintf(err_str,
2831                          sizeof(err_str),
2832                          "\"cannot get networks: %s\"",
2833                          strerror(l_errno));
2834                 rc = -l_errno;
2835                 goto out;
2836         } else
2837                 rc = LUSTRE_CFG_RC_NO_ERR;
2838
2839         snprintf(err_str, sizeof(err_str), "\"success\"");
2840 out:
2841         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
2842                 cYAML_free_tree(root);
2843         } else if (show_rc != NULL && *show_rc != NULL) {
2844                 struct cYAML *show_node;
2845                 /* find the net node, if one doesn't exist
2846                  * then insert one.  Otherwise add to the one there
2847                  */
2848                 show_node = cYAML_get_object_item(*show_rc, "net");
2849                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
2850                         cYAML_insert_child(show_node, first_seq);
2851                         free(net_node);
2852                         free(root);
2853                 } else if (show_node == NULL) {
2854                         cYAML_insert_sibling((*show_rc)->cy_child,
2855                                                 net_node);
2856                         free(root);
2857                 } else {
2858                         cYAML_free_tree(root);
2859                 }
2860         } else {
2861                 *show_rc = root;
2862         }
2863
2864         cYAML_build_error(rc, seq_no, SHOW_CMD, "net", err_str, err_rc);
2865
2866         return rc;
2867 }
2868
2869 int lustre_lnet_enable_routing(int enable, int seq_no, struct cYAML **err_rc)
2870 {
2871         struct lnet_ioctl_config_data data;
2872         int rc = LUSTRE_CFG_RC_NO_ERR;
2873         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2874
2875         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
2876         data.cfg_config_u.cfg_buffers.buf_enable = (enable) ? 1 : 0;
2877
2878         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CONFIG_RTR, &data);
2879         if (rc != 0) {
2880                 rc = -errno;
2881                 snprintf(err_str,
2882                          sizeof(err_str),
2883                          "\"cannot %s routing %s\"",
2884                          (enable) ? "enable" : "disable", strerror(errno));
2885                 goto out;
2886         }
2887
2888 out:
2889         cYAML_build_error(rc, seq_no,
2890                          (enable) ? ADD_CMD : DEL_CMD,
2891                          "routing", err_str, err_rc);
2892
2893         return rc;
2894 }
2895
2896 static int ioctl_set_value(__u32 val, int ioc, char *name,
2897                            int seq_no, struct cYAML **err_rc)
2898 {
2899         struct lnet_ioctl_set_value data;
2900         int rc = LUSTRE_CFG_RC_NO_ERR;
2901         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2902
2903         LIBCFS_IOC_INIT_V2(data, sv_hdr);
2904         data.sv_value = val;
2905
2906         rc = l_ioctl(LNET_DEV_ID, ioc , &data);
2907         if (rc != 0) {
2908                 rc = -errno;
2909                 snprintf(err_str,
2910                          sizeof(err_str),
2911                          "\"cannot configure %s to %d: %s\"", name,
2912                          val, strerror(errno));
2913         }
2914
2915         cYAML_build_error(rc, seq_no, ADD_CMD, name, err_str, err_rc);
2916
2917         return rc;
2918 }
2919
2920 int lustre_lnet_config_recov_intrv(int intrv, int seq_no, struct cYAML **err_rc)
2921 {
2922         int rc = LUSTRE_CFG_RC_NO_ERR;
2923         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2924         char val[LNET_MAX_STR_LEN];
2925
2926         snprintf(val, sizeof(val), "%d", intrv);
2927
2928         rc = write_sysfs_file(modparam_path, "lnet_recovery_interval", val,
2929                               1, strlen(val) + 1);
2930         if (rc)
2931                 snprintf(err_str, sizeof(err_str),
2932                          "\"cannot configure recovery interval: %s\"",
2933                          strerror(errno));
2934
2935         cYAML_build_error(rc, seq_no, ADD_CMD, "recovery_interval", err_str, err_rc);
2936
2937         return rc;
2938 }
2939
2940 int lustre_lnet_config_rtr_sensitivity(int sen, int seq_no, struct cYAML **err_rc)
2941 {
2942         int rc = LUSTRE_CFG_RC_NO_ERR;
2943         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2944         char val[LNET_MAX_STR_LEN];
2945
2946         snprintf(val, sizeof(val), "%d", sen);
2947
2948         rc = write_sysfs_file(modparam_path, "router_sensitivity_percentage", val,
2949                               1, strlen(val) + 1);
2950         if (rc)
2951                 snprintf(err_str, sizeof(err_str),
2952                          "\"cannot configure router health sensitivity: %s\"",
2953                          strerror(errno));
2954
2955         cYAML_build_error(rc, seq_no, ADD_CMD, "router_sensitivity", err_str, err_rc);
2956
2957         return rc;
2958 }
2959
2960 int lustre_lnet_config_hsensitivity(int sen, int seq_no, struct cYAML **err_rc)
2961 {
2962         int rc = LUSTRE_CFG_RC_NO_ERR;
2963         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2964         char val[LNET_MAX_STR_LEN];
2965
2966         snprintf(val, sizeof(val), "%d", sen);
2967
2968         rc = write_sysfs_file(modparam_path, "lnet_health_sensitivity", val,
2969                               1, strlen(val) + 1);
2970         if (rc)
2971                 snprintf(err_str, sizeof(err_str),
2972                          "\"cannot configure health sensitivity: %s\"",
2973                          strerror(errno));
2974
2975         cYAML_build_error(rc, seq_no, ADD_CMD, "health_sensitivity", err_str, err_rc);
2976
2977         return rc;
2978 }
2979
2980 int lustre_lnet_config_transaction_to(int timeout, int seq_no, struct cYAML **err_rc)
2981 {
2982         int rc = LUSTRE_CFG_RC_NO_ERR;
2983         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
2984         char val[LNET_MAX_STR_LEN];
2985
2986         snprintf(val, sizeof(val), "%d", timeout);
2987
2988         rc = write_sysfs_file(modparam_path, "lnet_transaction_timeout", val,
2989                               1, strlen(val) + 1);
2990         if (rc)
2991                 snprintf(err_str, sizeof(err_str),
2992                          "\"cannot configure transaction timeout: %s\"",
2993                          strerror(errno));
2994
2995         cYAML_build_error(rc, seq_no, ADD_CMD, "transaction_timeout", err_str, err_rc);
2996
2997         return rc;
2998 }
2999
3000 int lustre_lnet_config_retry_count(int count, int seq_no, struct cYAML **err_rc)
3001 {
3002         int rc = LUSTRE_CFG_RC_NO_ERR;
3003         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
3004         char val[LNET_MAX_STR_LEN];
3005
3006         snprintf(val, sizeof(val), "%d", count);
3007
3008         rc = write_sysfs_file(modparam_path, "lnet_retry_count", val,
3009                               1, strlen(val) + 1);
3010         if (rc)
3011                 snprintf(err_str, sizeof(err_str),
3012                          "\"cannot configure retry count: %s\"",
3013                          strerror(errno));
3014
3015         cYAML_build_error(rc, seq_no, ADD_CMD, "retry_count", err_str, err_rc);
3016
3017         return rc;
3018 }
3019
3020 int lustre_lnet_config_response_tracking(int val, int seq_no,
3021                                          struct cYAML **err_rc)
3022 {
3023         int rc = LUSTRE_CFG_RC_NO_ERR;
3024         char err_str[LNET_MAX_STR_LEN];
3025         char val_str[LNET_MAX_STR_LEN];
3026
3027         if (val < 0 || val > 3) {
3028                 rc = LUSTRE_CFG_RC_BAD_PARAM;
3029                 snprintf(err_str, sizeof(err_str),
3030                          "\"Valid values are: 0, 1, 2, or 3\"");
3031         } else {
3032                 snprintf(err_str, sizeof(err_str), "\"success\"");
3033
3034                 snprintf(val_str, sizeof(val_str), "%d", val);
3035
3036                 rc = write_sysfs_file(modparam_path, "lnet_response_tracking",
3037                                       val_str, 1, strlen(val_str) + 1);
3038                 if (rc)
3039                         snprintf(err_str, sizeof(err_str),
3040                                  "\"cannot configure response tracking: %s\"",
3041                                  strerror(errno));
3042         }
3043
3044         cYAML_build_error(rc, seq_no, ADD_CMD, "response_tracking", err_str,
3045                           err_rc);
3046
3047         return rc;
3048 }
3049
3050 int lustre_lnet_config_recovery_limit(int val, int seq_no,
3051                                       struct cYAML **err_rc)
3052 {
3053         int rc = LUSTRE_CFG_RC_NO_ERR;
3054         char err_str[LNET_MAX_STR_LEN];
3055         char val_str[LNET_MAX_STR_LEN];
3056
3057         if (val < 0) {
3058                 rc = LUSTRE_CFG_RC_BAD_PARAM;
3059                 snprintf(err_str, sizeof(err_str),
3060                          "\"Must be greater than or equal to 0\"");
3061         } else {
3062                 snprintf(err_str, sizeof(err_str), "\"success\"");
3063
3064                 snprintf(val_str, sizeof(val_str), "%d", val);
3065
3066                 rc = write_sysfs_file(modparam_path, "lnet_recovery_limit",
3067                                       val_str, 1, strlen(val_str) + 1);
3068                 if (rc)
3069                         snprintf(err_str, sizeof(err_str),
3070                                  "\"cannot configure recovery limit: %s\"",
3071                                  strerror(errno));
3072         }
3073
3074         cYAML_build_error(rc, seq_no, ADD_CMD, "recovery_limit", err_str,
3075                           err_rc);
3076
3077         return rc;
3078 }
3079
3080 int lustre_lnet_config_max_intf(int max, int seq_no, struct cYAML **err_rc)
3081 {
3082         int rc = LUSTRE_CFG_RC_NO_ERR;
3083         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
3084         char val[LNET_MAX_STR_LEN];
3085
3086         snprintf(val, sizeof(val), "%d", max);
3087
3088         rc = write_sysfs_file(modparam_path, "lnet_interfaces_max", val,
3089                               1, strlen(val) + 1);
3090         if (rc)
3091                 snprintf(err_str, sizeof(err_str),
3092                          "\"cannot configure max interfaces: %s\"",
3093                          strerror(errno));
3094
3095         cYAML_build_error(rc, seq_no, ADD_CMD, "max_interfaces", err_str, err_rc);
3096
3097         return rc;
3098 }
3099
3100 int lustre_lnet_config_discovery(int enable, int seq_no, struct cYAML **err_rc)
3101 {
3102         int rc = LUSTRE_CFG_RC_NO_ERR;
3103         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
3104         char val[LNET_MAX_STR_LEN];
3105
3106         snprintf(val, sizeof(val), "%u", (enable) ? 0 : 1);
3107
3108         rc = write_sysfs_file(modparam_path, "lnet_peer_discovery_disabled", val,
3109                               1, strlen(val) + 1);
3110         if (rc)
3111                 snprintf(err_str, sizeof(err_str),
3112                          "\"cannot configure discovery: %s\"",
3113                          strerror(errno));
3114
3115         cYAML_build_error(rc, seq_no, ADD_CMD, "discovery", err_str, err_rc);
3116
3117         return rc;
3118
3119 }
3120
3121 int lustre_lnet_config_drop_asym_route(int drop, int seq_no,
3122                                        struct cYAML **err_rc)
3123 {
3124         int rc = LUSTRE_CFG_RC_NO_ERR;
3125         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
3126         char val[LNET_MAX_STR_LEN];
3127
3128         snprintf(val, sizeof(val), "%u", (drop) ? 1 : 0);
3129
3130         rc = write_sysfs_file(modparam_path, "lnet_drop_asym_route", val,
3131                               1, strlen(val) + 1);
3132         if (rc)
3133                 snprintf(err_str, sizeof(err_str),
3134                          "\"cannot configure drop asym route: %s\"",
3135                          strerror(errno));
3136
3137         cYAML_build_error(rc, seq_no, ADD_CMD, "drop_asym_route",
3138                           err_str, err_rc);
3139
3140         return rc;
3141
3142 }
3143
3144 int lustre_lnet_config_numa_range(int range, int seq_no, struct cYAML **err_rc)
3145 {
3146         return ioctl_set_value(range, IOC_LIBCFS_SET_NUMA_RANGE,
3147                                "numa_range", seq_no, err_rc);
3148 }
3149
3150 int lustre_lnet_config_buffers(int tiny, int small, int large, int seq_no,
3151                                struct cYAML **err_rc)
3152 {
3153         struct lnet_ioctl_config_data data;
3154         int rc = LUSTRE_CFG_RC_NO_ERR;
3155         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
3156
3157         /* -1 indicates to ignore changes to this field */
3158         if (tiny < -1 || small < -1 || large < -1) {
3159                 snprintf(err_str,
3160                          sizeof(err_str),
3161                          "\"tiny, small and large must be >= 0\"");
3162                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
3163                 goto out;
3164         }
3165
3166         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
3167         data.cfg_config_u.cfg_buffers.buf_tiny = tiny;
3168         data.cfg_config_u.cfg_buffers.buf_small = small;
3169         data.cfg_config_u.cfg_buffers.buf_large = large;
3170
3171         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_BUF, &data);
3172         if (rc != 0) {
3173                 rc = -errno;
3174                 snprintf(err_str,
3175                          sizeof(err_str),
3176                          "\"cannot configure buffers: %s\"", strerror(errno));
3177                 goto out;
3178         }
3179
3180 out:
3181         cYAML_build_error(rc, seq_no, ADD_CMD, "buf", err_str, err_rc);
3182
3183         return rc;
3184 }
3185
3186 int lustre_lnet_config_max_recovery_ping_interval(int interval, int seq_no,
3187                                                   struct cYAML **err_rc)
3188 {
3189         int rc = LUSTRE_CFG_RC_NO_ERR;
3190         char err_str[LNET_MAX_STR_LEN] = "\"success\"";
3191         char interval_str[LNET_MAX_STR_LEN];
3192
3193         if (interval <= 0) {
3194                 rc = LUSTRE_CFG_RC_BAD_PARAM;
3195                 snprintf(err_str, sizeof(err_str),
3196                          "\"must be strictly positive\"");
3197
3198         } else {
3199                 snprintf(interval_str, sizeof(interval_str), "%d", interval);
3200
3201                 rc = write_sysfs_file(modparam_path,
3202                                       "lnet_max_recovery_ping_interval",
3203                                       interval_str, 1,
3204                                       strlen(interval_str) + 1);
3205                 if (rc)
3206                         snprintf(err_str, sizeof(err_str),
3207                                  "\"cannot configure maximum recovery ping interval: %s\"",
3208                                  strerror(errno));
3209         }
3210
3211         cYAML_build_error(rc, seq_no, ADD_CMD, "maximum recovery ping interval",
3212                           err_str, err_rc);
3213
3214         return rc;
3215 }
3216
3217
3218 int lustre_lnet_show_routing(int seq_no, struct cYAML **show_rc,
3219                              struct cYAML **err_rc, bool backup)
3220 {
3221         struct lnet_ioctl_config_data *data;
3222         struct lnet_ioctl_pool_cfg *pool_cfg = NULL;
3223         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3224         int l_errno = 0;
3225         char *buf;
3226         char *pools[LNET_NRBPOOLS] = {"tiny", "small", "large"};
3227         int buf_count[LNET_NRBPOOLS] = {0};
3228         struct cYAML *root = NULL, *pools_node = NULL,
3229                      *type_node = NULL, *item = NULL, *cpt = NULL,
3230                      *first_seq = NULL, *buffers = NULL;
3231         int i, j;
3232         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
3233         char node_name[LNET_MAX_STR_LEN];
3234         bool exist = false;
3235
3236         buf = calloc(1, sizeof(*data) + sizeof(*pool_cfg));
3237         if (buf == NULL)
3238                 goto out;
3239
3240         data = (struct lnet_ioctl_config_data *)buf;
3241
3242         root = cYAML_create_object(NULL, NULL);
3243         if (root == NULL)
3244                 goto out;
3245
3246         if (backup)
3247                 pools_node = cYAML_create_object(root, "routing");
3248         else
3249                 pools_node = cYAML_create_seq(root, "routing");
3250         if (pools_node == NULL)
3251                 goto out;
3252
3253         for (i = 0;; i++) {
3254                 LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
3255                 data->cfg_hdr.ioc_len = sizeof(struct lnet_ioctl_config_data) +
3256                                         sizeof(struct lnet_ioctl_pool_cfg);
3257                 data->cfg_count = i;
3258
3259                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_BUF, data);
3260                 if (rc != 0) {
3261                         l_errno = errno;
3262                         break;
3263                 }
3264
3265                 exist = true;
3266
3267                 pool_cfg = (struct lnet_ioctl_pool_cfg *)data->cfg_bulk;
3268
3269                 if (backup)
3270                         goto calculate_buffers;
3271
3272                 snprintf(node_name, sizeof(node_name), "cpt[%d]", i);
3273                 item = cYAML_create_seq_item(pools_node);
3274                 if (item == NULL)
3275                         goto out;
3276
3277                 if (first_seq == NULL)
3278                         first_seq = item;
3279
3280                 cpt = cYAML_create_object(item, node_name);
3281                 if (cpt == NULL)
3282                         goto out;
3283
3284 calculate_buffers:
3285                 /* create the tree  and print */
3286                 for (j = 0; j < LNET_NRBPOOLS; j++) {
3287                         if (!backup) {
3288                                 type_node = cYAML_create_object(cpt, pools[j]);
3289                                 if (type_node == NULL)
3290                                         goto out;
3291                         }
3292                         if (!backup &&
3293                             cYAML_create_number(type_node, "npages",
3294                                                 pool_cfg->pl_pools[j].pl_npages)
3295                             == NULL)
3296                                 goto out;
3297                         if (!backup &&
3298                             cYAML_create_number(type_node, "nbuffers",
3299                                                 pool_cfg->pl_pools[j].
3300                                                   pl_nbuffers) == NULL)
3301                                 goto out;
3302                         if (!backup &&
3303                             cYAML_create_number(type_node, "credits",
3304                                                 pool_cfg->pl_pools[j].
3305                                                    pl_credits) == NULL)
3306                                 goto out;
3307                         if (!backup &&
3308                             cYAML_create_number(type_node, "mincredits",
3309                                                 pool_cfg->pl_pools[j].
3310                                                    pl_mincredits) == NULL)
3311                                 goto out;
3312                         /* keep track of the total count for each of the
3313                          * tiny, small and large buffers */
3314                         buf_count[j] += pool_cfg->pl_pools[j].pl_nbuffers;
3315                 }
3316         }
3317
3318         if (pool_cfg != NULL) {
3319                 if (backup) {
3320                         if (cYAML_create_number(pools_node, "enable",
3321                                                 pool_cfg->pl_routing) ==
3322                         NULL)
3323                                 goto out;
3324
3325                         goto add_buffer_section;
3326                 }
3327
3328                 item = cYAML_create_seq_item(pools_node);
3329                 if (item == NULL)
3330                         goto out;
3331
3332                 if (cYAML_create_number(item, "enable", pool_cfg->pl_routing) ==
3333                     NULL)
3334                         goto out;
3335         }
3336
3337 add_buffer_section:
3338         /* create a buffers entry in the show. This is necessary so that
3339          * if the YAML output is used to configure a node, the buffer
3340          * configuration takes hold */
3341         buffers = cYAML_create_object(root, "buffers");
3342         if (buffers == NULL)
3343                 goto out;
3344
3345         for (i = 0; i < LNET_NRBPOOLS; i++) {
3346                 if (cYAML_create_number(buffers, pools[i], buf_count[i]) == NULL)
3347                         goto out;
3348         }
3349
3350         if (show_rc == NULL)
3351                 cYAML_print_tree(root);
3352
3353         if (l_errno != ENOENT) {
3354                 snprintf(err_str,
3355                          sizeof(err_str),
3356                          "\"cannot get routing information: %s\"",
3357                          strerror(l_errno));
3358                 rc = -l_errno;
3359                 goto out;
3360         } else
3361                 rc = LUSTRE_CFG_RC_NO_ERR;
3362
3363         snprintf(err_str, sizeof(err_str), "\"success\"");
3364         rc = LUSTRE_CFG_RC_NO_ERR;
3365
3366 out:
3367         free(buf);
3368         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
3369                 cYAML_free_tree(root);
3370         } else if (show_rc != NULL && *show_rc != NULL) {
3371                 struct cYAML *routing_node;
3372                 /* there should exist only one routing block and one
3373                  * buffers block. If there already exists a previous one
3374                  * then don't add another */
3375                 routing_node = cYAML_get_object_item(*show_rc, "routing");
3376                 if (routing_node == NULL) {
3377                         cYAML_insert_sibling((*show_rc)->cy_child,
3378                                                 root->cy_child);
3379                         free(root);
3380                 } else {
3381                         cYAML_free_tree(root);
3382                 }
3383         } else {
3384                 *show_rc = root;
3385         }
3386
3387         cYAML_build_error(rc, seq_no, SHOW_CMD, "routing", err_str, err_rc);
3388
3389         return rc;
3390 }
3391
3392 int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
3393                           struct cYAML **show_rc, struct cYAML **err_rc,
3394                           bool backup)
3395 {
3396         /*
3397          * TODO: This function is changing in a future patch to accommodate
3398          * PEER_LIST and proper filtering on any nid of the peer
3399          */
3400         struct lnet_ioctl_peer_cfg peer_info;
3401         struct lnet_peer_ni_credit_info *lpni_cri;
3402         struct lnet_ioctl_element_stats *lpni_stats;
3403         struct lnet_ioctl_element_msg_stats *msg_stats;
3404         struct lnet_ioctl_peer_ni_hstats *hstats;
3405         struct lnet_ioctl_construct_udsp_info udsp_info;
3406         lnet_nid_t *nidp;
3407         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3408         int i, j, k;
3409         int l_errno = 0;
3410         __u32 count;
3411         __u32 size;
3412         struct cYAML *root = NULL, *peer = NULL, *peer_ni = NULL,
3413                      *first_seq = NULL, *peer_root = NULL, *tmp = NULL,
3414                      *msg_statistics = NULL, *statistics = NULL,
3415                      *yhstats;
3416         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
3417         struct lnet_process_id *list = NULL;
3418         void *data = NULL;
3419         void *lpni_data;
3420         bool exist = false;
3421
3422         /* create struct cYAML root object */
3423         root = cYAML_create_object(NULL, NULL);
3424         if (root == NULL)
3425                 goto out;
3426
3427         peer_root = cYAML_create_seq(root, "peer");
3428         if (peer_root == NULL)
3429                 goto out;
3430
3431         count = 1000;
3432         size = count * sizeof(struct lnet_process_id);
3433         list = malloc(size);
3434         if (list == NULL) {
3435                 l_errno = ENOMEM;
3436                 goto out;
3437         }
3438         if (knid != NULL) {
3439                 list[0].nid = libcfs_str2nid(knid);
3440                 count = 1;
3441         } else {
3442                 for (;;) {
3443                         memset(&peer_info, 0, sizeof(peer_info));
3444                         LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
3445                         peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
3446                         peer_info.prcfg_size = size;
3447                         peer_info.prcfg_bulk = list;
3448
3449                         l_errno = 0;
3450                         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_PEER_LIST,
3451                                      &peer_info);
3452                         count = peer_info.prcfg_count;
3453                         if (rc == 0)
3454                                 break;
3455                         l_errno = errno;
3456                         if (l_errno != E2BIG) {
3457                                 snprintf(err_str,
3458                                         sizeof(err_str),
3459                                         "\"cannot get peer list: %s\"",
3460                                         strerror(l_errno));
3461                                 rc = -l_errno;
3462                                 goto out;
3463                         }
3464                         free(list);
3465                         size = peer_info.prcfg_size;
3466                         list = malloc(size);
3467                         if (list == NULL) {
3468                                 l_errno = ENOMEM;
3469                                 goto out;
3470                         }
3471                 }
3472         }
3473
3474         size = 4096;
3475         data = malloc(size);
3476         if (data == NULL) {
3477                 l_errno = ENOMEM;
3478                 goto out;
3479         }
3480
3481         for (i = 0; i < count; i++) {
3482                 for (;;) {
3483                         memset(&peer_info, 0, sizeof(peer_info));
3484                         LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
3485                         peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
3486                         peer_info.prcfg_prim_nid = list[i].nid;
3487                         peer_info.prcfg_size = size;
3488                         peer_info.prcfg_bulk = data;
3489
3490                         l_errno = 0;
3491                         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_PEER_NI,
3492                                      &peer_info);
3493                         if (rc == 0)
3494                                 break;
3495                         l_errno = errno;
3496                         if (l_errno != E2BIG) {
3497                                 snprintf(err_str,
3498                                         sizeof(err_str),
3499                                         "\"cannot get peer information: %s\"",
3500                                         strerror(l_errno));
3501                                 rc = -l_errno;
3502                                 goto out;
3503                         }
3504                         free(data);
3505                         size = peer_info.prcfg_size;
3506                         data = malloc(size);
3507                         if (data == NULL) {
3508                                 l_errno = ENOMEM;
3509                                 goto out;
3510                         }
3511                 }
3512                 exist = true;
3513
3514                 peer = cYAML_create_seq_item(peer_root);
3515                 if (peer == NULL)
3516                         goto out;
3517
3518                 if (first_seq == NULL)
3519                         first_seq = peer;
3520
3521                 lnet_nid_t pnid = peer_info.prcfg_prim_nid;
3522                 if (cYAML_create_string(peer, "primary nid",
3523                                         libcfs_nid2str(pnid))
3524                     == NULL)
3525                         goto out;
3526                 if (cYAML_create_string(peer, "Multi-Rail",
3527                                         peer_info.prcfg_mr ? "True" : "False")
3528                     == NULL)
3529                         goto out;
3530                 /*
3531                  * print out the state of the peer only if details are
3532                  * requested
3533                  */
3534                 if (detail >= 3) {
3535                         if (!backup &&
3536                             cYAML_create_number(peer, "peer state",
3537                                                 peer_info.prcfg_state)
3538                                 == NULL)
3539                                 goto out;
3540                 }
3541
3542                 tmp = cYAML_create_seq(peer, "peer ni");
3543                 if (tmp == NULL)
3544                         goto out;
3545
3546                 lpni_data = data;
3547                 for (j = 0; j < peer_info.prcfg_count; j++) {
3548                         nidp = lpni_data;
3549                         lpni_cri = (void*)nidp + sizeof(nidp);
3550                         lpni_stats = (void *)lpni_cri + sizeof(*lpni_cri);
3551                         msg_stats = (void *)lpni_stats + sizeof(*lpni_stats);
3552                         hstats = (void *)msg_stats + sizeof(*msg_stats);
3553                         lpni_data = (void *)hstats + sizeof(*hstats);
3554
3555                         peer_ni = cYAML_create_seq_item(tmp);
3556                         if (peer_ni == NULL)
3557                                 goto out;
3558
3559                         if (cYAML_create_string(peer_ni, "nid",
3560                                                 libcfs_nid2str(*nidp))
3561                             == NULL)
3562                                 goto out;
3563
3564                         if (backup)
3565                                 continue;
3566
3567                         if (detail < 4)
3568                                 goto continue_without_udsp_info;
3569
3570                         LIBCFS_IOC_INIT_V2(udsp_info, cud_hdr);
3571                         udsp_info.cud_nid = *nidp;
3572                         udsp_info.cud_peer = true;
3573                         rc = l_ioctl(LNET_DEV_ID,
3574                                         IOC_LIBCFS_GET_CONST_UDSP_INFO,
3575                                         &udsp_info);
3576                         if (rc != 0) {
3577                                 l_errno = errno;
3578                                 goto continue_without_udsp_info;
3579                         }
3580
3581                         rc = create_remote_udsp_info(&udsp_info, peer_ni);
3582                         if (rc) {
3583                                 l_errno = errno;
3584                                 goto out;
3585                         }
3586
3587 continue_without_udsp_info:
3588                         if (cYAML_create_string(peer_ni, "state",
3589                                                 lpni_cri->cr_aliveness)
3590                             == NULL)
3591                                 goto out;
3592
3593                         if (!detail)
3594                                 continue;
3595
3596                         if (cYAML_create_number(peer_ni, "max_ni_tx_credits",
3597                                                 lpni_cri->cr_ni_peer_tx_credits)
3598                             == NULL)
3599                                 goto out;
3600
3601                         if (cYAML_create_number(peer_ni, "available_tx_credits",
3602                                                 lpni_cri->cr_peer_tx_credits)
3603                             == NULL)
3604                                 goto out;
3605
3606                         if (cYAML_create_number(peer_ni, "min_tx_credits",
3607                                                 lpni_cri->cr_peer_min_tx_credits)
3608                             == NULL)
3609                                 goto out;
3610
3611                         if (cYAML_create_number(peer_ni, "tx_q_num_of_buf",
3612                                                 lpni_cri->cr_peer_tx_qnob)
3613                             == NULL)
3614                                 goto out;
3615
3616                         if (cYAML_create_number(peer_ni, "available_rtr_credits",
3617                                                 lpni_cri->cr_peer_rtr_credits)
3618                             == NULL)
3619                                 goto out;
3620
3621                         if (cYAML_create_number(peer_ni, "min_rtr_credits",
3622                                                 lpni_cri->cr_peer_min_rtr_credits)
3623                             == NULL)
3624                                 goto out;
3625
3626                         if (cYAML_create_number(peer_ni, "refcount",
3627                                                 lpni_cri->cr_refcount) == NULL)
3628                                 goto out;
3629
3630                         statistics = cYAML_create_object(peer_ni, "statistics");
3631                         if (statistics == NULL)
3632                                 goto out;
3633
3634                         if (cYAML_create_number(statistics, "send_count",
3635                                                 lpni_stats->iel_send_count)
3636                             == NULL)
3637                                 goto out;
3638
3639                         if (cYAML_create_number(statistics, "recv_count",
3640                                                 lpni_stats->iel_recv_count)
3641                             == NULL)
3642                                 goto out;
3643
3644                         if (cYAML_create_number(statistics, "drop_count",
3645                                                 lpni_stats->iel_drop_count)
3646                             == NULL)
3647                                 goto out;
3648
3649                         if (detail < 2)
3650                                 continue;
3651
3652                         for (k = 0; k < 3; k++) {
3653                                 struct lnet_ioctl_comm_count *counts;
3654
3655                                 msg_statistics = cYAML_create_object(peer_ni,
3656                                                  (char *) gmsg_stat_names[k]);
3657                                 if (msg_statistics == NULL)
3658                                         goto out;
3659
3660                                 counts = get_counts(msg_stats, k);
3661                                 if (counts == NULL)
3662                                         goto out;
3663
3664                                 if (!add_msg_stats_to_yaml_blk(msg_statistics,
3665                                                                counts))
3666                                         goto out;
3667                         }
3668
3669                         yhstats = cYAML_create_object(peer_ni, "health stats");
3670                         if (!yhstats)
3671                                 goto out;
3672                         if (cYAML_create_number(yhstats, "health value",
3673                                                 hstats->hlpni_health_value)
3674                                                         == NULL)
3675                                 goto out;
3676                         if (cYAML_create_number(yhstats, "dropped",
3677                                                 hstats->hlpni_remote_dropped)
3678                                                         == NULL)
3679                                 goto out;
3680                         if (cYAML_create_number(yhstats, "timeout",
3681                                                 hstats->hlpni_remote_timeout)
3682                                                         == NULL)
3683                                 goto out;
3684                         if (cYAML_create_number(yhstats, "error",
3685                                                 hstats->hlpni_remote_error)
3686                                                         == NULL)
3687                                 goto out;
3688                         if (cYAML_create_number(yhstats, "network timeout",
3689                                                 hstats->hlpni_network_timeout)
3690                                                         == NULL)
3691                                 goto out;
3692                         if (cYAML_create_number(yhstats, "ping_count",
3693                                                 hstats->hlpni_ping_count)
3694                                                         == NULL)
3695                                 goto out;
3696
3697                         if (cYAML_create_number(yhstats, "next_ping",
3698                                                 hstats->hlpni_next_ping)
3699                                                         == NULL)
3700                                 goto out;
3701
3702                 }
3703         }
3704
3705         /* print output iff show_rc is not provided */
3706         if (show_rc == NULL)
3707                 cYAML_print_tree(root);
3708
3709         snprintf(err_str, sizeof(err_str), "\"success\"");
3710         rc = LUSTRE_CFG_RC_NO_ERR;
3711
3712 out:
3713         free(list);
3714         free(data);
3715         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
3716                 cYAML_free_tree(root);
3717         } else if (show_rc != NULL && *show_rc != NULL) {
3718                 struct cYAML *show_node;
3719                 /* find the peer node, if one doesn't exist then
3720                  * insert one.  Otherwise add to the one there
3721                  */
3722                 show_node = cYAML_get_object_item(*show_rc,
3723                                                   "peer");
3724                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
3725                         cYAML_insert_child(show_node, first_seq);
3726                         free(peer_root);
3727                         free(root);
3728                 } else if (show_node == NULL) {
3729                         cYAML_insert_sibling((*show_rc)->cy_child,
3730                                              peer_root);
3731                         free(root);
3732                 } else {
3733                         cYAML_free_tree(root);
3734                 }
3735         } else {
3736                 *show_rc = root;
3737         }
3738
3739         cYAML_build_error(rc, seq_no, SHOW_CMD, "peer", err_str,
3740                           err_rc);
3741
3742         return rc;
3743 }
3744
3745 int lustre_lnet_list_peer(int seq_no,
3746                           struct cYAML **show_rc, struct cYAML **err_rc)
3747 {
3748         struct lnet_ioctl_peer_cfg peer_info;
3749         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3750         __u32 count;
3751         __u32 size;
3752         int i = 0;
3753         int l_errno = 0;
3754         struct cYAML *root = NULL, *list_root = NULL, *first_seq = NULL;
3755         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
3756         struct lnet_process_id *list = NULL;
3757
3758         memset(&peer_info, 0, sizeof(peer_info));
3759
3760         /* create struct cYAML root object */
3761         root = cYAML_create_object(NULL, NULL);
3762         if (root == NULL)
3763                 goto out;
3764
3765         list_root = cYAML_create_seq(root, "peer list");
3766         if (list_root == NULL)
3767                 goto out;
3768
3769         count = 1000;
3770         size = count * sizeof(struct lnet_process_id);
3771         list = malloc(size);
3772         if (list == NULL) {
3773                 l_errno = ENOMEM;
3774                 goto out;
3775         }
3776         for (;;) {
3777                 LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
3778                 peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
3779                 peer_info.prcfg_size = size;
3780                 peer_info.prcfg_bulk = list;
3781
3782                 l_errno = 0;
3783                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_PEER_LIST, &peer_info);
3784                 count = peer_info.prcfg_count;
3785                 if (rc == 0)
3786                         break;
3787                 l_errno = errno;
3788                 if (l_errno != E2BIG) {
3789                         snprintf(err_str,
3790                                 sizeof(err_str),
3791                                 "\"cannot get peer list: %s\"",
3792                                 strerror(l_errno));
3793                         rc = -l_errno;
3794                         goto out;
3795                 }
3796                 free(list);
3797                 size = peer_info.prcfg_size;
3798                 list = malloc(size);
3799                 if (list == NULL) {
3800                         l_errno = ENOMEM;
3801                         goto out;
3802                 }
3803         }
3804
3805         /* count is now the actual number of ids in the list. */
3806         for (i = 0; i < count; i++) {
3807                 if (cYAML_create_string(list_root, "nid",
3808                                         libcfs_nid2str(list[i].nid))
3809                     == NULL)
3810                         goto out;
3811         }
3812
3813         /* print output iff show_rc is not provided */
3814         if (show_rc == NULL)
3815                 cYAML_print_tree(root);
3816
3817         snprintf(err_str, sizeof(err_str), "\"success\"");
3818         rc = LUSTRE_CFG_RC_NO_ERR;
3819
3820 out:
3821         if (list != NULL)
3822                 free(list);
3823         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
3824                 cYAML_free_tree(root);
3825         } else if (show_rc != NULL && *show_rc != NULL) {
3826                 struct cYAML *show_node;
3827                 /* find the peer node, if one doesn't exist then
3828                  * insert one.  Otherwise add to the one there
3829                  */
3830                 show_node = cYAML_get_object_item(*show_rc,
3831                                                   "peer");
3832                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
3833                         cYAML_insert_child(show_node, first_seq);
3834                         free(list_root);
3835                         free(root);
3836                 } else if (show_node == NULL) {
3837                         cYAML_insert_sibling((*show_rc)->cy_child,
3838                                              list_root);
3839                         free(root);
3840                 } else {
3841                         cYAML_free_tree(root);
3842                 }
3843         } else {
3844                 *show_rc = root;
3845         }
3846
3847         cYAML_build_error(rc, seq_no, SHOW_CMD, "peer", err_str,
3848                           err_rc);
3849
3850         return rc;
3851 }
3852
3853 static void add_to_global(struct cYAML *show_rc, struct cYAML *node,
3854                           struct cYAML *root)
3855 {
3856         struct cYAML *show_node;
3857
3858         show_node = cYAML_get_object_item(show_rc, "global");
3859         if (show_node != NULL)
3860                 cYAML_insert_sibling(show_node->cy_child,
3861                                      node->cy_child);
3862         else
3863                 cYAML_insert_sibling(show_rc->cy_child,
3864                                      node);
3865         free(root);
3866 }
3867
3868 static int build_global_yaml_entry(char *err_str, int err_len, int seq_no,
3869                                    char *name, __u64 value,
3870                                    struct cYAML **show_rc,
3871                                    struct cYAML **err_rc, int err)
3872 {
3873         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3874         struct cYAML *root = NULL, *global = NULL;
3875
3876         if (err) {
3877                 rc = err;
3878                 goto out;
3879         }
3880
3881         root = cYAML_create_object(NULL, NULL);
3882         if (root == NULL)
3883                 goto out;
3884
3885         global = cYAML_create_object(root, "global");
3886         if (global == NULL)
3887                 goto out;
3888
3889         if (cYAML_create_number(global, name,
3890                                 value) == NULL)
3891                 goto out;
3892
3893         if (show_rc == NULL)
3894                 cYAML_print_tree(root);
3895
3896         snprintf(err_str, err_len, "\"success\"");
3897
3898         rc = LUSTRE_CFG_RC_NO_ERR;
3899
3900 out:
3901         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
3902                 cYAML_free_tree(root);
3903         } else if (show_rc != NULL && *show_rc != NULL) {
3904                 add_to_global(*show_rc, global, root);
3905         } else {
3906                 *show_rc = root;
3907         }
3908
3909         cYAML_build_error(rc, seq_no, SHOW_CMD, "global", err_str, err_rc);
3910
3911         return rc;
3912 }
3913
3914 static int ioctl_show_global_values(int ioc, int seq_no, char *name,
3915                                     struct cYAML **show_rc,
3916                                     struct cYAML **err_rc)
3917 {
3918         struct lnet_ioctl_set_value data;
3919         int rc;
3920         int l_errno = 0;
3921         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
3922
3923         LIBCFS_IOC_INIT_V2(data, sv_hdr);
3924
3925         rc = l_ioctl(LNET_DEV_ID, ioc, &data);
3926         if (rc != 0) {
3927                 l_errno = -errno;
3928                 snprintf(err_str,
3929                          sizeof(err_str),
3930                          "\"cannot get %s: %s\"",
3931                          name, strerror(l_errno));
3932         }
3933
3934         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no, name,
3935                                        data.sv_value, show_rc, err_rc, l_errno);
3936 }
3937
3938 int lustre_lnet_show_recov_intrv(int seq_no, struct cYAML **show_rc,
3939                                  struct cYAML **err_rc)
3940 {
3941         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3942         char val[LNET_MAX_STR_LEN];
3943         int intrv = -1, l_errno = 0;
3944         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
3945
3946         rc = read_sysfs_file(modparam_path, "lnet_recovery_interval", val,
3947                              1, sizeof(val));
3948         if (rc) {
3949                 l_errno = -errno;
3950                 snprintf(err_str, sizeof(err_str),
3951                          "\"cannot get recovery interval: %d\"", rc);
3952         } else {
3953                 intrv = atoi(val);
3954         }
3955
3956         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
3957                                        "recovery_interval", intrv, show_rc,
3958                                        err_rc, l_errno);
3959 }
3960
3961 int lustre_lnet_show_hsensitivity(int seq_no, struct cYAML **show_rc,
3962                                   struct cYAML **err_rc)
3963 {
3964         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3965         char val[LNET_MAX_STR_LEN];
3966         int sen = -1, l_errno = 0;
3967         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
3968
3969         rc = read_sysfs_file(modparam_path, "lnet_health_sensitivity", val,
3970                              1, sizeof(val));
3971         if (rc) {
3972                 l_errno = -errno;
3973                 snprintf(err_str, sizeof(err_str),
3974                          "\"cannot get health sensitivity: %d\"", rc);
3975         } else {
3976                 sen = atoi(val);
3977         }
3978
3979         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
3980                                        "health_sensitivity", sen, show_rc,
3981                                        err_rc, l_errno);
3982 }
3983
3984 int lustre_lnet_show_rtr_sensitivity(int seq_no, struct cYAML **show_rc,
3985                                      struct cYAML **err_rc)
3986 {
3987         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3988         char val[LNET_MAX_STR_LEN];
3989         int sen = -1, l_errno = 0;
3990         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
3991
3992         rc = read_sysfs_file(modparam_path, "router_sensitivity_percentage", val,
3993                              1, sizeof(val));
3994         if (rc) {
3995                 l_errno = -errno;
3996                 snprintf(err_str, sizeof(err_str),
3997                          "\"cannot get router sensitivity percentage: %d\"", rc);
3998         } else {
3999                 sen = atoi(val);
4000         }
4001
4002         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4003                                        "router_sensitivity", sen, show_rc,
4004                                        err_rc, l_errno);
4005 }
4006
4007 int lustre_lnet_show_lnd_timeout(int seq_no, struct cYAML **show_rc,
4008                                  struct cYAML **err_rc)
4009 {
4010         char val[LNET_MAX_STR_LEN];
4011         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4012         int lnd_to = -1;
4013         int l_errno = 0;
4014         int rc;
4015         int fd;
4016         glob_t path;
4017
4018         rc = cfs_get_param_paths(&path, "lnet_lnd_timeout");
4019         if (rc < 0) {
4020                 l_errno = -errno;
4021                 snprintf(err_str, sizeof(err_str),
4022                          "\"cannot get LND timeout: %d\"", rc);
4023                 return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4024                                                "lnd_timeout", lnd_to, show_rc,
4025                                                err_rc, l_errno);
4026         }
4027
4028         fd = open(path.gl_pathv[0], O_RDONLY);
4029         if (fd < 0) {
4030                 l_errno = -errno;
4031                 snprintf(err_str, sizeof(err_str),
4032                          "\"error opening %s\"", path.gl_pathv[0]);
4033                 goto failed;
4034         }
4035
4036         rc = read(fd, val, sizeof(val));
4037         if (rc < 0)
4038                 l_errno = -errno;
4039
4040         close(fd);
4041
4042         if (rc < 0) {
4043                 snprintf(err_str, sizeof(err_str),
4044                          "\"error reading %s\"", path.gl_pathv[0]);
4045                 goto failed;
4046         }
4047
4048         lnd_to = atoi(val);
4049
4050 failed:
4051         cfs_free_param_data(&path);
4052
4053         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4054                                        "lnd_timeout", lnd_to, show_rc,
4055                                        err_rc, l_errno);
4056 }
4057
4058 int lustre_lnet_show_transaction_to(int seq_no, struct cYAML **show_rc,
4059                                     struct cYAML **err_rc)
4060 {
4061         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4062         char val[LNET_MAX_STR_LEN];
4063         int tto = -1, l_errno = 0;
4064         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4065
4066         rc = read_sysfs_file(modparam_path, "lnet_transaction_timeout", val,
4067                              1, sizeof(val));
4068         if (rc) {
4069                 l_errno = -errno;
4070                 snprintf(err_str, sizeof(err_str),
4071                          "\"cannot get transaction timeout: %d\"", rc);
4072         } else {
4073                 tto = atoi(val);
4074         }
4075
4076         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4077                                        "transaction_timeout", tto, show_rc,
4078                                        err_rc, l_errno);
4079 }
4080
4081 int lustre_lnet_show_retry_count(int seq_no, struct cYAML **show_rc,
4082                                  struct cYAML **err_rc)
4083 {
4084         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4085         char val[LNET_MAX_STR_LEN];
4086         int retry_count = -1, l_errno = 0;
4087         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4088
4089         rc = read_sysfs_file(modparam_path, "lnet_retry_count", val,
4090                              1, sizeof(val));
4091         if (rc) {
4092                 l_errno = -errno;
4093                 snprintf(err_str, sizeof(err_str),
4094                          "\"cannot get retry count: %d\"", rc);
4095         } else {
4096                 retry_count = atoi(val);
4097         }
4098
4099         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4100                                        "retry_count", retry_count, show_rc,
4101                                        err_rc, l_errno);
4102 }
4103
4104 int lustre_lnet_calc_service_id(__u64 *service_id)
4105 {
4106         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4107         char val[LNET_MAX_STR_LEN];
4108         int service_port = -1, l_errno = 0;
4109
4110         rc = read_sysfs_file(o2ib_modparam_path, "service", val,
4111                              1, sizeof(val));
4112         if (rc) {
4113                 l_errno = errno;
4114                 fprintf(stderr, "error:\n    msg: \"cannot get service port: %s (%d)\"\n",
4115                         strerror(l_errno), -l_errno);
4116                 return rc;
4117         } else {
4118                 service_port = atoi(val);
4119         }
4120
4121         *service_id = htobe64(((__u64)RDMA_PS_TCP << 16) + service_port);
4122
4123         return LUSTRE_CFG_RC_NO_ERR;
4124 }
4125
4126 int lustre_lnet_setup_mrrouting(struct cYAML **err_rc)
4127 {
4128         char *buf;
4129         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i;
4130         int l_errno = 0;
4131         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4132         struct lnet_ioctl_config_ni *ni_data;
4133         struct lnet_ioctl_config_lnd_tunables *lnd;
4134         struct lnet_ioctl_element_stats *stats;
4135         size_t buf_size = sizeof(*ni_data) + sizeof(*lnd) + sizeof(*stats);
4136         char ifstr_buf[LNET_INTERFACES_NUM*LNET_MAX_STR_LEN];
4137         char *ifstr_ptr, *tmp_ptr, *tmp_ptr2;
4138         int if_cnt = 0, prc;
4139         char syscmdbuf[LNET_MAX_STR_LEN];
4140         char cmdpath[LNET_MAX_STR_LEN];
4141         bool use_custom = false;
4142
4143         buf = calloc(1, buf_size);
4144         if (buf == NULL)
4145                 goto out;
4146
4147         ni_data = (struct lnet_ioctl_config_ni *)buf;
4148
4149         ifstr_buf[0] = 0;
4150         ifstr_ptr = ifstr_buf;
4151
4152         for (i = 0;; i++) {
4153                 __u32 rc_net;
4154
4155                 memset(buf, 0, buf_size);
4156
4157                 LIBCFS_IOC_INIT_V2(*ni_data, lic_cfg_hdr);
4158                 /* set the ioc_len to the proper value since INIT assumes
4159                  * size of data
4160                  */
4161                 ni_data->lic_cfg_hdr.ioc_len = buf_size;
4162                 ni_data->lic_idx = i;
4163
4164                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LOCAL_NI, ni_data);
4165                 if (rc != 0) {
4166                         l_errno = errno;
4167                         break;
4168                 }
4169
4170                 rc_net = LNET_NIDNET(ni_data->lic_nid);
4171
4172                 /* only need to setup routing for tcp */
4173                 if (LNET_NETTYP(rc_net) != SOCKLND)
4174                         continue;
4175
4176                 /* don't add interfaces unless there is at least one
4177                  * interface
4178                  */
4179                 if (strlen(ni_data->lic_ni_intf) > 0) {
4180                         if (if_cnt > 0)
4181                                 strcat(ifstr_ptr, ",");
4182                         strcat(ifstr_ptr, ni_data->lic_ni_intf);
4183                         if_cnt++;
4184                 }
4185         }
4186
4187         if (l_errno != ENOENT) {
4188                 snprintf(err_str,
4189                          sizeof(err_str),
4190                          "\"cannot get networks: %s\"",
4191                          strerror(l_errno));
4192                 rc = -l_errno;
4193                 goto out;
4194         } else {
4195                 rc = LUSTRE_CFG_RC_NO_ERR;
4196         }
4197
4198         snprintf(err_str, sizeof(err_str), "\"success\"");
4199
4200         if (if_cnt > 0) {
4201                 tmp_ptr = getenv("KSOCKLND_CONFIG");
4202                 if (tmp_ptr) {
4203                         tmp_ptr2 = strrchr(tmp_ptr, '/');
4204                         if (tmp_ptr2 && !strcmp(tmp_ptr2, "/ksocklnd-config")) {
4205                                 snprintf(cmdpath, sizeof(cmdpath), "%s",
4206                                          tmp_ptr);
4207                                 use_custom = true;
4208                         }
4209                 }
4210
4211                 if (!use_custom)
4212                         snprintf(cmdpath, sizeof(cmdpath),
4213                                  "/usr/sbin/ksocklnd-config");
4214
4215                 prc = snprintf(0, 0, "%s %s", cmdpath, ifstr_ptr);
4216
4217                 if (prc < 0) {
4218                         l_errno = errno;
4219                         snprintf(err_str,
4220                                  sizeof(err_str),
4221                                  "\"snprintf failed : %s\"",
4222                                  strerror(l_errno));
4223                         rc = -l_errno;
4224                 } else if (prc >= LNET_MAX_STR_LEN) {
4225                         snprintf(err_str, sizeof(err_str),
4226                                  "\"ksocklnd-config: argument too long\"");
4227                 } else {
4228                         prc = snprintf(syscmdbuf, sizeof(syscmdbuf), "%s %s",
4229                                        cmdpath, ifstr_ptr);
4230
4231                         if (prc < 0) {
4232                                 l_errno = errno;
4233                                 snprintf(err_str,
4234                                          sizeof(err_str),
4235                                          "\"snprintf failed : %s\"",
4236                                          strerror(l_errno));
4237                                 rc = -l_errno;
4238                                 goto out;
4239                         }
4240
4241                         rc = system(syscmdbuf);
4242                         if (rc != 0) {
4243                                 l_errno = errno;
4244                                 snprintf(err_str,
4245                                          sizeof(err_str),
4246                                          "\"failed to execute ksocklnd-config : %s\"",
4247                                          strerror(l_errno));
4248                                 rc = -l_errno;
4249                         }
4250                 }
4251         }
4252 out:
4253         if (buf)
4254                 free(buf);
4255
4256         cYAML_build_error(rc, -1, MANAGE_CMD, "setup-mrrouting", err_str,
4257                           err_rc);
4258
4259         return rc;
4260 }
4261
4262 static int show_recovery_queue(enum lnet_health_type type, char *name,
4263                                int seq_no, struct cYAML **show_rc,
4264                                struct cYAML **err_rc)
4265 {
4266         struct lnet_ioctl_recovery_list nid_list;
4267         struct cYAML *root = NULL, *nids = NULL;
4268         int rc, i;
4269         char err_str[LNET_MAX_STR_LEN] = "failed to print recovery queue\n";
4270
4271         LIBCFS_IOC_INIT_V2(nid_list, rlst_hdr);
4272         nid_list.rlst_type = type;
4273
4274         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_RECOVERY_QUEUE, &nid_list);
4275         if (rc) {
4276                 rc = errno;
4277                 goto out;
4278         }
4279
4280         if (nid_list.rlst_num_nids == 0)
4281                 goto out;
4282
4283         root = cYAML_create_object(NULL, NULL);
4284         if (root == NULL)
4285                 goto out;
4286
4287         nids = cYAML_create_object(root, name);
4288         if (nids == NULL)
4289                 goto out;
4290
4291         rc = -EINVAL;
4292
4293         for (i = 0; i < nid_list.rlst_num_nids; i++) {
4294                 char nidenum[LNET_MAX_STR_LEN];
4295                 snprintf(nidenum, sizeof(nidenum), "nid-%d", i);
4296                 if (!cYAML_create_string(nids, nidenum,
4297                         libcfs_nid2str(nid_list.rlst_nid_array[i])))
4298                         goto out;
4299         }
4300
4301         snprintf(err_str, sizeof(err_str), "success\n");
4302
4303         rc = 0;
4304
4305 out:
4306         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
4307                 cYAML_free_tree(root);
4308         } else if (show_rc != NULL && *show_rc != NULL) {
4309                 struct cYAML *show_node;
4310                 /* find the net node, if one doesn't exist
4311                  * then insert one.  Otherwise add to the one there
4312                  */
4313                 show_node = cYAML_get_object_item(*show_rc, name);
4314                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
4315                         cYAML_insert_child(show_node, nids);
4316                         free(nids);
4317                         free(root);
4318                 } else if (show_node == NULL) {
4319                         cYAML_insert_sibling((*show_rc)->cy_child,
4320                                                 nids);
4321                         free(root);
4322                 } else {
4323                         cYAML_free_tree(root);
4324                 }
4325         } else {
4326                 *show_rc = root;
4327         }
4328
4329         cYAML_build_error(rc, seq_no, SHOW_CMD, name, err_str, err_rc);
4330
4331         return rc;
4332 }
4333
4334 int lustre_lnet_show_peer_debug_info(char *peer_nid, int seq_no,
4335                                      struct cYAML **err_rc)
4336 {
4337         struct libcfs_ioctl_data data;
4338         int rc;
4339         char err_str[LNET_MAX_STR_LEN] = "Error";
4340         lnet_nid_t pnid = LNET_NID_ANY;
4341
4342         if (!peer_nid) {
4343                 rc = LUSTRE_CFG_RC_BAD_PARAM;
4344                 snprintf(err_str, LNET_MAX_STR_LEN,
4345                          "--nid must be specified");
4346                 goto out;
4347         }
4348
4349         pnid = libcfs_str2nid(peer_nid);
4350         if (pnid == LNET_NID_ANY) {
4351                 rc = LUSTRE_CFG_RC_BAD_PARAM;
4352                 snprintf(err_str, LNET_MAX_STR_LEN,
4353                         "badly formatted primary NID: %s", peer_nid);
4354                 goto out;
4355         }
4356
4357         LIBCFS_IOC_INIT(data);
4358         data.ioc_net = LNET_NIDNET(pnid);
4359         data.ioc_nid = pnid;
4360
4361         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_PEER, &data);
4362
4363 out:
4364         if (rc != 0)
4365                 cYAML_build_error(rc, seq_no, "debug", "peer", err_str,
4366                                   err_rc);
4367
4368         return rc;
4369 }
4370
4371 int lustre_lnet_show_local_ni_recovq(int seq_no, struct cYAML **show_rc,
4372                                      struct cYAML **err_rc)
4373 {
4374         return show_recovery_queue(LNET_HEALTH_TYPE_LOCAL_NI, "local NI recovery",
4375                                    seq_no, show_rc, err_rc);
4376 }
4377
4378 int lustre_lnet_show_peer_ni_recovq(int seq_no, struct cYAML **show_rc,
4379                                     struct cYAML **err_rc)
4380 {
4381         return show_recovery_queue(LNET_HEALTH_TYPE_PEER_NI, "peer NI recovery",
4382                                    seq_no, show_rc, err_rc);
4383 }
4384
4385 int lustre_lnet_show_response_tracking(int seq_no, struct cYAML **show_rc,
4386                                        struct cYAML **err_rc)
4387 {
4388         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4389         char val[LNET_MAX_STR_LEN];
4390         int rsp_tracking = -1, l_errno = 0;
4391         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4392
4393         rc = read_sysfs_file(modparam_path, "lnet_response_tracking", val,
4394                              1, sizeof(val));
4395         if (rc) {
4396                 l_errno = -errno;
4397                 snprintf(err_str, sizeof(err_str),
4398                          "\"cannot get lnet_response_tracking value: %d\"", rc);
4399         } else {
4400                 rsp_tracking = atoi(val);
4401         }
4402
4403         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4404                                        "response_tracking", rsp_tracking,
4405                                        show_rc, err_rc, l_errno);
4406 }
4407
4408 int lustre_lnet_show_recovery_limit(int seq_no, struct cYAML **show_rc,
4409                                     struct cYAML **err_rc)
4410 {
4411         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4412         char val[LNET_MAX_STR_LEN];
4413         int recov_limit = -1, l_errno = 0;
4414         char err_str[LNET_MAX_STR_LEN];
4415
4416         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
4417
4418         rc = read_sysfs_file(modparam_path, "lnet_recovery_limit", val,
4419                              1, sizeof(val));
4420         if (rc) {
4421                 l_errno = -errno;
4422                 snprintf(err_str, sizeof(err_str),
4423                          "\"cannot get lnet_recovery_limit value: %d\"", rc);
4424         } else {
4425                 recov_limit = atoi(val);
4426         }
4427
4428         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4429                                        "recovery_limit", recov_limit,
4430                                        show_rc, err_rc, l_errno);
4431 }
4432
4433 int lustre_lnet_show_max_recovery_ping_interval(int seq_no,
4434                                                 struct cYAML **show_rc,
4435                                                 struct cYAML **err_rc)
4436 {
4437         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4438         char val[LNET_MAX_STR_LEN];
4439         int interval = -1, l_errno = 0;
4440         char err_str[LNET_MAX_STR_LEN];
4441
4442         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
4443
4444         rc = read_sysfs_file(modparam_path, "lnet_max_recovery_ping_interval",
4445                              val, 1, sizeof(val));
4446         if (rc) {
4447                 l_errno = -errno;
4448                 snprintf(err_str, sizeof(err_str),
4449                          "\"cannot get lnet_max_recovery_ping_interval value: %d\"",
4450                          rc);
4451         } else {
4452                 interval = atoi(val);
4453         }
4454
4455         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4456                                        "max_recovery_ping_interval", interval,
4457                                        show_rc, err_rc, l_errno);
4458 }
4459
4460
4461 int lustre_lnet_show_max_intf(int seq_no, struct cYAML **show_rc,
4462                               struct cYAML **err_rc)
4463 {
4464         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4465         char val[LNET_MAX_STR_LEN];
4466         int max_intf = -1, l_errno = 0;
4467         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4468
4469         rc = read_sysfs_file(modparam_path, "lnet_interfaces_max", val,
4470                              1, sizeof(val));
4471         if (rc) {
4472                 l_errno = -errno;
4473                 snprintf(err_str, sizeof(err_str),
4474                          "\"cannot get max interfaces: %d\"", rc);
4475         } else {
4476                 max_intf = atoi(val);
4477         }
4478
4479         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4480                                        "max_interfaces", max_intf, show_rc,
4481                                        err_rc, l_errno);
4482 }
4483
4484 int lustre_lnet_show_discovery(int seq_no, struct cYAML **show_rc,
4485                                struct cYAML **err_rc)
4486 {
4487         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4488         char val[LNET_MAX_STR_LEN];
4489         int discovery = -1, l_errno = 0;
4490         char err_str[LNET_MAX_STR_LEN]  = "\"out of memory\"";
4491
4492         rc = read_sysfs_file(modparam_path, "lnet_peer_discovery_disabled", val,
4493                              1, sizeof(val));
4494         if (rc) {
4495                 l_errno = -errno;
4496                 snprintf(err_str, sizeof(err_str),
4497                          "\"cannot get discovery setting: %d\"", rc);
4498         } else {
4499                 /*
4500                  * The kernel stores a discovery disabled value. User space
4501                  * shows whether discovery is enabled. So the value must be
4502                  * inverted.
4503                  */
4504                 discovery = !atoi(val);
4505         }
4506
4507         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4508                                        "discovery", discovery, show_rc,
4509                                        err_rc, l_errno);
4510 }
4511
4512 int lustre_lnet_show_drop_asym_route(int seq_no, struct cYAML **show_rc,
4513                                      struct cYAML **err_rc)
4514 {
4515         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4516         char val[LNET_MAX_STR_LEN];
4517         int drop_asym_route = -1, l_errno = 0;
4518         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4519
4520         rc = read_sysfs_file(modparam_path, "lnet_drop_asym_route", val,
4521                              1, sizeof(val));
4522         if (rc) {
4523                 l_errno = -errno;
4524                 snprintf(err_str, sizeof(err_str),
4525                          "\"cannot get drop asym route setting: %d\"", rc);
4526         } else {
4527                 drop_asym_route = atoi(val);
4528         }
4529
4530         return build_global_yaml_entry(err_str, sizeof(err_str), seq_no,
4531                                        "drop_asym_route", drop_asym_route,
4532                                        show_rc, err_rc, l_errno);
4533 }
4534
4535 int lustre_lnet_show_numa_range(int seq_no, struct cYAML **show_rc,
4536                                 struct cYAML **err_rc)
4537 {
4538         return ioctl_show_global_values(IOC_LIBCFS_GET_NUMA_RANGE, seq_no,
4539                                         "numa_range", show_rc, err_rc);
4540 }
4541
4542 int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc,
4543                            struct cYAML **err_rc)
4544 {
4545         struct lnet_ioctl_lnet_stats data;
4546         struct lnet_counters *cntrs;
4547         int rc;
4548         char err_str[LNET_MAX_STR_LEN] = "\"out of memory\"";
4549         struct cYAML *root = NULL, *stats = NULL;
4550
4551         LIBCFS_IOC_INIT_V2(data, st_hdr);
4552
4553         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LNET_STATS, &data);
4554         if (rc) {
4555                 snprintf(err_str,
4556                          sizeof(err_str),
4557                          "\"cannot get lnet statistics: %s\"",
4558                          strerror(-rc));
4559                 goto out;
4560         }
4561
4562         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
4563
4564         cntrs = &data.st_cntrs;
4565
4566         root = cYAML_create_object(NULL, NULL);
4567         if (!root)
4568                 goto out;
4569
4570         stats = cYAML_create_object(root, "statistics");
4571         if (!stats)
4572                 goto out;
4573
4574         if (!cYAML_create_number(stats, "msgs_alloc",
4575                                  cntrs->lct_common.lcc_msgs_alloc))
4576                 goto out;
4577
4578         if (!cYAML_create_number(stats, "msgs_max",
4579                                  cntrs->lct_common.lcc_msgs_max))
4580                 goto out;
4581
4582         if (!cYAML_create_number(stats, "rst_alloc",
4583                                  cntrs->lct_health.lch_rst_alloc))
4584                 goto out;
4585
4586         if (!cYAML_create_number(stats, "errors",
4587                                  cntrs->lct_common.lcc_errors))
4588                 goto out;
4589
4590         if (!cYAML_create_number(stats, "send_count",
4591                                  cntrs->lct_common.lcc_send_count))
4592                 goto out;
4593
4594         if (!cYAML_create_number(stats, "resend_count",
4595                                  cntrs->lct_health.lch_resend_count))
4596                 goto out;
4597
4598         if (!cYAML_create_number(stats, "response_timeout_count",
4599                                  cntrs->lct_health.lch_response_timeout_count))
4600                 goto out;
4601
4602         if (!cYAML_create_number(stats, "local_interrupt_count",
4603                                  cntrs->lct_health.lch_local_interrupt_count))
4604                 goto out;
4605
4606         if (!cYAML_create_number(stats, "local_dropped_count",
4607                                  cntrs->lct_health.lch_local_dropped_count))
4608                 goto out;
4609
4610         if (!cYAML_create_number(stats, "local_aborted_count",
4611                                  cntrs->lct_health.lch_local_aborted_count))
4612                 goto out;
4613
4614         if (!cYAML_create_number(stats, "local_no_route_count",
4615                                  cntrs->lct_health.lch_local_no_route_count))
4616                 goto out;
4617
4618         if (!cYAML_create_number(stats, "local_timeout_count",
4619                                  cntrs->lct_health.lch_local_timeout_count))
4620                 goto out;
4621
4622         if (!cYAML_create_number(stats, "local_error_count",
4623                                  cntrs->lct_health.lch_local_error_count))
4624                 goto out;
4625
4626         if (!cYAML_create_number(stats, "remote_dropped_count",
4627                                  cntrs->lct_health.lch_remote_dropped_count))
4628                 goto out;
4629
4630         if (!cYAML_create_number(stats, "remote_error_count",
4631                                  cntrs->lct_health.lch_remote_error_count))
4632                 goto out;
4633
4634         if (!cYAML_create_number(stats, "remote_timeout_count",
4635                                  cntrs->lct_health.lch_remote_timeout_count))
4636                 goto out;
4637
4638         if (!cYAML_create_number(stats, "network_timeout_count",
4639                                  cntrs->lct_health.lch_network_timeout_count))
4640                 goto out;
4641
4642         if (!cYAML_create_number(stats, "recv_count",
4643                                  cntrs->lct_common.lcc_recv_count))
4644                 goto out;
4645
4646         if (!cYAML_create_number(stats, "route_count",
4647                                  cntrs->lct_common.lcc_route_count))
4648                 goto out;
4649
4650         if (!cYAML_create_number(stats, "drop_count",
4651                                  cntrs->lct_common.lcc_drop_count))
4652                 goto out;
4653
4654         if (!cYAML_create_number(stats, "send_length",
4655                                  cntrs->lct_common.lcc_send_length))
4656                 goto out;
4657
4658         if (!cYAML_create_number(stats, "recv_length",
4659                                  cntrs->lct_common.lcc_recv_length))
4660                 goto out;
4661
4662         if (!cYAML_create_number(stats, "route_length",
4663                                  cntrs->lct_common.lcc_route_length))
4664                 goto out;
4665
4666         if (!cYAML_create_number(stats, "drop_length",
4667                                  cntrs->lct_common.lcc_drop_length))
4668                 goto out;
4669
4670         if (!show_rc)
4671                 cYAML_print_tree(root);
4672
4673         snprintf(err_str, sizeof(err_str), "\"success\"");
4674         rc = LUSTRE_CFG_RC_NO_ERR;
4675 out:
4676         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
4677                 cYAML_free_tree(root);
4678         } else if (show_rc != NULL && *show_rc != NULL) {
4679                 cYAML_insert_sibling((*show_rc)->cy_child,
4680                                         root->cy_child);
4681                 free(root);
4682         } else {
4683                 *show_rc = root;
4684         }
4685
4686         cYAML_build_error(rc, seq_no, SHOW_CMD, "statistics", err_str, err_rc);
4687
4688         return rc;
4689 }
4690
4691 int lustre_lnet_reset_stats(int seq_no, struct cYAML **err_rc)
4692 {
4693         struct libcfs_ioctl_data data;
4694         int rc = LUSTRE_CFG_RC_NO_ERR;
4695         int l_errno;
4696         char err_str[LNET_MAX_STR_LEN];
4697
4698         LIBCFS_IOC_INIT(data);
4699
4700         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_RESET_LNET_STATS, &data);
4701         if (rc) {
4702                 l_errno = errno;
4703                 snprintf(err_str,
4704                          sizeof(err_str),
4705                          "\"cannot reset lnet statistics: %s\"",
4706                          strerror(l_errno));
4707                 rc = -l_errno;
4708         } else {
4709                 snprintf(err_str, sizeof(err_str), "\"success\"");
4710                 rc = LUSTRE_CFG_RC_NO_ERR;
4711         }
4712
4713         cYAML_build_error(rc, seq_no, SHOW_CMD, "statistics", err_str, err_rc);
4714         return rc;
4715 }
4716
4717 typedef int (*cmd_handler_t)(struct cYAML *tree,
4718                              struct cYAML **show_rc,
4719                              struct cYAML **err_rc);
4720
4721 static int handle_yaml_config_route(struct cYAML *tree, struct cYAML **show_rc,
4722                                     struct cYAML **err_rc)
4723 {
4724         struct cYAML *net, *gw, *hop, *prio, *sen, *seq_no;
4725
4726         net = cYAML_get_object_item(tree, "net");
4727         gw = cYAML_get_object_item(tree, "gateway");
4728         hop = cYAML_get_object_item(tree, "hop");
4729         prio = cYAML_get_object_item(tree, "priority");
4730         sen = cYAML_get_object_item(tree, "health_sensitivity");
4731         seq_no = cYAML_get_object_item(tree, "seq_no");
4732
4733         return lustre_lnet_config_route((net) ? net->cy_valuestring : NULL,
4734                                         (gw) ? gw->cy_valuestring : NULL,
4735                                         (hop) ? hop->cy_valueint : -1,
4736                                         (prio) ? prio->cy_valueint : -1,
4737                                         (sen) ? sen->cy_valueint : -1,
4738                                         (seq_no) ? seq_no->cy_valueint : -1,
4739                                         err_rc);
4740 }
4741
4742 /*
4743  *    interfaces:
4744  *        0: <intf_name>['['<expr>']']
4745  *        1: <intf_name>['['<expr>']']
4746  */
4747 static int yaml_copy_intf_info(struct cYAML *intf_tree,
4748                                struct lnet_dlc_network_descr *nw_descr)
4749 {
4750         struct cYAML *child = NULL;
4751         int intf_num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
4752         struct lnet_dlc_intf_descr *intf_descr, *tmp;
4753
4754         if (intf_tree == NULL || nw_descr == NULL)
4755                 return LUSTRE_CFG_RC_BAD_PARAM;
4756
4757         /* now grab all the interfaces and their cpts */
4758         child = intf_tree->cy_child;
4759         while (child != NULL) {
4760                 if (child->cy_valuestring == NULL) {
4761                         child = child->cy_next;
4762                         continue;
4763                 }
4764
4765                 if (strlen(child->cy_valuestring) >= LNET_MAX_STR_LEN)
4766                         goto failed;
4767
4768                 rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist,
4769                                                 child->cy_valuestring,
4770                                                 strlen(child->cy_valuestring));
4771                 if (rc != LUSTRE_CFG_RC_NO_ERR)
4772                         goto failed;
4773
4774                 intf_num++;
4775                 child = child->cy_next;
4776         }
4777
4778         if (intf_num == 0)
4779                 return LUSTRE_CFG_RC_MISSING_PARAM;
4780
4781         return intf_num;
4782
4783 failed:
4784         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
4785                                  intf_on_network) {
4786                 list_del(&intf_descr->intf_on_network);
4787                 free_intf_descr(intf_descr);
4788         }
4789
4790         return rc;
4791 }
4792
4793 static bool
4794 yaml_extract_cmn_tunables(struct cYAML *tree,
4795                           struct lnet_ioctl_config_lnd_cmn_tunables *tunables)
4796 {
4797         struct cYAML *tun, *item;
4798
4799         tun = cYAML_get_object_item(tree, "tunables");
4800         if (tun != NULL) {
4801                 item = cYAML_get_object_item(tun, "peer_timeout");
4802                 if (item != NULL)
4803                         tunables->lct_peer_timeout = item->cy_valueint;
4804                 else
4805                         tunables->lct_peer_timeout = -1;
4806                 item = cYAML_get_object_item(tun, "peer_credits");
4807                 if (item != NULL)
4808                         tunables->lct_peer_tx_credits = item->cy_valueint;
4809                 item = cYAML_get_object_item(tun, "peer_buffer_credits");
4810                 if (item != NULL)
4811                         tunables->lct_peer_rtr_credits = item->cy_valueint;
4812                 item = cYAML_get_object_item(tun, "credits");
4813                 if (item != NULL)
4814                         tunables->lct_max_tx_credits = item->cy_valueint;
4815
4816                 return true;
4817         }
4818
4819         return false;
4820 }
4821
4822 static bool
4823 yaml_extract_tunables(struct cYAML *tree,
4824                       struct lnet_ioctl_config_lnd_tunables *tunables,
4825                       __u32 net_type)
4826 {
4827         bool rc;
4828
4829         rc = yaml_extract_cmn_tunables(tree, &tunables->lt_cmn);
4830
4831         if (!rc)
4832                 return rc;
4833
4834         lustre_yaml_extract_lnd_tunables(tree, net_type,
4835                                          &tunables->lt_tun);
4836
4837         return rc;
4838 }
4839
4840 static void
4841 yaml_extract_cpt(struct cYAML *tree,
4842                       struct cfs_expr_list **global_cpts)
4843 {
4844         int rc;
4845         struct cYAML *smp;
4846
4847         smp = cYAML_get_object_item(tree, "CPT");
4848         if (smp != NULL) {
4849                 rc = cfs_expr_list_parse(smp->cy_valuestring,
4850                                          strlen(smp->cy_valuestring),
4851                                          0, UINT_MAX, global_cpts);
4852                 if (rc != 0)
4853                         *global_cpts = NULL;
4854         }
4855 }
4856
4857 /*
4858  * net:
4859  *    - net type: <net>[<NUM>]
4860   *      local NI(s):
4861  *        - nid: <ip>@<net>[<NUM>]
4862  *          status: up
4863  *          interfaces:
4864  *               0: <intf_name>['['<expr>']']
4865  *               1: <intf_name>['['<expr>']']
4866  *        tunables:
4867  *               peer_timeout: <NUM>
4868  *               peer_credits: <NUM>
4869  *               peer_buffer_credits: <NUM>
4870  *               credits: <NUM>
4871 *         lnd tunables:
4872  *               peercredits_hiw: <NUM>
4873  *               map_on_demand: <NUM>
4874  *               concurrent_sends: <NUM>
4875  *               fmr_pool_size: <NUM>
4876  *               fmr_flush_trigger: <NUM>
4877  *               fmr_cache: <NUM>
4878  *
4879  * At least one interface is required. If no interfaces are provided the
4880  * network interface can not be configured.
4881  */
4882 static int handle_yaml_config_ni(struct cYAML *tree, struct cYAML **show_rc,
4883                                  struct cYAML **err_rc)
4884 {
4885         struct cYAML *net, *intf, *seq_no, *ip2net = NULL, *local_nis = NULL,
4886                      *item = NULL;
4887         int num_entries = 0, rc;
4888         struct lnet_dlc_network_descr nw_descr;
4889         struct cfs_expr_list *global_cpts = NULL;
4890         struct lnet_ioctl_config_lnd_tunables tunables;
4891         bool found = false;
4892
4893         memset(&tunables, 0, sizeof(tunables));
4894         /* Use LND defaults */
4895         tunables.lt_cmn.lct_peer_timeout = -1;
4896         tunables.lt_cmn.lct_peer_tx_credits = -1;
4897         tunables.lt_cmn.lct_peer_rtr_credits = -1;
4898         tunables.lt_cmn.lct_max_tx_credits = -1;
4899
4900         INIT_LIST_HEAD(&nw_descr.network_on_rule);
4901         INIT_LIST_HEAD(&nw_descr.nw_intflist);
4902
4903         ip2net = cYAML_get_object_item(tree, "ip2net");
4904         net = cYAML_get_object_item(tree, "net type");
4905         if (net)
4906                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
4907         else
4908                 nw_descr.nw_id = LOLND;
4909
4910         /*
4911          * if neither net nor ip2nets are present, then we can not
4912          * configure the network.
4913          */
4914         if (!net && !ip2net)
4915                 return LUSTRE_CFG_RC_MISSING_PARAM;
4916
4917         local_nis = cYAML_get_object_item(tree, "local NI(s)");
4918         if (local_nis == NULL)
4919                 return LUSTRE_CFG_RC_MISSING_PARAM;
4920
4921         if (!cYAML_is_sequence(local_nis))
4922                 return LUSTRE_CFG_RC_BAD_PARAM;
4923
4924         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
4925                 intf = cYAML_get_object_item(item, "interfaces");
4926                 if (intf == NULL)
4927                         continue;
4928                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
4929                 if (num_entries <= 0) {
4930                         cYAML_build_error(num_entries, -1, "ni", "add",
4931                                         "bad interface list",
4932                                         err_rc);
4933                         return LUSTRE_CFG_RC_BAD_PARAM;
4934                 }
4935         }
4936
4937         found = yaml_extract_tunables(tree, &tunables,
4938                                       LNET_NETTYP(nw_descr.nw_id));
4939         yaml_extract_cpt(tree, &global_cpts);
4940         seq_no = cYAML_get_object_item(tree, "seq_no");
4941
4942         rc = lustre_lnet_config_ni(&nw_descr, global_cpts,
4943                                    (ip2net) ? ip2net->cy_valuestring : NULL,
4944                                    (found) ? &tunables : NULL,
4945                                    (seq_no) ? seq_no->cy_valueint : -1,
4946                                    err_rc);
4947
4948         if (global_cpts != NULL)
4949                 cfs_expr_list_free(global_cpts);
4950
4951         return rc;
4952 }
4953
4954 /*
4955  * ip2nets:
4956  *  - net-spec: <tcp|o2ib|gni>[NUM]
4957  *    interfaces:
4958  *        0: <intf name>['['<expr>']']
4959  *        1: <intf name>['['<expr>']']
4960  *    ip-range:
4961  *        0: <expr.expr.expr.expr>
4962  *        1: <expr.expr.expr.expr>
4963  */
4964 static int handle_yaml_config_ip2nets(struct cYAML *tree,
4965                                       struct cYAML **show_rc,
4966                                       struct cYAML **err_rc)
4967 {
4968         struct cYAML *net, *ip_range, *item = NULL, *intf = NULL,
4969                      *seq_no = NULL;
4970         struct lustre_lnet_ip2nets ip2nets;
4971         struct lustre_lnet_ip_range_descr *ip_range_descr = NULL,
4972                                           *tmp = NULL;
4973         int rc = LUSTRE_CFG_RC_NO_ERR;
4974         struct cfs_expr_list *global_cpts = NULL;
4975         struct cfs_expr_list *el, *el_tmp;
4976         struct lnet_ioctl_config_lnd_tunables tunables;
4977         struct lnet_dlc_intf_descr *intf_descr, *intf_tmp;
4978         bool found = false;
4979
4980         memset(&tunables, 0, sizeof(tunables));
4981
4982         /* initialize all lists */
4983         INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
4984         INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
4985         INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
4986
4987         net = cYAML_get_object_item(tree, "net-spec");
4988         if (net == NULL)
4989                 return LUSTRE_CFG_RC_BAD_PARAM;
4990
4991         if (net != NULL && net->cy_valuestring == NULL)
4992                 return LUSTRE_CFG_RC_BAD_PARAM;
4993
4994         /* assign the network id */
4995         ip2nets.ip2nets_net.nw_id = libcfs_str2net(net->cy_valuestring);
4996         if (ip2nets.ip2nets_net.nw_id == LNET_NET_ANY)
4997                 return LUSTRE_CFG_RC_BAD_PARAM;
4998
4999         seq_no = cYAML_get_object_item(tree, "seq_no");
5000
5001         intf = cYAML_get_object_item(tree, "interfaces");
5002         if (intf != NULL) {
5003                 rc = yaml_copy_intf_info(intf, &ip2nets.ip2nets_net);
5004                 if (rc <= 0)
5005                         return LUSTRE_CFG_RC_BAD_PARAM;
5006         }
5007
5008         ip_range = cYAML_get_object_item(tree, "ip-range");
5009         if (ip_range != NULL) {
5010                 item = ip_range->cy_child;
5011                 while (item != NULL) {
5012                         if (item->cy_valuestring == NULL) {
5013                                 item = item->cy_next;
5014                                 continue;
5015                         }
5016
5017                         rc = lustre_lnet_add_ip_range(&ip2nets.ip2nets_ip_ranges,
5018                                                       item->cy_valuestring);
5019
5020                         if (rc != LUSTRE_CFG_RC_NO_ERR)
5021                                 goto out;
5022
5023                         item = item->cy_next;
5024                 }
5025         }
5026
5027         found = yaml_extract_tunables(tree, &tunables,
5028                                       LNET_NETTYP(ip2nets.ip2nets_net.nw_id));
5029         yaml_extract_cpt(tree, &global_cpts);
5030
5031         rc = lustre_lnet_config_ip2nets(&ip2nets,
5032                         (found) ? &tunables : NULL,
5033                         global_cpts,
5034                         (seq_no) ? seq_no->cy_valueint : -1,
5035                         err_rc);
5036
5037         if (global_cpts != NULL)
5038                 cfs_expr_list_free(global_cpts);
5039
5040         /*
5041          * don't stop because there was no match. Continue processing the
5042          * rest of the rules. If non-match then nothing is configured
5043          */
5044         if (rc == LUSTRE_CFG_RC_NO_MATCH)
5045                 rc = LUSTRE_CFG_RC_NO_ERR;
5046 out:
5047         list_for_each_entry_safe(intf_descr, intf_tmp,
5048                                  &ip2nets.ip2nets_net.nw_intflist,
5049                                  intf_on_network) {
5050                 list_del(&intf_descr->intf_on_network);
5051                 free_intf_descr(intf_descr);
5052         }
5053
5054         list_for_each_entry_safe(ip_range_descr, tmp,
5055                                  &ip2nets.ip2nets_ip_ranges,
5056                                  ipr_entry) {
5057                 list_del(&ip_range_descr->ipr_entry);
5058                 list_for_each_entry_safe(el, el_tmp, &ip_range_descr->ipr_expr,
5059                                          el_link) {
5060                         list_del(&el->el_link);
5061                         cfs_expr_list_free(el);
5062                 }
5063                 free(ip_range_descr);
5064         }
5065
5066         return rc;
5067 }
5068
5069 static int handle_yaml_del_ni(struct cYAML *tree, struct cYAML **show_rc,
5070                               struct cYAML **err_rc)
5071 {
5072         struct cYAML *net = NULL, *intf = NULL, *seq_no = NULL, *item = NULL,
5073                      *local_nis = NULL;
5074         int num_entries, rc;
5075         struct lnet_dlc_network_descr nw_descr;
5076
5077         INIT_LIST_HEAD(&nw_descr.network_on_rule);
5078         INIT_LIST_HEAD(&nw_descr.nw_intflist);
5079
5080         net = cYAML_get_object_item(tree, "net type");
5081         if (net != NULL)
5082                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
5083
5084         local_nis = cYAML_get_object_item(tree, "local NI(s)");
5085         if (local_nis == NULL)
5086                 return LUSTRE_CFG_RC_MISSING_PARAM;
5087
5088         if (!cYAML_is_sequence(local_nis))
5089                 return LUSTRE_CFG_RC_BAD_PARAM;
5090
5091         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
5092                 intf = cYAML_get_object_item(item, "interfaces");
5093                 if (intf == NULL)
5094                         continue;
5095                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
5096                 if (num_entries <= 0) {
5097                         cYAML_build_error(num_entries, -1, "ni", "add",
5098                                         "bad interface list",
5099                                         err_rc);
5100                         return LUSTRE_CFG_RC_BAD_PARAM;
5101                 }
5102         }
5103
5104         seq_no = cYAML_get_object_item(tree, "seq_no");
5105
5106         rc = lustre_lnet_del_ni((net) ? &nw_descr : NULL,
5107                                 (seq_no) ? seq_no->cy_valueint : -1,
5108                                 err_rc);
5109
5110         return rc;
5111 }
5112
5113 /* Create a nidstring parseable by the nidstrings library from the nid
5114  * information encoded in the CYAML structure.
5115  * NOTE: Caller must free memory allocated to nidstr
5116  */
5117 static int yaml_nids2nidstr(struct cYAML *nids_entry, char **nidstr,
5118                             char *prim_nid, int cmd)
5119 {
5120         int num_strs = 0, rc;
5121         size_t buf_size, buf_pos, nidstr_len = 0;
5122         char *buffer;
5123         struct cYAML *child = NULL, *entry = NULL;
5124
5125         if (cYAML_is_sequence(nids_entry)) {
5126                 while (cYAML_get_next_seq_item(nids_entry, &child)) {
5127                         entry = cYAML_get_object_item(child, "nid");
5128                         /* don't count an empty entry */
5129                         if (!entry || !entry->cy_valuestring)
5130                                 continue;
5131
5132                         if (prim_nid &&
5133                             (strcmp(entry->cy_valuestring, prim_nid) == 0)) {
5134                                 if (cmd == LNETCTL_DEL_CMD) {
5135                                         /*
5136                                          * primary nid is present in the list of
5137                                          * nids so that means we want to delete
5138                                          * the entire peer, so no need to go
5139                                          * further. Just delete the entire peer.
5140                                          */
5141                                         return LUSTRE_CFG_RC_NO_ERR;
5142                                 } else {
5143                                         continue;
5144                                 }
5145                         }
5146
5147                         /*
5148                          * + 1 for the space separating each string, and
5149                          * accounts for the terminating null char
5150                          */
5151                         nidstr_len += strlen(entry->cy_valuestring) + 1;
5152                         num_strs++;
5153                 }
5154         }
5155
5156         if (num_strs == 0 && !prim_nid)
5157                 return LUSTRE_CFG_RC_MISSING_PARAM;
5158         else if (num_strs == 0) /* Only the primary nid was given to add/del */
5159                 return LUSTRE_CFG_RC_NO_ERR;
5160
5161         buffer = malloc(nidstr_len);
5162         if (!buffer)
5163                 return LUSTRE_CFG_RC_OUT_OF_MEM;
5164
5165         /* now grab all the nids */
5166         rc = 0;
5167         buf_pos = 0;
5168         buf_size = nidstr_len;
5169         child = NULL;
5170         while (cYAML_get_next_seq_item(nids_entry, &child)) {
5171                 entry = cYAML_get_object_item(child, "nid");
5172                 if (!entry || !entry->cy_valuestring)
5173                         continue;
5174
5175                 if (prim_nid &&
5176                     (strcmp(entry->cy_valuestring, prim_nid) == 0))
5177                         continue;
5178
5179                 if (buf_pos) {
5180                         rc = snprintf(buffer + buf_pos, buf_size, " ");
5181                         buf_pos += (rc < buf_size) ? rc : buf_size;
5182                         buf_size = nidstr_len - buf_pos;
5183                 }
5184
5185                 rc = snprintf(buffer + buf_pos, buf_size, "%s",
5186                               entry->cy_valuestring);
5187                 buf_pos += (rc < buf_size) ? rc : buf_size;
5188                 buf_size = nidstr_len - buf_pos;
5189         }
5190
5191         *nidstr = buffer;
5192
5193         return LUSTRE_CFG_RC_NO_ERR;
5194 }
5195
5196 static int handle_yaml_peer_common(struct cYAML *tree, struct cYAML **show_rc,
5197                                    struct cYAML **err_rc, int cmd)
5198 {
5199         int rc, num_nids = 0, seqn;
5200         bool mr_value = false;
5201         char *nidstr = NULL, *prim_nidstr;
5202         char err_str[LNET_MAX_STR_LEN];
5203         struct cYAML *seq_no, *prim_nid, *mr, *peer_nis;
5204         lnet_nid_t lnet_nidlist[LNET_MAX_NIDS_PER_PEER];
5205         lnet_nid_t pnid = LNET_NID_ANY;
5206         int force = 0;
5207
5208         seq_no = cYAML_get_object_item(tree, "seq_no");
5209         seqn = seq_no ? seq_no->cy_valueint : -1;
5210
5211         prim_nid = cYAML_get_object_item(tree, "primary nid");
5212         peer_nis = cYAML_get_object_item(tree, "peer ni");
5213         if (!prim_nid) {
5214                 rc = LUSTRE_CFG_RC_BAD_PARAM;
5215                 snprintf(err_str, LNET_MAX_STR_LEN,
5216                          "\"primary nid\" must be specified");
5217                 goto failed;
5218         }
5219
5220         prim_nidstr = prim_nid->cy_valuestring;
5221
5222         /* if the provided primary NID is bad, no need to go any further */
5223         pnid = libcfs_str2nid(prim_nidstr);
5224         if (pnid == LNET_NID_ANY) {
5225                 rc = LUSTRE_CFG_RC_BAD_PARAM;
5226                 snprintf(err_str, LNET_MAX_STR_LEN,
5227                         "badly formatted primary NID: %s", prim_nidstr);
5228                 goto failed;
5229         }
5230
5231         rc = yaml_nids2nidstr(peer_nis, &nidstr, prim_nidstr, cmd);
5232         if (rc == LUSTRE_CFG_RC_MISSING_PARAM) {
5233                 snprintf(err_str, LNET_MAX_STR_LEN,
5234                          "No nids defined in YAML block");
5235                 goto failed;
5236         } else if (rc == LUSTRE_CFG_RC_OUT_OF_MEM) {
5237                 snprintf(err_str, LNET_MAX_STR_LEN, "out of memory");
5238                 goto failed;
5239         } else if (rc != LUSTRE_CFG_RC_NO_ERR) {
5240                 snprintf(err_str, LNET_MAX_STR_LEN,
5241                          "Unrecognized error %d", rc);
5242                 goto failed;
5243         }
5244
5245         num_nids = 0;
5246         if (nidstr) {
5247                 num_nids = lustre_lnet_parse_nidstr(nidstr, lnet_nidlist,
5248                                                     LNET_MAX_NIDS_PER_PEER,
5249                                                     err_str);
5250                 if (num_nids < 0) {
5251                         rc = num_nids;
5252                         goto failed;
5253                 }
5254         }
5255
5256         if (cmd == LNETCTL_ADD_CMD) {
5257                 mr = cYAML_get_object_item(tree, "Multi-Rail");
5258                 mr_value = true;
5259                 if (mr && mr->cy_valuestring) {
5260                         if (strcmp(mr->cy_valuestring, "False") == 0)
5261                                 mr_value = false;
5262                         else if (strcmp(mr->cy_valuestring, "True") != 0) {
5263                                 rc = LUSTRE_CFG_RC_BAD_PARAM;
5264                                 snprintf(err_str, LNET_MAX_STR_LEN,
5265                                          "Multi-Rail must be set to \"True\" or \"False\" found \"%s\"",
5266                                          mr->cy_valuestring);
5267                                 goto failed;
5268                         }
5269                 }
5270         }
5271
5272         rc = lustre_lnet_mod_peer_nidlist(pnid, lnet_nidlist, cmd,
5273                                           num_nids, mr_value, force,
5274                                           seqn, err_rc);
5275
5276 failed:
5277         if (nidstr)
5278                 free(nidstr);
5279
5280         if (rc != LUSTRE_CFG_RC_NO_ERR)
5281                 cYAML_build_error(rc, seqn, "peer",
5282                                   cmd == LNETCTL_ADD_CMD ? ADD_CMD : DEL_CMD,
5283                                   err_str, err_rc);
5284
5285         return rc;
5286 }
5287
5288 static int handle_yaml_config_peer(struct cYAML *tree, struct cYAML **show_rc,
5289                                    struct cYAML **err_rc)
5290 {
5291         return handle_yaml_peer_common(tree, show_rc, err_rc, LNETCTL_ADD_CMD);
5292 }
5293
5294 static int handle_yaml_del_peer(struct cYAML *tree, struct cYAML **show_rc,
5295                                 struct cYAML **err_rc)
5296 {
5297         return handle_yaml_peer_common(tree, show_rc, err_rc, LNETCTL_DEL_CMD);
5298 }
5299
5300 static int handle_yaml_config_buffers(struct cYAML *tree,
5301                                       struct cYAML **show_rc,
5302                                       struct cYAML **err_rc)
5303 {
5304         int rc;
5305         struct cYAML *tiny, *small, *large, *seq_no;
5306
5307         tiny = cYAML_get_object_item(tree, "tiny");
5308         small = cYAML_get_object_item(tree, "small");
5309         large = cYAML_get_object_item(tree, "large");
5310         seq_no = cYAML_get_object_item(tree, "seq_no");
5311
5312         rc = lustre_lnet_config_buffers((tiny) ? tiny->cy_valueint : -1,
5313                                         (small) ? small->cy_valueint : -1,
5314                                         (large) ? large->cy_valueint : -1,
5315                                         (seq_no) ? seq_no->cy_valueint : -1,
5316                                         err_rc);
5317
5318         return rc;
5319 }
5320
5321 static int handle_yaml_config_routing(struct cYAML *tree,
5322                                       struct cYAML **show_rc,
5323                                       struct cYAML **err_rc)
5324 {
5325         int rc = LUSTRE_CFG_RC_NO_ERR;
5326         struct cYAML *seq_no, *enable;
5327
5328         seq_no = cYAML_get_object_item(tree, "seq_no");
5329         enable = cYAML_get_object_item(tree, "enable");
5330
5331         if (enable) {
5332                 rc = lustre_lnet_enable_routing(enable->cy_valueint,
5333                                                 (seq_no) ?
5334                                                     seq_no->cy_valueint : -1,
5335                                                 err_rc);
5336         }
5337
5338         return rc;
5339 }
5340
5341 static int handle_yaml_del_route(struct cYAML *tree, struct cYAML **show_rc,
5342                                  struct cYAML **err_rc)
5343 {
5344         struct cYAML *net;
5345         struct cYAML *gw;
5346         struct cYAML *seq_no;
5347
5348         net = cYAML_get_object_item(tree, "net");
5349         gw = cYAML_get_object_item(tree, "gateway");
5350         seq_no = cYAML_get_object_item(tree, "seq_no");
5351
5352         return lustre_lnet_del_route((net) ? net->cy_valuestring : NULL,
5353                                      (gw) ? gw->cy_valuestring : NULL,
5354                                      (seq_no) ? seq_no->cy_valueint : -1,
5355                                      err_rc);
5356 }
5357
5358 static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
5359                                    struct cYAML **err_rc)
5360 {
5361         struct cYAML *seq_no;
5362
5363         seq_no = cYAML_get_object_item(tree, "seq_no");
5364
5365         return lustre_lnet_enable_routing(0, (seq_no) ?
5366                                                 seq_no->cy_valueint : -1,
5367                                         err_rc);
5368 }
5369
5370 static int handle_yaml_show_route(struct cYAML *tree, struct cYAML **show_rc,
5371                                   struct cYAML **err_rc)
5372 {
5373         struct cYAML *net;
5374         struct cYAML *gw;
5375         struct cYAML *hop;
5376         struct cYAML *prio;
5377         struct cYAML *detail;
5378         struct cYAML *seq_no;
5379
5380         net = cYAML_get_object_item(tree, "net");
5381         gw = cYAML_get_object_item(tree, "gateway");
5382         hop = cYAML_get_object_item(tree, "hop");
5383         prio = cYAML_get_object_item(tree, "priority");
5384         detail = cYAML_get_object_item(tree, "detail");
5385         seq_no = cYAML_get_object_item(tree, "seq_no");
5386
5387         return lustre_lnet_show_route((net) ? net->cy_valuestring : NULL,
5388                                       (gw) ? gw->cy_valuestring : NULL,
5389                                       (hop) ? hop->cy_valueint : -1,
5390                                       (prio) ? prio->cy_valueint : -1,
5391                                       (detail) ? detail->cy_valueint : 0,
5392                                       (seq_no) ? seq_no->cy_valueint : -1,
5393                                       show_rc, err_rc, false);
5394 }
5395
5396 static int handle_yaml_show_net(struct cYAML *tree, struct cYAML **show_rc,
5397                                 struct cYAML **err_rc)
5398 {
5399         struct cYAML *net, *detail, *seq_no;
5400
5401         net = cYAML_get_object_item(tree, "net type");
5402         detail = cYAML_get_object_item(tree, "detail");
5403         seq_no = cYAML_get_object_item(tree, "seq_no");
5404
5405         return lustre_lnet_show_net((net) ? net->cy_valuestring : NULL,
5406                                     (detail) ? detail->cy_valueint : 0,
5407                                     (seq_no) ? seq_no->cy_valueint : -1,
5408                                     show_rc, err_rc, false);
5409 }
5410
5411 static int handle_yaml_show_routing(struct cYAML *tree, struct cYAML **show_rc,
5412                                     struct cYAML **err_rc)
5413 {
5414         struct cYAML *seq_no;
5415
5416         seq_no = cYAML_get_object_item(tree, "seq_no");
5417
5418         return lustre_lnet_show_routing((seq_no) ? seq_no->cy_valueint : -1,
5419                                         show_rc, err_rc, false);
5420 }
5421
5422 static int handle_yaml_show_peers(struct cYAML *tree, struct cYAML **show_rc,
5423                                   struct cYAML **err_rc)
5424 {
5425         struct cYAML *seq_no, *nid, *detail;
5426
5427         seq_no = cYAML_get_object_item(tree, "seq_no");
5428         detail = cYAML_get_object_item(tree, "detail");
5429         nid = cYAML_get_object_item(tree, "nid");
5430
5431         return lustre_lnet_show_peer((nid) ? nid->cy_valuestring : NULL,
5432                                      (detail) ? detail->cy_valueint : 0,
5433                                      (seq_no) ? seq_no->cy_valueint : -1,
5434                                      show_rc, err_rc, false);
5435 }
5436
5437 static int handle_yaml_show_stats(struct cYAML *tree, struct cYAML **show_rc,
5438                                   struct cYAML **err_rc)
5439 {
5440         struct cYAML *seq_no;
5441
5442         seq_no = cYAML_get_object_item(tree, "seq_no");
5443
5444         return lustre_lnet_show_stats((seq_no) ? seq_no->cy_valueint : -1,
5445                                       show_rc, err_rc);
5446 }
5447
5448 static int handle_yaml_config_numa(struct cYAML *tree, struct cYAML **show_rc,
5449                                   struct cYAML **err_rc)
5450 {
5451         struct cYAML *seq_no, *range;
5452
5453         seq_no = cYAML_get_object_item(tree, "seq_no");
5454         range = cYAML_get_object_item(tree, "range");
5455
5456         return lustre_lnet_config_numa_range(range ? range->cy_valueint : -1,
5457                                              seq_no ? seq_no->cy_valueint : -1,
5458                                              err_rc);
5459 }
5460
5461 static int handle_yaml_del_numa(struct cYAML *tree, struct cYAML **show_rc,
5462                                struct cYAML **err_rc)
5463 {
5464         struct cYAML *seq_no;
5465
5466         seq_no = cYAML_get_object_item(tree, "seq_no");
5467
5468         return lustre_lnet_config_numa_range(0, seq_no ? seq_no->cy_valueint : -1,
5469                                              err_rc);
5470 }
5471
5472 static int handle_yaml_show_numa(struct cYAML *tree, struct cYAML **show_rc,
5473                                 struct cYAML **err_rc)
5474 {
5475         struct cYAML *seq_no;
5476
5477         seq_no = cYAML_get_object_item(tree, "seq_no");
5478
5479         return lustre_lnet_show_numa_range(seq_no ? seq_no->cy_valueint : -1,
5480                                            show_rc, err_rc);
5481 }
5482
5483 static int handle_yaml_del_udsp(struct cYAML *tree, struct cYAML **show_rc,
5484                                 struct cYAML **err_rc)
5485 {
5486         struct cYAML *seq_no, *idx;
5487
5488         seq_no = cYAML_get_object_item(tree, "seq_no");
5489         idx = cYAML_get_object_item(tree, "idx");
5490
5491         return lustre_lnet_del_udsp(idx ? idx->cy_valueint : -1,
5492                                     seq_no ? seq_no->cy_valueint : -1,
5493                                     err_rc);
5494 }
5495
5496 static int handle_yaml_config_udsp(struct cYAML *tree, struct cYAML **show_rc,
5497                                    struct cYAML **err_rc)
5498 {
5499         struct cYAML *seq_no, *src, *rte, *dst, *prio, *idx;
5500         union lnet_udsp_action action;
5501
5502         seq_no = cYAML_get_object_item(tree, "seq_no");
5503         src = cYAML_get_object_item(tree, "src");
5504         rte = cYAML_get_object_item(tree, "rte");
5505         dst = cYAML_get_object_item(tree, "dst");
5506         prio = cYAML_get_object_item(tree, "priority");
5507         idx = cYAML_get_object_item(tree, "idx");
5508
5509         action.udsp_priority = prio ? prio->cy_valueint : -1;
5510
5511         return lustre_lnet_add_udsp(src ? src->cy_valuestring : NULL,
5512                                     dst ? dst->cy_valuestring : NULL,
5513                                     rte ? rte->cy_valuestring : NULL,
5514                                     prio ? "priority" : "",
5515                                     &action,
5516                                     idx ? idx->cy_valueint : -1,
5517                                     seq_no ? seq_no->cy_valueint : -1,
5518                                     err_rc);
5519 }
5520
5521 static int handle_yaml_show_udsp(struct cYAML *tree, struct cYAML **show_rc,
5522                                  struct cYAML **err_rc)
5523 {
5524         struct cYAML *seq_no;
5525         struct cYAML *idx;
5526
5527         seq_no = cYAML_get_object_item(tree, "seq_no");
5528         idx = cYAML_get_object_item(tree, "idx");
5529
5530         return lustre_lnet_show_udsp(idx ? idx->cy_valueint : -1,
5531                                      seq_no ? seq_no->cy_valueint : -1,
5532                                      show_rc, err_rc);
5533 }
5534
5535 static int handle_yaml_config_global_settings(struct cYAML *tree,
5536                                               struct cYAML **show_rc,
5537                                               struct cYAML **err_rc)
5538 {
5539         struct cYAML *max_intf, *numa, *discovery, *retry, *tto, *seq_no,
5540                      *sen, *recov, *rsen, *drop_asym_route, *rsp_tracking,
5541                      *recov_limit;
5542         int rc = 0;
5543
5544         seq_no = cYAML_get_object_item(tree, "seq_no");
5545         max_intf = cYAML_get_object_item(tree, "max_interfaces");
5546         if (!max_intf) /* try legacy name */
5547                 max_intf = cYAML_get_object_item(tree, "max_intf");
5548         if (max_intf)
5549                 rc = lustre_lnet_config_max_intf(max_intf->cy_valueint,
5550                                                  seq_no ? seq_no->cy_valueint
5551                                                         : -1,
5552                                                  err_rc);
5553
5554         numa = cYAML_get_object_item(tree, "numa_range");
5555         if (numa)
5556                 rc = lustre_lnet_config_numa_range(numa->cy_valueint,
5557                                                    seq_no ? seq_no->cy_valueint
5558                                                         : -1,
5559                                                    err_rc);
5560
5561         discovery = cYAML_get_object_item(tree, "discovery");
5562         if (discovery)
5563                 rc = lustre_lnet_config_discovery(discovery->cy_valueint,
5564                                                   seq_no ? seq_no->cy_valueint
5565                                                         : -1,
5566                                                   err_rc);
5567
5568         drop_asym_route = cYAML_get_object_item(tree, "drop_asym_route");
5569         if (drop_asym_route)
5570                 rc = lustre_lnet_config_drop_asym_route(
5571                         drop_asym_route->cy_valueint,
5572                         seq_no ? seq_no->cy_valueint : -1,
5573                         err_rc);
5574
5575         retry = cYAML_get_object_item(tree, "retry_count");
5576         if (retry)
5577                 rc = lustre_lnet_config_retry_count(retry->cy_valueint,
5578                                                     seq_no ? seq_no->cy_valueint
5579                                                         : -1,
5580                                                     err_rc);
5581
5582         tto = cYAML_get_object_item(tree, "transaction_timeout");
5583         if (tto)
5584                 rc = lustre_lnet_config_transaction_to(tto->cy_valueint,
5585                                                        seq_no ? seq_no->cy_valueint
5586                                                                 : -1,
5587                                                        err_rc);
5588
5589         sen = cYAML_get_object_item(tree, "health_sensitivity");
5590         if (sen)
5591                 rc = lustre_lnet_config_hsensitivity(sen->cy_valueint,
5592                                                      seq_no ? seq_no->cy_valueint
5593                                                         : -1,
5594                                                      err_rc);
5595
5596         recov = cYAML_get_object_item(tree, "recovery_interval");
5597         if (recov)
5598                 rc = lustre_lnet_config_recov_intrv(recov->cy_valueint,
5599                                                     seq_no ? seq_no->cy_valueint
5600                                                         : -1,
5601                                                     err_rc);
5602
5603         rsen = cYAML_get_object_item(tree, "router_sensitivity");
5604         if (rsen)
5605                 rc = lustre_lnet_config_rtr_sensitivity(rsen->cy_valueint,
5606                                                      seq_no ? seq_no->cy_valueint
5607                                                         : -1,
5608                                                      err_rc);
5609
5610         rsp_tracking = cYAML_get_object_item(tree, "response_tracking");
5611         if (rsp_tracking)
5612                 rc = lustre_lnet_config_response_tracking(rsp_tracking->cy_valueint,
5613                                                      seq_no ? seq_no->cy_valueint
5614                                                         : -1,
5615                                                      err_rc);
5616
5617         recov_limit = cYAML_get_object_item(tree, "recovery_limit");
5618         if (recov_limit)
5619                 rc = lustre_lnet_config_recovery_limit(recov_limit->cy_valueint,
5620                                                        seq_no ? seq_no->cy_valueint
5621                                                         : -1,
5622                                                        err_rc);
5623
5624         return rc;
5625 }
5626
5627 static int handle_yaml_del_global_settings(struct cYAML *tree,
5628                                            struct cYAML **show_rc,
5629                                            struct cYAML **err_rc)
5630 {
5631         struct cYAML *max_intf, *numa, *discovery, *seq_no, *drop_asym_route;
5632         int rc = 0;
5633
5634         seq_no = cYAML_get_object_item(tree, "seq_no");
5635         max_intf = cYAML_get_object_item(tree, "max_interfaces");
5636         if (!max_intf) /* try legacy name */
5637                 max_intf = cYAML_get_object_item(tree, "max_intf");
5638         if (max_intf)
5639                 rc = lustre_lnet_config_max_intf(LNET_INTERFACES_MAX_DEFAULT,
5640                                                  seq_no ? seq_no->cy_valueint
5641                                                         : -1,
5642                                                  err_rc);
5643
5644         numa = cYAML_get_object_item(tree, "numa_range");
5645         if (numa)
5646                 rc = lustre_lnet_config_numa_range(0,
5647                                                    seq_no ? seq_no->cy_valueint
5648                                                         : -1,
5649                                                    err_rc);
5650
5651         /* peer discovery is enabled by default */
5652         discovery = cYAML_get_object_item(tree, "discovery");
5653         if (discovery)
5654                 rc = lustre_lnet_config_discovery(1,
5655                                                   seq_no ? seq_no->cy_valueint
5656                                                         : -1,
5657                                                   err_rc);
5658
5659         /* asymmetrical route messages are accepted by default */
5660         drop_asym_route = cYAML_get_object_item(tree, "drop_asym_route");
5661         if (drop_asym_route)
5662                 rc = lustre_lnet_config_drop_asym_route(
5663                         0, seq_no ? seq_no->cy_valueint : -1, err_rc);
5664
5665         return rc;
5666 }
5667
5668 static int handle_yaml_show_global_settings(struct cYAML *tree,
5669                                             struct cYAML **show_rc,
5670                                             struct cYAML **err_rc)
5671 {
5672         struct cYAML *max_intf, *numa, *discovery, *retry, *tto, *seq_no,
5673                      *sen, *recov, *rsen, *drop_asym_route, *rsp_tracking,
5674                      *recov_limit;
5675         int rc = 0;
5676
5677         seq_no = cYAML_get_object_item(tree, "seq_no");
5678         max_intf = cYAML_get_object_item(tree, "max_interfaces");
5679         if (!max_intf) /* try legacy name */
5680                 max_intf = cYAML_get_object_item(tree, "max_intf");
5681         if (max_intf)
5682                 rc = lustre_lnet_show_max_intf(seq_no ? seq_no->cy_valueint
5683                                                         : -1,
5684                                                 show_rc, err_rc);
5685
5686         numa = cYAML_get_object_item(tree, "numa_range");
5687         if (numa)
5688                 rc = lustre_lnet_show_numa_range(seq_no ? seq_no->cy_valueint
5689                                                         : -1,
5690                                                  show_rc, err_rc);
5691
5692         discovery = cYAML_get_object_item(tree, "discovery");
5693         if (discovery)
5694                 rc = lustre_lnet_show_discovery(seq_no ? seq_no->cy_valueint
5695                                                         : -1,
5696                                                 show_rc, err_rc);
5697
5698         drop_asym_route = cYAML_get_object_item(tree, "drop_asym_route");
5699         if (drop_asym_route)
5700                 rc = lustre_lnet_show_drop_asym_route(
5701                         seq_no ? seq_no->cy_valueint : -1,
5702                         show_rc, err_rc);
5703
5704         retry = cYAML_get_object_item(tree, "retry_count");
5705         if (retry)
5706                 rc = lustre_lnet_show_retry_count(seq_no ? seq_no->cy_valueint
5707                                                         : -1,
5708                                                   show_rc, err_rc);
5709
5710         tto = cYAML_get_object_item(tree, "transaction_timeout");
5711         if (tto)
5712                 rc = lustre_lnet_show_transaction_to(seq_no ? seq_no->cy_valueint
5713                                                         : -1,
5714                                                      show_rc, err_rc);
5715
5716         sen = cYAML_get_object_item(tree, "health_sensitivity");
5717         if (sen)
5718                 rc = lustre_lnet_show_hsensitivity(seq_no ? seq_no->cy_valueint
5719                                                         : -1,
5720                                                      show_rc, err_rc);
5721
5722         recov = cYAML_get_object_item(tree, "recovery_interval");
5723         if (recov)
5724                 rc = lustre_lnet_show_recov_intrv(seq_no ? seq_no->cy_valueint
5725                                                         : -1,
5726                                                   show_rc, err_rc);
5727
5728         rsen = cYAML_get_object_item(tree, "router_sensitivity");
5729         if (rsen)
5730                 rc = lustre_lnet_show_hsensitivity(seq_no ? seq_no->cy_valueint
5731                                                         : -1,
5732                                                      show_rc, err_rc);
5733
5734         rsp_tracking = cYAML_get_object_item(tree, "response_tracking");
5735         if (rsp_tracking)
5736                 rc = lustre_lnet_show_response_tracking(seq_no ?
5737                                                         seq_no->cy_valueint :
5738                                                         -1,
5739                                                         show_rc, err_rc);
5740
5741         recov_limit = cYAML_get_object_item(tree, "recovery_limit");
5742         if (recov_limit)
5743                 rc = lustre_lnet_show_recovery_limit(seq_no ?
5744                                                      seq_no->cy_valueint :
5745                                                      -1,
5746                                                      show_rc, err_rc);
5747
5748         return rc;
5749 }
5750
5751 static int handle_yaml_ping(struct cYAML *tree, struct cYAML **show_rc,
5752                             struct cYAML **err_rc)
5753 {
5754         struct cYAML *seq_no, *nid, *timeout, *src_nid;
5755
5756         seq_no = cYAML_get_object_item(tree, "seq_no");
5757         nid = cYAML_get_object_item(tree, "primary nid");
5758         timeout = cYAML_get_object_item(tree, "timeout");
5759         src_nid = cYAML_get_object_item(tree, "source_nid");
5760
5761         return lustre_lnet_ping_nid((nid) ? nid->cy_valuestring : NULL,
5762                                     (src_nid) ? src_nid->cy_valuestring : NULL,
5763                                     (timeout) ? timeout->cy_valueint : 1000,
5764                                     (seq_no) ? seq_no->cy_valueint : -1,
5765                                     show_rc, err_rc);
5766 }
5767
5768 static int handle_yaml_discover(struct cYAML *tree, struct cYAML **show_rc,
5769                                 struct cYAML **err_rc)
5770 {
5771         struct cYAML *seq_no, *nid, *force;
5772
5773         seq_no = cYAML_get_object_item(tree, "seq_no");
5774         nid = cYAML_get_object_item(tree, "primary nid");
5775         force = cYAML_get_object_item(tree, "force");
5776
5777         return lustre_lnet_discover_nid((nid) ? nid->cy_valuestring : NULL,
5778                                         (force) ? force->cy_valueint : 0,
5779                                         (seq_no) ? seq_no->cy_valueint : -1,
5780                                         show_rc, err_rc);
5781 }
5782
5783 static int handle_yaml_no_op()
5784 {
5785         return LUSTRE_CFG_RC_NO_ERR;
5786 }
5787
5788 struct lookup_cmd_hdlr_tbl {
5789         char *name;
5790         cmd_handler_t cb;
5791 };
5792
5793 static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
5794         { .name = "route",      .cb = handle_yaml_config_route },
5795         { .name = "net",        .cb = handle_yaml_config_ni },
5796         { .name = "ip2nets",    .cb = handle_yaml_config_ip2nets },
5797         { .name = "peer",       .cb = handle_yaml_config_peer },
5798         { .name = "routing",    .cb = handle_yaml_config_routing },
5799         { .name = "buffers",    .cb = handle_yaml_config_buffers },
5800         { .name = "statistics", .cb = handle_yaml_no_op },
5801         { .name = "global",     .cb = handle_yaml_config_global_settings},
5802         { .name = "numa",       .cb = handle_yaml_config_numa },
5803         { .name = "ping",       .cb = handle_yaml_no_op },
5804         { .name = "discover",   .cb = handle_yaml_no_op },
5805         { .name = "udsp",       .cb = handle_yaml_config_udsp },
5806         { .name = NULL } };
5807
5808 static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
5809         { .name = "route",      .cb = handle_yaml_del_route },
5810         { .name = "net",        .cb = handle_yaml_del_ni },
5811         { .name = "ip2nets",    .cb = handle_yaml_no_op },
5812         { .name = "peer",       .cb = handle_yaml_del_peer },
5813         { .name = "routing",    .cb = handle_yaml_del_routing },
5814         { .name = "buffers",    .cb = handle_yaml_no_op },
5815         { .name = "statistics", .cb = handle_yaml_no_op },
5816         { .name = "global",     .cb = handle_yaml_del_global_settings},
5817         { .name = "numa",       .cb = handle_yaml_del_numa },
5818         { .name = "ping",       .cb = handle_yaml_no_op },
5819         { .name = "discover",   .cb = handle_yaml_no_op },
5820         { .name = "udsp",       .cb = handle_yaml_del_udsp },
5821         { .name = NULL } };
5822
5823 static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = {
5824         { .name = "route",      .cb = handle_yaml_show_route },
5825         { .name = "net",        .cb = handle_yaml_show_net },
5826         { .name = "peer",       .cb = handle_yaml_show_peers },
5827         { .name = "ip2nets",    .cb = handle_yaml_no_op },
5828         { .name = "routing",    .cb = handle_yaml_show_routing },
5829         { .name = "buffers",    .cb = handle_yaml_show_routing },
5830         { .name = "statistics", .cb = handle_yaml_show_stats },
5831         { .name = "global",     .cb = handle_yaml_show_global_settings},
5832         { .name = "numa",       .cb = handle_yaml_show_numa },
5833         { .name = "ping",       .cb = handle_yaml_no_op },
5834         { .name = "discover",   .cb = handle_yaml_no_op },
5835         { .name = "udsp",       .cb = handle_yaml_show_udsp },
5836         { .name = NULL } };
5837
5838 static struct lookup_cmd_hdlr_tbl lookup_exec_tbl[] = {
5839         { .name = "route",      .cb = handle_yaml_no_op },
5840         { .name = "net",        .cb = handle_yaml_no_op },
5841         { .name = "peer",       .cb = handle_yaml_no_op },
5842         { .name = "ip2nets",    .cb = handle_yaml_no_op },
5843         { .name = "routing",    .cb = handle_yaml_no_op },
5844         { .name = "buffers",    .cb = handle_yaml_no_op },
5845         { .name = "statistics", .cb = handle_yaml_no_op },
5846         { .name = "global",     .cb = handle_yaml_no_op },
5847         { .name = "numa",       .cb = handle_yaml_no_op },
5848         { .name = "ping",       .cb = handle_yaml_ping },
5849         { .name = "discover",   .cb = handle_yaml_discover },
5850         { .name = NULL } };
5851
5852 static cmd_handler_t lookup_fn(char *key,
5853                                struct lookup_cmd_hdlr_tbl *tbl)
5854 {
5855         int i;
5856         if (key == NULL)
5857                 return NULL;
5858
5859         for (i = 0; tbl[i].name != NULL; i++) {
5860                 if (strncmp(key, tbl[i].name, strlen(tbl[i].name)) == 0)
5861                         return tbl[i].cb;
5862         }
5863
5864         return NULL;
5865 }
5866
5867 static int lustre_yaml_cb_helper(char *f, int len,
5868                                  struct lookup_cmd_hdlr_tbl *table,
5869                                  struct cYAML **show_rc, struct cYAML **err_rc)
5870 {
5871         struct cYAML *tree, *item = NULL, *head, *child;
5872         cmd_handler_t cb;
5873         char err_str[LNET_MAX_STR_LEN];
5874         int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
5875
5876         tree = cYAML_build_tree(NULL, f, len, err_rc, false);
5877         if (tree == NULL)
5878                 return LUSTRE_CFG_RC_BAD_PARAM;
5879
5880         child = tree->cy_child;
5881         while (child != NULL) {
5882                 cb = lookup_fn(child->cy_string, table);
5883                 if (cb == NULL) {
5884                         snprintf(err_str, sizeof(err_str),
5885                                 "\"call back for '%s' not found\"",
5886                                 child->cy_string);
5887                         cYAML_build_error(LUSTRE_CFG_RC_BAD_PARAM, -1,
5888                                         "yaml", "helper", err_str, err_rc);
5889                         goto out;
5890                 }
5891
5892                 if (cYAML_is_sequence(child)) {
5893                         while ((head = cYAML_get_next_seq_item(child, &item))
5894                                != NULL) {
5895                                 rc = cb(head, show_rc, err_rc);
5896                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
5897                                         return_rc = rc;
5898                         }
5899                 } else {
5900                         rc = cb(child, show_rc, err_rc);
5901                         if (rc != LUSTRE_CFG_RC_NO_ERR)
5902                                 return_rc = rc;
5903                 }
5904                 item = NULL;
5905                 child = child->cy_next;
5906         }
5907
5908 out:
5909         cYAML_free_tree(tree);
5910
5911         return return_rc;
5912 }
5913
5914 int lustre_yaml_config(char *f, int len, struct cYAML **err_rc)
5915 {
5916         return lustre_yaml_cb_helper(f, len, lookup_config_tbl,
5917                                      NULL, err_rc);
5918 }
5919
5920 int lustre_yaml_del(char *f, int len, struct cYAML **err_rc)
5921 {
5922         return lustre_yaml_cb_helper(f, len, lookup_del_tbl,
5923                                      NULL, err_rc);
5924 }
5925
5926 int lustre_yaml_show(char *f, int len, struct cYAML **show_rc,
5927                      struct cYAML **err_rc)
5928 {
5929         return lustre_yaml_cb_helper(f, len, lookup_show_tbl,
5930                                      show_rc, err_rc);
5931 }
5932
5933 int lustre_yaml_exec(char *f, int len, struct cYAML **show_rc,
5934                      struct cYAML **err_rc)
5935 {
5936         return lustre_yaml_cb_helper(f, len, lookup_exec_tbl,
5937                                      show_rc, err_rc);
5938 }