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