Whamcloud - gitweb
LU-9480 lnet: configure lnet_interfaces_max tunable from dlc
[fs/lustre-release.git] / lnet / utils / lnetctl.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 #include <getopt.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <libcfs/util/ioctl.h>
32 #include <libcfs/util/parser.h>
33 #include <cyaml.h>
34 #include "lnetconfig/liblnetconfig.h"
35
36 #define LNET_CONFIGURE          true
37 #define LNET_UNCONFIGURE        false
38
39 static int jt_config_lnet(int argc, char **argv);
40 static int jt_unconfig_lnet(int argc, char **argv);
41 static int jt_add_route(int argc, char **argv);
42 static int jt_add_ni(int argc, char **argv);
43 static int jt_set_routing(int argc, char **argv);
44 static int jt_del_route(int argc, char **argv);
45 static int jt_del_ni(int argc, char **argv);
46 static int jt_show_route(int argc, char **argv);
47 static int jt_show_net(int argc, char **argv);
48 static int jt_show_routing(int argc, char **argv);
49 static int jt_show_stats(int argc, char **argv);
50 static int jt_show_peer(int argc, char **argv);
51 static int jt_show_global(int argc, char **argv);
52 static int jt_set_tiny(int argc, char **argv);
53 static int jt_set_small(int argc, char **argv);
54 static int jt_set_large(int argc, char **argv);
55 static int jt_set_numa(int argc, char **argv);
56 static int jt_add_peer_nid(int argc, char **argv);
57 static int jt_del_peer_nid(int argc, char **argv);
58 static int jt_set_max_intf(int argc, char **argv);
59 /*static int jt_show_peer(int argc, char **argv);*/
60 static int lnetctl_list_commands(int argc, char **argv);
61
62 command_t lnet_cmds[] = {
63         {"configure", jt_config_lnet, 0, "configure lnet\n"
64          "\t--all: load NI configuration from module parameters\n"},
65         {"unconfigure", jt_unconfig_lnet, 0, "unconfigure lnet\n"},
66         { 0, 0, 0, NULL }
67 };
68
69 command_t route_cmds[] = {
70         {"add", jt_add_route, 0, "add a route\n"
71          "\t--net: net name (e.g. tcp0)\n"
72          "\t--gateway: gateway nid (e.g. 10.1.1.2@tcp)\n"
73          "\t--hop: number to final destination (1 < hops < 255)\n"
74          "\t--priority: priority of route (0 - highest prio\n"},
75         {"del", jt_del_route, 0, "delete a route\n"
76          "\t--net: net name (e.g. tcp0)\n"
77          "\t--gateway: gateway nid (e.g. 10.1.1.2@tcp)\n"},
78         {"show", jt_show_route, 0, "show routes\n"
79          "\t--net: net name (e.g. tcp0) to filter on\n"
80          "\t--gateway: gateway nid (e.g. 10.1.1.2@tcp) to filter on\n"
81          "\t--hop: number to final destination (1 < hops < 255) to filter on\n"
82          "\t--priority: priority of route (0 - highest prio to filter on\n"
83          "\t--verbose: display detailed output per route\n"},
84         { 0, 0, 0, NULL }
85 };
86
87 command_t net_cmds[] = {
88         {"add", jt_add_ni, 0, "add a network\n"
89          "\t--net: net name (e.g. tcp0)\n"
90          "\t--if: physical interface (e.g. eth0)\n"
91          "\t--ip2net: specify networks based on IP address patterns\n"
92          "\t--peer-timeout: time to wait before declaring a peer dead\n"
93          "\t--peer-credits: define the max number of inflight messages\n"
94          "\t--peer-buffer-credits: the number of buffer credits per peer\n"
95          "\t--credits: Network Interface credits\n"
96          "\t--cpt: CPU Partitions configured net uses (e.g. [0,1]\n"},
97         {"del", jt_del_ni, 0, "delete a network\n"
98          "\t--net: net name (e.g. tcp0)\n"
99          "\t--if: physical interface (e.g. eth0)\n"},
100         {"show", jt_show_net, 0, "show networks\n"
101          "\t--net: net name (e.g. tcp0) to filter on\n"
102          "\t--verbose: display detailed output per network\n"},
103         { 0, 0, 0, NULL }
104 };
105
106 command_t routing_cmds[] = {
107         {"show", jt_show_routing, 0, "show routing information\n"},
108         { 0, 0, 0, NULL }
109 };
110
111 command_t stats_cmds[] = {
112         {"show", jt_show_stats, 0, "show LNET statistics\n"},
113         { 0, 0, 0, NULL }
114 };
115
116 command_t global_cmds[] = {
117         {"show", jt_show_global, 0, "show global variables\n"},
118         { 0, 0, 0, NULL }
119 };
120
121 command_t set_cmds[] = {
122         {"tiny_buffers", jt_set_tiny, 0, "set tiny routing buffers\n"
123          "\tVALUE must be greater than 0\n"},
124         {"small_buffers", jt_set_small, 0, "set small routing buffers\n"
125          "\tVALUE must be greater than 0\n"},
126         {"large_buffers", jt_set_large, 0, "set large routing buffers\n"
127          "\tVALUE must be greater than 0\n"},
128         {"routing", jt_set_routing, 0, "enable/disable routing\n"
129          "\t0 - disable routing\n"
130          "\t1 - enable routing\n"},
131         {"numa_range", jt_set_numa, 0, "set NUMA range for NI selection\n"
132          "\tVALUE must be at least 0\n"},
133         {"max_interfaces", jt_set_max_intf, 0, "set the default value for "
134                 "max interfaces\n"
135          "\tValue must be greater than 16\n"},
136         { 0, 0, 0, NULL }
137 };
138
139 command_t peer_cmds[] = {
140         {"add", jt_add_peer_nid, 0, "add a peer NID\n"
141          "\t--prim_nid: Primary NID of the peer. If not provided then the first\n"
142          "\t            NID in the list becomes the Primary NID of a newly created\n"
143          "\t            peer. \n"
144          "\t--nid: one or more peer NIDs\n"
145          "\t--non_mr: create this peer as not Multi-Rail capable\n"},
146         {"del", jt_del_peer_nid, 0, "delete a peer NID\n"
147          "\t--prim_nid: Primary NID of the peer.\n"
148          "\t--nid: list of NIDs to remove. If none provided,\n"
149          "\t       peer is deleted\n"},
150         {"show", jt_show_peer, 0, "show peer information\n"
151          "\t--nid: NID of peer to filter on.\n"
152          "\t--verbose: Include  extended  statistics\n"},
153         { 0, 0, 0, NULL }
154 };
155
156 static inline void print_help(const command_t cmds[], const char *cmd_type,
157                               const char *pc_name)
158 {
159         const command_t *cmd;
160
161         for (cmd = cmds; cmd->pc_name; cmd++) {
162                 if (pc_name != NULL &&
163                     strcmp(cmd->pc_name, pc_name) == 0) {
164                         printf("%s %s: %s\n", cmd_type, cmd->pc_name,
165                                cmd->pc_help);
166                         return;
167                 } else if (pc_name != NULL) {
168                         continue;
169                 }
170                 printf("%s %s: %s\n", cmd_type, cmd->pc_name, cmd->pc_help);
171         }
172 }
173
174 static int parse_long(const char *number, long int *value)
175 {
176         char *end;
177
178         *value = strtol(number,  &end, 0);
179         if (end != NULL && *end != 0)
180                 return -1;
181
182         return 0;
183 }
184
185 static int handle_help(const command_t *cmd_list, const char *cmd,
186                        const char *sub_cmd, int argc, char **argv)
187 {
188         int opt;
189         int rc = -1;
190         optind = 0;
191         opterr = 0;
192
193         const char *const short_options = "h";
194         static const struct option long_options[] = {
195                 { .name = "help", .has_arg = no_argument, .val = 'h' },
196                 { .name = NULL }
197         };
198
199         while ((opt = getopt_long(argc, argv, short_options,
200                                   long_options, NULL)) != -1) {
201                 switch (opt) {
202                 case 'h':
203                         print_help(cmd_list, cmd, sub_cmd);
204                         rc = 0;
205                         break;
206                 default:
207                         rc = -1;
208                         break;
209                 }
210         }
211
212         opterr = 1;
213         optind = 0;
214         return rc;
215 }
216
217 static int jt_set_max_intf(int argc, char **argv)
218 {
219         long int value;
220         int rc;
221         struct cYAML *err_rc = NULL;
222
223         if (handle_help(set_cmds, "set", "max_interfaces", argc, argv) == 0)
224                 return 0;
225
226         rc = parse_long(argv[1], &value);
227         if (rc != 0) {
228                 cYAML_build_error(-1, -1, "parser", "set",
229                                   "cannot parse max_interfaces value", &err_rc);
230                 cYAML_print_tree2file(stderr, err_rc);
231                 cYAML_free_tree(err_rc);
232                 return -1;
233         }
234
235         rc = lustre_lnet_config_max_intf(value, -1, &err_rc);
236         if (rc != LUSTRE_CFG_RC_NO_ERR)
237                 cYAML_print_tree2file(stderr, err_rc);
238
239         cYAML_free_tree(err_rc);
240
241         return rc;
242 }
243
244 static int jt_set_numa(int argc, char **argv)
245 {
246         long int value;
247         int rc;
248         struct cYAML *err_rc = NULL;
249
250         if (handle_help(set_cmds, "set", "numa_range", argc, argv) == 0)
251                 return 0;
252
253         rc = parse_long(argv[1], &value);
254         if (rc != 0) {
255                 cYAML_build_error(-1, -1, "parser", "set",
256                                   "cannot parse numa_range value", &err_rc);
257                 cYAML_print_tree2file(stderr, err_rc);
258                 cYAML_free_tree(err_rc);
259                 return -1;
260         }
261
262         rc = lustre_lnet_config_numa_range(value, -1, &err_rc);
263         if (rc != LUSTRE_CFG_RC_NO_ERR)
264                 cYAML_print_tree2file(stderr, err_rc);
265
266         cYAML_free_tree(err_rc);
267
268         return rc;
269 }
270
271 static int jt_set_tiny(int argc, char **argv)
272 {
273         long int value;
274         int rc;
275         struct cYAML *err_rc = NULL;
276
277         if (handle_help(set_cmds, "set", "tiny_buffers", argc, argv) == 0)
278                 return 0;
279
280         rc = parse_long(argv[1], &value);
281         if (rc != 0) {
282                 cYAML_build_error(-1, -1, "parser", "set",
283                                   "cannot parse tiny_buffers value", &err_rc);
284                 cYAML_print_tree2file(stderr, err_rc);
285                 cYAML_free_tree(err_rc);
286                 return -1;
287         }
288
289         rc = lustre_lnet_config_buffers(value, -1, -1, -1, &err_rc);
290         if (rc != LUSTRE_CFG_RC_NO_ERR)
291                 cYAML_print_tree2file(stderr, err_rc);
292
293         cYAML_free_tree(err_rc);
294
295         return rc;
296 }
297
298 static int jt_set_small(int argc, char **argv)
299 {
300         long int value;
301         int rc;
302         struct cYAML *err_rc = NULL;
303
304         if (handle_help(set_cmds, "set", "small_buffers", argc, argv) == 0)
305                 return 0;
306
307         rc = parse_long(argv[1], &value);
308         if (rc != 0) {
309                 cYAML_build_error(-1, -1, "parser", "set",
310                                   "cannot parse small_buffers value", &err_rc);
311                 cYAML_print_tree2file(stderr, err_rc);
312                 cYAML_free_tree(err_rc);
313                 return -1;
314         }
315
316         rc = lustre_lnet_config_buffers(-1, value, -1, -1, &err_rc);
317         if (rc != LUSTRE_CFG_RC_NO_ERR)
318                 cYAML_print_tree2file(stderr, err_rc);
319
320         cYAML_free_tree(err_rc);
321
322         return rc;
323 }
324
325 static int jt_set_large(int argc, char **argv)
326 {
327         long int value;
328         int rc;
329         struct cYAML *err_rc = NULL;
330
331         if (handle_help(set_cmds, "set", "large_buffers", argc, argv) == 0)
332                 return 0;
333
334         rc = parse_long(argv[1], &value);
335         if (rc != 0) {
336                 cYAML_build_error(-1, -1, "parser", "set",
337                                   "cannot parse large_buffers value", &err_rc);
338                 cYAML_print_tree2file(stderr, err_rc);
339                 cYAML_free_tree(err_rc);
340                 return -1;
341         }
342
343         rc = lustre_lnet_config_buffers(-1, -1, value, -1, &err_rc);
344         if (rc != LUSTRE_CFG_RC_NO_ERR)
345                 cYAML_print_tree2file(stderr, err_rc);
346
347         cYAML_free_tree(err_rc);
348
349         return rc;
350 }
351
352 static int jt_set_routing(int argc, char **argv)
353 {
354         long int value;
355         struct cYAML *err_rc = NULL;
356         int rc;
357
358         if (handle_help(set_cmds, "set", "routing", argc, argv) == 0)
359                 return 0;
360
361         rc = parse_long(argv[1], &value);
362         if (rc != 0 || (value != 0 && value != 1)) {
363                 cYAML_build_error(-1, -1, "parser", "set",
364                                   "cannot parse routing value.\n"
365                                   "must be 0 for disable or 1 for enable",
366                                   &err_rc);
367                 cYAML_print_tree2file(stderr, err_rc);
368                 cYAML_free_tree(err_rc);
369                 return -1;
370         }
371
372         rc = lustre_lnet_enable_routing(value, -1, &err_rc);
373
374         if (rc != LUSTRE_CFG_RC_NO_ERR)
375                 cYAML_print_tree2file(stderr, err_rc);
376
377         cYAML_free_tree(err_rc);
378
379         return rc;
380 }
381
382 static int jt_config_lnet(int argc, char **argv)
383 {
384         struct cYAML *err_rc = NULL;
385         bool load_mod_params = false;
386         int rc, opt;
387
388         const char *const short_options = "ah";
389         static const struct option long_options[] = {
390                 { .name = "all",  .has_arg = no_argument, .val = 'a' },
391                 { .name = "help", .has_arg = no_argument, .val = 'h' },
392                 { .name = NULL }
393         };
394
395         while ((opt = getopt_long(argc, argv, short_options,
396                                    long_options, NULL)) != -1) {
397                 switch (opt) {
398                 case 'a':
399                         load_mod_params = true;
400                         break;
401                 case 'h':
402                         print_help(lnet_cmds, "lnet", "configure");
403                         return 0;
404                 default:
405                         return 0;
406                 }
407         }
408
409         rc = lustre_lnet_config_ni_system(LNET_CONFIGURE, load_mod_params,
410                                           -1, &err_rc);
411
412         if (rc != LUSTRE_CFG_RC_NO_ERR)
413                 cYAML_print_tree2file(stderr, err_rc);
414
415         cYAML_free_tree(err_rc);
416
417         return rc;
418 }
419
420 static int jt_unconfig_lnet(int argc, char **argv)
421 {
422         struct cYAML *err_rc = NULL;
423         int rc;
424
425         if (handle_help(lnet_cmds, "lnet", "unconfigure", argc, argv) == 0)
426                 return 0;
427
428         rc = lustre_lnet_config_ni_system(LNET_UNCONFIGURE, 0, -1, &err_rc);
429
430         if (rc != LUSTRE_CFG_RC_NO_ERR)
431                 cYAML_print_tree2file(stderr, err_rc);
432
433         cYAML_free_tree(err_rc);
434
435         return rc;
436 }
437 static int jt_add_route(int argc, char **argv)
438 {
439         char *network = NULL, *gateway = NULL;
440         long int hop = -1, prio = -1;
441         struct cYAML *err_rc = NULL;
442         int rc, opt;
443
444         const char *const short_options = "n:g:c:p:h";
445         static const struct option long_options[] = {
446         { .name = "net",       .has_arg = required_argument, .val = 'n' },
447         { .name = "gateway",   .has_arg = required_argument, .val = 'g' },
448         { .name = "hop-count", .has_arg = required_argument, .val = 'c' },
449         { .name = "priority",  .has_arg = required_argument, .val = 'p' },
450         { .name = "help",      .has_arg = no_argument,       .val = 'h' },
451         { .name = NULL } };
452
453         while ((opt = getopt_long(argc, argv, short_options,
454                                    long_options, NULL)) != -1) {
455                 switch (opt) {
456                 case 'n':
457                         network = optarg;
458                         break;
459                 case 'g':
460                         gateway = optarg;
461                         break;
462                 case 'c':
463                         rc = parse_long(optarg, &hop);
464                         if (rc != 0) {
465                                 /* ignore option */
466                                 hop = -1;
467                                 continue;
468                         }
469                         break;
470                 case 'p':
471                         rc = parse_long(optarg, &prio);
472                         if (rc != 0) {
473                                 /* ingore option */
474                                 prio = -1;
475                                 continue;
476                         }
477                         break;
478                 case 'h':
479                         print_help(route_cmds, "route", "add");
480                         return 0;
481                 default:
482                         return 0;
483                 }
484         }
485
486         rc = lustre_lnet_config_route(network, gateway, hop, prio, -1, &err_rc);
487
488         if (rc != LUSTRE_CFG_RC_NO_ERR)
489                 cYAML_print_tree2file(stderr, err_rc);
490
491         cYAML_free_tree(err_rc);
492
493         return rc;
494 }
495
496 static int jt_add_ni(int argc, char **argv)
497 {
498         char *ip2net = NULL;
499         long int pto = -1, pc = -1, pbc = -1, cre = -1;
500         struct cYAML *err_rc = NULL;
501         int rc, opt, cpt_rc = -1;
502         struct lnet_dlc_network_descr nw_descr;
503         struct cfs_expr_list *global_cpts = NULL;
504         struct lnet_ioctl_config_lnd_tunables tunables;
505         bool found = false;
506
507         memset(&tunables, 0, sizeof(tunables));
508         lustre_lnet_init_nw_descr(&nw_descr);
509
510         const char *const short_options = "n:i:p:t:c:b:r:s:h";
511         static const struct option long_options[] = {
512         { .name = "net",          .has_arg = required_argument, .val = 'n' },
513         { .name = "if",           .has_arg = required_argument, .val = 'i' },
514         { .name = "ip2net",       .has_arg = required_argument, .val = 'p' },
515         { .name = "peer-timeout", .has_arg = required_argument, .val = 't' },
516         { .name = "peer-credits", .has_arg = required_argument, .val = 'c' },
517         { .name = "peer-buffer-credits",
518                                   .has_arg = required_argument, .val = 'b' },
519         { .name = "credits",      .has_arg = required_argument, .val = 'r' },
520         { .name = "cpt",          .has_arg = required_argument, .val = 's' },
521         { .name = "help",         .has_arg = no_argument,       .val = 'h' },
522         { .name = NULL } };
523
524         while ((opt = getopt_long(argc, argv, short_options,
525                                    long_options, NULL)) != -1) {
526                 switch (opt) {
527                 case 'n':
528                         nw_descr.nw_id = libcfs_str2net(optarg);
529                         break;
530                 case 'i':
531                         rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
532                         if (rc != 0) {
533                                 cYAML_build_error(-1, -1, "ni", "add",
534                                                 "bad interface list",
535                                                 &err_rc);
536                                 goto failed;
537                         }
538                         break;
539                 case 'p':
540                         ip2net = optarg;
541                         break;
542                 case 't':
543                         rc = parse_long(optarg, &pto);
544                         if (rc != 0) {
545                                 /* ignore option */
546                                 pto = -1;
547                                 continue;
548                         }
549                         break;
550                 case 'c':
551                         rc = parse_long(optarg, &pc);
552                         if (rc != 0) {
553                                 /* ignore option */
554                                 pc = -1;
555                                 continue;
556                         }
557                         break;
558                 case 'b':
559                         rc = parse_long(optarg, &pbc);
560                         if (rc != 0) {
561                                 /* ignore option */
562                                 pbc = -1;
563                                 continue;
564                         }
565                         break;
566                 case 'r':
567                         rc = parse_long(optarg, &cre);
568                         if (rc != 0) {
569                                 /* ignore option */
570                                 cre = -1;
571                                 continue;
572                         }
573                         break;
574                 case 's':
575                         cpt_rc = cfs_expr_list_parse(optarg,
576                                                      strlen(optarg), 0,
577                                                      UINT_MAX, &global_cpts);
578                         break;
579                 case 'h':
580                         print_help(net_cmds, "net", "add");
581                         return 0;
582                 default:
583                         return 0;
584                 }
585         }
586
587         if (pto > 0 || pc > 0 || pbc > 0 || cre > 0) {
588                 tunables.lt_cmn.lct_peer_timeout = pto;
589                 tunables.lt_cmn.lct_peer_tx_credits = pc;
590                 tunables.lt_cmn.lct_peer_rtr_credits = pbc;
591                 tunables.lt_cmn.lct_max_tx_credits = cre;
592                 found = true;
593         }
594
595         rc = lustre_lnet_config_ni(&nw_descr,
596                                    (cpt_rc == 0) ? global_cpts: NULL,
597                                    ip2net, (found) ? &tunables : NULL,
598                                    -1, &err_rc);
599
600         if (global_cpts != NULL)
601                 cfs_expr_list_free(global_cpts);
602
603 failed:
604         if (rc != LUSTRE_CFG_RC_NO_ERR)
605                 cYAML_print_tree2file(stderr, err_rc);
606
607         cYAML_free_tree(err_rc);
608
609         return rc;
610 }
611
612 static int jt_del_route(int argc, char **argv)
613 {
614         char *network = NULL, *gateway = NULL;
615         struct cYAML *err_rc = NULL;
616         int rc, opt;
617
618         const char *const short_options = "n:g:h";
619         static const struct option long_options[] = {
620                 { .name = "net",     .has_arg = required_argument, .val = 'n' },
621                 { .name = "gateway", .has_arg = required_argument, .val = 'g' },
622                 { .name = "help",    .has_arg = no_argument,       .val = 'h' },
623                 { .name = NULL } };
624
625         while ((opt = getopt_long(argc, argv, short_options,
626                                    long_options, NULL)) != -1) {
627                 switch (opt) {
628                 case 'n':
629                         network = optarg;
630                         break;
631                 case 'g':
632                         gateway = optarg;
633                         break;
634                 case 'h':
635                         print_help(route_cmds, "route", "del");
636                         return 0;
637                 default:
638                         return 0;
639                 }
640         }
641
642         rc = lustre_lnet_del_route(network, gateway, -1, &err_rc);
643
644         if (rc != LUSTRE_CFG_RC_NO_ERR)
645                 cYAML_print_tree2file(stderr, err_rc);
646
647         cYAML_free_tree(err_rc);
648
649         return rc;
650 }
651
652 static int jt_del_ni(int argc, char **argv)
653 {
654         struct cYAML *err_rc = NULL;
655         int rc, opt;
656         struct lnet_dlc_network_descr nw_descr;
657
658         lustre_lnet_init_nw_descr(&nw_descr);
659
660         const char *const short_options = "n:i:h";
661         static const struct option long_options[] = {
662         { .name = "net",        .has_arg = required_argument,   .val = 'n' },
663         { .name = "if",         .has_arg = required_argument,   .val = 'i' },
664         { .name = "help",       .has_arg = no_argument,         .val = 'h' },
665         { .name = NULL } };
666
667         while ((opt = getopt_long(argc, argv, short_options,
668                                    long_options, NULL)) != -1) {
669                 switch (opt) {
670                 case 'n':
671                         nw_descr.nw_id = libcfs_str2net(optarg);
672                         break;
673                 case 'i':
674                         rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
675                         if (rc != 0) {
676                                 cYAML_build_error(-1, -1, "ni", "add",
677                                                 "bad interface list",
678                                                 &err_rc);
679                                 goto out;
680                         }
681                         break;
682                 case 'h':
683                         print_help(net_cmds, "net", "del");
684                         return 0;
685                 default:
686                         return 0;
687                 }
688         }
689
690         rc = lustre_lnet_del_ni(&nw_descr, -1, &err_rc);
691
692 out:
693         if (rc != LUSTRE_CFG_RC_NO_ERR)
694                 cYAML_print_tree2file(stderr, err_rc);
695
696         cYAML_free_tree(err_rc);
697
698         return rc;
699 }
700
701 static int jt_show_route(int argc, char **argv)
702 {
703         char *network = NULL, *gateway = NULL;
704         long int hop = -1, prio = -1;
705         int detail = 0, rc, opt;
706         struct cYAML *err_rc = NULL, *show_rc = NULL;
707
708         const char *const short_options = "n:g:h:p:vh";
709         static const struct option long_options[] = {
710         { .name = "net",       .has_arg = required_argument, .val = 'n' },
711         { .name = "gateway",   .has_arg = required_argument, .val = 'g' },
712         { .name = "hop-count", .has_arg = required_argument, .val = 'c' },
713         { .name = "priority",  .has_arg = required_argument, .val = 'p' },
714         { .name = "verbose",   .has_arg = no_argument,       .val = 'v' },
715         { .name = "help",      .has_arg = no_argument,       .val = 'h' },
716         { .name = NULL } };
717
718         while ((opt = getopt_long(argc, argv, short_options,
719                                    long_options, NULL)) != -1) {
720                 switch (opt) {
721                 case 'n':
722                         network = optarg;
723                         break;
724                 case 'g':
725                         gateway = optarg;
726                         break;
727                 case 'c':
728                         rc = parse_long(optarg, &hop);
729                         if (rc != 0) {
730                                 /* ignore option */
731                                 hop = -1;
732                                 continue;
733                         }
734                         break;
735                 case 'p':
736                         rc = parse_long(optarg, &prio);
737                         if (rc != 0) {
738                                 /* ignore option */
739                                 prio = -1;
740                                 continue;
741                         }
742                         break;
743                 case 'v':
744                         detail = 1;
745                         break;
746                 case 'h':
747                         print_help(route_cmds, "route", "show");
748                         return 0;
749                 default:
750                         return 0;
751                 }
752         }
753
754         rc = lustre_lnet_show_route(network, gateway, hop, prio, detail, -1,
755                                     &show_rc, &err_rc);
756
757         if (rc != LUSTRE_CFG_RC_NO_ERR)
758                 cYAML_print_tree2file(stderr, err_rc);
759         else if (show_rc)
760                 cYAML_print_tree(show_rc);
761
762         cYAML_free_tree(err_rc);
763         cYAML_free_tree(show_rc);
764
765         return rc;
766 }
767
768 static int jt_show_net(int argc, char **argv)
769 {
770         char *network = NULL;
771         int detail = 0, rc, opt;
772         struct cYAML *err_rc = NULL, *show_rc = NULL;
773
774         const char *const short_options = "n:vh";
775         static const struct option long_options[] = {
776                 { .name = "net",     .has_arg = required_argument, .val = 'n' },
777                 { .name = "verbose", .has_arg = no_argument,       .val = 'v' },
778                 { .name = "help",    .has_arg = no_argument,       .val = 'h' },
779                 { .name = NULL } };
780
781         while ((opt = getopt_long(argc, argv, short_options,
782                                    long_options, NULL)) != -1) {
783                 switch (opt) {
784                 case 'n':
785                         network = optarg;
786                         break;
787                 case 'v':
788                         detail = 1;
789                         break;
790                 case 'h':
791                         print_help(net_cmds, "net", "show");
792                         return 0;
793                 default:
794                         return 0;
795                 }
796         }
797
798         rc = lustre_lnet_show_net(network, detail, -1, &show_rc, &err_rc);
799
800         if (rc != LUSTRE_CFG_RC_NO_ERR)
801                 cYAML_print_tree2file(stderr, err_rc);
802         else if (show_rc)
803                 cYAML_print_tree(show_rc);
804
805         cYAML_free_tree(err_rc);
806         cYAML_free_tree(show_rc);
807
808         return rc;
809 }
810
811 static int jt_show_routing(int argc, char **argv)
812 {
813         struct cYAML *err_rc = NULL, *show_rc = NULL;
814         int rc;
815
816         if (handle_help(routing_cmds, "routing", "show", argc, argv) == 0)
817                 return 0;
818
819         rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc);
820
821         if (rc != LUSTRE_CFG_RC_NO_ERR)
822                 cYAML_print_tree2file(stderr, err_rc);
823         else if (show_rc)
824                 cYAML_print_tree(show_rc);
825
826         cYAML_free_tree(err_rc);
827         cYAML_free_tree(show_rc);
828
829         return rc;
830 }
831
832 static int jt_show_stats(int argc, char **argv)
833 {
834         int rc;
835         struct cYAML *show_rc = NULL, *err_rc = NULL;
836
837         if (handle_help(stats_cmds, "stats", "show", argc, argv) == 0)
838                 return 0;
839
840         rc = lustre_lnet_show_stats(-1, &show_rc, &err_rc);
841
842         if (rc != LUSTRE_CFG_RC_NO_ERR)
843                 cYAML_print_tree2file(stderr, err_rc);
844         else if (show_rc)
845                 cYAML_print_tree(show_rc);
846
847         cYAML_free_tree(err_rc);
848         cYAML_free_tree(show_rc);
849
850         return rc;
851 }
852
853 static int jt_show_global(int argc, char **argv)
854 {
855         int rc;
856         struct cYAML *show_rc = NULL, *err_rc = NULL;
857
858         if (handle_help(global_cmds, "global", "show", argc, argv) == 0)
859                 return 0;
860
861         rc = lustre_lnet_show_numa_range(-1, &show_rc, &err_rc);
862         if (rc != LUSTRE_CFG_RC_NO_ERR) {
863                 cYAML_print_tree2file(stderr, err_rc);
864                 goto out;
865         }
866
867         rc = lustre_lnet_show_max_intf(-1, &show_rc, &err_rc);
868         if (rc != LUSTRE_CFG_RC_NO_ERR) {
869                 cYAML_print_tree2file(stderr, err_rc);
870                 goto out;
871         }
872
873         if (show_rc)
874                 cYAML_print_tree(show_rc);
875
876 out:
877         cYAML_free_tree(err_rc);
878         cYAML_free_tree(show_rc);
879
880         return rc;
881 }
882
883 static inline int jt_lnet(int argc, char **argv)
884 {
885         if (argc < 2)
886                 return CMD_HELP;
887
888         if (argc == 2 &&
889             handle_help(lnet_cmds, "lnet", NULL, argc, argv) == 0)
890                 return 0;
891
892         return Parser_execarg(argc - 1, &argv[1], lnet_cmds);
893 }
894
895 static inline int jt_route(int argc, char **argv)
896 {
897         if (argc < 2)
898                 return CMD_HELP;
899
900         if (argc == 2 &&
901             handle_help(route_cmds, "route", NULL, argc, argv) == 0)
902                 return 0;
903
904         return Parser_execarg(argc - 1, &argv[1], route_cmds);
905 }
906
907 static inline int jt_net(int argc, char **argv)
908 {
909         if (argc < 2)
910                 return CMD_HELP;
911
912         if (argc == 2 &&
913             handle_help(net_cmds, "net", NULL, argc, argv) == 0)
914                 return 0;
915
916         return Parser_execarg(argc - 1, &argv[1], net_cmds);
917 }
918
919 static inline int jt_routing(int argc, char **argv)
920 {
921         if (argc < 2)
922                 return CMD_HELP;
923
924         if (argc == 2 &&
925             handle_help(routing_cmds, "routing", NULL, argc, argv) == 0)
926                 return 0;
927
928         return Parser_execarg(argc - 1, &argv[1], routing_cmds);
929 }
930
931 static inline int jt_stats(int argc, char **argv)
932 {
933         if (argc < 2)
934                 return CMD_HELP;
935
936         if (argc == 2 &&
937             handle_help(stats_cmds, "stats", NULL, argc, argv) == 0)
938                 return 0;
939
940         return Parser_execarg(argc - 1, &argv[1], stats_cmds);
941 }
942
943 static inline int jt_global(int argc, char **argv)
944 {
945         if (argc < 2)
946                 return CMD_HELP;
947
948         if (argc == 2 &&
949             handle_help(global_cmds, "global", NULL, argc, argv) == 0)
950                 return 0;
951
952         return Parser_execarg(argc - 1, &argv[1], global_cmds);
953 }
954
955 static inline int jt_peers(int argc, char **argv)
956 {
957         if (argc < 2)
958                 return CMD_HELP;
959
960         if (argc == 2 &&
961             handle_help(peer_cmds, "peer", NULL, argc, argv) == 0)
962                 return 0;
963
964         return Parser_execarg(argc - 1, &argv[1], peer_cmds);
965 }
966
967 static inline int jt_set(int argc, char **argv)
968 {
969         if (argc < 2)
970                 return CMD_HELP;
971
972         if (argc == 2  &&
973             handle_help(set_cmds, "set", NULL, argc, argv) == 0)
974                 return 0;
975
976         return Parser_execarg(argc - 1, &argv[1], set_cmds);
977 }
978
979 static int jt_import(int argc, char **argv)
980 {
981         char *file = NULL;
982         struct cYAML *err_rc = NULL;
983         struct cYAML *show_rc = NULL;
984         int rc = 0, opt, opt_found = 0;
985         char cmd = 'a';
986
987         const char *const short_options = "adsh";
988         static const struct option long_options[] = {
989                 { .name = "add",  .has_arg = no_argument, .val = 'a' },
990                 { .name = "del",  .has_arg = no_argument, .val = 'd' },
991                 { .name = "show", .has_arg = no_argument, .val = 's' },
992                 { .name = "help", .has_arg = no_argument, .val = 'h' },
993                 { .name = NULL } };
994
995         while ((opt = getopt_long(argc, argv, short_options,
996                                    long_options, NULL)) != -1) {
997                 opt_found = 1;
998                 switch (opt) {
999                 case 'a':
1000                 case 'd':
1001                 case 's':
1002                         cmd = opt;
1003                         break;
1004                 case 'h':
1005                         printf("import FILE\n"
1006                                "import < FILE : import a file\n"
1007                                "\t--add: add configuration\n"
1008                                "\t--del: delete configuration\n"
1009                                "\t--show: show configuration\n"
1010                                "\t--help: display this help\n"
1011                                "If no command option is given then --add"
1012                                " is assumed by default\n");
1013                         return 0;
1014                 default:
1015                         return 0;
1016                 }
1017         }
1018
1019         /* grab the file name if one exists */
1020         if (opt_found && argc == 3)
1021                 file = argv[2];
1022         else if (!opt_found && argc == 2)
1023                 file = argv[1];
1024
1025         switch (cmd) {
1026         case 'a':
1027                 rc = lustre_yaml_config(file, &err_rc);
1028                 break;
1029         case 'd':
1030                 rc = lustre_yaml_del(file, &err_rc);
1031                 break;
1032         case 's':
1033                 rc = lustre_yaml_show(file, &show_rc, &err_rc);
1034                 cYAML_print_tree(show_rc);
1035                 cYAML_free_tree(show_rc);
1036                 break;
1037         }
1038
1039         cYAML_print_tree2file(stderr, err_rc);
1040
1041         cYAML_free_tree(err_rc);
1042
1043         return rc;
1044 }
1045
1046 static int jt_export(int argc, char **argv)
1047 {
1048         struct cYAML *show_rc = NULL;
1049         struct cYAML *err_rc = NULL;
1050         int rc, opt;
1051         FILE *f = NULL;
1052
1053         const char *const short_options = "h";
1054         static const struct option long_options[] = {
1055                 { .name = "help", .has_arg = no_argument, .val = 'h' },
1056                 { .name = NULL } };
1057
1058         while ((opt = getopt_long(argc, argv, short_options,
1059                                    long_options, NULL)) != -1) {
1060                 switch (opt) {
1061                 case 'h':
1062                         printf("export FILE\n"
1063                                "export > FILE : export configuration\n"
1064                                "\t--help: display this help\n");
1065                         return 0;
1066                 default:
1067                         return 0;
1068                 }
1069         }
1070
1071         if (argc >= 2) {
1072                 f = fopen(argv[1], "w");
1073                 if (f == NULL)
1074                         return -1;
1075         } else
1076                 f = stdout;
1077
1078         rc = lustre_lnet_show_net(NULL, 1, -1, &show_rc, &err_rc);
1079         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1080                 cYAML_print_tree2file(stderr, err_rc);
1081                 cYAML_free_tree(err_rc);
1082         }
1083
1084         rc = lustre_lnet_show_route(NULL, NULL, -1, -1, 1, -1, &show_rc,
1085                                     &err_rc);
1086         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1087                 cYAML_print_tree2file(stderr, err_rc);
1088                 cYAML_free_tree(err_rc);
1089         }
1090
1091         rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc);
1092         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1093                 cYAML_print_tree2file(stderr, err_rc);
1094                 cYAML_free_tree(err_rc);
1095         }
1096
1097         rc = lustre_lnet_show_peer(NULL, 1, -1, &show_rc, &err_rc);
1098         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1099                 cYAML_print_tree2file(stderr, err_rc);
1100                 cYAML_free_tree(err_rc);
1101         }
1102
1103         rc = lustre_lnet_show_numa_range(-1, &show_rc, &err_rc);
1104         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1105                 cYAML_print_tree2file(stderr, err_rc);
1106                 cYAML_free_tree(err_rc);
1107         }
1108
1109         rc = lustre_lnet_show_max_intf(-1, &show_rc, &err_rc);
1110         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1111                 cYAML_print_tree2file(stderr, err_rc);
1112                 cYAML_free_tree(err_rc);
1113         }
1114
1115         if (show_rc != NULL) {
1116                 cYAML_print_tree2file(f, show_rc);
1117                 cYAML_free_tree(show_rc);
1118         }
1119
1120         if (argc >= 2)
1121                 fclose(f);
1122
1123         return 0;
1124 }
1125
1126 static int jt_add_peer_nid(int argc, char **argv)
1127 {
1128         char *prim_nid = NULL;
1129         char **nids = NULL, **nids2 = NULL;
1130         int size = 0;
1131         struct cYAML *err_rc = NULL;
1132         int rc = LUSTRE_CFG_RC_NO_ERR, opt, i;
1133         bool non_mr = false;
1134
1135         const char *const short_options = "k:n:mh";
1136         const struct option long_options[] = {
1137                 { "prim_nid", 1, NULL, 'k' },
1138                 { "nid", 1, NULL, 'n' },
1139                 { "non_mr", 0, NULL, 'm'},
1140                 { "help", 0, NULL, 'h' },
1141                 { NULL, 0, NULL, 0 },
1142         };
1143
1144         while ((opt = getopt_long(argc, argv, short_options,
1145                                   long_options, NULL)) != -1) {
1146                 switch (opt) {
1147                 case 'k':
1148                         prim_nid = optarg;
1149                         break;
1150                 case 'n':
1151                         size = lustre_lnet_parse_nids(optarg, nids, size,
1152                                                       &nids2);
1153                         if (nids2 == NULL)
1154                                 goto failed;
1155                         nids = nids2;
1156                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1157                         break;
1158                 case 'm':
1159                         non_mr = true;
1160                         break;
1161                 case 'h':
1162                         print_help(peer_cmds, "peer", "add");
1163                         return 0;
1164                 default:
1165                         return 0;
1166                 }
1167         }
1168
1169         rc = lustre_lnet_config_peer_nid(prim_nid, nids, size,
1170                                          !non_mr, -1, &err_rc);
1171
1172 failed:
1173         if (nids) {
1174                 /* free the array of nids */
1175                 for (i = 0; i < size; i++)
1176                         free(nids[i]);
1177                 free(nids);
1178         }
1179
1180         if (rc != LUSTRE_CFG_RC_NO_ERR)
1181                 cYAML_print_tree2file(stderr, err_rc);
1182
1183         cYAML_free_tree(err_rc);
1184
1185         return rc;
1186 }
1187
1188 static int jt_del_peer_nid(int argc, char **argv)
1189 {
1190         char *prim_nid = NULL;
1191         char **nids = NULL, **nids2 = NULL;
1192         struct cYAML *err_rc = NULL;
1193         int rc = LUSTRE_CFG_RC_NO_ERR, opt, i, size = 0;
1194
1195         const char *const short_options = "k:n:h";
1196         const struct option long_options[] = {
1197                 { "prim_nid", 1, NULL, 'k' },
1198                 { "nid", 1, NULL, 'n' },
1199                 { "help", 0, NULL, 'h' },
1200                 { NULL, 0, NULL, 0 },
1201         };
1202
1203         while ((opt = getopt_long(argc, argv, short_options,
1204                                   long_options, NULL)) != -1) {
1205                 switch (opt) {
1206                 case 'k':
1207                         prim_nid = optarg;
1208                         break;
1209                 case 'n':
1210                         size = lustre_lnet_parse_nids(optarg, nids, size,
1211                                                       &nids2);
1212                         if (nids2 == NULL)
1213                                 goto failed;
1214                         nids = nids2;
1215                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1216                         break;
1217                 case 'h':
1218                         print_help(peer_cmds, "peer", "del");
1219                         return 0;
1220                 default:
1221                         return 0;
1222                 }
1223         }
1224
1225         rc = lustre_lnet_del_peer_nid(prim_nid, nids, size, -1, &err_rc);
1226
1227 failed:
1228         if (nids) {
1229                 for (i = 0; i < size; i++)
1230                         free(nids[i]);
1231                 free(nids);
1232         }
1233
1234         if (rc != LUSTRE_CFG_RC_NO_ERR)
1235                 cYAML_print_tree2file(stderr, err_rc);
1236
1237         cYAML_free_tree(err_rc);
1238
1239         return rc;
1240 }
1241
1242 static int jt_show_peer(int argc, char **argv)
1243 {
1244         char *nid = NULL;
1245         int rc, opt;
1246         struct cYAML *err_rc = NULL, *show_rc = NULL;
1247         int detail = 0;
1248
1249         const char *const short_options = "n:vh";
1250         const struct option long_options[] = {
1251                 { "nid", 1, NULL, 'n' },
1252                 { "verbose", 0, NULL, 'v' },
1253                 { "help", 0, NULL, 'h' },
1254                 { NULL, 0, NULL, 0 },
1255         };
1256
1257         while ((opt = getopt_long(argc, argv, short_options,
1258                                   long_options, NULL)) != -1) {
1259                 switch (opt) {
1260                 case 'n':
1261                         nid = optarg;
1262                         break;
1263                 case 'v':
1264                         detail = 1;
1265                         break;
1266                 case 'h':
1267                         print_help(peer_cmds, "peer", "show");
1268                         return 0;
1269                 default:
1270                         return 0;
1271                 }
1272         }
1273
1274         rc = lustre_lnet_show_peer(nid, detail, -1, &show_rc, &err_rc);
1275
1276         if (rc != LUSTRE_CFG_RC_NO_ERR)
1277                 cYAML_print_tree2file(stderr, err_rc);
1278         else if (show_rc)
1279                 cYAML_print_tree(show_rc);
1280
1281         cYAML_free_tree(err_rc);
1282         cYAML_free_tree(show_rc);
1283
1284         return rc;
1285 }
1286
1287 command_t list[] = {
1288         {"lnet", jt_lnet, 0, "lnet {configure | unconfigure} [--all]"},
1289         {"route", jt_route, 0, "route {add | del | show | help}"},
1290         {"net", jt_net, 0, "net {add | del | show | help}"},
1291         {"routing", jt_routing, 0, "routing {show | help}"},
1292         {"set", jt_set, 0, "set {tiny_buffers | small_buffers | large_buffers"
1293                            " | routing | numa_range | max_interfaces}"},
1294         {"import", jt_import, 0, "import {--add | --del | --show | "
1295                                  "--help} FILE.yaml"},
1296         {"export", jt_export, 0, "export {--help} FILE.yaml"},
1297         {"stats", jt_stats, 0, "stats {show | help}"},
1298         {"global", jt_global, 0, "global {show | help}"},
1299         {"peer", jt_peers, 0, "peer {add | del | show | help}"},
1300         {"help", Parser_help, 0, "help"},
1301         {"exit", Parser_quit, 0, "quit"},
1302         {"quit", Parser_quit, 0, "quit"},
1303         {"--list-commands", lnetctl_list_commands, 0, "list commands"},
1304         { 0, 0, 0, NULL }
1305 };
1306
1307 static int lnetctl_list_commands(int argc, char **argv)
1308 {
1309         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
1310
1311         Parser_list_commands(list, buffer, sizeof(buffer), NULL, 0, 4);
1312
1313         return 0;
1314 }
1315
1316 int main(int argc, char **argv)
1317 {
1318         int rc = 0;
1319         struct cYAML *err_rc = NULL;
1320
1321         rc = lustre_lnet_config_lib_init();
1322         if (rc < 0) {
1323                 cYAML_build_error(-1, -1, "lnetctl", "startup",
1324                                   "cannot register LNet device", &err_rc);
1325                 cYAML_print_tree2file(stderr, err_rc);
1326                 return rc;
1327         }
1328
1329         Parser_init("lnetctl > ", list);
1330         if (argc > 1) {
1331                 rc = Parser_execarg(argc - 1, &argv[1], list);
1332                 goto errorout;
1333         }
1334
1335         Parser_commands();
1336
1337 errorout:
1338         return rc;
1339 }