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