blob: 5a0f7ec3c103807269910ca7a5190e809fe99793 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * cli.c: command line interface
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vlib/vlib.h>
Damjan Marioneccf5092016-11-18 16:59:24 +010041#include <vppinfra/cpu.h>
Damjan Marione5ef1d72017-03-02 12:33:48 +010042#include <unistd.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070043
44/* Root of all show commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040045/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070046VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
47 .path = "show",
48 .short_help = "Show commands",
49};
Dave Barach9b8ffd92016-07-08 08:13:45 -040050/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
52/* Root of all clear commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040053/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070054VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
55 .path = "clear",
56 .short_help = "Clear commands",
57};
Dave Barach9b8ffd92016-07-08 08:13:45 -040058/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
60/* Root of all set commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040061/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070062VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
63 .path = "set",
64 .short_help = "Set commands",
65};
Dave Barach9b8ffd92016-07-08 08:13:45 -040066/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070067
68/* Root of all test commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040069/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070070VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
71 .path = "test",
72 .short_help = "Test commands",
73};
Dave Barach9b8ffd92016-07-08 08:13:45 -040074/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070075
76/* Returns bitmap of commands which match key. */
77static uword *
78vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
79{
80 int i, n;
Dave Barach9b8ffd92016-07-08 08:13:45 -040081 uword *match = 0;
82 vlib_cli_parse_position_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -070083
84 unformat_skip_white_space (input);
85
Dave Barach9b8ffd92016-07-08 08:13:45 -040086 for (i = 0;; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 {
88 uword k;
89
90 k = unformat_get_input (input);
91 switch (k)
92 {
93 case 'a' ... 'z':
94 case 'A' ... 'Z':
95 case '0' ... '9':
Dave Barach9b8ffd92016-07-08 08:13:45 -040096 case '-':
97 case '_':
Ed Warnickecb9cada2015-12-08 15:45:58 -070098 break;
99
Dave Barach9b8ffd92016-07-08 08:13:45 -0400100 case ' ':
101 case '\t':
102 case '\r':
103 case '\n':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104 case UNFORMAT_END_OF_INPUT:
105 /* White space or end of input removes any non-white
106 matches that were before possible. */
107 if (i < vec_len (c->sub_command_positions)
108 && clib_bitmap_count_set_bits (match) > 1)
109 {
110 p = vec_elt_at_index (c->sub_command_positions, i);
111 for (n = 0; n < vec_len (p->bitmaps); n++)
112 match = clib_bitmap_andnot (match, p->bitmaps[n]);
113 }
114 goto done;
115
116 default:
117 unformat_put_input (input);
118 goto done;
119 }
120
121 if (i >= vec_len (c->sub_command_positions))
122 {
123 no_match:
124 clib_bitmap_free (match);
125 return 0;
126 }
127
128 p = vec_elt_at_index (c->sub_command_positions, i);
129 if (vec_len (p->bitmaps) == 0)
130 goto no_match;
131
132 n = k - p->min_char;
133 if (n < 0 || n >= vec_len (p->bitmaps))
134 goto no_match;
135
136 if (i == 0)
137 match = clib_bitmap_dup (p->bitmaps[n]);
138 else
139 match = clib_bitmap_and (match, p->bitmaps[n]);
140
141 if (clib_bitmap_is_zero (match))
142 goto no_match;
143 }
144
Dave Barach9b8ffd92016-07-08 08:13:45 -0400145done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146 return match;
147}
148
149/* Looks for string based sub-input formatted { SUB-INPUT }. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400150uword
151unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400153 unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
154 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155 uword c;
156
157 while (1)
158 {
159 c = unformat_get_input (i);
160 switch (c)
161 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400162 case ' ':
163 case '\t':
164 case '\n':
165 case '\r':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 case '\f':
167 break;
168
169 case '{':
170 default:
171 /* Put back paren. */
172 if (c != UNFORMAT_END_OF_INPUT)
173 unformat_put_input (i);
174
175 if (c == '{' && unformat (i, "%v", &s))
176 {
177 unformat_init_vector (sub_input, s);
178 return 1;
179 }
180 return 0;
181 }
182 }
183 return 0;
184}
185
186static vlib_cli_command_t *
187get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
188{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400189 vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190 return vec_elt_at_index (cm->commands, s->index);
191}
192
Dave Barach9b8ffd92016-07-08 08:13:45 -0400193static uword
194unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400196 vlib_main_t *vm = va_arg (*args, vlib_main_t *);
197 vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
198 vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
199 vlib_cli_main_t *cm = &vm->cli_main;
200 uword *match_bitmap, is_unique, index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201
202 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400203 vlib_cli_sub_rule_t *sr;
204 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 vec_foreach (sr, c->sub_rules)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400206 {
207 void **d;
208 r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
209 vec_add2 (cm->parse_rule_data, d, 1);
210 vec_reset_length (d[0]);
211 if (r->data_size)
212 d[0] = _vec_resize (d[0],
213 /* length increment */ 1,
214 r->data_size,
215 /* header_bytes */ 0,
216 /* data align */ sizeof (uword));
217 if (unformat_user (i, r->unformat_function, vm, d[0]))
218 {
219 *result = vec_elt_at_index (cm->commands, sr->command_index);
220 return 1;
221 }
222 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223 }
224
225 match_bitmap = vlib_cli_sub_command_match (c, i);
226 is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
227 index = ~0;
228 if (is_unique)
229 {
230 index = clib_bitmap_first_set (match_bitmap);
231 *result = get_sub_command (cm, c, index);
232 }
233 clib_bitmap_free (match_bitmap);
234
235 return is_unique;
236}
237
Dave Barach9b8ffd92016-07-08 08:13:45 -0400238static u8 *
239format_vlib_cli_command_help (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400241 vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 int is_long = va_arg (*args, int);
243 if (is_long && c->long_help)
244 s = format (s, "%s", c->long_help);
245 else if (c->short_help)
246 s = format (s, "%s", c->short_help);
247 else
248 s = format (s, "%v commands", c->path);
249 return s;
250}
251
Dave Barach9b8ffd92016-07-08 08:13:45 -0400252static u8 *
253format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400255 vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 return format (s, "<%U>", format_c_identifier, r->name);
257}
258
Dave Barach9b8ffd92016-07-08 08:13:45 -0400259static u8 *
260format_vlib_cli_path (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400262 u8 *path = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263 int i, in_rule;
264 in_rule = 0;
265 for (i = 0; i < vec_len (path); i++)
266 {
267 switch (path[i])
268 {
269 case '%':
270 in_rule = 1;
271 vec_add1 (s, '<'); /* start of <RULE> */
272 break;
273
274 case '_':
275 /* _ -> space in rules. */
276 vec_add1 (s, in_rule ? ' ' : '_');
277 break;
278
279 case ' ':
280 if (in_rule)
281 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400282 vec_add1 (s, '>'); /* end of <RULE> */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283 in_rule = 0;
284 }
285 vec_add1 (s, ' ');
286 break;
287
288 default:
289 vec_add1 (s, path[i]);
290 break;
291 }
292 }
293
294 if (in_rule)
295 vec_add1 (s, '>'); /* terminate <RULE> */
296
297 return s;
298}
299
300static vlib_cli_command_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400301all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400303 vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
304 vlib_cli_sub_command_t *sc;
305 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
307 if (c->function)
308 vec_add1 (subs, c[0]);
309
310 vec_foreach (sr, c->sub_rules)
311 subs = all_subs (cm, subs, sr->command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400312 vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700313
314 return subs;
315}
316
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500317static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400318vlib_cli_cmp_rule (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500319{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400320 vlib_cli_sub_rule_t *r1 = a1;
321 vlib_cli_sub_rule_t *r2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500322
323 return vec_cmp (r1->name, r2->name);
324}
325
326static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400327vlib_cli_cmp_command (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500328{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400329 vlib_cli_command_t *c1 = a1;
330 vlib_cli_command_t *c2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500331
332 return vec_cmp (c1->path, c2->path);
333}
334
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335static clib_error_t *
336vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
337 vlib_cli_main_t * cm,
338 unformat_input_t * input,
339 uword parent_command_index)
340{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400341 vlib_cli_command_t *parent, *c;
342 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343 unformat_input_t sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400344 u8 *string;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345 uword is_main_dispatch = cm == &vm->cli_main;
346
347 parent = vec_elt_at_index (cm->commands, parent_command_index);
348 if (is_main_dispatch && unformat (input, "help"))
349 {
350 uword help_at_end_of_line, i;
351
Dave Barach9b8ffd92016-07-08 08:13:45 -0400352 help_at_end_of_line =
353 unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354 while (1)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400355 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356 c = parent;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400357 if (unformat_user
358 (input, unformat_vlib_cli_sub_command, vm, c, &parent))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 ;
360
Dave Barach9b8ffd92016-07-08 08:13:45 -0400361 else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362 goto unknown;
363
364 else
365 break;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400366 }
367
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 /* help SUB-COMMAND => long format help.
Dave Barach9b8ffd92016-07-08 08:13:45 -0400369 "help" at end of line: show all commands. */
370 if (!help_at_end_of_line)
371 vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
372 /* is_long */ 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373
374 else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
375 vlib_cli_output (vm, "%v: no sub-commands", c->path);
376
377 else
378 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400379 vlib_cli_sub_command_t *sc;
380 vlib_cli_sub_rule_t *sr, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381
382 subs = vec_dup (c->sub_rules);
383
384 /* Add in rules if any. */
385 vec_foreach (sc, c->sub_commands)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400386 {
387 vec_add2 (subs, sr, 1);
388 sr->name = sc->name;
389 sr->command_index = sc->index;
390 sr->rule_index = ~0;
391 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500393 vec_sort_with_function (subs, vlib_cli_cmp_rule);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394
Dave Barach9b8ffd92016-07-08 08:13:45 -0400395 for (i = 0; i < vec_len (subs); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400397 vlib_cli_command_t *d;
398 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399
400 d = vec_elt_at_index (cm->commands, subs[i].command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400401 r =
402 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
403 subs
404 [i].rule_index) :
405 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406
407 if (r)
408 vlib_cli_output
409 (vm, " %-30U %U",
410 format_vlib_cli_parse_rule_name, r,
411 format_vlib_cli_command_help, d, /* is_long */ 0);
412 else
413 vlib_cli_output
414 (vm, " %-30v %U",
415 subs[i].name,
416 format_vlib_cli_command_help, d, /* is_long */ 0);
417 }
418
419 vec_free (subs);
420 }
421 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400422
423 else if (is_main_dispatch
424 && (unformat (input, "choices") || unformat (input, "?")))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400426 vlib_cli_command_t *sub, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700427
428 subs = all_subs (cm, 0, parent_command_index);
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500429 vec_sort_with_function (subs, vlib_cli_cmp_command);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430 vec_foreach (sub, subs)
431 vlib_cli_output (vm, " %-40U %U",
432 format_vlib_cli_path, sub->path,
433 format_vlib_cli_command_help, sub, /* is_long */ 0);
434 vec_free (subs);
435 }
436
437 else if (unformat (input, "comment %v", &string))
438 {
439 vec_free (string);
440 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400441
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 else if (unformat (input, "uncomment %U",
443 unformat_vlib_cli_sub_input, &sub_input))
444 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400445 error =
446 vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
447 parent_command_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448 unformat_free (&sub_input);
449 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400450
451 else
452 if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400454 unformat_input_t *si;
455 uword has_sub_commands =
456 vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
457
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458 si = input;
459 if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
460 si = &sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400461
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 if (has_sub_commands)
463 error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
464
Dave Barach9b8ffd92016-07-08 08:13:45 -0400465 if (has_sub_commands && !error)
466 /* Found valid sub-command. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467
468 else if (c->function)
469 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400470 clib_error_t *c_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471
472 /* Skip white space for benefit of called function. */
473 unformat_skip_white_space (si);
474
475 if (unformat (si, "?"))
476 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400477 vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */
478 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700479 }
480 else
481 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400482 if (!c->is_mp_safe)
483 vlib_worker_thread_barrier_sync (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484
485 c_error = c->function (vm, si, c);
486
Dave Barach9b8ffd92016-07-08 08:13:45 -0400487 if (!c->is_mp_safe)
488 vlib_worker_thread_barrier_release (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489
490 if (c_error)
491 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400492 error =
493 clib_error_return (0, "%v: %v", c->path, c_error->what);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 clib_error_free (c_error);
495 /* Free sub input. */
496 if (si != input)
497 unformat_free (si);
498
499 return error;
500 }
501 }
502
503 /* Free any previous error. */
504 clib_error_free (error);
505 }
506
Dave Barach9b8ffd92016-07-08 08:13:45 -0400507 else if (!error)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508 error = clib_error_return (0, "%v: no sub-commands", c->path);
509
510 /* Free sub input. */
511 if (si != input)
512 unformat_free (si);
513 }
514
515 else
516 goto unknown;
517
518 return error;
519
Dave Barach9b8ffd92016-07-08 08:13:45 -0400520unknown:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 if (parent->path)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400522 return clib_error_return (0, "%v: unknown input `%U'", parent->path,
523 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400525 return clib_error_return (0, "unknown input `%U'", format_unformat_error,
526 input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527}
528
529
Dave Barach9b8ffd92016-07-08 08:13:45 -0400530void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
531 __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532
Dave Barach9b8ffd92016-07-08 08:13:45 -0400533void
534vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
535{
536}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537
538/* Process CLI input. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400539void
540vlib_cli_input (vlib_main_t * vm,
541 unformat_input_t * input,
542 vlib_cli_output_function_t * function, uword function_arg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700543{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400544 vlib_process_t *cp = vlib_get_current_process (vm);
545 vlib_cli_main_t *cm = &vm->cli_main;
546 clib_error_t *error;
547 vlib_cli_output_function_t *save_function;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700548 uword save_function_arg;
549
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000550 save_function = cp->output_function;
551 save_function_arg = cp->output_function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000553 cp->output_function = function;
554 cp->output_function_arg = function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555
Dave Barach9b8ffd92016-07-08 08:13:45 -0400556 do
557 {
558 vec_reset_length (cm->parse_rule_data);
559 error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
560 0);
561 }
562 while (!error && !unformat (input, "%U", unformat_eof));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563
564 if (error)
565 {
566 vlib_cli_output (vm, "%v", error->what);
567 vlib_unix_error_report (vm, error);
568 clib_error_free (error);
569 }
570
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000571 cp->output_function = save_function;
572 cp->output_function_arg = save_function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573}
574
575/* Output to current CLI connection. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400576void
577vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700578{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400579 vlib_process_t *cp = vlib_get_current_process (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700580 va_list va;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400581 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582
583 va_start (va, fmt);
584 s = va_format (0, fmt, &va);
585 va_end (va);
586
587 /* Terminate with \n if not present. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400588 if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700589 vec_add1 (s, '\n');
590
Dave Barach9b8ffd92016-07-08 08:13:45 -0400591 if ((!cp) || (!cp->output_function))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592 fformat (stdout, "%v", s);
593 else
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000594 cp->output_function (cp->output_function_arg, s, vec_len (s));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595
596 vec_free (s);
597}
598
599static clib_error_t *
600show_memory_usage (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400601 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700602{
603 int verbose = 0;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400604 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700605 u32 index = 0;
606
Dave Barach9b8ffd92016-07-08 08:13:45 -0400607 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400609 if (unformat (input, "verbose"))
610 verbose = 1;
611 else
612 {
613 error = clib_error_return (0, "unknown input `%U'",
614 format_unformat_error, input);
615 return error;
616 }
617 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618
Dave Barach9b8ffd92016-07-08 08:13:45 -0400619 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700620 foreach_vlib_main (
621 ({
622 vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
623 vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
624 index++;
625 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400626 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627 return 0;
628}
629
Dave Barach9b8ffd92016-07-08 08:13:45 -0400630/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
632 .path = "show memory",
633 .short_help = "Show current memory usage",
634 .function = show_memory_usage,
635};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400636/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700637
638static clib_error_t *
Damjan Marioneccf5092016-11-18 16:59:24 +0100639show_cpu (vlib_main_t * vm, unformat_input_t * input,
640 vlib_cli_command_t * cmd)
641{
642#define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
643 _("Model name", "%U", format_cpu_model_name);
644 _("Microarchitecture", "%U", format_cpu_uarch);
645 _("Flags", "%U", format_cpu_flags);
646 _("Base frequency", "%.2f GHz",
647 ((f64) vm->clib_time.clocks_per_second) * 1e-9);
648#undef _
649 return 0;
650}
651
652/*?
653 * Displays various information about the CPU.
654 *
655 * @cliexpar
656 * @cliexstart{show cpu}
657 * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
658 * Microarchitecture: Broadwell (Broadwell-EP/EX)
659 * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
660 * Base Frequency: 3.20 GHz
661 * @cliexend
662?*/
663/* *INDENT-OFF* */
664VLIB_CLI_COMMAND (show_cpu_command, static) = {
665 .path = "show cpu",
666 .short_help = "Show cpu information",
667 .function = show_cpu,
668};
669
670/* *INDENT-ON* */
671static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700672enable_disable_memory_trace (vlib_main_t * vm,
673 unformat_input_t * input,
674 vlib_cli_command_t * cmd)
675{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400676 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 int enable;
678
Dave Barach9b8ffd92016-07-08 08:13:45 -0400679 if (!unformat_user (input, unformat_vlib_enable_disable, &enable))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680 {
681 error = clib_error_return (0, "expecting enable/on or disable/off");
682 goto done;
683 }
684
685 clib_mem_trace (enable);
686
Dave Barach9b8ffd92016-07-08 08:13:45 -0400687done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688 return error;
689}
690
Dave Barach9b8ffd92016-07-08 08:13:45 -0400691/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
693 .path = "memory-trace",
694 .short_help = "Enable/disable memory allocation trace",
695 .function = enable_disable_memory_trace,
696};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400697/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698
699
700static clib_error_t *
701test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400702 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400704 clib_error_t *error = 0;
705 void *heap;
706 mheap_t *mheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707
Dave Barach9b8ffd92016-07-08 08:13:45 -0400708 if (unformat (input, "on"))
709 {
710 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200712 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713 mheap = mheap_header(heap);
714 mheap->flags |= MHEAP_FLAG_VALIDATE;
715 // Turn off small object cache because it delays detection of errors
716 mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
717 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400718 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
Dave Barach9b8ffd92016-07-08 08:13:45 -0400720 }
721 else if (unformat (input, "off"))
722 {
723 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200725 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726 mheap = mheap_header(heap);
727 mheap->flags &= ~MHEAP_FLAG_VALIDATE;
728 mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
729 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400730 /* *INDENT-ON* */
731 }
732 else if (unformat (input, "now"))
733 {
734 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200736 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737 mheap = mheap_header(heap);
738 mheap_validate(heap);
739 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400740 /* *INDENT-ON* */
741 vlib_cli_output (vm, "heap validation complete");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742
Dave Barach9b8ffd92016-07-08 08:13:45 -0400743 }
744 else
745 {
746 return clib_error_return (0, "unknown input `%U'",
747 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748 }
749
Dave Barach9b8ffd92016-07-08 08:13:45 -0400750 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751}
752
Dave Barach9b8ffd92016-07-08 08:13:45 -0400753/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
755 .path = "test heap-validate",
756 .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
757 .function = test_heap_validate,
758};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400759/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760
Damjan Marione5ef1d72017-03-02 12:33:48 +0100761static clib_error_t *
762restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
763 vlib_cli_command_t * cmd)
764{
765 char *newenviron[] = { NULL };
766
767 execve (vm->name, (char **) vm->argv, newenviron);
768
769 return 0;
770}
771
772/* *INDENT-OFF* */
773VLIB_CLI_COMMAND (restart_cmd,static) = {
774 .path = "restart",
775 .short_help = "restart process",
776 .function = restart_cmd_fn,
777};
778/* *INDENT-ON* */
779
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000780#ifdef TEST_CODE
781/*
782 * A trivial test harness to verify the per-process output_function
783 * is working correcty.
784 */
785
786static clib_error_t *
787sleep_ten_seconds (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400788 unformat_input_t * input, vlib_cli_command_t * cmd)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000789{
790 u16 i;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400791 u16 my_id = rand ();
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000792
Dave Barach9b8ffd92016-07-08 08:13:45 -0400793 vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000794
Dave Barach9b8ffd92016-07-08 08:13:45 -0400795 for (i = 0; i < 10; i++)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000796 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400797 vlib_process_wait_for_event_or_clock (vm, 1.0);
798 vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000799 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400800 vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000801 return 0;
802}
803
Dave Barach9b8ffd92016-07-08 08:13:45 -0400804/* *INDENT-OFF* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000805VLIB_CLI_COMMAND (ping_command, static) = {
806 .path = "test sleep",
807 .function = sleep_ten_seconds,
808 .short_help = "Sleep for 10 seconds",
809};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400810/* *INDENT-ON* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000811#endif /* ifdef TEST_CODE */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812
Dave Barach9b8ffd92016-07-08 08:13:45 -0400813static uword
814vlib_cli_normalize_path (char *input, char **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400816 char *i = input;
817 char *s = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700818 uword l = 0;
819 uword index_of_last_space = ~0;
820
821 while (*i != 0)
822 {
823 u8 c = *i++;
824 /* Multiple white space -> single space. */
825 switch (c)
826 {
827 case ' ':
828 case '\t':
829 case '\n':
830 case '\r':
Dave Barach9b8ffd92016-07-08 08:13:45 -0400831 if (l > 0 && s[l - 1] != ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832 {
833 vec_add1 (s, ' ');
834 l++;
835 }
836 break;
837
838 default:
Dave Barach9b8ffd92016-07-08 08:13:45 -0400839 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700840 index_of_last_space = vec_len (s);
841 vec_add1 (s, c);
842 l++;
843 break;
844 }
845 }
846
847 /* Remove any extra space at end. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400848 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700849 _vec_len (s) -= 1;
850
851 *result = s;
852 return index_of_last_space;
853}
854
855always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -0400856parent_path_len (char *path)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857{
858 word i;
859 for (i = vec_len (path) - 1; i >= 0; i--)
860 {
861 if (path[i] == ' ')
862 return i;
863 }
864 return ~0;
865}
866
Dave Barach9b8ffd92016-07-08 08:13:45 -0400867static void
868add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400870 vlib_cli_command_t *p, *c;
871 vlib_cli_sub_command_t *sub_c;
872 u8 *sub_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873 word i, l;
874
875 p = vec_elt_at_index (cm->commands, parent_index);
876 c = vec_elt_at_index (cm->commands, child_index);
877
878 l = parent_path_len (c->path);
879 if (l == ~0)
880 sub_name = vec_dup ((u8 *) c->path);
881 else
882 {
883 ASSERT (l + 1 < vec_len (c->path));
884 sub_name = 0;
885 vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
886 }
887
888 if (sub_name[0] == '%')
889 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400890 uword *q;
891 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700892
893 /* Remove %. */
894 vec_delete (sub_name, 1, 0);
895
Dave Barach9b8ffd92016-07-08 08:13:45 -0400896 if (!p->sub_rule_index_by_name)
897 p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
898 sizeof (sub_name[0]),
899 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700900 q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
901 if (q)
902 {
903 sr = vec_elt_at_index (p->sub_rules, q[0]);
904 ASSERT (sr->command_index == child_index);
905 return;
906 }
907
908 q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400909 if (!q)
Ed Warnicke853e7202016-08-12 11:42:26 -0700910 {
911 clib_error ("reference to unknown rule `%%%v' in path `%v'",
912 sub_name, c->path);
913 return;
914 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915
Dave Barach9b8ffd92016-07-08 08:13:45 -0400916 hash_set_mem (p->sub_rule_index_by_name, sub_name,
917 vec_len (p->sub_rules));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918 vec_add2 (p->sub_rules, sr, 1);
919 sr->name = sub_name;
920 sr->rule_index = q[0];
921 sr->command_index = child_index;
922 return;
923 }
924
Dave Barach9b8ffd92016-07-08 08:13:45 -0400925 if (!p->sub_command_index_by_name)
926 p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
927 sizeof (c->path[0]),
928 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700929
930 /* Check if sub-command has already been created. */
931 if (hash_get_mem (p->sub_command_index_by_name, sub_name))
932 {
933 vec_free (sub_name);
934 return;
935 }
936
937 vec_add2 (p->sub_commands, sub_c, 1);
938 sub_c->index = child_index;
939 sub_c->name = sub_name;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400940 hash_set_mem (p->sub_command_index_by_name, sub_c->name,
941 sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942
943 vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
944 for (i = 0; i < vec_len (sub_c->name); i++)
945 {
946 int n;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400947 vlib_cli_parse_position_t *pos;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700948
949 pos = vec_elt_at_index (p->sub_command_positions, i);
950
Dave Barach9b8ffd92016-07-08 08:13:45 -0400951 if (!pos->bitmaps)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952 pos->min_char = sub_c->name[i];
953
954 n = sub_c->name[i] - pos->min_char;
955 if (n < 0)
956 {
957 pos->min_char = sub_c->name[i];
958 vec_insert (pos->bitmaps, -n, 0);
959 n = 0;
960 }
961
962 vec_validate (pos->bitmaps, n);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400963 pos->bitmaps[n] =
964 clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700965 }
966}
967
968static void
969vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
970{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400971 uword p_len, pi, *p;
972 char *p_path;
973 vlib_cli_command_t *c, *parent;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974
975 /* Root command (index 0) should have already been added. */
976 ASSERT (vec_len (cm->commands) > 0);
977
978 c = vec_elt_at_index (cm->commands, ci);
979 p_len = parent_path_len (c->path);
980
Dave Barach9b8ffd92016-07-08 08:13:45 -0400981 /* No space? Parent is root command. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982 if (p_len == ~0)
983 {
984 add_sub_command (cm, 0, ci);
985 return;
986 }
987
988 p_path = 0;
989 vec_add (p_path, c->path, p_len);
990
991 p = hash_get_mem (cm->command_index_by_path, p_path);
992
993 /* Parent exists? */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400994 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995 {
996 /* Parent does not exist; create it. */
997 vec_add2 (cm->commands, parent, 1);
998 parent->path = p_path;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400999 hash_set_mem (cm->command_index_by_path, parent->path,
1000 parent - cm->commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001001 pi = parent - cm->commands;
1002 }
1003 else
1004 {
1005 pi = p[0];
1006 vec_free (p_path);
1007 }
1008
1009 add_sub_command (cm, pi, ci);
1010
1011 /* Create parent's parent. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001012 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013 vlib_cli_make_parent (cm, pi);
1014}
1015
1016always_inline uword
1017vlib_cli_command_is_empty (vlib_cli_command_t * c)
1018{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001019 return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020}
1021
Dave Barach9b8ffd92016-07-08 08:13:45 -04001022clib_error_t *
1023vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001024{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001025 vlib_cli_main_t *cm = &vm->cli_main;
1026 clib_error_t *error = 0;
1027 uword ci, *p;
1028 char *normalized_path;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029
1030 if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1031 return error;
1032
1033 (void) vlib_cli_normalize_path (c->path, &normalized_path);
1034
Dave Barach9b8ffd92016-07-08 08:13:45 -04001035 if (!cm->command_index_by_path)
1036 cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037 sizeof (c->path[0]),
1038 sizeof (uword));
1039
1040 /* See if command already exists with given path. */
1041 p = hash_get_mem (cm->command_index_by_path, normalized_path);
1042 if (p)
1043 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001044 vlib_cli_command_t *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045
1046 ci = p[0];
1047 d = vec_elt_at_index (cm->commands, ci);
1048
1049 /* If existing command was created via vlib_cli_make_parent
Dave Barach9b8ffd92016-07-08 08:13:45 -04001050 replaced it with callers data. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 if (vlib_cli_command_is_empty (d))
1052 {
1053 vlib_cli_command_t save = d[0];
1054
Dave Barach9b8ffd92016-07-08 08:13:45 -04001055 ASSERT (!vlib_cli_command_is_empty (c));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056
1057 /* Copy callers fields. */
1058 d[0] = c[0];
1059
1060 /* Save internal fields. */
1061 d->path = save.path;
1062 d->sub_commands = save.sub_commands;
1063 d->sub_command_index_by_name = save.sub_command_index_by_name;
1064 d->sub_command_positions = save.sub_command_positions;
1065 d->sub_rules = save.sub_rules;
1066 }
1067 else
Dave Barach9b8ffd92016-07-08 08:13:45 -04001068 error =
1069 clib_error_return (0, "duplicate command name with path %v",
1070 normalized_path);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071
1072 vec_free (normalized_path);
1073 if (error)
1074 return error;
1075 }
1076 else
1077 {
1078 /* Command does not exist: create it. */
1079
1080 /* Add root command (index 0). */
1081 if (vec_len (cm->commands) == 0)
1082 {
1083 /* Create command with index 0; path is empty string. */
1084 vec_resize (cm->commands, 1);
1085 }
1086
1087 ci = vec_len (cm->commands);
1088 hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1089 vec_add1 (cm->commands, c[0]);
1090
1091 c = vec_elt_at_index (cm->commands, ci);
1092 c->path = normalized_path;
1093
1094 /* Don't inherit from registration. */
1095 c->sub_commands = 0;
1096 c->sub_command_index_by_name = 0;
1097 c->sub_command_positions = 0;
1098 }
1099
1100 vlib_cli_make_parent (cm, ci);
1101 return 0;
1102}
1103
1104clib_error_t *
1105vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1106{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001107 vlib_cli_main_t *cm = &vm->cli_main;
1108 vlib_cli_parse_rule_t *r;
1109 clib_error_t *error = 0;
1110 u8 *r_name;
1111 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112
Dave Barach9b8ffd92016-07-08 08:13:45 -04001113 if (!cm->parse_rule_index_by_name)
1114 cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115 sizeof (r->name[0]),
1116 sizeof (uword));
1117
1118 /* Make vector copy of name. */
1119 r_name = format (0, "%s", r_reg->name);
1120
1121 if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1122 {
1123 vec_free (r_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001124 return clib_error_return (0, "duplicate parse rule name `%s'",
1125 r_reg->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126 }
1127
1128 vec_add2 (cm->parse_rules, r, 1);
1129 r[0] = r_reg[0];
1130 r->name = (char *) r_name;
1131 hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1132
1133 return error;
1134}
1135
1136#if 0
1137/* $$$ turn back on again someday, maybe */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001138static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1139 vlib_cli_parse_rule_t *
1140 lo,
1141 vlib_cli_parse_rule_t *
1142 hi)
1143 __attribute__ ((unused))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001145 clib_error_t *error = 0;
1146 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001147
1148 for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1149 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001150 if (!r->name || strlen (r->name) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 {
1152 error = clib_error_return (0, "parse rule with no name");
1153 goto done;
1154 }
1155
1156 error = vlib_cli_register_parse_rule (vm, r);
1157 if (error)
1158 goto done;
1159 }
1160
Dave Barach9b8ffd92016-07-08 08:13:45 -04001161done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162 return error;
1163}
1164#endif
1165
Damjan Marion9c2b9f42017-04-21 13:56:40 +02001166static int
1167cli_path_compare (void *a1, void *a2)
1168{
1169 u8 **s1 = a1;
1170 u8 **s2 = a2;
1171
1172 if ((vec_len (*s1) < vec_len (*s2)) &&
1173 memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1174 return -1;
1175
1176
1177 if ((vec_len (*s1) > vec_len (*s2)) &&
1178 memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1179 return 1;
1180
1181 return vec_cmp (*s1, *s2);
1182}
1183
1184static clib_error_t *
1185show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1186 vlib_cli_command_t * cmd)
1187{
1188 vlib_cli_main_t *cm = &vm->cli_main;
1189 vlib_cli_command_t *cli;
1190 u8 **paths = 0, **s;
1191
1192 /* *INDENT-OFF* */
1193 vec_foreach (cli, cm->commands)
1194 if (vec_len (cli->path) > 0)
1195 vec_add1 (paths, (u8 *) cli->path);
1196
1197 vec_sort_with_function (paths, cli_path_compare);
1198
1199 vec_foreach (s, paths)
1200 vlib_cli_output (vm, "%v", *s);
1201 /* *INDENT-ON* */
1202
1203 vec_free (paths);
1204 return 0;
1205}
1206
1207/* *INDENT-OFF* */
1208VLIB_CLI_COMMAND (show_cli_command, static) = {
1209 .path = "show cli",
1210 .short_help = "Show cli commands",
1211 .function = show_cli_cmd_fn,
1212};
1213/* *INDENT-ON* */
1214
Dave Barach9b8ffd92016-07-08 08:13:45 -04001215static clib_error_t *
1216vlib_cli_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001217{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001218 vlib_cli_main_t *cm = &vm->cli_main;
1219 clib_error_t *error = 0;
1220 vlib_cli_command_t *cmd;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221
1222 cmd = cm->cli_command_registrations;
1223
1224 while (cmd)
1225 {
1226 error = vlib_cli_register (vm, cmd);
1227 if (error)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001228 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229 cmd = cmd->next_cli_command;
1230 }
1231 return error;
1232}
1233
1234VLIB_INIT_FUNCTION (vlib_cli_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001235
1236/*
1237 * fd.io coding-style-patch-verification: ON
1238 *
1239 * Local Variables:
1240 * eval: (c-set-style "gnu")
1241 * End:
1242 */