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