VPP API: Memory trace
[vpp.git] / src / vlib / cli.c
1 /*
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>
41 #include <vppinfra/cpu.h>
42 #include <unistd.h>
43 #include <ctype.h>
44
45 /* Root of all show commands. */
46 /* *INDENT-OFF* */
47 VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
48   .path = "show",
49   .short_help = "Show commands",
50 };
51 /* *INDENT-ON* */
52
53 /* Root of all clear commands. */
54 /* *INDENT-OFF* */
55 VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
56   .path = "clear",
57   .short_help = "Clear commands",
58 };
59 /* *INDENT-ON* */
60
61 /* Root of all set commands. */
62 /* *INDENT-OFF* */
63 VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
64   .path = "set",
65   .short_help = "Set commands",
66 };
67 /* *INDENT-ON* */
68
69 /* Root of all test commands. */
70 /* *INDENT-OFF* */
71 VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
72   .path = "test",
73   .short_help = "Test commands",
74 };
75 /* *INDENT-ON* */
76
77 /* Returns bitmap of commands which match key. */
78 static uword *
79 vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
80 {
81   int i, n;
82   uword *match = 0;
83   vlib_cli_parse_position_t *p;
84
85   unformat_skip_white_space (input);
86
87   for (i = 0;; i++)
88     {
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':
97         case '-':
98         case '_':
99           break;
100
101         case ' ':
102         case '\t':
103         case '\r':
104         case '\n':
105         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
146 done:
147   return match;
148 }
149
150 /* Looks for string based sub-input formatted { SUB-INPUT }. */
151 uword
152 unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
153 {
154   unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
155   u8 *s;
156   uword c;
157
158   while (1)
159     {
160       c = unformat_get_input (i);
161       switch (c)
162         {
163         case ' ':
164         case '\t':
165         case '\n':
166         case '\r':
167         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
187 static vlib_cli_command_t *
188 get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
189 {
190   vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si);
191   return vec_elt_at_index (cm->commands, s->index);
192 }
193
194 static uword
195 unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
196 {
197   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;
202
203   {
204     vlib_cli_sub_rule_t *sr;
205     vlib_cli_parse_rule_t *r;
206     vec_foreach (sr, c->sub_rules)
207     {
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     }
224   }
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
239 static int
240 vlib_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
248 u8 **
249 vlib_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
332 done:
333   clib_bitmap_free (match_bitmap);
334   unformat_free (&input);
335
336   if (result)
337     vec_sort_with_function (result, vlib_cli_cmp_strings);
338   return result;
339 }
340
341 static u8 *
342 format_vlib_cli_command_help (u8 * s, va_list * args)
343 {
344   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
345   int is_long = va_arg (*args, int);
346   if (is_long && c->long_help)
347     s = format (s, "%s", c->long_help);
348   else if (c->short_help)
349     s = format (s, "%s", c->short_help);
350   else
351     s = format (s, "%v commands", c->path);
352   return s;
353 }
354
355 static u8 *
356 format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
357 {
358   vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
359   return format (s, "<%U>", format_c_identifier, r->name);
360 }
361
362 static u8 *
363 format_vlib_cli_path (u8 * s, va_list * args)
364 {
365   u8 *path = va_arg (*args, u8 *);
366   int i, in_rule;
367   in_rule = 0;
368   for (i = 0; i < vec_len (path); i++)
369     {
370       switch (path[i])
371         {
372         case '%':
373           in_rule = 1;
374           vec_add1 (s, '<');    /* start of <RULE> */
375           break;
376
377         case '_':
378           /* _ -> space in rules. */
379           vec_add1 (s, in_rule ? ' ' : '_');
380           break;
381
382         case ' ':
383           if (in_rule)
384             {
385               vec_add1 (s, '>');        /* end of <RULE> */
386               in_rule = 0;
387             }
388           vec_add1 (s, ' ');
389           break;
390
391         default:
392           vec_add1 (s, path[i]);
393           break;
394         }
395     }
396
397   if (in_rule)
398     vec_add1 (s, '>');          /* terminate <RULE> */
399
400   return s;
401 }
402
403 static vlib_cli_command_t *
404 all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
405 {
406   vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
407   vlib_cli_sub_command_t *sc;
408   vlib_cli_sub_rule_t *sr;
409
410   if (c->function)
411     vec_add1 (subs, c[0]);
412
413   vec_foreach (sr, c->sub_rules)
414     subs = all_subs (cm, subs, sr->command_index);
415   vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
416
417   return subs;
418 }
419
420 static int
421 vlib_cli_cmp_rule (void *a1, void *a2)
422 {
423   vlib_cli_sub_rule_t *r1 = a1;
424   vlib_cli_sub_rule_t *r2 = a2;
425
426   return vec_cmp (r1->name, r2->name);
427 }
428
429 static int
430 vlib_cli_cmp_command (void *a1, void *a2)
431 {
432   vlib_cli_command_t *c1 = a1;
433   vlib_cli_command_t *c2 = a2;
434
435   return vec_cmp (c1->path, c2->path);
436 }
437
438 static clib_error_t *
439 vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
440                                 vlib_cli_main_t * cm,
441                                 unformat_input_t * input,
442                                 uword parent_command_index)
443 {
444   vlib_cli_command_t *parent, *c;
445   clib_error_t *error = 0;
446   unformat_input_t sub_input;
447   u8 *string;
448   uword is_main_dispatch = cm == &vm->cli_main;
449
450   parent = vec_elt_at_index (cm->commands, parent_command_index);
451   if (is_main_dispatch && unformat (input, "help"))
452     {
453       uword help_at_end_of_line, i;
454
455       help_at_end_of_line =
456         unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
457       while (1)
458         {
459           c = parent;
460           if (unformat_user
461               (input, unformat_vlib_cli_sub_command, vm, c, &parent))
462             ;
463
464           else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
465             goto unknown;
466
467           else
468             break;
469         }
470
471       /* help SUB-COMMAND => long format help.
472          "help" at end of line: show all commands. */
473       if (!help_at_end_of_line)
474         vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
475                          /* is_long */ 1);
476
477       else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
478         vlib_cli_output (vm, "%v: no sub-commands", c->path);
479
480       else
481         {
482           vlib_cli_sub_command_t *sc;
483           vlib_cli_sub_rule_t *sr, *subs;
484
485           subs = vec_dup (c->sub_rules);
486
487           /* Add in rules if any. */
488           vec_foreach (sc, c->sub_commands)
489           {
490             vec_add2 (subs, sr, 1);
491             sr->name = sc->name;
492             sr->command_index = sc->index;
493             sr->rule_index = ~0;
494           }
495
496           vec_sort_with_function (subs, vlib_cli_cmp_rule);
497
498           for (i = 0; i < vec_len (subs); i++)
499             {
500               vlib_cli_command_t *d;
501               vlib_cli_parse_rule_t *r;
502
503               d = vec_elt_at_index (cm->commands, subs[i].command_index);
504               r =
505                 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
506                                                              subs
507                                                              [i].rule_index) :
508                 0;
509
510               if (r)
511                 vlib_cli_output
512                   (vm, "  %-30U %U",
513                    format_vlib_cli_parse_rule_name, r,
514                    format_vlib_cli_command_help, d, /* is_long */ 0);
515               else
516                 vlib_cli_output
517                   (vm, "  %-30v %U",
518                    subs[i].name,
519                    format_vlib_cli_command_help, d, /* is_long */ 0);
520             }
521
522           vec_free (subs);
523         }
524     }
525
526   else if (is_main_dispatch
527            && (unformat (input, "choices") || unformat (input, "?")))
528     {
529       vlib_cli_command_t *sub, *subs;
530
531       subs = all_subs (cm, 0, parent_command_index);
532       vec_sort_with_function (subs, vlib_cli_cmp_command);
533       vec_foreach (sub, subs)
534         vlib_cli_output (vm, "  %-40U %U",
535                          format_vlib_cli_path, sub->path,
536                          format_vlib_cli_command_help, sub, /* is_long */ 0);
537       vec_free (subs);
538     }
539
540   else if (unformat (input, "comment %v", &string))
541     {
542       vec_free (string);
543     }
544
545   else if (unformat (input, "uncomment %U",
546                      unformat_vlib_cli_sub_input, &sub_input))
547     {
548       error =
549         vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
550                                         parent_command_index);
551       unformat_free (&sub_input);
552     }
553
554   else
555     if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
556     {
557       unformat_input_t *si;
558       uword has_sub_commands =
559         vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
560
561       si = input;
562       if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
563         si = &sub_input;
564
565       if (has_sub_commands)
566         error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
567
568       if (has_sub_commands && !error)
569         /* Found valid sub-command. */ ;
570
571       else if (c->function)
572         {
573           clib_error_t *c_error;
574
575           /* Skip white space for benefit of called function. */
576           unformat_skip_white_space (si);
577
578           if (unformat (si, "?"))
579             {
580               vlib_cli_output (vm, "  %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c,        /* is_long */
581                                0);
582             }
583           else
584             {
585               if (!c->is_mp_safe)
586                 vlib_worker_thread_barrier_sync (vm);
587
588               c_error = c->function (vm, si, c);
589
590               if (!c->is_mp_safe)
591                 vlib_worker_thread_barrier_release (vm);
592
593               if (c_error)
594                 {
595                   error =
596                     clib_error_return (0, "%v: %v", c->path, c_error->what);
597                   clib_error_free (c_error);
598                   /* Free sub input. */
599                   if (si != input)
600                     unformat_free (si);
601
602                   return error;
603                 }
604             }
605
606           /* Free any previous error. */
607           clib_error_free (error);
608         }
609
610       else if (!error)
611         error = clib_error_return (0, "%v: no sub-commands", c->path);
612
613       /* Free sub input. */
614       if (si != input)
615         unformat_free (si);
616     }
617
618   else
619     goto unknown;
620
621   return error;
622
623 unknown:
624   if (parent->path)
625     return clib_error_return (0, "%v: unknown input `%U'", parent->path,
626                               format_unformat_error, input);
627   else
628     return clib_error_return (0, "unknown input `%U'", format_unformat_error,
629                               input);
630 }
631
632
633 void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
634   __attribute__ ((weak));
635
636 void
637 vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
638 {
639 }
640
641 /* Process CLI input. */
642 void
643 vlib_cli_input (vlib_main_t * vm,
644                 unformat_input_t * input,
645                 vlib_cli_output_function_t * function, uword function_arg)
646 {
647   vlib_process_t *cp = vlib_get_current_process (vm);
648   vlib_cli_main_t *cm = &vm->cli_main;
649   clib_error_t *error;
650   vlib_cli_output_function_t *save_function;
651   uword save_function_arg;
652
653   save_function = cp->output_function;
654   save_function_arg = cp->output_function_arg;
655
656   cp->output_function = function;
657   cp->output_function_arg = function_arg;
658
659   do
660     {
661       vec_reset_length (cm->parse_rule_data);
662       error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
663                                               0);
664     }
665   while (!error && !unformat (input, "%U", unformat_eof));
666
667   if (error)
668     {
669       vlib_cli_output (vm, "%v", error->what);
670       vlib_unix_error_report (vm, error);
671       clib_error_free (error);
672     }
673
674   cp->output_function = save_function;
675   cp->output_function_arg = save_function_arg;
676 }
677
678 /* Output to current CLI connection. */
679 void
680 vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
681 {
682   vlib_process_t *cp = vlib_get_current_process (vm);
683   va_list va;
684   u8 *s;
685
686   va_start (va, fmt);
687   s = va_format (0, fmt, &va);
688   va_end (va);
689
690   /* Terminate with \n if not present. */
691   if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
692     vec_add1 (s, '\n');
693
694   if ((!cp) || (!cp->output_function))
695     fformat (stdout, "%v", s);
696   else
697     cp->output_function (cp->output_function_arg, s, vec_len (s));
698
699   vec_free (s);
700 }
701
702 void *vl_msg_push_heap (void) __attribute__ ((weak));
703 void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
704
705 static clib_error_t *
706 show_memory_usage (vlib_main_t * vm,
707                    unformat_input_t * input, vlib_cli_command_t * cmd)
708 {
709   int verbose = 0, api_segment = 0;
710   clib_error_t *error;
711   u32 index = 0;
712
713   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
714     {
715       if (unformat (input, "verbose"))
716         verbose = 1;
717       else if (unformat (input, "api-segment"))
718         api_segment = 1;
719       else
720         {
721           error = clib_error_return (0, "unknown input `%U'",
722                                      format_unformat_error, input);
723           return error;
724         }
725     }
726
727   if (api_segment)
728     {
729       void *oldheap = vl_msg_push_heap ();
730       u8 *s_in_svm =
731         format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
732       vl_msg_pop_heap (oldheap);
733       u8 *s = vec_dup (s_in_svm);
734
735       oldheap = vl_msg_push_heap ();
736       vec_free (s_in_svm);
737       vl_msg_pop_heap (oldheap);
738       vlib_cli_output (vm, "API segment start:");
739       vlib_cli_output (vm, "%v", s);
740       vlib_cli_output (vm, "API segment end:");
741       vec_free (s);
742     }
743
744   /* *INDENT-OFF* */
745   foreach_vlib_main (
746   ({
747       vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
748       vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
749       index++;
750   }));
751   /* *INDENT-ON* */
752   return 0;
753 }
754
755 /* *INDENT-OFF* */
756 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
757   .path = "show memory",
758   .short_help = "[verbose | api-segment] Show current memory usage",
759   .function = show_memory_usage,
760 };
761 /* *INDENT-ON* */
762
763 static clib_error_t *
764 show_cpu (vlib_main_t * vm, unformat_input_t * input,
765           vlib_cli_command_t * cmd)
766 {
767 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
768   _("Model name", "%U", format_cpu_model_name);
769   _("Microarchitecture", "%U", format_cpu_uarch);
770   _("Flags", "%U", format_cpu_flags);
771   _("Base frequency", "%.2f GHz",
772     ((f64) vm->clib_time.clocks_per_second) * 1e-9);
773 #undef _
774   return 0;
775 }
776
777 /*?
778  * Displays various information about the CPU.
779  *
780  * @cliexpar
781  * @cliexstart{show cpu}
782  * Model name:               Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
783  * Microarchitecture:        Broadwell (Broadwell-EP/EX)
784  * Flags:                    sse3 ssse3 sse41 sse42 avx avx2 aes
785  * Base Frequency:           3.20 GHz
786  * @cliexend
787 ?*/
788 /* *INDENT-OFF* */
789 VLIB_CLI_COMMAND (show_cpu_command, static) = {
790   .path = "show cpu",
791   .short_help = "Show cpu information",
792   .function = show_cpu,
793 };
794
795 /* *INDENT-ON* */
796
797 static clib_error_t *
798 enable_disable_memory_trace (vlib_main_t * vm,
799                              unformat_input_t * input,
800                              vlib_cli_command_t * cmd)
801 {
802   unformat_input_t _line_input, *line_input = &_line_input;
803   int enable;
804   int api_segment = 0;
805   void *oldheap;
806
807
808   if (!unformat_user (input, unformat_line_input, line_input))
809     return 0;
810
811   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
812     {
813       if (!unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
814         ;
815       else if (unformat (line_input, "api-segment"))
816         api_segment = 1;
817       else
818         {
819           unformat_free (line_input);
820           return clib_error_return (0, "invalid input");
821         }
822     }
823   unformat_free (line_input);
824
825   if (api_segment)
826     oldheap = vl_msg_push_heap ();
827   clib_mem_trace (enable);
828   if (api_segment)
829     vl_msg_pop_heap (oldheap);
830
831   return 0;
832 }
833
834 /* *INDENT-OFF* */
835 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
836   .path = "memory-trace",
837   .short_help = "on|off [api-segment] Enable/disable memory allocation trace",
838   .function = enable_disable_memory_trace,
839 };
840 /* *INDENT-ON* */
841
842
843 static clib_error_t *
844 test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
845                     vlib_cli_command_t * cmd)
846 {
847   clib_error_t *error = 0;
848   void *heap;
849   mheap_t *mheap;
850
851   if (unformat (input, "on"))
852     {
853         /* *INDENT-OFF* */
854         foreach_vlib_main({
855           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
856           mheap = mheap_header(heap);
857           mheap->flags |= MHEAP_FLAG_VALIDATE;
858           // Turn off small object cache because it delays detection of errors
859           mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
860         });
861         /* *INDENT-ON* */
862
863     }
864   else if (unformat (input, "off"))
865     {
866         /* *INDENT-OFF* */
867         foreach_vlib_main({
868           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
869           mheap = mheap_header(heap);
870           mheap->flags &= ~MHEAP_FLAG_VALIDATE;
871           mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
872         });
873         /* *INDENT-ON* */
874     }
875   else if (unformat (input, "now"))
876     {
877         /* *INDENT-OFF* */
878         foreach_vlib_main({
879           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
880           mheap = mheap_header(heap);
881           mheap_validate(heap);
882         });
883         /* *INDENT-ON* */
884       vlib_cli_output (vm, "heap validation complete");
885
886     }
887   else
888     {
889       return clib_error_return (0, "unknown input `%U'",
890                                 format_unformat_error, input);
891     }
892
893   return error;
894 }
895
896 /* *INDENT-OFF* */
897 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
898     .path = "test heap-validate",
899     .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
900     .function = test_heap_validate,
901 };
902 /* *INDENT-ON* */
903
904 static clib_error_t *
905 restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
906                 vlib_cli_command_t * cmd)
907 {
908   char *newenviron[] = { NULL };
909
910   execve (vm->name, (char **) vm->argv, newenviron);
911
912   return 0;
913 }
914
915 /* *INDENT-OFF* */
916 VLIB_CLI_COMMAND (restart_cmd,static) = {
917     .path = "restart",
918     .short_help = "restart process",
919     .function = restart_cmd_fn,
920 };
921 /* *INDENT-ON* */
922
923 #ifdef TEST_CODE
924 /*
925  * A trivial test harness to verify the per-process output_function
926  * is working correcty.
927  */
928
929 static clib_error_t *
930 sleep_ten_seconds (vlib_main_t * vm,
931                    unformat_input_t * input, vlib_cli_command_t * cmd)
932 {
933   u16 i;
934   u16 my_id = rand ();
935
936   vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
937
938   for (i = 0; i < 10; i++)
939     {
940       vlib_process_wait_for_event_or_clock (vm, 1.0);
941       vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
942     }
943   vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
944   return 0;
945 }
946
947 /* *INDENT-OFF* */
948 VLIB_CLI_COMMAND (ping_command, static) = {
949   .path = "test sleep",
950   .function = sleep_ten_seconds,
951   .short_help = "Sleep for 10 seconds",
952 };
953 /* *INDENT-ON* */
954 #endif /* ifdef TEST_CODE */
955
956 static uword
957 vlib_cli_normalize_path (char *input, char **result)
958 {
959   char *i = input;
960   char *s = 0;
961   uword l = 0;
962   uword index_of_last_space = ~0;
963
964   while (*i != 0)
965     {
966       u8 c = *i++;
967       /* Multiple white space -> single space. */
968       switch (c)
969         {
970         case ' ':
971         case '\t':
972         case '\n':
973         case '\r':
974           if (l > 0 && s[l - 1] != ' ')
975             {
976               vec_add1 (s, ' ');
977               l++;
978             }
979           break;
980
981         default:
982           if (l > 0 && s[l - 1] == ' ')
983             index_of_last_space = vec_len (s);
984           vec_add1 (s, c);
985           l++;
986           break;
987         }
988     }
989
990   /* Remove any extra space at end. */
991   if (l > 0 && s[l - 1] == ' ')
992     _vec_len (s) -= 1;
993
994   *result = s;
995   return index_of_last_space;
996 }
997
998 always_inline uword
999 parent_path_len (char *path)
1000 {
1001   word i;
1002   for (i = vec_len (path) - 1; i >= 0; i--)
1003     {
1004       if (path[i] == ' ')
1005         return i;
1006     }
1007   return ~0;
1008 }
1009
1010 static void
1011 add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
1012 {
1013   vlib_cli_command_t *p, *c;
1014   vlib_cli_sub_command_t *sub_c;
1015   u8 *sub_name;
1016   word i, l;
1017
1018   p = vec_elt_at_index (cm->commands, parent_index);
1019   c = vec_elt_at_index (cm->commands, child_index);
1020
1021   l = parent_path_len (c->path);
1022   if (l == ~0)
1023     sub_name = vec_dup ((u8 *) c->path);
1024   else
1025     {
1026       ASSERT (l + 1 < vec_len (c->path));
1027       sub_name = 0;
1028       vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
1029     }
1030
1031   if (sub_name[0] == '%')
1032     {
1033       uword *q;
1034       vlib_cli_sub_rule_t *sr;
1035
1036       /* Remove %. */
1037       vec_delete (sub_name, 1, 0);
1038
1039       if (!p->sub_rule_index_by_name)
1040         p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1041                                                      sizeof (sub_name[0]),
1042                                                      sizeof (uword));
1043       q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1044       if (q)
1045         {
1046           sr = vec_elt_at_index (p->sub_rules, q[0]);
1047           ASSERT (sr->command_index == child_index);
1048           return;
1049         }
1050
1051       q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
1052       if (!q)
1053         {
1054           clib_error ("reference to unknown rule `%%%v' in path `%v'",
1055                       sub_name, c->path);
1056           return;
1057         }
1058
1059       hash_set_mem (p->sub_rule_index_by_name, sub_name,
1060                     vec_len (p->sub_rules));
1061       vec_add2 (p->sub_rules, sr, 1);
1062       sr->name = sub_name;
1063       sr->rule_index = q[0];
1064       sr->command_index = child_index;
1065       return;
1066     }
1067
1068   if (!p->sub_command_index_by_name)
1069     p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1070                                                     sizeof (c->path[0]),
1071                                                     sizeof (uword));
1072
1073   /* Check if sub-command has already been created. */
1074   if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1075     {
1076       vec_free (sub_name);
1077       return;
1078     }
1079
1080   vec_add2 (p->sub_commands, sub_c, 1);
1081   sub_c->index = child_index;
1082   sub_c->name = sub_name;
1083   hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1084                 sub_c - p->sub_commands);
1085
1086   vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1087   for (i = 0; i < vec_len (sub_c->name); i++)
1088     {
1089       int n;
1090       vlib_cli_parse_position_t *pos;
1091
1092       pos = vec_elt_at_index (p->sub_command_positions, i);
1093
1094       if (!pos->bitmaps)
1095         pos->min_char = sub_c->name[i];
1096
1097       n = sub_c->name[i] - pos->min_char;
1098       if (n < 0)
1099         {
1100           pos->min_char = sub_c->name[i];
1101           vec_insert (pos->bitmaps, -n, 0);
1102           n = 0;
1103         }
1104
1105       vec_validate (pos->bitmaps, n);
1106       pos->bitmaps[n] =
1107         clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
1108     }
1109 }
1110
1111 static void
1112 vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1113 {
1114   uword p_len, pi, *p;
1115   char *p_path;
1116   vlib_cli_command_t *c, *parent;
1117
1118   /* Root command (index 0) should have already been added. */
1119   ASSERT (vec_len (cm->commands) > 0);
1120
1121   c = vec_elt_at_index (cm->commands, ci);
1122   p_len = parent_path_len (c->path);
1123
1124   /* No space?  Parent is root command. */
1125   if (p_len == ~0)
1126     {
1127       add_sub_command (cm, 0, ci);
1128       return;
1129     }
1130
1131   p_path = 0;
1132   vec_add (p_path, c->path, p_len);
1133
1134   p = hash_get_mem (cm->command_index_by_path, p_path);
1135
1136   /* Parent exists? */
1137   if (!p)
1138     {
1139       /* Parent does not exist; create it. */
1140       vec_add2 (cm->commands, parent, 1);
1141       parent->path = p_path;
1142       hash_set_mem (cm->command_index_by_path, parent->path,
1143                     parent - cm->commands);
1144       pi = parent - cm->commands;
1145     }
1146   else
1147     {
1148       pi = p[0];
1149       vec_free (p_path);
1150     }
1151
1152   add_sub_command (cm, pi, ci);
1153
1154   /* Create parent's parent. */
1155   if (!p)
1156     vlib_cli_make_parent (cm, pi);
1157 }
1158
1159 always_inline uword
1160 vlib_cli_command_is_empty (vlib_cli_command_t * c)
1161 {
1162   return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
1163 }
1164
1165 clib_error_t *
1166 vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
1167 {
1168   vlib_cli_main_t *cm = &vm->cli_main;
1169   clib_error_t *error = 0;
1170   uword ci, *p;
1171   char *normalized_path;
1172
1173   if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1174     return error;
1175
1176   (void) vlib_cli_normalize_path (c->path, &normalized_path);
1177
1178   if (!cm->command_index_by_path)
1179     cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
1180                                                  sizeof (c->path[0]),
1181                                                  sizeof (uword));
1182
1183   /* See if command already exists with given path. */
1184   p = hash_get_mem (cm->command_index_by_path, normalized_path);
1185   if (p)
1186     {
1187       vlib_cli_command_t *d;
1188
1189       ci = p[0];
1190       d = vec_elt_at_index (cm->commands, ci);
1191
1192       /* If existing command was created via vlib_cli_make_parent
1193          replaced it with callers data. */
1194       if (vlib_cli_command_is_empty (d))
1195         {
1196           vlib_cli_command_t save = d[0];
1197
1198           ASSERT (!vlib_cli_command_is_empty (c));
1199
1200           /* Copy callers fields. */
1201           d[0] = c[0];
1202
1203           /* Save internal fields. */
1204           d->path = save.path;
1205           d->sub_commands = save.sub_commands;
1206           d->sub_command_index_by_name = save.sub_command_index_by_name;
1207           d->sub_command_positions = save.sub_command_positions;
1208           d->sub_rules = save.sub_rules;
1209         }
1210       else
1211         error =
1212           clib_error_return (0, "duplicate command name with path %v",
1213                              normalized_path);
1214
1215       vec_free (normalized_path);
1216       if (error)
1217         return error;
1218     }
1219   else
1220     {
1221       /* Command does not exist: create it. */
1222
1223       /* Add root command (index 0). */
1224       if (vec_len (cm->commands) == 0)
1225         {
1226           /* Create command with index 0; path is empty string. */
1227           vec_resize (cm->commands, 1);
1228         }
1229
1230       ci = vec_len (cm->commands);
1231       hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1232       vec_add1 (cm->commands, c[0]);
1233
1234       c = vec_elt_at_index (cm->commands, ci);
1235       c->path = normalized_path;
1236
1237       /* Don't inherit from registration. */
1238       c->sub_commands = 0;
1239       c->sub_command_index_by_name = 0;
1240       c->sub_command_positions = 0;
1241     }
1242
1243   vlib_cli_make_parent (cm, ci);
1244   return 0;
1245 }
1246
1247 clib_error_t *
1248 vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1249 {
1250   vlib_cli_main_t *cm = &vm->cli_main;
1251   vlib_cli_parse_rule_t *r;
1252   clib_error_t *error = 0;
1253   u8 *r_name;
1254   uword *p;
1255
1256   if (!cm->parse_rule_index_by_name)
1257     cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1258                                                     sizeof (r->name[0]),
1259                                                     sizeof (uword));
1260
1261   /* Make vector copy of name. */
1262   r_name = format (0, "%s", r_reg->name);
1263
1264   if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1265     {
1266       vec_free (r_name);
1267       return clib_error_return (0, "duplicate parse rule name `%s'",
1268                                 r_reg->name);
1269     }
1270
1271   vec_add2 (cm->parse_rules, r, 1);
1272   r[0] = r_reg[0];
1273   r->name = (char *) r_name;
1274   hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1275
1276   return error;
1277 }
1278
1279 #if 0
1280 /* $$$ turn back on again someday, maybe */
1281 static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1282                                                     vlib_cli_parse_rule_t *
1283                                                     lo,
1284                                                     vlib_cli_parse_rule_t *
1285                                                     hi)
1286   __attribute__ ((unused))
1287 {
1288   clib_error_t *error = 0;
1289   vlib_cli_parse_rule_t *r;
1290
1291   for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1292     {
1293       if (!r->name || strlen (r->name) == 0)
1294         {
1295           error = clib_error_return (0, "parse rule with no name");
1296           goto done;
1297         }
1298
1299       error = vlib_cli_register_parse_rule (vm, r);
1300       if (error)
1301         goto done;
1302     }
1303
1304 done:
1305   return error;
1306 }
1307 #endif
1308
1309 static int
1310 cli_path_compare (void *a1, void *a2)
1311 {
1312   u8 **s1 = a1;
1313   u8 **s2 = a2;
1314
1315   if ((vec_len (*s1) < vec_len (*s2)) &&
1316       memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1317     return -1;
1318
1319
1320   if ((vec_len (*s1) > vec_len (*s2)) &&
1321       memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1322     return 1;
1323
1324   return vec_cmp (*s1, *s2);
1325 }
1326
1327 static clib_error_t *
1328 show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1329                  vlib_cli_command_t * cmd)
1330 {
1331   vlib_cli_main_t *cm = &vm->cli_main;
1332   vlib_cli_command_t *cli;
1333   u8 **paths = 0, **s;
1334
1335   /* *INDENT-OFF* */
1336   vec_foreach (cli, cm->commands)
1337     if (vec_len (cli->path) > 0)
1338       vec_add1 (paths, (u8 *) cli->path);
1339
1340   vec_sort_with_function (paths, cli_path_compare);
1341
1342   vec_foreach (s, paths)
1343     vlib_cli_output (vm, "%v", *s);
1344   /* *INDENT-ON* */
1345
1346   vec_free (paths);
1347   return 0;
1348 }
1349
1350 /* *INDENT-OFF* */
1351 VLIB_CLI_COMMAND (show_cli_command, static) = {
1352   .path = "show cli",
1353   .short_help = "Show cli commands",
1354   .function = show_cli_cmd_fn,
1355 };
1356 /* *INDENT-ON* */
1357
1358 static clib_error_t *
1359 vlib_cli_init (vlib_main_t * vm)
1360 {
1361   vlib_cli_main_t *cm = &vm->cli_main;
1362   clib_error_t *error = 0;
1363   vlib_cli_command_t *cmd;
1364
1365   cmd = cm->cli_command_registrations;
1366
1367   while (cmd)
1368     {
1369       error = vlib_cli_register (vm, cmd);
1370       if (error)
1371         return error;
1372       cmd = cmd->next_cli_command;
1373     }
1374   return error;
1375 }
1376
1377 VLIB_INIT_FUNCTION (vlib_cli_init);
1378
1379 /*
1380  * fd.io coding-style-patch-verification: ON
1381  *
1382  * Local Variables:
1383  * eval: (c-set-style "gnu")
1384  * End:
1385  */