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