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