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