Add per-device startup config support
[vpp.git] / vlib / 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
42 /* Root of all show commands. */
43 VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
44   .path = "show",
45   .short_help = "Show commands",
46 };
47
48 /* Root of all clear commands. */
49 VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
50   .path = "clear",
51   .short_help = "Clear commands",
52 };
53
54 /* Root of all set commands. */
55 VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
56   .path = "set",
57   .short_help = "Set commands",
58 };
59
60 /* Root of all test commands. */
61 VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
62   .path = "test",
63   .short_help = "Test commands",
64 };
65
66 /* Returns bitmap of commands which match key. */
67 static uword *
68 vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
69 {
70   int i, n;
71   uword * match = 0;
72   vlib_cli_parse_position_t * p;
73
74   unformat_skip_white_space (input);
75
76   for (i = 0; ; i++)
77     {
78       uword k;
79
80       k = unformat_get_input (input);
81       switch (k)
82         {
83         case 'a' ... 'z':
84         case 'A' ... 'Z':
85         case '0' ... '9':
86         case '-': case '_':
87           break;
88
89         case ' ': case '\t': case '\r': case '\n':
90         case UNFORMAT_END_OF_INPUT:
91           /* White space or end of input removes any non-white
92              matches that were before possible. */
93           if (i < vec_len (c->sub_command_positions)
94               && clib_bitmap_count_set_bits (match) > 1)
95             {
96               p = vec_elt_at_index (c->sub_command_positions, i);
97               for (n = 0; n < vec_len (p->bitmaps); n++)
98                 match = clib_bitmap_andnot (match, p->bitmaps[n]);
99             }
100           goto done;
101
102         default:
103           unformat_put_input (input);
104           goto done;
105         }
106
107       if (i >= vec_len (c->sub_command_positions))
108         {
109         no_match:
110           clib_bitmap_free (match);
111           return 0;
112         }
113
114       p = vec_elt_at_index (c->sub_command_positions, i);
115       if (vec_len (p->bitmaps) == 0)
116         goto no_match;
117
118       n = k - p->min_char;
119       if (n < 0 || n >= vec_len (p->bitmaps))
120         goto no_match;
121
122       if (i == 0)
123         match = clib_bitmap_dup (p->bitmaps[n]);
124       else
125         match = clib_bitmap_and (match, p->bitmaps[n]);
126
127       if (clib_bitmap_is_zero (match))
128         goto no_match;
129     }
130
131  done:
132   return match;
133 }
134
135 /* Looks for string based sub-input formatted { SUB-INPUT }. */
136 uword unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
137 {
138   unformat_input_t * sub_input = va_arg (*args, unformat_input_t *);
139   u8 * s;
140   uword c;
141
142   while (1)
143     {
144       c = unformat_get_input (i);
145       switch (c)
146         {
147         case ' ': case '\t':
148         case '\n': case '\r':
149         case '\f':
150           break;
151
152         case '{':
153         default:
154           /* Put back paren. */
155           if (c != UNFORMAT_END_OF_INPUT)
156             unformat_put_input (i);
157
158           if (c == '{' && unformat (i, "%v", &s))
159             {
160               unformat_init_vector (sub_input, s);
161               return 1;
162             }
163           return 0;
164         }
165     }
166   return 0;
167 }
168
169 static vlib_cli_command_t *
170 get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
171 {
172   vlib_cli_sub_command_t * s = vec_elt_at_index (parent->sub_commands, si);
173   return vec_elt_at_index (cm->commands, s->index);
174 }
175
176 static uword unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
177 {
178   vlib_main_t * vm = va_arg (*args, vlib_main_t *);
179   vlib_cli_command_t * c = va_arg (*args, vlib_cli_command_t *);
180   vlib_cli_command_t ** result = va_arg (*args, vlib_cli_command_t **);
181   vlib_cli_main_t * cm = &vm->cli_main;
182   uword * match_bitmap, is_unique, index;
183
184   {
185     vlib_cli_sub_rule_t * sr;
186     vlib_cli_parse_rule_t * r;
187     vec_foreach (sr, c->sub_rules)
188       {
189         void ** d;
190         r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
191         vec_add2 (cm->parse_rule_data, d, 1);
192         vec_reset_length (d[0]);
193         if (r->data_size)
194           d[0] = _vec_resize (d[0],
195                               /* length increment */ 1,
196                               r->data_size,
197                               /* header_bytes */ 0,
198                               /* data align */ sizeof (uword));
199         if (unformat_user (i, r->unformat_function, vm, d[0]))
200           {
201             *result = vec_elt_at_index (cm->commands, sr->command_index);
202             return 1;
203           }
204       }
205   }
206
207   match_bitmap = vlib_cli_sub_command_match (c, i);
208   is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
209   index = ~0;
210   if (is_unique)
211     {
212       index = clib_bitmap_first_set (match_bitmap);
213       *result = get_sub_command (cm, c, index);
214     }
215   clib_bitmap_free (match_bitmap);
216
217   return is_unique;
218 }
219
220 static u8 * format_vlib_cli_command_help (u8 * s, va_list * args)
221 {
222   vlib_cli_command_t * c = va_arg (*args, vlib_cli_command_t *);
223   int is_long = va_arg (*args, int);
224   if (is_long && c->long_help)
225     s = format (s, "%s", c->long_help);
226   else if (c->short_help)
227     s = format (s, "%s", c->short_help);
228   else
229     s = format (s, "%v commands", c->path);
230   return s;
231 }
232
233 static u8 * format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
234 {
235   vlib_cli_parse_rule_t * r  = va_arg (*args, vlib_cli_parse_rule_t *);
236   return format (s, "<%U>", format_c_identifier, r->name);
237 }
238
239 static u8 * format_vlib_cli_path (u8 * s, va_list * args)
240 {
241   u8 * path = va_arg (*args, u8 *);
242   int i, in_rule;
243   in_rule = 0;
244   for (i = 0; i < vec_len (path); i++)
245     {
246       switch (path[i])
247         {
248         case '%':
249           in_rule = 1;
250           vec_add1 (s, '<');    /* start of <RULE> */
251           break;
252
253         case '_':
254           /* _ -> space in rules. */
255           vec_add1 (s, in_rule ? ' ' : '_');
256           break;
257
258         case ' ':
259           if (in_rule)
260             {
261               vec_add1 (s, '>'); /* end of <RULE> */
262               in_rule = 0;
263             }
264           vec_add1 (s, ' ');
265           break;
266
267         default:
268           vec_add1 (s, path[i]);
269           break;
270         }
271     }
272
273   if (in_rule)
274     vec_add1 (s, '>');          /* terminate <RULE> */
275
276   return s;
277 }
278
279 static vlib_cli_command_t *
280 all_subs (vlib_cli_main_t * cm,
281           vlib_cli_command_t * subs,
282           u32 command_index)
283 {
284   vlib_cli_command_t * c = vec_elt_at_index (cm->commands, command_index);
285   vlib_cli_sub_command_t * sc;
286   vlib_cli_sub_rule_t * sr;
287
288   if (c->function)
289     vec_add1 (subs, c[0]);
290
291   vec_foreach (sr, c->sub_rules)
292     subs = all_subs (cm, subs, sr->command_index);
293   vec_foreach (sc, c->sub_commands)
294     subs = all_subs (cm, subs, sc->index);
295
296   return subs;
297 }
298
299 static int
300 vlib_cli_cmp_rule (void * a1, void * a2)
301 {
302   vlib_cli_sub_rule_t * r1 = a1;
303   vlib_cli_sub_rule_t * r2 = a2;
304
305   return vec_cmp (r1->name, r2->name);
306 }
307
308 static int
309 vlib_cli_cmp_command (void * a1, void * a2)
310 {
311   vlib_cli_command_t * c1 = a1;
312   vlib_cli_command_t * c2 = a2;
313
314   return vec_cmp (c1->path, c2->path);
315 }
316
317 static clib_error_t *
318 vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
319                                 vlib_cli_main_t * cm,
320                                 unformat_input_t * input,
321                                 uword parent_command_index)
322 {
323   vlib_cli_command_t * parent, * c;
324   clib_error_t * error = 0;
325   unformat_input_t sub_input;
326   u8 * string;
327   uword is_main_dispatch = cm == &vm->cli_main;
328
329   parent = vec_elt_at_index (cm->commands, parent_command_index);
330   if (is_main_dispatch && unformat (input, "help"))
331     {
332       uword help_at_end_of_line, i;
333
334       help_at_end_of_line = unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
335       while (1)
336         {
337           c = parent;
338           if (unformat_user (input, unformat_vlib_cli_sub_command, vm, c, &parent))
339             ;
340
341           else if (! (unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
342             goto unknown;
343
344           else
345             break;
346         }
347       
348       /* help SUB-COMMAND => long format help.
349          "help" at end of line: show all commands. */
350       if (! help_at_end_of_line)
351         vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c, /* is_long */ 1);
352
353       else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
354         vlib_cli_output (vm, "%v: no sub-commands", c->path);
355
356       else
357         {
358           vlib_cli_sub_command_t * sc;
359           vlib_cli_sub_rule_t * sr, * subs;
360
361           subs = vec_dup (c->sub_rules);
362
363           /* Add in rules if any. */
364           vec_foreach (sc, c->sub_commands)
365             {
366               vec_add2 (subs, sr, 1);
367               sr->name = sc->name;
368               sr->command_index = sc->index;
369               sr->rule_index = ~0;
370             }
371
372           vec_sort_with_function (subs, vlib_cli_cmp_rule);
373
374           for (i = 0; i < vec_len (subs); i++) 
375             {
376               vlib_cli_command_t * d;
377               vlib_cli_parse_rule_t * r;
378
379               d = vec_elt_at_index (cm->commands, subs[i].command_index);
380               r = subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules, subs[i].rule_index) : 0;
381
382               if (r)
383                 vlib_cli_output
384                   (vm, "  %-30U %U",
385                    format_vlib_cli_parse_rule_name, r,
386                    format_vlib_cli_command_help, d, /* is_long */ 0);
387               else
388                 vlib_cli_output
389                   (vm, "  %-30v %U",
390                    subs[i].name,
391                    format_vlib_cli_command_help, d, /* is_long */ 0);
392             }
393
394           vec_free (subs);
395         }
396     }
397   
398   else if (is_main_dispatch && (unformat (input, "choices") || unformat (input, "?")))
399     {
400       vlib_cli_command_t * sub, * subs;
401
402       subs = all_subs (cm, 0, parent_command_index);
403       vec_sort_with_function (subs, vlib_cli_cmp_command);
404       vec_foreach (sub, subs)
405         vlib_cli_output (vm, "  %-40U %U",
406                          format_vlib_cli_path, sub->path,
407                          format_vlib_cli_command_help, sub, /* is_long */ 0);
408       vec_free (subs);
409     }
410
411   else if (unformat (input, "comment %v", &string))
412     {
413       vec_free (string);
414     }
415   
416   else if (unformat (input, "uncomment %U",
417                      unformat_vlib_cli_sub_input, &sub_input))
418     {
419       error = vlib_cli_dispatch_sub_commands (vm, cm, &sub_input, parent_command_index);
420       unformat_free (&sub_input);
421     }
422   
423   else if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
424     {
425       unformat_input_t * si;
426       uword has_sub_commands = vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
427       
428       si = input;
429       if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
430         si = &sub_input;
431       
432       if (has_sub_commands)
433         error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
434
435       if (has_sub_commands && ! error)
436         /* Found valid sub-command. */;
437
438       else if (c->function)
439         {
440           clib_error_t * c_error;
441
442           /* Skip white space for benefit of called function. */
443           unformat_skip_white_space (si);
444
445           if (unformat (si, "?"))
446             {
447               vlib_cli_output (vm, "  %-40U %U",
448                                format_vlib_cli_path, c->path,
449                                format_vlib_cli_command_help, c, /* is_long */ 0);
450             }
451           else
452             {
453               if (!c->is_mp_safe)
454                 vlib_worker_thread_barrier_sync(vm);
455
456               c_error = c->function (vm, si, c);
457
458               if (!c->is_mp_safe)
459                 vlib_worker_thread_barrier_release(vm);
460
461               if (c_error)
462                 {
463                   error = clib_error_return (0, "%v: %v", c->path, c_error->what);
464                   clib_error_free (c_error);
465                   /* Free sub input. */
466                   if (si != input)
467                     unformat_free (si);
468
469                   return error;
470                 }
471             }
472
473           /* Free any previous error. */
474           clib_error_free (error);
475         }
476
477       else if (! error)
478         error = clib_error_return (0, "%v: no sub-commands", c->path);
479
480       /* Free sub input. */
481       if (si != input)
482         unformat_free (si);
483     }
484
485   else
486     goto unknown;
487
488   return error;
489
490  unknown:
491   if (parent->path)
492     return clib_error_return (0, "%v: unknown input `%U'", parent->path, format_unformat_error, input);
493   else
494     return clib_error_return (0, "unknown input `%U'", format_unformat_error, input);
495 }
496
497
498 void vlib_unix_error_report (vlib_main_t *, clib_error_t *) 
499     __attribute__ ((weak));
500
501 void vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error) { }
502
503 /* Process CLI input. */
504 void vlib_cli_input (vlib_main_t * vm,
505                      unformat_input_t * input,
506                      vlib_cli_output_function_t * function,
507                      uword function_arg)
508 {
509   vlib_process_t * cp = vlib_get_current_process(vm);
510   vlib_cli_main_t * cm = &vm->cli_main;
511   clib_error_t * error;
512   vlib_cli_output_function_t * save_function;
513   uword save_function_arg;
514
515   save_function = cp->output_function;
516   save_function_arg = cp->output_function_arg;
517
518   cp->output_function = function;
519   cp->output_function_arg = function_arg;
520
521   do {
522     vec_reset_length (cm->parse_rule_data);
523     error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */ 0);
524   } while (! error && ! unformat (input, "%U", unformat_eof));
525
526   if (error)
527     {
528       vlib_cli_output (vm, "%v", error->what);
529       vlib_unix_error_report (vm, error);
530       clib_error_free (error);
531     }
532
533   cp->output_function = save_function;
534   cp->output_function_arg = save_function_arg;
535 }
536
537 /* Output to current CLI connection. */
538 void vlib_cli_output (vlib_main_t * vm, char * fmt, ...)
539 {
540   vlib_process_t * cp = vlib_get_current_process(vm);
541   va_list va;
542   u8 * s;
543
544   va_start (va, fmt);
545   s = va_format (0, fmt, &va);
546   va_end (va);
547
548   /* Terminate with \n if not present. */
549   if (vec_len (s) > 0 && s[vec_len (s)-1] != '\n')
550     vec_add1 (s, '\n');
551
552   if ((! cp) || (! cp->output_function))
553     fformat (stdout, "%v", s);
554   else
555     cp->output_function (cp->output_function_arg, s, vec_len (s));
556
557   vec_free (s);
558 }
559
560 static clib_error_t *
561 show_memory_usage (vlib_main_t * vm,
562                    unformat_input_t * input,
563                    vlib_cli_command_t * cmd)
564 {
565   int verbose = 0;
566   clib_error_t * error;
567   u32 index = 0;
568
569   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) 
570     {
571       if (unformat (input, "verbose")) 
572         verbose = 1;
573       else {
574         error = clib_error_return (0, "unknown input `%U'", 
575                                    format_unformat_error, input);
576         return error;
577       }
578   }
579
580   foreach_vlib_main (
581   ({
582       vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
583       vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
584       index++;
585   }));
586   return 0;
587 }
588
589 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
590   .path = "show memory",
591   .short_help = "Show current memory usage",
592   .function = show_memory_usage,
593 };
594
595 static clib_error_t *
596 enable_disable_memory_trace (vlib_main_t * vm,
597                              unformat_input_t * input,
598                              vlib_cli_command_t * cmd)
599 {
600   clib_error_t * error = 0;
601   int enable;
602
603   if (! unformat_user (input, unformat_vlib_enable_disable, &enable))
604     {
605       error = clib_error_return (0, "expecting enable/on or disable/off");
606       goto done;
607     }
608
609   clib_mem_trace (enable);
610
611  done:
612   return error;
613 }
614
615 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
616   .path = "memory-trace",
617   .short_help = "Enable/disable memory allocation trace",
618   .function = enable_disable_memory_trace,
619 };
620
621
622 static clib_error_t *
623 test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
624                         vlib_cli_command_t * cmd)
625 {
626     clib_error_t * error = 0;
627     void * heap;
628     mheap_t *mheap;
629
630     if (unformat(input, "on")) {
631         foreach_vlib_main({
632           heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
633           mheap = mheap_header(heap);
634           mheap->flags |= MHEAP_FLAG_VALIDATE;
635           // Turn off small object cache because it delays detection of errors
636           mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
637         });
638
639     } else if (unformat(input, "off")) {
640         foreach_vlib_main({
641           heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
642           mheap = mheap_header(heap);
643           mheap->flags &= ~MHEAP_FLAG_VALIDATE;
644           mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
645         });
646
647     } else if (unformat(input, "now")) {
648         foreach_vlib_main({
649           heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
650           mheap = mheap_header(heap);
651           mheap_validate(heap);
652         });
653         vlib_cli_output(vm, "heap validation complete");
654
655     } else {
656         return clib_error_return(0, "unknown input `%U'",
657                                   format_unformat_error, input);
658     }
659
660     return error;
661 }
662
663 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
664     .path = "test heap-validate",
665     .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
666     .function = test_heap_validate,
667 };
668
669 #ifdef TEST_CODE
670 /*
671  * A trivial test harness to verify the per-process output_function
672  * is working correcty.
673  */
674
675 static clib_error_t *
676 sleep_ten_seconds (vlib_main_t * vm,
677                    unformat_input_t * input,
678                    vlib_cli_command_t * cmd)
679 {
680   u16 i;
681   u16 my_id = rand();
682
683   vlib_cli_output(vm, "Starting 10 seconds sleep with id %u\n", my_id);
684
685   for(i=0; i<10; i++)
686     {
687       vlib_process_wait_for_event_or_clock(vm, 1.0);
688       vlib_cli_output(vm, "Iteration number %u, my id: %u\n", i, my_id);
689     }
690   vlib_cli_output(vm, "Done with sleep with id %u\n", my_id);
691   return 0;
692 }
693
694 VLIB_CLI_COMMAND (ping_command, static) = {
695   .path = "test sleep",
696   .function = sleep_ten_seconds,
697   .short_help = "Sleep for 10 seconds",
698 };
699 #endif /* ifdef TEST_CODE */
700
701 static uword vlib_cli_normalize_path (char * input, char ** result)
702 {
703   char * i = input;
704   char * s = 0;
705   uword l = 0;
706   uword index_of_last_space = ~0;
707
708   while (*i != 0)
709     {
710       u8 c = *i++;
711       /* Multiple white space -> single space. */
712       switch (c)
713         {
714         case ' ':
715         case '\t':
716         case '\n':
717         case '\r':
718           if (l > 0 && s[l-1] != ' ')
719             {
720               vec_add1 (s, ' ');
721               l++;
722             }
723           break;
724
725         default:
726           if (l > 0 && s[l-1] == ' ')
727             index_of_last_space = vec_len (s);
728           vec_add1 (s, c);
729           l++;
730           break;
731         }
732     }
733
734   /* Remove any extra space at end. */
735   if (l > 0 && s[l-1] == ' ')
736     _vec_len (s) -= 1;
737
738   *result = s;
739   return index_of_last_space;
740 }
741
742 always_inline uword
743 parent_path_len (char * path)
744 {
745   word i;
746   for (i = vec_len (path) - 1; i >= 0; i--)
747     {
748       if (path[i] == ' ')
749         return i;
750     }
751   return ~0;
752 }
753
754 static void add_sub_command (vlib_cli_main_t * cm,
755                              uword parent_index,
756                              uword child_index)
757 {
758   vlib_cli_command_t * p, * c;
759   vlib_cli_sub_command_t * sub_c;
760   u8 * sub_name;
761   word i, l;
762
763   p = vec_elt_at_index (cm->commands, parent_index);
764   c = vec_elt_at_index (cm->commands, child_index);
765
766   l = parent_path_len (c->path);
767   if (l == ~0)
768     sub_name = vec_dup ((u8 *) c->path);
769   else
770     {
771       ASSERT (l + 1 < vec_len (c->path));
772       sub_name = 0;
773       vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
774     }
775
776   if (sub_name[0] == '%')
777     {
778       uword * q;
779       vlib_cli_sub_rule_t * sr;
780
781       /* Remove %. */
782       vec_delete (sub_name, 1, 0);
783
784       if (! p->sub_rule_index_by_name)
785         p->sub_rule_index_by_name
786           = hash_create_vec (/* initial length */ 32,
787                              sizeof (sub_name[0]),
788                              sizeof (uword));
789       q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
790       if (q)
791         {
792           sr = vec_elt_at_index (p->sub_rules, q[0]);
793           ASSERT (sr->command_index == child_index);
794           return;
795         }
796
797       q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
798       if (! q)
799         clib_error ("reference to unknown rule `%%%v' in path `%v'",
800                     sub_name, c->path);
801
802       hash_set_mem (p->sub_rule_index_by_name, sub_name, vec_len (p->sub_rules));
803       vec_add2 (p->sub_rules, sr, 1);
804       sr->name = sub_name;
805       sr->rule_index = q[0];
806       sr->command_index = child_index;
807       return;
808     }
809
810   if (! p->sub_command_index_by_name)
811     p->sub_command_index_by_name
812       = hash_create_vec (/* initial length */ 32,
813                          sizeof (c->path[0]),
814                          sizeof (uword));
815
816   /* Check if sub-command has already been created. */
817   if (hash_get_mem (p->sub_command_index_by_name, sub_name))
818     {
819       vec_free (sub_name);
820       return;
821     }
822
823   vec_add2 (p->sub_commands, sub_c, 1);
824   sub_c->index = child_index;
825   sub_c->name = sub_name;
826   hash_set_mem (p->sub_command_index_by_name, sub_c->name, sub_c - p->sub_commands);
827
828   vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
829   for (i = 0; i < vec_len (sub_c->name); i++)
830     {
831       int n;
832       vlib_cli_parse_position_t * pos;
833
834       pos = vec_elt_at_index (p->sub_command_positions, i);
835
836       if (! pos->bitmaps)
837         pos->min_char = sub_c->name[i];
838
839       n = sub_c->name[i] - pos->min_char;
840       if (n < 0)
841         {
842           pos->min_char = sub_c->name[i];
843           vec_insert (pos->bitmaps, -n, 0);
844           n = 0;
845         }
846
847       vec_validate (pos->bitmaps, n);
848       pos->bitmaps[n] = clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
849     }
850 }
851
852 static void
853 vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
854 {
855   uword p_len, pi, * p;
856   char * p_path;
857   vlib_cli_command_t * c, * parent;
858
859   /* Root command (index 0) should have already been added. */
860   ASSERT (vec_len (cm->commands) > 0);
861
862   c = vec_elt_at_index (cm->commands, ci);
863   p_len = parent_path_len (c->path);
864
865   /* No space?  Parent is root command. */ 
866   if (p_len == ~0)
867     {
868       add_sub_command (cm, 0, ci);
869       return;
870     }
871
872   p_path = 0;
873   vec_add (p_path, c->path, p_len);
874
875   p = hash_get_mem (cm->command_index_by_path, p_path);
876
877   /* Parent exists? */
878   if (! p)
879     {
880       /* Parent does not exist; create it. */
881       vec_add2 (cm->commands, parent, 1);
882       parent->path = p_path;
883       hash_set_mem (cm->command_index_by_path, parent->path, parent - cm->commands);
884       pi = parent - cm->commands;
885     }
886   else
887     {
888       pi = p[0];
889       vec_free (p_path);
890     }
891
892   add_sub_command (cm, pi, ci);
893
894   /* Create parent's parent. */
895   if (! p)
896     vlib_cli_make_parent (cm, pi);
897 }
898
899 always_inline uword
900 vlib_cli_command_is_empty (vlib_cli_command_t * c)
901 {
902   return (c->long_help == 0
903           && c->short_help == 0
904           && c->function == 0);
905 }
906
907 clib_error_t * vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
908 {
909   vlib_cli_main_t * cm = &vm->cli_main;
910   clib_error_t * error = 0;
911   uword ci, * p;
912   char * normalized_path;
913
914   if ((error = vlib_call_init_function (vm, vlib_cli_init)))
915     return error;
916
917   (void) vlib_cli_normalize_path (c->path, &normalized_path);
918
919   if (! cm->command_index_by_path)
920     cm->command_index_by_path = hash_create_vec (/* initial length */ 32,
921                                                  sizeof (c->path[0]),
922                                                  sizeof (uword));
923
924   /* See if command already exists with given path. */
925   p = hash_get_mem (cm->command_index_by_path, normalized_path);
926   if (p)
927     {
928       vlib_cli_command_t * d;
929
930       ci = p[0];
931       d = vec_elt_at_index (cm->commands, ci);
932
933       /* If existing command was created via vlib_cli_make_parent
934          replaced it with callers data. */
935       if (vlib_cli_command_is_empty (d))
936         {
937           vlib_cli_command_t save = d[0];
938
939           ASSERT (! vlib_cli_command_is_empty (c));
940
941           /* Copy callers fields. */
942           d[0] = c[0];
943
944           /* Save internal fields. */
945           d->path = save.path;
946           d->sub_commands = save.sub_commands;
947           d->sub_command_index_by_name = save.sub_command_index_by_name;
948           d->sub_command_positions = save.sub_command_positions;
949           d->sub_rules = save.sub_rules;
950         }
951       else
952         error = clib_error_return (0, "duplicate command name with path %v", normalized_path);
953
954       vec_free (normalized_path);
955       if (error)
956         return error;
957     }
958   else
959     {
960       /* Command does not exist: create it. */
961
962       /* Add root command (index 0). */
963       if (vec_len (cm->commands) == 0)
964         {
965           /* Create command with index 0; path is empty string. */
966           vec_resize (cm->commands, 1);
967         }
968
969       ci = vec_len (cm->commands);
970       hash_set_mem (cm->command_index_by_path, normalized_path, ci);
971       vec_add1 (cm->commands, c[0]);
972
973       c = vec_elt_at_index (cm->commands, ci);
974       c->path = normalized_path;
975
976       /* Don't inherit from registration. */
977       c->sub_commands = 0;
978       c->sub_command_index_by_name = 0;
979       c->sub_command_positions = 0;
980     }
981
982   vlib_cli_make_parent (cm, ci);
983   return 0;
984 }
985
986 clib_error_t *
987 vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
988 {
989   vlib_cli_main_t * cm = &vm->cli_main;
990   vlib_cli_parse_rule_t * r;
991   clib_error_t * error = 0;
992   u8 * r_name;
993   uword * p;
994
995   if (! cm->parse_rule_index_by_name)
996     cm->parse_rule_index_by_name = hash_create_vec (/* initial length */ 32,
997                                                     sizeof (r->name[0]),
998                                                     sizeof (uword));
999
1000   /* Make vector copy of name. */
1001   r_name = format (0, "%s", r_reg->name);
1002
1003   if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1004     {
1005       vec_free (r_name);
1006       return clib_error_return (0, "duplicate parse rule name `%s'", r_reg->name);
1007     }
1008
1009   vec_add2 (cm->parse_rules, r, 1);
1010   r[0] = r_reg[0];
1011   r->name = (char *) r_name;
1012   hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1013
1014   return error;
1015 }
1016
1017 #if 0
1018 /* $$$ turn back on again someday, maybe */
1019 static clib_error_t *
1020 vlib_cli_register_parse_rules (vlib_main_t * vm,
1021                                vlib_cli_parse_rule_t * lo,
1022                                vlib_cli_parse_rule_t * hi)
1023
1024     __attribute__((unused))
1025 {
1026   clib_error_t * error = 0;
1027   vlib_cli_parse_rule_t * r;
1028
1029   for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1030     {
1031       if (! r->name || strlen (r->name) == 0)
1032         {
1033           error = clib_error_return (0, "parse rule with no name");
1034           goto done;
1035         }
1036
1037       error = vlib_cli_register_parse_rule (vm, r);
1038       if (error)
1039         goto done;
1040     }
1041
1042  done:
1043   return error;
1044 }
1045 #endif
1046
1047 static clib_error_t * vlib_cli_init (vlib_main_t * vm)
1048 {
1049   vlib_cli_main_t * cm = &vm->cli_main;
1050   clib_error_t * error = 0;
1051   vlib_cli_command_t * cmd;
1052
1053   cmd = cm->cli_command_registrations;
1054
1055   while (cmd)
1056     {
1057       error = vlib_cli_register (vm, cmd);
1058       if (error)
1059         return error;
1060       cmd = cmd->next_cli_command;
1061     }
1062   return error;
1063 }
1064
1065 VLIB_INIT_FUNCTION (vlib_cli_init);