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