FD.io VPP  v21.06-1-gbb7418cf9
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, int is_global)
336 {
338  clib_error_t *error = 0;
339  _vlib_init_function_list_elt_t *i;
340 
341  if (do_sort && (error = vlib_sort_init_exit_functions (headp)))
342  return (error);
343 
344  i = *headp;
345  while (i)
346  {
347  uword *h;
348 
349  if (is_global)
350  h = hash_get (vgm->init_functions_called, i->f);
351  else
352  h = hash_get (vm->worker_init_functions_called, i->f);
353 
354  if (call_once && !h)
355  {
356  if (call_once)
357  {
358  if (is_global)
359  hash_set1 (vgm->init_functions_called, i->f);
360  else
362  }
363  error = i->f (vm);
364  if (error)
365  return error;
366  }
367  i = i->next_init_function;
368  }
369  return error;
370 }
371 
372 clib_error_t *
374  _vlib_init_function_list_elt_t **headp,
375  int call_once, int is_global)
376 {
377  return call_init_exit_functions_internal (vm, headp, call_once,
378  1 /* do_sort */, is_global);
379 }
380 
381 clib_error_t *
383  _vlib_init_function_list_elt_t **headp,
384  int call_once, int is_global)
385 {
386  return call_init_exit_functions_internal (vm, headp, call_once,
387  0 /* do_sort */, is_global);
388 }
389 
390 clib_error_t *
392 {
394  /* Call placeholder functions to make sure purely static modules are
395  linked in. */
396 #define _(f) vlib_##f##_reference ();
398 #undef _
399 
401  1 /* call_once */, 1 /* is_global */);
402 }
403 
404 clib_error_t *
406 {
409  vm, &vgm->main_loop_enter_function_registrations, 1 /* call_once */,
410  1 /* is_global */);
411 }
412 
413 clib_error_t *
415 {
418  vm, &vgm->main_loop_exit_function_registrations, 1 /* call_once */,
419  1 /* is_global */);
420 }
421 
422 clib_error_t *
424  unformat_input_t * input, int is_early)
425 {
427  clib_error_t *error = 0;
429  uword *hash = 0, *p;
430  uword i;
431 
432  hash = hash_create_string (0, sizeof (uword));
433  all = 0;
434 
436 
437  while (c)
438  {
439  hash_set_mem (hash, c->name, vec_len (all));
440  vec_add1 (all, c);
441  unformat_init (&c->input, 0, 0);
442  c = c->next_registration;
443  }
444 
446  {
447  u8 *s, *v;
448 
449  if (!unformat (input, "%s %v", &s, &v) || !(p = hash_get_mem (hash, s)))
450  {
451  error = clib_error_create ("unknown input `%s %v'", s, v);
452  goto done;
453  }
454 
455  c = all[p[0]];
456  if (vec_len (c->input.buffer) > 0)
457  vec_add1 (c->input.buffer, ' ');
458  vec_add (c->input.buffer, v, vec_len (v));
459  vec_free (v);
460  vec_free (s);
461  }
462 
463  for (i = 0; i < vec_len (all); i++)
464  {
465  c = all[i];
466 
467  /* Is this an early config? Are we doing early configs? */
468  if (is_early ^ c->is_early)
469  continue;
470 
471  /* Already called? */
472  if (hash_get (vgm->init_functions_called, c->function))
473  continue;
475 
476  error = c->function (vm, &c->input);
477  if (error)
478  goto done;
479  }
480 
481 done:
482  for (i = 0; i < vec_len (all); i++)
483  {
484  c = all[i];
485  unformat_free (&c->input);
486  }
487  vec_free (all);
488  hash_free (hash);
489  return error;
490 }
491 
492 void
494 {
496  int i = 0;
497 
498  _vlib_init_function_list_elt_t *head, *this;
499  head = vgm->init_function_registrations;
500 
501  this = head;
502  while (this)
503  {
504  fformat (stdout, "[%d]: %s\n", i++, this->name);
505  this = this->next_init_function;
506  }
507 }
508 
509 static clib_error_t *
511  unformat_input_t * input,
512  vlib_cli_command_t * cmd)
513 {
515  int which = 1;
516  int verbose = 0;
517  int i, n_init_fns;
518  _vlib_init_function_list_elt_t *head, *this;
519  uword *index_by_name;
520  uword *reg_by_index;
521  u8 **init_f_names = 0;
522  u8 *init_f_name;
523  uword *p;
524  _vlib_init_function_list_elt_t *this_reg = 0;
525  hash_pair_t *hp;
526  u8 **keys_to_delete = 0;
527 
529  {
530  if (unformat (input, "init"))
531  which = 1;
532  else if (unformat (input, "enter"))
533  which = 2;
534  else if (unformat (input, "exit"))
535  which = 3;
536  else if (unformat (input, "verbose %d", &verbose))
537  ;
538  else if (unformat (input, "verbose"))
539  verbose = 1;
540  else
541  break;
542  }
543 
544  switch (which)
545  {
546  case 1:
547  head = vgm->init_function_registrations;
548  break;
549  case 2:
551  break;
552  case 3:
554  break;
555  default:
556  return clib_error_return (0, "BUG");
557  }
558 
559  if (verbose == 0)
560  {
561  this = head;
562  i = 0;
563  while (this)
564  {
565  vlib_cli_output (vm, "[%d]: %s", i++, this->name);
566  this = this->next_init_function;
567  }
568  return 0;
569  }
570 
571  index_by_name = hash_create_string (0, sizeof (uword));
572  reg_by_index = hash_create (0, sizeof (uword));
573 
574  this_reg = head;
575  n_init_fns = 0;
576  /* collect init fcn names */
577  while (this_reg)
578  {
579  init_f_name = format (0, "%s%c", this_reg->name, 0);
580  hash_set (reg_by_index, vec_len (init_f_names), (uword) this_reg);
581 
582  hash_set_mem (index_by_name, init_f_name, vec_len (init_f_names));
583  vec_add1 (init_f_names, init_f_name);
584  n_init_fns++;
585  this_reg = this_reg->next_init_function;
586  }
587 
588  for (i = 0; i < n_init_fns; i++)
589  {
590  p = hash_get (reg_by_index, i);
591  ASSERT (p != 0);
592  this_reg = (_vlib_init_function_list_elt_t *) p[0];
593  vlib_cli_output (vm, "[%d] %s", i, this_reg->name);
594  {
595  char **runs_before, **runs_after, **init_order;
596  runs_before = this_reg->runs_before;
597  while (runs_before && runs_before[0])
598  {
599  _vlib_init_function_list_elt_t *successor;
600  uword successor_index;
601  p = hash_get_mem (index_by_name, runs_before[0]);
602  if (p == 0)
603  {
604  clib_warning ("couldn't find successor '%s'", runs_before[0]);
605  runs_before++;
606  continue;
607  }
608  successor_index = p[0];
609  p = hash_get (reg_by_index, p[0]);
610  ASSERT (p != 0);
611  successor = (_vlib_init_function_list_elt_t *) p[0];
612  vlib_cli_output (vm, " before '%s' [%lld]",
613  successor->name, successor_index);
614  runs_before++;
615  }
616  runs_after = this_reg->runs_after;
617  while (runs_after && runs_after[0])
618  {
619  _vlib_init_function_list_elt_t *predecessor;
620  uword predecessor_index;
621  p = hash_get_mem (index_by_name, runs_after[0]);
622  if (p == 0)
623  {
624  clib_warning ("couldn't find predecessor '%s'",
625  runs_after[0]);
626  runs_after++;
627  continue;
628  }
629  predecessor_index = p[0];
630  p = hash_get (reg_by_index, p[0]);
631  ASSERT (p != 0);
632  predecessor = (_vlib_init_function_list_elt_t *) p[0];
633  vlib_cli_output (vm, " after '%s' [%lld]",
634  predecessor->name, predecessor_index);
635  runs_after++;
636  }
637  init_order = this_reg->init_order;
638  while (init_order && init_order[0])
639  {
640  _vlib_init_function_list_elt_t *inorder;
641  uword inorder_index;
642  p = hash_get_mem (index_by_name, init_order[0]);
643  if (p == 0)
644  {
645  clib_warning ("couldn't find order element'%s'",
646  init_order[0]);
647  init_order++;
648  continue;
649  }
650  inorder_index = p[0];
651  p = hash_get (reg_by_index, p[0]);
652  ASSERT (p != 0);
653  inorder = (_vlib_init_function_list_elt_t *) p[0];
654  vlib_cli_output (vm, " in order '%s' [%lld]",
655  inorder->name, inorder_index);
656  init_order++;
657  }
658  }
659  }
660  /* *INDENT-OFF* */
661  hash_foreach_pair (hp, index_by_name,
662  ({
663  vec_add1 (keys_to_delete, (u8 *)hp->key);
664  }));
665  /* *INDENT-ON* */
666  hash_free (index_by_name);
667  for (i = 0; i < vec_len (keys_to_delete); i++)
668  vec_free (keys_to_delete[i]);
669  vec_free (keys_to_delete);
670  hash_free (reg_by_index);
671 
672  return 0;
673 }
674 
675 /*?
676  * Show init function order
677  *
678  * @cliexpar
679  * @cliexstart{show init-function [init | enter | exit] [verbose [nn]]}
680  * @cliexend
681  ?*/
682 /* *INDENT-OFF* */
684  .path = "show init-function",
685  .short_help = "show init-function [init | enter | exit][verbose [nn]]",
686  .function = show_init_function_command_fn,
687 };
688 /* *INDENT-ON* */
689 
690 
691 /*
692  * fd.io coding-style-patch-verification: ON
693  *
694  * Local Variables:
695  * eval: (c-set-style "gnu")
696  * End:
697  */
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:510
clib_error_t * vlib_call_all_main_loop_exit_functions(vlib_main_t *vm)
Definition: init.c:414
#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:405
a
Definition: bitmap.h:544
_vlib_init_function_list_elt_t * init_function_registrations
Definition: main.h:307
#define is_global(M)
Definition: dlmalloc.c:1220
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
#define foreach_vlib_module_reference
Definition: init.h:344
#define hash_set_mem(h, key, value)
Definition: hash.h:275
string name[64]
Definition: fib.api:25
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:683
unsigned char u8
Definition: types.h:56
vlib_buffer_t ** b
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
unsigned int u32
Definition: types.h:88
clib_error_t * vlib_call_init_exit_functions(vlib_main_t *vm, _vlib_init_function_list_elt_t **headp, int call_once, int is_global)
Definition: init.c:373
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:689
__clib_export word fformat(FILE *f, char *fmt,...)
Definition: format.c:466
**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, int is_global)
Definition: init.c:333
int which
Definition: cJSON.h:234
uword * init_functions_called
Definition: main.h:315
static vlib_global_main_t * vlib_get_global_main(void)
Definition: global_funcs.h:50
description fragment has unexpected format
Definition: map.api:433
#define clib_error_return(e, args...)
Definition: error.h:99
#define clib_error_create(args...)
Definition: error.h:96
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
__clib_export u8 ** clib_ptclosure(u8 **orig)
Definition: ptclosure.c:90
Definition: cJSON.c:88
#define hash_get(h, key)
Definition: hash.h:249
struct _unformat_input_t unformat_input_t
#define hash_free(h)
Definition: hash.h:310
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
uword * worker_init_functions_called
Definition: main.h:189
__clib_export void clib_ptclosure_free(u8 **ptc)
Definition: ptclosure.c:39
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
svmdb_client_t * c
_vlib_init_function_list_elt_t * main_loop_exit_function_registrations
Definition: main.h:309
clib_error_t * vlib_call_init_exit_functions_no_sort(vlib_main_t *vm, _vlib_init_function_list_elt_t **headp, int call_once, int is_global)
Definition: init.c:382
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
#define clib_warning(format, args...)
Definition: error.h:59
_vlib_init_function_list_elt_t * main_loop_enter_function_registrations
Definition: main.h:308
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
#define hash_set1(h, key)
Definition: hash.h:258
#define hash_create(elts, value_bytes)
Definition: hash.h:696
#define ASSERT(truth)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
static void unformat_init(unformat_input_t *i, uword(*fill_buffer)(unformat_input_t *), void *fill_buffer_arg)
Definition: format.h:145
static int comma_split(u8 *s, u8 **a, u8 **b)
Definition: init.c:53
#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:155
clib_error_t * vlib_call_all_config_functions(vlib_main_t *vm, unformat_input_t *input, int is_early)
Definition: init.c:423
void vlib_init_dump(void)
Definition: init.c:493
clib_error_t * vlib_call_all_init_functions(vlib_main_t *vm)
Definition: init.c:391
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:312
__clib_export u8 ** clib_ptclosure_alloc(int n)
Definition: ptclosure.c:19
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:163