blob: 131a5931ac2ad5b12ca230306999c666b0a215fb [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>
Chris Luke6edd3602018-06-12 22:45:06 -040041#include <vlib/unix/unix.h>
Damjan Marioneccf5092016-11-18 16:59:24 +010042#include <vppinfra/cpu.h>
Dave Barachc3a06552018-10-01 09:25:32 -040043#include <vppinfra/elog.h>
Damjan Marione5ef1d72017-03-02 12:33:48 +010044#include <unistd.h>
Yoann Desmouceaux3060e072017-05-18 11:00:48 +020045#include <ctype.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070046
Dave Barachb09f4d02019-07-15 16:00:03 -040047int vl_api_set_elog_trace_api_messages (int enable);
48int vl_api_get_elog_trace_api_messages (void);
49
Dave Barachd67a4282019-06-15 12:46:13 -040050static void *current_traced_heap;
51
Ed Warnickecb9cada2015-12-08 15:45:58 -070052/* Root of all show commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040053/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070054VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
55 .path = "show",
56 .short_help = "Show commands",
57};
Dave Barach9b8ffd92016-07-08 08:13:45 -040058/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
60/* Root of all clear commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040061/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070062VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
63 .path = "clear",
64 .short_help = "Clear commands",
65};
Dave Barach9b8ffd92016-07-08 08:13:45 -040066/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070067
68/* Root of all set commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040069/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070070VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
71 .path = "set",
72 .short_help = "Set commands",
73};
Dave Barach9b8ffd92016-07-08 08:13:45 -040074/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070075
76/* Root of all test commands. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040077/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070078VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
79 .path = "test",
80 .short_help = "Test commands",
81};
Dave Barach9b8ffd92016-07-08 08:13:45 -040082/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070083
84/* Returns bitmap of commands which match key. */
85static uword *
86vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
87{
88 int i, n;
Dave Barach9b8ffd92016-07-08 08:13:45 -040089 uword *match = 0;
90 vlib_cli_parse_position_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -070091
92 unformat_skip_white_space (input);
93
Dave Barach9b8ffd92016-07-08 08:13:45 -040094 for (i = 0;; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -070095 {
96 uword k;
97
98 k = unformat_get_input (input);
99 switch (k)
100 {
101 case 'a' ... 'z':
102 case 'A' ... 'Z':
103 case '0' ... '9':
Dave Barach9b8ffd92016-07-08 08:13:45 -0400104 case '-':
105 case '_':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106 break;
107
Dave Barach9b8ffd92016-07-08 08:13:45 -0400108 case ' ':
109 case '\t':
110 case '\r':
111 case '\n':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700112 case UNFORMAT_END_OF_INPUT:
113 /* White space or end of input removes any non-white
114 matches that were before possible. */
115 if (i < vec_len (c->sub_command_positions)
116 && clib_bitmap_count_set_bits (match) > 1)
117 {
118 p = vec_elt_at_index (c->sub_command_positions, i);
119 for (n = 0; n < vec_len (p->bitmaps); n++)
120 match = clib_bitmap_andnot (match, p->bitmaps[n]);
121 }
122 goto done;
123
124 default:
125 unformat_put_input (input);
126 goto done;
127 }
128
129 if (i >= vec_len (c->sub_command_positions))
130 {
131 no_match:
132 clib_bitmap_free (match);
133 return 0;
134 }
135
136 p = vec_elt_at_index (c->sub_command_positions, i);
137 if (vec_len (p->bitmaps) == 0)
138 goto no_match;
139
140 n = k - p->min_char;
141 if (n < 0 || n >= vec_len (p->bitmaps))
142 goto no_match;
143
144 if (i == 0)
145 match = clib_bitmap_dup (p->bitmaps[n]);
146 else
147 match = clib_bitmap_and (match, p->bitmaps[n]);
148
149 if (clib_bitmap_is_zero (match))
150 goto no_match;
151 }
152
Dave Barach9b8ffd92016-07-08 08:13:45 -0400153done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 return match;
155}
156
157/* Looks for string based sub-input formatted { SUB-INPUT }. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400158uword
159unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400161 unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
162 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163 uword c;
164
165 while (1)
166 {
167 c = unformat_get_input (i);
168 switch (c)
169 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400170 case ' ':
171 case '\t':
172 case '\n':
173 case '\r':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174 case '\f':
175 break;
176
177 case '{':
178 default:
179 /* Put back paren. */
180 if (c != UNFORMAT_END_OF_INPUT)
181 unformat_put_input (i);
182
183 if (c == '{' && unformat (i, "%v", &s))
184 {
185 unformat_init_vector (sub_input, s);
186 return 1;
187 }
188 return 0;
189 }
190 }
191 return 0;
192}
193
194static vlib_cli_command_t *
195get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
196{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400197 vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 return vec_elt_at_index (cm->commands, s->index);
199}
200
Dave Barach9b8ffd92016-07-08 08:13:45 -0400201static uword
202unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400204 vlib_main_t *vm = va_arg (*args, vlib_main_t *);
205 vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
206 vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
207 vlib_cli_main_t *cm = &vm->cli_main;
208 uword *match_bitmap, is_unique, index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209
210 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400211 vlib_cli_sub_rule_t *sr;
212 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213 vec_foreach (sr, c->sub_rules)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400214 {
215 void **d;
216 r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
217 vec_add2 (cm->parse_rule_data, d, 1);
218 vec_reset_length (d[0]);
219 if (r->data_size)
220 d[0] = _vec_resize (d[0],
221 /* length increment */ 1,
222 r->data_size,
223 /* header_bytes */ 0,
224 /* data align */ sizeof (uword));
225 if (unformat_user (i, r->unformat_function, vm, d[0]))
226 {
227 *result = vec_elt_at_index (cm->commands, sr->command_index);
228 return 1;
229 }
230 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231 }
232
233 match_bitmap = vlib_cli_sub_command_match (c, i);
234 is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
235 index = ~0;
236 if (is_unique)
237 {
238 index = clib_bitmap_first_set (match_bitmap);
239 *result = get_sub_command (cm, c, index);
240 }
241 clib_bitmap_free (match_bitmap);
242
243 return is_unique;
244}
245
Yoann Desmouceaux3060e072017-05-18 11:00:48 +0200246static int
247vlib_cli_cmp_strings (void *a1, void *a2)
248{
249 u8 *c1 = *(u8 **) a1;
250 u8 *c2 = *(u8 **) a2;
251
252 return vec_cmp (c1, c2);
253}
254
255u8 **
256vlib_cli_get_possible_completions (u8 * str)
257{
258 vlib_cli_command_t *c;
259 vlib_cli_sub_command_t *sc;
260 vlib_main_t *vm = vlib_get_main ();
261 vlib_cli_main_t *vcm = &vm->cli_main;
262 uword *match_bitmap = 0;
263 uword index, is_unique, help_next_level;
264 u8 **result = 0;
265 unformat_input_t input;
266 unformat_init_vector (&input, vec_dup (str));
267 c = vec_elt_at_index (vcm->commands, 0);
268
269 /* remove trailing whitespace, except for one of them */
270 while (vec_len (input.buffer) >= 2 &&
271 isspace (input.buffer[vec_len (input.buffer) - 1]) &&
272 isspace (input.buffer[vec_len (input.buffer) - 2]))
273 {
274 vec_del1 (input.buffer, vec_len (input.buffer) - 1);
275 }
276
277 /* if input is empty, directly return list of root commands */
278 if (vec_len (input.buffer) == 0 ||
279 (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
280 {
281 vec_foreach (sc, c->sub_commands)
282 {
283 vec_add1 (result, (u8 *) sc->name);
284 }
285 goto done;
286 }
287
288 /* add a trailing '?' so that vlib_cli_sub_command_match can find
289 * all commands starting with the input string */
290 vec_add1 (input.buffer, '?');
291
292 while (1)
293 {
294 match_bitmap = vlib_cli_sub_command_match (c, &input);
295 /* no match: return no result */
296 if (match_bitmap == 0)
297 {
298 goto done;
299 }
300 is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
301 /* unique match: try to step one subcommand level further */
302 if (is_unique)
303 {
304 /* stop if no more input */
305 if (input.index >= vec_len (input.buffer) - 1)
306 {
307 break;
308 }
309
310 index = clib_bitmap_first_set (match_bitmap);
311 c = get_sub_command (vcm, c, index);
312 clib_bitmap_free (match_bitmap);
313 continue;
314 }
315 /* multiple matches: stop here, return all matches */
316 break;
317 }
318
319 /* remove trailing '?' */
320 vec_del1 (input.buffer, vec_len (input.buffer) - 1);
321
322 /* if we have a space at the end of input, and a unique match,
323 * autocomplete the next level of subcommands */
324 help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
325 /* *INDENT-OFF* */
326 clib_bitmap_foreach(index, match_bitmap, {
327 if (help_next_level && is_unique) {
328 c = get_sub_command (vcm, c, index);
329 vec_foreach (sc, c->sub_commands) {
330 vec_add1 (result, (u8*) sc->name);
331 }
332 goto done; /* break doesn't work in this macro-loop */
333 }
334 sc = &c->sub_commands[index];
335 vec_add1(result, (u8*) sc->name);
336 });
337 /* *INDENT-ON* */
338
339done:
340 clib_bitmap_free (match_bitmap);
341 unformat_free (&input);
342
Yoann Desmouceaux4227eef2017-05-24 15:51:48 +0200343 if (result)
344 vec_sort_with_function (result, vlib_cli_cmp_strings);
Yoann Desmouceaux3060e072017-05-18 11:00:48 +0200345 return result;
346}
347
Dave Barach9b8ffd92016-07-08 08:13:45 -0400348static u8 *
349format_vlib_cli_command_help (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400351 vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352 int is_long = va_arg (*args, int);
353 if (is_long && c->long_help)
354 s = format (s, "%s", c->long_help);
355 else if (c->short_help)
356 s = format (s, "%s", c->short_help);
357 else
358 s = format (s, "%v commands", c->path);
359 return s;
360}
361
Dave Barach9b8ffd92016-07-08 08:13:45 -0400362static u8 *
363format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400365 vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366 return format (s, "<%U>", format_c_identifier, r->name);
367}
368
Dave Barach9b8ffd92016-07-08 08:13:45 -0400369static u8 *
370format_vlib_cli_path (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400372 u8 *path = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373 int i, in_rule;
374 in_rule = 0;
375 for (i = 0; i < vec_len (path); i++)
376 {
377 switch (path[i])
378 {
379 case '%':
380 in_rule = 1;
381 vec_add1 (s, '<'); /* start of <RULE> */
382 break;
383
384 case '_':
385 /* _ -> space in rules. */
386 vec_add1 (s, in_rule ? ' ' : '_');
387 break;
388
389 case ' ':
390 if (in_rule)
391 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400392 vec_add1 (s, '>'); /* end of <RULE> */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393 in_rule = 0;
394 }
395 vec_add1 (s, ' ');
396 break;
397
398 default:
399 vec_add1 (s, path[i]);
400 break;
401 }
402 }
403
404 if (in_rule)
405 vec_add1 (s, '>'); /* terminate <RULE> */
406
407 return s;
408}
409
410static vlib_cli_command_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400411all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400413 vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
414 vlib_cli_sub_command_t *sc;
415 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416
417 if (c->function)
418 vec_add1 (subs, c[0]);
419
420 vec_foreach (sr, c->sub_rules)
421 subs = all_subs (cm, subs, sr->command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400422 vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423
424 return subs;
425}
426
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500427static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400428vlib_cli_cmp_rule (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500429{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400430 vlib_cli_sub_rule_t *r1 = a1;
431 vlib_cli_sub_rule_t *r2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500432
433 return vec_cmp (r1->name, r2->name);
434}
435
436static int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400437vlib_cli_cmp_command (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500438{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400439 vlib_cli_command_t *c1 = a1;
440 vlib_cli_command_t *c2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500441
442 return vec_cmp (c1->path, c2->path);
443}
444
Ed Warnickecb9cada2015-12-08 15:45:58 -0700445static clib_error_t *
446vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
447 vlib_cli_main_t * cm,
448 unformat_input_t * input,
449 uword parent_command_index)
450{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400451 vlib_cli_command_t *parent, *c;
452 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453 unformat_input_t sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400454 u8 *string;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455 uword is_main_dispatch = cm == &vm->cli_main;
456
457 parent = vec_elt_at_index (cm->commands, parent_command_index);
458 if (is_main_dispatch && unformat (input, "help"))
459 {
460 uword help_at_end_of_line, i;
461
Dave Barach9b8ffd92016-07-08 08:13:45 -0400462 help_at_end_of_line =
463 unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464 while (1)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400465 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466 c = parent;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400467 if (unformat_user
468 (input, unformat_vlib_cli_sub_command, vm, c, &parent))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469 ;
470
Dave Barach9b8ffd92016-07-08 08:13:45 -0400471 else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472 goto unknown;
473
474 else
475 break;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400476 }
477
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478 /* help SUB-COMMAND => long format help.
Dave Barach9b8ffd92016-07-08 08:13:45 -0400479 "help" at end of line: show all commands. */
480 if (!help_at_end_of_line)
481 vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
482 /* is_long */ 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483
484 else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
485 vlib_cli_output (vm, "%v: no sub-commands", c->path);
486
487 else
488 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400489 vlib_cli_sub_command_t *sc;
490 vlib_cli_sub_rule_t *sr, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491
492 subs = vec_dup (c->sub_rules);
493
494 /* Add in rules if any. */
495 vec_foreach (sc, c->sub_commands)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400496 {
497 vec_add2 (subs, sr, 1);
498 sr->name = sc->name;
499 sr->command_index = sc->index;
500 sr->rule_index = ~0;
501 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700502
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500503 vec_sort_with_function (subs, vlib_cli_cmp_rule);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700504
Dave Barach9b8ffd92016-07-08 08:13:45 -0400505 for (i = 0; i < vec_len (subs); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400507 vlib_cli_command_t *d;
508 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700509
510 d = vec_elt_at_index (cm->commands, subs[i].command_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400511 r =
512 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
513 subs
514 [i].rule_index) :
515 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700516
517 if (r)
518 vlib_cli_output
519 (vm, " %-30U %U",
520 format_vlib_cli_parse_rule_name, r,
521 format_vlib_cli_command_help, d, /* is_long */ 0);
522 else
523 vlib_cli_output
524 (vm, " %-30v %U",
525 subs[i].name,
526 format_vlib_cli_command_help, d, /* is_long */ 0);
527 }
528
529 vec_free (subs);
530 }
531 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400532
533 else if (is_main_dispatch
534 && (unformat (input, "choices") || unformat (input, "?")))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400536 vlib_cli_command_t *sub, *subs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537
538 subs = all_subs (cm, 0, parent_command_index);
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500539 vec_sort_with_function (subs, vlib_cli_cmp_command);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540 vec_foreach (sub, subs)
541 vlib_cli_output (vm, " %-40U %U",
542 format_vlib_cli_path, sub->path,
543 format_vlib_cli_command_help, sub, /* is_long */ 0);
544 vec_free (subs);
545 }
546
547 else if (unformat (input, "comment %v", &string))
548 {
549 vec_free (string);
550 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400551
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552 else if (unformat (input, "uncomment %U",
553 unformat_vlib_cli_sub_input, &sub_input))
554 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400555 error =
556 vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
557 parent_command_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558 unformat_free (&sub_input);
559 }
Dave Barach8fdde3c2019-05-17 10:46:40 -0400560 else if (unformat (input, "leak-check %U",
561 unformat_vlib_cli_sub_input, &sub_input))
562 {
563 u8 *leak_report;
Dave Barachd67a4282019-06-15 12:46:13 -0400564 if (current_traced_heap)
565 {
566 void *oldheap;
567 oldheap = clib_mem_set_heap (current_traced_heap);
568 clib_mem_trace (0);
569 clib_mem_set_heap (oldheap);
570 current_traced_heap = 0;
571 }
Dave Barach8fdde3c2019-05-17 10:46:40 -0400572 clib_mem_trace (1);
573 error =
574 vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
575 parent_command_index);
576 unformat_free (&sub_input);
577
578 /* Otherwise, the clib_error_t shows up as a leak... */
579 if (error)
580 {
581 vlib_cli_output (vm, "%v", error->what);
582 clib_error_free (error);
583 error = 0;
584 }
585
586 (void) clib_mem_trace_enable_disable (0);
587 leak_report = format (0, "%U", format_mheap, clib_mem_get_heap (),
588 1 /* verbose, i.e. print leaks */ );
589 clib_mem_trace (0);
590 vlib_cli_output (vm, "%v", leak_report);
591 vec_free (leak_report);
592 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400593
594 else
595 if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400597 unformat_input_t *si;
598 uword has_sub_commands =
599 vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
600
Ed Warnickecb9cada2015-12-08 15:45:58 -0700601 si = input;
602 if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
603 si = &sub_input;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400604
Ed Warnickecb9cada2015-12-08 15:45:58 -0700605 if (has_sub_commands)
606 error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
607
Dave Barach9b8ffd92016-07-08 08:13:45 -0400608 if (has_sub_commands && !error)
609 /* Found valid sub-command. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610
611 else if (c->function)
612 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400613 clib_error_t *c_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700614
615 /* Skip white space for benefit of called function. */
616 unformat_skip_white_space (si);
617
618 if (unformat (si, "?"))
619 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400620 vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */
621 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622 }
623 else
624 {
Dave Barachc3a06552018-10-01 09:25:32 -0400625 if (PREDICT_FALSE (vm->elog_trace_cli_commands))
626 {
627 /* *INDENT-OFF* */
628 ELOG_TYPE_DECLARE (e) =
629 {
630 .format = "cli-cmd: %s",
631 .format_args = "T4",
632 };
633 /* *INDENT-ON* */
634 struct
635 {
636 u32 c;
637 } *ed;
638 ed = ELOG_DATA (&vm->elog_main, e);
Dave Barachb09f4d02019-07-15 16:00:03 -0400639 ed->c = elog_string (&vm->elog_main, c->path);
Dave Barachc3a06552018-10-01 09:25:32 -0400640 }
641
Dave Barach9b8ffd92016-07-08 08:13:45 -0400642 if (!c->is_mp_safe)
643 vlib_worker_thread_barrier_sync (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644
645 c_error = c->function (vm, si, c);
646
Dave Barach9b8ffd92016-07-08 08:13:45 -0400647 if (!c->is_mp_safe)
648 vlib_worker_thread_barrier_release (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649
Dave Barachc3a06552018-10-01 09:25:32 -0400650 if (PREDICT_FALSE (vm->elog_trace_cli_commands))
651 {
652 /* *INDENT-OFF* */
653 ELOG_TYPE_DECLARE (e) =
654 {
655 .format = "cli-cmd: %s %s",
656 .format_args = "T4T4",
657 };
658 /* *INDENT-ON* */
659 struct
660 {
661 u32 c, err;
662 } *ed;
663 ed = ELOG_DATA (&vm->elog_main, e);
Dave Barachb09f4d02019-07-15 16:00:03 -0400664 ed->c = elog_string (&vm->elog_main, c->path);
Dave Barachc3a06552018-10-01 09:25:32 -0400665 if (c_error)
666 {
667 vec_add1 (c_error->what, 0);
Dave Barachb09f4d02019-07-15 16:00:03 -0400668 ed->err = elog_string (&vm->elog_main,
669 (char *) c_error->what);
Dave Barachc3a06552018-10-01 09:25:32 -0400670 _vec_len (c_error->what) -= 1;
671 }
672 else
Dave Barachb09f4d02019-07-15 16:00:03 -0400673 ed->err = elog_string (&vm->elog_main, "OK");
Dave Barachc3a06552018-10-01 09:25:32 -0400674 }
675
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 if (c_error)
677 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400678 error =
679 clib_error_return (0, "%v: %v", c->path, c_error->what);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680 clib_error_free (c_error);
681 /* Free sub input. */
682 if (si != input)
683 unformat_free (si);
684
685 return error;
686 }
687 }
688
689 /* Free any previous error. */
690 clib_error_free (error);
691 }
692
Dave Barach9b8ffd92016-07-08 08:13:45 -0400693 else if (!error)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694 error = clib_error_return (0, "%v: no sub-commands", c->path);
695
696 /* Free sub input. */
697 if (si != input)
698 unformat_free (si);
699 }
700
701 else
702 goto unknown;
703
704 return error;
705
Dave Barach9b8ffd92016-07-08 08:13:45 -0400706unknown:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707 if (parent->path)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400708 return clib_error_return (0, "%v: unknown input `%U'", parent->path,
709 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400711 return clib_error_return (0, "unknown input `%U'", format_unformat_error,
712 input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713}
714
715
Dave Barach9b8ffd92016-07-08 08:13:45 -0400716void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
717 __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718
Dave Barach9b8ffd92016-07-08 08:13:45 -0400719void
720vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
721{
722}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723
724/* Process CLI input. */
Ole Troan72d87582019-05-10 12:01:10 +0200725int
Dave Barach9b8ffd92016-07-08 08:13:45 -0400726vlib_cli_input (vlib_main_t * vm,
727 unformat_input_t * input,
728 vlib_cli_output_function_t * function, uword function_arg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700729{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400730 vlib_process_t *cp = vlib_get_current_process (vm);
731 vlib_cli_main_t *cm = &vm->cli_main;
732 clib_error_t *error;
733 vlib_cli_output_function_t *save_function;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734 uword save_function_arg;
Ole Troan72d87582019-05-10 12:01:10 +0200735 int rv = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000737 save_function = cp->output_function;
738 save_function_arg = cp->output_function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000740 cp->output_function = function;
741 cp->output_function_arg = function_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742
Dave Barach9b8ffd92016-07-08 08:13:45 -0400743 do
744 {
745 vec_reset_length (cm->parse_rule_data);
746 error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
747 0);
748 }
749 while (!error && !unformat (input, "%U", unformat_eof));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750
751 if (error)
752 {
753 vlib_cli_output (vm, "%v", error->what);
754 vlib_unix_error_report (vm, error);
Ole Troan72d87582019-05-10 12:01:10 +0200755 /* clib_error_return is unfortunately often called with a '0'
756 return code */
757 rv = error->code != 0 ? error->code : -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700758 clib_error_free (error);
759 }
760
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000761 cp->output_function = save_function;
762 cp->output_function_arg = save_function_arg;
Ole Troan72d87582019-05-10 12:01:10 +0200763 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700764}
765
766/* Output to current CLI connection. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400767void
768vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700769{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400770 vlib_process_t *cp = vlib_get_current_process (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700771 va_list va;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400772 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700773
774 va_start (va, fmt);
775 s = va_format (0, fmt, &va);
776 va_end (va);
777
778 /* Terminate with \n if not present. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400779 if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780 vec_add1 (s, '\n');
781
Dave Barach9b8ffd92016-07-08 08:13:45 -0400782 if ((!cp) || (!cp->output_function))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783 fformat (stdout, "%v", s);
784 else
Andrew Yourtchenko716d9592016-05-10 10:51:34 +0000785 cp->output_function (cp->output_function_arg, s, vec_len (s));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786
787 vec_free (s);
788}
789
Ole Troan73710c72018-06-04 22:27:49 +0200790void *vl_msg_push_heap (void) __attribute__ ((weak));
Dave Barachd67a4282019-06-15 12:46:13 -0400791void *
792vl_msg_push_heap (void)
793{
794 return 0;
795}
796
Ole Troan73710c72018-06-04 22:27:49 +0200797void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
Dave Barachd67a4282019-06-15 12:46:13 -0400798void
799vl_msg_pop_heap (void *oldheap)
800{
801}
802
803void *vlib_stats_push_heap (void *) __attribute__ ((weak));
804void *
805vlib_stats_push_heap (void *notused)
806{
807 return 0;
808}
Ole Troan73710c72018-06-04 22:27:49 +0200809
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810static clib_error_t *
811show_memory_usage (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400812 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813{
Dave Barachd67a4282019-06-15 12:46:13 -0400814 int verbose __attribute__ ((unused)) = 0;
815 int api_segment = 0, stats_segment = 0, main_heap = 0;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400816 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700817 u32 index = 0;
Dave Barachd67a4282019-06-15 12:46:13 -0400818 uword clib_mem_trace_enable_disable (uword enable);
819 uword was_enabled;
820
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821
Dave Barach9b8ffd92016-07-08 08:13:45 -0400822 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400824 if (unformat (input, "verbose"))
825 verbose = 1;
Ole Troan73710c72018-06-04 22:27:49 +0200826 else if (unformat (input, "api-segment"))
827 api_segment = 1;
Dave Barachd67a4282019-06-15 12:46:13 -0400828 else if (unformat (input, "stats-segment"))
829 stats_segment = 1;
830 else if (unformat (input, "main-heap"))
831 main_heap = 1;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400832 else
833 {
834 error = clib_error_return (0, "unknown input `%U'",
835 format_unformat_error, input);
836 return error;
837 }
838 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839
Dave Barachd67a4282019-06-15 12:46:13 -0400840 if ((api_segment + stats_segment + main_heap) == 0)
841 return clib_error_return
842 (0, "Please supply one of api-segment, stats-segment or main-heap");
843
Ole Troan73710c72018-06-04 22:27:49 +0200844 if (api_segment)
845 {
846 void *oldheap = vl_msg_push_heap ();
Dave Barachd67a4282019-06-15 12:46:13 -0400847 was_enabled = clib_mem_trace_enable_disable (0);
Ole Troan73710c72018-06-04 22:27:49 +0200848 u8 *s_in_svm =
849 format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
850 vl_msg_pop_heap (oldheap);
851 u8 *s = vec_dup (s_in_svm);
852
853 oldheap = vl_msg_push_heap ();
854 vec_free (s_in_svm);
Dave Barachd67a4282019-06-15 12:46:13 -0400855 clib_mem_trace_enable_disable (was_enabled);
Ole Troan73710c72018-06-04 22:27:49 +0200856 vl_msg_pop_heap (oldheap);
Dave Barachd67a4282019-06-15 12:46:13 -0400857 vlib_cli_output (vm, "API segment");
Ole Troan73710c72018-06-04 22:27:49 +0200858 vlib_cli_output (vm, "%v", s);
Dave Barachd67a4282019-06-15 12:46:13 -0400859 vec_free (s);
860 }
861 if (stats_segment)
862 {
863 void *oldheap = vlib_stats_push_heap (0);
864 was_enabled = clib_mem_trace_enable_disable (0);
865 u8 *s_in_svm =
866 format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
867 if (oldheap)
868 clib_mem_set_heap (oldheap);
869 u8 *s = vec_dup (s_in_svm);
870
871 oldheap = vlib_stats_push_heap (0);
872 vec_free (s_in_svm);
873 if (oldheap)
874 {
875 clib_mem_trace_enable_disable (was_enabled);
876 clib_mem_set_heap (oldheap);
877 }
878 vlib_cli_output (vm, "Stats segment");
879 vlib_cli_output (vm, "%v", s);
Ole Troan73710c72018-06-04 22:27:49 +0200880 vec_free (s);
881 }
882
Dave Barach6a5adc32018-07-04 10:56:23 -0400883#if USE_DLMALLOC == 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400884 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885 foreach_vlib_main (
886 ({
Damjan Marion926b5642018-07-02 21:33:31 +0200887 mheap_t *h = mheap_header (clib_per_cpu_mheaps[index]);
Dave Barach6a5adc32018-07-04 10:56:23 -0400888 vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index,
Damjan Marion926b5642018-07-02 21:33:31 +0200889 vlib_worker_threads[index].name);
890 vlib_cli_output (vm, " %U\n", format_page_map, pointer_to_uword (h) -
891 h->vm_alloc_offset_from_header,
892 h->vm_alloc_size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400893 vlib_cli_output (vm, " %U\n", format_mheap, clib_per_cpu_mheaps[index],
894 verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700895 index++;
896 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400897 /* *INDENT-ON* */
Dave Barach6a5adc32018-07-04 10:56:23 -0400898#else
899 {
Dave Barachd67a4282019-06-15 12:46:13 -0400900 if (main_heap)
901 {
902 /*
903 * Note: the foreach_vlib_main causes allocator traffic,
904 * so shut off tracing before we go there...
905 */
906 was_enabled = clib_mem_trace_enable_disable (0);
Dave Barach6a5adc32018-07-04 10:56:23 -0400907
Dave Barachd67a4282019-06-15 12:46:13 -0400908 /* *INDENT-OFF* */
909 foreach_vlib_main (
910 ({
911 struct dlmallinfo mi;
912 void *mspace;
913 mspace = clib_per_cpu_mheaps[index];
Dave Barach6a5adc32018-07-04 10:56:23 -0400914
Dave Barachd67a4282019-06-15 12:46:13 -0400915 mi = mspace_mallinfo (mspace);
916 vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index,
917 vlib_worker_threads[index].name);
918 vlib_cli_output (vm, " %U\n", format_page_map,
919 pointer_to_uword (mspace_least_addr(mspace)),
920 mi.arena);
921 vlib_cli_output (vm, " %U\n", format_mheap,
922 clib_per_cpu_mheaps[index],
923 verbose);
924 index++;
925 }));
926 /* *INDENT-ON* */
Dave Barach6a5adc32018-07-04 10:56:23 -0400927
Dave Barachd67a4282019-06-15 12:46:13 -0400928 /* Restore the trace flag */
929 clib_mem_trace_enable_disable (was_enabled);
930 }
Dave Barach6a5adc32018-07-04 10:56:23 -0400931 }
932#endif /* USE_DLMALLOC */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700933 return 0;
934}
935
Dave Barach9b8ffd92016-07-08 08:13:45 -0400936/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
938 .path = "show memory",
Dave Barachd67a4282019-06-15 12:46:13 -0400939 .short_help = "show memory [api-segment][stats-segment][verbose]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940 .function = show_memory_usage,
941};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400942/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943
944static clib_error_t *
Damjan Marioneccf5092016-11-18 16:59:24 +0100945show_cpu (vlib_main_t * vm, unformat_input_t * input,
946 vlib_cli_command_t * cmd)
947{
948#define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
949 _("Model name", "%U", format_cpu_model_name);
Paul Vinciguerrad6897c12018-12-30 11:07:36 -0800950 _("Microarch model (family)", "%U", format_cpu_uarch);
Damjan Marioneccf5092016-11-18 16:59:24 +0100951 _("Flags", "%U", format_cpu_flags);
952 _("Base frequency", "%.2f GHz",
953 ((f64) vm->clib_time.clocks_per_second) * 1e-9);
954#undef _
955 return 0;
956}
957
958/*?
959 * Displays various information about the CPU.
960 *
961 * @cliexpar
962 * @cliexstart{show cpu}
963 * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
964 * Microarchitecture: Broadwell (Broadwell-EP/EX)
965 * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
966 * Base Frequency: 3.20 GHz
967 * @cliexend
968?*/
969/* *INDENT-OFF* */
970VLIB_CLI_COMMAND (show_cpu_command, static) = {
971 .path = "show cpu",
972 .short_help = "Show cpu information",
973 .function = show_cpu,
974};
Damjan Marioneccf5092016-11-18 16:59:24 +0100975/* *INDENT-ON* */
Ole Troan73710c72018-06-04 22:27:49 +0200976
Damjan Marioneccf5092016-11-18 16:59:24 +0100977static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978enable_disable_memory_trace (vlib_main_t * vm,
979 unformat_input_t * input,
980 vlib_cli_command_t * cmd)
981{
Ole Troan73710c72018-06-04 22:27:49 +0200982 unformat_input_t _line_input, *line_input = &_line_input;
Dave Barachd67a4282019-06-15 12:46:13 -0400983 int enable = 1;
Ole Troan73710c72018-06-04 22:27:49 +0200984 int api_segment = 0;
Dave Barachd67a4282019-06-15 12:46:13 -0400985 int stats_segment = 0;
986 int main_heap = 0;
Ole Troan73710c72018-06-04 22:27:49 +0200987 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988
Ole Troan73710c72018-06-04 22:27:49 +0200989 if (!unformat_user (input, unformat_line_input, line_input))
990 return 0;
991
992 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 {
Dave Barach1ddbc012018-06-13 09:26:05 -0400994 if (unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
Ole Troan73710c72018-06-04 22:27:49 +0200995 ;
996 else if (unformat (line_input, "api-segment"))
997 api_segment = 1;
Dave Barachd67a4282019-06-15 12:46:13 -0400998 else if (unformat (line_input, "stats-segment"))
999 stats_segment = 1;
1000 else if (unformat (line_input, "main-heap"))
1001 main_heap = 1;
Ole Troan73710c72018-06-04 22:27:49 +02001002 else
1003 {
1004 unformat_free (line_input);
1005 return clib_error_return (0, "invalid input");
1006 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007 }
Ole Troan73710c72018-06-04 22:27:49 +02001008 unformat_free (line_input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009
Dave Barachd67a4282019-06-15 12:46:13 -04001010 if ((api_segment + stats_segment + main_heap + (enable == 0)) == 0)
1011 {
1012 return clib_error_return
1013 (0, "Need one of main-heap, stats-segment or api-segment");
1014 }
1015
1016 /* Turn off current trace, if any */
1017 if (current_traced_heap)
1018 {
1019 void *oldheap;
1020 oldheap = clib_mem_set_heap (current_traced_heap);
1021 clib_mem_trace (0);
1022 clib_mem_set_heap (oldheap);
1023 current_traced_heap = 0;
1024 }
1025
1026 if (enable == 0)
1027 return 0;
1028
1029 /* API segment */
Ole Troan73710c72018-06-04 22:27:49 +02001030 if (api_segment)
Dave Barachd67a4282019-06-15 12:46:13 -04001031 {
1032 oldheap = vl_msg_push_heap ();
1033 current_traced_heap = clib_mem_get_heap ();
1034 clib_mem_trace (1);
1035 vl_msg_pop_heap (oldheap);
1036
1037 }
1038
1039 /* Stats segment */
1040 if (stats_segment)
1041 {
1042 oldheap = vlib_stats_push_heap (0);
1043 current_traced_heap = clib_mem_get_heap ();
1044 clib_mem_trace (stats_segment);
1045 /* We don't want to call vlib_stats_pop_heap... */
1046 if (oldheap)
1047 clib_mem_set_heap (oldheap);
1048 }
1049
1050 /* main_heap */
1051 if (main_heap)
1052 {
1053 current_traced_heap = clib_mem_get_heap ();
1054 clib_mem_trace (main_heap);
1055 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056
Ole Troan73710c72018-06-04 22:27:49 +02001057 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058}
1059
Dave Barach9b8ffd92016-07-08 08:13:45 -04001060/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
1062 .path = "memory-trace",
Dave Barachd67a4282019-06-15 12:46:13 -04001063 .short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001064 .function = enable_disable_memory_trace,
1065};
Dave Barach9b8ffd92016-07-08 08:13:45 -04001066/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067
1068
1069static clib_error_t *
1070test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001071 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072{
Dave Barach6a5adc32018-07-04 10:56:23 -04001073#if USE_DLMALLOC == 0
Dave Barach9b8ffd92016-07-08 08:13:45 -04001074 clib_error_t *error = 0;
1075 void *heap;
1076 mheap_t *mheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077
Dave Barach9b8ffd92016-07-08 08:13:45 -04001078 if (unformat (input, "on"))
1079 {
1080 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +02001082 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083 mheap = mheap_header(heap);
1084 mheap->flags |= MHEAP_FLAG_VALIDATE;
1085 // Turn off small object cache because it delays detection of errors
1086 mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
1087 });
Dave Barach9b8ffd92016-07-08 08:13:45 -04001088 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089
Dave Barach9b8ffd92016-07-08 08:13:45 -04001090 }
1091 else if (unformat (input, "off"))
1092 {
1093 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +02001095 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 mheap = mheap_header(heap);
1097 mheap->flags &= ~MHEAP_FLAG_VALIDATE;
1098 mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
1099 });
Dave Barach9b8ffd92016-07-08 08:13:45 -04001100 /* *INDENT-ON* */
1101 }
1102 else if (unformat (input, "now"))
1103 {
1104 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105 foreach_vlib_main({
Damjan Marion586afd72017-04-05 19:18:20 +02001106 heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001107 mheap = mheap_header(heap);
1108 mheap_validate(heap);
1109 });
Dave Barach9b8ffd92016-07-08 08:13:45 -04001110 /* *INDENT-ON* */
1111 vlib_cli_output (vm, "heap validation complete");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112
Dave Barach9b8ffd92016-07-08 08:13:45 -04001113 }
1114 else
1115 {
1116 return clib_error_return (0, "unknown input `%U'",
1117 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118 }
1119
Dave Barach9b8ffd92016-07-08 08:13:45 -04001120 return error;
Dave Barach6a5adc32018-07-04 10:56:23 -04001121#else
1122 return clib_error_return (0, "unimplemented...");
1123#endif /* USE_DLMALLOC */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124}
1125
Dave Barach9b8ffd92016-07-08 08:13:45 -04001126/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
1128 .path = "test heap-validate",
1129 .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
1130 .function = test_heap_validate,
1131};
Dave Barach9b8ffd92016-07-08 08:13:45 -04001132/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001133
Damjan Marione5ef1d72017-03-02 12:33:48 +01001134static clib_error_t *
1135restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1136 vlib_cli_command_t * cmd)
1137{
Chris Luke6edd3602018-06-12 22:45:06 -04001138 clib_file_main_t *fm = &file_main;
1139 clib_file_t *f;
Damjan Marione5ef1d72017-03-02 12:33:48 +01001140
Chris Luke6edd3602018-06-12 22:45:06 -04001141 /* environ(7) does not indicate a header for this */
1142 extern char **environ;
1143
1144 /* Close all known open files */
1145 /* *INDENT-OFF* */
1146 pool_foreach(f, fm->file_pool,
1147 ({
1148 if (f->file_descriptor > 2)
1149 close(f->file_descriptor);
1150 }));
1151 /* *INDENT-ON* */
1152
1153 /* Exec ourself */
1154 execve (vm->name, (char **) vm->argv, environ);
Damjan Marione5ef1d72017-03-02 12:33:48 +01001155
1156 return 0;
1157}
1158
1159/* *INDENT-OFF* */
1160VLIB_CLI_COMMAND (restart_cmd,static) = {
1161 .path = "restart",
1162 .short_help = "restart process",
1163 .function = restart_cmd_fn,
1164};
1165/* *INDENT-ON* */
1166
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001167#ifdef TEST_CODE
1168/*
1169 * A trivial test harness to verify the per-process output_function
1170 * is working correcty.
1171 */
1172
1173static clib_error_t *
1174sleep_ten_seconds (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001175 unformat_input_t * input, vlib_cli_command_t * cmd)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001176{
1177 u16 i;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001178 u16 my_id = rand ();
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001179
Dave Barach9b8ffd92016-07-08 08:13:45 -04001180 vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001181
Dave Barach9b8ffd92016-07-08 08:13:45 -04001182 for (i = 0; i < 10; i++)
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001183 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001184 vlib_process_wait_for_event_or_clock (vm, 1.0);
1185 vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001186 }
Dave Barach9b8ffd92016-07-08 08:13:45 -04001187 vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001188 return 0;
1189}
1190
Dave Barach9b8ffd92016-07-08 08:13:45 -04001191/* *INDENT-OFF* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001192VLIB_CLI_COMMAND (ping_command, static) = {
1193 .path = "test sleep",
1194 .function = sleep_ten_seconds,
1195 .short_help = "Sleep for 10 seconds",
1196};
Dave Barach9b8ffd92016-07-08 08:13:45 -04001197/* *INDENT-ON* */
Andrew Yourtchenko716d9592016-05-10 10:51:34 +00001198#endif /* ifdef TEST_CODE */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
Dave Barach9b8ffd92016-07-08 08:13:45 -04001200static uword
1201vlib_cli_normalize_path (char *input, char **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001203 char *i = input;
1204 char *s = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001205 uword l = 0;
1206 uword index_of_last_space = ~0;
1207
1208 while (*i != 0)
1209 {
1210 u8 c = *i++;
1211 /* Multiple white space -> single space. */
1212 switch (c)
1213 {
1214 case ' ':
1215 case '\t':
1216 case '\n':
1217 case '\r':
Dave Barach9b8ffd92016-07-08 08:13:45 -04001218 if (l > 0 && s[l - 1] != ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 {
1220 vec_add1 (s, ' ');
1221 l++;
1222 }
1223 break;
1224
1225 default:
Dave Barach9b8ffd92016-07-08 08:13:45 -04001226 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227 index_of_last_space = vec_len (s);
1228 vec_add1 (s, c);
1229 l++;
1230 break;
1231 }
1232 }
1233
1234 /* Remove any extra space at end. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001235 if (l > 0 && s[l - 1] == ' ')
Ed Warnickecb9cada2015-12-08 15:45:58 -07001236 _vec_len (s) -= 1;
1237
1238 *result = s;
1239 return index_of_last_space;
1240}
1241
1242always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -04001243parent_path_len (char *path)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001244{
1245 word i;
1246 for (i = vec_len (path) - 1; i >= 0; i--)
1247 {
1248 if (path[i] == ' ')
1249 return i;
1250 }
1251 return ~0;
1252}
1253
Dave Barach9b8ffd92016-07-08 08:13:45 -04001254static void
1255add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001257 vlib_cli_command_t *p, *c;
1258 vlib_cli_sub_command_t *sub_c;
1259 u8 *sub_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001260 word i, l;
1261
1262 p = vec_elt_at_index (cm->commands, parent_index);
1263 c = vec_elt_at_index (cm->commands, child_index);
1264
1265 l = parent_path_len (c->path);
1266 if (l == ~0)
1267 sub_name = vec_dup ((u8 *) c->path);
1268 else
1269 {
1270 ASSERT (l + 1 < vec_len (c->path));
1271 sub_name = 0;
1272 vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
1273 }
1274
1275 if (sub_name[0] == '%')
1276 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001277 uword *q;
1278 vlib_cli_sub_rule_t *sr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279
1280 /* Remove %. */
1281 vec_delete (sub_name, 1, 0);
1282
Dave Barach9b8ffd92016-07-08 08:13:45 -04001283 if (!p->sub_rule_index_by_name)
1284 p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1285 sizeof (sub_name[0]),
1286 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001287 q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1288 if (q)
1289 {
1290 sr = vec_elt_at_index (p->sub_rules, q[0]);
1291 ASSERT (sr->command_index == child_index);
1292 return;
1293 }
1294
1295 q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001296 if (!q)
Ed Warnicke853e7202016-08-12 11:42:26 -07001297 {
1298 clib_error ("reference to unknown rule `%%%v' in path `%v'",
1299 sub_name, c->path);
1300 return;
1301 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302
Dave Barach9b8ffd92016-07-08 08:13:45 -04001303 hash_set_mem (p->sub_rule_index_by_name, sub_name,
1304 vec_len (p->sub_rules));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305 vec_add2 (p->sub_rules, sr, 1);
1306 sr->name = sub_name;
1307 sr->rule_index = q[0];
1308 sr->command_index = child_index;
1309 return;
1310 }
1311
Dave Barach9b8ffd92016-07-08 08:13:45 -04001312 if (!p->sub_command_index_by_name)
1313 p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1314 sizeof (c->path[0]),
1315 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316
1317 /* Check if sub-command has already been created. */
1318 if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1319 {
1320 vec_free (sub_name);
1321 return;
1322 }
1323
1324 vec_add2 (p->sub_commands, sub_c, 1);
1325 sub_c->index = child_index;
1326 sub_c->name = sub_name;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001327 hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1328 sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001329
1330 vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1331 for (i = 0; i < vec_len (sub_c->name); i++)
1332 {
1333 int n;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001334 vlib_cli_parse_position_t *pos;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335
1336 pos = vec_elt_at_index (p->sub_command_positions, i);
1337
Dave Barach9b8ffd92016-07-08 08:13:45 -04001338 if (!pos->bitmaps)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001339 pos->min_char = sub_c->name[i];
1340
1341 n = sub_c->name[i] - pos->min_char;
1342 if (n < 0)
1343 {
1344 pos->min_char = sub_c->name[i];
1345 vec_insert (pos->bitmaps, -n, 0);
1346 n = 0;
1347 }
1348
1349 vec_validate (pos->bitmaps, n);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001350 pos->bitmaps[n] =
1351 clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001352 }
1353}
1354
1355static void
1356vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1357{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001358 uword p_len, pi, *p;
1359 char *p_path;
1360 vlib_cli_command_t *c, *parent;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001361
1362 /* Root command (index 0) should have already been added. */
1363 ASSERT (vec_len (cm->commands) > 0);
1364
1365 c = vec_elt_at_index (cm->commands, ci);
1366 p_len = parent_path_len (c->path);
1367
Dave Barach9b8ffd92016-07-08 08:13:45 -04001368 /* No space? Parent is root command. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001369 if (p_len == ~0)
1370 {
1371 add_sub_command (cm, 0, ci);
1372 return;
1373 }
1374
1375 p_path = 0;
1376 vec_add (p_path, c->path, p_len);
1377
1378 p = hash_get_mem (cm->command_index_by_path, p_path);
1379
1380 /* Parent exists? */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001381 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382 {
1383 /* Parent does not exist; create it. */
1384 vec_add2 (cm->commands, parent, 1);
1385 parent->path = p_path;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001386 hash_set_mem (cm->command_index_by_path, parent->path,
1387 parent - cm->commands);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388 pi = parent - cm->commands;
1389 }
1390 else
1391 {
1392 pi = p[0];
1393 vec_free (p_path);
1394 }
1395
1396 add_sub_command (cm, pi, ci);
1397
1398 /* Create parent's parent. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001399 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400 vlib_cli_make_parent (cm, pi);
1401}
1402
1403always_inline uword
1404vlib_cli_command_is_empty (vlib_cli_command_t * c)
1405{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001406 return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407}
1408
Dave Barach9b8ffd92016-07-08 08:13:45 -04001409clib_error_t *
1410vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001411{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001412 vlib_cli_main_t *cm = &vm->cli_main;
1413 clib_error_t *error = 0;
1414 uword ci, *p;
1415 char *normalized_path;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001416
1417 if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1418 return error;
1419
1420 (void) vlib_cli_normalize_path (c->path, &normalized_path);
1421
Dave Barach9b8ffd92016-07-08 08:13:45 -04001422 if (!cm->command_index_by_path)
1423 cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001424 sizeof (c->path[0]),
1425 sizeof (uword));
1426
1427 /* See if command already exists with given path. */
1428 p = hash_get_mem (cm->command_index_by_path, normalized_path);
1429 if (p)
1430 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001431 vlib_cli_command_t *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432
1433 ci = p[0];
1434 d = vec_elt_at_index (cm->commands, ci);
1435
1436 /* If existing command was created via vlib_cli_make_parent
Dave Barach9b8ffd92016-07-08 08:13:45 -04001437 replaced it with callers data. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001438 if (vlib_cli_command_is_empty (d))
1439 {
1440 vlib_cli_command_t save = d[0];
1441
Dave Barach9b8ffd92016-07-08 08:13:45 -04001442 ASSERT (!vlib_cli_command_is_empty (c));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001443
1444 /* Copy callers fields. */
1445 d[0] = c[0];
1446
1447 /* Save internal fields. */
1448 d->path = save.path;
1449 d->sub_commands = save.sub_commands;
1450 d->sub_command_index_by_name = save.sub_command_index_by_name;
1451 d->sub_command_positions = save.sub_command_positions;
1452 d->sub_rules = save.sub_rules;
1453 }
1454 else
Dave Barach9b8ffd92016-07-08 08:13:45 -04001455 error =
1456 clib_error_return (0, "duplicate command name with path %v",
1457 normalized_path);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001458
1459 vec_free (normalized_path);
1460 if (error)
1461 return error;
1462 }
1463 else
1464 {
1465 /* Command does not exist: create it. */
1466
1467 /* Add root command (index 0). */
1468 if (vec_len (cm->commands) == 0)
1469 {
1470 /* Create command with index 0; path is empty string. */
1471 vec_resize (cm->commands, 1);
1472 }
1473
1474 ci = vec_len (cm->commands);
1475 hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1476 vec_add1 (cm->commands, c[0]);
1477
1478 c = vec_elt_at_index (cm->commands, ci);
1479 c->path = normalized_path;
1480
1481 /* Don't inherit from registration. */
1482 c->sub_commands = 0;
1483 c->sub_command_index_by_name = 0;
1484 c->sub_command_positions = 0;
1485 }
1486
1487 vlib_cli_make_parent (cm, ci);
1488 return 0;
1489}
1490
1491clib_error_t *
1492vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1493{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001494 vlib_cli_main_t *cm = &vm->cli_main;
1495 vlib_cli_parse_rule_t *r;
1496 clib_error_t *error = 0;
1497 u8 *r_name;
1498 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001499
Dave Barach9b8ffd92016-07-08 08:13:45 -04001500 if (!cm->parse_rule_index_by_name)
1501 cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001502 sizeof (r->name[0]),
1503 sizeof (uword));
1504
1505 /* Make vector copy of name. */
1506 r_name = format (0, "%s", r_reg->name);
1507
1508 if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1509 {
1510 vec_free (r_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001511 return clib_error_return (0, "duplicate parse rule name `%s'",
1512 r_reg->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001513 }
1514
1515 vec_add2 (cm->parse_rules, r, 1);
1516 r[0] = r_reg[0];
1517 r->name = (char *) r_name;
1518 hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1519
1520 return error;
1521}
1522
1523#if 0
1524/* $$$ turn back on again someday, maybe */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001525static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1526 vlib_cli_parse_rule_t *
1527 lo,
1528 vlib_cli_parse_rule_t *
1529 hi)
1530 __attribute__ ((unused))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001531{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001532 clib_error_t *error = 0;
1533 vlib_cli_parse_rule_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001534
1535 for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1536 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001537 if (!r->name || strlen (r->name) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001538 {
1539 error = clib_error_return (0, "parse rule with no name");
1540 goto done;
1541 }
1542
1543 error = vlib_cli_register_parse_rule (vm, r);
1544 if (error)
1545 goto done;
1546 }
1547
Dave Barach9b8ffd92016-07-08 08:13:45 -04001548done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001549 return error;
1550}
1551#endif
1552
Damjan Marion9c2b9f42017-04-21 13:56:40 +02001553static int
1554cli_path_compare (void *a1, void *a2)
1555{
1556 u8 **s1 = a1;
1557 u8 **s2 = a2;
1558
1559 if ((vec_len (*s1) < vec_len (*s2)) &&
1560 memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1561 return -1;
1562
1563
1564 if ((vec_len (*s1) > vec_len (*s2)) &&
1565 memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1566 return 1;
1567
1568 return vec_cmp (*s1, *s2);
1569}
1570
1571static clib_error_t *
1572show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1573 vlib_cli_command_t * cmd)
1574{
1575 vlib_cli_main_t *cm = &vm->cli_main;
1576 vlib_cli_command_t *cli;
1577 u8 **paths = 0, **s;
1578
1579 /* *INDENT-OFF* */
1580 vec_foreach (cli, cm->commands)
1581 if (vec_len (cli->path) > 0)
1582 vec_add1 (paths, (u8 *) cli->path);
1583
1584 vec_sort_with_function (paths, cli_path_compare);
1585
1586 vec_foreach (s, paths)
1587 vlib_cli_output (vm, "%v", *s);
1588 /* *INDENT-ON* */
1589
1590 vec_free (paths);
1591 return 0;
1592}
1593
1594/* *INDENT-OFF* */
1595VLIB_CLI_COMMAND (show_cli_command, static) = {
1596 .path = "show cli",
1597 .short_help = "Show cli commands",
1598 .function = show_cli_cmd_fn,
1599};
1600/* *INDENT-ON* */
1601
Dave Barach9b8ffd92016-07-08 08:13:45 -04001602static clib_error_t *
Dave Barachc3a06552018-10-01 09:25:32 -04001603elog_trace_command_fn (vlib_main_t * vm,
1604 unformat_input_t * input, vlib_cli_command_t * cmd)
1605{
1606 unformat_input_t _line_input, *line_input = &_line_input;
1607 int enable = 1;
Dave Barach900cbad2019-01-31 19:12:51 -05001608 int api = 0, cli = 0, barrier = 0, dispatch = 0, circuit = 0;
1609 u32 circuit_node_index;
Dave Barachc3a06552018-10-01 09:25:32 -04001610
1611 if (!unformat_user (input, unformat_line_input, line_input))
1612 goto print_status;
1613
1614 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1615 {
1616 if (unformat (line_input, "api"))
1617 api = 1;
Dave Barach900cbad2019-01-31 19:12:51 -05001618 else if (unformat (line_input, "dispatch"))
1619 dispatch = 1;
1620 else if (unformat (line_input, "circuit-node %U",
1621 unformat_vlib_node, vm, &circuit_node_index))
1622 circuit = 1;
Dave Barachc3a06552018-10-01 09:25:32 -04001623 else if (unformat (line_input, "cli"))
1624 cli = 1;
1625 else if (unformat (line_input, "barrier"))
1626 barrier = 1;
1627 else if (unformat (line_input, "disable"))
1628 enable = 0;
1629 else if (unformat (line_input, "enable"))
1630 enable = 1;
1631 else
1632 break;
1633 }
1634 unformat_free (line_input);
1635
Dave Barachb09f4d02019-07-15 16:00:03 -04001636 vl_api_set_elog_trace_api_messages
1637 (api ? enable : vl_api_get_elog_trace_api_messages ());
Dave Barachc3a06552018-10-01 09:25:32 -04001638 vm->elog_trace_cli_commands = cli ? enable : vm->elog_trace_cli_commands;
Dave Barach900cbad2019-01-31 19:12:51 -05001639 vm->elog_trace_graph_dispatch = dispatch ?
1640 enable : vm->elog_trace_graph_dispatch;
1641 vm->elog_trace_graph_circuit = circuit ?
1642 enable : vm->elog_trace_graph_circuit;
Dave Barachc3a06552018-10-01 09:25:32 -04001643 vlib_worker_threads->barrier_elog_enabled =
1644 barrier ? enable : vlib_worker_threads->barrier_elog_enabled;
Dave Barach900cbad2019-01-31 19:12:51 -05001645 vm->elog_trace_graph_circuit_node_index = circuit_node_index;
1646
1647 /*
1648 * Set up start-of-buffer logic-analyzer trigger
1649 * for main loop event logs, which are fairly heavyweight.
1650 * See src/vlib/main/vlib_elog_main_loop_event(...), which
1651 * will fully disable the scheme when the elog buffer fills.
1652 */
1653 if (dispatch || circuit)
1654 {
1655 elog_main_t *em = &vm->elog_main;
1656
1657 em->n_total_events_disable_limit =
1658 em->n_total_events + vec_len (em->event_ring);
1659 }
1660
Dave Barachc3a06552018-10-01 09:25:32 -04001661
1662print_status:
1663 vlib_cli_output (vm, "Current status:");
1664
1665 vlib_cli_output
1666 (vm, " Event log API message trace: %s\n CLI command trace: %s",
Dave Barachb09f4d02019-07-15 16:00:03 -04001667 vl_api_get_elog_trace_api_messages ()? "on" : "off",
Dave Barachc3a06552018-10-01 09:25:32 -04001668 vm->elog_trace_cli_commands ? "on" : "off");
1669 vlib_cli_output
1670 (vm, " Barrier sync trace: %s",
1671 vlib_worker_threads->barrier_elog_enabled ? "on" : "off");
Dave Barach900cbad2019-01-31 19:12:51 -05001672 vlib_cli_output
1673 (vm, " Graph Dispatch: %s",
1674 vm->elog_trace_graph_dispatch ? "on" : "off");
1675 vlib_cli_output
1676 (vm, " Graph Circuit: %s",
1677 vm->elog_trace_graph_circuit ? "on" : "off");
1678 if (vm->elog_trace_graph_circuit)
1679 vlib_cli_output
1680 (vm, " node %U",
1681 format_vlib_node_name, vm, vm->elog_trace_graph_circuit_node_index);
Dave Barachc3a06552018-10-01 09:25:32 -04001682
1683 return 0;
1684}
1685
1686/*?
1687 * Control event logging of api, cli, and thread barrier events
1688 * With no arguments, displays the current trace status.
1689 * Name the event groups you wish to trace or stop tracing.
1690 *
1691 * @cliexpar
1692 * @clistart
1693 * elog trace api cli barrier
1694 * elog trace api cli barrier disable
Dave Barach900cbad2019-01-31 19:12:51 -05001695 * elog trace dispatch
1696 * elog trace circuit-node ethernet-input
Dave Barachc3a06552018-10-01 09:25:32 -04001697 * elog trace
1698 * @cliend
1699 * @cliexcmd{elog trace [api][cli][barrier][disable]}
1700?*/
1701/* *INDENT-OFF* */
1702VLIB_CLI_COMMAND (elog_trace_command, static) =
1703{
1704 .path = "elog trace",
Dave Barach900cbad2019-01-31 19:12:51 -05001705 .short_help = "elog trace [api][cli][barrier][dispatch]\n"
1706 "[circuit-node <name> e.g. ethernet-input][disable]",
Dave Barachc3a06552018-10-01 09:25:32 -04001707 .function = elog_trace_command_fn,
1708};
1709/* *INDENT-ON* */
1710
1711static clib_error_t *
Dave Barachc4abafd2019-09-04 12:09:32 -04001712suspend_command_fn (vlib_main_t * vm,
1713 unformat_input_t * input, vlib_cli_command_t * cmd)
1714{
1715 vlib_process_suspend (vm, 30e-3);
1716 return 0;
1717}
1718
1719/* *INDENT-OFF* */
1720VLIB_CLI_COMMAND (suspend_command, static) =
1721{
1722 .path = "suspend",
1723 .short_help = "suspend debug CLI for 30ms",
1724 .function = suspend_command_fn,
1725};
1726/* *INDENT-ON* */
1727
1728static clib_error_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -04001729vlib_cli_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001731 vlib_cli_main_t *cm = &vm->cli_main;
1732 clib_error_t *error = 0;
1733 vlib_cli_command_t *cmd;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001734
1735 cmd = cm->cli_command_registrations;
1736
1737 while (cmd)
1738 {
1739 error = vlib_cli_register (vm, cmd);
1740 if (error)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001741 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001742 cmd = cmd->next_cli_command;
1743 }
1744 return error;
1745}
1746
1747VLIB_INIT_FUNCTION (vlib_cli_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001748
1749/*
1750 * fd.io coding-style-patch-verification: ON
1751 *
1752 * Local Variables:
1753 * eval: (c-set-style "gnu")
1754 * End:
1755 */