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