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