Whamcloud - gitweb
LU-7734 lnet: configure peers from DLC
[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, 2016, 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 <netdb.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/ioctl.h>
43 #include <libcfs/util/ioctl.h>
44 #include <lnet/lnetctl.h>
45 #include <lnet/socklnd.h>
46 #include "liblnd.h"
47 #include "liblnetconfig.h"
48 #include "cyaml.h"
49
50 #define CONFIG_CMD              "configure"
51 #define UNCONFIG_CMD            "unconfigure"
52 #define ADD_CMD                 "add"
53 #define DEL_CMD                 "del"
54 #define SHOW_CMD                "show"
55
56 int lustre_lnet_config_lib_init(void)
57 {
58         return register_ioc_dev(LNET_DEV_ID, LNET_DEV_PATH,
59                                 LNET_DEV_MAJOR, LNET_DEV_MINOR);
60 }
61
62 int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
63                                  int seq_no, struct cYAML **err_rc)
64 {
65         struct libcfs_ioctl_data data;
66         unsigned int opc;
67         int rc;
68         char err_str[LNET_MAX_STR_LEN];
69
70         snprintf(err_str, sizeof(err_str), "\"Success\"");
71
72         LIBCFS_IOC_INIT(data);
73
74         /* Reverse logic is used here in order not to change
75          * the lctl utility */
76         data.ioc_flags = load_ni_from_mod ? 0 : 1;
77
78         opc = up ? IOC_LIBCFS_CONFIGURE : IOC_LIBCFS_UNCONFIGURE;
79
80         rc = l_ioctl(LNET_DEV_ID, opc, &data);
81         if (rc != 0) {
82                 snprintf(err_str,
83                         sizeof(err_str),
84                         "\"LNet %s error: %s\"", (up) ? "configure" :
85                         "unconfigure", strerror(errno));
86                 rc = -errno;
87         }
88
89         cYAML_build_error(rc, seq_no, (up) ? CONFIG_CMD : UNCONFIG_CMD,
90                           "lnet", err_str, err_rc);
91
92         return rc;
93 }
94
95 static lnet_nid_t *allocate_create_nid_array(char **nids, char *err_str)
96 {
97         lnet_nid_t *array = NULL;
98         int idx = 0;
99
100         if (!nids) {
101                 snprintf(err_str, LNET_MAX_STR_LEN, "no NIDs to add");
102                 return NULL;
103         }
104
105         /* count the size of the array */
106         while (nids[idx] != NULL)
107                 idx++;
108
109         array = calloc(sizeof(*array) * idx + 1, 1);
110         if (array == NULL) {
111                 snprintf(err_str, LNET_MAX_STR_LEN, "out of memory");
112                 return NULL;
113         }
114
115         idx = 0;
116         while (nids[idx] != NULL) {
117                 array[idx] = libcfs_str2nid(nids[idx]);
118                 if (array[idx] == LNET_NID_ANY) {
119                         free(array);
120                         snprintf(err_str, LNET_MAX_STR_LEN,
121                                  "bad NID: '%s'",
122                                  nids[idx]);
123                         return NULL;
124                 }
125                 idx++;
126         }
127
128         /* identify last entry */
129         array[idx] = LNET_NID_ANY;
130
131         return array;
132 }
133
134 static int dispatch_peer_ni_cmd(lnet_nid_t knid, lnet_nid_t nid, __u32 cmd,
135                                 struct lnet_ioctl_peer_cfg *data,
136                                 char *err_str, char *cmd_str)
137 {
138         int rc;
139
140         data->prcfg_key_nid = knid;
141         data->prcfg_cfg_nid = nid;
142
143         rc = l_ioctl(LNET_DEV_ID, cmd, data);
144         if (rc != 0) {
145                 rc = -errno;
146                 snprintf(err_str,
147                         LNET_MAX_STR_LEN,
148                         "\"cannot %s peer ni: %s\"",
149                         (cmd_str) ? cmd_str : "add", strerror(errno));
150         }
151
152         return rc;
153 }
154
155 int lustre_lnet_config_peer_nid(char *knid, char **nid, int seq_no,
156                                 struct cYAML **err_rc)
157 {
158         struct lnet_ioctl_peer_cfg data;
159         lnet_nid_t key_nid = LNET_NID_ANY;
160         int rc = LUSTRE_CFG_RC_NO_ERR;
161         int idx = 0;
162         char err_str[LNET_MAX_STR_LEN] = {0};
163         lnet_nid_t *nids = allocate_create_nid_array(nid, err_str);
164
165         if (knid != NULL) {
166                 key_nid = libcfs_str2nid(knid);
167                 if (key_nid == LNET_NID_ANY) {
168                         snprintf(err_str, sizeof(err_str),
169                                  "bad key NID: '%s'",
170                                  knid);
171                         rc = LUSTRE_CFG_RC_MISSING_PARAM;
172                         goto out;
173                 }
174         } else if (nids[0] == LNET_NID_ANY) {
175                 snprintf(err_str, sizeof(err_str),
176                          "no NIDs provided for configuration");
177                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
178                 goto out;
179         } else {
180                 key_nid = LNET_NID_ANY;
181         }
182
183         snprintf(err_str, sizeof(err_str), "\"Success\"");
184
185         LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
186         if (nids[0] == LNET_NID_ANY) {
187                 rc = dispatch_peer_ni_cmd(LNET_NID_ANY, key_nid,
188                                           IOC_LIBCFS_ADD_PEER_NI,
189                                           &data, err_str, "add");
190                 goto out;
191         }
192
193         while (nids[idx] != LNET_NID_ANY) {
194                 /*
195                  * If key_nid is not provided then the first nid in the
196                  * list becomes the key_nid. First time round the loop use
197                  * LNET_NID_ANY for the first parameter, then use nid[0]
198                  * as the key nid after wards
199                  */
200                 rc = dispatch_peer_ni_cmd(key_nid, nids[idx],
201                                           IOC_LIBCFS_ADD_PEER_NI, &data,
202                                           err_str, "add");
203
204                 if (rc != 0)
205                         goto out;
206
207                 if (idx == 0 && key_nid == LNET_NID_ANY)
208                         key_nid = nids[0];
209
210                 idx++;
211         }
212
213 out:
214         if (nids != NULL)
215                 free(nids);
216         cYAML_build_error(rc, seq_no, ADD_CMD, "peer_ni", err_str, err_rc);
217         return rc;
218 }
219
220 int lustre_lnet_del_peer_nid(char *knid, char **nid, int seq_no,
221                              struct cYAML **err_rc)
222 {
223         struct lnet_ioctl_peer_cfg data;
224         lnet_nid_t key_nid;
225         int rc = LUSTRE_CFG_RC_NO_ERR;
226         int idx = 0;
227         char err_str[LNET_MAX_STR_LEN] = {0};
228         lnet_nid_t *nids = allocate_create_nid_array(nid, err_str);
229
230         if (knid == NULL) {
231                 snprintf(err_str, sizeof(err_str),
232                          "\"Primary nid is not provided\"");
233                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
234                 goto out;
235         } else {
236                 key_nid = libcfs_str2nid(knid);
237                 if (key_nid == LNET_NID_ANY) {
238                         rc = LUSTRE_CFG_RC_BAD_PARAM;
239                         snprintf(err_str, sizeof(err_str),
240                                  "bad key NID: '%s'",
241                                  knid);
242                         goto out;
243                 }
244         }
245
246         snprintf(err_str, sizeof(err_str), "\"Success\"");
247
248         LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
249         if (nids[0] == LNET_NID_ANY) {
250                 rc = dispatch_peer_ni_cmd(key_nid, LNET_NID_ANY,
251                                           IOC_LIBCFS_DEL_PEER_NI,
252                                           &data, err_str, "del");
253                 goto out;
254         }
255
256         while (nids[idx] != LNET_NID_ANY) {
257                 rc = dispatch_peer_ni_cmd(key_nid, nids[idx],
258                                           IOC_LIBCFS_DEL_PEER_NI, &data,
259                                           err_str, "del");
260
261                 if (rc != 0)
262                         goto out;
263
264                 idx++;
265         }
266
267 out:
268         if (nids != NULL)
269                 free(nids);
270         cYAML_build_error(rc, seq_no, DEL_CMD, "peer_ni", err_str, err_rc);
271         return rc;
272 }
273
274 int lustre_lnet_config_route(char *nw, char *gw, int hops, int prio,
275                              int seq_no, struct cYAML **err_rc)
276 {
277         struct lnet_ioctl_config_data data;
278         lnet_nid_t gateway_nid;
279         int rc = LUSTRE_CFG_RC_NO_ERR;
280         __u32 net = LNET_NIDNET(LNET_NID_ANY);
281         char err_str[LNET_MAX_STR_LEN];
282
283         snprintf(err_str, sizeof(err_str), "\"Success\"");
284
285         if (nw == NULL || gw == NULL) {
286                 snprintf(err_str,
287                          sizeof(err_str),
288                          "\"missing mandatory parameter(s): '%s'\"",
289                          (nw == NULL && gw == NULL) ? "network, gateway" :
290                          (nw == NULL) ? "network" : "gateway");
291                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
292                 goto out;
293         }
294
295         net = libcfs_str2net(nw);
296         if (net == LNET_NIDNET(LNET_NID_ANY)) {
297                 snprintf(err_str,
298                          sizeof(err_str),
299                          "\"cannot parse net %s\"", nw);
300                 rc = LUSTRE_CFG_RC_BAD_PARAM;
301                 goto out;
302         }
303
304         if (LNET_NETTYP(net) == CIBLND    ||
305             LNET_NETTYP(net) == OPENIBLND ||
306             LNET_NETTYP(net) == IIBLND    ||
307             LNET_NETTYP(net) == VIBLND) {
308                 snprintf(err_str,
309                          sizeof(err_str),
310                          "\"obselete LNet type '%s'\"", libcfs_lnd2str(net));
311                 rc = LUSTRE_CFG_RC_BAD_PARAM;
312                 goto out;
313         }
314
315         gateway_nid = libcfs_str2nid(gw);
316         if (gateway_nid == LNET_NID_ANY) {
317                 snprintf(err_str,
318                         sizeof(err_str),
319                         "\"cannot parse gateway NID '%s'\"", gw);
320                 rc = LUSTRE_CFG_RC_BAD_PARAM;
321                 goto out;
322         }
323
324         if (hops == -1) {
325                 /* hops is undefined */
326                 hops = LNET_UNDEFINED_HOPS;
327         } else if (hops < 1 || hops > 255) {
328                 snprintf(err_str,
329                         sizeof(err_str),
330                         "\"invalid hop count %d, must be between 1 and 255\"",
331                         hops);
332                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
333                 goto out;
334         }
335
336         if (prio == -1) {
337                 prio = 0;
338         } else if (prio < 0) {
339                 snprintf(err_str,
340                          sizeof(err_str),
341                         "\"invalid priority %d, must be greater than 0\"",
342                         prio);
343                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
344                 goto out;
345         }
346
347         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
348         data.cfg_net = net;
349         data.cfg_config_u.cfg_route.rtr_hop = hops;
350         data.cfg_config_u.cfg_route.rtr_priority = prio;
351         data.cfg_nid = gateway_nid;
352
353         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_ROUTE, &data);
354         if (rc != 0) {
355                 rc = -errno;
356                 snprintf(err_str,
357                          sizeof(err_str),
358                          "\"cannot add route: %s\"", strerror(errno));
359                 goto out;
360         }
361
362 out:
363         cYAML_build_error(rc, seq_no, ADD_CMD, "route", err_str, err_rc);
364
365         return rc;
366 }
367
368 int lustre_lnet_del_route(char *nw, char *gw,
369                           int seq_no, struct cYAML **err_rc)
370 {
371         struct lnet_ioctl_config_data data;
372         lnet_nid_t gateway_nid;
373         int rc = LUSTRE_CFG_RC_NO_ERR;
374         __u32 net = LNET_NIDNET(LNET_NID_ANY);
375         char err_str[LNET_MAX_STR_LEN];
376
377         snprintf(err_str, sizeof(err_str), "\"Success\"");
378
379         if (nw == NULL || gw == NULL) {
380                 snprintf(err_str,
381                          sizeof(err_str),
382                          "\"missing mandatory parameter(s): '%s'\"",
383                          (nw == NULL && gw == NULL) ? "network, gateway" :
384                          (nw == NULL) ? "network" : "gateway");
385                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
386                 goto out;
387         }
388
389         net = libcfs_str2net(nw);
390         if (net == LNET_NIDNET(LNET_NID_ANY)) {
391                 snprintf(err_str,
392                          sizeof(err_str),
393                          "\"cannot parse net '%s'\"", nw);
394                 rc = LUSTRE_CFG_RC_BAD_PARAM;
395                 goto out;
396         }
397
398         if (LNET_NETTYP(net) == CIBLND    ||
399             LNET_NETTYP(net) == OPENIBLND ||
400             LNET_NETTYP(net) == IIBLND    ||
401             LNET_NETTYP(net) == VIBLND) {
402                 snprintf(err_str,
403                          sizeof(err_str),
404                          "\"obselete LNet type '%s'\"", libcfs_lnd2str(net));
405                 rc = LUSTRE_CFG_RC_BAD_PARAM;
406                 goto out;
407         }
408
409         gateway_nid = libcfs_str2nid(gw);
410         if (gateway_nid == LNET_NID_ANY) {
411                 snprintf(err_str,
412                          sizeof(err_str),
413                          "\"cannot parse gateway NID '%s'\"", gw);
414                 rc = LUSTRE_CFG_RC_BAD_PARAM;
415                 goto out;
416         }
417
418         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
419         data.cfg_net = net;
420         data.cfg_nid = gateway_nid;
421
422         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_ROUTE, &data);
423         if (rc != 0) {
424                 rc = -errno;
425                 snprintf(err_str,
426                          sizeof(err_str),
427                          "\"cannot delete route: %s\"", strerror(errno));
428                 goto out;
429         }
430
431 out:
432         cYAML_build_error(rc, seq_no, DEL_CMD, "route", err_str, err_rc);
433
434         return rc;
435 }
436
437 int lustre_lnet_show_route(char *nw, char *gw, int hops, int prio, int detail,
438                            int seq_no, struct cYAML **show_rc,
439                            struct cYAML **err_rc)
440 {
441         struct lnet_ioctl_config_data data;
442         lnet_nid_t gateway_nid;
443         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
444         int l_errno = 0;
445         __u32 net = LNET_NIDNET(LNET_NID_ANY);
446         int i;
447         struct cYAML *root = NULL, *route = NULL, *item = NULL;
448         struct cYAML *first_seq = NULL;
449         char err_str[LNET_MAX_STR_LEN];
450         bool exist = false;
451
452         snprintf(err_str, sizeof(err_str),
453                  "\"out of memory\"");
454
455         if (nw != NULL) {
456                 net = libcfs_str2net(nw);
457                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
458                         snprintf(err_str,
459                                  sizeof(err_str),
460                                  "\"cannot parse net '%s'\"", nw);
461                         rc = LUSTRE_CFG_RC_BAD_PARAM;
462                         goto out;
463                 }
464
465                 if (LNET_NETTYP(net) == CIBLND    ||
466                     LNET_NETTYP(net) == OPENIBLND ||
467                     LNET_NETTYP(net) == IIBLND    ||
468                     LNET_NETTYP(net) == VIBLND) {
469                         snprintf(err_str,
470                                  sizeof(err_str),
471                                  "\"obsolete LNet type '%s'\"",
472                                  libcfs_lnd2str(net));
473                         rc = LUSTRE_CFG_RC_BAD_PARAM;
474                         goto out;
475                 }
476         } else {
477                 /* show all routes without filtering on net */
478                 net = LNET_NIDNET(LNET_NID_ANY);
479         }
480
481         if (gw != NULL) {
482                 gateway_nid = libcfs_str2nid(gw);
483                 if (gateway_nid == LNET_NID_ANY) {
484                         snprintf(err_str,
485                                  sizeof(err_str),
486                                  "\"cannot parse gateway NID '%s'\"", gw);
487                         rc = LUSTRE_CFG_RC_BAD_PARAM;
488                         goto out;
489                 }
490         } else
491                 /* show all routes with out filtering on gateway */
492                 gateway_nid = LNET_NID_ANY;
493
494         if ((hops < 1 && hops != -1) || hops > 255) {
495                 snprintf(err_str,
496                          sizeof(err_str),
497                          "\"invalid hop count %d, must be between 0 and 256\"",
498                          hops);
499                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
500                 goto out;
501         }
502
503         /* create struct cYAML root object */
504         root = cYAML_create_object(NULL, NULL);
505         if (root == NULL)
506                 goto out;
507
508         route = cYAML_create_seq(root, "route");
509         if (route == NULL)
510                 goto out;
511
512         for (i = 0;; i++) {
513                 LIBCFS_IOC_INIT_V2(data, cfg_hdr);
514                 data.cfg_count = i;
515
516                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_ROUTE, &data);
517                 if (rc != 0) {
518                         l_errno = errno;
519                         break;
520                 }
521
522                 /* filter on provided data */
523                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
524                     net != data.cfg_net)
525                         continue;
526
527                 if (gateway_nid != LNET_NID_ANY &&
528                     gateway_nid != data.cfg_nid)
529                         continue;
530
531                 if (hops != -1 &&
532                     hops != data.cfg_config_u.cfg_route.rtr_hop)
533                         continue;
534
535                 if (prio != -1 &&
536                     prio != data.cfg_config_u.cfg_route.rtr_priority)
537                         continue;
538
539                 /* default rc to -1 incase we hit the goto */
540                 rc = -1;
541                 exist = true;
542
543                 item = cYAML_create_seq_item(route);
544                 if (item == NULL)
545                         goto out;
546
547                 if (first_seq == NULL)
548                         first_seq = item;
549
550                 if (cYAML_create_string(item, "net",
551                                         libcfs_net2str(data.cfg_net)) == NULL)
552                         goto out;
553
554                 if (cYAML_create_string(item, "gateway",
555                                         libcfs_nid2str(data.cfg_nid)) == NULL)
556                         goto out;
557
558                 if (detail) {
559                         if (cYAML_create_number(item, "hop",
560                                                 data.cfg_config_u.cfg_route.
561                                                         rtr_hop) ==
562                             NULL)
563                                 goto out;
564
565                         if (cYAML_create_number(item, "priority",
566                                                 data.cfg_config_u.
567                                                 cfg_route.rtr_priority) == NULL)
568                                 goto out;
569
570                         if (cYAML_create_string(item, "state",
571                                                 data.cfg_config_u.cfg_route.
572                                                         rtr_flags ?
573                                                 "up" : "down") == NULL)
574                                 goto out;
575                 }
576         }
577
578         /* print output iff show_rc is not provided */
579         if (show_rc == NULL)
580                 cYAML_print_tree(root);
581
582         if (l_errno != ENOENT) {
583                 snprintf(err_str,
584                          sizeof(err_str),
585                          "\"cannot get routes: %s\"",
586                          strerror(l_errno));
587                 rc = -l_errno;
588                 goto out;
589         } else
590                 rc = LUSTRE_CFG_RC_NO_ERR;
591
592         snprintf(err_str, sizeof(err_str), "\"success\"");
593 out:
594         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
595                 cYAML_free_tree(root);
596         } else if (show_rc != NULL && *show_rc != NULL) {
597                 struct cYAML *show_node;
598                 /* find the route node, if one doesn't exist then
599                  * insert one.  Otherwise add to the one there
600                  */
601                 show_node = cYAML_get_object_item(*show_rc, "route");
602                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
603                         cYAML_insert_child(show_node, first_seq);
604                         free(route);
605                         free(root);
606                 } else if (show_node == NULL) {
607                         cYAML_insert_sibling((*show_rc)->cy_child,
608                                                 route);
609                         free(root);
610                 } else {
611                         cYAML_free_tree(root);
612                 }
613         } else {
614                 *show_rc = root;
615         }
616
617         cYAML_build_error(rc, seq_no, SHOW_CMD, "route", err_str, err_rc);
618
619         return rc;
620 }
621
622 int lustre_lnet_config_net(char *net, char *intf, char *ip2net,
623                            int peer_to, int peer_cr, int peer_buf_cr,
624                            int credits, char *smp, int seq_no,
625                            struct lnet_ioctl_config_lnd_tunables *lnd_tunables,
626                            struct cYAML **err_rc)
627 {
628         struct lnet_ioctl_config_lnd_tunables *lnd = NULL;
629         struct lnet_ioctl_config_data *data;
630         size_t ioctl_size = sizeof(*data);
631         char buf[LNET_MAX_STR_LEN];
632         int rc = LUSTRE_CFG_RC_NO_ERR;
633         char err_str[LNET_MAX_STR_LEN];
634
635         snprintf(err_str, sizeof(err_str), "\"success\"");
636
637         /* No need to register lo */
638         if (net != NULL && !strcmp(net, "lo"))
639                 return 0;
640
641         if (ip2net == NULL && (intf == NULL || net == NULL)) {
642                 snprintf(err_str,
643                          sizeof(err_str),
644                          "\"mandatory parameter '%s' not specified."
645                          " Optionally specify ip2net parameter\"",
646                          (intf == NULL && net == NULL) ? "net, if" :
647                          (intf == NULL) ? "if" : "net");
648                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
649                 goto out;
650         }
651
652         if (peer_to != -1 && peer_to <= 0) {
653                 snprintf(err_str,
654                          sizeof(err_str),
655                          "\"peer timeout %d, must be greater than 0\"",
656                          peer_to);
657                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
658                 goto out;
659         }
660
661         if (ip2net != NULL && strlen(ip2net) >= sizeof(buf)) {
662                 snprintf(err_str,
663                          sizeof(err_str),
664                          "\"ip2net string too long %d\"",
665                                 (int)strlen(ip2net));
666                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
667                 goto out;
668         }
669
670         if (lnd_tunables != NULL)
671                 ioctl_size += sizeof(*lnd_tunables);
672
673         data = calloc(1, ioctl_size);
674         if (data == NULL)
675                 goto out;
676
677         if (ip2net == NULL)
678                 snprintf(buf, sizeof(buf) - 1, "%s(%s)%s",
679                         net, intf,
680                         (smp) ? smp : "");
681
682         LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
683         strncpy(data->cfg_config_u.cfg_net.net_intf,
684                 (ip2net != NULL) ? ip2net : buf, sizeof(buf));
685         data->cfg_config_u.cfg_net.net_peer_timeout = peer_to;
686         data->cfg_config_u.cfg_net.net_peer_tx_credits = peer_cr;
687         data->cfg_config_u.cfg_net.net_peer_rtr_credits = peer_buf_cr;
688         data->cfg_config_u.cfg_net.net_max_tx_credits = credits;
689         /* Add in tunable settings if available */
690         if (lnd_tunables != NULL) {
691                 lnd = (struct lnet_ioctl_config_lnd_tunables *)data->cfg_bulk;
692
693                 data->cfg_hdr.ioc_len = ioctl_size;
694                 memcpy(lnd, lnd_tunables, sizeof(*lnd_tunables));
695         }
696
697         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_NET, data);
698         if (rc < 0) {
699                 rc = -errno;
700                 snprintf(err_str,
701                          sizeof(err_str),
702                          "\"cannot add network: %s\"", strerror(errno));
703         }
704         free(data);
705
706 out:
707         cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
708
709         return rc;
710 }
711
712 int lustre_lnet_del_net(char *nw, int seq_no, struct cYAML **err_rc)
713 {
714         struct lnet_ioctl_config_data data;
715         __u32 net = LNET_NIDNET(LNET_NID_ANY);
716         int rc = LUSTRE_CFG_RC_NO_ERR;
717         char err_str[LNET_MAX_STR_LEN];
718
719         snprintf(err_str, sizeof(err_str), "\"success\"");
720
721         if (nw == NULL) {
722                 snprintf(err_str,
723                          sizeof(err_str),
724                          "\"missing mandatory parameter\"");
725                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
726                 goto out;
727         }
728
729         net = libcfs_str2net(nw);
730         if (net == LNET_NIDNET(LNET_NID_ANY)) {
731                 snprintf(err_str,
732                          sizeof(err_str),
733                          "\"cannot parse net '%s'\"", nw);
734                 rc = LUSTRE_CFG_RC_BAD_PARAM;
735                 goto out;
736         }
737
738         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
739         data.cfg_net = net;
740
741         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_NET, &data);
742         if (rc != 0) {
743                 rc = -errno;
744                 snprintf(err_str,
745                          sizeof(err_str),
746                          "\"cannot delete network: %s\"", strerror(errno));
747                 goto out;
748         }
749
750 out:
751         cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
752
753         return rc;
754 }
755
756 int lustre_lnet_show_net(char *nw, int detail, int seq_no,
757                          struct cYAML **show_rc, struct cYAML **err_rc)
758 {
759         char *buf;
760         struct lnet_ioctl_config_lnd_tunables *lnd_cfg;
761         struct lnet_ioctl_config_data *data;
762         struct lnet_ioctl_net_config *net_config;
763         __u32 net = LNET_NIDNET(LNET_NID_ANY);
764         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
765         int l_errno = 0;
766         struct cYAML *root = NULL, *tunables = NULL, *net_node = NULL,
767                 *interfaces = NULL, *item = NULL, *first_seq = NULL;
768         int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
769         char str_buf[str_buf_len];
770         char *pos;
771         char err_str[LNET_MAX_STR_LEN];
772         bool exist = false;
773         size_t buf_len;
774
775         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
776
777         buf_len = sizeof(*data) + sizeof(*net_config) + sizeof(*lnd_cfg);
778         buf = calloc(1, buf_len);
779         if (buf == NULL)
780                 goto out;
781
782         data = (struct lnet_ioctl_config_data *)buf;
783
784         if (nw != NULL) {
785                 net = libcfs_str2net(nw);
786                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
787                         snprintf(err_str,
788                                  sizeof(err_str),
789                                  "\"cannot parse net '%s'\"", nw);
790                         rc = LUSTRE_CFG_RC_BAD_PARAM;
791                         goto out;
792                 }
793         }
794
795         root = cYAML_create_object(NULL, NULL);
796         if (root == NULL)
797                 goto out;
798
799         net_node = cYAML_create_seq(root, "net");
800         if (net_node == NULL)
801                 goto out;
802
803         for (i = 0;; i++) {
804                 pos = str_buf;
805
806                 memset(buf, 0, buf_len);
807
808                 LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
809                 /*
810                  * set the ioc_len to the proper value since INIT assumes
811                  * size of data
812                  */
813                 data->cfg_hdr.ioc_len = buf_len;
814                 data->cfg_count = i;
815
816                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_NET, data);
817                 if (rc != 0) {
818                         l_errno = errno;
819                         break;
820                 }
821
822                 /* filter on provided data */
823                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
824                     net != LNET_NIDNET(data->cfg_nid))
825                         continue;
826
827                 /* default rc to -1 in case we hit the goto */
828                 rc = -1;
829                 exist = true;
830
831                 net_config = (struct lnet_ioctl_net_config *)data->cfg_bulk;
832
833                 /* create the tree to be printed. */
834                 item = cYAML_create_seq_item(net_node);
835                 if (item == NULL)
836                         goto out;
837
838                 if (first_seq == NULL)
839                         first_seq = item;
840
841                 if (cYAML_create_string(item, "net",
842                                         libcfs_net2str(
843                                                 LNET_NIDNET(data->cfg_nid)))
844                     == NULL)
845                         goto out;
846
847                 if (cYAML_create_string(item, "nid",
848                                         libcfs_nid2str(data->cfg_nid)) == NULL)
849                         goto out;
850
851                 if (cYAML_create_string(item, "status",
852                                         (net_config->ni_status ==
853                                           LNET_NI_STATUS_UP) ?
854                                             "up" : "down") == NULL)
855                         goto out;
856
857                 /* don't add interfaces unless there is at least one
858                  * interface */
859                 if (strlen(net_config->ni_interfaces[0]) > 0) {
860                         interfaces = cYAML_create_object(item, "interfaces");
861                         if (interfaces == NULL)
862                                 goto out;
863
864                         for (j = 0; j < LNET_MAX_INTERFACES; j++) {
865                                 if (lustre_interface_show_net(interfaces, j,
866                                                               detail, data,
867                                                               net_config) < 0)
868                                         goto out;
869                         }
870                 }
871
872                 if (detail) {
873                         char *limit;
874
875                         tunables = cYAML_create_object(item, "tunables");
876                         if (tunables == NULL)
877                                 goto out;
878
879                         if (cYAML_create_number(tunables, "peer_timeout",
880                                                 data->cfg_config_u.cfg_net.
881                                                 net_peer_timeout) == NULL)
882                                 goto out;
883
884                         if (cYAML_create_number(tunables, "peer_credits",
885                                                 data->cfg_config_u.cfg_net.
886                                                 net_peer_tx_credits) == NULL)
887                                 goto out;
888
889                         if (cYAML_create_number(tunables,
890                                                 "peer_buffer_credits",
891                                                 data->cfg_config_u.cfg_net.
892                                                 net_peer_rtr_credits) == NULL)
893                                 goto out;
894
895                         if (cYAML_create_number(tunables, "credits",
896                                                 data->cfg_config_u.cfg_net.
897                                                 net_max_tx_credits) == NULL)
898                                 goto out;
899
900                         /* out put the CPTs in the format: "[x,x,x,...]" */
901                         limit = str_buf + str_buf_len - 3;
902                         pos += snprintf(pos, limit - pos, "\"[");
903                         for (j = 0 ; data->cfg_ncpts > 1 &&
904                                 j < data->cfg_ncpts &&
905                                 pos < limit; j++) {
906                                 pos += snprintf(pos, limit - pos,
907                                                 "%d", net_config->ni_cpts[j]);
908                                 if ((j + 1) < data->cfg_ncpts)
909                                         pos += snprintf(pos, limit - pos, ",");
910                         }
911                         pos += snprintf(pos, 3, "]\"");
912
913                         if (data->cfg_ncpts > 1 &&
914                             cYAML_create_string(tunables, "CPT",
915                                                 str_buf) == NULL)
916                                 goto out;
917                 }
918         }
919
920         /* Print out the net information only if show_rc is not provided */
921         if (show_rc == NULL)
922                 cYAML_print_tree(root);
923
924         if (l_errno != ENOENT) {
925                 snprintf(err_str,
926                          sizeof(err_str),
927                          "\"cannot get networks: %s\"",
928                          strerror(l_errno));
929                 rc = -l_errno;
930                 goto out;
931         } else
932                 rc = LUSTRE_CFG_RC_NO_ERR;
933
934         snprintf(err_str, sizeof(err_str), "\"success\"");
935 out:
936         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
937                 cYAML_free_tree(root);
938         } else if (show_rc != NULL && *show_rc != NULL) {
939                 struct cYAML *show_node;
940                 /* find the net node, if one doesn't exist
941                  * then insert one.  Otherwise add to the one there
942                  */
943                 show_node = cYAML_get_object_item(*show_rc, "net");
944                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
945                         cYAML_insert_child(show_node, first_seq);
946                         free(net_node);
947                         free(root);
948                 } else if (show_node == NULL) {
949                         cYAML_insert_sibling((*show_rc)->cy_child,
950                                                 net_node);
951                         free(root);
952                 } else {
953                         cYAML_free_tree(root);
954                 }
955         } else {
956                 *show_rc = root;
957         }
958
959         cYAML_build_error(rc, seq_no, SHOW_CMD, "net", err_str, err_rc);
960
961         return rc;
962 }
963
964 int lustre_lnet_enable_routing(int enable, int seq_no, struct cYAML **err_rc)
965 {
966         struct lnet_ioctl_config_data data;
967         int rc = LUSTRE_CFG_RC_NO_ERR;
968         char err_str[LNET_MAX_STR_LEN];
969
970         snprintf(err_str, sizeof(err_str), "\"success\"");
971
972         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
973         data.cfg_config_u.cfg_buffers.buf_enable = (enable) ? 1 : 0;
974
975         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CONFIG_RTR, &data);
976         if (rc != 0) {
977                 rc = -errno;
978                 snprintf(err_str,
979                          sizeof(err_str),
980                          "\"cannot %s routing %s\"",
981                          (enable) ? "enable" : "disable", strerror(errno));
982                 goto out;
983         }
984
985 out:
986         cYAML_build_error(rc, seq_no,
987                          (enable) ? ADD_CMD : DEL_CMD,
988                          "routing", err_str, err_rc);
989
990         return rc;
991 }
992
993 int lustre_lnet_config_buffers(int tiny, int small, int large, int seq_no,
994                                struct cYAML **err_rc)
995 {
996         struct lnet_ioctl_config_data data;
997         int rc = LUSTRE_CFG_RC_NO_ERR;
998         char err_str[LNET_MAX_STR_LEN];
999
1000         snprintf(err_str, sizeof(err_str), "\"success\"");
1001
1002         /* -1 indicates to ignore changes to this field */
1003         if (tiny < -1 || small < -1 || large < -1) {
1004                 snprintf(err_str,
1005                          sizeof(err_str),
1006                          "\"tiny, small and large must be >= 0\"");
1007                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1008                 goto out;
1009         }
1010
1011         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
1012         data.cfg_config_u.cfg_buffers.buf_tiny = tiny;
1013         data.cfg_config_u.cfg_buffers.buf_small = small;
1014         data.cfg_config_u.cfg_buffers.buf_large = large;
1015
1016         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_BUF, &data);
1017         if (rc != 0) {
1018                 rc = -errno;
1019                 snprintf(err_str,
1020                          sizeof(err_str),
1021                          "\"cannot configure buffers: %s\"", strerror(errno));
1022                 goto out;
1023         }
1024
1025 out:
1026         cYAML_build_error(rc, seq_no, ADD_CMD, "buf", err_str, err_rc);
1027
1028         return rc;
1029 }
1030
1031 int lustre_lnet_show_routing(int seq_no, struct cYAML **show_rc,
1032                              struct cYAML **err_rc)
1033 {
1034         struct lnet_ioctl_config_data *data;
1035         struct lnet_ioctl_pool_cfg *pool_cfg = NULL;
1036         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1037         int l_errno = 0;
1038         char *buf;
1039         char *pools[LNET_NRBPOOLS] = {"tiny", "small", "large"};
1040         int buf_count[LNET_NRBPOOLS] = {0};
1041         struct cYAML *root = NULL, *pools_node = NULL,
1042                      *type_node = NULL, *item = NULL, *cpt = NULL,
1043                      *first_seq = NULL, *buffers = NULL;
1044         int i, j;
1045         char err_str[LNET_MAX_STR_LEN];
1046         char node_name[LNET_MAX_STR_LEN];
1047         bool exist = false;
1048
1049         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
1050
1051         buf = calloc(1, sizeof(*data) + sizeof(*pool_cfg));
1052         if (buf == NULL)
1053                 goto out;
1054
1055         data = (struct lnet_ioctl_config_data *)buf;
1056
1057         root = cYAML_create_object(NULL, NULL);
1058         if (root == NULL)
1059                 goto out;
1060
1061         pools_node = cYAML_create_seq(root, "routing");
1062         if (pools_node == NULL)
1063                 goto out;
1064
1065         for (i = 0;; i++) {
1066                 LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
1067                 data->cfg_hdr.ioc_len = sizeof(struct lnet_ioctl_config_data) +
1068                                         sizeof(struct lnet_ioctl_pool_cfg);
1069                 data->cfg_count = i;
1070
1071                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_BUF, data);
1072                 if (rc != 0) {
1073                         l_errno = errno;
1074                         break;
1075                 }
1076
1077                 exist = true;
1078
1079                 pool_cfg = (struct lnet_ioctl_pool_cfg *)data->cfg_bulk;
1080
1081                 snprintf(node_name, sizeof(node_name), "cpt[%d]", i);
1082                 item = cYAML_create_seq_item(pools_node);
1083                 if (item == NULL)
1084                         goto out;
1085
1086                 if (first_seq == NULL)
1087                         first_seq = item;
1088
1089                 cpt = cYAML_create_object(item, node_name);
1090                 if (cpt == NULL)
1091                         goto out;
1092
1093                 /* create the tree  and print */
1094                 for (j = 0; j < LNET_NRBPOOLS; j++) {
1095                         type_node = cYAML_create_object(cpt, pools[j]);
1096                         if (type_node == NULL)
1097                                 goto out;
1098                         if (cYAML_create_number(type_node, "npages",
1099                                                 pool_cfg->pl_pools[j].pl_npages)
1100                             == NULL)
1101                                 goto out;
1102                         if (cYAML_create_number(type_node, "nbuffers",
1103                                                 pool_cfg->pl_pools[j].
1104                                                   pl_nbuffers) == NULL)
1105                                 goto out;
1106                         if (cYAML_create_number(type_node, "credits",
1107                                                 pool_cfg->pl_pools[j].
1108                                                    pl_credits) == NULL)
1109                                 goto out;
1110                         if (cYAML_create_number(type_node, "mincredits",
1111                                                 pool_cfg->pl_pools[j].
1112                                                    pl_mincredits) == NULL)
1113                                 goto out;
1114                         /* keep track of the total count for each of the
1115                          * tiny, small and large buffers */
1116                         buf_count[j] += pool_cfg->pl_pools[j].pl_nbuffers;
1117                 }
1118         }
1119
1120         if (pool_cfg != NULL) {
1121                 item = cYAML_create_seq_item(pools_node);
1122                 if (item == NULL)
1123                         goto out;
1124
1125                 if (cYAML_create_number(item, "enable", pool_cfg->pl_routing) ==
1126                     NULL)
1127                         goto out;
1128         }
1129
1130         /* create a buffers entry in the show. This is necessary so that
1131          * if the YAML output is used to configure a node, the buffer
1132          * configuration takes hold */
1133         buffers = cYAML_create_object(root, "buffers");
1134         if (buffers == NULL)
1135                 goto out;
1136
1137         for (i = 0; i < LNET_NRBPOOLS; i++) {
1138                 if (cYAML_create_number(buffers, pools[i], buf_count[i]) == NULL)
1139                         goto out;
1140         }
1141
1142         if (show_rc == NULL)
1143                 cYAML_print_tree(root);
1144
1145         if (l_errno != ENOENT) {
1146                 snprintf(err_str,
1147                          sizeof(err_str),
1148                          "\"cannot get routing information: %s\"",
1149                          strerror(l_errno));
1150                 rc = -l_errno;
1151                 goto out;
1152         } else
1153                 rc = LUSTRE_CFG_RC_NO_ERR;
1154
1155         snprintf(err_str, sizeof(err_str), "\"success\"");
1156         rc = LUSTRE_CFG_RC_NO_ERR;
1157
1158 out:
1159         free(buf);
1160         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1161                 cYAML_free_tree(root);
1162         } else if (show_rc != NULL && *show_rc != NULL) {
1163                 struct cYAML *routing_node;
1164                 /* there should exist only one routing block and one
1165                  * buffers block. If there already exists a previous one
1166                  * then don't add another */
1167                 routing_node = cYAML_get_object_item(*show_rc, "routing");
1168                 if (routing_node == NULL) {
1169                         cYAML_insert_sibling((*show_rc)->cy_child,
1170                                                 root->cy_child);
1171                         free(root);
1172                 } else {
1173                         cYAML_free_tree(root);
1174                 }
1175         } else {
1176                 *show_rc = root;
1177         }
1178
1179         cYAML_build_error(rc, seq_no, SHOW_CMD, "routing", err_str, err_rc);
1180
1181         return rc;
1182 }
1183
1184 int lustre_lnet_show_peer(char *knid, int seq_no, struct cYAML **show_rc,
1185                           struct cYAML **err_rc)
1186 {
1187         struct lnet_ioctl_peer_cfg *peer_info;
1188         struct lnet_peer_ni_credit_info *lpni_cri;
1189         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, ncpt = 0, i = 0, j = 0;
1190         int l_errno = 0;
1191         struct cYAML *root = NULL, *peer = NULL, *peer_ni = NULL,
1192                      *first_seq = NULL, *peer_root = NULL, *tmp = NULL;
1193         char err_str[LNET_MAX_STR_LEN];
1194         lnet_nid_t prev_primary_nid = LNET_NID_ANY, primary_nid = LNET_NID_ANY;
1195         char *data = calloc(sizeof(*peer_info) + sizeof(*lpni_cri), 1);
1196         bool new_peer = true;
1197
1198         snprintf(err_str, sizeof(err_str),
1199                  "\"out of memory\"");
1200
1201         if (data == NULL)
1202                 goto out;
1203
1204         peer_info = (struct lnet_ioctl_peer_cfg *)data;
1205
1206         /* create struct cYAML root object */
1207         root = cYAML_create_object(NULL, NULL);
1208         if (root == NULL)
1209                 goto out;
1210
1211         peer_root = cYAML_create_seq(root, "peer");
1212         if (peer_root == NULL)
1213                 goto out;
1214
1215         if (knid != NULL)
1216                 primary_nid = libcfs_str2nid(knid);
1217
1218         do {
1219                 for (i = 0;; i++) {
1220                         memset(data, 0, sizeof(*peer_info) + sizeof(*lpni_cri));
1221                         LIBCFS_IOC_INIT_V2(*peer_info, prcfg_hdr);
1222                         peer_info->prcfg_hdr.ioc_len = sizeof(*peer_info) +
1223                                                        sizeof(*lpni_cri);
1224                         peer_info->prcfg_idx = i;
1225
1226                         rc = l_ioctl(LNET_DEV_ID,
1227                                      IOC_LIBCFS_GET_PEER_NI, peer_info);
1228                         if (rc != 0) {
1229                                 l_errno = errno;
1230                                 break;
1231                         }
1232
1233                         if (primary_nid != LNET_NID_ANY &&
1234                             primary_nid != peer_info->prcfg_key_nid)
1235                                         continue;
1236
1237                         lpni_cri = (struct lnet_peer_ni_credit_info*)peer_info->prcfg_bulk;
1238
1239                         peer = cYAML_create_seq_item(peer_root);
1240                         if (peer == NULL)
1241                                 goto out;
1242
1243                         if (peer_info->prcfg_key_nid != prev_primary_nid) {
1244                                 prev_primary_nid = peer_info->prcfg_key_nid;
1245                                 new_peer = true;
1246                         }
1247
1248                         if (new_peer) {
1249                                 lnet_nid_t pnid = peer_info->prcfg_key_nid;
1250                                 if (cYAML_create_string(peer, "primary nid",
1251                                                         libcfs_nid2str(pnid))
1252                                     == NULL)
1253                                         goto out;
1254                                 tmp = cYAML_create_seq(peer, "peer ni");
1255                                 if (tmp == NULL)
1256                                         goto out;
1257                                 new_peer = false;
1258                         }
1259
1260                         if (first_seq == NULL)
1261                                 first_seq = peer;
1262
1263                         peer_ni = cYAML_create_seq_item(tmp);
1264                         if (peer_ni == NULL)
1265                                 goto out;
1266
1267                         if (cYAML_create_string(peer_ni, "nid",
1268                                                 libcfs_nid2str
1269                                                  (peer_info->prcfg_cfg_nid))
1270                             == NULL)
1271                                 goto out;
1272
1273                         if (cYAML_create_string(peer_ni, "state",
1274                                                 lpni_cri->cr_aliveness)
1275                             == NULL)
1276                                 goto out;
1277
1278                         if (cYAML_create_number(peer_ni, "refcount",
1279                                                 lpni_cri->cr_refcount) == NULL)
1280                                 goto out;
1281
1282                         if (cYAML_create_number(peer_ni, "max_ni_tx_credits",
1283                                                 lpni_cri->cr_ni_peer_tx_credits)
1284                             == NULL)
1285                                 goto out;
1286
1287                         if (cYAML_create_number(peer_ni, "available_tx_credits",
1288                                                 lpni_cri->cr_peer_tx_credits)
1289                             == NULL)
1290                                 goto out;
1291
1292                         if (cYAML_create_number(peer_ni, "available_rtr_credits",
1293                                                 lpni_cri->cr_peer_rtr_credits)
1294                             == NULL)
1295                                 goto out;
1296
1297                         if (cYAML_create_number(peer_ni, "min_rtr_credits",
1298                                                 lpni_cri->cr_peer_min_rtr_credits)
1299                             == NULL)
1300                                 goto out;
1301
1302                         if (cYAML_create_number(peer_ni, "tx_q_num_of_buf",
1303                                                 lpni_cri->cr_peer_tx_qnob)
1304                             == NULL)
1305                                 goto out;
1306                 }
1307
1308                 if (l_errno != ENOENT) {
1309                         snprintf(err_str,
1310                                 sizeof(err_str),
1311                                 "\"cannot get peer information: %s\"",
1312                                 strerror(l_errno));
1313                         rc = -l_errno;
1314                         goto out;
1315                 }
1316
1317                 j++;
1318         } while (j < ncpt);
1319
1320         /* print output iff show_rc is not provided */
1321         if (show_rc == NULL)
1322                 cYAML_print_tree(root);
1323
1324         snprintf(err_str, sizeof(err_str), "\"success\"");
1325         rc = LUSTRE_CFG_RC_NO_ERR;
1326
1327 out:
1328         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
1329                 cYAML_free_tree(root);
1330         } else if (show_rc != NULL && *show_rc != NULL) {
1331                 struct cYAML *show_node;
1332                 /* find the peer node, if one doesn't exist then
1333                  * insert one.  Otherwise add to the one there
1334                  */
1335                 show_node = cYAML_get_object_item(*show_rc,
1336                                                   "peer");
1337                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
1338                         cYAML_insert_child(show_node, first_seq);
1339                         free(peer_root);
1340                         free(root);
1341                 } else if (show_node == NULL) {
1342                         cYAML_insert_sibling((*show_rc)->cy_child,
1343                                              peer_root);
1344                         free(root);
1345                 } else {
1346                         cYAML_free_tree(root);
1347                 }
1348         } else {
1349                 *show_rc = root;
1350         }
1351
1352         cYAML_build_error(rc, seq_no, SHOW_CMD, "peer", err_str,
1353                           err_rc);
1354
1355         return rc;
1356 }
1357
1358 int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc,
1359                            struct cYAML **err_rc)
1360 {
1361         struct lnet_ioctl_lnet_stats data;
1362         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1363         int l_errno;
1364         char err_str[LNET_MAX_STR_LEN];
1365         struct cYAML *root = NULL, *stats = NULL;
1366
1367         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
1368
1369         LIBCFS_IOC_INIT_V2(data, st_hdr);
1370
1371         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LNET_STATS, &data);
1372         if (rc != 0) {
1373                 l_errno = errno;
1374                 snprintf(err_str,
1375                          sizeof(err_str),
1376                          "\"cannot get lnet statistics: %s\"",
1377                          strerror(l_errno));
1378                 rc = -l_errno;
1379                 goto out;
1380         }
1381
1382         root = cYAML_create_object(NULL, NULL);
1383         if (root == NULL)
1384                 goto out;
1385
1386         stats = cYAML_create_object(root, "statistics");
1387         if (stats == NULL)
1388                 goto out;
1389
1390         if (cYAML_create_number(stats, "msgs_alloc",
1391                                 data.st_cntrs.msgs_alloc) == NULL)
1392                 goto out;
1393
1394         if (cYAML_create_number(stats, "msgs_max",
1395                                 data.st_cntrs.msgs_max) == NULL)
1396                 goto out;
1397
1398         if (cYAML_create_number(stats, "errors",
1399                                 data.st_cntrs.errors) == NULL)
1400                 goto out;
1401
1402         if (cYAML_create_number(stats, "send_count",
1403                                 data.st_cntrs.send_count) == NULL)
1404                 goto out;
1405
1406         if (cYAML_create_number(stats, "recv_count",
1407                                 data.st_cntrs.recv_count) == NULL)
1408                 goto out;
1409
1410         if (cYAML_create_number(stats, "route_count",
1411                                 data.st_cntrs.route_count) == NULL)
1412                 goto out;
1413
1414         if (cYAML_create_number(stats, "drop_count",
1415                                 data.st_cntrs.drop_count) == NULL)
1416                 goto out;
1417
1418         if (cYAML_create_number(stats, "send_length",
1419                                 data.st_cntrs.send_length) == NULL)
1420                 goto out;
1421
1422         if (cYAML_create_number(stats, "recv_length",
1423                                 data.st_cntrs.recv_length) == NULL)
1424                 goto out;
1425
1426         if (cYAML_create_number(stats, "route_length",
1427                                 data.st_cntrs.route_length) == NULL)
1428                 goto out;
1429
1430         if (cYAML_create_number(stats, "drop_length",
1431                                 data.st_cntrs.drop_length) == NULL)
1432                 goto out;
1433
1434         if (show_rc == NULL)
1435                 cYAML_print_tree(root);
1436
1437         snprintf(err_str, sizeof(err_str), "\"success\"");
1438 out:
1439         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
1440                 cYAML_free_tree(root);
1441         } else if (show_rc != NULL && *show_rc != NULL) {
1442                 cYAML_insert_sibling((*show_rc)->cy_child,
1443                                         root->cy_child);
1444                 free(root);
1445         } else {
1446                 *show_rc = root;
1447         }
1448
1449         cYAML_build_error(rc, seq_no, SHOW_CMD, "statistics", err_str, err_rc);
1450
1451         return rc;
1452 }
1453
1454 typedef int (*cmd_handler_t)(struct cYAML *tree,
1455                              struct cYAML **show_rc,
1456                              struct cYAML **err_rc);
1457
1458 static int handle_yaml_config_route(struct cYAML *tree, struct cYAML **show_rc,
1459                                     struct cYAML **err_rc)
1460 {
1461         struct cYAML *net, *gw, *hop, *prio, *seq_no;
1462
1463         net = cYAML_get_object_item(tree, "net");
1464         gw = cYAML_get_object_item(tree, "gateway");
1465         hop = cYAML_get_object_item(tree, "hop");
1466         prio = cYAML_get_object_item(tree, "priority");
1467         seq_no = cYAML_get_object_item(tree, "seq_no");
1468
1469         return lustre_lnet_config_route((net) ? net->cy_valuestring : NULL,
1470                                         (gw) ? gw->cy_valuestring : NULL,
1471                                         (hop) ? hop->cy_valueint : -1,
1472                                         (prio) ? prio->cy_valueint : -1,
1473                                         (seq_no) ? seq_no->cy_valueint : -1,
1474                                         err_rc);
1475 }
1476
1477 static int handle_yaml_config_net(struct cYAML *tree, struct cYAML **show_rc,
1478                                   struct cYAML **err_rc)
1479 {
1480         struct cYAML *net, *intf, *tunables, *seq_no,
1481               *peer_to = NULL, *peer_buf_cr = NULL, *peer_cr = NULL,
1482               *credits = NULL, *ip2net = NULL, *smp = NULL, *child;
1483         struct lnet_ioctl_config_lnd_tunables *lnd_tunables_p = NULL;
1484         struct lnet_ioctl_config_lnd_tunables lnd_tunables;
1485         char devs[LNET_MAX_STR_LEN];
1486         char *loc = devs;
1487         int size = LNET_MAX_STR_LEN;
1488         int num;
1489         bool intf_found = false;
1490
1491         ip2net = cYAML_get_object_item(tree, "ip2net");
1492         net = cYAML_get_object_item(tree, "net");
1493         intf = cYAML_get_object_item(tree, "interfaces");
1494         if (intf != NULL) {
1495                 /* grab all the interfaces */
1496                 child = intf->cy_child;
1497                 while (child != NULL && size > 0) {
1498                         struct cYAML *lnd_params;
1499
1500                         if (child->cy_valuestring == NULL)
1501                                 goto ignore_child;
1502
1503                         if (loc > devs)
1504                                 num  = snprintf(loc, size, ",%s",
1505                                                 child->cy_valuestring);
1506                         else
1507                                 num = snprintf(loc, size, "%s",
1508                                                child->cy_valuestring);
1509                         size -= num;
1510                         loc += num;
1511                         intf_found = true;
1512
1513                         lnd_params = cYAML_get_object_item(intf,
1514                                                            "lnd tunables");
1515                         if (lnd_params != NULL) {
1516                                 const char *dev_name = child->cy_valuestring;
1517                                 lnd_tunables_p = &lnd_tunables;
1518
1519                                 lustre_interface_parse(lnd_params, dev_name,
1520                                                        lnd_tunables_p);
1521                         }
1522 ignore_child:
1523                         child = child->cy_next;
1524                 }
1525         }
1526
1527         tunables = cYAML_get_object_item(tree, "tunables");
1528         if (tunables != NULL) {
1529                 peer_to = cYAML_get_object_item(tunables, "peer_timeout");
1530                 peer_cr = cYAML_get_object_item(tunables, "peer_credits");
1531                 peer_buf_cr = cYAML_get_object_item(tunables,
1532                                                     "peer_buffer_credits");
1533                 credits = cYAML_get_object_item(tunables, "credits");
1534                 smp = cYAML_get_object_item(tunables, "CPT");
1535         }
1536         seq_no = cYAML_get_object_item(tree, "seq_no");
1537
1538         return lustre_lnet_config_net((net) ? net->cy_valuestring : NULL,
1539                                       (intf_found) ? devs : NULL,
1540                                       (ip2net) ? ip2net->cy_valuestring : NULL,
1541                                       (peer_to) ? peer_to->cy_valueint : -1,
1542                                       (peer_cr) ? peer_cr->cy_valueint : -1,
1543                                       (peer_buf_cr) ?
1544                                         peer_buf_cr->cy_valueint : -1,
1545                                       (credits) ? credits->cy_valueint : -1,
1546                                       (smp) ? smp->cy_valuestring : NULL,
1547                                       (seq_no) ? seq_no->cy_valueint : -1,
1548                                       lnd_tunables_p,
1549                                       err_rc);
1550 }
1551
1552 static void yaml_free_string_array(char **str_array, int num)
1553 {
1554         int i;
1555
1556         for (i = 0; i < num; i++)
1557                 free(str_array[num]);
1558         free(str_array);
1559 }
1560
1561 static int yaml_copy_peer_nids(struct cYAML *tree, char ***nidsppp)
1562 {
1563         struct cYAML *nids_entry = NULL, *child;
1564         char **nids = NULL;
1565         int num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
1566
1567         nids_entry = cYAML_get_object_item(tree, "nids");
1568         if (nids_entry != NULL) {
1569                 /* count */
1570                 child = nids_entry->cy_child;
1571                 while (child != NULL) {
1572                         num++;
1573                         child = child->cy_next;
1574                 }
1575
1576                 if (num == 0)
1577                         return LUSTRE_CFG_RC_MISSING_PARAM;
1578
1579                 nids = calloc(sizeof(*nids) * num, 1);
1580                 if (nids == NULL)
1581                         return LUSTRE_CFG_RC_OUT_OF_MEM;
1582
1583                 /* now grab all the nids */
1584                 child = nids_entry->cy_child;
1585                 num = 0;
1586                 while (child != NULL) {
1587                         nids[num] = calloc(strlen(child->cy_valuestring) + 1,
1588                                            1);
1589                         if (nids[num] == NULL) {
1590                                 rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1591                                 goto failed;
1592                         }
1593                         strncpy(nids[num], child->cy_valuestring,
1594                                 strlen(child->cy_valuestring));
1595                         child = child->cy_next;
1596                         num++;
1597                 }
1598                 rc = num;
1599         } else {
1600                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
1601                 goto failed;
1602         }
1603
1604         *nidsppp = nids;
1605         return rc;
1606
1607 failed:
1608         if (nids != NULL)
1609                 yaml_free_string_array(nids, num);
1610         *nidsppp = NULL;
1611         return rc;
1612 }
1613
1614 static int handle_yaml_config_peer(struct cYAML *tree, struct cYAML **show_rc,
1615                                    struct cYAML **err_rc)
1616 {
1617         char **nids = NULL;
1618         int num, rc;
1619         struct cYAML *seq_no, *key_nid;
1620
1621         num = yaml_copy_peer_nids(tree, &nids);
1622         if (num < 0)
1623                 return num;
1624
1625         seq_no = cYAML_get_object_item(tree, "seq_no");
1626         key_nid = cYAML_get_object_item(tree, "key_nid");
1627
1628         rc = lustre_lnet_config_peer_nid((key_nid) ? key_nid->cy_valuestring : NULL,
1629                                          nids,
1630                                          (seq_no) ? seq_no->cy_valueint : -1,
1631                                          err_rc);
1632
1633         yaml_free_string_array(nids, num);
1634         return rc;
1635 }
1636
1637 static int handle_yaml_del_peer(struct cYAML *tree, struct cYAML **show_rc,
1638                                 struct cYAML **err_rc)
1639 {
1640         char **nids = NULL;
1641         int num, rc;
1642         struct cYAML *seq_no, *key_nid;
1643
1644         num = yaml_copy_peer_nids(tree, &nids);
1645         if (num < 0)
1646                 return num;
1647
1648         seq_no = cYAML_get_object_item(tree, "seq_no");
1649         key_nid = cYAML_get_object_item(tree, "key_nid");
1650
1651         rc = lustre_lnet_del_peer_nid((key_nid) ? key_nid->cy_valuestring : NULL,
1652                                       nids,
1653                                       (seq_no) ? seq_no->cy_valueint : -1,
1654                                       err_rc);
1655
1656         yaml_free_string_array(nids, num);
1657         return rc;
1658 }
1659
1660 static int handle_yaml_config_buffers(struct cYAML *tree,
1661                                       struct cYAML **show_rc,
1662                                       struct cYAML **err_rc)
1663 {
1664         int rc;
1665         struct cYAML *tiny, *small, *large, *seq_no;
1666
1667         tiny = cYAML_get_object_item(tree, "tiny");
1668         small = cYAML_get_object_item(tree, "small");
1669         large = cYAML_get_object_item(tree, "large");
1670         seq_no = cYAML_get_object_item(tree, "seq_no");
1671
1672         rc = lustre_lnet_config_buffers((tiny) ? tiny->cy_valueint : -1,
1673                                         (small) ? small->cy_valueint : -1,
1674                                         (large) ? large->cy_valueint : -1,
1675                                         (seq_no) ? seq_no->cy_valueint : -1,
1676                                         err_rc);
1677
1678         return rc;
1679 }
1680
1681 static int handle_yaml_config_routing(struct cYAML *tree,
1682                                       struct cYAML **show_rc,
1683                                       struct cYAML **err_rc)
1684 {
1685         int rc = LUSTRE_CFG_RC_NO_ERR;
1686         struct cYAML *seq_no, *enable;
1687
1688         seq_no = cYAML_get_object_item(tree, "seq_no");
1689         enable = cYAML_get_object_item(tree, "enable");
1690
1691         if (enable) {
1692                 rc = lustre_lnet_enable_routing(enable->cy_valueint,
1693                                                 (seq_no) ?
1694                                                     seq_no->cy_valueint : -1,
1695                                                 err_rc);
1696         }
1697
1698         return rc;
1699 }
1700
1701 static int handle_yaml_del_route(struct cYAML *tree, struct cYAML **show_rc,
1702                                  struct cYAML **err_rc)
1703 {
1704         struct cYAML *net;
1705         struct cYAML *gw;
1706         struct cYAML *seq_no;
1707
1708         net = cYAML_get_object_item(tree, "net");
1709         gw = cYAML_get_object_item(tree, "gateway");
1710         seq_no = cYAML_get_object_item(tree, "seq_no");
1711
1712         return lustre_lnet_del_route((net) ? net->cy_valuestring : NULL,
1713                                      (gw) ? gw->cy_valuestring : NULL,
1714                                      (seq_no) ? seq_no->cy_valueint : -1,
1715                                      err_rc);
1716 }
1717
1718 static int handle_yaml_del_net(struct cYAML *tree, struct cYAML **show_rc,
1719                                struct cYAML **err_rc)
1720 {
1721         struct cYAML *net, *seq_no;
1722
1723         net = cYAML_get_object_item(tree, "net");
1724         seq_no = cYAML_get_object_item(tree, "seq_no");
1725
1726         return lustre_lnet_del_net((net) ? net->cy_valuestring : NULL,
1727                                    (seq_no) ? seq_no->cy_valueint : -1,
1728                                    err_rc);
1729 }
1730
1731 static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
1732                                    struct cYAML **err_rc)
1733 {
1734         struct cYAML *seq_no;
1735
1736         seq_no = cYAML_get_object_item(tree, "seq_no");
1737
1738         return lustre_lnet_enable_routing(0, (seq_no) ?
1739                                                 seq_no->cy_valueint : -1,
1740                                         err_rc);
1741 }
1742
1743 static int handle_yaml_show_route(struct cYAML *tree, struct cYAML **show_rc,
1744                                   struct cYAML **err_rc)
1745 {
1746         struct cYAML *net;
1747         struct cYAML *gw;
1748         struct cYAML *hop;
1749         struct cYAML *prio;
1750         struct cYAML *detail;
1751         struct cYAML *seq_no;
1752
1753         net = cYAML_get_object_item(tree, "net");
1754         gw = cYAML_get_object_item(tree, "gateway");
1755         hop = cYAML_get_object_item(tree, "hop");
1756         prio = cYAML_get_object_item(tree, "priority");
1757         detail = cYAML_get_object_item(tree, "detail");
1758         seq_no = cYAML_get_object_item(tree, "seq_no");
1759
1760         return lustre_lnet_show_route((net) ? net->cy_valuestring : NULL,
1761                                       (gw) ? gw->cy_valuestring : NULL,
1762                                       (hop) ? hop->cy_valueint : -1,
1763                                       (prio) ? prio->cy_valueint : -1,
1764                                       (detail) ? detail->cy_valueint : 0,
1765                                       (seq_no) ? seq_no->cy_valueint : -1,
1766                                       show_rc,
1767                                       err_rc);
1768 }
1769
1770 static int handle_yaml_show_net(struct cYAML *tree, struct cYAML **show_rc,
1771                                 struct cYAML **err_rc)
1772 {
1773         struct cYAML *net, *detail, *seq_no;
1774
1775         net = cYAML_get_object_item(tree, "net");
1776         detail = cYAML_get_object_item(tree, "detail");
1777         seq_no = cYAML_get_object_item(tree, "seq_no");
1778
1779         return lustre_lnet_show_net((net) ? net->cy_valuestring : NULL,
1780                                     (detail) ? detail->cy_valueint : 0,
1781                                     (seq_no) ? seq_no->cy_valueint : -1,
1782                                     show_rc,
1783                                     err_rc);
1784 }
1785
1786 static int handle_yaml_show_routing(struct cYAML *tree, struct cYAML **show_rc,
1787                                     struct cYAML **err_rc)
1788 {
1789         struct cYAML *seq_no;
1790
1791         seq_no = cYAML_get_object_item(tree, "seq_no");
1792
1793         return lustre_lnet_show_routing((seq_no) ? seq_no->cy_valueint : -1,
1794                                         show_rc, err_rc);
1795 }
1796
1797 static int handle_yaml_show_credits(struct cYAML *tree, struct cYAML **show_rc,
1798                                     struct cYAML **err_rc)
1799 {
1800         struct cYAML *seq_no, *key_nid;
1801
1802         seq_no = cYAML_get_object_item(tree, "seq_no");
1803         key_nid = cYAML_get_object_item(tree, "key_nid");
1804
1805         return lustre_lnet_show_peer((key_nid) ? key_nid->cy_valuestring : NULL,
1806                                      (seq_no) ? seq_no->cy_valueint : -1,
1807                                      show_rc, err_rc);
1808 }
1809
1810 static int handle_yaml_show_stats(struct cYAML *tree, struct cYAML **show_rc,
1811                                   struct cYAML **err_rc)
1812 {
1813         struct cYAML *seq_no;
1814
1815         seq_no = cYAML_get_object_item(tree, "seq_no");
1816
1817         return lustre_lnet_show_stats((seq_no) ? seq_no->cy_valueint : -1,
1818                                       show_rc, err_rc);
1819 }
1820
1821 struct lookup_cmd_hdlr_tbl {
1822         char *name;
1823         cmd_handler_t cb;
1824 };
1825
1826 static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
1827         {"route", handle_yaml_config_route},
1828         {"net", handle_yaml_config_net},
1829         {"peer", handle_yaml_config_peer},
1830         {"routing", handle_yaml_config_routing},
1831         {"buffers", handle_yaml_config_buffers},
1832         {NULL, NULL}
1833 };
1834
1835 static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
1836         {"route", handle_yaml_del_route},
1837         {"net", handle_yaml_del_net},
1838         {"peer", handle_yaml_del_peer},
1839         {"routing", handle_yaml_del_routing},
1840         {NULL, NULL}
1841 };
1842
1843 static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = {
1844         {"route", handle_yaml_show_route},
1845         {"net", handle_yaml_show_net},
1846         {"buffers", handle_yaml_show_routing},
1847         {"routing", handle_yaml_show_routing},
1848         {"credits", handle_yaml_show_credits},
1849         {"statistics", handle_yaml_show_stats},
1850         {NULL, NULL}
1851 };
1852
1853 static cmd_handler_t lookup_fn(char *key,
1854                                struct lookup_cmd_hdlr_tbl *tbl)
1855 {
1856         int i;
1857         if (key == NULL)
1858                 return NULL;
1859
1860         for (i = 0; tbl[i].name != NULL; i++) {
1861                 if (strncmp(key, tbl[i].name, strlen(tbl[i].name)) == 0)
1862                         return tbl[i].cb;
1863         }
1864
1865         return NULL;
1866 }
1867
1868 static int lustre_yaml_cb_helper(char *f, struct lookup_cmd_hdlr_tbl *table,
1869                                  struct cYAML **show_rc, struct cYAML **err_rc)
1870 {
1871         struct cYAML *tree, *item = NULL, *head, *child;
1872         cmd_handler_t cb;
1873         char err_str[LNET_MAX_STR_LEN];
1874         int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
1875
1876         tree = cYAML_build_tree(f, NULL, 0, err_rc);
1877         if (tree == NULL)
1878                 return LUSTRE_CFG_RC_BAD_PARAM;
1879
1880         child = tree->cy_child;
1881         while (child != NULL) {
1882                 cb = lookup_fn(child->cy_string, table);
1883                 if (cb == NULL) {
1884                         snprintf(err_str, sizeof(err_str),
1885                                 "\"call back for '%s' not found\"",
1886                                 child->cy_string);
1887                         cYAML_build_error(LUSTRE_CFG_RC_BAD_PARAM, -1,
1888                                         "yaml", "helper", err_str, err_rc);
1889                         goto out;
1890                 }
1891
1892                 if (cYAML_is_sequence(child)) {
1893                         while ((head = cYAML_get_next_seq_item(child, &item))
1894                                != NULL) {
1895                                 rc = cb(head, show_rc, err_rc);
1896                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
1897                                         return_rc = rc;
1898                         }
1899                 } else {
1900                         rc = cb(child, show_rc, err_rc);
1901                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1902                                 return_rc = rc;
1903                 }
1904                 item = NULL;
1905                 child = child->cy_next;
1906         }
1907
1908 out:
1909         cYAML_free_tree(tree);
1910
1911         return return_rc;
1912 }
1913
1914 int lustre_yaml_config(char *f, struct cYAML **err_rc)
1915 {
1916         return lustre_yaml_cb_helper(f, lookup_config_tbl,
1917                                      NULL, err_rc);
1918 }
1919
1920 int lustre_yaml_del(char *f, struct cYAML **err_rc)
1921 {
1922         return lustre_yaml_cb_helper(f, lookup_del_tbl,
1923                                      NULL, err_rc);
1924 }
1925
1926 int lustre_yaml_show(char *f, struct cYAML **show_rc, struct cYAML **err_rc)
1927 {
1928         return lustre_yaml_cb_helper(f, lookup_show_tbl,
1929                                      show_rc, err_rc);
1930 }