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