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