ec27c48137429dd7381ff35b683ac4f20798b0bc
[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 <vlib/unix/unix.h>
42 #include <vppinfra/cpu.h>
43 #include <vppinfra/elog.h>
44 #include <unistd.h>
45 #include <ctype.h>
46
47 /** \file src/vlib/cli.c Debug CLI Implementation
48  */
49
50 int vl_api_set_elog_trace_api_messages (int enable);
51 int vl_api_get_elog_trace_api_messages (void);
52
53 static void *current_traced_heap;
54
55 /* Root of all show commands. */
56 /* *INDENT-OFF* */
57 VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
58   .path = "show",
59   .short_help = "Show commands",
60 };
61 /* *INDENT-ON* */
62
63 /* Root of all clear commands. */
64 /* *INDENT-OFF* */
65 VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
66   .path = "clear",
67   .short_help = "Clear commands",
68 };
69 /* *INDENT-ON* */
70
71 /* Root of all set commands. */
72 /* *INDENT-OFF* */
73 VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
74   .path = "set",
75   .short_help = "Set commands",
76 };
77 /* *INDENT-ON* */
78
79 /* Root of all test commands. */
80 /* *INDENT-OFF* */
81 VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
82   .path = "test",
83   .short_help = "Test commands",
84 };
85 /* *INDENT-ON* */
86
87 /* Returns bitmap of commands which match key. */
88 static uword *
89 vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
90 {
91   int i, n;
92   uword *match = 0;
93   vlib_cli_parse_position_t *p;
94
95   unformat_skip_white_space (input);
96
97   for (i = 0;; i++)
98     {
99       uword k;
100
101       k = unformat_get_input (input);
102       switch (k)
103         {
104         case 'a' ... 'z':
105         case 'A' ... 'Z':
106         case '0' ... '9':
107         case '-':
108         case '_':
109           break;
110
111         case ' ':
112         case '\t':
113         case '\r':
114         case '\n':
115         case UNFORMAT_END_OF_INPUT:
116           /* White space or end of input removes any non-white
117              matches that were before possible. */
118           if (i < vec_len (c->sub_command_positions)
119               && clib_bitmap_count_set_bits (match) > 1)
120             {
121               p = vec_elt_at_index (c->sub_command_positions, i);
122               for (n = 0; n < vec_len (p->bitmaps); n++)
123                 match = clib_bitmap_andnot (match, p->bitmaps[n]);
124             }
125           goto done;
126
127         default:
128           unformat_put_input (input);
129           goto done;
130         }
131
132       if (i >= vec_len (c->sub_command_positions))
133         {
134         no_match:
135           clib_bitmap_free (match);
136           return 0;
137         }
138
139       p = vec_elt_at_index (c->sub_command_positions, i);
140       if (vec_len (p->bitmaps) == 0)
141         goto no_match;
142
143       n = k - p->min_char;
144       if (n < 0 || n >= vec_len (p->bitmaps))
145         goto no_match;
146
147       if (i == 0)
148         match = clib_bitmap_dup (p->bitmaps[n]);
149       else
150         match = clib_bitmap_and (match, p->bitmaps[n]);
151
152       if (clib_bitmap_is_zero (match))
153         goto no_match;
154     }
155
156 done:
157   return match;
158 }
159
160 /* Looks for string based sub-input formatted { SUB-INPUT }. */
161 uword
162 unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
163 {
164   unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
165   u8 *s;
166   uword c;
167
168   while (1)
169     {
170       c = unformat_get_input (i);
171       switch (c)
172         {
173         case ' ':
174         case '\t':
175         case '\n':
176         case '\r':
177         case '\f':
178           break;
179
180         case '{':
181         default:
182           /* Put back paren. */
183           if (c != UNFORMAT_END_OF_INPUT)
184             unformat_put_input (i);
185
186           if (c == '{' && unformat (i, "%v", &s))
187             {
188               unformat_init_vector (sub_input, s);
189               return 1;
190             }
191           return 0;
192         }
193     }
194   return 0;
195 }
196
197 static vlib_cli_command_t *
198 get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
199 {
200   vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si);
201   return vec_elt_at_index (cm->commands, s->index);
202 }
203
204 static uword
205 unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
206 {
207   vlib_main_t *vm = va_arg (*args, vlib_main_t *);
208   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
209   vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
210   vlib_cli_main_t *cm = &vm->cli_main;
211   uword *match_bitmap, is_unique, index;
212
213   {
214     vlib_cli_sub_rule_t *sr;
215     vlib_cli_parse_rule_t *r;
216     vec_foreach (sr, c->sub_rules)
217     {
218       void **d;
219       r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
220       vec_add2 (cm->parse_rule_data, d, 1);
221       vec_reset_length (d[0]);
222       if (r->data_size)
223         d[0] = _vec_resize (d[0],
224                             /* length increment */ 1,
225                             r->data_size,
226                             /* header_bytes */ 0,
227                             /* data align */ sizeof (uword));
228       if (unformat_user (i, r->unformat_function, vm, d[0]))
229         {
230           *result = vec_elt_at_index (cm->commands, sr->command_index);
231           return 1;
232         }
233     }
234   }
235
236   match_bitmap = vlib_cli_sub_command_match (c, i);
237   is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
238   index = ~0;
239   if (is_unique)
240     {
241       index = clib_bitmap_first_set (match_bitmap);
242       *result = get_sub_command (cm, c, index);
243     }
244   clib_bitmap_free (match_bitmap);
245
246   return is_unique;
247 }
248
249 static int
250 vlib_cli_cmp_strings (void *a1, void *a2)
251 {
252   u8 *c1 = *(u8 **) a1;
253   u8 *c2 = *(u8 **) a2;
254
255   return vec_cmp (c1, c2);
256 }
257
258 u8 **
259 vlib_cli_get_possible_completions (u8 * str)
260 {
261   vlib_cli_command_t *c;
262   vlib_cli_sub_command_t *sc;
263   vlib_main_t *vm = vlib_get_main ();
264   vlib_cli_main_t *vcm = &vm->cli_main;
265   uword *match_bitmap = 0;
266   uword index, is_unique, help_next_level;
267   u8 **result = 0;
268   unformat_input_t input;
269   unformat_init_vector (&input, vec_dup (str));
270   c = vec_elt_at_index (vcm->commands, 0);
271
272   /* remove trailing whitespace, except for one of them */
273   while (vec_len (input.buffer) >= 2 &&
274          isspace (input.buffer[vec_len (input.buffer) - 1]) &&
275          isspace (input.buffer[vec_len (input.buffer) - 2]))
276     {
277       vec_del1 (input.buffer, vec_len (input.buffer) - 1);
278     }
279
280   /* if input is empty, directly return list of root commands */
281   if (vec_len (input.buffer) == 0 ||
282       (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
283     {
284       vec_foreach (sc, c->sub_commands)
285       {
286         vec_add1 (result, (u8 *) sc->name);
287       }
288       goto done;
289     }
290
291   /* add a trailing '?' so that vlib_cli_sub_command_match can find
292    * all commands starting with the input string */
293   vec_add1 (input.buffer, '?');
294
295   while (1)
296     {
297       match_bitmap = vlib_cli_sub_command_match (c, &input);
298       /* no match: return no result */
299       if (match_bitmap == 0)
300         {
301           goto done;
302         }
303       is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
304       /* unique match: try to step one subcommand level further */
305       if (is_unique)
306         {
307           /* stop if no more input */
308           if (input.index >= vec_len (input.buffer) - 1)
309             {
310               break;
311             }
312
313           index = clib_bitmap_first_set (match_bitmap);
314           c = get_sub_command (vcm, c, index);
315           clib_bitmap_free (match_bitmap);
316           continue;
317         }
318       /* multiple matches: stop here, return all matches */
319       break;
320     }
321
322   /* remove trailing '?' */
323   vec_del1 (input.buffer, vec_len (input.buffer) - 1);
324
325   /* if we have a space at the end of input, and a unique match,
326    * autocomplete the next level of subcommands */
327   help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
328   /* *INDENT-OFF* */
329   clib_bitmap_foreach(index, match_bitmap, {
330     if (help_next_level && is_unique) {
331         c = get_sub_command (vcm, c, index);
332         vec_foreach (sc, c->sub_commands) {
333           vec_add1 (result, (u8*) sc->name);
334         }
335         goto done; /* break doesn't work in this macro-loop */
336     }
337     sc = &c->sub_commands[index];
338     vec_add1(result, (u8*) sc->name);
339   });
340   /* *INDENT-ON* */
341
342 done:
343   clib_bitmap_free (match_bitmap);
344   unformat_free (&input);
345
346   if (result)
347     vec_sort_with_function (result, vlib_cli_cmp_strings);
348   return result;
349 }
350
351 static u8 *
352 format_vlib_cli_command_help (u8 * s, va_list * args)
353 {
354   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
355   int is_long = va_arg (*args, int);
356   if (is_long && c->long_help)
357     s = format (s, "%s", c->long_help);
358   else if (c->short_help)
359     s = format (s, "%s", c->short_help);
360   else
361     s = format (s, "%v commands", c->path);
362   return s;
363 }
364
365 static u8 *
366 format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
367 {
368   vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
369   return format (s, "<%U>", format_c_identifier, r->name);
370 }
371
372 static u8 *
373 format_vlib_cli_path (u8 * s, va_list * args)
374 {
375   u8 *path = va_arg (*args, u8 *);
376   int i, in_rule;
377   in_rule = 0;
378   for (i = 0; i < vec_len (path); i++)
379     {
380       switch (path[i])
381         {
382         case '%':
383           in_rule = 1;
384           vec_add1 (s, '<');    /* start of <RULE> */
385           break;
386
387         case '_':
388           /* _ -> space in rules. */
389           vec_add1 (s, in_rule ? ' ' : '_');
390           break;
391
392         case ' ':
393           if (in_rule)
394             {
395               vec_add1 (s, '>');        /* end of <RULE> */
396               in_rule = 0;
397             }
398           vec_add1 (s, ' ');
399           break;
400
401         default:
402           vec_add1 (s, path[i]);
403           break;
404         }
405     }
406
407   if (in_rule)
408     vec_add1 (s, '>');          /* terminate <RULE> */
409
410   return s;
411 }
412
413 static vlib_cli_command_t *
414 all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
415 {
416   vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
417   vlib_cli_sub_command_t *sc;
418   vlib_cli_sub_rule_t *sr;
419
420   if (c->function)
421     vec_add1 (subs, c[0]);
422
423   vec_foreach (sr, c->sub_rules)
424     subs = all_subs (cm, subs, sr->command_index);
425   vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
426
427   return subs;
428 }
429
430 static int
431 vlib_cli_cmp_rule (void *a1, void *a2)
432 {
433   vlib_cli_sub_rule_t *r1 = a1;
434   vlib_cli_sub_rule_t *r2 = a2;
435
436   return vec_cmp (r1->name, r2->name);
437 }
438
439 static int
440 vlib_cli_cmp_command (void *a1, void *a2)
441 {
442   vlib_cli_command_t *c1 = a1;
443   vlib_cli_command_t *c2 = a2;
444
445   return vec_cmp (c1->path, c2->path);
446 }
447
448 static clib_error_t *
449 vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
450                                 vlib_cli_main_t * cm,
451                                 unformat_input_t * input,
452                                 uword parent_command_index)
453 {
454   vlib_cli_command_t *parent, *c;
455   clib_error_t *error = 0;
456   unformat_input_t sub_input;
457   u8 *string;
458   uword is_main_dispatch = cm == &vm->cli_main;
459
460   parent = vec_elt_at_index (cm->commands, parent_command_index);
461   if (is_main_dispatch && unformat (input, "help"))
462     {
463       uword help_at_end_of_line, i;
464
465       help_at_end_of_line =
466         unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
467       while (1)
468         {
469           c = parent;
470           if (unformat_user
471               (input, unformat_vlib_cli_sub_command, vm, c, &parent))
472             ;
473
474           else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
475             goto unknown;
476
477           else
478             break;
479         }
480
481       /* help SUB-COMMAND => long format help.
482          "help" at end of line: show all commands. */
483       if (!help_at_end_of_line)
484         vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
485                          /* is_long */ 1);
486
487       else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
488         vlib_cli_output (vm, "%v: no sub-commands", c->path);
489
490       else
491         {
492           vlib_cli_sub_command_t *sc;
493           vlib_cli_sub_rule_t *sr, *subs;
494
495           subs = vec_dup (c->sub_rules);
496
497           /* Add in rules if any. */
498           vec_foreach (sc, c->sub_commands)
499           {
500             vec_add2 (subs, sr, 1);
501             sr->name = sc->name;
502             sr->command_index = sc->index;
503             sr->rule_index = ~0;
504           }
505
506           vec_sort_with_function (subs, vlib_cli_cmp_rule);
507
508           for (i = 0; i < vec_len (subs); i++)
509             {
510               vlib_cli_command_t *d;
511               vlib_cli_parse_rule_t *r;
512
513               d = vec_elt_at_index (cm->commands, subs[i].command_index);
514               r =
515                 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
516                                                              subs
517                                                              [i].rule_index) :
518                 0;
519
520               if (r)
521                 vlib_cli_output
522                   (vm, "  %-30U %U",
523                    format_vlib_cli_parse_rule_name, r,
524                    format_vlib_cli_command_help, d, /* is_long */ 0);
525               else
526                 vlib_cli_output
527                   (vm, "  %-30v %U",
528                    subs[i].name,
529                    format_vlib_cli_command_help, d, /* is_long */ 0);
530             }
531
532           vec_free (subs);
533         }
534     }
535
536   else if (is_main_dispatch
537            && (unformat (input, "choices") || unformat (input, "?")))
538     {
539       vlib_cli_command_t *sub, *subs;
540
541       subs = all_subs (cm, 0, parent_command_index);
542       vec_sort_with_function (subs, vlib_cli_cmp_command);
543       vec_foreach (sub, subs)
544         vlib_cli_output (vm, "  %-40U %U",
545                          format_vlib_cli_path, sub->path,
546                          format_vlib_cli_command_help, sub, /* is_long */ 0);
547       vec_free (subs);
548     }
549
550   else if (unformat (input, "comment %v", &string))
551     {
552       vec_free (string);
553     }
554
555   else if (unformat (input, "uncomment %U",
556                      unformat_vlib_cli_sub_input, &sub_input))
557     {
558       error =
559         vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
560                                         parent_command_index);
561       unformat_free (&sub_input);
562     }
563   else if (unformat (input, "leak-check %U",
564                      unformat_vlib_cli_sub_input, &sub_input))
565     {
566       u8 *leak_report;
567       if (current_traced_heap)
568         {
569           void *oldheap;
570           oldheap = clib_mem_set_heap (current_traced_heap);
571           clib_mem_trace (0);
572           clib_mem_set_heap (oldheap);
573           current_traced_heap = 0;
574         }
575       clib_mem_trace (1);
576       error =
577         vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
578                                         parent_command_index);
579       unformat_free (&sub_input);
580
581       /* Otherwise, the clib_error_t shows up as a leak... */
582       if (error)
583         {
584           vlib_cli_output (vm, "%v", error->what);
585           clib_error_free (error);
586           error = 0;
587         }
588
589       (void) clib_mem_trace_enable_disable (0);
590       leak_report = format (0, "%U", format_mheap, clib_mem_get_heap (),
591                             1 /* verbose, i.e. print leaks */ );
592       clib_mem_trace (0);
593       vlib_cli_output (vm, "%v", leak_report);
594       vec_free (leak_report);
595     }
596
597   else
598     if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
599     {
600       unformat_input_t *si;
601       uword has_sub_commands =
602         vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
603
604       si = input;
605       if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
606         si = &sub_input;
607
608       if (has_sub_commands)
609         error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
610
611       if (has_sub_commands && !error)
612         /* Found valid sub-command. */ ;
613
614       else if (c->function)
615         {
616           clib_error_t *c_error;
617
618           /* Skip white space for benefit of called function. */
619           unformat_skip_white_space (si);
620
621           if (unformat (si, "?"))
622             {
623               vlib_cli_output (vm, "  %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c,        /* is_long */
624                                0);
625             }
626           else
627             {
628               if (PREDICT_FALSE (vm->elog_trace_cli_commands))
629                 {
630                   /* *INDENT-OFF* */
631                   ELOG_TYPE_DECLARE (e) =
632                     {
633                       .format = "cli-cmd: %s",
634                       .format_args = "T4",
635                     };
636                   /* *INDENT-ON* */
637                   struct
638                   {
639                     u32 c;
640                   } *ed;
641                   ed = ELOG_DATA (&vm->elog_main, e);
642                   ed->c = elog_string (&vm->elog_main, c->path);
643                 }
644
645               if (!c->is_mp_safe)
646                 vlib_worker_thread_barrier_sync (vm);
647
648               c->hit_counter++;
649               c_error = c->function (vm, si, c);
650
651               if (!c->is_mp_safe)
652                 vlib_worker_thread_barrier_release (vm);
653
654               if (PREDICT_FALSE (vm->elog_trace_cli_commands))
655                 {
656                   /* *INDENT-OFF* */
657                   ELOG_TYPE_DECLARE (e) =
658                     {
659                       .format = "cli-cmd: %s %s",
660                       .format_args = "T4T4",
661                     };
662                   /* *INDENT-ON* */
663                   struct
664                   {
665                     u32 c, err;
666                   } *ed;
667                   ed = ELOG_DATA (&vm->elog_main, e);
668                   ed->c = elog_string (&vm->elog_main, c->path);
669                   if (c_error)
670                     {
671                       vec_add1 (c_error->what, 0);
672                       ed->err = elog_string (&vm->elog_main,
673                                              (char *) c_error->what);
674                       _vec_len (c_error->what) -= 1;
675                     }
676                   else
677                     ed->err = elog_string (&vm->elog_main, "OK");
678                 }
679
680               if (c_error)
681                 {
682                   error =
683                     clib_error_return (0, "%v: %v", c->path, c_error->what);
684                   clib_error_free (c_error);
685                   /* Free sub input. */
686                   if (si != input)
687                     unformat_free (si);
688
689                   return error;
690                 }
691             }
692
693           /* Free any previous error. */
694           clib_error_free (error);
695         }
696
697       else if (!error)
698         error = clib_error_return (0, "%v: no sub-commands", c->path);
699
700       /* Free sub input. */
701       if (si != input)
702         unformat_free (si);
703     }
704
705   else
706     goto unknown;
707
708   return error;
709
710 unknown:
711   if (parent->path)
712     return clib_error_return (0, "%v: unknown input `%U'", parent->path,
713                               format_unformat_error, input);
714   else
715     return clib_error_return (0, "unknown input `%U'", format_unformat_error,
716                               input);
717 }
718
719
720 void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
721   __attribute__ ((weak));
722
723 void
724 vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
725 {
726 }
727
728 /* Process CLI input. */
729 int
730 vlib_cli_input (vlib_main_t * vm,
731                 unformat_input_t * input,
732                 vlib_cli_output_function_t * function, uword function_arg)
733 {
734   vlib_process_t *cp = vlib_get_current_process (vm);
735   vlib_cli_main_t *cm = &vm->cli_main;
736   clib_error_t *error;
737   vlib_cli_output_function_t *save_function;
738   uword save_function_arg;
739   int rv = 0;
740
741   save_function = cp->output_function;
742   save_function_arg = cp->output_function_arg;
743
744   cp->output_function = function;
745   cp->output_function_arg = function_arg;
746
747   do
748     {
749       vec_reset_length (cm->parse_rule_data);
750       error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
751                                               0);
752     }
753   while (!error && !unformat (input, "%U", unformat_eof));
754
755   if (error)
756     {
757       vlib_cli_output (vm, "%v", error->what);
758       vlib_unix_error_report (vm, error);
759       /* clib_error_return is unfortunately often called with a '0'
760          return code */
761       rv = error->code != 0 ? error->code : -1;
762       clib_error_free (error);
763     }
764
765   cp->output_function = save_function;
766   cp->output_function_arg = save_function_arg;
767   return rv;
768 }
769
770 /* Output to current CLI connection. */
771 void
772 vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
773 {
774   vlib_process_t *cp = vlib_get_current_process (vm);
775   va_list va;
776   u8 *s;
777
778   va_start (va, fmt);
779   s = va_format (0, fmt, &va);
780   va_end (va);
781
782   /* Terminate with \n if not present. */
783   if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
784     vec_add1 (s, '\n');
785
786   if ((!cp) || (!cp->output_function))
787     fformat (stdout, "%v", s);
788   else
789     cp->output_function (cp->output_function_arg, s, vec_len (s));
790
791   vec_free (s);
792 }
793
794 void *vl_msg_push_heap (void) __attribute__ ((weak));
795 void *
796 vl_msg_push_heap (void)
797 {
798   return 0;
799 }
800
801 void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
802 void
803 vl_msg_pop_heap (void *oldheap)
804 {
805 }
806
807 void *vlib_stats_push_heap (void *) __attribute__ ((weak));
808 void *
809 vlib_stats_push_heap (void *notused)
810 {
811   return 0;
812 }
813
814 static clib_error_t *
815 show_memory_usage (vlib_main_t * vm,
816                    unformat_input_t * input, vlib_cli_command_t * cmd)
817 {
818   int verbose __attribute__ ((unused)) = 0;
819   int api_segment = 0, stats_segment = 0, main_heap = 0;
820   clib_error_t *error;
821   u32 index = 0;
822   uword clib_mem_trace_enable_disable (uword enable);
823   uword was_enabled;
824
825
826   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
827     {
828       if (unformat (input, "verbose"))
829         verbose = 1;
830       else if (unformat (input, "api-segment"))
831         api_segment = 1;
832       else if (unformat (input, "stats-segment"))
833         stats_segment = 1;
834       else if (unformat (input, "main-heap"))
835         main_heap = 1;
836       else
837         {
838           error = clib_error_return (0, "unknown input `%U'",
839                                      format_unformat_error, input);
840           return error;
841         }
842     }
843
844   if ((api_segment + stats_segment + main_heap) == 0)
845     return clib_error_return
846       (0, "Please supply one of api-segment, stats-segment or main-heap");
847
848   if (api_segment)
849     {
850       void *oldheap = vl_msg_push_heap ();
851       was_enabled = clib_mem_trace_enable_disable (0);
852       u8 *s_in_svm =
853         format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
854       vl_msg_pop_heap (oldheap);
855       u8 *s = vec_dup (s_in_svm);
856
857       oldheap = vl_msg_push_heap ();
858       vec_free (s_in_svm);
859       clib_mem_trace_enable_disable (was_enabled);
860       vl_msg_pop_heap (oldheap);
861       vlib_cli_output (vm, "API segment");
862       vlib_cli_output (vm, "%v", s);
863       vec_free (s);
864     }
865   if (stats_segment)
866     {
867       void *oldheap = vlib_stats_push_heap (0);
868       was_enabled = clib_mem_trace_enable_disable (0);
869       u8 *s_in_svm =
870         format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
871       if (oldheap)
872         clib_mem_set_heap (oldheap);
873       u8 *s = vec_dup (s_in_svm);
874
875       oldheap = vlib_stats_push_heap (0);
876       vec_free (s_in_svm);
877       if (oldheap)
878         {
879           clib_mem_trace_enable_disable (was_enabled);
880           clib_mem_set_heap (oldheap);
881         }
882       vlib_cli_output (vm, "Stats segment");
883       vlib_cli_output (vm, "%v", s);
884       vec_free (s);
885     }
886
887 #if USE_DLMALLOC == 0
888   /* *INDENT-OFF* */
889   foreach_vlib_main (
890   ({
891       mheap_t *h = mheap_header (clib_per_cpu_mheaps[index]);
892       vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index,
893                        vlib_worker_threads[index].name);
894       vlib_cli_output (vm, "  %U\n", format_page_map, pointer_to_uword (h) -
895                        h->vm_alloc_offset_from_header,
896                        h->vm_alloc_size);
897       vlib_cli_output (vm, "  %U\n", format_mheap, clib_per_cpu_mheaps[index],
898                        verbose);
899       index++;
900   }));
901   /* *INDENT-ON* */
902 #else
903   {
904     if (main_heap)
905       {
906         /*
907          * Note: the foreach_vlib_main causes allocator traffic,
908          * so shut off tracing before we go there...
909          */
910         was_enabled = clib_mem_trace_enable_disable (0);
911
912         /* *INDENT-OFF* */
913         foreach_vlib_main (
914         ({
915           struct dlmallinfo mi;
916           void *mspace;
917           mspace = clib_per_cpu_mheaps[index];
918
919           mi = mspace_mallinfo (mspace);
920           vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index,
921                            vlib_worker_threads[index].name);
922           vlib_cli_output (vm, "  %U\n", format_page_map,
923                            pointer_to_uword (mspace_least_addr(mspace)),
924                            mi.arena);
925           vlib_cli_output (vm, "  %U\n", format_mheap,
926                            clib_per_cpu_mheaps[index],
927                            verbose);
928           index++;
929         }));
930         /* *INDENT-ON* */
931
932         /* Restore the trace flag */
933         clib_mem_trace_enable_disable (was_enabled);
934       }
935   }
936 #endif /* USE_DLMALLOC */
937   return 0;
938 }
939
940 /* *INDENT-OFF* */
941 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
942   .path = "show memory",
943   .short_help = "show memory [api-segment][stats-segment][verbose]",
944   .function = show_memory_usage,
945 };
946 /* *INDENT-ON* */
947
948 static clib_error_t *
949 show_cpu (vlib_main_t * vm, unformat_input_t * input,
950           vlib_cli_command_t * cmd)
951 {
952 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
953   _("Model name", "%U", format_cpu_model_name);
954   _("Microarch model (family)", "%U", format_cpu_uarch);
955   _("Flags", "%U", format_cpu_flags);
956   _("Base frequency", "%.2f GHz",
957     ((f64) vm->clib_time.clocks_per_second) * 1e-9);
958 #undef _
959   return 0;
960 }
961
962 /*?
963  * Displays various information about the CPU.
964  *
965  * @cliexpar
966  * @cliexstart{show cpu}
967  * Model name:               Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
968  * Microarchitecture:        Broadwell (Broadwell-EP/EX)
969  * Flags:                    sse3 ssse3 sse41 sse42 avx avx2 aes
970  * Base Frequency:           3.20 GHz
971  * @cliexend
972 ?*/
973 /* *INDENT-OFF* */
974 VLIB_CLI_COMMAND (show_cpu_command, static) = {
975   .path = "show cpu",
976   .short_help = "Show cpu information",
977   .function = show_cpu,
978 };
979 /* *INDENT-ON* */
980
981 static clib_error_t *
982 enable_disable_memory_trace (vlib_main_t * vm,
983                              unformat_input_t * input,
984                              vlib_cli_command_t * cmd)
985 {
986   unformat_input_t _line_input, *line_input = &_line_input;
987   int enable = 1;
988   int api_segment = 0;
989   int stats_segment = 0;
990   int main_heap = 0;
991   void *oldheap;
992
993   if (!unformat_user (input, unformat_line_input, line_input))
994     return 0;
995
996   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
997     {
998       if (unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
999         ;
1000       else if (unformat (line_input, "api-segment"))
1001         api_segment = 1;
1002       else if (unformat (line_input, "stats-segment"))
1003         stats_segment = 1;
1004       else if (unformat (line_input, "main-heap"))
1005         main_heap = 1;
1006       else
1007         {
1008           unformat_free (line_input);
1009           return clib_error_return (0, "invalid input");
1010         }
1011     }
1012   unformat_free (line_input);
1013
1014   if ((api_segment + stats_segment + main_heap + (enable == 0)) == 0)
1015     {
1016       return clib_error_return
1017         (0, "Need one of main-heap, stats-segment or api-segment");
1018     }
1019
1020   /* Turn off current trace, if any */
1021   if (current_traced_heap)
1022     {
1023       void *oldheap;
1024       oldheap = clib_mem_set_heap (current_traced_heap);
1025       clib_mem_trace (0);
1026       clib_mem_set_heap (oldheap);
1027       current_traced_heap = 0;
1028     }
1029
1030   if (enable == 0)
1031     return 0;
1032
1033   /* API segment */
1034   if (api_segment)
1035     {
1036       oldheap = vl_msg_push_heap ();
1037       current_traced_heap = clib_mem_get_heap ();
1038       clib_mem_trace (1);
1039       vl_msg_pop_heap (oldheap);
1040
1041     }
1042
1043   /* Stats segment */
1044   if (stats_segment)
1045     {
1046       oldheap = vlib_stats_push_heap (0);
1047       current_traced_heap = clib_mem_get_heap ();
1048       clib_mem_trace (stats_segment);
1049       /* We don't want to call vlib_stats_pop_heap... */
1050       if (oldheap)
1051         clib_mem_set_heap (oldheap);
1052     }
1053
1054   /* main_heap */
1055   if (main_heap)
1056     {
1057       current_traced_heap = clib_mem_get_heap ();
1058       clib_mem_trace (main_heap);
1059     }
1060
1061   return 0;
1062 }
1063
1064 /* *INDENT-OFF* */
1065 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
1066   .path = "memory-trace",
1067   .short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n",
1068   .function = enable_disable_memory_trace,
1069 };
1070 /* *INDENT-ON* */
1071
1072
1073 static clib_error_t *
1074 test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
1075                     vlib_cli_command_t * cmd)
1076 {
1077 #if USE_DLMALLOC == 0
1078   clib_error_t *error = 0;
1079   void *heap;
1080   mheap_t *mheap;
1081
1082   if (unformat (input, "on"))
1083     {
1084         /* *INDENT-OFF* */
1085         foreach_vlib_main({
1086           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
1087           mheap = mheap_header(heap);
1088           mheap->flags |= MHEAP_FLAG_VALIDATE;
1089           // Turn off small object cache because it delays detection of errors
1090           mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
1091         });
1092         /* *INDENT-ON* */
1093
1094     }
1095   else if (unformat (input, "off"))
1096     {
1097         /* *INDENT-OFF* */
1098         foreach_vlib_main({
1099           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
1100           mheap = mheap_header(heap);
1101           mheap->flags &= ~MHEAP_FLAG_VALIDATE;
1102           mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
1103         });
1104         /* *INDENT-ON* */
1105     }
1106   else if (unformat (input, "now"))
1107     {
1108         /* *INDENT-OFF* */
1109         foreach_vlib_main({
1110           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
1111           mheap = mheap_header(heap);
1112           mheap_validate(heap);
1113         });
1114         /* *INDENT-ON* */
1115       vlib_cli_output (vm, "heap validation complete");
1116
1117     }
1118   else
1119     {
1120       return clib_error_return (0, "unknown input `%U'",
1121                                 format_unformat_error, input);
1122     }
1123
1124   return error;
1125 #else
1126   return clib_error_return (0, "unimplemented...");
1127 #endif /* USE_DLMALLOC */
1128 }
1129
1130 /* *INDENT-OFF* */
1131 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
1132     .path = "test heap-validate",
1133     .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
1134     .function = test_heap_validate,
1135 };
1136 /* *INDENT-ON* */
1137
1138 static clib_error_t *
1139 restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1140                 vlib_cli_command_t * cmd)
1141 {
1142   clib_file_main_t *fm = &file_main;
1143   clib_file_t *f;
1144
1145   /* environ(7) does not indicate a header for this */
1146   extern char **environ;
1147
1148   /* Close all known open files */
1149   /* *INDENT-OFF* */
1150   pool_foreach(f, fm->file_pool,
1151     ({
1152       if (f->file_descriptor > 2)
1153         close(f->file_descriptor);
1154     }));
1155   /* *INDENT-ON* */
1156
1157   /* Exec ourself */
1158   execve (vm->name, (char **) vm->argv, environ);
1159
1160   return 0;
1161 }
1162
1163 /* *INDENT-OFF* */
1164 VLIB_CLI_COMMAND (restart_cmd,static) = {
1165     .path = "restart",
1166     .short_help = "restart process",
1167     .function = restart_cmd_fn,
1168 };
1169 /* *INDENT-ON* */
1170
1171 #ifdef TEST_CODE
1172 /*
1173  * A trivial test harness to verify the per-process output_function
1174  * is working correcty.
1175  */
1176
1177 static clib_error_t *
1178 sleep_ten_seconds (vlib_main_t * vm,
1179                    unformat_input_t * input, vlib_cli_command_t * cmd)
1180 {
1181   u16 i;
1182   u16 my_id = rand ();
1183
1184   vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
1185
1186   for (i = 0; i < 10; i++)
1187     {
1188       vlib_process_wait_for_event_or_clock (vm, 1.0);
1189       vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
1190     }
1191   vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
1192   return 0;
1193 }
1194
1195 /* *INDENT-OFF* */
1196 VLIB_CLI_COMMAND (ping_command, static) = {
1197   .path = "test sleep",
1198   .function = sleep_ten_seconds,
1199   .short_help = "Sleep for 10 seconds",
1200 };
1201 /* *INDENT-ON* */
1202 #endif /* ifdef TEST_CODE */
1203
1204 static uword
1205 vlib_cli_normalize_path (char *input, char **result)
1206 {
1207   char *i = input;
1208   char *s = 0;
1209   uword l = 0;
1210   uword index_of_last_space = ~0;
1211
1212   while (*i != 0)
1213     {
1214       u8 c = *i++;
1215       /* Multiple white space -> single space. */
1216       switch (c)
1217         {
1218         case ' ':
1219         case '\t':
1220         case '\n':
1221         case '\r':
1222           if (l > 0 && s[l - 1] != ' ')
1223             {
1224               vec_add1 (s, ' ');
1225               l++;
1226             }
1227           break;
1228
1229         default:
1230           if (l > 0 && s[l - 1] == ' ')
1231             index_of_last_space = vec_len (s);
1232           vec_add1 (s, c);
1233           l++;
1234           break;
1235         }
1236     }
1237
1238   /* Remove any extra space at end. */
1239   if (l > 0 && s[l - 1] == ' ')
1240     _vec_len (s) -= 1;
1241
1242   *result = s;
1243   return index_of_last_space;
1244 }
1245
1246 always_inline uword
1247 parent_path_len (char *path)
1248 {
1249   word i;
1250   for (i = vec_len (path) - 1; i >= 0; i--)
1251     {
1252       if (path[i] == ' ')
1253         return i;
1254     }
1255   return ~0;
1256 }
1257
1258 static void
1259 add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
1260 {
1261   vlib_cli_command_t *p, *c;
1262   vlib_cli_sub_command_t *sub_c;
1263   u8 *sub_name;
1264   word i, l;
1265
1266   p = vec_elt_at_index (cm->commands, parent_index);
1267   c = vec_elt_at_index (cm->commands, child_index);
1268
1269   l = parent_path_len (c->path);
1270   if (l == ~0)
1271     sub_name = vec_dup ((u8 *) c->path);
1272   else
1273     {
1274       ASSERT (l + 1 < vec_len (c->path));
1275       sub_name = 0;
1276       vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
1277     }
1278
1279   if (sub_name[0] == '%')
1280     {
1281       uword *q;
1282       vlib_cli_sub_rule_t *sr;
1283
1284       /* Remove %. */
1285       vec_delete (sub_name, 1, 0);
1286
1287       if (!p->sub_rule_index_by_name)
1288         p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1289                                                      sizeof (sub_name[0]),
1290                                                      sizeof (uword));
1291       q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1292       if (q)
1293         {
1294           sr = vec_elt_at_index (p->sub_rules, q[0]);
1295           ASSERT (sr->command_index == child_index);
1296           return;
1297         }
1298
1299       q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
1300       if (!q)
1301         {
1302           clib_error ("reference to unknown rule `%%%v' in path `%v'",
1303                       sub_name, c->path);
1304           return;
1305         }
1306
1307       hash_set_mem (p->sub_rule_index_by_name, sub_name,
1308                     vec_len (p->sub_rules));
1309       vec_add2 (p->sub_rules, sr, 1);
1310       sr->name = sub_name;
1311       sr->rule_index = q[0];
1312       sr->command_index = child_index;
1313       return;
1314     }
1315
1316   if (!p->sub_command_index_by_name)
1317     p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1318                                                     sizeof (c->path[0]),
1319                                                     sizeof (uword));
1320
1321   /* Check if sub-command has already been created. */
1322   if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1323     {
1324       vec_free (sub_name);
1325       return;
1326     }
1327
1328   vec_add2 (p->sub_commands, sub_c, 1);
1329   sub_c->index = child_index;
1330   sub_c->name = sub_name;
1331   hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1332                 sub_c - p->sub_commands);
1333
1334   vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1335   for (i = 0; i < vec_len (sub_c->name); i++)
1336     {
1337       int n;
1338       vlib_cli_parse_position_t *pos;
1339
1340       pos = vec_elt_at_index (p->sub_command_positions, i);
1341
1342       if (!pos->bitmaps)
1343         pos->min_char = sub_c->name[i];
1344
1345       n = sub_c->name[i] - pos->min_char;
1346       if (n < 0)
1347         {
1348           pos->min_char = sub_c->name[i];
1349           vec_insert (pos->bitmaps, -n, 0);
1350           n = 0;
1351         }
1352
1353       vec_validate (pos->bitmaps, n);
1354       pos->bitmaps[n] =
1355         clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
1356     }
1357 }
1358
1359 static void
1360 vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1361 {
1362   uword p_len, pi, *p;
1363   char *p_path;
1364   vlib_cli_command_t *c, *parent;
1365
1366   /* Root command (index 0) should have already been added. */
1367   ASSERT (vec_len (cm->commands) > 0);
1368
1369   c = vec_elt_at_index (cm->commands, ci);
1370   p_len = parent_path_len (c->path);
1371
1372   /* No space?  Parent is root command. */
1373   if (p_len == ~0)
1374     {
1375       add_sub_command (cm, 0, ci);
1376       return;
1377     }
1378
1379   p_path = 0;
1380   vec_add (p_path, c->path, p_len);
1381
1382   p = hash_get_mem (cm->command_index_by_path, p_path);
1383
1384   /* Parent exists? */
1385   if (!p)
1386     {
1387       /* Parent does not exist; create it. */
1388       vec_add2 (cm->commands, parent, 1);
1389       parent->path = p_path;
1390       hash_set_mem (cm->command_index_by_path, parent->path,
1391                     parent - cm->commands);
1392       pi = parent - cm->commands;
1393     }
1394   else
1395     {
1396       pi = p[0];
1397       vec_free (p_path);
1398     }
1399
1400   add_sub_command (cm, pi, ci);
1401
1402   /* Create parent's parent. */
1403   if (!p)
1404     vlib_cli_make_parent (cm, pi);
1405 }
1406
1407 always_inline uword
1408 vlib_cli_command_is_empty (vlib_cli_command_t * c)
1409 {
1410   return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
1411 }
1412
1413 clib_error_t *
1414 vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
1415 {
1416   vlib_cli_main_t *cm = &vm->cli_main;
1417   clib_error_t *error = 0;
1418   uword ci, *p;
1419   char *normalized_path;
1420
1421   if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1422     return error;
1423
1424   (void) vlib_cli_normalize_path (c->path, &normalized_path);
1425
1426   if (!cm->command_index_by_path)
1427     cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
1428                                                  sizeof (c->path[0]),
1429                                                  sizeof (uword));
1430
1431   /* See if command already exists with given path. */
1432   p = hash_get_mem (cm->command_index_by_path, normalized_path);
1433   if (p)
1434     {
1435       vlib_cli_command_t *d;
1436
1437       ci = p[0];
1438       d = vec_elt_at_index (cm->commands, ci);
1439
1440       /* If existing command was created via vlib_cli_make_parent
1441          replaced it with callers data. */
1442       if (vlib_cli_command_is_empty (d))
1443         {
1444           vlib_cli_command_t save = d[0];
1445
1446           ASSERT (!vlib_cli_command_is_empty (c));
1447
1448           /* Copy callers fields. */
1449           d[0] = c[0];
1450
1451           /* Save internal fields. */
1452           d->path = save.path;
1453           d->sub_commands = save.sub_commands;
1454           d->sub_command_index_by_name = save.sub_command_index_by_name;
1455           d->sub_command_positions = save.sub_command_positions;
1456           d->sub_rules = save.sub_rules;
1457         }
1458       else
1459         error =
1460           clib_error_return (0, "duplicate command name with path %v",
1461                              normalized_path);
1462
1463       vec_free (normalized_path);
1464       if (error)
1465         return error;
1466     }
1467   else
1468     {
1469       /* Command does not exist: create it. */
1470
1471       /* Add root command (index 0). */
1472       if (vec_len (cm->commands) == 0)
1473         {
1474           /* Create command with index 0; path is empty string. */
1475           vec_resize (cm->commands, 1);
1476         }
1477
1478       ci = vec_len (cm->commands);
1479       hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1480       vec_add1 (cm->commands, c[0]);
1481
1482       c = vec_elt_at_index (cm->commands, ci);
1483       c->path = normalized_path;
1484
1485       /* Don't inherit from registration. */
1486       c->sub_commands = 0;
1487       c->sub_command_index_by_name = 0;
1488       c->sub_command_positions = 0;
1489     }
1490
1491   vlib_cli_make_parent (cm, ci);
1492   return 0;
1493 }
1494
1495 clib_error_t *
1496 vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1497 {
1498   vlib_cli_main_t *cm = &vm->cli_main;
1499   vlib_cli_parse_rule_t *r;
1500   clib_error_t *error = 0;
1501   u8 *r_name;
1502   uword *p;
1503
1504   if (!cm->parse_rule_index_by_name)
1505     cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1506                                                     sizeof (r->name[0]),
1507                                                     sizeof (uword));
1508
1509   /* Make vector copy of name. */
1510   r_name = format (0, "%s", r_reg->name);
1511
1512   if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1513     {
1514       vec_free (r_name);
1515       return clib_error_return (0, "duplicate parse rule name `%s'",
1516                                 r_reg->name);
1517     }
1518
1519   vec_add2 (cm->parse_rules, r, 1);
1520   r[0] = r_reg[0];
1521   r->name = (char *) r_name;
1522   hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1523
1524   return error;
1525 }
1526
1527 #if 0
1528 /* $$$ turn back on again someday, maybe */
1529 static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1530                                                     vlib_cli_parse_rule_t *
1531                                                     lo,
1532                                                     vlib_cli_parse_rule_t *
1533                                                     hi)
1534   __attribute__ ((unused))
1535 {
1536   clib_error_t *error = 0;
1537   vlib_cli_parse_rule_t *r;
1538
1539   for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1540     {
1541       if (!r->name || strlen (r->name) == 0)
1542         {
1543           error = clib_error_return (0, "parse rule with no name");
1544           goto done;
1545         }
1546
1547       error = vlib_cli_register_parse_rule (vm, r);
1548       if (error)
1549         goto done;
1550     }
1551
1552 done:
1553   return error;
1554 }
1555 #endif
1556
1557 static clib_error_t *
1558 elog_trace_command_fn (vlib_main_t * vm,
1559                        unformat_input_t * input, vlib_cli_command_t * cmd)
1560 {
1561   unformat_input_t _line_input, *line_input = &_line_input;
1562   int enable = 1;
1563   int api = 0, cli = 0, barrier = 0, dispatch = 0, circuit = 0;
1564   u32 circuit_node_index;
1565
1566   if (!unformat_user (input, unformat_line_input, line_input))
1567     goto print_status;
1568
1569   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1570     {
1571       if (unformat (line_input, "api"))
1572         api = 1;
1573       else if (unformat (line_input, "dispatch"))
1574         dispatch = 1;
1575       else if (unformat (line_input, "circuit-node %U",
1576                          unformat_vlib_node, vm, &circuit_node_index))
1577         circuit = 1;
1578       else if (unformat (line_input, "cli"))
1579         cli = 1;
1580       else if (unformat (line_input, "barrier"))
1581         barrier = 1;
1582       else if (unformat (line_input, "disable"))
1583         enable = 0;
1584       else if (unformat (line_input, "enable"))
1585         enable = 1;
1586       else
1587         break;
1588     }
1589   unformat_free (line_input);
1590
1591   vl_api_set_elog_trace_api_messages
1592     (api ? enable : vl_api_get_elog_trace_api_messages ());
1593   vm->elog_trace_cli_commands = cli ? enable : vm->elog_trace_cli_commands;
1594   vm->elog_trace_graph_dispatch = dispatch ?
1595     enable : vm->elog_trace_graph_dispatch;
1596   vm->elog_trace_graph_circuit = circuit ?
1597     enable : vm->elog_trace_graph_circuit;
1598   vlib_worker_threads->barrier_elog_enabled =
1599     barrier ? enable : vlib_worker_threads->barrier_elog_enabled;
1600   vm->elog_trace_graph_circuit_node_index = circuit_node_index;
1601
1602   /*
1603    * Set up start-of-buffer logic-analyzer trigger
1604    * for main loop event logs, which are fairly heavyweight.
1605    * See src/vlib/main/vlib_elog_main_loop_event(...), which
1606    * will fully disable the scheme when the elog buffer fills.
1607    */
1608   if (dispatch || circuit)
1609     {
1610       elog_main_t *em = &vm->elog_main;
1611
1612       em->n_total_events_disable_limit =
1613         em->n_total_events + vec_len (em->event_ring);
1614     }
1615
1616
1617 print_status:
1618   vlib_cli_output (vm, "Current status:");
1619
1620   vlib_cli_output
1621     (vm, "    Event log API message trace: %s\n    CLI command trace: %s",
1622      vl_api_get_elog_trace_api_messages ()? "on" : "off",
1623      vm->elog_trace_cli_commands ? "on" : "off");
1624   vlib_cli_output
1625     (vm, "    Barrier sync trace: %s",
1626      vlib_worker_threads->barrier_elog_enabled ? "on" : "off");
1627   vlib_cli_output
1628     (vm, "    Graph Dispatch: %s",
1629      vm->elog_trace_graph_dispatch ? "on" : "off");
1630   vlib_cli_output
1631     (vm, "    Graph Circuit: %s",
1632      vm->elog_trace_graph_circuit ? "on" : "off");
1633   if (vm->elog_trace_graph_circuit)
1634     vlib_cli_output
1635       (vm, "                   node %U",
1636        format_vlib_node_name, vm, vm->elog_trace_graph_circuit_node_index);
1637
1638   return 0;
1639 }
1640
1641 /*?
1642  * Control event logging of api, cli, and thread barrier events
1643  * With no arguments, displays the current trace status.
1644  * Name the event groups you wish to trace or stop tracing.
1645  *
1646  * @cliexpar
1647  * @clistart
1648  * elog trace api cli barrier
1649  * elog trace api cli barrier disable
1650  * elog trace dispatch
1651  * elog trace circuit-node ethernet-input
1652  * elog trace
1653  * @cliend
1654  * @cliexcmd{elog trace [api][cli][barrier][disable]}
1655 ?*/
1656 /* *INDENT-OFF* */
1657 VLIB_CLI_COMMAND (elog_trace_command, static) =
1658 {
1659   .path = "elog trace",
1660   .short_help = "elog trace [api][cli][barrier][dispatch]\n"
1661   "[circuit-node <name> e.g. ethernet-input][disable]",
1662   .function = elog_trace_command_fn,
1663 };
1664 /* *INDENT-ON* */
1665
1666 static clib_error_t *
1667 suspend_command_fn (vlib_main_t * vm,
1668                     unformat_input_t * input, vlib_cli_command_t * cmd)
1669 {
1670   vlib_process_suspend (vm, 30e-3);
1671   return 0;
1672 }
1673
1674 /* *INDENT-OFF* */
1675 VLIB_CLI_COMMAND (suspend_command, static) =
1676 {
1677   .path = "suspend",
1678   .short_help = "suspend debug CLI for 30ms",
1679   .function = suspend_command_fn,
1680   .is_mp_safe = 1,
1681 };
1682 /* *INDENT-ON* */
1683
1684
1685 static int
1686 sort_cmds_by_path (void *a1, void *a2)
1687 {
1688   u32 *index1 = a1;
1689   u32 *index2 = a2;
1690   vlib_main_t *vm = vlib_get_main ();
1691   vlib_cli_main_t *cm = &vm->cli_main;
1692   vlib_cli_command_t *c1, *c2;
1693   int i, lmin;
1694
1695   c1 = vec_elt_at_index (cm->commands, *index1);
1696   c2 = vec_elt_at_index (cm->commands, *index2);
1697
1698   lmin = vec_len (c1->path);
1699   lmin = (vec_len (c2->path) >= lmin) ? lmin : vec_len (c2->path);
1700
1701   for (i = 0; i < lmin; i++)
1702     {
1703       if (c1->path[i] < c2->path[i])
1704         return -1;
1705       else if (c1->path[i] > c2->path[i])
1706         return 1;
1707     }
1708
1709   return 0;
1710 }
1711
1712 typedef struct
1713 {
1714   vlib_cli_main_t *cm;
1715   u32 parent_command_index;
1716   int show_mp_safe;
1717   int show_not_mp_safe;
1718   int show_hit;
1719   int clear_hit;
1720 } vlib_cli_walk_args_t;
1721
1722 static void
1723 cli_recursive_walk (vlib_cli_walk_args_t * aa)
1724 {
1725   vlib_cli_command_t *parent;
1726   vlib_cli_sub_command_t *sub;
1727   vlib_cli_walk_args_t _a, *a = &_a;
1728   vlib_cli_main_t *cm;
1729   int i;
1730
1731   /* Copy args into this stack frame */
1732   *a = *aa;
1733   cm = a->cm;
1734
1735   parent = vec_elt_at_index (cm->commands, a->parent_command_index);
1736
1737   if (parent->function)
1738     {
1739       if (((a->show_mp_safe && parent->is_mp_safe)
1740            || (a->show_not_mp_safe && !parent->is_mp_safe))
1741           && (a->show_hit == 0 || parent->hit_counter))
1742         {
1743           vec_add1 (cm->sort_vector, a->parent_command_index);
1744         }
1745
1746       if (a->clear_hit)
1747         parent->hit_counter = 0;
1748     }
1749
1750   for (i = 0; i < vec_len (parent->sub_commands); i++)
1751     {
1752       sub = vec_elt_at_index (parent->sub_commands, i);
1753       a->parent_command_index = sub->index;
1754       cli_recursive_walk (a);
1755     }
1756 }
1757
1758 static u8 *
1759 format_mp_safe (u8 * s, va_list * args)
1760 {
1761   vlib_cli_main_t *cm = va_arg (*args, vlib_cli_main_t *);
1762   int show_mp_safe = va_arg (*args, int);
1763   int show_not_mp_safe = va_arg (*args, int);
1764   int show_hit = va_arg (*args, int);
1765   int clear_hit = va_arg (*args, int);
1766   vlib_cli_command_t *c;
1767   vlib_cli_walk_args_t _a, *a = &_a;
1768   int i;
1769   char *format_string = "\n%v";
1770
1771   if (show_hit)
1772     format_string = "\n%v: %u";
1773
1774   vec_reset_length (cm->sort_vector);
1775
1776   a->cm = cm;
1777   a->parent_command_index = 0;
1778   a->show_mp_safe = show_mp_safe;
1779   a->show_not_mp_safe = show_not_mp_safe;
1780   a->show_hit = show_hit;
1781   a->clear_hit = clear_hit;
1782
1783   cli_recursive_walk (a);
1784
1785   vec_sort_with_function (cm->sort_vector, sort_cmds_by_path);
1786
1787   for (i = 0; i < vec_len (cm->sort_vector); i++)
1788     {
1789       c = vec_elt_at_index (cm->commands, cm->sort_vector[i]);
1790       s = format (s, format_string, c->path, c->hit_counter);
1791     }
1792
1793   return s;
1794 }
1795
1796
1797 static clib_error_t *
1798 show_cli_command_fn (vlib_main_t * vm,
1799                      unformat_input_t * input, vlib_cli_command_t * cmd)
1800 {
1801   int show_mp_safe = 0;
1802   int show_not_mp_safe = 0;
1803   int show_hit = 0;
1804   int clear_hit = 0;
1805
1806   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1807     {
1808       if (unformat (input, "mp-safe"))
1809         show_mp_safe = 1;
1810       if (unformat (input, "not-mp-safe"))
1811         show_not_mp_safe = 1;
1812       else if (unformat (input, "hit"))
1813         show_hit = 1;
1814       else if (unformat (input, "clear-hit"))
1815         clear_hit = 1;
1816       else
1817         break;
1818     }
1819
1820   /* default set: all cli commands */
1821   if (clear_hit == 0 && (show_mp_safe + show_not_mp_safe) == 0)
1822     show_mp_safe = show_not_mp_safe = 1;
1823
1824   vlib_cli_output (vm, "%U", format_mp_safe, &vm->cli_main,
1825                    show_mp_safe, show_not_mp_safe, show_hit, clear_hit);
1826   if (clear_hit)
1827     vlib_cli_output (vm, "hit counters cleared...");
1828
1829   return 0;
1830 }
1831
1832 /*?
1833  * Displays debug cli command information
1834  *
1835  * @cliexpar
1836  * @cliexstart{show cli [mp-safe][not-mp-safe][hit][clear-hit]}
1837  *
1838  * "show cli" displays the entire debug cli:
1839  *
1840  * abf attach
1841  * abf policy
1842  * adjacency counters
1843  * api trace
1844  * app ns
1845  * bfd key del
1846  * ... and so on ...
1847  *
1848  * "show cli mp-safe" displays mp-safe debug CLI commands:
1849  *
1850  * abf policy
1851  * binary-api
1852  * create vhost-user
1853  * exec
1854  * ip container
1855  * ip mroute
1856  * ip probe-neighbor
1857  * ip route
1858  * ip scan-neighbor
1859  * ip table
1860  * ip6 table
1861  *
1862  * "show cli not-mp-safe" displays debug CLI commands
1863  * which cause worker thread barrier synchronization
1864  *
1865  * "show cli hit" displays commands which have been executed. Qualify
1866  * as desired with "mp-safe" or "not-mp-safe".
1867  *
1868  * "show cli clear-hit" clears the per-command hit counters.
1869  * @cliexend
1870 ?*/
1871
1872 /* *INDENT-OFF* */
1873 VLIB_CLI_COMMAND (show_cli_command, static) =
1874 {
1875   .path = "show cli",
1876   .short_help = "show cli [mp-safe][not-mp-safe][hit][clear-hit]",
1877   .function = show_cli_command_fn,
1878   .is_mp_safe = 1,
1879 };
1880 /* *INDENT-ON* */
1881
1882 static clib_error_t *
1883 vlib_cli_init (vlib_main_t * vm)
1884 {
1885   vlib_cli_main_t *cm = &vm->cli_main;
1886   clib_error_t *error = 0;
1887   vlib_cli_command_t *cmd;
1888
1889   cmd = cm->cli_command_registrations;
1890
1891   while (cmd)
1892     {
1893       error = vlib_cli_register (vm, cmd);
1894       if (error)
1895         return error;
1896       cmd = cmd->next_cli_command;
1897     }
1898   return error;
1899 }
1900
1901 VLIB_INIT_FUNCTION (vlib_cli_init);
1902
1903 /*
1904  * fd.io coding-style-patch-verification: ON
1905  *
1906  * Local Variables:
1907  * eval: (c-set-style "gnu")
1908  * End:
1909  */