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