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