LCOV - code coverage report
Current view: top level - vlib - init.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 162 287 56.4 %
Date: 2023-10-26 01:39:38 Functions: 11 13 84.6 %

          Line data    Source code
       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       48316 : comma_split (u8 * s, u8 ** a, u8 ** b)
      54             : {
      55       48316 :   *a = s;
      56             : 
      57      714360 :   while (*s && *s != ',')
      58      666044 :     s++;
      59             : 
      60       48316 :   if (*s == ',')
      61       48316 :     *s = 0;
      62             :   else
      63           0 :     return 1;
      64             : 
      65       48316 :   *b = (u8 *) (s + 1);
      66       48316 :   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             : 
      75        3450 : clib_error_t *vlib_sort_init_exit_functions
      76             :   (_vlib_init_function_list_elt_t ** head)
      77             : {
      78             :   uword *index_by_name;
      79             :   uword *reg_by_index;
      80        3450 :   u8 **init_f_names = 0;
      81             :   u8 *init_f_name;
      82             :   char **these_constraints;
      83             :   char *this_constraint_c;
      84        3450 :   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        3450 :   u32 *result = 0;
      95        3450 :   _vlib_init_function_list_elt_t *this_reg = 0;
      96             :   hash_pair_t *hp;
      97        3450 :   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        3450 :   index_by_name = hash_create_string (0, sizeof (uword));
     104        3450 :   reg_by_index = hash_create (0, sizeof (uword));
     105             : 
     106        3450 :   this_reg = *head;
     107             : 
     108             :   /* pass 1, collect init fcn names, construct a before b pairs */
     109      244413 :   while (this_reg)
     110             :     {
     111      240963 :       init_f_name = format (0, "%s%c", this_reg->name, 0);
     112      240963 :       hash_set (reg_by_index, vec_len (init_f_names), (uword) this_reg);
     113             : 
     114      481926 :       hash_set_mem (index_by_name, init_f_name, vec_len (init_f_names));
     115             : 
     116      240963 :       vec_add1 (init_f_names, init_f_name);
     117             : 
     118      240963 :       these_constraints = this_reg->runs_before;
     119      244413 :       while (these_constraints && these_constraints[0])
     120             :         {
     121        3450 :           this_constraint_c = these_constraints[0];
     122             : 
     123        3450 :           constraint_tuple = format (0, "%s,%s%c", init_f_name,
     124             :                                      this_constraint_c, 0);
     125        3450 :           vec_add1 (constraints, constraint_tuple);
     126        3450 :           these_constraints++;
     127             :         }
     128             : 
     129      240963 :       these_constraints = this_reg->runs_after;
     130      272604 :       while (these_constraints && these_constraints[0])
     131             :         {
     132       31641 :           this_constraint_c = these_constraints[0];
     133             : 
     134       31641 :           constraint_tuple = format (0, "%s,%s%c",
     135             :                                      this_constraint_c, init_f_name, 0);
     136       31641 :           vec_add1 (constraints, constraint_tuple);
     137       31641 :           these_constraints++;
     138             :         }
     139             : 
     140      240963 :       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        3450 :   this_reg = *head;
     148      244413 :   while (this_reg)
     149             :     {
     150      240963 :       these_constraints = this_reg->init_order;
     151             : 
     152      240963 :       prev_name = 0;
     153             :       /* Across the list of constraints */
     154      256488 :       while (these_constraints && these_constraints[0])
     155             :         {
     156       15525 :           this_constraint_c = these_constraints[0];
     157       15525 :           p = hash_get_mem (index_by_name, this_constraint_c);
     158       15525 :           if (p == 0)
     159             :             {
     160           0 :               clib_warning
     161             :                 ("order constraint fcn '%s' not found", this_constraint_c);
     162           0 :               these_constraints++;
     163           0 :               continue;
     164             :             }
     165             : 
     166       15525 :           if (prev_name == 0)
     167             :             {
     168        2300 :               prev_name = this_constraint_c;
     169        2300 :               these_constraints++;
     170        2300 :               continue;
     171             :             }
     172             : 
     173       13225 :           constraint_tuple = format (0, "%s,%s%c", prev_name,
     174             :                                      this_constraint_c, 0);
     175       13225 :           vec_add1 (constraints, constraint_tuple);
     176       13225 :           prev_name = this_constraint_c;
     177       13225 :           these_constraints++;
     178             :         }
     179      240963 :       this_reg = this_reg->next_init_function;
     180             :     }
     181             : 
     182        3450 :   n_init_fns = vec_len (init_f_names);
     183        3450 :   orig = clib_ptclosure_alloc (n_init_fns);
     184             : 
     185       51766 :   for (i = 0; i < vec_len (constraints); i++)
     186             :     {
     187       48316 :       this_constraint = constraints[i];
     188             : 
     189       48316 :       if (comma_split (this_constraint, &a_name, &b_name))
     190           0 :         return clib_error_return (0, "comma_split failed!");
     191             : 
     192       96632 :       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       48316 :       if (p == 0)
     199             :         {
     200           0 :           clib_warning ("init function '%s' not found (before '%s')",
     201             :                         a_name, b_name);
     202           0 :           continue;
     203             :         }
     204       48316 :       a_index = p[0];
     205             : 
     206       96632 :       p = hash_get_mem (index_by_name, b_name);
     207       48316 :       if (p == 0)
     208             :         {
     209           0 :           clib_warning ("init function '%s' not found (after '%s')",
     210             :                         b_name, a_name);
     211           0 :           continue;
     212             :         }
     213       48316 :       b_index = p[0];
     214             : 
     215             :       /* add a before b to the original set of constraints */
     216       48316 :       orig[a_index][b_index] = 1;
     217       48316 :       vec_free (this_constraint);
     218             :     }
     219             : 
     220             :   /* Compute the positive transitive closure of the original constraints */
     221        3450 :   closure = clib_ptclosure (orig);
     222             : 
     223             :   /* Compute a partial order across feature nodes, if one exists. */
     224      244413 : again:
     225    34870700 :   for (i = 0; i < n_init_fns; i++)
     226             :     {
     227  3928160000 :       for (j = 0; j < n_init_fns; j++)
     228             :         {
     229  3927920000 :           if (closure[i][j])
     230    34626300 :             goto item_constrained;
     231             :         }
     232             :       /* Item i can be output */
     233      240963 :       vec_add1 (result, i);
     234             :       {
     235    69252600 :         for (k = 0; k < n_init_fns; k++)
     236    69011600 :           closure[k][i] = 0;
     237             :         /*
     238             :          * Add a "Magic" a before a constraint.
     239             :          * This means we'll never output it again
     240             :          */
     241      240963 :         closure[i][i] = 1;
     242      240963 :         goto again;
     243             :       }
     244    34626300 :     item_constrained:
     245             :       ;
     246             :     }
     247             : 
     248             :   /* see if we got a partial order... */
     249        3450 :   if (vec_len (result) != n_init_fns)
     250           0 :     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        3450 :   *head = 0;
     262      244413 :   for (i = 0; i < n_init_fns; i++)
     263             :     {
     264      240963 :       p = hash_get (reg_by_index, result[i]);
     265      240963 :       ASSERT (p != 0);
     266      240963 :       this_reg = (_vlib_init_function_list_elt_t *) p[0];
     267             : 
     268      240963 :       this_reg->next_init_function = *head;
     269      240963 :       *head = this_reg;
     270             :     }
     271             : 
     272             :   /* Finally, clean up all the fine data we allocated */
     273             :   /* *INDENT-OFF* */
     274      759613 :   hash_foreach_pair (hp, index_by_name,
     275             :   ({
     276             :     vec_add1 (keys_to_delete, (u8 *)hp->key);
     277             :   }));
     278             :   /* *INDENT-ON* */
     279        3450 :   hash_free (index_by_name);
     280      244413 :   for (i = 0; i < vec_len (keys_to_delete); i++)
     281      240963 :     vec_free (keys_to_delete[i]);
     282        3450 :   vec_free (keys_to_delete);
     283        3450 :   hash_free (reg_by_index);
     284        3450 :   vec_free (result);
     285        3450 :   clib_ptclosure_free (orig);
     286        3450 :   clib_ptclosure_free (closure);
     287        3450 :   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 *
     333        2930 : call_init_exit_functions_internal (vlib_main_t *vm,
     334             :                                    _vlib_init_function_list_elt_t **headp,
     335             :                                    int call_once, int do_sort, int is_global)
     336             : {
     337        2930 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     338        2929 :   clib_error_t *error = 0;
     339             :   _vlib_init_function_list_elt_t *i;
     340             : 
     341        2929 :   if (do_sort && (error = vlib_sort_init_exit_functions (headp)))
     342           0 :     return (error);
     343             : 
     344        2930 :   i = *headp;
     345      241293 :   while (i)
     346             :     {
     347             :       uword *h;
     348             : 
     349      238363 :       if (is_global)
     350      238088 :         h = hash_get (vgm->init_functions_called, i->f);
     351             :       else
     352         275 :         h = hash_get (vm->worker_init_functions_called, i->f);
     353             : 
     354      238359 :       if (call_once && !h)
     355             :         {
     356      216509 :           if (call_once)
     357             :             {
     358      216509 :               if (is_global)
     359      216238 :                 hash_set1 (vgm->init_functions_called, i->f);
     360             :               else
     361         271 :                 hash_set1 (vm->worker_init_functions_called, i->f);
     362             :             }
     363      216505 :           error = i->f (vm);
     364      216513 :           if (error)
     365           0 :             return error;
     366             :         }
     367      238363 :       i = i->next_init_function;
     368             :     }
     369        2930 :   return error;
     370             : }
     371             : 
     372             : clib_error_t *
     373        2875 : vlib_call_init_exit_functions (vlib_main_t *vm,
     374             :                                _vlib_init_function_list_elt_t **headp,
     375             :                                int call_once, int is_global)
     376             : {
     377        2875 :   return call_init_exit_functions_internal (vm, headp, call_once,
     378             :                                             1 /* do_sort */, is_global);
     379             : }
     380             : 
     381             : clib_error_t *
     382          54 : vlib_call_init_exit_functions_no_sort (vlib_main_t *vm,
     383             :                                        _vlib_init_function_list_elt_t **headp,
     384             :                                        int call_once, int is_global)
     385             : {
     386          54 :   return call_init_exit_functions_internal (vm, headp, call_once,
     387             :                                             0 /* do_sort */, is_global);
     388             : }
     389             : 
     390             : clib_error_t *
     391         575 : vlib_call_all_init_functions (vlib_main_t * vm)
     392             : {
     393         575 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     394             :   /* Call placeholder functions to make sure purely static modules are
     395             :      linked in. */
     396             : #define _(f) vlib_##f##_reference ();
     397         575 :   foreach_vlib_module_reference;
     398             : #undef _
     399             : 
     400         575 :   return vlib_call_init_exit_functions (vm, &vgm->init_function_registrations,
     401             :                                         1 /* call_once */, 1 /* is_global */);
     402             : }
     403             : 
     404             : clib_error_t *
     405         575 : vlib_call_all_main_loop_enter_functions (vlib_main_t * vm)
     406             : {
     407         575 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     408         575 :   return vlib_call_init_exit_functions (
     409             :     vm, &vgm->main_loop_enter_function_registrations, 1 /* call_once */,
     410             :     1 /* is_global */);
     411             : }
     412             : 
     413             : clib_error_t *
     414         575 : vlib_call_all_main_loop_exit_functions (vlib_main_t * vm)
     415             : {
     416         575 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     417         575 :   return vlib_call_init_exit_functions (
     418             :     vm, &vgm->main_loop_exit_function_registrations, 1 /* call_once */,
     419             :     1 /* is_global */);
     420             : }
     421             : 
     422             : clib_error_t *
     423        1150 : vlib_call_all_config_functions (vlib_main_t * vm,
     424             :                                 unformat_input_t * input, int is_early)
     425             : {
     426        1150 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     427        1150 :   clib_error_t *error = 0;
     428             :   vlib_config_function_runtime_t *c, **all;
     429        1150 :   uword *hash = 0, *p;
     430             :   uword i;
     431             : 
     432        1150 :   hash = hash_create_string (0, sizeof (uword));
     433        1150 :   all = 0;
     434             : 
     435        1150 :   c = vgm->config_function_registrations;
     436             : 
     437       49504 :   while (c)
     438             :     {
     439       96708 :       hash_set_mem (hash, c->name, vec_len (all));
     440       48354 :       vec_add1 (all, c);
     441       48354 :       unformat_init (&c->input, 0, 0);
     442       48354 :       c = c->next_registration;
     443             :     }
     444             : 
     445       12824 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     446             :     {
     447             :       u8 *s, *v;
     448             : 
     449       23348 :       if (!unformat (input, "%s %v", &s, &v) || !(p = hash_get_mem (hash, s)))
     450             :         {
     451           0 :           error = clib_error_create ("unknown input `%s %v'", s, v);
     452           0 :           goto done;
     453             :         }
     454             : 
     455       11674 :       c = all[p[0]];
     456       11674 :       if (vec_len (c->input.buffer) > 0)
     457           0 :         vec_add1 (c->input.buffer, ' ');
     458       11674 :       vec_add (c->input.buffer, v, vec_len (v));
     459       11674 :       vec_free (v);
     460       11674 :       vec_free (s);
     461             :     }
     462             : 
     463       49504 :   for (i = 0; i < vec_len (all); i++)
     464             :     {
     465       48354 :       c = all[i];
     466             : 
     467             :       /* Is this an early config? Are we doing early configs? */
     468       48354 :       if (is_early ^ c->is_early)
     469       24177 :         continue;
     470             : 
     471             :       /* Already called? */
     472       24177 :       if (hash_get (vgm->init_functions_called, c->function))
     473           0 :         continue;
     474       24177 :       hash_set1 (vgm->init_functions_called, c->function);
     475             : 
     476       24177 :       error = c->function (vm, &c->input);
     477       24177 :       if (error)
     478           0 :         goto done;
     479             :     }
     480             : 
     481        1150 : done:
     482       49504 :   for (i = 0; i < vec_len (all); i++)
     483             :     {
     484       48354 :       c = all[i];
     485       48354 :       unformat_free (&c->input);
     486             :     }
     487        1150 :   vec_free (all);
     488        1150 :   hash_free (hash);
     489        1150 :   return error;
     490             : }
     491             : 
     492             : void
     493           0 : vlib_init_dump (void)
     494             : {
     495           0 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     496           0 :   int i = 0;
     497             : 
     498             :   _vlib_init_function_list_elt_t *head, *this;
     499           0 :   head = vgm->init_function_registrations;
     500             : 
     501           0 :   this = head;
     502           0 :   while (this)
     503             :     {
     504           0 :       fformat (stdout, "[%d]: %s\n", i++, this->name);
     505           0 :       this = this->next_init_function;
     506             :     }
     507           0 : }
     508             : 
     509             : static clib_error_t *
     510           0 : show_init_function_command_fn (vlib_main_t * vm,
     511             :                                unformat_input_t * input,
     512             :                                vlib_cli_command_t * cmd)
     513             : {
     514           0 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     515           0 :   int which = 1;
     516           0 :   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           0 :   u8 **init_f_names = 0;
     522             :   u8 *init_f_name;
     523             :   uword *p;
     524           0 :   _vlib_init_function_list_elt_t *this_reg = 0;
     525             :   hash_pair_t *hp;
     526           0 :   u8 **keys_to_delete = 0;
     527             : 
     528           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     529             :     {
     530           0 :       if (unformat (input, "init"))
     531           0 :         which = 1;
     532           0 :       else if (unformat (input, "enter"))
     533           0 :         which = 2;
     534           0 :       else if (unformat (input, "exit"))
     535           0 :         which = 3;
     536           0 :       else if (unformat (input, "verbose %d", &verbose))
     537             :         ;
     538           0 :       else if (unformat (input, "verbose"))
     539           0 :         verbose = 1;
     540             :       else
     541           0 :         break;
     542             :     }
     543             : 
     544           0 :   switch (which)
     545             :     {
     546           0 :     case 1:
     547           0 :       head = vgm->init_function_registrations;
     548           0 :       break;
     549           0 :     case 2:
     550           0 :       head = vgm->main_loop_enter_function_registrations;
     551           0 :       break;
     552           0 :     case 3:
     553           0 :       head = vgm->main_loop_exit_function_registrations;
     554           0 :       break;
     555           0 :     default:
     556           0 :       return clib_error_return (0, "BUG");
     557             :     }
     558             : 
     559           0 :   if (verbose == 0)
     560             :     {
     561           0 :       this = head;
     562           0 :       i = 0;
     563           0 :       while (this)
     564             :         {
     565           0 :           vlib_cli_output (vm, "[%d]: %s", i++, this->name);
     566           0 :           this = this->next_init_function;
     567             :         }
     568           0 :       return 0;
     569             :     }
     570             : 
     571           0 :   index_by_name = hash_create_string (0, sizeof (uword));
     572           0 :   reg_by_index = hash_create (0, sizeof (uword));
     573             : 
     574           0 :   this_reg = head;
     575           0 :   n_init_fns = 0;
     576             :   /* collect init fcn names */
     577           0 :   while (this_reg)
     578             :     {
     579           0 :       init_f_name = format (0, "%s%c", this_reg->name, 0);
     580           0 :       hash_set (reg_by_index, vec_len (init_f_names), (uword) this_reg);
     581             : 
     582           0 :       hash_set_mem (index_by_name, init_f_name, vec_len (init_f_names));
     583           0 :       vec_add1 (init_f_names, init_f_name);
     584           0 :       n_init_fns++;
     585           0 :       this_reg = this_reg->next_init_function;
     586             :     }
     587             : 
     588           0 :   for (i = 0; i < n_init_fns; i++)
     589             :     {
     590           0 :       p = hash_get (reg_by_index, i);
     591           0 :       ASSERT (p != 0);
     592           0 :       this_reg = (_vlib_init_function_list_elt_t *) p[0];
     593           0 :       vlib_cli_output (vm, "[%d] %s", i, this_reg->name);
     594             :       {
     595             :         char **runs_before, **runs_after, **init_order;
     596           0 :         runs_before = this_reg->runs_before;
     597           0 :         while (runs_before && runs_before[0])
     598             :           {
     599             :             _vlib_init_function_list_elt_t *successor;
     600             :             uword successor_index;
     601           0 :             p = hash_get_mem (index_by_name, runs_before[0]);
     602           0 :             if (p == 0)
     603             :               {
     604           0 :                 clib_warning ("couldn't find successor '%s'", runs_before[0]);
     605           0 :                 runs_before++;
     606           0 :                 continue;
     607             :               }
     608           0 :             successor_index = p[0];
     609           0 :             p = hash_get (reg_by_index, p[0]);
     610           0 :             ASSERT (p != 0);
     611           0 :             successor = (_vlib_init_function_list_elt_t *) p[0];
     612           0 :             vlib_cli_output (vm, "  before '%s' [%lld]",
     613             :                              successor->name, successor_index);
     614           0 :             runs_before++;
     615             :           }
     616           0 :         runs_after = this_reg->runs_after;
     617           0 :         while (runs_after && runs_after[0])
     618             :           {
     619             :             _vlib_init_function_list_elt_t *predecessor;
     620             :             uword predecessor_index;
     621           0 :             p = hash_get_mem (index_by_name, runs_after[0]);
     622           0 :             if (p == 0)
     623             :               {
     624           0 :                 clib_warning ("couldn't find predecessor '%s'",
     625             :                               runs_after[0]);
     626           0 :                 runs_after++;
     627           0 :                 continue;
     628             :               }
     629           0 :             predecessor_index = p[0];
     630           0 :             p = hash_get (reg_by_index, p[0]);
     631           0 :             ASSERT (p != 0);
     632           0 :             predecessor = (_vlib_init_function_list_elt_t *) p[0];
     633           0 :             vlib_cli_output (vm, "  after '%s' [%lld]",
     634             :                              predecessor->name, predecessor_index);
     635           0 :             runs_after++;
     636             :           }
     637           0 :         init_order = this_reg->init_order;
     638           0 :         while (init_order && init_order[0])
     639             :           {
     640             :             _vlib_init_function_list_elt_t *inorder;
     641             :             uword inorder_index;
     642           0 :             p = hash_get_mem (index_by_name, init_order[0]);
     643           0 :             if (p == 0)
     644             :               {
     645           0 :                 clib_warning ("couldn't find order element'%s'",
     646             :                               init_order[0]);
     647           0 :                 init_order++;
     648           0 :                 continue;
     649             :               }
     650           0 :             inorder_index = p[0];
     651           0 :             p = hash_get (reg_by_index, p[0]);
     652           0 :             ASSERT (p != 0);
     653           0 :             inorder = (_vlib_init_function_list_elt_t *) p[0];
     654           0 :             vlib_cli_output (vm, "  in order '%s' [%lld]",
     655             :                              inorder->name, inorder_index);
     656           0 :             init_order++;
     657             :           }
     658             :       }
     659             :     }
     660             :   /* *INDENT-OFF* */
     661           0 :   hash_foreach_pair (hp, index_by_name,
     662             :   ({
     663             :     vec_add1 (keys_to_delete, (u8 *)hp->key);
     664             :   }));
     665             :   /* *INDENT-ON* */
     666           0 :   hash_free (index_by_name);
     667           0 :   for (i = 0; i < vec_len (keys_to_delete); i++)
     668           0 :     vec_free (keys_to_delete[i]);
     669           0 :   vec_free (keys_to_delete);
     670           0 :   hash_free (reg_by_index);
     671             : 
     672           0 :   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* */
     683      285289 : VLIB_CLI_COMMAND (show_init_function, static) = {
     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             :  */

Generated by: LCOV version 1.14