Whamcloud - gitweb
LU-7734 lnet: Fix setting numa range
[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         const struct option long_options[] = {
192                 { "help", 0, NULL, 'h' },
193                 { NULL, 0, NULL, 0 },
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         const struct option long_options[] = {
360                 { "all", 0, NULL, 'a' },
361                 { "help", 0, NULL, 'h' },
362                 { NULL, 0, NULL, 0 },
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         const struct option long_options[] = {
416                 { "net", 1, NULL, 'n' },
417                 { "gateway", 1, NULL, 'g' },
418                 { "hop-count", 1, NULL, 'c' },
419                 { "priority", 1, NULL, 'p' },
420                 { "help", 0, NULL, 'h' },
421                 { NULL, 0, NULL, 0 },
422         };
423
424         while ((opt = getopt_long(argc, argv, short_options,
425                                    long_options, NULL)) != -1) {
426                 switch (opt) {
427                 case 'n':
428                         network = optarg;
429                         break;
430                 case 'g':
431                         gateway = optarg;
432                         break;
433                 case 'c':
434                         rc = parse_long(optarg, &hop);
435                         if (rc != 0) {
436                                 /* ignore option */
437                                 hop = -1;
438                                 continue;
439                         }
440                         break;
441                 case 'p':
442                         rc = parse_long(optarg, &prio);
443                         if (rc != 0) {
444                                 /* ingore option */
445                                 prio = -1;
446                                 continue;
447                         }
448                         break;
449                 case 'h':
450                         print_help(route_cmds, "route", "add");
451                         return 0;
452                 default:
453                         return 0;
454                 }
455         }
456
457         rc = lustre_lnet_config_route(network, gateway, hop, prio, -1, &err_rc);
458
459         if (rc != LUSTRE_CFG_RC_NO_ERR)
460                 cYAML_print_tree2file(stderr, err_rc);
461
462         cYAML_free_tree(err_rc);
463
464         return rc;
465 }
466
467 static int jt_add_ni(int argc, char **argv)
468 {
469         char *ip2net = NULL;
470         long int pto = -1, pc = -1, pbc = -1, cre = -1;
471         struct cYAML *err_rc = NULL;
472         int rc, opt, cpt_rc = -1;
473         struct lnet_dlc_network_descr nw_descr;
474         struct cfs_expr_list *global_cpts = NULL;
475         struct lnet_ioctl_config_lnd_tunables tunables;
476         bool found = false;
477
478         memset(&tunables, 0, sizeof(tunables));
479         lustre_lnet_init_nw_descr(&nw_descr);
480
481         const char *const short_options = "n:i:p:t:c:b:r:s:h";
482         const struct option long_options[] = {
483                 { "net", 1, NULL, 'n' },
484                 { "if", 1, NULL, 'i' },
485                 { "ip2net", 1, NULL, 'p' },
486                 { "peer-timeout", 1, NULL, 't' },
487                 { "peer-credits", 1, NULL, 'c' },
488                 { "peer-buffer-credits", 1, NULL, 'b' },
489                 { "credits", 1, NULL, 'r' },
490                 { "cpt", 1, NULL, 's' },
491                 { "help", 0, NULL, 'h' },
492                 { NULL, 0, NULL, 0 },
493         };
494
495         while ((opt = getopt_long(argc, argv, short_options,
496                                    long_options, NULL)) != -1) {
497                 switch (opt) {
498                 case 'n':
499                         nw_descr.nw_id = libcfs_str2net(optarg);
500                         break;
501                 case 'i':
502                         rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
503                         if (rc != 0) {
504                                 cYAML_build_error(-1, -1, "ni", "add",
505                                                 "bad interface list",
506                                                 &err_rc);
507                                 goto failed;
508                         }
509                         break;
510                 case 'p':
511                         ip2net = optarg;
512                         break;
513                 case 't':
514                         rc = parse_long(optarg, &pto);
515                         if (rc != 0) {
516                                 /* ignore option */
517                                 pto = -1;
518                                 continue;
519                         }
520                         break;
521                 case 'c':
522                         rc = parse_long(optarg, &pc);
523                         if (rc != 0) {
524                                 /* ignore option */
525                                 pc = -1;
526                                 continue;
527                         }
528                         break;
529                 case 'b':
530                         rc = parse_long(optarg, &pbc);
531                         if (rc != 0) {
532                                 /* ignore option */
533                                 pbc = -1;
534                                 continue;
535                         }
536                         break;
537                 case 'r':
538                         rc = parse_long(optarg, &cre);
539                         if (rc != 0) {
540                                 /* ignore option */
541                                 cre = -1;
542                                 continue;
543                         }
544                         break;
545                 case 's':
546                         cpt_rc = cfs_expr_list_parse(optarg,
547                                                      strlen(optarg), 0,
548                                                      UINT_MAX, &global_cpts);
549                         break;
550                 case 'h':
551                         print_help(net_cmds, "net", "add");
552                         return 0;
553                 default:
554                         return 0;
555                 }
556         }
557
558         if (pto > 0 || pc > 0 || pbc > 0 || cre > 0) {
559                 tunables.lt_cmn.lct_peer_timeout = pto;
560                 tunables.lt_cmn.lct_peer_tx_credits = pc;
561                 tunables.lt_cmn.lct_peer_rtr_credits = pbc;
562                 tunables.lt_cmn.lct_max_tx_credits = cre;
563                 found = true;
564         }
565
566         rc = lustre_lnet_config_ni(&nw_descr,
567                                    (cpt_rc == 0) ? global_cpts: NULL,
568                                    ip2net, (found) ? &tunables : NULL,
569                                    -1, &err_rc);
570
571         if (global_cpts != NULL)
572                 cfs_expr_list_free(global_cpts);
573
574 failed:
575         if (rc != LUSTRE_CFG_RC_NO_ERR)
576                 cYAML_print_tree2file(stderr, err_rc);
577
578         cYAML_free_tree(err_rc);
579
580         return rc;
581 }
582
583 static int jt_del_route(int argc, char **argv)
584 {
585         char *network = NULL, *gateway = NULL;
586         struct cYAML *err_rc = NULL;
587         int rc, opt;
588
589         const char *const short_options = "n:g:h";
590         const struct option long_options[] = {
591                 { "net", 1, NULL, 'n' },
592                 { "gateway", 1, NULL, 'g' },
593                 { "help", 0, NULL, 'h' },
594                 { NULL, 0, NULL, 0 },
595         };
596
597         while ((opt = getopt_long(argc, argv, short_options,
598                                    long_options, NULL)) != -1) {
599                 switch (opt) {
600                 case 'n':
601                         network = optarg;
602                         break;
603                 case 'g':
604                         gateway = optarg;
605                         break;
606                 case 'h':
607                         print_help(route_cmds, "route", "del");
608                         return 0;
609                 default:
610                         return 0;
611                 }
612         }
613
614         rc = lustre_lnet_del_route(network, gateway, -1, &err_rc);
615
616         if (rc != LUSTRE_CFG_RC_NO_ERR)
617                 cYAML_print_tree2file(stderr, err_rc);
618
619         cYAML_free_tree(err_rc);
620
621         return rc;
622 }
623
624 static int jt_del_ni(int argc, char **argv)
625 {
626         struct cYAML *err_rc = NULL;
627         int rc, opt;
628         struct lnet_dlc_network_descr nw_descr;
629
630         lustre_lnet_init_nw_descr(&nw_descr);
631
632         const char *const short_options = "n:i:h";
633         const struct option long_options[] = {
634                 { "net", 1, NULL, 'n' },
635                 { "if", 1, NULL, 'i' },
636                 { "help", 0, NULL, 'h' },
637                 { NULL, 0, NULL, 0 },
638         };
639
640         while ((opt = getopt_long(argc, argv, short_options,
641                                    long_options, NULL)) != -1) {
642                 switch (opt) {
643                 case 'n':
644                         nw_descr.nw_id = libcfs_str2net(optarg);
645                         break;
646                 case 'i':
647                         rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
648                         if (rc != 0) {
649                                 cYAML_build_error(-1, -1, "ni", "add",
650                                                 "bad interface list",
651                                                 &err_rc);
652                                 goto out;
653                         }
654                         break;
655                 case 'h':
656                         print_help(net_cmds, "net", "del");
657                         return 0;
658                 default:
659                         return 0;
660                 }
661         }
662
663         rc = lustre_lnet_del_ni(&nw_descr, -1, &err_rc);
664
665 out:
666         if (rc != LUSTRE_CFG_RC_NO_ERR)
667                 cYAML_print_tree2file(stderr, err_rc);
668
669         cYAML_free_tree(err_rc);
670
671         return rc;
672 }
673
674 static int jt_show_route(int argc, char **argv)
675 {
676         char *network = NULL, *gateway = NULL;
677         long int hop = -1, prio = -1;
678         int detail = 0, rc, opt;
679         struct cYAML *err_rc = NULL, *show_rc = NULL;
680
681         const char *const short_options = "n:g:h:p:vh";
682         const struct option long_options[] = {
683                 { "net", 1, NULL, 'n' },
684                 { "gateway", 1, NULL, 'g' },
685                 { "hop-count", 1, NULL, 'c' },
686                 { "priority", 1, NULL, 'p' },
687                 { "verbose", 0, NULL, 'v' },
688                 { "help", 0, NULL, 'h' },
689                 { NULL, 0, NULL, 0 },
690         };
691
692         while ((opt = getopt_long(argc, argv, short_options,
693                                    long_options, NULL)) != -1) {
694                 switch (opt) {
695                 case 'n':
696                         network = optarg;
697                         break;
698                 case 'g':
699                         gateway = optarg;
700                         break;
701                 case 'c':
702                         rc = parse_long(optarg, &hop);
703                         if (rc != 0) {
704                                 /* ignore option */
705                                 hop = -1;
706                                 continue;
707                         }
708                         break;
709                 case 'p':
710                         rc = parse_long(optarg, &prio);
711                         if (rc != 0) {
712                                 /* ignore option */
713                                 prio = -1;
714                                 continue;
715                         }
716                         break;
717                 case 'v':
718                         detail = 1;
719                         break;
720                 case 'h':
721                         print_help(route_cmds, "route", "show");
722                         return 0;
723                 default:
724                         return 0;
725                 }
726         }
727
728         rc = lustre_lnet_show_route(network, gateway, hop, prio, detail, -1,
729                                     &show_rc, &err_rc);
730
731         if (rc != LUSTRE_CFG_RC_NO_ERR)
732                 cYAML_print_tree2file(stderr, err_rc);
733         else if (show_rc)
734                 cYAML_print_tree(show_rc);
735
736         cYAML_free_tree(err_rc);
737         cYAML_free_tree(show_rc);
738
739         return rc;
740 }
741
742 static int jt_show_net(int argc, char **argv)
743 {
744         char *network = NULL;
745         int detail = 0, rc, opt;
746         struct cYAML *err_rc = NULL, *show_rc = NULL;
747
748         const char *const short_options = "n:vh";
749         const struct option long_options[] = {
750                 { "net", 1, NULL, 'n' },
751                 { "verbose", 0, NULL, 'v' },
752                 { "help", 0, NULL, 'h' },
753                 { NULL, 0, NULL, 0 },
754         };
755
756         while ((opt = getopt_long(argc, argv, short_options,
757                                    long_options, NULL)) != -1) {
758                 switch (opt) {
759                 case 'n':
760                         network = optarg;
761                         break;
762                 case 'v':
763                         detail = 1;
764                         break;
765                 case 'h':
766                         print_help(net_cmds, "net", "show");
767                         return 0;
768                 default:
769                         return 0;
770                 }
771         }
772
773         rc = lustre_lnet_show_net(network, detail, -1, &show_rc, &err_rc);
774
775         if (rc != LUSTRE_CFG_RC_NO_ERR)
776                 cYAML_print_tree2file(stderr, err_rc);
777         else if (show_rc)
778                 cYAML_print_tree(show_rc);
779
780         cYAML_free_tree(err_rc);
781         cYAML_free_tree(show_rc);
782
783         return rc;
784 }
785
786 static int jt_show_routing(int argc, char **argv)
787 {
788         struct cYAML *err_rc = NULL, *show_rc = NULL;
789         int rc;
790
791         if (handle_help(routing_cmds, "routing", "show", argc, argv) == 0)
792                 return 0;
793
794         rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc);
795
796         if (rc != LUSTRE_CFG_RC_NO_ERR)
797                 cYAML_print_tree2file(stderr, err_rc);
798         else if (show_rc)
799                 cYAML_print_tree(show_rc);
800
801         cYAML_free_tree(err_rc);
802         cYAML_free_tree(show_rc);
803
804         return rc;
805 }
806
807 static int jt_show_stats(int argc, char **argv)
808 {
809         int rc;
810         struct cYAML *show_rc = NULL, *err_rc = NULL;
811
812         if (handle_help(stats_cmds, "stats", "show", argc, argv) == 0)
813                 return 0;
814
815         rc = lustre_lnet_show_stats(-1, &show_rc, &err_rc);
816
817         if (rc != LUSTRE_CFG_RC_NO_ERR)
818                 cYAML_print_tree2file(stderr, err_rc);
819         else if (show_rc)
820                 cYAML_print_tree(show_rc);
821
822         cYAML_free_tree(err_rc);
823         cYAML_free_tree(show_rc);
824
825         return rc;
826 }
827
828 static int jt_show_numa(int argc, char **argv)
829 {
830         int rc;
831         struct cYAML *show_rc = NULL, *err_rc = NULL;
832
833         if (handle_help(numa_cmds, "numa", "show", argc, argv) == 0)
834                 return 0;
835
836         rc = lustre_lnet_show_numa_range(-1, &show_rc, &err_rc);
837
838         if (rc != LUSTRE_CFG_RC_NO_ERR)
839                 cYAML_print_tree2file(stderr, err_rc);
840         else if (show_rc)
841                 cYAML_print_tree(show_rc);
842
843         cYAML_free_tree(err_rc);
844         cYAML_free_tree(show_rc);
845
846         return rc;
847 }
848
849 static inline int jt_lnet(int argc, char **argv)
850 {
851         if (argc < 2)
852                 return CMD_HELP;
853
854         if (argc == 2 &&
855             handle_help(lnet_cmds, "lnet", NULL, argc, argv) == 0)
856                 return 0;
857
858         return Parser_execarg(argc - 1, &argv[1], lnet_cmds);
859 }
860
861 static inline int jt_route(int argc, char **argv)
862 {
863         if (argc < 2)
864                 return CMD_HELP;
865
866         if (argc == 2 &&
867             handle_help(route_cmds, "route", NULL, argc, argv) == 0)
868                 return 0;
869
870         return Parser_execarg(argc - 1, &argv[1], route_cmds);
871 }
872
873 static inline int jt_net(int argc, char **argv)
874 {
875         if (argc < 2)
876                 return CMD_HELP;
877
878         if (argc == 2 &&
879             handle_help(net_cmds, "net", NULL, argc, argv) == 0)
880                 return 0;
881
882         return Parser_execarg(argc - 1, &argv[1], net_cmds);
883 }
884
885 static inline int jt_routing(int argc, char **argv)
886 {
887         if (argc < 2)
888                 return CMD_HELP;
889
890         if (argc == 2 &&
891             handle_help(routing_cmds, "routing", NULL, argc, argv) == 0)
892                 return 0;
893
894         return Parser_execarg(argc - 1, &argv[1], routing_cmds);
895 }
896
897 static inline int jt_stats(int argc, char **argv)
898 {
899         if (argc < 2)
900                 return CMD_HELP;
901
902         if (argc == 2 &&
903             handle_help(stats_cmds, "stats", NULL, argc, argv) == 0)
904                 return 0;
905
906         return Parser_execarg(argc - 1, &argv[1], stats_cmds);
907 }
908
909 static inline int jt_numa(int argc, char **argv)
910 {
911         if (argc < 2)
912                 return CMD_HELP;
913
914         if (argc == 2 &&
915             handle_help(numa_cmds, "numa", NULL, argc, argv) == 0)
916                 return 0;
917
918         return Parser_execarg(argc - 1, &argv[1], numa_cmds);
919 }
920
921 static inline int jt_peers(int argc, char **argv)
922 {
923         if (argc < 2)
924                 return CMD_HELP;
925
926         if (argc == 2 &&
927             handle_help(peer_cmds, "peer", NULL, argc, argv) == 0)
928                 return 0;
929
930         return Parser_execarg(argc - 1, &argv[1], peer_cmds);
931 }
932
933 static inline int jt_set(int argc, char **argv)
934 {
935         if (argc < 2)
936                 return CMD_HELP;
937
938         if (argc == 2  &&
939             handle_help(set_cmds, "set", NULL, argc, argv) == 0)
940                 return 0;
941
942         return Parser_execarg(argc - 1, &argv[1], set_cmds);
943 }
944
945 static int jt_import(int argc, char **argv)
946 {
947         char *file = NULL;
948         struct cYAML *err_rc = NULL;
949         struct cYAML *show_rc = NULL;
950         int rc = 0, opt, opt_found = 0;
951         char cmd = 'a';
952
953         const char *const short_options = "adsh";
954         const struct option long_options[] = {
955                 { "add", 0, NULL, 'a' },
956                 { "del", 0, NULL, 'd' },
957                 { "show", 0, NULL, 's' },
958                 { "help", 0, NULL, 'h' },
959                 { NULL, 0, NULL, 0 },
960         };
961
962         while ((opt = getopt_long(argc, argv, short_options,
963                                    long_options, NULL)) != -1) {
964                 opt_found = 1;
965                 switch (opt) {
966                 case 'a':
967                 case 'd':
968                 case 's':
969                         cmd = opt;
970                         break;
971                 case 'h':
972                         printf("import FILE\n"
973                                "import < FILE : import a file\n"
974                                "\t--add: add configuration\n"
975                                "\t--del: delete configuration\n"
976                                "\t--show: show configuration\n"
977                                "\t--help: display this help\n"
978                                "If no command option is given then --add"
979                                " is assumed by default\n");
980                         return 0;
981                 default:
982                         return 0;
983                 }
984         }
985
986         /* grab the file name if one exists */
987         if (opt_found && argc == 3)
988                 file = argv[2];
989         else if (!opt_found && argc == 2)
990                 file = argv[1];
991
992         switch (cmd) {
993         case 'a':
994                 rc = lustre_yaml_config(file, &err_rc);
995                 break;
996         case 'd':
997                 rc = lustre_yaml_del(file, &err_rc);
998                 break;
999         case 's':
1000                 rc = lustre_yaml_show(file, &show_rc, &err_rc);
1001                 cYAML_print_tree(show_rc);
1002                 cYAML_free_tree(show_rc);
1003                 break;
1004         }
1005
1006         cYAML_print_tree2file(stderr, err_rc);
1007
1008         cYAML_free_tree(err_rc);
1009
1010         return rc;
1011 }
1012
1013 static int jt_export(int argc, char **argv)
1014 {
1015         struct cYAML *show_rc = NULL;
1016         struct cYAML *err_rc = NULL;
1017         int rc, opt;
1018         FILE *f = NULL;
1019
1020         const char *const short_options = "h";
1021         const struct option long_options[] = {
1022                 { "help", 0, NULL, 'h' },
1023                 { NULL, 0, NULL, 0 },
1024         };
1025
1026         while ((opt = getopt_long(argc, argv, short_options,
1027                                    long_options, NULL)) != -1) {
1028                 switch (opt) {
1029                 case 'h':
1030                         printf("export FILE\n"
1031                                "export > FILE : export configuration\n"
1032                                "\t--help: display this help\n");
1033                         return 0;
1034                 default:
1035                         return 0;
1036                 }
1037         }
1038
1039         if (argc >= 2) {
1040                 f = fopen(argv[1], "w");
1041                 if (f == NULL)
1042                         return -1;
1043         } else
1044                 f = stdout;
1045
1046         rc = lustre_lnet_show_net(NULL, 1, -1, &show_rc, &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_route(NULL, NULL, -1, -1, 1, -1, &show_rc,
1053                                     &err_rc);
1054         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1055                 cYAML_print_tree2file(stderr, err_rc);
1056                 cYAML_free_tree(err_rc);
1057         }
1058
1059         rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc);
1060         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1061                 cYAML_print_tree2file(stderr, err_rc);
1062                 cYAML_free_tree(err_rc);
1063         }
1064
1065         rc = lustre_lnet_show_peer(NULL, 1, -1, &show_rc, &err_rc);
1066         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1067                 cYAML_print_tree2file(stderr, err_rc);
1068                 cYAML_free_tree(err_rc);
1069         }
1070
1071         rc = lustre_lnet_show_numa_range(-1, &show_rc, &err_rc);
1072         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1073                 cYAML_print_tree2file(stderr, err_rc);
1074                 cYAML_free_tree(err_rc);
1075         }
1076
1077         if (show_rc != NULL) {
1078                 cYAML_print_tree2file(f, show_rc);
1079                 cYAML_free_tree(show_rc);
1080         }
1081
1082         if (argc >= 2)
1083                 fclose(f);
1084
1085         return 0;
1086 }
1087
1088 static int jt_add_peer_nid(int argc, char **argv)
1089 {
1090         char *prim_nid = NULL;
1091         char **nids = NULL, **nids2 = NULL;
1092         int size = 0;
1093         struct cYAML *err_rc = NULL;
1094         int rc = LUSTRE_CFG_RC_NO_ERR, opt, i;
1095         bool non_mr = false;
1096
1097         const char *const short_options = "k:n:mh";
1098         const struct option long_options[] = {
1099                 { "prim_nid", 1, NULL, 'k' },
1100                 { "nid", 1, NULL, 'n' },
1101                 { "non_mr", 0, NULL, 'm'},
1102                 { "help", 0, NULL, 'h' },
1103                 { NULL, 0, NULL, 0 },
1104         };
1105
1106         while ((opt = getopt_long(argc, argv, short_options,
1107                                   long_options, NULL)) != -1) {
1108                 switch (opt) {
1109                 case 'k':
1110                         prim_nid = optarg;
1111                         break;
1112                 case 'n':
1113                         size = lustre_lnet_parse_nids(optarg, nids, size,
1114                                                       &nids2);
1115                         if (nids2 == NULL)
1116                                 goto failed;
1117                         nids = nids2;
1118                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1119                         break;
1120                 case 'm':
1121                         non_mr = true;
1122                         break;
1123                 case 'h':
1124                         print_help(peer_cmds, "peer", "add");
1125                         return 0;
1126                 default:
1127                         return 0;
1128                 }
1129         }
1130
1131         rc = lustre_lnet_config_peer_nid(prim_nid, nids, size,
1132                                          !non_mr, -1, &err_rc);
1133
1134 failed:
1135         for (i = 0; i < size; i++)
1136                 free(nids[i]);
1137         free(nids);
1138
1139         if (rc != LUSTRE_CFG_RC_NO_ERR)
1140                 cYAML_print_tree2file(stderr, err_rc);
1141
1142         cYAML_free_tree(err_rc);
1143
1144         return rc;
1145 }
1146
1147 static int jt_del_peer_nid(int argc, char **argv)
1148 {
1149         char *prim_nid = NULL;
1150         char **nids = NULL, **nids2 = NULL;
1151         struct cYAML *err_rc = NULL;
1152         int rc = LUSTRE_CFG_RC_NO_ERR, opt, i, size = 0;
1153
1154         const char *const short_options = "k:n:h";
1155         const struct option long_options[] = {
1156                 { "prim_nid", 1, NULL, 'k' },
1157                 { "nid", 1, NULL, 'n' },
1158                 { "help", 0, NULL, 'h' },
1159                 { NULL, 0, NULL, 0 },
1160         };
1161
1162         while ((opt = getopt_long(argc, argv, short_options,
1163                                   long_options, NULL)) != -1) {
1164                 switch (opt) {
1165                 case 'k':
1166                         prim_nid = optarg;
1167                         break;
1168                 case 'n':
1169                         size = lustre_lnet_parse_nids(optarg, nids, size,
1170                                                       &nids2);
1171                         if (nids2 == NULL)
1172                                 goto failed;
1173                         nids = nids2;
1174                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1175                         break;
1176                 case 'h':
1177                         print_help(peer_cmds, "peer", "del");
1178                         return 0;
1179                 default:
1180                         return 0;
1181                 }
1182         }
1183
1184         rc = lustre_lnet_del_peer_nid(prim_nid, nids, size, -1, &err_rc);
1185
1186 failed:
1187         for (i = 0; i < size; i++)
1188                 free(nids[i]);
1189         free(nids);
1190
1191         if (rc != LUSTRE_CFG_RC_NO_ERR)
1192                 cYAML_print_tree2file(stderr, err_rc);
1193
1194         cYAML_free_tree(err_rc);
1195
1196         return rc;
1197 }
1198
1199 static int jt_show_peer(int argc, char **argv)
1200 {
1201         char *nid = NULL;
1202         int rc, opt;
1203         struct cYAML *err_rc = NULL, *show_rc = NULL;
1204         int detail = 0;
1205
1206         const char *const short_options = "n:vh";
1207         const struct option long_options[] = {
1208                 { "nid", 1, NULL, 'n' },
1209                 { "verbose", 0, NULL, 'v' },
1210                 { "help", 0, NULL, 'h' },
1211                 { NULL, 0, NULL, 0 },
1212         };
1213
1214         while ((opt = getopt_long(argc, argv, short_options,
1215                                   long_options, NULL)) != -1) {
1216                 switch (opt) {
1217                 case 'n':
1218                         nid = optarg;
1219                         break;
1220                 case 'v':
1221                         detail = 1;
1222                         break;
1223                 case 'h':
1224                         print_help(peer_cmds, "peer", "show");
1225                         return 0;
1226                 default:
1227                         return 0;
1228                 }
1229         }
1230
1231         rc = lustre_lnet_show_peer(nid, detail, -1, &show_rc, &err_rc);
1232
1233         if (rc != LUSTRE_CFG_RC_NO_ERR)
1234                 cYAML_print_tree2file(stderr, err_rc);
1235         else if (show_rc)
1236                 cYAML_print_tree(show_rc);
1237
1238         cYAML_free_tree(err_rc);
1239         cYAML_free_tree(show_rc);
1240
1241         return rc;
1242 }
1243
1244 command_t list[] = {
1245         {"lnet", jt_lnet, 0, "lnet {configure | unconfigure} [--all]"},
1246         {"route", jt_route, 0, "route {add | del | show | help}"},
1247         {"net", jt_net, 0, "net {add | del | show | help}"},
1248         {"routing", jt_routing, 0, "routing {show | help}"},
1249         {"set", jt_set, 0, "set {tiny_buffers | small_buffers | large_buffers"
1250                            " | routing}"},
1251         {"import", jt_import, 0, "import {--add | --del | --show | "
1252                                  "--help} FILE.yaml"},
1253         {"export", jt_export, 0, "export {--help} FILE.yaml"},
1254         {"stats", jt_stats, 0, "stats {show | help}"},
1255         {"numa", jt_numa, 0, "numa {show | help}"},
1256         {"peer", jt_peers, 0, "peer {add | del | show | help}"},
1257         {"help", Parser_help, 0, "help"},
1258         {"exit", Parser_quit, 0, "quit"},
1259         {"quit", Parser_quit, 0, "quit"},
1260         { 0, 0, 0, NULL }
1261 };
1262
1263 int main(int argc, char **argv)
1264 {
1265         int rc = 0;
1266         struct cYAML *err_rc = NULL;
1267
1268         rc = lustre_lnet_config_lib_init();
1269         if (rc < 0) {
1270                 cYAML_build_error(-1, -1, "lnetctl", "startup",
1271                                   "cannot register LNet device", &err_rc);
1272                 cYAML_print_tree2file(stderr, err_rc);
1273                 return rc;
1274         }
1275
1276         Parser_init("lnetctl > ", list);
1277         if (argc > 1) {
1278                 rc = Parser_execarg(argc - 1, &argv[1], list);
1279                 goto errorout;
1280         }
1281
1282         Parser_commands();
1283
1284 errorout:
1285         return rc;
1286 }