blob: a85fa93906c27a99ea357dae8fefd807bfcc6a50 [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>
Yoann Desmouceaux3060e072017-05-18 11:00:48 +020043#include <ctype.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070044
45/* Root of all show commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040046/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070047VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
48 .path = "show",
49 .short_help = "Show commands",
50};
Dave Barach9b8ffd92016-07-08 08:13:45 -040051/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070052
53/* Root of all clear commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040054/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070055VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
56 .path = "clear",
57 .short_help = "Clear commands",
58};
Dave Barach9b8ffd92016-07-08 08:13:45 -040059/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070060
61/* Root of all set commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040062/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070063VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
64 .path = "set",
65 .short_help = "Set commands",
66};
Dave Barach9b8ffd92016-07-08 08:13:45 -040067/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070068
69/* Root of all test commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040070/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070071VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
72 .path = "test",
73 .short_help = "Test commands",
74};
Dave Barach9b8ffd92016-07-08 08:13:45 -040075/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070076
77/* Returns bitmap of commands which match key. */
78static uword *
79vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
80{
81 int i, n;
Dave Barach9b8ffd92016-07-08 08:13:45 -040082 uword *match = 0;
83 vlib_cli_parse_position_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -070084
85 unformat_skip_white_space (input);
86
Dave Barach9b8ffd92016-07-08 08:13:45 -040087 for (i = 0;; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 {
89 uword k;
90
91 k = unformat_get_input (input);
92 switch (k)
93 {
94 case 'a' ... 'z':
95 case 'A' ... 'Z':
96 case '0' ... '9':
Dave Barach9b8ffd92016-07-08 08:13:45 -040097 case '-':
98 case '_':
Ed Warnickecb9cada2015-12-08 15:45:58 -070099 break;
100
Dave Barach9b8ffd92016-07-08 08:13:45 -0400101 case ' ':
102 case '\t':
103 case '\r':
104 case '\n':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 case UNFORMAT_END_OF_INPUT:
106 /* White space or end of input removes any non-white
107 matches that were before possible. */
108 if (i < vec_len (c->sub_command_positions)
109 && clib_bitmap_count_set_bits (match) > 1)
110 {
111 p = vec_elt_at_index (c->sub_command_positions, i);
112 for (n = 0; n < vec_len (p->bitmaps); n++)
113 match = clib_bitmap_andnot (match, p->bitmaps[n]);
114 }
115 goto done;
116
117 default:
118 unformat_put_input (input);
119 goto done;
120 }
121
122 if (i >= vec_len (c->sub_command_positions))
123 {
124 no_match:
125 clib_bitmap_free (match);
126 return 0;
127 }
128
129 p = vec_elt_at_index (c->sub_command_positions, i);
130 if (vec_len (p->bitmaps) == 0)
131 goto no_match;
132
133 n = k - p->min_char;
134 if (n < 0 || n >= vec_len (p->bitmaps))
135 goto no_match;
136
137 if (i == 0)
138 match = clib_bitmap_dup (p->bitmaps[n]);
139 else
140 match = clib_bitmap_and (match, p->bitmaps[n]);
141
142 if (clib_bitmap_is_zero (match))
143 goto no_match;
144 }
145
Dave Barach9b8ffd92016-07-08 08:13:45 -0400146done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147 return match;
148}
149
150/* Looks for string based sub-input formatted { SUB-INPUT }. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400151uword
152unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400154 unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
155 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156 uword c;
157
158 while (1)
159 {
160 c = unformat_get_input (i);
161 switch (c)
162 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400163 case ' ':
164 case '\t':
165 case '\n':
166 case '\r':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167 case '\f':
168 break;
169
170 case '{':
171 default:
172 /* Put back paren. */
173 if (c != UNFORMAT_END_OF_INPUT)
174 unformat_put_input (i);
175
176 if (c == '{' && unformat (i, "%v", &s))
177 {
178 unformat_init_vector (sub_input, s);
179 return 1;
180 }
181 return 0;
182 }
183 }
184 return 0;
185}
186
187static vlib_cli_command_t *
188get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
189{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400190 vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191 return vec_elt_at_index (cm->commands, s->index);
192}
193
Dave Barach9b8ffd92016-07-08 08:13:45 -0400194static uword
195unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400197 vlib_main_t *vm = va_arg (*args, vlib_main_t *);
198 vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
199 vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
200 vlib_cli_main_t *cm = &vm->cli_main;
201 uword *match_bitmap, is_unique, index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202
203 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400204 vlib_cli_sub_rule_t *sr;
205 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206 vec_foreach (sr, c->sub_rules)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400207 {
208 void **d;
209 r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
210 vec_add2 (cm->parse_rule_data, d, 1);
211 vec_reset_length (d[0]);
212 if (r->data_size)
213 d[0] = _vec_resize (d[0],
214 /* length increment */ 1,
215 r->data_size,
216 /* header_bytes */ 0,
217 /* data align */ sizeof (uword));
218 if (unformat_user (i, r->unformat_function, vm, d[0]))
219 {
220 *result = vec_elt_at_index (cm->commands, sr->command_index);
221 return 1;
222 }
223 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 }
225
226 match_bitmap = vlib_cli_sub_command_match (c, i);
227 is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
228 index = ~0;
229 if (is_unique)
230 {
231 index = clib_bitmap_first_set (match_bitmap);
232 *result = get_sub_command (cm, c, index);
233 }
234 clib_bitmap_free (match_bitmap);
235
236 return is_unique;
237}
238
Yoann Desmouceaux3060e072017-05-18 11:00:48 +0200239static int
240vlib_cli_cmp_strings (void *a1, void *a2)
241{
242 u8 *c1 = *(u8 **) a1;
243 u8 *c2 = *(u8 **) a2;
244
245 return vec_cmp (c1, c2);
246}
247
248u8 **
249vlib_cli_get_possible_completions (u8 * str)
250{
251 vlib_cli_command_t *c;
252 vlib_cli_sub_command_t *sc;
253 vlib_main_t *vm = vlib_get_main ();
254 vlib_cli_main_t *vcm = &vm->cli_main;
255 uword *match_bitmap = 0;
256 uword index, is_unique, help_next_level;
257 u8 **result = 0;
258 unformat_input_t input;
259 unformat_init_vector (&input, vec_dup (str));
260 c = vec_elt_at_index (vcm->commands, 0);
261
262 /* remove trailing whitespace, except for one of them */
263 while (vec_len (input.buffer) >= 2 &&
264 isspace (input.buffer[vec_len (input.buffer) - 1]) &&
265 isspace (input.buffer[vec_len (input.buffer) - 2]))
266 {
267 vec_del1 (input.buffer, vec_len (input.buffer) - 1);
268 }
269
270 /* if input is empty, directly return list of root commands */
271 if (vec_len (input.buffer) == 0 ||
272 (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
273 {
274 vec_foreach (sc, c->sub_commands)
275 {
276 vec_add1 (result, (u8 *) sc->name);
277 }
278 goto done;
279 }
280
281 /* add a trailing '?' so that vlib_cli_sub_command_match can find
282 * all commands starting with the input string */
283 vec_add1 (input.buffer, '?');
284
285 while (1)
286 {
287 match_bitmap = vlib_cli_sub_command_match (c, &input);
288 /* no match: return no result */
289 if (match_bitmap == 0)
290 {
291 goto done;
292 }
293 is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
294 /* unique match: try to step one subcommand level further */
295 if (is_unique)
296 {
297 /* stop if no more input */
298 if (input.index >= vec_len (input.buffer) - 1)
299 {
300 break;
301 }
302
303 index = clib_bitmap_first_set (match_bitmap);
304 c = get_sub_command (vcm, c, index);
305 clib_bitmap_free (match_bitmap);
306 continue;
307 }
308 /* multiple matches: stop here, return all matches */
309 break;
310 }
311
312 /* remove trailing '?' */
313 vec_del1 (input.buffer, vec_len (input.buffer) - 1);
314
315 /* if we have a space at the end of input, and a unique match,
316 * autocomplete the next level of subcommands */
317 help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
318 /* *INDENT-OFF* */
319 clib_bitmap_foreach(index, match_bitmap, {
320 if (help_next_level && is_unique) {
321 c = get_sub_command (vcm, c, index);
322 vec_foreach (sc, c->sub_commands) {
323 vec_add1 (result, (u8*) sc->name);
324 }
325 goto done; /* break doesn't work in this macro-loop */
326 }
327 sc = &c->sub_commands[index];
328 vec_add1(result, (u8*) sc->name);
329 });
330 /* *INDENT-ON* */
331
332done:
333 clib_bitmap_free (match_bitmap);
334 unformat_free (&input);
335
Yoann Desmouceaux4227eef2017-05-24 15:51:48 +0200336 if (result)
337 vec_sort_with_function (result, vlib_cli_cmp_strings);
Yoann Desmouceaux3060e072017-05-18 11:00:48 +0200338 return result;
339}
340
Dave Barach9b8ffd92016-07-08 08:13:45 -0400341static u8 *
342format_vlib_cli_command_help (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400344 vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345 int is_long = va_arg (*args, int);
346 if (is_long && c->long_help)
347 s = format (s, "%s", c->long_help);
348 else if (c->short_help)
349 s = format (s, "%s", c->short_help);
350 else
351 s = format (s, "%v commands", c->path);
352 return s;
353}
354
Dave Barach9b8ffd92016-07-08 08:13:45 -0400355static u8 *
356format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400358 vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 return format (s, "<%U>", format_c_identifier, r->name);
360}
361
Dave Barach9b8ffd92016-07-08 08:13:45 -0400362static u8 *
363format_vlib_cli_path (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400365 u8 *path = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366 int i, in_rule;
367 in_rule = 0;
368 for (i = 0; i < vec_len (path); i++)
369 {
370 switch (path[i])
371 {
372 case '%':
373 in_rule = 1;
374 vec_add1 (s, '<'); /* start of <RULE> */
375 break;
376
377 case '_':
378 /* _ -> space in rules. */
379 vec_add1 (s, in_rule ? ' ' : '_');
380 break;
381
382 case ' ':
383 if (in_rule)
384 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400385 vec_add1 (s, '>'); /* end of <RULE> */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386 in_rule = 0;
387 }
388 vec_add1 (s, ' ');
389 break;
390
391 default:
392 vec_add1 (s, path[i]);
393 break;
394 }
395 }
396
397 if (in_rule)
398 vec_add1 (s, '>'); /* terminate <RULE> */
399
400 return s;
401}
402
403static vlib_cli_command_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400404all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400406 vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
407 vlib_cli_sub_command_t *sc;
408 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409
410 if (c->function)
411 vec_add1 (subs, c[0]);
412
413 vec_foreach (sr, c->sub_rules)
414 subs = all_subs (cm, subs, sr->command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400415 vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416
417 return subs;
418}
419
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500420static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400421vlib_cli_cmp_rule (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500422{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400423 vlib_cli_sub_rule_t *r1 = a1;
424 vlib_cli_sub_rule_t *r2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500425
426 return vec_cmp (r1->name, r2->name);
427}
428
429static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400430vlib_cli_cmp_command (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500431{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400432 vlib_cli_command_t *c1 = a1;
433 vlib_cli_command_t *c2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500434
435 return vec_cmp (c1->path, c2->path);
436}
437
Ed Warnickecb9cada2015-12-08 15:45:58 -0700438static clib_error_t *
439vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
440 vlib_cli_main_t * cm,
441 unformat_input_t * input,
442 uword parent_command_index)
443{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400444 vlib_cli_command_t *parent, *c;
445 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700446 unformat_input_t sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400447 u8 *string;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448 uword is_main_dispatch = cm == &vm->cli_main;
449
450 parent = vec_elt_at_index (cm->commands, parent_command_index);
451 if (is_main_dispatch && unformat (input, "help"))
452 {
453 uword help_at_end_of_line, i;
454
Dave Barach9b8ffd92016-07-08 08:13:45 -0400455 help_at_end_of_line =
456 unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457 while (1)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400458 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459 c = parent;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400460 if (unformat_user
461 (input, unformat_vlib_cli_sub_command, vm, c, &parent))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 ;
463
Dave Barach9b8ffd92016-07-08 08:13:45 -0400464 else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465 goto unknown;
466
467 else
468 break;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400469 }
470
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 /* help SUB-COMMAND => long format help.
Dave Barach9b8ffd92016-07-08 08:13:45 -0400472 "help" at end of line: show all commands. */
473 if (!help_at_end_of_line)
474 vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
475 /* is_long */ 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476
477 else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
478 vlib_cli_output (vm, "%v: no sub-commands", c->path);
479
480 else
481 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400482 vlib_cli_sub_command_t *sc;
483 vlib_cli_sub_rule_t *sr, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484
485 subs = vec_dup (c->sub_rules);
486
487 /* Add in rules if any. */
488 vec_foreach (sc, c->sub_commands)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400489 {
490 vec_add2 (subs, sr, 1);
491 sr->name = sc->name;
492 sr->command_index = sc->index;
493 sr->rule_index = ~0;
494 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500496 vec_sort_with_function (subs, vlib_cli_cmp_rule);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497
Dave Barach9b8ffd92016-07-08 08:13:45 -0400498 for (i = 0; i < vec_len (subs); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400500 vlib_cli_command_t *d;
501 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700502
503 d = vec_elt_at_index (cm->commands, subs[i].command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400504 r =
505 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
506 subs
507 [i].rule_index) :
508 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700509
510 if (r)
511 vlib_cli_output
512 (vm, " %-30U %U",
513 format_vlib_cli_parse_rule_name, r,
514 format_vlib_cli_command_help, d, /* is_long */ 0);
515 else
516 vlib_cli_output
517 (vm, " %-30v %U",
518 subs[i].name,
519 format_vlib_cli_command_help, d, /* is_long */ 0);
520 }
521
522 vec_free (subs);
523 }
524 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400525
526 else if (is_main_dispatch
527 && (unformat (input, "choices") || unformat (input, "?")))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400529 vlib_cli_command_t *sub, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530
531 subs = all_subs (cm, 0, parent_command_index);
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500532 vec_sort_with_function (subs, vlib_cli_cmp_command);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533 vec_foreach (sub, subs)
534 vlib_cli_output (vm, " %-40U %U",
535 format_vlib_cli_path, sub->path,
536 format_vlib_cli_command_help, sub, /* is_long */ 0);
537 vec_free (subs);
538 }
539
540 else if (unformat (input, "comment %v", &string))
541 {
542 vec_free (string);
543 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400544
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545 else if (unformat (input, "uncomment %U",
546 unformat_vlib_cli_sub_input, &sub_input))
547 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400548 error =
549 vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
550 parent_command_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551 unformat_free (&sub_input);
552 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400553
554 else
555 if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400557 unformat_input_t *si;
558 uword has_sub_commands =
559 vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
560
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561 si = input;
562 if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
563 si = &sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400564
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565 if (has_sub_commands)
566 error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
567
Dave Barach9b8ffd92016-07-08 08:13:45 -0400568 if (has_sub_commands && !error)
569 /* Found valid sub-command. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700570
571 else if (c->function)
572 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400573 clib_error_t *c_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700574
575 /* Skip white space for benefit of called function. */
576 unformat_skip_white_space (si);
577
578 if (unformat (si, "?"))
579 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400580 vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */
581 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582 }
583 else
584 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400585 if (!c->is_mp_safe)
586 vlib_worker_thread_barrier_sync (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700587
588 c_error = c->function (vm, si, c);
589
Dave Barach9b8ffd92016-07-08 08:13:45 -0400590 if (!c->is_mp_safe)
591 vlib_worker_thread_barrier_release (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592
593 if (c_error)
594 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400595 error =
596 clib_error_return (0, "%v: %v", c->path, c_error->what);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597 clib_error_free (c_error);
598 /* Free sub input. */
599 if (si != input)
600 unformat_free (si);
601
602 return error;
603 }
604 }
605
606 /* Free any previous error. */
607 clib_error_free (error);
608 }
609
Dave Barach9b8ffd92016-07-08 08:13:45 -0400610 else if (!error)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700611 error = clib_error_return (0, "%v: no sub-commands", c->path);
612
613 /* Free sub input. */
614 if (si != input)
615 unformat_free (si);
616 }
617
618 else
619 goto unknown;
620
621 return error;
622
Dave Barach9b8ffd92016-07-08 08:13:45 -0400623unknown:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700624 if (parent->path)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400625 return clib_error_return (0, "%v: unknown input `%U'", parent->path,
626 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400628 return clib_error_return (0, "unknown input `%U'", format_unformat_error,
629 input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700630}
631
632
Dave Barach9b8ffd92016-07-08 08:13:45 -0400633void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
634 __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700635
Dave Barach9b8ffd92016-07-08 08:13:45 -0400636void
637vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
638{
639}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640
641/* Process CLI input. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400642void
643vlib_cli_input (vlib_main_t * vm,
644 unformat_input_t * input,
645 vlib_cli_output_function_t * function, uword function_arg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400647 vlib_process_t *cp = vlib_get_current_process (vm);
648 vlib_cli_main_t *cm = &vm->cli_main;
649 clib_error_t *error;
650 vlib_cli_output_function_t *save_function;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651 uword save_function_arg;
652
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000653 save_function = cp->output_function;
654 save_function_arg = cp->output_function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000656 cp->output_function = function;
657 cp->output_function_arg = function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658
Dave Barach9b8ffd92016-07-08 08:13:45 -0400659 do
660 {
661 vec_reset_length (cm->parse_rule_data);
662 error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
663 0);
664 }
665 while (!error && !unformat (input, "%U", unformat_eof));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700666
667 if (error)
668 {
669 vlib_cli_output (vm, "%v", error->what);
670 vlib_unix_error_report (vm, error);
671 clib_error_free (error);
672 }
673
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000674 cp->output_function = save_function;
675 cp->output_function_arg = save_function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676}
677
678/* Output to current CLI connection. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400679void
680vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400682 vlib_process_t *cp = vlib_get_current_process (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683 va_list va;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400684 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685
686 va_start (va, fmt);
687 s = va_format (0, fmt, &va);
688 va_end (va);
689
690 /* Terminate with \n if not present. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400691 if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692 vec_add1 (s, '\n');
693
Dave Barach9b8ffd92016-07-08 08:13:45 -0400694 if ((!cp) || (!cp->output_function))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 fformat (stdout, "%v", s);
696 else
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000697 cp->output_function (cp->output_function_arg, s, vec_len (s));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698
699 vec_free (s);
700}
701
Ole Troan73710c72018-06-04 22:27:49 +0200702void *vl_msg_push_heap (void) __attribute__ ((weak));
703void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
704
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705static clib_error_t *
706show_memory_usage (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400707 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708{
Ole Troan73710c72018-06-04 22:27:49 +0200709 int verbose = 0, api_segment = 0;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400710 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711 u32 index = 0;
712
Dave Barach9b8ffd92016-07-08 08:13:45 -0400713 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400715 if (unformat (input, "verbose"))
716 verbose = 1;
Ole Troan73710c72018-06-04 22:27:49 +0200717 else if (unformat (input, "api-segment"))
718 api_segment = 1;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400719 else
720 {
721 error = clib_error_return (0, "unknown input `%U'",
722 format_unformat_error, input);
723 return error;
724 }
725 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726
Ole Troan73710c72018-06-04 22:27:49 +0200727 if (api_segment)
728 {
729 void *oldheap = vl_msg_push_heap ();
730 u8 *s_in_svm =
731 format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
732 vl_msg_pop_heap (oldheap);
733 u8 *s = vec_dup (s_in_svm);
734
735 oldheap = vl_msg_push_heap ();
736 vec_free (s_in_svm);
737 vl_msg_pop_heap (oldheap);
738 vlib_cli_output (vm, "API segment start:");
739 vlib_cli_output (vm, "%v", s);
740 vlib_cli_output (vm, "API segment end:");
741 vec_free (s);
742 }
743
Dave Barach9b8ffd92016-07-08 08:13:45 -0400744 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745 foreach_vlib_main (
746 ({
747 vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
748 vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
749 index++;
750 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400751 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752 return 0;
753}
754
Dave Barach9b8ffd92016-07-08 08:13:45 -0400755/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
757 .path = "show memory",
Ole Troan73710c72018-06-04 22:27:49 +0200758 .short_help = "[verbose | api-segment] Show current memory usage",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700759 .function = show_memory_usage,
760};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400761/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762
763static clib_error_t *
Damjan Marioneccf5092016-11-18 16:59:24 +0100764show_cpu (vlib_main_t * vm, unformat_input_t * input,
765 vlib_cli_command_t * cmd)
766{
767#define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
768 _("Model name", "%U", format_cpu_model_name);
769 _("Microarchitecture", "%U", format_cpu_uarch);
770 _("Flags", "%U", format_cpu_flags);
771 _("Base frequency", "%.2f GHz",
772 ((f64) vm->clib_time.clocks_per_second) * 1e-9);
773#undef _
774 return 0;
775}
776
777/*?
778 * Displays various information about the CPU.
779 *
780 * @cliexpar
781 * @cliexstart{show cpu}
782 * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
783 * Microarchitecture: Broadwell (Broadwell-EP/EX)
784 * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
785 * Base Frequency: 3.20 GHz
786 * @cliexend
787?*/
788/* *INDENT-OFF* */
789VLIB_CLI_COMMAND (show_cpu_command, static) = {
790 .path = "show cpu",
791 .short_help = "Show cpu information",
792 .function = show_cpu,
793};
794
795/* *INDENT-ON* */
Ole Troan73710c72018-06-04 22:27:49 +0200796
Damjan Marioneccf5092016-11-18 16:59:24 +0100797static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798enable_disable_memory_trace (vlib_main_t * vm,
799 unformat_input_t * input,
800 vlib_cli_command_t * cmd)
801{
Ole Troan73710c72018-06-04 22:27:49 +0200802 unformat_input_t _line_input, *line_input = &_line_input;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 int enable;
Ole Troan73710c72018-06-04 22:27:49 +0200804 int api_segment = 0;
805 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806
Ole Troan73710c72018-06-04 22:27:49 +0200807
808 if (!unformat_user (input, unformat_line_input, line_input))
809 return 0;
810
811 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812 {
Ole Troan73710c72018-06-04 22:27:49 +0200813 if (!unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
814 ;
815 else if (unformat (line_input, "api-segment"))
816 api_segment = 1;
817 else
818 {
819 unformat_free (line_input);
820 return clib_error_return (0, "invalid input");
821 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822 }
Ole Troan73710c72018-06-04 22:27:49 +0200823 unformat_free (line_input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700824
Ole Troan73710c72018-06-04 22:27:49 +0200825 if (api_segment)
826 oldheap = vl_msg_push_heap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827 clib_mem_trace (enable);
Ole Troan73710c72018-06-04 22:27:49 +0200828 if (api_segment)
829 vl_msg_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830
Ole Troan73710c72018-06-04 22:27:49 +0200831 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832}
833
Dave Barach9b8ffd92016-07-08 08:13:45 -0400834/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700835VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
836 .path = "memory-trace",
Ole Troan73710c72018-06-04 22:27:49 +0200837 .short_help = "on|off [api-segment] Enable/disable memory allocation trace",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838 .function = enable_disable_memory_trace,
839};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400840/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700841
842
843static clib_error_t *
844test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400845 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700846{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400847 clib_error_t *error = 0;
848 void *heap;
849 mheap_t *mheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700850
Dave Barach9b8ffd92016-07-08 08:13:45 -0400851 if (unformat (input, "on"))
852 {
853 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200855 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700856 mheap = mheap_header(heap);
857 mheap->flags |= MHEAP_FLAG_VALIDATE;
858 // Turn off small object cache because it delays detection of errors
859 mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
860 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400861 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862
Dave Barach9b8ffd92016-07-08 08:13:45 -0400863 }
864 else if (unformat (input, "off"))
865 {
866 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200868 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869 mheap = mheap_header(heap);
870 mheap->flags &= ~MHEAP_FLAG_VALIDATE;
871 mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
872 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400873 /* *INDENT-ON* */
874 }
875 else if (unformat (input, "now"))
876 {
877 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700878 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200879 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880 mheap = mheap_header(heap);
881 mheap_validate(heap);
882 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400883 /* *INDENT-ON* */
884 vlib_cli_output (vm, "heap validation complete");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885
Dave Barach9b8ffd92016-07-08 08:13:45 -0400886 }
887 else
888 {
889 return clib_error_return (0, "unknown input `%U'",
890 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700891 }
892
Dave Barach9b8ffd92016-07-08 08:13:45 -0400893 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700894}
895
Dave Barach9b8ffd92016-07-08 08:13:45 -0400896/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700897VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
898 .path = "test heap-validate",
899 .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
900 .function = test_heap_validate,
901};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400902/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903
Damjan Marione5ef1d72017-03-02 12:33:48 +0100904static clib_error_t *
905restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
906 vlib_cli_command_t * cmd)
907{
908 char *newenviron[] = { NULL };
909
910 execve (vm->name, (char **) vm->argv, newenviron);
911
912 return 0;
913}
914
915/* *INDENT-OFF* */
916VLIB_CLI_COMMAND (restart_cmd,static) = {
917 .path = "restart",
918 .short_help = "restart process",
919 .function = restart_cmd_fn,
920};
921/* *INDENT-ON* */
922
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000923#ifdef TEST_CODE
924/*
925 * A trivial test harness to verify the per-process output_function
926 * is working correcty.
927 */
928
929static clib_error_t *
930sleep_ten_seconds (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400931 unformat_input_t * input, vlib_cli_command_t * cmd)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000932{
933 u16 i;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400934 u16 my_id = rand ();
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000935
Dave Barach9b8ffd92016-07-08 08:13:45 -0400936 vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000937
Dave Barach9b8ffd92016-07-08 08:13:45 -0400938 for (i = 0; i < 10; i++)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000939 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400940 vlib_process_wait_for_event_or_clock (vm, 1.0);
941 vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000942 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400943 vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000944 return 0;
945}
946
Dave Barach9b8ffd92016-07-08 08:13:45 -0400947/* *INDENT-OFF* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000948VLIB_CLI_COMMAND (ping_command, static) = {
949 .path = "test sleep",
950 .function = sleep_ten_seconds,
951 .short_help = "Sleep for 10 seconds",
952};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400953/* *INDENT-ON* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000954#endif /* ifdef TEST_CODE */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955
Dave Barach9b8ffd92016-07-08 08:13:45 -0400956static uword
957vlib_cli_normalize_path (char *input, char **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400959 char *i = input;
960 char *s = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961 uword l = 0;
962 uword index_of_last_space = ~0;
963
964 while (*i != 0)
965 {
966 u8 c = *i++;
967 /* Multiple white space -> single space. */
968 switch (c)
969 {
970 case ' ':
971 case '\t':
972 case '\n':
973 case '\r':
Dave Barach9b8ffd92016-07-08 08:13:45 -0400974 if (l > 0 && s[l - 1] != ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975 {
976 vec_add1 (s, ' ');
977 l++;
978 }
979 break;
980
981 default:
Dave Barach9b8ffd92016-07-08 08:13:45 -0400982 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 index_of_last_space = vec_len (s);
984 vec_add1 (s, c);
985 l++;
986 break;
987 }
988 }
989
990 /* Remove any extra space at end. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400991 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992 _vec_len (s) -= 1;
993
994 *result = s;
995 return index_of_last_space;
996}
997
998always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -0400999parent_path_len (char *path)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001000{
1001 word i;
1002 for (i = vec_len (path) - 1; i >= 0; i--)
1003 {
1004 if (path[i] == ' ')
1005 return i;
1006 }
1007 return ~0;
1008}
1009
Dave Barach9b8ffd92016-07-08 08:13:45 -04001010static void
1011add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001012{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001013 vlib_cli_command_t *p, *c;
1014 vlib_cli_sub_command_t *sub_c;
1015 u8 *sub_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016 word i, l;
1017
1018 p = vec_elt_at_index (cm->commands, parent_index);
1019 c = vec_elt_at_index (cm->commands, child_index);
1020
1021 l = parent_path_len (c->path);
1022 if (l == ~0)
1023 sub_name = vec_dup ((u8 *) c->path);
1024 else
1025 {
1026 ASSERT (l + 1 < vec_len (c->path));
1027 sub_name = 0;
1028 vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
1029 }
1030
1031 if (sub_name[0] == '%')
1032 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001033 uword *q;
1034 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001035
1036 /* Remove %. */
1037 vec_delete (sub_name, 1, 0);
1038
Dave Barach9b8ffd92016-07-08 08:13:45 -04001039 if (!p->sub_rule_index_by_name)
1040 p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1041 sizeof (sub_name[0]),
1042 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043 q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1044 if (q)
1045 {
1046 sr = vec_elt_at_index (p->sub_rules, q[0]);
1047 ASSERT (sr->command_index == child_index);
1048 return;
1049 }
1050
1051 q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001052 if (!q)
Ed Warnicke853e7202016-08-12 11:42:26 -07001053 {
1054 clib_error ("reference to unknown rule `%%%v' in path `%v'",
1055 sub_name, c->path);
1056 return;
1057 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058
Dave Barach9b8ffd92016-07-08 08:13:45 -04001059 hash_set_mem (p->sub_rule_index_by_name, sub_name,
1060 vec_len (p->sub_rules));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061 vec_add2 (p->sub_rules, sr, 1);
1062 sr->name = sub_name;
1063 sr->rule_index = q[0];
1064 sr->command_index = child_index;
1065 return;
1066 }
1067
Dave Barach9b8ffd92016-07-08 08:13:45 -04001068 if (!p->sub_command_index_by_name)
1069 p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1070 sizeof (c->path[0]),
1071 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072
1073 /* Check if sub-command has already been created. */
1074 if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1075 {
1076 vec_free (sub_name);
1077 return;
1078 }
1079
1080 vec_add2 (p->sub_commands, sub_c, 1);
1081 sub_c->index = child_index;
1082 sub_c->name = sub_name;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001083 hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1084 sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085
1086 vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1087 for (i = 0; i < vec_len (sub_c->name); i++)
1088 {
1089 int n;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001090 vlib_cli_parse_position_t *pos;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091
1092 pos = vec_elt_at_index (p->sub_command_positions, i);
1093
Dave Barach9b8ffd92016-07-08 08:13:45 -04001094 if (!pos->bitmaps)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095 pos->min_char = sub_c->name[i];
1096
1097 n = sub_c->name[i] - pos->min_char;
1098 if (n < 0)
1099 {
1100 pos->min_char = sub_c->name[i];
1101 vec_insert (pos->bitmaps, -n, 0);
1102 n = 0;
1103 }
1104
1105 vec_validate (pos->bitmaps, n);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001106 pos->bitmaps[n] =
1107 clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108 }
1109}
1110
1111static void
1112vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1113{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001114 uword p_len, pi, *p;
1115 char *p_path;
1116 vlib_cli_command_t *c, *parent;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001117
1118 /* Root command (index 0) should have already been added. */
1119 ASSERT (vec_len (cm->commands) > 0);
1120
1121 c = vec_elt_at_index (cm->commands, ci);
1122 p_len = parent_path_len (c->path);
1123
Dave Barach9b8ffd92016-07-08 08:13:45 -04001124 /* No space? Parent is root command. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125 if (p_len == ~0)
1126 {
1127 add_sub_command (cm, 0, ci);
1128 return;
1129 }
1130
1131 p_path = 0;
1132 vec_add (p_path, c->path, p_len);
1133
1134 p = hash_get_mem (cm->command_index_by_path, p_path);
1135
1136 /* Parent exists? */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001137 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001138 {
1139 /* Parent does not exist; create it. */
1140 vec_add2 (cm->commands, parent, 1);
1141 parent->path = p_path;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001142 hash_set_mem (cm->command_index_by_path, parent->path,
1143 parent - cm->commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144 pi = parent - cm->commands;
1145 }
1146 else
1147 {
1148 pi = p[0];
1149 vec_free (p_path);
1150 }
1151
1152 add_sub_command (cm, pi, ci);
1153
1154 /* Create parent's parent. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001155 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156 vlib_cli_make_parent (cm, pi);
1157}
1158
1159always_inline uword
1160vlib_cli_command_is_empty (vlib_cli_command_t * c)
1161{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001162 return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163}
1164
Dave Barach9b8ffd92016-07-08 08:13:45 -04001165clib_error_t *
1166vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001168 vlib_cli_main_t *cm = &vm->cli_main;
1169 clib_error_t *error = 0;
1170 uword ci, *p;
1171 char *normalized_path;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
1173 if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1174 return error;
1175
1176 (void) vlib_cli_normalize_path (c->path, &normalized_path);
1177
Dave Barach9b8ffd92016-07-08 08:13:45 -04001178 if (!cm->command_index_by_path)
1179 cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180 sizeof (c->path[0]),
1181 sizeof (uword));
1182
1183 /* See if command already exists with given path. */
1184 p = hash_get_mem (cm->command_index_by_path, normalized_path);
1185 if (p)
1186 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001187 vlib_cli_command_t *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188
1189 ci = p[0];
1190 d = vec_elt_at_index (cm->commands, ci);
1191
1192 /* If existing command was created via vlib_cli_make_parent
Dave Barach9b8ffd92016-07-08 08:13:45 -04001193 replaced it with callers data. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001194 if (vlib_cli_command_is_empty (d))
1195 {
1196 vlib_cli_command_t save = d[0];
1197
Dave Barach9b8ffd92016-07-08 08:13:45 -04001198 ASSERT (!vlib_cli_command_is_empty (c));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
1200 /* Copy callers fields. */
1201 d[0] = c[0];
1202
1203 /* Save internal fields. */
1204 d->path = save.path;
1205 d->sub_commands = save.sub_commands;
1206 d->sub_command_index_by_name = save.sub_command_index_by_name;
1207 d->sub_command_positions = save.sub_command_positions;
1208 d->sub_rules = save.sub_rules;
1209 }
1210 else
Dave Barach9b8ffd92016-07-08 08:13:45 -04001211 error =
1212 clib_error_return (0, "duplicate command name with path %v",
1213 normalized_path);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214
1215 vec_free (normalized_path);
1216 if (error)
1217 return error;
1218 }
1219 else
1220 {
1221 /* Command does not exist: create it. */
1222
1223 /* Add root command (index 0). */
1224 if (vec_len (cm->commands) == 0)
1225 {
1226 /* Create command with index 0; path is empty string. */
1227 vec_resize (cm->commands, 1);
1228 }
1229
1230 ci = vec_len (cm->commands);
1231 hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1232 vec_add1 (cm->commands, c[0]);
1233
1234 c = vec_elt_at_index (cm->commands, ci);
1235 c->path = normalized_path;
1236
1237 /* Don't inherit from registration. */
1238 c->sub_commands = 0;
1239 c->sub_command_index_by_name = 0;
1240 c->sub_command_positions = 0;
1241 }
1242
1243 vlib_cli_make_parent (cm, ci);
1244 return 0;
1245}
1246
1247clib_error_t *
1248vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1249{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001250 vlib_cli_main_t *cm = &vm->cli_main;
1251 vlib_cli_parse_rule_t *r;
1252 clib_error_t *error = 0;
1253 u8 *r_name;
1254 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001255
Dave Barach9b8ffd92016-07-08 08:13:45 -04001256 if (!cm->parse_rule_index_by_name)
1257 cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258 sizeof (r->name[0]),
1259 sizeof (uword));
1260
1261 /* Make vector copy of name. */
1262 r_name = format (0, "%s", r_reg->name);
1263
1264 if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1265 {
1266 vec_free (r_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001267 return clib_error_return (0, "duplicate parse rule name `%s'",
1268 r_reg->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001269 }
1270
1271 vec_add2 (cm->parse_rules, r, 1);
1272 r[0] = r_reg[0];
1273 r->name = (char *) r_name;
1274 hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1275
1276 return error;
1277}
1278
1279#if 0
1280/* $$$ turn back on again someday, maybe */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001281static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1282 vlib_cli_parse_rule_t *
1283 lo,
1284 vlib_cli_parse_rule_t *
1285 hi)
1286 __attribute__ ((unused))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001287{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001288 clib_error_t *error = 0;
1289 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
1291 for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1292 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001293 if (!r->name || strlen (r->name) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294 {
1295 error = clib_error_return (0, "parse rule with no name");
1296 goto done;
1297 }
1298
1299 error = vlib_cli_register_parse_rule (vm, r);
1300 if (error)
1301 goto done;
1302 }
1303
Dave Barach9b8ffd92016-07-08 08:13:45 -04001304done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305 return error;
1306}
1307#endif
1308
Damjan Marion9c2b9f42017-04-21 13:56:40 +02001309static int
1310cli_path_compare (void *a1, void *a2)
1311{
1312 u8 **s1 = a1;
1313 u8 **s2 = a2;
1314
1315 if ((vec_len (*s1) < vec_len (*s2)) &&
1316 memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1317 return -1;
1318
1319
1320 if ((vec_len (*s1) > vec_len (*s2)) &&
1321 memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1322 return 1;
1323
1324 return vec_cmp (*s1, *s2);
1325}
1326
1327static clib_error_t *
1328show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1329 vlib_cli_command_t * cmd)
1330{
1331 vlib_cli_main_t *cm = &vm->cli_main;
1332 vlib_cli_command_t *cli;
1333 u8 **paths = 0, **s;
1334
1335 /* *INDENT-OFF* */
1336 vec_foreach (cli, cm->commands)
1337 if (vec_len (cli->path) > 0)
1338 vec_add1 (paths, (u8 *) cli->path);
1339
1340 vec_sort_with_function (paths, cli_path_compare);
1341
1342 vec_foreach (s, paths)
1343 vlib_cli_output (vm, "%v", *s);
1344 /* *INDENT-ON* */
1345
1346 vec_free (paths);
1347 return 0;
1348}
1349
1350/* *INDENT-OFF* */
1351VLIB_CLI_COMMAND (show_cli_command, static) = {
1352 .path = "show cli",
1353 .short_help = "Show cli commands",
1354 .function = show_cli_cmd_fn,
1355};
1356/* *INDENT-ON* */
1357
Dave Barach9b8ffd92016-07-08 08:13:45 -04001358static clib_error_t *
1359vlib_cli_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001360{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001361 vlib_cli_main_t *cm = &vm->cli_main;
1362 clib_error_t *error = 0;
1363 vlib_cli_command_t *cmd;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364
1365 cmd = cm->cli_command_registrations;
1366
1367 while (cmd)
1368 {
1369 error = vlib_cli_register (vm, cmd);
1370 if (error)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001371 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372 cmd = cmd->next_cli_command;
1373 }
1374 return error;
1375}
1376
1377VLIB_INIT_FUNCTION (vlib_cli_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001378
1379/*
1380 * fd.io coding-style-patch-verification: ON
1381 *
1382 * Local Variables:
1383 * eval: (c-set-style "gnu")
1384 * End:
1385 */