blob: 48cf0426488a609bdf8a6f581c05951a3bed0317 [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
702static clib_error_t *
703show_memory_usage (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400704 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705{
706 int verbose = 0;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400707 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708 u32 index = 0;
709
Dave Barach9b8ffd92016-07-08 08:13:45 -0400710 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400712 if (unformat (input, "verbose"))
713 verbose = 1;
714 else
715 {
716 error = clib_error_return (0, "unknown input `%U'",
717 format_unformat_error, input);
718 return error;
719 }
720 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721
Dave Barach9b8ffd92016-07-08 08:13:45 -0400722 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723 foreach_vlib_main (
724 ({
725 vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
726 vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
727 index++;
728 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400729 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700730 return 0;
731}
732
Dave Barach9b8ffd92016-07-08 08:13:45 -0400733/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
735 .path = "show memory",
736 .short_help = "Show current memory usage",
737 .function = show_memory_usage,
738};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400739/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740
741static clib_error_t *
Damjan Marioneccf5092016-11-18 16:59:24 +0100742show_cpu (vlib_main_t * vm, unformat_input_t * input,
743 vlib_cli_command_t * cmd)
744{
745#define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
746 _("Model name", "%U", format_cpu_model_name);
747 _("Microarchitecture", "%U", format_cpu_uarch);
748 _("Flags", "%U", format_cpu_flags);
749 _("Base frequency", "%.2f GHz",
750 ((f64) vm->clib_time.clocks_per_second) * 1e-9);
751#undef _
752 return 0;
753}
754
755/*?
756 * Displays various information about the CPU.
757 *
758 * @cliexpar
759 * @cliexstart{show cpu}
760 * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
761 * Microarchitecture: Broadwell (Broadwell-EP/EX)
762 * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
763 * Base Frequency: 3.20 GHz
764 * @cliexend
765?*/
766/* *INDENT-OFF* */
767VLIB_CLI_COMMAND (show_cpu_command, static) = {
768 .path = "show cpu",
769 .short_help = "Show cpu information",
770 .function = show_cpu,
771};
772
773/* *INDENT-ON* */
774static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700775enable_disable_memory_trace (vlib_main_t * vm,
776 unformat_input_t * input,
777 vlib_cli_command_t * cmd)
778{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400779 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780 int enable;
781
Dave Barach9b8ffd92016-07-08 08:13:45 -0400782 if (!unformat_user (input, unformat_vlib_enable_disable, &enable))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783 {
784 error = clib_error_return (0, "expecting enable/on or disable/off");
785 goto done;
786 }
787
788 clib_mem_trace (enable);
789
Dave Barach9b8ffd92016-07-08 08:13:45 -0400790done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 return error;
792}
793
Dave Barach9b8ffd92016-07-08 08:13:45 -0400794/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700795VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
796 .path = "memory-trace",
797 .short_help = "Enable/disable memory allocation trace",
798 .function = enable_disable_memory_trace,
799};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400800/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801
802
803static clib_error_t *
804test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400805 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400807 clib_error_t *error = 0;
808 void *heap;
809 mheap_t *mheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810
Dave Barach9b8ffd92016-07-08 08:13:45 -0400811 if (unformat (input, "on"))
812 {
813 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700814 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200815 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816 mheap = mheap_header(heap);
817 mheap->flags |= MHEAP_FLAG_VALIDATE;
818 // Turn off small object cache because it delays detection of errors
819 mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
820 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400821 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822
Dave Barach9b8ffd92016-07-08 08:13:45 -0400823 }
824 else if (unformat (input, "off"))
825 {
826 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200828 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700829 mheap = mheap_header(heap);
830 mheap->flags &= ~MHEAP_FLAG_VALIDATE;
831 mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
832 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400833 /* *INDENT-ON* */
834 }
835 else if (unformat (input, "now"))
836 {
837 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200839 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700840 mheap = mheap_header(heap);
841 mheap_validate(heap);
842 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400843 /* *INDENT-ON* */
844 vlib_cli_output (vm, "heap validation complete");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700845
Dave Barach9b8ffd92016-07-08 08:13:45 -0400846 }
847 else
848 {
849 return clib_error_return (0, "unknown input `%U'",
850 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700851 }
852
Dave Barach9b8ffd92016-07-08 08:13:45 -0400853 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854}
855
Dave Barach9b8ffd92016-07-08 08:13:45 -0400856/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
858 .path = "test heap-validate",
859 .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
860 .function = test_heap_validate,
861};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400862/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863
Damjan Marione5ef1d72017-03-02 12:33:48 +0100864static clib_error_t *
865restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
866 vlib_cli_command_t * cmd)
867{
868 char *newenviron[] = { NULL };
869
870 execve (vm->name, (char **) vm->argv, newenviron);
871
872 return 0;
873}
874
875/* *INDENT-OFF* */
876VLIB_CLI_COMMAND (restart_cmd,static) = {
877 .path = "restart",
878 .short_help = "restart process",
879 .function = restart_cmd_fn,
880};
881/* *INDENT-ON* */
882
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000883#ifdef TEST_CODE
884/*
885 * A trivial test harness to verify the per-process output_function
886 * is working correcty.
887 */
888
889static clib_error_t *
890sleep_ten_seconds (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400891 unformat_input_t * input, vlib_cli_command_t * cmd)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000892{
893 u16 i;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400894 u16 my_id = rand ();
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000895
Dave Barach9b8ffd92016-07-08 08:13:45 -0400896 vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000897
Dave Barach9b8ffd92016-07-08 08:13:45 -0400898 for (i = 0; i < 10; i++)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000899 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400900 vlib_process_wait_for_event_or_clock (vm, 1.0);
901 vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000902 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400903 vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000904 return 0;
905}
906
Dave Barach9b8ffd92016-07-08 08:13:45 -0400907/* *INDENT-OFF* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000908VLIB_CLI_COMMAND (ping_command, static) = {
909 .path = "test sleep",
910 .function = sleep_ten_seconds,
911 .short_help = "Sleep for 10 seconds",
912};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400913/* *INDENT-ON* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000914#endif /* ifdef TEST_CODE */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915
Dave Barach9b8ffd92016-07-08 08:13:45 -0400916static uword
917vlib_cli_normalize_path (char *input, char **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400919 char *i = input;
920 char *s = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700921 uword l = 0;
922 uword index_of_last_space = ~0;
923
924 while (*i != 0)
925 {
926 u8 c = *i++;
927 /* Multiple white space -> single space. */
928 switch (c)
929 {
930 case ' ':
931 case '\t':
932 case '\n':
933 case '\r':
Dave Barach9b8ffd92016-07-08 08:13:45 -0400934 if (l > 0 && s[l - 1] != ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700935 {
936 vec_add1 (s, ' ');
937 l++;
938 }
939 break;
940
941 default:
Dave Barach9b8ffd92016-07-08 08:13:45 -0400942 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943 index_of_last_space = vec_len (s);
944 vec_add1 (s, c);
945 l++;
946 break;
947 }
948 }
949
950 /* Remove any extra space at end. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400951 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952 _vec_len (s) -= 1;
953
954 *result = s;
955 return index_of_last_space;
956}
957
958always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -0400959parent_path_len (char *path)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960{
961 word i;
962 for (i = vec_len (path) - 1; i >= 0; i--)
963 {
964 if (path[i] == ' ')
965 return i;
966 }
967 return ~0;
968}
969
Dave Barach9b8ffd92016-07-08 08:13:45 -0400970static void
971add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400973 vlib_cli_command_t *p, *c;
974 vlib_cli_sub_command_t *sub_c;
975 u8 *sub_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976 word i, l;
977
978 p = vec_elt_at_index (cm->commands, parent_index);
979 c = vec_elt_at_index (cm->commands, child_index);
980
981 l = parent_path_len (c->path);
982 if (l == ~0)
983 sub_name = vec_dup ((u8 *) c->path);
984 else
985 {
986 ASSERT (l + 1 < vec_len (c->path));
987 sub_name = 0;
988 vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
989 }
990
991 if (sub_name[0] == '%')
992 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400993 uword *q;
994 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995
996 /* Remove %. */
997 vec_delete (sub_name, 1, 0);
998
Dave Barach9b8ffd92016-07-08 08:13:45 -0400999 if (!p->sub_rule_index_by_name)
1000 p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1001 sizeof (sub_name[0]),
1002 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001003 q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1004 if (q)
1005 {
1006 sr = vec_elt_at_index (p->sub_rules, q[0]);
1007 ASSERT (sr->command_index == child_index);
1008 return;
1009 }
1010
1011 q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001012 if (!q)
Ed Warnicke853e7202016-08-12 11:42:26 -07001013 {
1014 clib_error ("reference to unknown rule `%%%v' in path `%v'",
1015 sub_name, c->path);
1016 return;
1017 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001018
Dave Barach9b8ffd92016-07-08 08:13:45 -04001019 hash_set_mem (p->sub_rule_index_by_name, sub_name,
1020 vec_len (p->sub_rules));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001021 vec_add2 (p->sub_rules, sr, 1);
1022 sr->name = sub_name;
1023 sr->rule_index = q[0];
1024 sr->command_index = child_index;
1025 return;
1026 }
1027
Dave Barach9b8ffd92016-07-08 08:13:45 -04001028 if (!p->sub_command_index_by_name)
1029 p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1030 sizeof (c->path[0]),
1031 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032
1033 /* Check if sub-command has already been created. */
1034 if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1035 {
1036 vec_free (sub_name);
1037 return;
1038 }
1039
1040 vec_add2 (p->sub_commands, sub_c, 1);
1041 sub_c->index = child_index;
1042 sub_c->name = sub_name;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001043 hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1044 sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045
1046 vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1047 for (i = 0; i < vec_len (sub_c->name); i++)
1048 {
1049 int n;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001050 vlib_cli_parse_position_t *pos;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051
1052 pos = vec_elt_at_index (p->sub_command_positions, i);
1053
Dave Barach9b8ffd92016-07-08 08:13:45 -04001054 if (!pos->bitmaps)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055 pos->min_char = sub_c->name[i];
1056
1057 n = sub_c->name[i] - pos->min_char;
1058 if (n < 0)
1059 {
1060 pos->min_char = sub_c->name[i];
1061 vec_insert (pos->bitmaps, -n, 0);
1062 n = 0;
1063 }
1064
1065 vec_validate (pos->bitmaps, n);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001066 pos->bitmaps[n] =
1067 clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068 }
1069}
1070
1071static void
1072vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1073{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001074 uword p_len, pi, *p;
1075 char *p_path;
1076 vlib_cli_command_t *c, *parent;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077
1078 /* Root command (index 0) should have already been added. */
1079 ASSERT (vec_len (cm->commands) > 0);
1080
1081 c = vec_elt_at_index (cm->commands, ci);
1082 p_len = parent_path_len (c->path);
1083
Dave Barach9b8ffd92016-07-08 08:13:45 -04001084 /* No space? Parent is root command. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 if (p_len == ~0)
1086 {
1087 add_sub_command (cm, 0, ci);
1088 return;
1089 }
1090
1091 p_path = 0;
1092 vec_add (p_path, c->path, p_len);
1093
1094 p = hash_get_mem (cm->command_index_by_path, p_path);
1095
1096 /* Parent exists? */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001097 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098 {
1099 /* Parent does not exist; create it. */
1100 vec_add2 (cm->commands, parent, 1);
1101 parent->path = p_path;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001102 hash_set_mem (cm->command_index_by_path, parent->path,
1103 parent - cm->commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104 pi = parent - cm->commands;
1105 }
1106 else
1107 {
1108 pi = p[0];
1109 vec_free (p_path);
1110 }
1111
1112 add_sub_command (cm, pi, ci);
1113
1114 /* Create parent's parent. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001115 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 vlib_cli_make_parent (cm, pi);
1117}
1118
1119always_inline uword
1120vlib_cli_command_is_empty (vlib_cli_command_t * c)
1121{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001122 return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123}
1124
Dave Barach9b8ffd92016-07-08 08:13:45 -04001125clib_error_t *
1126vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001128 vlib_cli_main_t *cm = &vm->cli_main;
1129 clib_error_t *error = 0;
1130 uword ci, *p;
1131 char *normalized_path;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132
1133 if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1134 return error;
1135
1136 (void) vlib_cli_normalize_path (c->path, &normalized_path);
1137
Dave Barach9b8ffd92016-07-08 08:13:45 -04001138 if (!cm->command_index_by_path)
1139 cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140 sizeof (c->path[0]),
1141 sizeof (uword));
1142
1143 /* See if command already exists with given path. */
1144 p = hash_get_mem (cm->command_index_by_path, normalized_path);
1145 if (p)
1146 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001147 vlib_cli_command_t *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148
1149 ci = p[0];
1150 d = vec_elt_at_index (cm->commands, ci);
1151
1152 /* If existing command was created via vlib_cli_make_parent
Dave Barach9b8ffd92016-07-08 08:13:45 -04001153 replaced it with callers data. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154 if (vlib_cli_command_is_empty (d))
1155 {
1156 vlib_cli_command_t save = d[0];
1157
Dave Barach9b8ffd92016-07-08 08:13:45 -04001158 ASSERT (!vlib_cli_command_is_empty (c));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001159
1160 /* Copy callers fields. */
1161 d[0] = c[0];
1162
1163 /* Save internal fields. */
1164 d->path = save.path;
1165 d->sub_commands = save.sub_commands;
1166 d->sub_command_index_by_name = save.sub_command_index_by_name;
1167 d->sub_command_positions = save.sub_command_positions;
1168 d->sub_rules = save.sub_rules;
1169 }
1170 else
Dave Barach9b8ffd92016-07-08 08:13:45 -04001171 error =
1172 clib_error_return (0, "duplicate command name with path %v",
1173 normalized_path);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174
1175 vec_free (normalized_path);
1176 if (error)
1177 return error;
1178 }
1179 else
1180 {
1181 /* Command does not exist: create it. */
1182
1183 /* Add root command (index 0). */
1184 if (vec_len (cm->commands) == 0)
1185 {
1186 /* Create command with index 0; path is empty string. */
1187 vec_resize (cm->commands, 1);
1188 }
1189
1190 ci = vec_len (cm->commands);
1191 hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1192 vec_add1 (cm->commands, c[0]);
1193
1194 c = vec_elt_at_index (cm->commands, ci);
1195 c->path = normalized_path;
1196
1197 /* Don't inherit from registration. */
1198 c->sub_commands = 0;
1199 c->sub_command_index_by_name = 0;
1200 c->sub_command_positions = 0;
1201 }
1202
1203 vlib_cli_make_parent (cm, ci);
1204 return 0;
1205}
1206
1207clib_error_t *
1208vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1209{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001210 vlib_cli_main_t *cm = &vm->cli_main;
1211 vlib_cli_parse_rule_t *r;
1212 clib_error_t *error = 0;
1213 u8 *r_name;
1214 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001215
Dave Barach9b8ffd92016-07-08 08:13:45 -04001216 if (!cm->parse_rule_index_by_name)
1217 cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001218 sizeof (r->name[0]),
1219 sizeof (uword));
1220
1221 /* Make vector copy of name. */
1222 r_name = format (0, "%s", r_reg->name);
1223
1224 if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1225 {
1226 vec_free (r_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001227 return clib_error_return (0, "duplicate parse rule name `%s'",
1228 r_reg->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229 }
1230
1231 vec_add2 (cm->parse_rules, r, 1);
1232 r[0] = r_reg[0];
1233 r->name = (char *) r_name;
1234 hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1235
1236 return error;
1237}
1238
1239#if 0
1240/* $$$ turn back on again someday, maybe */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001241static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1242 vlib_cli_parse_rule_t *
1243 lo,
1244 vlib_cli_parse_rule_t *
1245 hi)
1246 __attribute__ ((unused))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001248 clib_error_t *error = 0;
1249 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001250
1251 for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1252 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001253 if (!r->name || strlen (r->name) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254 {
1255 error = clib_error_return (0, "parse rule with no name");
1256 goto done;
1257 }
1258
1259 error = vlib_cli_register_parse_rule (vm, r);
1260 if (error)
1261 goto done;
1262 }
1263
Dave Barach9b8ffd92016-07-08 08:13:45 -04001264done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001265 return error;
1266}
1267#endif
1268
Damjan Marion9c2b9f42017-04-21 13:56:40 +02001269static int
1270cli_path_compare (void *a1, void *a2)
1271{
1272 u8 **s1 = a1;
1273 u8 **s2 = a2;
1274
1275 if ((vec_len (*s1) < vec_len (*s2)) &&
1276 memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1277 return -1;
1278
1279
1280 if ((vec_len (*s1) > vec_len (*s2)) &&
1281 memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1282 return 1;
1283
1284 return vec_cmp (*s1, *s2);
1285}
1286
1287static clib_error_t *
1288show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1289 vlib_cli_command_t * cmd)
1290{
1291 vlib_cli_main_t *cm = &vm->cli_main;
1292 vlib_cli_command_t *cli;
1293 u8 **paths = 0, **s;
1294
1295 /* *INDENT-OFF* */
1296 vec_foreach (cli, cm->commands)
1297 if (vec_len (cli->path) > 0)
1298 vec_add1 (paths, (u8 *) cli->path);
1299
1300 vec_sort_with_function (paths, cli_path_compare);
1301
1302 vec_foreach (s, paths)
1303 vlib_cli_output (vm, "%v", *s);
1304 /* *INDENT-ON* */
1305
1306 vec_free (paths);
1307 return 0;
1308}
1309
1310/* *INDENT-OFF* */
1311VLIB_CLI_COMMAND (show_cli_command, static) = {
1312 .path = "show cli",
1313 .short_help = "Show cli commands",
1314 .function = show_cli_cmd_fn,
1315};
1316/* *INDENT-ON* */
1317
Dave Barach9b8ffd92016-07-08 08:13:45 -04001318static clib_error_t *
1319vlib_cli_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001320{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001321 vlib_cli_main_t *cm = &vm->cli_main;
1322 clib_error_t *error = 0;
1323 vlib_cli_command_t *cmd;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001324
1325 cmd = cm->cli_command_registrations;
1326
1327 while (cmd)
1328 {
1329 error = vlib_cli_register (vm, cmd);
1330 if (error)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001331 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332 cmd = cmd->next_cli_command;
1333 }
1334 return error;
1335}
1336
1337VLIB_INIT_FUNCTION (vlib_cli_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001338
1339/*
1340 * fd.io coding-style-patch-verification: ON
1341 *
1342 * Local Variables:
1343 * eval: (c-set-style "gnu")
1344 * End:
1345 */