blob: 9e14bee219e06d711f9f10aade9a09511df13ce7 [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
336 vec_sort_with_function (result, vlib_cli_cmp_strings);
337 return result;
338}
339
Dave Barach9b8ffd92016-07-08 08:13:45 -0400340static u8 *
341format_vlib_cli_command_help (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400343 vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344 int is_long = va_arg (*args, int);
345 if (is_long && c->long_help)
346 s = format (s, "%s", c->long_help);
347 else if (c->short_help)
348 s = format (s, "%s", c->short_help);
349 else
350 s = format (s, "%v commands", c->path);
351 return s;
352}
353
Dave Barach9b8ffd92016-07-08 08:13:45 -0400354static u8 *
355format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400357 vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358 return format (s, "<%U>", format_c_identifier, r->name);
359}
360
Dave Barach9b8ffd92016-07-08 08:13:45 -0400361static u8 *
362format_vlib_cli_path (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700363{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400364 u8 *path = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365 int i, in_rule;
366 in_rule = 0;
367 for (i = 0; i < vec_len (path); i++)
368 {
369 switch (path[i])
370 {
371 case '%':
372 in_rule = 1;
373 vec_add1 (s, '<'); /* start of <RULE> */
374 break;
375
376 case '_':
377 /* _ -> space in rules. */
378 vec_add1 (s, in_rule ? ' ' : '_');
379 break;
380
381 case ' ':
382 if (in_rule)
383 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400384 vec_add1 (s, '>'); /* end of <RULE> */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385 in_rule = 0;
386 }
387 vec_add1 (s, ' ');
388 break;
389
390 default:
391 vec_add1 (s, path[i]);
392 break;
393 }
394 }
395
396 if (in_rule)
397 vec_add1 (s, '>'); /* terminate <RULE> */
398
399 return s;
400}
401
402static vlib_cli_command_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400403all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400405 vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
406 vlib_cli_sub_command_t *sc;
407 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408
409 if (c->function)
410 vec_add1 (subs, c[0]);
411
412 vec_foreach (sr, c->sub_rules)
413 subs = all_subs (cm, subs, sr->command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400414 vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415
416 return subs;
417}
418
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500419static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400420vlib_cli_cmp_rule (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500421{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400422 vlib_cli_sub_rule_t *r1 = a1;
423 vlib_cli_sub_rule_t *r2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500424
425 return vec_cmp (r1->name, r2->name);
426}
427
428static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400429vlib_cli_cmp_command (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500430{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400431 vlib_cli_command_t *c1 = a1;
432 vlib_cli_command_t *c2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500433
434 return vec_cmp (c1->path, c2->path);
435}
436
Ed Warnickecb9cada2015-12-08 15:45:58 -0700437static clib_error_t *
438vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
439 vlib_cli_main_t * cm,
440 unformat_input_t * input,
441 uword parent_command_index)
442{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400443 vlib_cli_command_t *parent, *c;
444 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700445 unformat_input_t sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400446 u8 *string;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447 uword is_main_dispatch = cm == &vm->cli_main;
448
449 parent = vec_elt_at_index (cm->commands, parent_command_index);
450 if (is_main_dispatch && unformat (input, "help"))
451 {
452 uword help_at_end_of_line, i;
453
Dave Barach9b8ffd92016-07-08 08:13:45 -0400454 help_at_end_of_line =
455 unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456 while (1)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400457 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458 c = parent;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400459 if (unformat_user
460 (input, unformat_vlib_cli_sub_command, vm, c, &parent))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461 ;
462
Dave Barach9b8ffd92016-07-08 08:13:45 -0400463 else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464 goto unknown;
465
466 else
467 break;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400468 }
469
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470 /* help SUB-COMMAND => long format help.
Dave Barach9b8ffd92016-07-08 08:13:45 -0400471 "help" at end of line: show all commands. */
472 if (!help_at_end_of_line)
473 vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
474 /* is_long */ 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475
476 else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
477 vlib_cli_output (vm, "%v: no sub-commands", c->path);
478
479 else
480 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400481 vlib_cli_sub_command_t *sc;
482 vlib_cli_sub_rule_t *sr, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483
484 subs = vec_dup (c->sub_rules);
485
486 /* Add in rules if any. */
487 vec_foreach (sc, c->sub_commands)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400488 {
489 vec_add2 (subs, sr, 1);
490 sr->name = sc->name;
491 sr->command_index = sc->index;
492 sr->rule_index = ~0;
493 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500495 vec_sort_with_function (subs, vlib_cli_cmp_rule);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496
Dave Barach9b8ffd92016-07-08 08:13:45 -0400497 for (i = 0; i < vec_len (subs); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400499 vlib_cli_command_t *d;
500 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501
502 d = vec_elt_at_index (cm->commands, subs[i].command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400503 r =
504 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
505 subs
506 [i].rule_index) :
507 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508
509 if (r)
510 vlib_cli_output
511 (vm, " %-30U %U",
512 format_vlib_cli_parse_rule_name, r,
513 format_vlib_cli_command_help, d, /* is_long */ 0);
514 else
515 vlib_cli_output
516 (vm, " %-30v %U",
517 subs[i].name,
518 format_vlib_cli_command_help, d, /* is_long */ 0);
519 }
520
521 vec_free (subs);
522 }
523 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400524
525 else if (is_main_dispatch
526 && (unformat (input, "choices") || unformat (input, "?")))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400528 vlib_cli_command_t *sub, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529
530 subs = all_subs (cm, 0, parent_command_index);
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500531 vec_sort_with_function (subs, vlib_cli_cmp_command);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532 vec_foreach (sub, subs)
533 vlib_cli_output (vm, " %-40U %U",
534 format_vlib_cli_path, sub->path,
535 format_vlib_cli_command_help, sub, /* is_long */ 0);
536 vec_free (subs);
537 }
538
539 else if (unformat (input, "comment %v", &string))
540 {
541 vec_free (string);
542 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400543
Ed Warnickecb9cada2015-12-08 15:45:58 -0700544 else if (unformat (input, "uncomment %U",
545 unformat_vlib_cli_sub_input, &sub_input))
546 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400547 error =
548 vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
549 parent_command_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550 unformat_free (&sub_input);
551 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400552
553 else
554 if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400556 unformat_input_t *si;
557 uword has_sub_commands =
558 vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
559
Ed Warnickecb9cada2015-12-08 15:45:58 -0700560 si = input;
561 if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
562 si = &sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400563
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564 if (has_sub_commands)
565 error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
566
Dave Barach9b8ffd92016-07-08 08:13:45 -0400567 if (has_sub_commands && !error)
568 /* Found valid sub-command. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569
570 else if (c->function)
571 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400572 clib_error_t *c_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573
574 /* Skip white space for benefit of called function. */
575 unformat_skip_white_space (si);
576
577 if (unformat (si, "?"))
578 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400579 vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */
580 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581 }
582 else
583 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400584 if (!c->is_mp_safe)
585 vlib_worker_thread_barrier_sync (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700586
587 c_error = c->function (vm, si, c);
588
Dave Barach9b8ffd92016-07-08 08:13:45 -0400589 if (!c->is_mp_safe)
590 vlib_worker_thread_barrier_release (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700591
592 if (c_error)
593 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400594 error =
595 clib_error_return (0, "%v: %v", c->path, c_error->what);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596 clib_error_free (c_error);
597 /* Free sub input. */
598 if (si != input)
599 unformat_free (si);
600
601 return error;
602 }
603 }
604
605 /* Free any previous error. */
606 clib_error_free (error);
607 }
608
Dave Barach9b8ffd92016-07-08 08:13:45 -0400609 else if (!error)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610 error = clib_error_return (0, "%v: no sub-commands", c->path);
611
612 /* Free sub input. */
613 if (si != input)
614 unformat_free (si);
615 }
616
617 else
618 goto unknown;
619
620 return error;
621
Dave Barach9b8ffd92016-07-08 08:13:45 -0400622unknown:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623 if (parent->path)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400624 return clib_error_return (0, "%v: unknown input `%U'", parent->path,
625 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400627 return clib_error_return (0, "unknown input `%U'", format_unformat_error,
628 input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629}
630
631
Dave Barach9b8ffd92016-07-08 08:13:45 -0400632void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
633 __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634
Dave Barach9b8ffd92016-07-08 08:13:45 -0400635void
636vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
637{
638}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639
640/* Process CLI input. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400641void
642vlib_cli_input (vlib_main_t * vm,
643 unformat_input_t * input,
644 vlib_cli_output_function_t * function, uword function_arg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700645{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400646 vlib_process_t *cp = vlib_get_current_process (vm);
647 vlib_cli_main_t *cm = &vm->cli_main;
648 clib_error_t *error;
649 vlib_cli_output_function_t *save_function;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650 uword save_function_arg;
651
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000652 save_function = cp->output_function;
653 save_function_arg = cp->output_function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000655 cp->output_function = function;
656 cp->output_function_arg = function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657
Dave Barach9b8ffd92016-07-08 08:13:45 -0400658 do
659 {
660 vec_reset_length (cm->parse_rule_data);
661 error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
662 0);
663 }
664 while (!error && !unformat (input, "%U", unformat_eof));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665
666 if (error)
667 {
668 vlib_cli_output (vm, "%v", error->what);
669 vlib_unix_error_report (vm, error);
670 clib_error_free (error);
671 }
672
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000673 cp->output_function = save_function;
674 cp->output_function_arg = save_function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700675}
676
677/* Output to current CLI connection. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400678void
679vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400681 vlib_process_t *cp = vlib_get_current_process (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700682 va_list va;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400683 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684
685 va_start (va, fmt);
686 s = va_format (0, fmt, &va);
687 va_end (va);
688
689 /* Terminate with \n if not present. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400690 if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691 vec_add1 (s, '\n');
692
Dave Barach9b8ffd92016-07-08 08:13:45 -0400693 if ((!cp) || (!cp->output_function))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694 fformat (stdout, "%v", s);
695 else
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000696 cp->output_function (cp->output_function_arg, s, vec_len (s));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700697
698 vec_free (s);
699}
700
701static clib_error_t *
702show_memory_usage (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400703 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704{
705 int verbose = 0;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400706 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707 u32 index = 0;
708
Dave Barach9b8ffd92016-07-08 08:13:45 -0400709 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400711 if (unformat (input, "verbose"))
712 verbose = 1;
713 else
714 {
715 error = clib_error_return (0, "unknown input `%U'",
716 format_unformat_error, input);
717 return error;
718 }
719 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720
Dave Barach9b8ffd92016-07-08 08:13:45 -0400721 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722 foreach_vlib_main (
723 ({
724 vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
725 vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
726 index++;
727 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400728 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700729 return 0;
730}
731
Dave Barach9b8ffd92016-07-08 08:13:45 -0400732/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
734 .path = "show memory",
735 .short_help = "Show current memory usage",
736 .function = show_memory_usage,
737};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400738/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739
740static clib_error_t *
Damjan Marioneccf5092016-11-18 16:59:24 +0100741show_cpu (vlib_main_t * vm, unformat_input_t * input,
742 vlib_cli_command_t * cmd)
743{
744#define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
745 _("Model name", "%U", format_cpu_model_name);
746 _("Microarchitecture", "%U", format_cpu_uarch);
747 _("Flags", "%U", format_cpu_flags);
748 _("Base frequency", "%.2f GHz",
749 ((f64) vm->clib_time.clocks_per_second) * 1e-9);
750#undef _
751 return 0;
752}
753
754/*?
755 * Displays various information about the CPU.
756 *
757 * @cliexpar
758 * @cliexstart{show cpu}
759 * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
760 * Microarchitecture: Broadwell (Broadwell-EP/EX)
761 * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
762 * Base Frequency: 3.20 GHz
763 * @cliexend
764?*/
765/* *INDENT-OFF* */
766VLIB_CLI_COMMAND (show_cpu_command, static) = {
767 .path = "show cpu",
768 .short_help = "Show cpu information",
769 .function = show_cpu,
770};
771
772/* *INDENT-ON* */
773static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700774enable_disable_memory_trace (vlib_main_t * vm,
775 unformat_input_t * input,
776 vlib_cli_command_t * cmd)
777{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400778 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700779 int enable;
780
Dave Barach9b8ffd92016-07-08 08:13:45 -0400781 if (!unformat_user (input, unformat_vlib_enable_disable, &enable))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700782 {
783 error = clib_error_return (0, "expecting enable/on or disable/off");
784 goto done;
785 }
786
787 clib_mem_trace (enable);
788
Dave Barach9b8ffd92016-07-08 08:13:45 -0400789done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790 return error;
791}
792
Dave Barach9b8ffd92016-07-08 08:13:45 -0400793/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700794VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
795 .path = "memory-trace",
796 .short_help = "Enable/disable memory allocation trace",
797 .function = enable_disable_memory_trace,
798};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400799/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800
801
802static clib_error_t *
803test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400804 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700805{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400806 clib_error_t *error = 0;
807 void *heap;
808 mheap_t *mheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809
Dave Barach9b8ffd92016-07-08 08:13:45 -0400810 if (unformat (input, "on"))
811 {
812 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200814 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815 mheap = mheap_header(heap);
816 mheap->flags |= MHEAP_FLAG_VALIDATE;
817 // Turn off small object cache because it delays detection of errors
818 mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
819 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400820 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821
Dave Barach9b8ffd92016-07-08 08:13:45 -0400822 }
823 else if (unformat (input, "off"))
824 {
825 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700826 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200827 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828 mheap = mheap_header(heap);
829 mheap->flags &= ~MHEAP_FLAG_VALIDATE;
830 mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
831 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400832 /* *INDENT-ON* */
833 }
834 else if (unformat (input, "now"))
835 {
836 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700837 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +0200838 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839 mheap = mheap_header(heap);
840 mheap_validate(heap);
841 });
Dave Barach9b8ffd92016-07-08 08:13:45 -0400842 /* *INDENT-ON* */
843 vlib_cli_output (vm, "heap validation complete");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700844
Dave Barach9b8ffd92016-07-08 08:13:45 -0400845 }
846 else
847 {
848 return clib_error_return (0, "unknown input `%U'",
849 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700850 }
851
Dave Barach9b8ffd92016-07-08 08:13:45 -0400852 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700853}
854
Dave Barach9b8ffd92016-07-08 08:13:45 -0400855/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700856VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
857 .path = "test heap-validate",
858 .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
859 .function = test_heap_validate,
860};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400861/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862
Damjan Marione5ef1d72017-03-02 12:33:48 +0100863static clib_error_t *
864restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
865 vlib_cli_command_t * cmd)
866{
867 char *newenviron[] = { NULL };
868
869 execve (vm->name, (char **) vm->argv, newenviron);
870
871 return 0;
872}
873
874/* *INDENT-OFF* */
875VLIB_CLI_COMMAND (restart_cmd,static) = {
876 .path = "restart",
877 .short_help = "restart process",
878 .function = restart_cmd_fn,
879};
880/* *INDENT-ON* */
881
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000882#ifdef TEST_CODE
883/*
884 * A trivial test harness to verify the per-process output_function
885 * is working correcty.
886 */
887
888static clib_error_t *
889sleep_ten_seconds (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400890 unformat_input_t * input, vlib_cli_command_t * cmd)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000891{
892 u16 i;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400893 u16 my_id = rand ();
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000894
Dave Barach9b8ffd92016-07-08 08:13:45 -0400895 vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000896
Dave Barach9b8ffd92016-07-08 08:13:45 -0400897 for (i = 0; i < 10; i++)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000898 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400899 vlib_process_wait_for_event_or_clock (vm, 1.0);
900 vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000901 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400902 vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000903 return 0;
904}
905
Dave Barach9b8ffd92016-07-08 08:13:45 -0400906/* *INDENT-OFF* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000907VLIB_CLI_COMMAND (ping_command, static) = {
908 .path = "test sleep",
909 .function = sleep_ten_seconds,
910 .short_help = "Sleep for 10 seconds",
911};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400912/* *INDENT-ON* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000913#endif /* ifdef TEST_CODE */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700914
Dave Barach9b8ffd92016-07-08 08:13:45 -0400915static uword
916vlib_cli_normalize_path (char *input, char **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700917{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400918 char *i = input;
919 char *s = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700920 uword l = 0;
921 uword index_of_last_space = ~0;
922
923 while (*i != 0)
924 {
925 u8 c = *i++;
926 /* Multiple white space -> single space. */
927 switch (c)
928 {
929 case ' ':
930 case '\t':
931 case '\n':
932 case '\r':
Dave Barach9b8ffd92016-07-08 08:13:45 -0400933 if (l > 0 && s[l - 1] != ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934 {
935 vec_add1 (s, ' ');
936 l++;
937 }
938 break;
939
940 default:
Dave Barach9b8ffd92016-07-08 08:13:45 -0400941 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942 index_of_last_space = vec_len (s);
943 vec_add1 (s, c);
944 l++;
945 break;
946 }
947 }
948
949 /* Remove any extra space at end. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400950 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951 _vec_len (s) -= 1;
952
953 *result = s;
954 return index_of_last_space;
955}
956
957always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -0400958parent_path_len (char *path)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700959{
960 word i;
961 for (i = vec_len (path) - 1; i >= 0; i--)
962 {
963 if (path[i] == ' ')
964 return i;
965 }
966 return ~0;
967}
968
Dave Barach9b8ffd92016-07-08 08:13:45 -0400969static void
970add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400972 vlib_cli_command_t *p, *c;
973 vlib_cli_sub_command_t *sub_c;
974 u8 *sub_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975 word i, l;
976
977 p = vec_elt_at_index (cm->commands, parent_index);
978 c = vec_elt_at_index (cm->commands, child_index);
979
980 l = parent_path_len (c->path);
981 if (l == ~0)
982 sub_name = vec_dup ((u8 *) c->path);
983 else
984 {
985 ASSERT (l + 1 < vec_len (c->path));
986 sub_name = 0;
987 vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
988 }
989
990 if (sub_name[0] == '%')
991 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400992 uword *q;
993 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994
995 /* Remove %. */
996 vec_delete (sub_name, 1, 0);
997
Dave Barach9b8ffd92016-07-08 08:13:45 -0400998 if (!p->sub_rule_index_by_name)
999 p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1000 sizeof (sub_name[0]),
1001 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001002 q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1003 if (q)
1004 {
1005 sr = vec_elt_at_index (p->sub_rules, q[0]);
1006 ASSERT (sr->command_index == child_index);
1007 return;
1008 }
1009
1010 q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001011 if (!q)
Ed Warnicke853e7202016-08-12 11:42:26 -07001012 {
1013 clib_error ("reference to unknown rule `%%%v' in path `%v'",
1014 sub_name, c->path);
1015 return;
1016 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017
Dave Barach9b8ffd92016-07-08 08:13:45 -04001018 hash_set_mem (p->sub_rule_index_by_name, sub_name,
1019 vec_len (p->sub_rules));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020 vec_add2 (p->sub_rules, sr, 1);
1021 sr->name = sub_name;
1022 sr->rule_index = q[0];
1023 sr->command_index = child_index;
1024 return;
1025 }
1026
Dave Barach9b8ffd92016-07-08 08:13:45 -04001027 if (!p->sub_command_index_by_name)
1028 p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1029 sizeof (c->path[0]),
1030 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031
1032 /* Check if sub-command has already been created. */
1033 if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1034 {
1035 vec_free (sub_name);
1036 return;
1037 }
1038
1039 vec_add2 (p->sub_commands, sub_c, 1);
1040 sub_c->index = child_index;
1041 sub_c->name = sub_name;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001042 hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1043 sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044
1045 vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1046 for (i = 0; i < vec_len (sub_c->name); i++)
1047 {
1048 int n;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001049 vlib_cli_parse_position_t *pos;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050
1051 pos = vec_elt_at_index (p->sub_command_positions, i);
1052
Dave Barach9b8ffd92016-07-08 08:13:45 -04001053 if (!pos->bitmaps)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 pos->min_char = sub_c->name[i];
1055
1056 n = sub_c->name[i] - pos->min_char;
1057 if (n < 0)
1058 {
1059 pos->min_char = sub_c->name[i];
1060 vec_insert (pos->bitmaps, -n, 0);
1061 n = 0;
1062 }
1063
1064 vec_validate (pos->bitmaps, n);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001065 pos->bitmaps[n] =
1066 clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067 }
1068}
1069
1070static void
1071vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1072{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001073 uword p_len, pi, *p;
1074 char *p_path;
1075 vlib_cli_command_t *c, *parent;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076
1077 /* Root command (index 0) should have already been added. */
1078 ASSERT (vec_len (cm->commands) > 0);
1079
1080 c = vec_elt_at_index (cm->commands, ci);
1081 p_len = parent_path_len (c->path);
1082
Dave Barach9b8ffd92016-07-08 08:13:45 -04001083 /* No space? Parent is root command. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 if (p_len == ~0)
1085 {
1086 add_sub_command (cm, 0, ci);
1087 return;
1088 }
1089
1090 p_path = 0;
1091 vec_add (p_path, c->path, p_len);
1092
1093 p = hash_get_mem (cm->command_index_by_path, p_path);
1094
1095 /* Parent exists? */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001096 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097 {
1098 /* Parent does not exist; create it. */
1099 vec_add2 (cm->commands, parent, 1);
1100 parent->path = p_path;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001101 hash_set_mem (cm->command_index_by_path, parent->path,
1102 parent - cm->commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103 pi = parent - cm->commands;
1104 }
1105 else
1106 {
1107 pi = p[0];
1108 vec_free (p_path);
1109 }
1110
1111 add_sub_command (cm, pi, ci);
1112
1113 /* Create parent's parent. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001114 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115 vlib_cli_make_parent (cm, pi);
1116}
1117
1118always_inline uword
1119vlib_cli_command_is_empty (vlib_cli_command_t * c)
1120{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001121 return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122}
1123
Dave Barach9b8ffd92016-07-08 08:13:45 -04001124clib_error_t *
1125vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001127 vlib_cli_main_t *cm = &vm->cli_main;
1128 clib_error_t *error = 0;
1129 uword ci, *p;
1130 char *normalized_path;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001131
1132 if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1133 return error;
1134
1135 (void) vlib_cli_normalize_path (c->path, &normalized_path);
1136
Dave Barach9b8ffd92016-07-08 08:13:45 -04001137 if (!cm->command_index_by_path)
1138 cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001139 sizeof (c->path[0]),
1140 sizeof (uword));
1141
1142 /* See if command already exists with given path. */
1143 p = hash_get_mem (cm->command_index_by_path, normalized_path);
1144 if (p)
1145 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001146 vlib_cli_command_t *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001147
1148 ci = p[0];
1149 d = vec_elt_at_index (cm->commands, ci);
1150
1151 /* If existing command was created via vlib_cli_make_parent
Dave Barach9b8ffd92016-07-08 08:13:45 -04001152 replaced it with callers data. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153 if (vlib_cli_command_is_empty (d))
1154 {
1155 vlib_cli_command_t save = d[0];
1156
Dave Barach9b8ffd92016-07-08 08:13:45 -04001157 ASSERT (!vlib_cli_command_is_empty (c));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158
1159 /* Copy callers fields. */
1160 d[0] = c[0];
1161
1162 /* Save internal fields. */
1163 d->path = save.path;
1164 d->sub_commands = save.sub_commands;
1165 d->sub_command_index_by_name = save.sub_command_index_by_name;
1166 d->sub_command_positions = save.sub_command_positions;
1167 d->sub_rules = save.sub_rules;
1168 }
1169 else
Dave Barach9b8ffd92016-07-08 08:13:45 -04001170 error =
1171 clib_error_return (0, "duplicate command name with path %v",
1172 normalized_path);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
1174 vec_free (normalized_path);
1175 if (error)
1176 return error;
1177 }
1178 else
1179 {
1180 /* Command does not exist: create it. */
1181
1182 /* Add root command (index 0). */
1183 if (vec_len (cm->commands) == 0)
1184 {
1185 /* Create command with index 0; path is empty string. */
1186 vec_resize (cm->commands, 1);
1187 }
1188
1189 ci = vec_len (cm->commands);
1190 hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1191 vec_add1 (cm->commands, c[0]);
1192
1193 c = vec_elt_at_index (cm->commands, ci);
1194 c->path = normalized_path;
1195
1196 /* Don't inherit from registration. */
1197 c->sub_commands = 0;
1198 c->sub_command_index_by_name = 0;
1199 c->sub_command_positions = 0;
1200 }
1201
1202 vlib_cli_make_parent (cm, ci);
1203 return 0;
1204}
1205
1206clib_error_t *
1207vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1208{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001209 vlib_cli_main_t *cm = &vm->cli_main;
1210 vlib_cli_parse_rule_t *r;
1211 clib_error_t *error = 0;
1212 u8 *r_name;
1213 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214
Dave Barach9b8ffd92016-07-08 08:13:45 -04001215 if (!cm->parse_rule_index_by_name)
1216 cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001217 sizeof (r->name[0]),
1218 sizeof (uword));
1219
1220 /* Make vector copy of name. */
1221 r_name = format (0, "%s", r_reg->name);
1222
1223 if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1224 {
1225 vec_free (r_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001226 return clib_error_return (0, "duplicate parse rule name `%s'",
1227 r_reg->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228 }
1229
1230 vec_add2 (cm->parse_rules, r, 1);
1231 r[0] = r_reg[0];
1232 r->name = (char *) r_name;
1233 hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1234
1235 return error;
1236}
1237
1238#if 0
1239/* $$$ turn back on again someday, maybe */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001240static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1241 vlib_cli_parse_rule_t *
1242 lo,
1243 vlib_cli_parse_rule_t *
1244 hi)
1245 __attribute__ ((unused))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001246{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001247 clib_error_t *error = 0;
1248 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249
1250 for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1251 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001252 if (!r->name || strlen (r->name) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253 {
1254 error = clib_error_return (0, "parse rule with no name");
1255 goto done;
1256 }
1257
1258 error = vlib_cli_register_parse_rule (vm, r);
1259 if (error)
1260 goto done;
1261 }
1262
Dave Barach9b8ffd92016-07-08 08:13:45 -04001263done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001264 return error;
1265}
1266#endif
1267
Damjan Marion9c2b9f42017-04-21 13:56:40 +02001268static int
1269cli_path_compare (void *a1, void *a2)
1270{
1271 u8 **s1 = a1;
1272 u8 **s2 = a2;
1273
1274 if ((vec_len (*s1) < vec_len (*s2)) &&
1275 memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1276 return -1;
1277
1278
1279 if ((vec_len (*s1) > vec_len (*s2)) &&
1280 memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1281 return 1;
1282
1283 return vec_cmp (*s1, *s2);
1284}
1285
1286static clib_error_t *
1287show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1288 vlib_cli_command_t * cmd)
1289{
1290 vlib_cli_main_t *cm = &vm->cli_main;
1291 vlib_cli_command_t *cli;
1292 u8 **paths = 0, **s;
1293
1294 /* *INDENT-OFF* */
1295 vec_foreach (cli, cm->commands)
1296 if (vec_len (cli->path) > 0)
1297 vec_add1 (paths, (u8 *) cli->path);
1298
1299 vec_sort_with_function (paths, cli_path_compare);
1300
1301 vec_foreach (s, paths)
1302 vlib_cli_output (vm, "%v", *s);
1303 /* *INDENT-ON* */
1304
1305 vec_free (paths);
1306 return 0;
1307}
1308
1309/* *INDENT-OFF* */
1310VLIB_CLI_COMMAND (show_cli_command, static) = {
1311 .path = "show cli",
1312 .short_help = "Show cli commands",
1313 .function = show_cli_cmd_fn,
1314};
1315/* *INDENT-ON* */
1316
Dave Barach9b8ffd92016-07-08 08:13:45 -04001317static clib_error_t *
1318vlib_cli_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001319{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001320 vlib_cli_main_t *cm = &vm->cli_main;
1321 clib_error_t *error = 0;
1322 vlib_cli_command_t *cmd;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323
1324 cmd = cm->cli_command_registrations;
1325
1326 while (cmd)
1327 {
1328 error = vlib_cli_register (vm, cmd);
1329 if (error)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001330 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001331 cmd = cmd->next_cli_command;
1332 }
1333 return error;
1334}
1335
1336VLIB_INIT_FUNCTION (vlib_cli_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001337
1338/*
1339 * fd.io coding-style-patch-verification: ON
1340 *
1341 * Local Variables:
1342 * eval: (c-set-style "gnu")
1343 * End:
1344 */