FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
init.c
Go to the documentation of this file.
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  * init.c: mechanism for functions to be called at init/exit.
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 
40 #include <vlib/vlib.h>
41 #include <vppinfra/ptclosure.h>
42 
43 /**
44  * @file
45  * @brief Init function ordering and execution implementation
46  * Topological sort for all classes of init functions, and
47  * a relatively simple API routine to invoke them.
48  */
49 
50 /*? %%clicmd:group_label Init functions %% ?*/
51 
52 static int
53 comma_split (u8 * s, u8 ** a, u8 ** b)
54 {
55  *a = s;
56 
57  while (*s && *s != ',')
58  s++;
59 
60  if (*s == ',')
61  *s = 0;
62  else
63  return 1;
64 
65  *b = (u8 *) (s + 1);
66  return 0;
67 }
68 
69 /**
70  * @brief Topological sorter for init function chains.
71  * @param head [in/out] address of the listhead to be sorted
72  * @returns 0 on success, otherwise a clib_error_t *.
73  */
74 
76  (_vlib_init_function_list_elt_t ** head)
77 {
78  uword *index_by_name;
79  uword *reg_by_index;
80  u8 **init_f_names = 0;
81  u8 *init_f_name;
82  char **these_constraints;
83  char *this_constraint_c;
84  u8 **constraints = 0;
85  u8 *constraint_tuple;
86  u8 *this_constraint;
87  char *prev_name;
88  u8 **orig, **closure;
89  uword *p;
90  int i, j, k;
91  u8 *a_name, *b_name;
92  int a_index, b_index;
93  int n_init_fns;
94  u32 *result = 0;
95  _vlib_init_function_list_elt_t *this_reg = 0;
96  hash_pair_t *hp;
97  u8 **keys_to_delete = 0;
98 
99  /*
100  * two hash tables: name to index in init_f_names, and
101  * init function registration pointer by index
102  */
103  index_by_name = hash_create_string (0, sizeof (uword));
104  reg_by_index = hash_create (0, sizeof (uword));
105 
106  this_reg = *head;
107 
108  /* pass 1, collect init fcn names, construct a before b pairs */
109  while (this_reg)
110  {
111  init_f_name = format (0, "%s%c", this_reg->name, 0);
112  hash_set (reg_by_index, vec_len (init_f_names), (uword) this_reg);
113 
114  hash_set_mem (index_by_name, init_f_name, vec_len (init_f_names));
115 
116  vec_add1 (init_f_names, init_f_name);
117 
118  these_constraints = this_reg->runs_before;
119  while (these_constraints && these_constraints[0])
120  {
121  this_constraint_c = these_constraints[0];
122 
123  constraint_tuple = format (0, "%s,%s%c", init_f_name,
124  this_constraint_c, 0);
125  vec_add1 (constraints, constraint_tuple);
126  these_constraints++;
127  }
128 
129  these_constraints = this_reg->runs_after;
130  while (these_constraints && these_constraints[0])
131  {
132  this_constraint_c = these_constraints[0];
133 
134  constraint_tuple = format (0, "%s,%s%c",
135  this_constraint_c, init_f_name, 0);
136  vec_add1 (constraints, constraint_tuple);
137  these_constraints++;
138  }
139 
140  this_reg = this_reg->next_init_function;
141  }
142 
143  /*
144  * pass 2: collect "a then b then c then d" constraints.
145  * all init fcns must be known at this point.
146  */
147  this_reg = *head;
148  while (this_reg)
149  {
150  these_constraints = this_reg->init_order;
151 
152  prev_name = 0;
153  /* Across the list of constraints */
154  while (these_constraints && these_constraints[0])
155  {
156  this_constraint_c = these_constraints[0];
157  p = hash_get_mem (index_by_name, this_constraint_c);
158  if (p == 0)
159  {
161  ("order constraint fcn '%s' not found", this_constraint_c);
162  these_constraints++;
163  continue;
164  }
165 
166  if (prev_name == 0)
167  {
168  prev_name = this_constraint_c;
169  these_constraints++;
170  continue;
171  }
172 
173  constraint_tuple = format (0, "%s,%s%c", prev_name,
174  this_constraint_c, 0);
175  vec_add1 (constraints, constraint_tuple);
176  prev_name = this_constraint_c;
177  these_constraints++;
178  }
179  this_reg = this_reg->next_init_function;
180  }
181 
182  n_init_fns = vec_len (init_f_names);
183  orig = clib_ptclosure_alloc (n_init_fns);
184 
185  for (i = 0; i < vec_len (constraints); i++)
186  {
187  this_constraint = constraints[i];
188 
189  if (comma_split (this_constraint, &a_name, &b_name))
190  return clib_error_return (0, "comma_split failed!");
191 
192  p = hash_get_mem (index_by_name, a_name);
193  /*
194  * Note: the next two errors mean that something is
195  * b0rked. As in: if you code "A runs before on B," and you type
196  * B incorrectly, you lose. Nonexistent init functions are tolerated.
197  */
198  if (p == 0)
199  {
200  clib_warning ("init function '%s' not found (before '%s')",
201  a_name, b_name);
202  continue;
203  }
204  a_index = p[0];
205 
206  p = hash_get_mem (index_by_name, b_name);
207  if (p == 0)
208  {
209  clib_warning ("init function '%s' not found (after '%s')",
210  b_name, a_name);
211  continue;
212  }
213  b_index = p[0];
214 
215  /* add a before b to the original set of constraints */
216  orig[a_index][b_index] = 1;
217  vec_free (this_constraint);
218  }
219 
220  /* Compute the positive transitive closure of the original constraints */
221  closure = clib_ptclosure (orig);
222 
223  /* Compute a partial order across feature nodes, if one exists. */
224 again:
225  for (i = 0; i < n_init_fns; i++)
226  {
227  for (j = 0; j < n_init_fns; j++)
228  {
229  if (closure[i][j])
230  goto item_constrained;
231  }
232  /* Item i can be output */
233  vec_add1 (result, i);
234  {
235  for (k = 0; k < n_init_fns; k++)
236  closure[k][i] = 0;
237  /*
238  * Add a "Magic" a before a constraint.
239  * This means we'll never output it again
240  */
241  closure[i][i] = 1;
242  goto again;
243  }
244  item_constrained:
245  ;
246  }
247 
248  /* see if we got a partial order... */
249  if (vec_len (result) != n_init_fns)
250  return clib_error_return
251  (0, "Failed to find a suitable init function order!");
252 
253  /*
254  * We win.
255  * Bind the index variables, and output the feature node name vector
256  * using the partial order we just computed. Result is in stack
257  * order, because the entry with the fewest constraints (e.g. none)
258  * is output first, etc.
259  * Reset the listhead, and add items in result (aka reverse) order.
260  */
261  *head = 0;
262  for (i = 0; i < n_init_fns; i++)
263  {
264  p = hash_get (reg_by_index, result[i]);
265  ASSERT (p != 0);
266  this_reg = (_vlib_init_function_list_elt_t *) p[0];
267 
268  this_reg->next_init_function = *head;
269  *head = this_reg;
270  }
271 
272  /* Finally, clean up all the fine data we allocated */
273  /* *INDENT-OFF* */
274  hash_foreach_pair (hp, index_by_name,
275  ({
276  vec_add1 (keys_to_delete, (u8 *)hp->key);
277  }));
278  /* *INDENT-ON* */
279  hash_free (index_by_name);
280  for (i = 0; i < vec_len (keys_to_delete); i++)
281  vec_free (keys_to_delete[i]);
282  vec_free (keys_to_delete);
283  hash_free (reg_by_index);
284  vec_free (result);
285  clib_ptclosure_free (orig);
286  clib_ptclosure_free (closure);
287  return 0;
288 }
289 
290 /**
291  * @brief call a set of init / exit / main-loop enter functions
292  * @param vm vlib_main_t
293  * @param head address of the listhead to sort and then invoke
294  * @returns 0 on success, clib_error_t * on error
295  *
296  * The "init_functions_called" hash supports a subtle mix of procedural
297  * and formally-specified ordering constraints. The following schemes
298  * are *roughly* equivalent:
299  *
300  * static clib_error_t *init_runs_first (vlib_main_t *vm)
301  * {
302  * clib_error_t *error;
303  *
304  * ... do some stuff...
305  *
306  * if ((error = vlib_call_init_function (init_runs_next)))
307  * return error;
308  * ...
309  * }
310  * VLIB_INIT_FUNCTION (init_runs_first);
311  *
312  * and
313  *
314  * static clib_error_t *init_runs_first (vlib_main_t *vm)
315  * {
316  * ... do some stuff...
317  * }
318  * VLIB_INIT_FUNCTION (init_runs_first) =
319  * {
320  * .runs_before = VLIB_INITS("init_runs_next"),
321  * };
322  *
323  * The first form will [most likely] call "init_runs_next" on the
324  * spot. The second form means that "init_runs_first" runs before
325  * "init_runs_next," possibly much earlier in the sequence.
326  *
327  * Please DO NOT construct sets of init functions where A before B
328  * actually means A *right before* B. It's not necessary - simply combine
329  * A and B - and it leads to hugely annoying debugging exercises.
330  */
331 
332 static inline clib_error_t *
334  _vlib_init_function_list_elt_t ** headp,
335  int call_once, int do_sort)
336 {
337  clib_error_t *error = 0;
338  _vlib_init_function_list_elt_t *i;
339 
340  if (do_sort && (error = vlib_sort_init_exit_functions (headp)))
341  return (error);
342 
343  i = *headp;
344  while (i)
345  {
346  if (call_once && !hash_get (vm->init_functions_called, i->f))
347  {
348  if (call_once)
349  hash_set1 (vm->init_functions_called, i->f);
350  error = i->f (vm);
351  if (error)
352  return error;
353  }
354  i = i->next_init_function;
355  }
356  return error;
357 }
358 
359 clib_error_t *
361  _vlib_init_function_list_elt_t ** headp,
362  int call_once)
363 {
364  return call_init_exit_functions_internal (vm, headp, call_once,
365  1 /* do_sort */ );
366 }
367 
368 clib_error_t *
370  _vlib_init_function_list_elt_t **
371  headp, int call_once)
372 {
373  return call_init_exit_functions_internal (vm, headp, call_once,
374  0 /* do_sort */ );
375 }
376 
377 clib_error_t *
379 {
380  /* Call dummy functions to make sure purely static modules are
381  linked in. */
382 #define _(f) vlib_##f##_reference ();
384 #undef _
385 
387  (vm, &vm->init_function_registrations, 1 /* call_once */ );
388 }
389 
390 clib_error_t *
392 {
394  (vm, &vm->main_loop_enter_function_registrations, 1 /* call_once */ );
395 }
396 
397 clib_error_t *
399 {
401  (vm, &vm->main_loop_exit_function_registrations, 1 /* call_once */ );
402 }
403 
404 clib_error_t *
406  unformat_input_t * input, int is_early)
407 {
408  clib_error_t *error = 0;
410  uword *hash = 0, *p;
411  uword i;
412 
413  hash = hash_create_string (0, sizeof (uword));
414  all = 0;
415 
417 
418  while (c)
419  {
420  hash_set_mem (hash, c->name, vec_len (all));
421  vec_add1 (all, c);
422  unformat_init (&c->input, 0, 0);
423  c = c->next_registration;
424  }
425 
427  {
428  u8 *s, *v;
429 
430  if (!unformat (input, "%s %v", &s, &v) || !(p = hash_get_mem (hash, s)))
431  {
432  error = clib_error_create ("unknown input `%s %v'", s, v);
433  goto done;
434  }
435 
436  c = all[p[0]];
437  if (vec_len (c->input.buffer) > 0)
438  vec_add1 (c->input.buffer, ' ');
439  vec_add (c->input.buffer, v, vec_len (v));
440  vec_free (v);
441  vec_free (s);
442  }
443 
444  for (i = 0; i < vec_len (all); i++)
445  {
446  c = all[i];
447 
448  /* Is this an early config? Are we doing early configs? */
449  if (is_early ^ c->is_early)
450  continue;
451 
452  /* Already called? */
454  continue;
456 
457  error = c->function (vm, &c->input);
458  if (error)
459  goto done;
460  }
461 
462 done:
463  for (i = 0; i < vec_len (all); i++)
464  {
465  c = all[i];
466  unformat_free (&c->input);
467  }
468  vec_free (all);
469  hash_free (hash);
470  return error;
471 }
472 
473 void
475 {
477  int i = 0;
478 
479  _vlib_init_function_list_elt_t *head, *this;
480  head = vm->init_function_registrations;
481 
482  this = head;
483  while (this)
484  {
485  fformat (stdout, "[%d]: %s\n", i++, this->name);
486  this = this->next_init_function;
487  }
488 }
489 
490 static clib_error_t *
492  unformat_input_t * input,
493  vlib_cli_command_t * cmd)
494 {
495  int which = 1;
496  int verbose = 0;
497  int i, n_init_fns;
498  _vlib_init_function_list_elt_t *head, *this;
499  uword *index_by_name;
500  uword *reg_by_index;
501  u8 **init_f_names = 0;
502  u8 *init_f_name;
503  uword *p;
504  _vlib_init_function_list_elt_t *this_reg = 0;
505  hash_pair_t *hp;
506  u8 **keys_to_delete = 0;
507 
509  {
510  if (unformat (input, "init"))
511  which = 1;
512  else if (unformat (input, "enter"))
513  which = 2;
514  else if (unformat (input, "exit"))
515  which = 3;
516  else if (unformat (input, "verbose %d", &verbose))
517  ;
518  else if (unformat (input, "verbose"))
519  verbose = 1;
520  else
521  break;
522  }
523 
524  switch (which)
525  {
526  case 1:
527  head = vm->init_function_registrations;
528  break;
529  case 2:
531  break;
532  case 3:
534  break;
535  default:
536  return clib_error_return (0, "BUG");
537  }
538 
539  if (verbose == 0)
540  {
541  this = head;
542  i = 0;
543  while (this)
544  {
545  vlib_cli_output (vm, "[%d]: %s", i++, this->name);
546  this = this->next_init_function;
547  }
548  return 0;
549  }
550 
551  index_by_name = hash_create_string (0, sizeof (uword));
552  reg_by_index = hash_create (0, sizeof (uword));
553 
554  this_reg = head;
555  n_init_fns = 0;
556  /* collect init fcn names */
557  while (this_reg)
558  {
559  init_f_name = format (0, "%s%c", this_reg->name, 0);
560  hash_set (reg_by_index, vec_len (init_f_names), (uword) this_reg);
561 
562  hash_set_mem (index_by_name, init_f_name, vec_len (init_f_names));
563  vec_add1 (init_f_names, init_f_name);
564  n_init_fns++;
565  this_reg = this_reg->next_init_function;
566  }
567 
568  for (i = 0; i < n_init_fns; i++)
569  {
570  p = hash_get (reg_by_index, i);
571  ASSERT (p != 0);
572  this_reg = (_vlib_init_function_list_elt_t *) p[0];
573  vlib_cli_output (vm, "[%d] %s", i, this_reg->name);
574  {
575  char **runs_before, **runs_after, **init_order;
576  runs_before = this_reg->runs_before;
577  while (runs_before && runs_before[0])
578  {
579  _vlib_init_function_list_elt_t *successor;
580  uword successor_index;
581  p = hash_get_mem (index_by_name, runs_before[0]);
582  if (p == 0)
583  {
584  clib_warning ("couldn't find successor '%s'", runs_before[0]);
585  runs_before++;
586  continue;
587  }
588  successor_index = p[0];
589  p = hash_get (reg_by_index, p[0]);
590  ASSERT (p != 0);
591  successor = (_vlib_init_function_list_elt_t *) p[0];
592  vlib_cli_output (vm, " before '%s' [%lld]",
593  successor->name, successor_index);
594  runs_before++;
595  }
596  runs_after = this_reg->runs_after;
597  while (runs_after && runs_after[0])
598  {
599  _vlib_init_function_list_elt_t *predecessor;
600  uword predecessor_index;
601  p = hash_get_mem (index_by_name, runs_after[0]);
602  if (p == 0)
603  {
604  clib_warning ("couldn't find predecessor '%s'",
605  runs_after[0]);
606  runs_after++;
607  continue;
608  }
609  predecessor_index = p[0];
610  p = hash_get (reg_by_index, p[0]);
611  ASSERT (p != 0);
612  predecessor = (_vlib_init_function_list_elt_t *) p[0];
613  vlib_cli_output (vm, " after '%s' [%lld]",
614  predecessor->name, predecessor_index);
615  runs_after++;
616  }
617  init_order = this_reg->init_order;
618  while (init_order && init_order[0])
619  {
620  _vlib_init_function_list_elt_t *inorder;
621  uword inorder_index;
622  p = hash_get_mem (index_by_name, init_order[0]);
623  if (p == 0)
624  {
625  clib_warning ("couldn't find order element'%s'",
626  init_order[0]);
627  init_order++;
628  continue;
629  }
630  inorder_index = p[0];
631  p = hash_get (reg_by_index, p[0]);
632  ASSERT (p != 0);
633  inorder = (_vlib_init_function_list_elt_t *) p[0];
634  vlib_cli_output (vm, " in order '%s' [%lld]",
635  inorder->name, inorder_index);
636  init_order++;
637  }
638  }
639  }
640  /* *INDENT-OFF* */
641  hash_foreach_pair (hp, index_by_name,
642  ({
643  vec_add1 (keys_to_delete, (u8 *)hp->key);
644  }));
645  /* *INDENT-ON* */
646  hash_free (index_by_name);
647  for (i = 0; i < vec_len (keys_to_delete); i++)
648  vec_free (keys_to_delete[i]);
649  vec_free (keys_to_delete);
650  hash_free (reg_by_index);
651 
652  return 0;
653 }
654 
655 /*?
656  * Show init function order
657  *
658  * @cliexpar
659  * @cliexstart{show init-function [init | enter | exit] [verbose [nn]]}
660  * @cliexend
661  ?*/
662 /* *INDENT-OFF* */
664  .path = "show init-function",
665  .short_help = "show init-function [init | enter | exit][verbose [nn]]",
666  .function = show_init_function_command_fn,
667 };
668 /* *INDENT-ON* */
669 
670 
671 /*
672  * fd.io coding-style-patch-verification: ON
673  *
674  * Local Variables:
675  * eval: (c-set-style "gnu")
676  * End:
677  */
static clib_error_t * show_init_function_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: init.c:491
clib_error_t * vlib_call_all_main_loop_exit_functions(vlib_main_t *vm)
Definition: init.c:398
#define hash_set(h, key, value)
Definition: hash.h:255
clib_error_t * vlib_call_all_main_loop_enter_functions(vlib_main_t *vm)
Definition: init.c:391
_vlib_init_function_list_elt_t * init_function_registrations
Definition: main.h:223
a
Definition: bitmap.h:538
_vlib_init_function_list_elt_t * main_loop_exit_function_registrations
Definition: main.h:226
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
int i
#define foreach_vlib_module_reference
Definition: init.h:336
#define hash_set_mem(h, key, value)
Definition: hash.h:275
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
vlib_config_function_t * function
Definition: init.h:71
static vlib_cli_command_t show_init_function
(constructor) VLIB_CLI_COMMAND (show_init_function)
Definition: init.c:663
unsigned char u8
Definition: types.h:56
clib_error_t * vlib_sort_init_exit_functions(_vlib_init_function_list_elt_t **head)
Topological sorter for init function chains.
Definition: init.c:76
clib_error_t * vlib_call_init_exit_functions(vlib_main_t *vm, _vlib_init_function_list_elt_t **headp, int call_once)
Definition: init.c:360
unformat_input_t input
Definition: init.h:74
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:599
clib_error_t * vlib_call_init_exit_functions_no_sort(vlib_main_t *vm, _vlib_init_function_list_elt_t **headp, int call_once)
Definition: init.c:369
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
#define clib_error_create(args...)
Definition: error.h:96
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
char * name
Definition: main.h:140
#define hash_get(h, key)
Definition: hash.h:249
struct _unformat_input_t unformat_input_t
#define hash_free(h)
Definition: hash.h:310
u8 ** clib_ptclosure_alloc(int n)
Definition: ptclosure.c:19
uword * init_functions_called
Definition: main.h:215
vlib_main_t * vm
Definition: in2out_ed.c:1810
word fformat(FILE *f, char *fmt,...)
Definition: format.c:462
**The first form will [most likely] call init_runs_next on the *spot The second form means that init_runs_first runs before possibly much earlier in the sequence **Please DO NOT construct sets of init functions where A before B *actually means A *right before *B It s not necessary simply combine *A and B and it leads to hugely annoying debugging exercises *static clib_error_t * call_init_exit_functions_internal(vlib_main_t *vm, _vlib_init_function_list_elt_t **headp, int call_once, int do_sort)
Definition: init.c:333
void clib_ptclosure_free(u8 **ptc)
Definition: ptclosure.c:39
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
svmdb_client_t * c
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:342
#define clib_warning(format, args...)
Definition: error.h:59
string name[64]
Definition: ip.api:44
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
#define hash_set1(h, key)
Definition: hash.h:258
#define hash_create(elts, value_bytes)
Definition: hash.h:696
#define ASSERT(truth)
static void unformat_init(unformat_input_t *i, uword(*fill_buffer)(unformat_input_t *), void *fill_buffer_arg)
Definition: format.h:153
_vlib_init_function_list_elt_t * main_loop_enter_function_registrations
Definition: main.h:225
static int comma_split(u8 *s, u8 **a, u8 **b)
Definition: init.c:53
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define hash_foreach_pair(p, v, body)
Iterate over hash pairs.
Definition: hash.h:373
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
clib_error_t * vlib_call_all_config_functions(vlib_main_t *vm, unformat_input_t *input, int is_early)
Definition: init.c:405
u8 ** clib_ptclosure(u8 **orig)
Definition: ptclosure.c:90
void vlib_init_dump(void)
Definition: init.c:474
clib_error_t * vlib_call_all_init_functions(vlib_main_t *vm)
Definition: init.c:378
struct vlib_config_function_runtime_t * next_registration
Definition: init.h:77
#define hash_get_mem(h, key)
Definition: hash.h:269
vlib_config_function_runtime_t * config_function_registrations
Definition: main.h:228
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
uword key
Definition: hash.h:162
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171