Whamcloud - gitweb
LU-9078 lnet: Fix route hops print
[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 <byteswap.h>
39 #include <netdb.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/ioctl.h>
44 #include <net/if.h>
45 #include <libcfs/util/ioctl.h>
46 #include <lnet/lnetctl.h>
47 #include <lnet/socklnd.h>
48 #include "liblnd.h"
49 #include <lnet/lnet.h>
50 #include <sys/types.h>
51 #include <ifaddrs.h>
52 #include "liblnetconfig.h"
53 #include "cyaml.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
62 /*
63  * lustre_lnet_ip_range_descr
64  *      Describes an IP range.
65  *      Each octect is an expression
66  */
67 struct lustre_lnet_ip_range_descr {
68         struct list_head ipr_entry;
69         struct list_head ipr_expr;
70 };
71
72 /*
73  * lustre_lnet_ip2nets
74  *      Describes an ip2nets rule. This can be on a list of rules.
75  */
76 struct lustre_lnet_ip2nets {
77         struct lnet_dlc_network_descr ip2nets_net;
78         struct list_head ip2nets_ip_ranges;
79 };
80
81 /*
82  * free_intf_descr
83  *      frees the memory allocated for an intf descriptor.
84  */
85 void free_intf_descr(struct lnet_dlc_intf_descr *intf_descr)
86 {
87         if (!intf_descr)
88                 return;
89
90         if (intf_descr->cpt_expr != NULL)
91                 cfs_expr_list_free(intf_descr->cpt_expr);
92         free(intf_descr);
93 }
94
95 /*
96  * lustre_lnet_add_ip_range
97  * Formatting:
98  *      given a string of the format:
99  *      <expr.expr.expr.expr> parse each expr into
100  *      a lustre_lnet_ip_range_descr structure and insert on the list.
101  *
102  *      This function is called from
103  *              YAML on each ip-range.
104  *              As a result of lnetctl command
105  *              When building a NID or P2P selection rules
106  */
107 int lustre_lnet_add_ip_range(struct list_head *list, char *str_ip_range)
108 {
109         struct lustre_lnet_ip_range_descr *ip_range;
110         int rc;
111
112         ip_range = calloc(1, sizeof(*ip_range));
113         if (ip_range == NULL)
114                 return LUSTRE_CFG_RC_OUT_OF_MEM;
115
116         INIT_LIST_HEAD(&ip_range->ipr_entry);
117         INIT_LIST_HEAD(&ip_range->ipr_expr);
118
119         rc = cfs_ip_addr_parse(str_ip_range, strlen(str_ip_range),
120                                &ip_range->ipr_expr);
121         if (rc != 0)
122                 return LUSTRE_CFG_RC_BAD_PARAM;
123
124         list_add_tail(&ip_range->ipr_entry, list);
125
126         return LUSTRE_CFG_RC_NO_ERR;
127 }
128
129 int lustre_lnet_add_intf_descr(struct list_head *list, char *intf, int len)
130 {
131         char *open_sq_bracket = NULL, *close_sq_bracket = NULL,
132              *intf_name;
133         struct lnet_dlc_intf_descr *intf_descr = NULL;
134         int rc;
135         char intf_string[LNET_MAX_STR_LEN];
136
137         if (len >= LNET_MAX_STR_LEN)
138                 return LUSTRE_CFG_RC_BAD_PARAM;
139
140         strncpy(intf_string, intf, len);
141         intf_string[len] = '\0';
142
143         intf_descr = calloc(1, sizeof(*intf_descr));
144         if (intf_descr == NULL)
145                 return LUSTRE_CFG_RC_OUT_OF_MEM;
146
147         INIT_LIST_HEAD(&intf_descr->intf_on_network);
148
149         intf_name = intf_string;
150         open_sq_bracket = strchr(intf_string, '[');
151         if (open_sq_bracket != NULL) {
152                 close_sq_bracket = strchr(intf_string, ']');
153                 if (close_sq_bracket == NULL) {
154                         free(intf_descr);
155                         return LUSTRE_CFG_RC_BAD_PARAM;
156                 }
157                 rc = cfs_expr_list_parse(open_sq_bracket,
158                                          strlen(open_sq_bracket), 0, UINT_MAX,
159                                          &intf_descr->cpt_expr);
160                 if (rc < 0) {
161                         free(intf_descr);
162                         return LUSTRE_CFG_RC_BAD_PARAM;
163                 }
164                 strncpy(intf_descr->intf_name, intf_name,
165                         open_sq_bracket - intf_name);
166                 intf_descr->intf_name[open_sq_bracket - intf_name] = '\0';
167         } else {
168                 strcpy(intf_descr->intf_name, intf_name);
169                 intf_descr->cpt_expr = NULL;
170         }
171
172         list_add_tail(&intf_descr->intf_on_network, list);
173
174         return LUSTRE_CFG_RC_NO_ERR;
175 }
176
177 void lustre_lnet_init_nw_descr(struct lnet_dlc_network_descr *nw_descr)
178 {
179         if (nw_descr != NULL) {
180                 INIT_LIST_HEAD(&nw_descr->network_on_rule);
181                 INIT_LIST_HEAD(&nw_descr->nw_intflist);
182         }
183 }
184
185 int lustre_lnet_parse_nids(char *nids, char **array, int size,
186                            char ***out_array)
187 {
188         int num_nids = 0;
189         char *comma = nids, *cur, *entry;
190         char **new_array;
191         int i, len, start = 0, finish = 0;
192
193         if (nids == NULL || strlen(nids) == 0)
194                 return size;
195
196         /* count the number or new nids, by counting the number of commas */
197         while (comma) {
198                 comma = strchr(comma, ',');
199                 if (comma) {
200                         comma++;
201                         num_nids++;
202                 } else {
203                         num_nids++;
204                 }
205         }
206
207         /*
208          * if the array is not NULL allocate a large enough array to house
209          * the old and new entries
210          */
211         new_array = calloc(sizeof(char*),
212                            (size > 0) ? size + num_nids : num_nids);
213
214         if (!new_array)
215                 goto failed;
216
217         /* parse our the new nids and add them to the tail of the array */
218         comma = nids;
219         cur = nids;
220         start = (size > 0) ? size: 0;
221         finish = (size > 0) ? size + num_nids : num_nids;
222         for (i = start; i < finish; i++) {
223                 comma = strchr(comma, ',');
224                 if (!comma)
225                         /*
226                          * the length of the string to be parsed out is
227                          * from cur to end of string. So it's good enough
228                          * to strlen(cur)
229                          */
230                         len = strlen(cur) + 1;
231                 else
232                         /* length of the string is comma - cur */
233                         len = (comma - cur) + 1;
234
235                 entry = calloc(1, len);
236                 if (!entry) {
237                         finish = i > 0 ? i - 1: 0;
238                         goto failed;
239                 }
240                 strncpy(entry, cur, len - 1);
241                 entry[len] = '\0';
242                 new_array[i] = entry;
243                 if (comma) {
244                         comma++;
245                         cur = comma;
246                 }
247         }
248
249         /* add the old entries in the array and delete the old array*/
250         for (i = 0; i < size; i++)
251                 new_array[i] = array[i];
252
253         if (array)
254                 free(array);
255
256         *out_array = new_array;
257
258         return finish;
259
260 failed:
261         for (i = start; i < finish; i++)
262                 free(new_array[i]);
263         if (new_array)
264                 free(new_array);
265
266         return size;
267 }
268
269 /*
270  * format expected:
271  *      <intf>[<expr>], <intf>[<expr>],..
272  */
273 int lustre_lnet_parse_interfaces(char *intf_str,
274                                  struct lnet_dlc_network_descr *nw_descr)
275 {
276         char *open_square;
277         char *close_square;
278         char *comma;
279         char *cur = intf_str, *next = NULL;
280         char *end = intf_str + strlen(intf_str);
281         int rc, len;
282         struct lnet_dlc_intf_descr *intf_descr, *tmp;
283
284         if (nw_descr == NULL)
285                 return LUSTRE_CFG_RC_BAD_PARAM;
286
287         while (cur < end) {
288                 open_square = strchr(cur, '[');
289                 if (open_square != NULL) {
290                         close_square = strchr(cur, ']');
291                         if (close_square == NULL) {
292                                 rc = LUSTRE_CFG_RC_BAD_PARAM;
293                                 goto failed;
294                         }
295
296                         comma = strchr(cur, ',');
297                         if (comma != NULL && comma > close_square) {
298                                 next = comma + 1;
299                                 len = next - close_square;
300                         } else {
301                                 len = strlen(cur);
302                                 next = cur + len;
303                         }
304                 } else {
305                         comma = strchr(cur, ',');
306                         if (comma != NULL) {
307                                 next = comma + 1;
308                                 len = comma - cur;
309                         } else {
310                                 len = strlen(cur);
311                                 next = cur + len;
312                         }
313                 }
314
315                 rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist, cur, len);
316                 if (rc != LUSTRE_CFG_RC_NO_ERR)
317                         goto failed;
318
319                 cur = next;
320         }
321
322         return LUSTRE_CFG_RC_NO_ERR;
323
324 failed:
325         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
326                                  intf_on_network) {
327                 list_del(&intf_descr->intf_on_network);
328                 free_intf_descr(intf_descr);
329         }
330
331         return rc;
332 }
333
334 int lustre_lnet_config_lib_init(void)
335 {
336         return register_ioc_dev(LNET_DEV_ID, LNET_DEV_PATH,
337                                 LNET_DEV_MAJOR, LNET_DEV_MINOR);
338 }
339
340 void lustre_lnet_config_lib_uninit(void)
341 {
342         unregister_ioc_dev(LNET_DEV_ID);
343 }
344
345 int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
346                                  int seq_no, struct cYAML **err_rc)
347 {
348         struct libcfs_ioctl_data data;
349         unsigned int opc;
350         int rc;
351         char err_str[LNET_MAX_STR_LEN];
352
353         snprintf(err_str, sizeof(err_str), "\"Success\"");
354
355         LIBCFS_IOC_INIT(data);
356
357         /* Reverse logic is used here in order not to change
358          * the lctl utility */
359         data.ioc_flags = load_ni_from_mod ? 0 : 1;
360
361         opc = up ? IOC_LIBCFS_CONFIGURE : IOC_LIBCFS_UNCONFIGURE;
362
363         rc = l_ioctl(LNET_DEV_ID, opc, &data);
364         if (rc != 0) {
365                 snprintf(err_str,
366                         sizeof(err_str),
367                         "\"LNet %s error: %s\"", (up) ? "configure" :
368                         "unconfigure", strerror(errno));
369                 rc = -errno;
370         }
371
372         cYAML_build_error(rc, seq_no, (up) ? CONFIG_CMD : UNCONFIG_CMD,
373                           "lnet", err_str, err_rc);
374
375         return rc;
376 }
377
378 static lnet_nid_t *allocate_create_nid_array(char **nids, __u32 num_nids,
379                                              char *err_str)
380 {
381         lnet_nid_t *array = NULL;
382         __u32 i;
383
384         if (!nids) {
385                 snprintf(err_str, LNET_MAX_STR_LEN, "no NIDs to add");
386                 return NULL;
387         }
388
389         array = calloc(sizeof(*array) * num_nids, 1);
390         if (array == NULL) {
391                 snprintf(err_str, LNET_MAX_STR_LEN, "out of memory");
392                 return NULL;
393         }
394
395         for (i = 0; i < num_nids; i++) {
396                 array[i] = libcfs_str2nid(nids[i]);
397                 if (array[i] == LNET_NID_ANY) {
398                         free(array);
399                         snprintf(err_str, LNET_MAX_STR_LEN,
400                                  "bad NID: '%s'",
401                                  nids[i]);
402                         return NULL;
403                 }
404         }
405
406         return array;
407 }
408
409 static int dispatch_peer_ni_cmd(lnet_nid_t pnid, lnet_nid_t nid, __u32 cmd,
410                                 struct lnet_ioctl_peer_cfg *data,
411                                 char *err_str, char *cmd_str)
412 {
413         int rc;
414
415         data->prcfg_prim_nid = pnid;
416         data->prcfg_cfg_nid = nid;
417
418         rc = l_ioctl(LNET_DEV_ID, cmd, data);
419         if (rc != 0) {
420                 rc = -errno;
421                 snprintf(err_str,
422                         LNET_MAX_STR_LEN,
423                         "\"cannot %s peer ni: %s\"",
424                         (cmd_str) ? cmd_str : "add", strerror(errno));
425         }
426
427         return rc;
428 }
429
430 int lustre_lnet_config_peer_nid(char *pnid, char **nid, int num_nids,
431                                 bool mr, int seq_no, struct cYAML **err_rc)
432 {
433         struct lnet_ioctl_peer_cfg data;
434         lnet_nid_t prim_nid = LNET_NID_ANY;
435         int rc = LUSTRE_CFG_RC_NO_ERR;
436         int idx = 0;
437         bool nid0_used = false;
438         char err_str[LNET_MAX_STR_LEN] = {0};
439         lnet_nid_t *nids = allocate_create_nid_array(nid, num_nids, err_str);
440
441         if (pnid) {
442                 prim_nid = libcfs_str2nid(pnid);
443                 if (prim_nid == LNET_NID_ANY) {
444                         snprintf(err_str, sizeof(err_str),
445                                  "bad key NID: '%s'",
446                                  pnid);
447                         rc = LUSTRE_CFG_RC_MISSING_PARAM;
448                         goto out;
449                 }
450         } else if (!nids || nids[0] == LNET_NID_ANY) {
451                 snprintf(err_str, sizeof(err_str),
452                          "no NIDs provided for configuration");
453                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
454                 goto out;
455         } else {
456                 prim_nid = LNET_NID_ANY;
457         }
458
459         snprintf(err_str, sizeof(err_str), "\"Success\"");
460
461         LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
462         data.prcfg_mr = mr;
463
464         /*
465          * if prim_nid is not specified use the first nid in the list of
466          * nids provided as the prim_nid. NOTE: on entering 'if' we must
467          * have at least 1 NID
468          */
469         if (prim_nid == LNET_NID_ANY) {
470                 nid0_used = true;
471                 prim_nid = nids[0];
472         }
473
474         /* Create the prim_nid first */
475         rc = dispatch_peer_ni_cmd(prim_nid, LNET_NID_ANY,
476                                   IOC_LIBCFS_ADD_PEER_NI,
477                                   &data, err_str, "add");
478
479         if (rc != 0)
480                 goto out;
481
482         /* add the rest of the nids to the key nid if any are available */
483         for (idx = nid0_used ? 1 : 0 ; nids && idx < num_nids; idx++) {
484                 /*
485                  * If prim_nid is not provided then the first nid in the
486                  * list becomes the prim_nid. First time round the loop use
487                  * LNET_NID_ANY for the first parameter, then use nid[0]
488                  * as the key nid after wards
489                  */
490                 rc = dispatch_peer_ni_cmd(prim_nid, nids[idx],
491                                           IOC_LIBCFS_ADD_PEER_NI, &data,
492                                           err_str, "add");
493
494                 if (rc != 0)
495                         goto out;
496         }
497
498 out:
499         if (nids != NULL)
500                 free(nids);
501         cYAML_build_error(rc, seq_no, ADD_CMD, "peer_ni", err_str, err_rc);
502         return rc;
503 }
504
505 int lustre_lnet_del_peer_nid(char *pnid, char **nid, int num_nids,
506                              int seq_no, struct cYAML **err_rc)
507 {
508         struct lnet_ioctl_peer_cfg data;
509         lnet_nid_t prim_nid;
510         int rc = LUSTRE_CFG_RC_NO_ERR;
511         int idx = 0;
512         char err_str[LNET_MAX_STR_LEN] = {0};
513         lnet_nid_t *nids = allocate_create_nid_array(nid, num_nids, err_str);
514
515         if (pnid == NULL) {
516                 snprintf(err_str, sizeof(err_str),
517                          "\"Primary nid is not provided\"");
518                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
519                 goto out;
520         } else {
521                 prim_nid = libcfs_str2nid(pnid);
522                 if (prim_nid == LNET_NID_ANY) {
523                         rc = LUSTRE_CFG_RC_BAD_PARAM;
524                         snprintf(err_str, sizeof(err_str),
525                                  "bad key NID: '%s'",
526                                  pnid);
527                         goto out;
528                 }
529         }
530
531         snprintf(err_str, sizeof(err_str), "\"Success\"");
532
533         LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
534         if (!nids || nids[0] == LNET_NID_ANY) {
535                 rc = dispatch_peer_ni_cmd(prim_nid, LNET_NID_ANY,
536                                           IOC_LIBCFS_DEL_PEER_NI,
537                                           &data, err_str, "del");
538                 goto out;
539         }
540
541         for (idx = 0; nids && idx < num_nids; idx++) {
542                 rc = dispatch_peer_ni_cmd(prim_nid, nids[idx],
543                                           IOC_LIBCFS_DEL_PEER_NI, &data,
544                                           err_str, "del");
545
546                 if (rc != 0)
547                         goto out;
548         }
549
550 out:
551         if (nids != NULL)
552                 free(nids);
553         cYAML_build_error(rc, seq_no, DEL_CMD, "peer_ni", err_str, err_rc);
554         return rc;
555 }
556
557 int lustre_lnet_config_route(char *nw, char *gw, int hops, int prio,
558                              int seq_no, struct cYAML **err_rc)
559 {
560         struct lnet_ioctl_config_data data;
561         lnet_nid_t gateway_nid;
562         int rc = LUSTRE_CFG_RC_NO_ERR;
563         __u32 net = LNET_NIDNET(LNET_NID_ANY);
564         char err_str[LNET_MAX_STR_LEN];
565
566         snprintf(err_str, sizeof(err_str), "\"Success\"");
567
568         if (nw == NULL || gw == NULL) {
569                 snprintf(err_str,
570                          sizeof(err_str),
571                          "\"missing mandatory parameter(s): '%s'\"",
572                          (nw == NULL && gw == NULL) ? "network, gateway" :
573                          (nw == NULL) ? "network" : "gateway");
574                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
575                 goto out;
576         }
577
578         net = libcfs_str2net(nw);
579         if (net == LNET_NIDNET(LNET_NID_ANY)) {
580                 snprintf(err_str,
581                          sizeof(err_str),
582                          "\"cannot parse net %s\"", nw);
583                 rc = LUSTRE_CFG_RC_BAD_PARAM;
584                 goto out;
585         }
586
587         gateway_nid = libcfs_str2nid(gw);
588         if (gateway_nid == LNET_NID_ANY) {
589                 snprintf(err_str,
590                         sizeof(err_str),
591                         "\"cannot parse gateway NID '%s'\"", gw);
592                 rc = LUSTRE_CFG_RC_BAD_PARAM;
593                 goto out;
594         }
595
596         if (hops == -1) {
597                 /* hops is undefined */
598                 hops = LNET_UNDEFINED_HOPS;
599         } else if (hops < 1 || hops > 255) {
600                 snprintf(err_str,
601                         sizeof(err_str),
602                         "\"invalid hop count %d, must be between 1 and 255\"",
603                         hops);
604                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
605                 goto out;
606         }
607
608         if (prio == -1) {
609                 prio = 0;
610         } else if (prio < 0) {
611                 snprintf(err_str,
612                          sizeof(err_str),
613                         "\"invalid priority %d, must be greater than 0\"",
614                         prio);
615                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
616                 goto out;
617         }
618
619         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
620         data.cfg_net = net;
621         data.cfg_config_u.cfg_route.rtr_hop = hops;
622         data.cfg_config_u.cfg_route.rtr_priority = prio;
623         data.cfg_nid = gateway_nid;
624
625         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_ROUTE, &data);
626         if (rc != 0) {
627                 rc = -errno;
628                 snprintf(err_str,
629                          sizeof(err_str),
630                          "\"cannot add route: %s\"", strerror(errno));
631                 goto out;
632         }
633
634 out:
635         cYAML_build_error(rc, seq_no, ADD_CMD, "route", err_str, err_rc);
636
637         return rc;
638 }
639
640 int lustre_lnet_del_route(char *nw, char *gw,
641                           int seq_no, struct cYAML **err_rc)
642 {
643         struct lnet_ioctl_config_data data;
644         lnet_nid_t gateway_nid;
645         int rc = LUSTRE_CFG_RC_NO_ERR;
646         __u32 net = LNET_NIDNET(LNET_NID_ANY);
647         char err_str[LNET_MAX_STR_LEN];
648
649         snprintf(err_str, sizeof(err_str), "\"Success\"");
650
651         if (nw == NULL || gw == NULL) {
652                 snprintf(err_str,
653                          sizeof(err_str),
654                          "\"missing mandatory parameter(s): '%s'\"",
655                          (nw == NULL && gw == NULL) ? "network, gateway" :
656                          (nw == NULL) ? "network" : "gateway");
657                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
658                 goto out;
659         }
660
661         net = libcfs_str2net(nw);
662         if (net == LNET_NIDNET(LNET_NID_ANY)) {
663                 snprintf(err_str,
664                          sizeof(err_str),
665                          "\"cannot parse net '%s'\"", nw);
666                 rc = LUSTRE_CFG_RC_BAD_PARAM;
667                 goto out;
668         }
669
670         gateway_nid = libcfs_str2nid(gw);
671         if (gateway_nid == LNET_NID_ANY) {
672                 snprintf(err_str,
673                          sizeof(err_str),
674                          "\"cannot parse gateway NID '%s'\"", gw);
675                 rc = LUSTRE_CFG_RC_BAD_PARAM;
676                 goto out;
677         }
678
679         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
680         data.cfg_net = net;
681         data.cfg_nid = gateway_nid;
682
683         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_ROUTE, &data);
684         if (rc != 0) {
685                 rc = -errno;
686                 snprintf(err_str,
687                          sizeof(err_str),
688                          "\"cannot delete route: %s\"", strerror(errno));
689                 goto out;
690         }
691
692 out:
693         cYAML_build_error(rc, seq_no, DEL_CMD, "route", err_str, err_rc);
694
695         return rc;
696 }
697
698 int lustre_lnet_show_route(char *nw, char *gw, int hops, int prio, int detail,
699                            int seq_no, struct cYAML **show_rc,
700                            struct cYAML **err_rc)
701 {
702         struct lnet_ioctl_config_data data;
703         lnet_nid_t gateway_nid;
704         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
705         int l_errno = 0;
706         __u32 net = LNET_NIDNET(LNET_NID_ANY);
707         int i;
708         struct cYAML *root = NULL, *route = NULL, *item = NULL;
709         struct cYAML *first_seq = NULL;
710         char err_str[LNET_MAX_STR_LEN];
711         bool exist = false;
712
713         snprintf(err_str, sizeof(err_str),
714                  "\"out of memory\"");
715
716         if (nw != NULL) {
717                 net = libcfs_str2net(nw);
718                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
719                         snprintf(err_str,
720                                  sizeof(err_str),
721                                  "\"cannot parse net '%s'\"", nw);
722                         rc = LUSTRE_CFG_RC_BAD_PARAM;
723                         goto out;
724                 }
725
726         } else {
727                 /* show all routes without filtering on net */
728                 net = LNET_NIDNET(LNET_NID_ANY);
729         }
730
731         if (gw != NULL) {
732                 gateway_nid = libcfs_str2nid(gw);
733                 if (gateway_nid == LNET_NID_ANY) {
734                         snprintf(err_str,
735                                  sizeof(err_str),
736                                  "\"cannot parse gateway NID '%s'\"", gw);
737                         rc = LUSTRE_CFG_RC_BAD_PARAM;
738                         goto out;
739                 }
740         } else
741                 /* show all routes with out filtering on gateway */
742                 gateway_nid = LNET_NID_ANY;
743
744         if ((hops < 1 && hops != -1) || hops > 255) {
745                 snprintf(err_str,
746                          sizeof(err_str),
747                          "\"invalid hop count %d, must be between 0 and 256\"",
748                          hops);
749                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
750                 goto out;
751         }
752
753         /* create struct cYAML root object */
754         root = cYAML_create_object(NULL, NULL);
755         if (root == NULL)
756                 goto out;
757
758         route = cYAML_create_seq(root, "route");
759         if (route == NULL)
760                 goto out;
761
762         for (i = 0;; i++) {
763                 LIBCFS_IOC_INIT_V2(data, cfg_hdr);
764                 data.cfg_count = i;
765
766                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_ROUTE, &data);
767                 if (rc != 0) {
768                         l_errno = errno;
769                         break;
770                 }
771
772                 /* filter on provided data */
773                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
774                     net != data.cfg_net)
775                         continue;
776
777                 if (gateway_nid != LNET_NID_ANY &&
778                     gateway_nid != data.cfg_nid)
779                         continue;
780
781                 if (hops != -1 &&
782                     hops != data.cfg_config_u.cfg_route.rtr_hop)
783                         continue;
784
785                 if (prio != -1 &&
786                     prio != data.cfg_config_u.cfg_route.rtr_priority)
787                         continue;
788
789                 /* default rc to -1 incase we hit the goto */
790                 rc = -1;
791                 exist = true;
792
793                 item = cYAML_create_seq_item(route);
794                 if (item == NULL)
795                         goto out;
796
797                 if (first_seq == NULL)
798                         first_seq = item;
799
800                 if (cYAML_create_string(item, "net",
801                                         libcfs_net2str(data.cfg_net)) == NULL)
802                         goto out;
803
804                 if (cYAML_create_string(item, "gateway",
805                                         libcfs_nid2str(data.cfg_nid)) == NULL)
806                         goto out;
807
808                 if (detail) {
809                         if (cYAML_create_number(item, "hop",
810                                                 (int) data.cfg_config_u.
811                                                 cfg_route.rtr_hop) ==
812                             NULL)
813                                 goto out;
814
815                         if (cYAML_create_number(item, "priority",
816                                                 data.cfg_config_u.
817                                                 cfg_route.rtr_priority) == NULL)
818                                 goto out;
819
820                         if (cYAML_create_string(item, "state",
821                                                 data.cfg_config_u.cfg_route.
822                                                         rtr_flags ?
823                                                 "up" : "down") == NULL)
824                                 goto out;
825                 }
826         }
827
828         /* print output iff show_rc is not provided */
829         if (show_rc == NULL)
830                 cYAML_print_tree(root);
831
832         if (l_errno != ENOENT) {
833                 snprintf(err_str,
834                          sizeof(err_str),
835                          "\"cannot get routes: %s\"",
836                          strerror(l_errno));
837                 rc = -l_errno;
838                 goto out;
839         } else
840                 rc = LUSTRE_CFG_RC_NO_ERR;
841
842         snprintf(err_str, sizeof(err_str), "\"success\"");
843 out:
844         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
845                 cYAML_free_tree(root);
846         } else if (show_rc != NULL && *show_rc != NULL) {
847                 struct cYAML *show_node;
848                 /* find the route node, if one doesn't exist then
849                  * insert one.  Otherwise add to the one there
850                  */
851                 show_node = cYAML_get_object_item(*show_rc, "route");
852                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
853                         cYAML_insert_child(show_node, first_seq);
854                         free(route);
855                         free(root);
856                 } else if (show_node == NULL) {
857                         cYAML_insert_sibling((*show_rc)->cy_child,
858                                                 route);
859                         free(root);
860                 } else {
861                         cYAML_free_tree(root);
862                 }
863         } else {
864                 *show_rc = root;
865         }
866
867         cYAML_build_error(rc, seq_no, SHOW_CMD, "route", err_str, err_rc);
868
869         return rc;
870 }
871
872 static int socket_intf_query(int request, char *intf,
873                              struct ifreq *ifr)
874 {
875         int rc;
876         int sockfd;
877
878         if (strlen(intf) >= IFNAMSIZ || ifr == NULL)
879                 return LUSTRE_CFG_RC_BAD_PARAM;
880
881         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
882         if (sockfd < 0)
883                 return LUSTRE_CFG_RC_BAD_PARAM;
884
885         strcpy(ifr->ifr_name, intf);
886         rc = ioctl(sockfd, request, ifr);
887         if (rc != 0)
888                 return LUSTRE_CFG_RC_BAD_PARAM;
889
890         return 0;
891 }
892
893 /*
894  * for each interface in the array of interfaces find the IP address of
895  * that interface, create its nid and add it to an array of NIDs.
896  * Stop if any of the interfaces is down
897  */
898 static int lustre_lnet_intf2nids(struct lnet_dlc_network_descr *nw,
899                                  lnet_nid_t **nids, __u32 *nnids)
900 {
901         int i = 0, count = 0, rc;
902         struct ifreq ifr;
903         __u32 ip;
904         struct lnet_dlc_intf_descr *intf;
905
906         if (nw == NULL || nids == NULL)
907                 return LUSTRE_CFG_RC_BAD_PARAM;
908
909         list_for_each_entry(intf, &nw->nw_intflist, intf_on_network)
910                 count++;
911
912         *nids = calloc(count, sizeof(lnet_nid_t));
913         if (*nids == NULL)
914                 return LUSTRE_CFG_RC_OUT_OF_MEM;
915
916         list_for_each_entry(intf, &nw->nw_intflist, intf_on_network) {
917                 memset(&ifr, 0, sizeof(ifr));
918                 rc = socket_intf_query(SIOCGIFFLAGS, intf->intf_name, &ifr);
919                 if (rc != 0)
920                         goto failed;
921
922                 if ((ifr.ifr_flags & IFF_UP) == 0) {
923                         rc = LUSTRE_CFG_RC_BAD_PARAM;
924                         goto failed;
925                 }
926
927                 memset(&ifr, 0, sizeof(ifr));
928                 rc = socket_intf_query(SIOCGIFADDR, intf->intf_name, &ifr);
929                 if (rc != 0)
930                         goto failed;
931
932                 ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
933                 ip = bswap_32(ip);
934                 (*nids)[i] = LNET_MKNID(nw->nw_id, ip);
935                 i++;
936         }
937
938         *nnids = count;
939
940         return 0;
941
942 failed:
943         free(*nids);
944         *nids = NULL;
945         return rc;
946 }
947
948 /*
949  * called repeatedly until a match or no more ip range
950  * What do you have?
951  *      ip_range expression
952  *      interface list with all the interface names.
953  *      all the interfaces in the system.
954  *
955  *      try to match the ip_range expr to one of the interfaces' IPs in
956  *      the system. If we hit a patch for an interface. Check if that
957  *      interface name is in the list.
958  *
959  *      If there are more than one interface in the list, then make sure
960  *      that the IPs for all of these interfaces match the ip ranges
961  *      given.
962  *
963  *      for each interface in intf_list
964  *              look up the intf name in ifa
965  *              if not there then no match
966  *              check ip obtained from ifa against a match to any of the
967  *              ip_ranges given.
968  *              If no match, then fail
969  *
970  *      The result is that all the interfaces have to match.
971  */
972 int lustre_lnet_match_ip_to_intf(struct ifaddrs *ifa,
973                                  struct list_head *intf_list,
974                                  struct list_head *ip_ranges)
975 {
976         int rc;
977         __u32 ip;
978         struct lnet_dlc_intf_descr *intf_descr, *tmp;
979         struct ifaddrs *ifaddr = ifa;
980         struct lustre_lnet_ip_range_descr *ip_range;
981         int family;
982
983         /*
984          * if there are no explicit interfaces, and no ip ranges, then
985          * configure the first tcp interface we encounter.
986          */
987         if (list_empty(intf_list) && list_empty(ip_ranges)) {
988                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
989                         if (ifaddr->ifa_addr == NULL)
990                                 continue;
991
992                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
993                                 continue;
994
995                         family = ifaddr->ifa_addr->sa_family;
996                         if (family == AF_INET &&
997                             strcmp(ifaddr->ifa_name, "lo") != 0) {
998                                 rc = lustre_lnet_add_intf_descr
999                                         (intf_list, ifaddr->ifa_name,
1000                                         strlen(ifaddr->ifa_name));
1001
1002                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
1003                                         return rc;
1004
1005                                 return LUSTRE_CFG_RC_MATCH;
1006                         }
1007                 }
1008                 return LUSTRE_CFG_RC_NO_MATCH;
1009         }
1010
1011         /*
1012          * First interface which matches an IP pattern will be used
1013          */
1014         if (list_empty(intf_list)) {
1015                 /*
1016                  * no interfaces provided in the rule, but an ip range is
1017                  * provided, so try and match an interface to the ip
1018                  * range.
1019                  */
1020                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1021                         if (ifaddr->ifa_addr == NULL)
1022                                 continue;
1023
1024                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
1025                                 continue;
1026
1027                         family = ifaddr->ifa_addr->sa_family;
1028                         if (family == AF_INET) {
1029                                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->
1030                                         sin_addr.s_addr;
1031
1032                                 list_for_each_entry(ip_range, ip_ranges,
1033                                                     ipr_entry) {
1034                                         rc = cfs_ip_addr_match(bswap_32(ip),
1035                                                         &ip_range->ipr_expr);
1036                                         if (!rc)
1037                                                 continue;
1038
1039                                         rc = lustre_lnet_add_intf_descr
1040                                           (intf_list, ifaddr->ifa_name,
1041                                            strlen(ifaddr->ifa_name));
1042
1043                                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1044                                                 return rc;
1045                                 }
1046                         }
1047                 }
1048
1049                 if (!list_empty(intf_list))
1050                         return LUSTRE_CFG_RC_MATCH;
1051
1052                 return LUSTRE_CFG_RC_NO_MATCH;
1053         }
1054
1055         /*
1056          * If an interface is explicitly specified the ip-range might or
1057          * might not be specified. if specified the interface needs to match the
1058          * ip-range. If no ip-range then the interfaces are
1059          * automatically matched if they are all up.
1060          * If > 1 interfaces all the interfaces must match for the NI to
1061          * be configured.
1062          */
1063         list_for_each_entry_safe(intf_descr, tmp, intf_list, intf_on_network) {
1064                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1065                         if (ifaddr->ifa_addr == NULL)
1066                                 continue;
1067
1068                         family = ifaddr->ifa_addr->sa_family;
1069                         if (family == AF_INET &&
1070                             strcmp(intf_descr->intf_name,
1071                                    ifaddr->ifa_name) == 0)
1072                                 break;
1073                 }
1074
1075                 if (ifaddr == NULL) {
1076                         list_del(&intf_descr->intf_on_network);
1077                         free_intf_descr(intf_descr);
1078                         continue;
1079                 }
1080
1081                 if ((ifaddr->ifa_flags & IFF_UP) == 0) {
1082                         list_del(&intf_descr->intf_on_network);
1083                         free_intf_descr(intf_descr);
1084                         continue;
1085                 }
1086
1087                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
1088
1089                 rc = 1;
1090                 list_for_each_entry(ip_range, ip_ranges, ipr_entry) {
1091                         rc = cfs_ip_addr_match(bswap_32(ip), &ip_range->ipr_expr);
1092                         if (rc)
1093                                 break;
1094                 }
1095
1096                 if (!rc) {
1097                         /* no match for this interface */
1098                         list_del(&intf_descr->intf_on_network);
1099                         free_intf_descr(intf_descr);
1100                 }
1101         }
1102
1103         return LUSTRE_CFG_RC_MATCH;
1104 }
1105
1106 int lustre_lnet_resolve_ip2nets_rule(struct lustre_lnet_ip2nets *ip2nets,
1107                                      lnet_nid_t **nids, __u32 *nnids)
1108 {
1109         struct ifaddrs *ifa;
1110         int rc = LUSTRE_CFG_RC_NO_ERR;
1111
1112         rc = getifaddrs(&ifa);
1113         if (rc < 0)
1114                 return -errno;
1115
1116         rc = lustre_lnet_match_ip_to_intf(ifa,
1117                                           &ip2nets->ip2nets_net.nw_intflist,
1118                                           &ip2nets->ip2nets_ip_ranges);
1119         if (rc != LUSTRE_CFG_RC_MATCH) {
1120                 freeifaddrs(ifa);
1121                 return rc;
1122         }
1123
1124         rc = lustre_lnet_intf2nids(&ip2nets->ip2nets_net, nids, nnids);
1125         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1126                 *nids = NULL;
1127                 *nnids = 0;
1128         }
1129
1130         freeifaddrs(ifa);
1131
1132         return rc;
1133 }
1134
1135 static int
1136 lustre_lnet_ioctl_config_ni(struct list_head *intf_list,
1137                             struct lnet_ioctl_config_lnd_tunables *tunables,
1138                             struct cfs_expr_list *global_cpts,
1139                             lnet_nid_t *nids, char *err_str)
1140 {
1141         char *data;
1142         struct lnet_ioctl_config_ni *conf;
1143         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1144         int rc = LUSTRE_CFG_RC_NO_ERR, i = 0;
1145         size_t len;
1146         int count;
1147         struct lnet_dlc_intf_descr *intf_descr;
1148         __u32 *cpt_array;
1149         struct cfs_expr_list *cpt_expr;
1150
1151         list_for_each_entry(intf_descr, intf_list,
1152                             intf_on_network) {
1153                 if (i == 0 && tunables != NULL)
1154                         len = sizeof(struct lnet_ioctl_config_ni) +
1155                               sizeof(struct lnet_ioctl_config_lnd_tunables);
1156                 else
1157                         len = sizeof(struct lnet_ioctl_config_ni);
1158
1159                 data = calloc(1, len);
1160                 conf = (struct lnet_ioctl_config_ni*) data;
1161                 if (i == 0 && tunables != NULL)
1162                         tun = (struct lnet_ioctl_config_lnd_tunables*)
1163                                 conf->lic_bulk;
1164
1165                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
1166                 conf->lic_cfg_hdr.ioc_len = len;
1167                 conf->lic_nid = nids[i];
1168                 strncpy(conf->lic_ni_intf[0], intf_descr->intf_name,
1169                         LNET_MAX_STR_LEN);
1170
1171                 if (intf_descr->cpt_expr != NULL)
1172                         cpt_expr = intf_descr->cpt_expr;
1173                 else if (global_cpts != NULL)
1174                         cpt_expr = global_cpts;
1175                 else
1176                         cpt_expr = NULL;
1177
1178                 if (cpt_expr != NULL) {
1179                         count = cfs_expr_list_values(cpt_expr,
1180                                                      LNET_MAX_SHOW_NUM_CPT,
1181                                                      &cpt_array);
1182                         if (count > 0) {
1183                                 memcpy(conf->lic_cpts, cpt_array,
1184                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
1185                                 free(cpt_array);
1186                         } else {
1187                                 count = 0;
1188                         }
1189                 } else {
1190                         count = 0;
1191                 }
1192
1193                 conf->lic_ncpts = count;
1194
1195                 if (i == 0 && tunables != NULL)
1196                         /* TODO put in the LND tunables */
1197                         memcpy(tun, tunables, sizeof(*tunables));
1198
1199                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
1200                 if (rc < 0) {
1201                         rc = -errno;
1202                         snprintf(err_str,
1203                                  LNET_MAX_STR_LEN,
1204                                  "\"cannot add network: %s\"", strerror(errno));
1205                         return rc;
1206                 }
1207                 i++;
1208         }
1209
1210         return LUSTRE_CFG_RC_NO_ERR;
1211 }
1212
1213 int
1214 lustre_lnet_config_ip2nets(struct lustre_lnet_ip2nets *ip2nets,
1215                            struct lnet_ioctl_config_lnd_tunables *tunables,
1216                            struct cfs_expr_list *global_cpts,
1217                            int seq_no, struct cYAML **err_rc)
1218 {
1219         lnet_nid_t *nids = NULL;
1220         __u32 nnids = 0;
1221         int rc;
1222         char err_str[LNET_MAX_STR_LEN];
1223
1224         snprintf(err_str, sizeof(err_str), "\"success\"");
1225
1226         if (!ip2nets) {
1227                 snprintf(err_str,
1228                          sizeof(err_str),
1229                          "\"incomplete ip2nets information\"");
1230                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1231                 goto out;
1232         }
1233
1234         rc = lustre_lnet_resolve_ip2nets_rule(ip2nets, &nids, &nnids);
1235         if (rc != LUSTRE_CFG_RC_NO_ERR && rc != LUSTRE_CFG_RC_MATCH) {
1236                 snprintf(err_str,
1237                          sizeof(err_str),
1238                          "\"cannot resolve ip2nets rule\"");
1239                 goto out;
1240         }
1241
1242         if (list_empty(&ip2nets->ip2nets_net.nw_intflist)) {
1243                 snprintf(err_str, sizeof(err_str),
1244                          "\"no interfaces match ip2nets rules\"");
1245                 goto out;
1246         }
1247
1248         rc = lustre_lnet_ioctl_config_ni(&ip2nets->ip2nets_net.nw_intflist,
1249                                          tunables, global_cpts, nids,
1250                                          err_str);
1251         if (rc != LUSTRE_CFG_RC_NO_ERR)
1252                 free(nids);
1253
1254 out:
1255         cYAML_build_error(rc, seq_no, ADD_CMD, "ip2nets", err_str, err_rc);
1256         return rc;
1257 }
1258
1259 int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
1260                           struct cfs_expr_list *global_cpts,
1261                           char *ip2net,
1262                           struct lnet_ioctl_config_lnd_tunables *tunables,
1263                           int seq_no, struct cYAML **err_rc)
1264 {
1265         char *data = NULL;
1266         struct lnet_ioctl_config_ni *conf;
1267         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1268         char buf[LNET_MAX_STR_LEN];
1269         int rc = LUSTRE_CFG_RC_NO_ERR;
1270         char err_str[LNET_MAX_STR_LEN];
1271         lnet_nid_t *nids = NULL;
1272         __u32 nnids = 0;
1273         size_t len;
1274         int count;
1275         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1276         __u32 *cpt_array;
1277
1278         snprintf(err_str, sizeof(err_str), "\"success\"");
1279
1280         if (ip2net == NULL && nw_descr == NULL) {
1281                 snprintf(err_str,
1282                          sizeof(err_str),
1283                          "\"mandatory parameters not specified.\"");
1284                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
1285                 goto out;
1286         }
1287
1288         if (ip2net != NULL && strlen(ip2net) >= sizeof(buf)) {
1289                 snprintf(err_str,
1290                          sizeof(err_str),
1291                          "\"ip2net string too long %d\"",
1292                                 (int)strlen(ip2net));
1293                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1294                 goto out;
1295         }
1296
1297         if (ip2net != NULL) {
1298                 if (tunables != NULL)
1299                         len = sizeof(struct lnet_ioctl_config_ni) +
1300                               sizeof(struct lnet_ioctl_config_lnd_tunables);
1301                 else
1302                         len = sizeof(struct lnet_ioctl_config_ni);
1303                 data = calloc(1, len);
1304                 conf = (struct lnet_ioctl_config_ni*) data;
1305                 if (tunables != NULL)
1306                         tun = (struct lnet_ioctl_config_lnd_tunables*)
1307                                 (data + sizeof(*conf));
1308
1309                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
1310                 conf->lic_cfg_hdr.ioc_len = len;
1311                 strncpy(conf->lic_legacy_ip2nets, ip2net,
1312                         LNET_MAX_STR_LEN);
1313
1314                 if (global_cpts != NULL) {
1315                         count = cfs_expr_list_values(global_cpts,
1316                                                      LNET_MAX_SHOW_NUM_CPT,
1317                                                      &cpt_array);
1318                         if (count > 0) {
1319                                 memcpy(conf->lic_cpts, cpt_array,
1320                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
1321                                 free(cpt_array);
1322                         } else {
1323                                 count = 0;
1324                         }
1325                 } else {
1326                         count = 0;
1327                 }
1328
1329                 conf->lic_ncpts = count;
1330
1331                 if (tunables != NULL)
1332                         memcpy(tun, tunables, sizeof(*tunables));
1333
1334                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
1335                 if (rc < 0) {
1336                         rc = -errno;
1337                         snprintf(err_str,
1338                                 sizeof(err_str),
1339                                 "\"cannot add network: %s\"", strerror(errno));
1340                         goto out;
1341                 }
1342
1343                 goto out;
1344         }
1345
1346         if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
1347                 return LUSTRE_CFG_RC_NO_ERR;
1348
1349         if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
1350                 snprintf(err_str,
1351                         sizeof(err_str),
1352                         "\"cannot parse net '%s'\"",
1353                         libcfs_net2str(nw_descr->nw_id));
1354                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1355                 goto out;
1356         }
1357
1358         if (list_empty(&nw_descr->nw_intflist)) {
1359                 snprintf(err_str,
1360                         sizeof(err_str),
1361                         "\"no interface name provided\"");
1362                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1363                 goto out;
1364         }
1365
1366         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
1367         if (rc != 0) {
1368                 snprintf(err_str, sizeof(err_str),
1369                          "\"bad parameter\"");
1370                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1371                 goto out;
1372         }
1373
1374         rc = lustre_lnet_ioctl_config_ni(&nw_descr->nw_intflist,
1375                                          tunables, global_cpts, nids,
1376                                          err_str);
1377
1378 out:
1379         if (nw_descr != NULL) {
1380                 list_for_each_entry_safe(intf_descr, tmp,
1381                                          &nw_descr->nw_intflist,
1382                                          intf_on_network) {
1383                         list_del(&intf_descr->intf_on_network);
1384                         free_intf_descr(intf_descr);
1385                 }
1386         }
1387
1388         cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
1389
1390         if (nids)
1391                 free(nids);
1392
1393         if (data)
1394                 free(data);
1395
1396         return rc;
1397 }
1398
1399 int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw_descr,
1400                        int seq_no, struct cYAML **err_rc)
1401 {
1402         struct lnet_ioctl_config_ni data;
1403         int rc = LUSTRE_CFG_RC_NO_ERR, i;
1404         char err_str[LNET_MAX_STR_LEN];
1405         lnet_nid_t *nids = NULL;
1406         __u32 nnids = 0;
1407         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1408
1409         if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
1410                 return LUSTRE_CFG_RC_NO_ERR;
1411
1412         snprintf(err_str, sizeof(err_str), "\"success\"");
1413
1414         if (nw_descr == NULL) {
1415                 snprintf(err_str,
1416                          sizeof(err_str),
1417                          "\"missing mandatory parameter\"");
1418                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
1419                 goto out;
1420         }
1421
1422         if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
1423                 snprintf(err_str,
1424                          sizeof(err_str),
1425                          "\"cannot parse net '%s'\"",
1426                          libcfs_net2str(nw_descr->nw_id));
1427                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1428                 goto out;
1429         }
1430
1431         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
1432         if (rc != 0) {
1433                 snprintf(err_str, sizeof(err_str),
1434                          "\"bad parameter\"");
1435                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1436                 goto out;
1437         }
1438
1439         /*
1440          * no interfaces just the nw_id is specified
1441          */
1442         if (nnids == 0) {
1443                 nids = calloc(1, sizeof(*nids));
1444                 if (nids == NULL) {
1445                         snprintf(err_str, sizeof(err_str),
1446                                 "\"out of memory\"");
1447                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1448                         goto out;
1449                 }
1450                 nids[0] = LNET_MKNID(nw_descr->nw_id, 0);
1451                 nnids = 1;
1452         }
1453
1454         for (i = 0; i < nnids; i++) {
1455                 LIBCFS_IOC_INIT_V2(data, lic_cfg_hdr);
1456                 data.lic_nid = nids[i];
1457
1458                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_LOCAL_NI, &data);
1459                 if (rc < 0) {
1460                         rc = -errno;
1461                         snprintf(err_str,
1462                                 sizeof(err_str),
1463                                 "\"cannot del network: %s\"", strerror(errno));
1464                 }
1465         }
1466
1467         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
1468                                  intf_on_network) {
1469                 list_del(&intf_descr->intf_on_network);
1470                 free_intf_descr(intf_descr);
1471         }
1472
1473 out:
1474         cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
1475
1476         if (nids != NULL)
1477                 free(nids);
1478
1479         return rc;
1480 }
1481
1482 int lustre_lnet_show_net(char *nw, int detail, int seq_no,
1483                          struct cYAML **show_rc, struct cYAML **err_rc)
1484 {
1485         char *buf;
1486         struct lnet_ioctl_config_ni *ni_data;
1487         struct lnet_ioctl_config_lnd_tunables *lnd;
1488         struct lnet_ioctl_element_stats *stats;
1489         __u32 net = LNET_NIDNET(LNET_NID_ANY);
1490         __u32 prev_net = LNET_NIDNET(LNET_NID_ANY);
1491         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
1492         int l_errno = 0;
1493         struct cYAML *root = NULL, *tunables = NULL,
1494                 *net_node = NULL, *interfaces = NULL,
1495                 *item = NULL, *first_seq = NULL,
1496                 *tmp = NULL, *statistics = NULL;
1497         int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
1498         char str_buf[str_buf_len];
1499         char *pos;
1500         char err_str[LNET_MAX_STR_LEN];
1501         bool exist = false, new_net = true;
1502         int net_num = 0;
1503         size_t buf_size = sizeof(*ni_data) + sizeof(*lnd) + sizeof(*stats);
1504
1505         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
1506
1507         buf = calloc(1, buf_size);
1508         if (buf == NULL)
1509                 goto out;
1510
1511         ni_data = (struct lnet_ioctl_config_ni *)buf;
1512
1513         if (nw != NULL) {
1514                 net = libcfs_str2net(nw);
1515                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
1516                         snprintf(err_str,
1517                                  sizeof(err_str),
1518                                  "\"cannot parse net '%s'\"", nw);
1519                         rc = LUSTRE_CFG_RC_BAD_PARAM;
1520                         goto out;
1521                 }
1522         }
1523
1524         root = cYAML_create_object(NULL, NULL);
1525         if (root == NULL)
1526                 goto out;
1527
1528         net_node = cYAML_create_seq(root, "net");
1529         if (net_node == NULL)
1530                 goto out;
1531
1532         for (i = 0;; i++) {
1533                 pos = str_buf;
1534                 __u32 rc_net;
1535
1536                 memset(buf, 0, buf_size);
1537
1538                 LIBCFS_IOC_INIT_V2(*ni_data, lic_cfg_hdr);
1539                 /*
1540                  * set the ioc_len to the proper value since INIT assumes
1541                  * size of data
1542                  */
1543                 ni_data->lic_cfg_hdr.ioc_len = buf_size;
1544                 ni_data->lic_idx = i;
1545
1546                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LOCAL_NI, ni_data);
1547                 if (rc != 0) {
1548                         l_errno = errno;
1549                         break;
1550                 }
1551
1552                 rc_net = LNET_NIDNET(ni_data->lic_nid);
1553
1554                 /* filter on provided data */
1555                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
1556                     net != rc_net)
1557                         continue;
1558
1559                 /* default rc to -1 in case we hit the goto */
1560                 rc = -1;
1561                 exist = true;
1562
1563                 stats = (struct lnet_ioctl_element_stats *)ni_data->lic_bulk;
1564                 lnd = (struct lnet_ioctl_config_lnd_tunables *)
1565                         (ni_data->lic_bulk + sizeof(*stats));
1566
1567                 if (rc_net != prev_net) {
1568                         prev_net = rc_net;
1569                         new_net = true;
1570                         net_num++;
1571                 }
1572
1573                 if (new_net) {
1574                         if (!cYAML_create_string(net_node, "net type",
1575                                                  libcfs_net2str(rc_net)))
1576                                 goto out;
1577
1578                         tmp = cYAML_create_seq(net_node, "local NI(s)");
1579                         if (tmp == NULL)
1580                                 goto out;
1581                         new_net = false;
1582                 }
1583
1584                 /* create the tree to be printed. */
1585                 item = cYAML_create_seq_item(tmp);
1586                 if (item == NULL)
1587                         goto out;
1588
1589                 if (first_seq == NULL)
1590                         first_seq = item;
1591
1592                 if (cYAML_create_string(item, "nid",
1593                                         libcfs_nid2str(ni_data->lic_nid)) == NULL)
1594                         goto out;
1595
1596                 if (cYAML_create_string(item,
1597                                         "status",
1598                                         (ni_data->lic_status ==
1599                                           LNET_NI_STATUS_UP) ?
1600                                             "up" : "down") == NULL)
1601                         goto out;
1602
1603                 /* don't add interfaces unless there is at least one
1604                  * interface */
1605                 if (strlen(ni_data->lic_ni_intf[0]) > 0) {
1606                         interfaces = cYAML_create_object(item, "interfaces");
1607                         if (interfaces == NULL)
1608                                 goto out;
1609
1610                         for (j = 0; j < LNET_MAX_INTERFACES; j++) {
1611                                 if (strlen(ni_data->lic_ni_intf[j]) > 0) {
1612                                         snprintf(str_buf,
1613                                                  sizeof(str_buf), "%d", j);
1614                                         if (cYAML_create_string(interfaces,
1615                                                 str_buf,
1616                                                 ni_data->lic_ni_intf[j]) ==
1617                                                         NULL)
1618                                                 goto out;
1619                                 }
1620                         }
1621                 }
1622
1623                 if (detail) {
1624                         char *limit;
1625
1626                         statistics = cYAML_create_object(item, "statistics");
1627                         if (statistics == NULL)
1628                                 goto out;
1629
1630                         if (cYAML_create_number(statistics, "send_count",
1631                                                 stats->send_count)
1632                                                         == NULL)
1633                                 goto out;
1634
1635                         if (cYAML_create_number(statistics, "recv_count",
1636                                                 stats->recv_count)
1637                                                         == NULL)
1638                                 goto out;
1639
1640                         if (cYAML_create_number(statistics, "drop_count",
1641                                                 stats->drop_count)
1642                                                         == NULL)
1643                                 goto out;
1644
1645                         tunables = cYAML_create_object(item, "tunables");
1646                         if (!tunables)
1647                                 goto out;
1648
1649                         rc = lustre_net_show_tunables(tunables, &lnd->lt_cmn);
1650                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1651                                 goto out;
1652
1653                         tunables = cYAML_create_object(item, "lnd tunables");
1654                         if (tunables == NULL)
1655                                 goto out;
1656
1657                         rc = lustre_ni_show_tunables(tunables, LNET_NETTYP(rc_net),
1658                                                      &lnd->lt_tun);
1659                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1660                                 goto out;
1661
1662                         if (cYAML_create_number(item, "tcp bonding",
1663                                                 ni_data->lic_tcp_bonding)
1664                                                         == NULL)
1665                                 goto out;
1666
1667                         if (cYAML_create_number(item, "dev cpt",
1668                                                 ni_data->lic_dev_cpt) == NULL)
1669                                 goto out;
1670
1671                         /* out put the CPTs in the format: "[x,x,x,...]" */
1672                         limit = str_buf + str_buf_len - 3;
1673                         pos += snprintf(pos, limit - pos, "\"[");
1674                         for (j = 0 ; ni_data->lic_ncpts >= 1 &&
1675                                 j < ni_data->lic_ncpts &&
1676                                 pos < limit; j++) {
1677                                 pos += snprintf(pos, limit - pos,
1678                                                 "%d", ni_data->lic_cpts[j]);
1679                                 if ((j + 1) < ni_data->lic_ncpts)
1680                                         pos += snprintf(pos, limit - pos, ",");
1681                         }
1682                         pos += snprintf(pos, 3, "]\"");
1683
1684                         if (ni_data->lic_ncpts >= 1 &&
1685                             cYAML_create_string(item, "CPT",
1686                                                 str_buf) == NULL)
1687                                 goto out;
1688                 }
1689         }
1690
1691         /* Print out the net information only if show_rc is not provided */
1692         if (show_rc == NULL)
1693                 cYAML_print_tree(root);
1694
1695         if (l_errno != ENOENT) {
1696                 snprintf(err_str,
1697                          sizeof(err_str),
1698                          "\"cannot get networks: %s\"",
1699                          strerror(l_errno));
1700                 rc = -l_errno;
1701                 goto out;
1702         } else
1703                 rc = LUSTRE_CFG_RC_NO_ERR;
1704
1705         snprintf(err_str, sizeof(err_str), "\"success\"");
1706 out:
1707         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1708                 cYAML_free_tree(root);
1709         } else if (show_rc != NULL && *show_rc != NULL) {
1710                 struct cYAML *show_node;
1711                 /* find the net node, if one doesn't exist
1712                  * then insert one.  Otherwise add to the one there
1713                  */
1714                 show_node = cYAML_get_object_item(*show_rc, "net");
1715                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
1716                         cYAML_insert_child(show_node, first_seq);
1717                         free(net_node);
1718                         free(root);
1719                 } else if (show_node == NULL) {
1720                         cYAML_insert_sibling((*show_rc)->cy_child,
1721                                                 net_node);
1722                         free(root);
1723                 } else {
1724                         cYAML_free_tree(root);
1725                 }
1726         } else {
1727                 *show_rc = root;
1728         }
1729
1730         cYAML_build_error(rc, seq_no, SHOW_CMD, "net", err_str, err_rc);
1731
1732         return rc;
1733 }
1734
1735 int lustre_lnet_enable_routing(int enable, int seq_no, struct cYAML **err_rc)
1736 {
1737         struct lnet_ioctl_config_data data;
1738         int rc = LUSTRE_CFG_RC_NO_ERR;
1739         char err_str[LNET_MAX_STR_LEN];
1740
1741         snprintf(err_str, sizeof(err_str), "\"success\"");
1742
1743         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
1744         data.cfg_config_u.cfg_buffers.buf_enable = (enable) ? 1 : 0;
1745
1746         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CONFIG_RTR, &data);
1747         if (rc != 0) {
1748                 rc = -errno;
1749                 snprintf(err_str,
1750                          sizeof(err_str),
1751                          "\"cannot %s routing %s\"",
1752                          (enable) ? "enable" : "disable", strerror(errno));
1753                 goto out;
1754         }
1755
1756 out:
1757         cYAML_build_error(rc, seq_no,
1758                          (enable) ? ADD_CMD : DEL_CMD,
1759                          "routing", err_str, err_rc);
1760
1761         return rc;
1762 }
1763
1764 int lustre_lnet_config_numa_range(int range, int seq_no, struct cYAML **err_rc)
1765 {
1766         struct lnet_ioctl_numa_range data;
1767         int rc = LUSTRE_CFG_RC_NO_ERR;
1768         char err_str[LNET_MAX_STR_LEN];
1769
1770         snprintf(err_str, sizeof(err_str), "\"success\"");
1771
1772         if (range < 0) {
1773                 snprintf(err_str,
1774                          sizeof(err_str),
1775                          "\"range must be >= 0\"");
1776                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1777                 goto out;
1778         }
1779
1780         LIBCFS_IOC_INIT_V2(data, nr_hdr);
1781         data.nr_range = range;
1782
1783         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_SET_NUMA_RANGE, &data);
1784         if (rc != 0) {
1785                 rc = -errno;
1786                 snprintf(err_str,
1787                          sizeof(err_str),
1788                          "\"cannot configure buffers: %s\"", strerror(errno));
1789                 goto out;
1790         }
1791
1792 out:
1793         cYAML_build_error(rc, seq_no, ADD_CMD, "numa_range", err_str, err_rc);
1794
1795         return rc;
1796 }
1797
1798 int lustre_lnet_config_buffers(int tiny, int small, int large, int seq_no,
1799                                struct cYAML **err_rc)
1800 {
1801         struct lnet_ioctl_config_data data;
1802         int rc = LUSTRE_CFG_RC_NO_ERR;
1803         char err_str[LNET_MAX_STR_LEN];
1804
1805         snprintf(err_str, sizeof(err_str), "\"success\"");
1806
1807         /* -1 indicates to ignore changes to this field */
1808         if (tiny < -1 || small < -1 || large < -1) {
1809                 snprintf(err_str,
1810                          sizeof(err_str),
1811                          "\"tiny, small and large must be >= 0\"");
1812                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1813                 goto out;
1814         }
1815
1816         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
1817         data.cfg_config_u.cfg_buffers.buf_tiny = tiny;
1818         data.cfg_config_u.cfg_buffers.buf_small = small;
1819         data.cfg_config_u.cfg_buffers.buf_large = large;
1820
1821         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_BUF, &data);
1822         if (rc != 0) {
1823                 rc = -errno;
1824                 snprintf(err_str,
1825                          sizeof(err_str),
1826                          "\"cannot configure buffers: %s\"", strerror(errno));
1827                 goto out;
1828         }
1829
1830 out:
1831         cYAML_build_error(rc, seq_no, ADD_CMD, "buf", err_str, err_rc);
1832
1833         return rc;
1834 }
1835
1836 int lustre_lnet_show_routing(int seq_no, struct cYAML **show_rc,
1837                              struct cYAML **err_rc)
1838 {
1839         struct lnet_ioctl_config_data *data;
1840         struct lnet_ioctl_pool_cfg *pool_cfg = NULL;
1841         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1842         int l_errno = 0;
1843         char *buf;
1844         char *pools[LNET_NRBPOOLS] = {"tiny", "small", "large"};
1845         int buf_count[LNET_NRBPOOLS] = {0};
1846         struct cYAML *root = NULL, *pools_node = NULL,
1847                      *type_node = NULL, *item = NULL, *cpt = NULL,
1848                      *first_seq = NULL, *buffers = NULL;
1849         int i, j;
1850         char err_str[LNET_MAX_STR_LEN];
1851         char node_name[LNET_MAX_STR_LEN];
1852         bool exist = false;
1853
1854         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
1855
1856         buf = calloc(1, sizeof(*data) + sizeof(*pool_cfg));
1857         if (buf == NULL)
1858                 goto out;
1859
1860         data = (struct lnet_ioctl_config_data *)buf;
1861
1862         root = cYAML_create_object(NULL, NULL);
1863         if (root == NULL)
1864                 goto out;
1865
1866         pools_node = cYAML_create_seq(root, "routing");
1867         if (pools_node == NULL)
1868                 goto out;
1869
1870         for (i = 0;; i++) {
1871                 LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
1872                 data->cfg_hdr.ioc_len = sizeof(struct lnet_ioctl_config_data) +
1873                                         sizeof(struct lnet_ioctl_pool_cfg);
1874                 data->cfg_count = i;
1875
1876                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_BUF, data);
1877                 if (rc != 0) {
1878                         l_errno = errno;
1879                         break;
1880                 }
1881
1882                 exist = true;
1883
1884                 pool_cfg = (struct lnet_ioctl_pool_cfg *)data->cfg_bulk;
1885
1886                 snprintf(node_name, sizeof(node_name), "cpt[%d]", i);
1887                 item = cYAML_create_seq_item(pools_node);
1888                 if (item == NULL)
1889                         goto out;
1890
1891                 if (first_seq == NULL)
1892                         first_seq = item;
1893
1894                 cpt = cYAML_create_object(item, node_name);
1895                 if (cpt == NULL)
1896                         goto out;
1897
1898                 /* create the tree  and print */
1899                 for (j = 0; j < LNET_NRBPOOLS; j++) {
1900                         type_node = cYAML_create_object(cpt, pools[j]);
1901                         if (type_node == NULL)
1902                                 goto out;
1903                         if (cYAML_create_number(type_node, "npages",
1904                                                 pool_cfg->pl_pools[j].pl_npages)
1905                             == NULL)
1906                                 goto out;
1907                         if (cYAML_create_number(type_node, "nbuffers",
1908                                                 pool_cfg->pl_pools[j].
1909                                                   pl_nbuffers) == NULL)
1910                                 goto out;
1911                         if (cYAML_create_number(type_node, "credits",
1912                                                 pool_cfg->pl_pools[j].
1913                                                    pl_credits) == NULL)
1914                                 goto out;
1915                         if (cYAML_create_number(type_node, "mincredits",
1916                                                 pool_cfg->pl_pools[j].
1917                                                    pl_mincredits) == NULL)
1918                                 goto out;
1919                         /* keep track of the total count for each of the
1920                          * tiny, small and large buffers */
1921                         buf_count[j] += pool_cfg->pl_pools[j].pl_nbuffers;
1922                 }
1923         }
1924
1925         if (pool_cfg != NULL) {
1926                 item = cYAML_create_seq_item(pools_node);
1927                 if (item == NULL)
1928                         goto out;
1929
1930                 if (cYAML_create_number(item, "enable", pool_cfg->pl_routing) ==
1931                     NULL)
1932                         goto out;
1933         }
1934
1935         /* create a buffers entry in the show. This is necessary so that
1936          * if the YAML output is used to configure a node, the buffer
1937          * configuration takes hold */
1938         buffers = cYAML_create_object(root, "buffers");
1939         if (buffers == NULL)
1940                 goto out;
1941
1942         for (i = 0; i < LNET_NRBPOOLS; i++) {
1943                 if (cYAML_create_number(buffers, pools[i], buf_count[i]) == NULL)
1944                         goto out;
1945         }
1946
1947         if (show_rc == NULL)
1948                 cYAML_print_tree(root);
1949
1950         if (l_errno != ENOENT) {
1951                 snprintf(err_str,
1952                          sizeof(err_str),
1953                          "\"cannot get routing information: %s\"",
1954                          strerror(l_errno));
1955                 rc = -l_errno;
1956                 goto out;
1957         } else
1958                 rc = LUSTRE_CFG_RC_NO_ERR;
1959
1960         snprintf(err_str, sizeof(err_str), "\"success\"");
1961         rc = LUSTRE_CFG_RC_NO_ERR;
1962
1963 out:
1964         free(buf);
1965         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1966                 cYAML_free_tree(root);
1967         } else if (show_rc != NULL && *show_rc != NULL) {
1968                 struct cYAML *routing_node;
1969                 /* there should exist only one routing block and one
1970                  * buffers block. If there already exists a previous one
1971                  * then don't add another */
1972                 routing_node = cYAML_get_object_item(*show_rc, "routing");
1973                 if (routing_node == NULL) {
1974                         cYAML_insert_sibling((*show_rc)->cy_child,
1975                                                 root->cy_child);
1976                         free(root);
1977                 } else {
1978                         cYAML_free_tree(root);
1979                 }
1980         } else {
1981                 *show_rc = root;
1982         }
1983
1984         cYAML_build_error(rc, seq_no, SHOW_CMD, "routing", err_str, err_rc);
1985
1986         return rc;
1987 }
1988
1989 int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
1990                           struct cYAML **show_rc, struct cYAML **err_rc)
1991 {
1992         /*
1993          * TODO: This function is changing in a future patch to accommodate
1994          * PEER_LIST and proper filtering on any nid of the peer
1995          */
1996         struct lnet_ioctl_peer_cfg *peer_info;
1997         struct lnet_peer_ni_credit_info *lpni_cri;
1998         struct lnet_ioctl_element_stats *lpni_stats;
1999         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, ncpt = 0, i = 0, j = 0;
2000         int l_errno = 0;
2001         struct cYAML *root = NULL, *peer = NULL, *peer_ni = NULL,
2002                      *first_seq = NULL, *peer_root = NULL, *tmp = NULL;
2003         char err_str[LNET_MAX_STR_LEN];
2004         lnet_nid_t prev_primary_nid = LNET_NID_ANY, primary_nid = LNET_NID_ANY;
2005         int data_size = sizeof(*peer_info) + sizeof(*lpni_cri) +
2006                         sizeof(*lpni_stats);
2007         char *data = calloc(data_size, 1);
2008         bool new_peer = true;
2009
2010         snprintf(err_str, sizeof(err_str),
2011                  "\"out of memory\"");
2012
2013         if (data == NULL)
2014                 goto out;
2015
2016         peer_info = (struct lnet_ioctl_peer_cfg *)data;
2017
2018         /* create struct cYAML root object */
2019         root = cYAML_create_object(NULL, NULL);
2020         if (root == NULL)
2021                 goto out;
2022
2023         peer_root = cYAML_create_seq(root, "peer");
2024         if (peer_root == NULL)
2025                 goto out;
2026
2027         if (knid != NULL)
2028                 primary_nid = libcfs_str2nid(knid);
2029
2030         do {
2031                 for (i = 0;; i++) {
2032                         memset(data, 0, data_size);
2033                         LIBCFS_IOC_INIT_V2(*peer_info, prcfg_hdr);
2034                         peer_info->prcfg_hdr.ioc_len = data_size;
2035                         peer_info->prcfg_idx = i;
2036
2037                         rc = l_ioctl(LNET_DEV_ID,
2038                                      IOC_LIBCFS_GET_PEER_NI, peer_info);
2039                         if (rc != 0) {
2040                                 l_errno = errno;
2041                                 break;
2042                         }
2043
2044                         if (primary_nid != LNET_NID_ANY &&
2045                             primary_nid != peer_info->prcfg_prim_nid)
2046                                         continue;
2047
2048                         lpni_cri = (struct lnet_peer_ni_credit_info*)peer_info->prcfg_bulk;
2049                         lpni_stats = (struct lnet_ioctl_element_stats *)
2050                                      (peer_info->prcfg_bulk +
2051                                      sizeof(*lpni_cri));
2052
2053                         peer = cYAML_create_seq_item(peer_root);
2054                         if (peer == NULL)
2055                                 goto out;
2056
2057                         if (peer_info->prcfg_prim_nid != prev_primary_nid) {
2058                                 prev_primary_nid = peer_info->prcfg_prim_nid;
2059                                 new_peer = true;
2060                         }
2061
2062                         if (new_peer) {
2063                                 lnet_nid_t pnid = peer_info->prcfg_prim_nid;
2064                                 if (cYAML_create_string(peer, "primary nid",
2065                                                         libcfs_nid2str(pnid))
2066                                     == NULL)
2067                                         goto out;
2068                                 if (cYAML_create_string(peer, "Multi-Rail",
2069                                                         peer_info->prcfg_mr ?
2070                                                         "True" : "False")
2071                                     == NULL)
2072                                         goto out;
2073                                 tmp = cYAML_create_seq(peer, "peer ni");
2074                                 if (tmp == NULL)
2075                                         goto out;
2076                                 new_peer = false;
2077                         }
2078
2079                         if (first_seq == NULL)
2080                                 first_seq = peer;
2081
2082                         peer_ni = cYAML_create_seq_item(tmp);
2083                         if (peer_ni == NULL)
2084                                 goto out;
2085
2086                         if (cYAML_create_string(peer_ni, "nid",
2087                                                 libcfs_nid2str
2088                                                  (peer_info->prcfg_cfg_nid))
2089                             == NULL)
2090                                 goto out;
2091
2092                         if (cYAML_create_string(peer_ni, "state",
2093                                                 lpni_cri->cr_aliveness)
2094                             == NULL)
2095                                 goto out;
2096
2097                         if (!detail)
2098                                 continue;
2099
2100                         if (cYAML_create_number(peer_ni, "max_ni_tx_credits",
2101                                                 lpni_cri->cr_ni_peer_tx_credits)
2102                             == NULL)
2103                                 goto out;
2104
2105                         if (cYAML_create_number(peer_ni, "available_tx_credits",
2106                                                 lpni_cri->cr_peer_tx_credits)
2107                             == NULL)
2108                                 goto out;
2109
2110                         if (cYAML_create_number(peer_ni, "min_tx_credits",
2111                                                 lpni_cri->cr_peer_min_tx_credits)
2112                             == NULL)
2113                                 goto out;
2114
2115                         if (cYAML_create_number(peer_ni, "tx_q_num_of_buf",
2116                                                 lpni_cri->cr_peer_tx_qnob)
2117                             == NULL)
2118                                 goto out;
2119
2120                         if (cYAML_create_number(peer_ni, "available_rtr_credits",
2121                                                 lpni_cri->cr_peer_rtr_credits)
2122                             == NULL)
2123                                 goto out;
2124
2125                         if (cYAML_create_number(peer_ni, "min_rtr_credits",
2126                                                 lpni_cri->cr_peer_min_rtr_credits)
2127                             == NULL)
2128                                 goto out;
2129
2130                         if (cYAML_create_number(peer_ni, "send_count",
2131                                                 lpni_stats->send_count)
2132                             == NULL)
2133                                 goto out;
2134
2135                         if (cYAML_create_number(peer_ni, "recv_count",
2136                                                 lpni_stats->recv_count)
2137                             == NULL)
2138                                 goto out;
2139
2140                         if (cYAML_create_number(peer_ni, "drop_count",
2141                                                 lpni_stats->drop_count)
2142                             == NULL)
2143                                 goto out;
2144
2145                         if (cYAML_create_number(peer_ni, "refcount",
2146                                                 lpni_cri->cr_refcount) == NULL)
2147                                 goto out;
2148                 }
2149
2150                 if (l_errno != ENOENT) {
2151                         snprintf(err_str,
2152                                 sizeof(err_str),
2153                                 "\"cannot get peer information: %s\"",
2154                                 strerror(l_errno));
2155                         rc = -l_errno;
2156                         goto out;
2157                 }
2158
2159                 j++;
2160         } while (j < ncpt);
2161
2162         /* print output iff show_rc is not provided */
2163         if (show_rc == NULL)
2164                 cYAML_print_tree(root);
2165
2166         snprintf(err_str, sizeof(err_str), "\"success\"");
2167         rc = LUSTRE_CFG_RC_NO_ERR;
2168
2169 out:
2170         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2171                 cYAML_free_tree(root);
2172         } else if (show_rc != NULL && *show_rc != NULL) {
2173                 struct cYAML *show_node;
2174                 /* find the peer node, if one doesn't exist then
2175                  * insert one.  Otherwise add to the one there
2176                  */
2177                 show_node = cYAML_get_object_item(*show_rc,
2178                                                   "peer");
2179                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
2180                         cYAML_insert_child(show_node, first_seq);
2181                         free(peer_root);
2182                         free(root);
2183                 } else if (show_node == NULL) {
2184                         cYAML_insert_sibling((*show_rc)->cy_child,
2185                                              peer_root);
2186                         free(root);
2187                 } else {
2188                         cYAML_free_tree(root);
2189                 }
2190         } else {
2191                 *show_rc = root;
2192         }
2193
2194         cYAML_build_error(rc, seq_no, SHOW_CMD, "peer", err_str,
2195                           err_rc);
2196
2197         return rc;
2198 }
2199
2200 int lustre_lnet_show_numa_range(int seq_no, struct cYAML **show_rc,
2201                                 struct cYAML **err_rc)
2202 {
2203         struct lnet_ioctl_numa_range data;
2204         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2205         int l_errno;
2206         char err_str[LNET_MAX_STR_LEN];
2207         struct cYAML *root = NULL, *range = NULL;
2208
2209         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2210
2211         LIBCFS_IOC_INIT_V2(data, nr_hdr);
2212
2213         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_NUMA_RANGE, &data);
2214         if (rc != 0) {
2215                 l_errno = errno;
2216                 snprintf(err_str,
2217                          sizeof(err_str),
2218                          "\"cannot get numa range: %s\"",
2219                          strerror(l_errno));
2220                 rc = -l_errno;
2221                 goto out;
2222         }
2223
2224         root = cYAML_create_object(NULL, NULL);
2225         if (root == NULL)
2226                 goto out;
2227
2228         range = cYAML_create_object(root, "numa");
2229         if (range == NULL)
2230                 goto out;
2231
2232         if (cYAML_create_number(range, "range",
2233                                 data.nr_range) == NULL)
2234                 goto out;
2235
2236         if (show_rc == NULL)
2237                 cYAML_print_tree(root);
2238
2239         snprintf(err_str, sizeof(err_str), "\"success\"");
2240 out:
2241         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2242                 cYAML_free_tree(root);
2243         } else if (show_rc != NULL && *show_rc != NULL) {
2244                 cYAML_insert_sibling((*show_rc)->cy_child,
2245                                         root->cy_child);
2246                 free(root);
2247         } else {
2248                 *show_rc = root;
2249         }
2250
2251         cYAML_build_error(rc, seq_no, SHOW_CMD, "numa", err_str, err_rc);
2252
2253         return rc;
2254 }
2255
2256 int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc,
2257                            struct cYAML **err_rc)
2258 {
2259         struct lnet_ioctl_lnet_stats data;
2260         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2261         int l_errno;
2262         char err_str[LNET_MAX_STR_LEN];
2263         struct cYAML *root = NULL, *stats = NULL;
2264
2265         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2266
2267         LIBCFS_IOC_INIT_V2(data, st_hdr);
2268
2269         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LNET_STATS, &data);
2270         if (rc != 0) {
2271                 l_errno = errno;
2272                 snprintf(err_str,
2273                          sizeof(err_str),
2274                          "\"cannot get lnet statistics: %s\"",
2275                          strerror(l_errno));
2276                 rc = -l_errno;
2277                 goto out;
2278         }
2279
2280         root = cYAML_create_object(NULL, NULL);
2281         if (root == NULL)
2282                 goto out;
2283
2284         stats = cYAML_create_object(root, "statistics");
2285         if (stats == NULL)
2286                 goto out;
2287
2288         if (cYAML_create_number(stats, "msgs_alloc",
2289                                 data.st_cntrs.msgs_alloc) == NULL)
2290                 goto out;
2291
2292         if (cYAML_create_number(stats, "msgs_max",
2293                                 data.st_cntrs.msgs_max) == NULL)
2294                 goto out;
2295
2296         if (cYAML_create_number(stats, "errors",
2297                                 data.st_cntrs.errors) == NULL)
2298                 goto out;
2299
2300         if (cYAML_create_number(stats, "send_count",
2301                                 data.st_cntrs.send_count) == NULL)
2302                 goto out;
2303
2304         if (cYAML_create_number(stats, "recv_count",
2305                                 data.st_cntrs.recv_count) == NULL)
2306                 goto out;
2307
2308         if (cYAML_create_number(stats, "route_count",
2309                                 data.st_cntrs.route_count) == NULL)
2310                 goto out;
2311
2312         if (cYAML_create_number(stats, "drop_count",
2313                                 data.st_cntrs.drop_count) == NULL)
2314                 goto out;
2315
2316         if (cYAML_create_number(stats, "send_length",
2317                                 data.st_cntrs.send_length) == NULL)
2318                 goto out;
2319
2320         if (cYAML_create_number(stats, "recv_length",
2321                                 data.st_cntrs.recv_length) == NULL)
2322                 goto out;
2323
2324         if (cYAML_create_number(stats, "route_length",
2325                                 data.st_cntrs.route_length) == NULL)
2326                 goto out;
2327
2328         if (cYAML_create_number(stats, "drop_length",
2329                                 data.st_cntrs.drop_length) == NULL)
2330                 goto out;
2331
2332         if (show_rc == NULL)
2333                 cYAML_print_tree(root);
2334
2335         snprintf(err_str, sizeof(err_str), "\"success\"");
2336 out:
2337         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2338                 cYAML_free_tree(root);
2339         } else if (show_rc != NULL && *show_rc != NULL) {
2340                 cYAML_insert_sibling((*show_rc)->cy_child,
2341                                         root->cy_child);
2342                 free(root);
2343         } else {
2344                 *show_rc = root;
2345         }
2346
2347         cYAML_build_error(rc, seq_no, SHOW_CMD, "statistics", err_str, err_rc);
2348
2349         return rc;
2350 }
2351
2352 typedef int (*cmd_handler_t)(struct cYAML *tree,
2353                              struct cYAML **show_rc,
2354                              struct cYAML **err_rc);
2355
2356 static int handle_yaml_config_route(struct cYAML *tree, struct cYAML **show_rc,
2357                                     struct cYAML **err_rc)
2358 {
2359         struct cYAML *net, *gw, *hop, *prio, *seq_no;
2360
2361         net = cYAML_get_object_item(tree, "net");
2362         gw = cYAML_get_object_item(tree, "gateway");
2363         hop = cYAML_get_object_item(tree, "hop");
2364         prio = cYAML_get_object_item(tree, "priority");
2365         seq_no = cYAML_get_object_item(tree, "seq_no");
2366
2367         return lustre_lnet_config_route((net) ? net->cy_valuestring : NULL,
2368                                         (gw) ? gw->cy_valuestring : NULL,
2369                                         (hop) ? hop->cy_valueint : -1,
2370                                         (prio) ? prio->cy_valueint : -1,
2371                                         (seq_no) ? seq_no->cy_valueint : -1,
2372                                         err_rc);
2373 }
2374
2375 static void yaml_free_string_array(char **array, int num)
2376 {
2377         int i;
2378         char **sub_array = array;
2379
2380         for (i = 0; i < num; i++) {
2381                 if (*sub_array != NULL)
2382                         free(*sub_array);
2383                 sub_array++;
2384         }
2385         if (array)
2386                 free(array);
2387 }
2388
2389 /*
2390  *    interfaces:
2391  *        0: <intf_name>['['<expr>']']
2392  *        1: <intf_name>['['<expr>']']
2393  */
2394 static int yaml_copy_intf_info(struct cYAML *intf_tree,
2395                                struct lnet_dlc_network_descr *nw_descr)
2396 {
2397         struct cYAML *child = NULL;
2398         int intf_num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
2399         struct lnet_dlc_intf_descr *intf_descr, *tmp;
2400
2401         if (intf_tree == NULL || nw_descr == NULL)
2402                 return LUSTRE_CFG_RC_BAD_PARAM;
2403
2404         /* now grab all the interfaces and their cpts */
2405         child = intf_tree->cy_child;
2406         while (child != NULL) {
2407                 if (child->cy_valuestring == NULL) {
2408                         child = child->cy_next;
2409                         continue;
2410                 }
2411
2412                 if (strlen(child->cy_valuestring) >= LNET_MAX_STR_LEN)
2413                         goto failed;
2414
2415                 rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist,
2416                                                 child->cy_valuestring,
2417                                                 strlen(child->cy_valuestring));
2418                 if (rc != LUSTRE_CFG_RC_NO_ERR)
2419                         goto failed;
2420
2421                 intf_num++;
2422                 child = child->cy_next;
2423         }
2424
2425         if (intf_num == 0)
2426                 return LUSTRE_CFG_RC_MISSING_PARAM;
2427
2428         return intf_num;
2429
2430 failed:
2431         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
2432                                  intf_on_network) {
2433                 list_del(&intf_descr->intf_on_network);
2434                 free_intf_descr(intf_descr);
2435         }
2436
2437         return rc;
2438 }
2439
2440 static bool
2441 yaml_extract_cmn_tunables(struct cYAML *tree,
2442                           struct lnet_ioctl_config_lnd_cmn_tunables *tunables,
2443                           struct cfs_expr_list **global_cpts)
2444 {
2445         struct cYAML *tun, *item, *smp;
2446         int rc;
2447
2448         tun = cYAML_get_object_item(tree, "tunables");
2449         if (tun != NULL) {
2450                 item = cYAML_get_object_item(tun, "peer_timeout");
2451                 if (item != NULL)
2452                         tunables->lct_peer_timeout = item->cy_valueint;
2453                 item = cYAML_get_object_item(tun, "peer_credits");
2454                 if (item != NULL)
2455                         tunables->lct_peer_tx_credits = item->cy_valueint;
2456                 item = cYAML_get_object_item(tun, "peer_buffer_credits");
2457                 if (item != NULL)
2458                         tunables->lct_peer_rtr_credits = item->cy_valueint;
2459                 item = cYAML_get_object_item(tun, "credits");
2460                 if (item != NULL)
2461                         tunables->lct_max_tx_credits = item->cy_valueint;
2462                 smp = cYAML_get_object_item(tun, "CPT");
2463                 if (smp != NULL) {
2464                         rc = cfs_expr_list_parse(smp->cy_valuestring,
2465                                                  strlen(smp->cy_valuestring),
2466                                                  0, UINT_MAX, global_cpts);
2467                         if (rc != 0)
2468                                 *global_cpts = NULL;
2469                 }
2470
2471                 return true;
2472         }
2473
2474         return false;
2475 }
2476
2477 static bool
2478 yaml_extract_tunables(struct cYAML *tree,
2479                       struct lnet_ioctl_config_lnd_tunables *tunables,
2480                       struct cfs_expr_list **global_cpts,
2481                       __u32 net_type)
2482 {
2483         bool rc;
2484
2485         rc = yaml_extract_cmn_tunables(tree, &tunables->lt_cmn,
2486                                        global_cpts);
2487
2488         if (!rc)
2489                 return rc;
2490
2491         lustre_yaml_extract_lnd_tunables(tree, net_type,
2492                                          &tunables->lt_tun);
2493
2494         return rc;
2495 }
2496
2497 /*
2498  * net:
2499  *    - net type: <net>[<NUM>]
2500   *      local NI(s):
2501  *        - nid: <ip>@<net>[<NUM>]
2502  *          status: up
2503  *          interfaces:
2504  *               0: <intf_name>['['<expr>']']
2505  *               1: <intf_name>['['<expr>']']
2506  *        tunables:
2507  *               peer_timeout: <NUM>
2508  *               peer_credits: <NUM>
2509  *               peer_buffer_credits: <NUM>
2510  *               credits: <NUM>
2511 *         lnd tunables:
2512  *               peercredits_hiw: <NUM>
2513  *               map_on_demand: <NUM>
2514  *               concurrent_sends: <NUM>
2515  *               fmr_pool_size: <NUM>
2516  *               fmr_flush_trigger: <NUM>
2517  *               fmr_cache: <NUM>
2518  *
2519  * At least one interface is required. If no interfaces are provided the
2520  * network interface can not be configured.
2521  */
2522 static int handle_yaml_config_ni(struct cYAML *tree, struct cYAML **show_rc,
2523                                  struct cYAML **err_rc)
2524 {
2525         struct cYAML *net, *intf, *seq_no, *ip2net = NULL, *local_nis = NULL,
2526                      *item = NULL;
2527         int num_entries = 0, rc;
2528         struct lnet_dlc_network_descr nw_descr;
2529         struct cfs_expr_list *global_cpts = NULL;
2530         struct lnet_ioctl_config_lnd_tunables tunables;
2531         bool found = false;
2532
2533         memset(&tunables, 0, sizeof(tunables));
2534
2535         INIT_LIST_HEAD(&nw_descr.network_on_rule);
2536         INIT_LIST_HEAD(&nw_descr.nw_intflist);
2537
2538         ip2net = cYAML_get_object_item(tree, "ip2net");
2539         net = cYAML_get_object_item(tree, "net type");
2540         if (net)
2541                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
2542
2543         /*
2544          * if neither net nor ip2nets are present, then we can not
2545          * configure the network.
2546          */
2547         if (!net && !ip2net)
2548                 return LUSTRE_CFG_RC_MISSING_PARAM;
2549
2550         local_nis = cYAML_get_object_item(tree, "local NI(s)");
2551         if (local_nis == NULL)
2552                 return LUSTRE_CFG_RC_MISSING_PARAM;
2553
2554         if (!cYAML_is_sequence(local_nis))
2555                 return LUSTRE_CFG_RC_BAD_PARAM;
2556
2557         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
2558                 intf = cYAML_get_object_item(item, "interfaces");
2559                 if (intf == NULL)
2560                         continue;
2561                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
2562                 if (num_entries <= 0) {
2563                         cYAML_build_error(num_entries, -1, "ni", "add",
2564                                         "bad interface list",
2565                                         err_rc);
2566                         return LUSTRE_CFG_RC_BAD_PARAM;
2567                 }
2568         }
2569
2570         found = yaml_extract_tunables(tree, &tunables, &global_cpts,
2571                                       LNET_NETTYP(nw_descr.nw_id));
2572         seq_no = cYAML_get_object_item(tree, "seq_no");
2573
2574         rc = lustre_lnet_config_ni(&nw_descr,
2575                                    global_cpts,
2576                                    (ip2net) ? ip2net->cy_valuestring : NULL,
2577                                    (found) ? &tunables: NULL,
2578                                    (seq_no) ? seq_no->cy_valueint : -1,
2579                                    err_rc);
2580
2581         if (global_cpts != NULL)
2582                 cfs_expr_list_free(global_cpts);
2583
2584         return rc;
2585 }
2586
2587 /*
2588  * ip2nets:
2589  *  - net-spec: <tcp|o2ib|gni>[NUM]
2590  *    interfaces:
2591  *        0: <intf name>['['<expr>']']
2592  *        1: <intf name>['['<expr>']']
2593  *    ip-range:
2594  *        0: <expr.expr.expr.expr>
2595  *        1: <expr.expr.expr.expr>
2596  */
2597 static int handle_yaml_config_ip2nets(struct cYAML *tree,
2598                                       struct cYAML **show_rc,
2599                                       struct cYAML **err_rc)
2600 {
2601         struct cYAML *net, *ip_range, *item = NULL, *intf = NULL,
2602                      *seq_no = NULL;
2603         struct lustre_lnet_ip2nets ip2nets;
2604         struct lustre_lnet_ip_range_descr *ip_range_descr = NULL,
2605                                           *tmp = NULL;
2606         int rc = LUSTRE_CFG_RC_NO_ERR;
2607         struct cfs_expr_list *global_cpts = NULL;
2608         struct cfs_expr_list *el, *el_tmp;
2609         struct lnet_ioctl_config_lnd_tunables tunables;
2610         struct lnet_dlc_intf_descr *intf_descr, *intf_tmp;
2611         bool found = false;
2612
2613         memset(&tunables, 0, sizeof(tunables));
2614
2615         /* initialize all lists */
2616         INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
2617         INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
2618         INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
2619
2620         net = cYAML_get_object_item(tree, "net-spec");
2621         if (net == NULL)
2622                 return LUSTRE_CFG_RC_BAD_PARAM;
2623
2624         if (net != NULL && net->cy_valuestring == NULL)
2625                 return LUSTRE_CFG_RC_BAD_PARAM;
2626
2627         /* assign the network id */
2628         ip2nets.ip2nets_net.nw_id = libcfs_str2net(net->cy_valuestring);
2629         if (ip2nets.ip2nets_net.nw_id == LNET_NID_ANY)
2630                 return LUSTRE_CFG_RC_BAD_PARAM;
2631
2632         seq_no = cYAML_get_object_item(tree, "seq_no");
2633
2634         intf = cYAML_get_object_item(tree, "interfaces");
2635         if (intf != NULL) {
2636                 rc = yaml_copy_intf_info(intf, &ip2nets.ip2nets_net);
2637                 if (rc <= 0)
2638                         return LUSTRE_CFG_RC_BAD_PARAM;
2639         }
2640
2641         ip_range = cYAML_get_object_item(tree, "ip-range");
2642         if (ip_range != NULL) {
2643                 item = ip_range->cy_child;
2644                 while (item != NULL) {
2645                         if (item->cy_valuestring == NULL) {
2646                                 item = item->cy_next;
2647                                 continue;
2648                         }
2649
2650                         rc = lustre_lnet_add_ip_range(&ip2nets.ip2nets_ip_ranges,
2651                                                       item->cy_valuestring);
2652
2653                         if (rc != LUSTRE_CFG_RC_NO_ERR)
2654                                 goto out;
2655
2656                         item = item->cy_next;
2657                 }
2658         }
2659
2660         found = yaml_extract_tunables(tree, &tunables, &global_cpts,
2661                                       LNET_NETTYP(ip2nets.ip2nets_net.nw_id));
2662
2663         rc = lustre_lnet_config_ip2nets(&ip2nets,
2664                         (found) ? &tunables : NULL,
2665                         global_cpts,
2666                         (seq_no) ? seq_no->cy_valueint : -1,
2667                         err_rc);
2668
2669         /*
2670          * don't stop because there was no match. Continue processing the
2671          * rest of the rules. If non-match then nothing is configured
2672          */
2673         if (rc == LUSTRE_CFG_RC_NO_MATCH)
2674                 rc = LUSTRE_CFG_RC_NO_ERR;
2675 out:
2676         list_for_each_entry_safe(intf_descr, intf_tmp,
2677                                  &ip2nets.ip2nets_net.nw_intflist,
2678                                  intf_on_network) {
2679                 list_del(&intf_descr->intf_on_network);
2680                 free_intf_descr(intf_descr);
2681         }
2682
2683         list_for_each_entry_safe(ip_range_descr, tmp,
2684                                  &ip2nets.ip2nets_ip_ranges,
2685                                  ipr_entry) {
2686                 list_del(&ip_range_descr->ipr_entry);
2687                 list_for_each_entry_safe(el, el_tmp, &ip_range_descr->ipr_expr,
2688                                          el_link) {
2689                         list_del(&el->el_link);
2690                         cfs_expr_list_free(el);
2691                 }
2692                 free(ip_range_descr);
2693         }
2694
2695         return rc;
2696 }
2697
2698 static int handle_yaml_del_ni(struct cYAML *tree, struct cYAML **show_rc,
2699                               struct cYAML **err_rc)
2700 {
2701         struct cYAML *net = NULL, *intf = NULL, *seq_no = NULL, *item = NULL,
2702                      *local_nis = NULL;
2703         int num_entries, rc;
2704         struct lnet_dlc_network_descr nw_descr;
2705
2706         INIT_LIST_HEAD(&nw_descr.network_on_rule);
2707         INIT_LIST_HEAD(&nw_descr.nw_intflist);
2708
2709         net = cYAML_get_object_item(tree, "net type");
2710         if (net != NULL)
2711                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
2712
2713         local_nis = cYAML_get_object_item(tree, "local NI(s)");
2714         if (local_nis == NULL)
2715                 return LUSTRE_CFG_RC_MISSING_PARAM;
2716
2717         if (!cYAML_is_sequence(local_nis))
2718                 return LUSTRE_CFG_RC_BAD_PARAM;
2719
2720         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
2721                 intf = cYAML_get_object_item(item, "interfaces");
2722                 if (intf == NULL)
2723                         continue;
2724                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
2725                 if (num_entries <= 0) {
2726                         cYAML_build_error(num_entries, -1, "ni", "add",
2727                                         "bad interface list",
2728                                         err_rc);
2729                         return LUSTRE_CFG_RC_BAD_PARAM;
2730                 }
2731         }
2732
2733         seq_no = cYAML_get_object_item(tree, "seq_no");
2734
2735         rc = lustre_lnet_del_ni((net) ? &nw_descr : NULL,
2736                                 (seq_no) ? seq_no->cy_valueint : -1,
2737                                 err_rc);
2738
2739         return rc;
2740 }
2741
2742 static int yaml_copy_peer_nids(struct cYAML *tree, char ***nidsppp)
2743 {
2744         struct cYAML *nids_entry = NULL, *child = NULL, *entry = NULL;
2745         char **nids = NULL;
2746         int num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
2747
2748         nids_entry = cYAML_get_object_item(tree, "peer ni");
2749         if (cYAML_is_sequence(nids_entry)) {
2750                 while (cYAML_get_next_seq_item(nids_entry, &child))
2751                         num++;
2752         }
2753
2754         if (num == 0)
2755                 return LUSTRE_CFG_RC_MISSING_PARAM;
2756
2757         nids = calloc(sizeof(*nids) * num, 1);
2758         if (nids == NULL)
2759                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2760
2761         /* now grab all the nids */
2762         num = 0;
2763         child = NULL;
2764         while (cYAML_get_next_seq_item(nids_entry, &child)) {
2765                 entry = cYAML_get_object_item(child, "nid");
2766                 if (!entry)
2767                         continue;
2768                 nids[num] = calloc(strlen(entry->cy_valuestring) + 1, 1);
2769                 if (!nids[num]) {
2770                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2771                         goto failed;
2772                 }
2773                 strncpy(nids[num], entry->cy_valuestring,
2774                         strlen(entry->cy_valuestring));
2775                 num++;
2776         }
2777         rc = num;
2778
2779         *nidsppp = nids;
2780         return rc;
2781
2782 failed:
2783         if (nids != NULL)
2784                 yaml_free_string_array(nids, num);
2785         *nidsppp = NULL;
2786         return rc;
2787 }
2788
2789 static int handle_yaml_config_peer(struct cYAML *tree, struct cYAML **show_rc,
2790                                    struct cYAML **err_rc)
2791 {
2792         char **nids = NULL;
2793         int num, rc;
2794         struct cYAML *seq_no, *prim_nid, *non_mr;
2795
2796         num = yaml_copy_peer_nids(tree, &nids);
2797         if (num < 0)
2798                 return num;
2799
2800         seq_no = cYAML_get_object_item(tree, "seq_no");
2801         prim_nid = cYAML_get_object_item(tree, "primary nid");
2802         non_mr = cYAML_get_object_item(tree, "non_mr");
2803
2804         rc = lustre_lnet_config_peer_nid((prim_nid) ? prim_nid->cy_valuestring : NULL,
2805                                          nids, num,
2806                                          (non_mr) ? false : true,
2807                                          (seq_no) ? seq_no->cy_valueint : -1,
2808                                          err_rc);
2809
2810         yaml_free_string_array(nids, num);
2811         return rc;
2812 }
2813
2814 static int handle_yaml_del_peer(struct cYAML *tree, struct cYAML **show_rc,
2815                                 struct cYAML **err_rc)
2816 {
2817         char **nids = NULL;
2818         int num, rc;
2819         struct cYAML *seq_no, *prim_nid;
2820
2821         num = yaml_copy_peer_nids(tree, &nids);
2822         if (num < 0)
2823                 return num;
2824
2825         seq_no = cYAML_get_object_item(tree, "seq_no");
2826         prim_nid = cYAML_get_object_item(tree, "primary nid");
2827
2828         rc = lustre_lnet_del_peer_nid((prim_nid) ? prim_nid->cy_valuestring : NULL,
2829                                       nids, num,
2830                                       (seq_no) ? seq_no->cy_valueint : -1,
2831                                       err_rc);
2832
2833         yaml_free_string_array(nids, num);
2834         return rc;
2835 }
2836
2837 static int handle_yaml_config_buffers(struct cYAML *tree,
2838                                       struct cYAML **show_rc,
2839                                       struct cYAML **err_rc)
2840 {
2841         int rc;
2842         struct cYAML *tiny, *small, *large, *seq_no;
2843
2844         tiny = cYAML_get_object_item(tree, "tiny");
2845         small = cYAML_get_object_item(tree, "small");
2846         large = cYAML_get_object_item(tree, "large");
2847         seq_no = cYAML_get_object_item(tree, "seq_no");
2848
2849         rc = lustre_lnet_config_buffers((tiny) ? tiny->cy_valueint : -1,
2850                                         (small) ? small->cy_valueint : -1,
2851                                         (large) ? large->cy_valueint : -1,
2852                                         (seq_no) ? seq_no->cy_valueint : -1,
2853                                         err_rc);
2854
2855         return rc;
2856 }
2857
2858 static int handle_yaml_config_routing(struct cYAML *tree,
2859                                       struct cYAML **show_rc,
2860                                       struct cYAML **err_rc)
2861 {
2862         int rc = LUSTRE_CFG_RC_NO_ERR;
2863         struct cYAML *seq_no, *enable;
2864
2865         seq_no = cYAML_get_object_item(tree, "seq_no");
2866         enable = cYAML_get_object_item(tree, "enable");
2867
2868         if (enable) {
2869                 rc = lustre_lnet_enable_routing(enable->cy_valueint,
2870                                                 (seq_no) ?
2871                                                     seq_no->cy_valueint : -1,
2872                                                 err_rc);
2873         }
2874
2875         return rc;
2876 }
2877
2878 static int handle_yaml_del_route(struct cYAML *tree, struct cYAML **show_rc,
2879                                  struct cYAML **err_rc)
2880 {
2881         struct cYAML *net;
2882         struct cYAML *gw;
2883         struct cYAML *seq_no;
2884
2885         net = cYAML_get_object_item(tree, "net");
2886         gw = cYAML_get_object_item(tree, "gateway");
2887         seq_no = cYAML_get_object_item(tree, "seq_no");
2888
2889         return lustre_lnet_del_route((net) ? net->cy_valuestring : NULL,
2890                                      (gw) ? gw->cy_valuestring : NULL,
2891                                      (seq_no) ? seq_no->cy_valueint : -1,
2892                                      err_rc);
2893 }
2894
2895 static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
2896                                    struct cYAML **err_rc)
2897 {
2898         struct cYAML *seq_no;
2899
2900         seq_no = cYAML_get_object_item(tree, "seq_no");
2901
2902         return lustre_lnet_enable_routing(0, (seq_no) ?
2903                                                 seq_no->cy_valueint : -1,
2904                                         err_rc);
2905 }
2906
2907 static int handle_yaml_show_route(struct cYAML *tree, struct cYAML **show_rc,
2908                                   struct cYAML **err_rc)
2909 {
2910         struct cYAML *net;
2911         struct cYAML *gw;
2912         struct cYAML *hop;
2913         struct cYAML *prio;
2914         struct cYAML *detail;
2915         struct cYAML *seq_no;
2916
2917         net = cYAML_get_object_item(tree, "net");
2918         gw = cYAML_get_object_item(tree, "gateway");
2919         hop = cYAML_get_object_item(tree, "hop");
2920         prio = cYAML_get_object_item(tree, "priority");
2921         detail = cYAML_get_object_item(tree, "detail");
2922         seq_no = cYAML_get_object_item(tree, "seq_no");
2923
2924         return lustre_lnet_show_route((net) ? net->cy_valuestring : NULL,
2925                                       (gw) ? gw->cy_valuestring : NULL,
2926                                       (hop) ? hop->cy_valueint : -1,
2927                                       (prio) ? prio->cy_valueint : -1,
2928                                       (detail) ? detail->cy_valueint : 0,
2929                                       (seq_no) ? seq_no->cy_valueint : -1,
2930                                       show_rc,
2931                                       err_rc);
2932 }
2933
2934 static int handle_yaml_show_net(struct cYAML *tree, struct cYAML **show_rc,
2935                                 struct cYAML **err_rc)
2936 {
2937         struct cYAML *net, *detail, *seq_no;
2938
2939         net = cYAML_get_object_item(tree, "net");
2940         detail = cYAML_get_object_item(tree, "detail");
2941         seq_no = cYAML_get_object_item(tree, "seq_no");
2942
2943         return lustre_lnet_show_net((net) ? net->cy_valuestring : NULL,
2944                                     (detail) ? detail->cy_valueint : 0,
2945                                     (seq_no) ? seq_no->cy_valueint : -1,
2946                                     show_rc,
2947                                     err_rc);
2948 }
2949
2950 static int handle_yaml_show_routing(struct cYAML *tree, struct cYAML **show_rc,
2951                                     struct cYAML **err_rc)
2952 {
2953         struct cYAML *seq_no;
2954
2955         seq_no = cYAML_get_object_item(tree, "seq_no");
2956
2957         return lustre_lnet_show_routing((seq_no) ? seq_no->cy_valueint : -1,
2958                                         show_rc, err_rc);
2959 }
2960
2961 static int handle_yaml_show_peers(struct cYAML *tree, struct cYAML **show_rc,
2962                                   struct cYAML **err_rc)
2963 {
2964         struct cYAML *seq_no, *nid, *detail;
2965
2966         seq_no = cYAML_get_object_item(tree, "seq_no");
2967         detail = cYAML_get_object_item(tree, "detail");
2968         nid = cYAML_get_object_item(tree, "nid");
2969
2970         return lustre_lnet_show_peer((nid) ? nid->cy_valuestring : NULL,
2971                                      (detail) ? detail->cy_valueint : 0,
2972                                      (seq_no) ? seq_no->cy_valueint : -1,
2973                                      show_rc, err_rc);
2974 }
2975
2976 static int handle_yaml_show_stats(struct cYAML *tree, struct cYAML **show_rc,
2977                                   struct cYAML **err_rc)
2978 {
2979         struct cYAML *seq_no;
2980
2981         seq_no = cYAML_get_object_item(tree, "seq_no");
2982
2983         return lustre_lnet_show_stats((seq_no) ? seq_no->cy_valueint : -1,
2984                                       show_rc, err_rc);
2985 }
2986
2987 static int handle_yaml_config_numa(struct cYAML *tree, struct cYAML **show_rc,
2988                                   struct cYAML **err_rc)
2989 {
2990         struct cYAML *seq_no, *range;
2991
2992         seq_no = cYAML_get_object_item(tree, "seq_no");
2993         range = cYAML_get_object_item(tree, "range");
2994
2995         return lustre_lnet_config_numa_range(range ? range->cy_valueint : -1,
2996                                              seq_no ? seq_no->cy_valueint : -1,
2997                                              err_rc);
2998 }
2999
3000 static int handle_yaml_del_numa(struct cYAML *tree, struct cYAML **show_rc,
3001                                struct cYAML **err_rc)
3002 {
3003         struct cYAML *seq_no;
3004
3005         seq_no = cYAML_get_object_item(tree, "seq_no");
3006
3007         return lustre_lnet_config_numa_range(0, seq_no ? seq_no->cy_valueint : -1,
3008                                              err_rc);
3009 }
3010
3011 static int handle_yaml_show_numa(struct cYAML *tree, struct cYAML **show_rc,
3012                                 struct cYAML **err_rc)
3013 {
3014         struct cYAML *seq_no;
3015
3016         seq_no = cYAML_get_object_item(tree, "seq_no");
3017
3018         return lustre_lnet_show_numa_range(seq_no ? seq_no->cy_valueint : -1,
3019                                            show_rc, err_rc);
3020 }
3021
3022 struct lookup_cmd_hdlr_tbl {
3023         char *name;
3024         cmd_handler_t cb;
3025 };
3026
3027 static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
3028         { .name = "route",      .cb = handle_yaml_config_route },
3029         { .name = "net",        .cb = handle_yaml_config_ni },
3030         { .name = "ip2nets",    .cb = handle_yaml_config_ip2nets },
3031         { .name = "peer",       .cb = handle_yaml_config_peer },
3032         { .name = "routing",    .cb = handle_yaml_config_routing },
3033         { .name = "buffers",    .cb = handle_yaml_config_buffers },
3034         { .name = "numa",       .cb = handle_yaml_config_numa },
3035         { .name = NULL } };
3036
3037 static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
3038         { .name = "route",      .cb = handle_yaml_del_route },
3039         { .name = "net",        .cb = handle_yaml_del_ni },
3040         { .name = "peer",       .cb = handle_yaml_del_peer },
3041         { .name = "routing",    .cb = handle_yaml_del_routing },
3042         { .name = "numa",       .cb = handle_yaml_del_numa },
3043         { .name = NULL } };
3044
3045 static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = {
3046         { .name = "route",      .cb = handle_yaml_show_route },
3047         { .name = "net",        .cb = handle_yaml_show_net },
3048         { .name = "buffers",    .cb = handle_yaml_show_routing },
3049         { .name = "routing",    .cb = handle_yaml_show_routing },
3050         { .name = "peer",       .cb = handle_yaml_show_peers },
3051         { .name = "statistics", .cb = handle_yaml_show_stats },
3052         { .name = "numa",       .cb = handle_yaml_show_numa },
3053         { .name = NULL } };
3054
3055 static cmd_handler_t lookup_fn(char *key,
3056                                struct lookup_cmd_hdlr_tbl *tbl)
3057 {
3058         int i;
3059         if (key == NULL)
3060                 return NULL;
3061
3062         for (i = 0; tbl[i].name != NULL; i++) {
3063                 if (strncmp(key, tbl[i].name, strlen(tbl[i].name)) == 0)
3064                         return tbl[i].cb;
3065         }
3066
3067         return NULL;
3068 }
3069
3070 static int lustre_yaml_cb_helper(char *f, struct lookup_cmd_hdlr_tbl *table,
3071                                  struct cYAML **show_rc, struct cYAML **err_rc)
3072 {
3073         struct cYAML *tree, *item = NULL, *head, *child;
3074         cmd_handler_t cb;
3075         char err_str[LNET_MAX_STR_LEN];
3076         int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
3077
3078         tree = cYAML_build_tree(f, NULL, 0, err_rc, false);
3079         if (tree == NULL)
3080                 return LUSTRE_CFG_RC_BAD_PARAM;
3081
3082         child = tree->cy_child;
3083         while (child != NULL) {
3084                 cb = lookup_fn(child->cy_string, table);
3085                 if (cb == NULL) {
3086                         snprintf(err_str, sizeof(err_str),
3087                                 "\"call back for '%s' not found\"",
3088                                 child->cy_string);
3089                         cYAML_build_error(LUSTRE_CFG_RC_BAD_PARAM, -1,
3090                                         "yaml", "helper", err_str, err_rc);
3091                         goto out;
3092                 }
3093
3094                 if (cYAML_is_sequence(child)) {
3095                         while ((head = cYAML_get_next_seq_item(child, &item))
3096                                != NULL) {
3097                                 rc = cb(head, show_rc, err_rc);
3098                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
3099                                         return_rc = rc;
3100                         }
3101                 } else {
3102                         rc = cb(child, show_rc, err_rc);
3103                         if (rc != LUSTRE_CFG_RC_NO_ERR)
3104                                 return_rc = rc;
3105                 }
3106                 item = NULL;
3107                 child = child->cy_next;
3108         }
3109
3110 out:
3111         cYAML_free_tree(tree);
3112
3113         return return_rc;
3114 }
3115
3116 int lustre_yaml_config(char *f, struct cYAML **err_rc)
3117 {
3118         return lustre_yaml_cb_helper(f, lookup_config_tbl,
3119                                      NULL, err_rc);
3120 }
3121
3122 int lustre_yaml_del(char *f, struct cYAML **err_rc)
3123 {
3124         return lustre_yaml_cb_helper(f, lookup_del_tbl,
3125                                      NULL, err_rc);
3126 }
3127
3128 int lustre_yaml_show(char *f, struct cYAML **show_rc, struct cYAML **err_rc)
3129 {
3130         return lustre_yaml_cb_helper(f, lookup_show_tbl,
3131                                      show_rc, err_rc);
3132 }
3133
3134 int lustre_lnet_send_dbg_task(enum lnet_dbg_task dbg_task,
3135                               struct lnet_dbg_task_info *dbg_info,
3136                               struct cYAML **show_rc,
3137                               struct cYAML **err_rc)
3138 {
3139         struct lnet_ioctl_dbg *dbg;
3140         struct lnet_dbg_task_info *info;
3141         int rc = LUSTRE_CFG_RC_NO_ERR;
3142         char err_str[LNET_MAX_STR_LEN];
3143
3144         snprintf(err_str, sizeof(err_str), "\"success\"");
3145
3146         dbg = calloc(1, sizeof(*dbg) + sizeof(*info));
3147         if (!dbg) {
3148                 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
3149                 rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3150                 goto out;
3151         }
3152
3153         info = (struct lnet_dbg_task_info *)dbg->dbg_bulk;
3154
3155         LIBCFS_IOC_INIT_V2(*dbg, dbg_hdr);
3156
3157         dbg->dbg_task = dbg_task;
3158         if (dbg_info)
3159                 memcpy(info, dbg_info, sizeof(*info));
3160
3161         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DBG, dbg);
3162         if (rc != 0) {
3163                 rc = -errno;
3164                 snprintf(err_str,
3165                          sizeof(err_str),
3166                          "\"debug task failed %s\"", strerror(errno));
3167                 goto out;
3168         }
3169
3170 out:
3171         cYAML_build_error(rc, -1, DBG_CMD,
3172                          "debug", err_str, err_rc);
3173
3174         return rc;
3175 }
3176