/* * Copyright (c) 2015 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * init.c: mechanism for functions to be called at init/exit. * * Copyright (c) 2008 Eliot Dresselhaus * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include /** * @file * @brief Init function ordering and execution implementation * Topological sort for all classes of init functions, and * a relatively simple API routine to invoke them. */ /*? %%clicmd:group_label Init functions %% ?*/ static int comma_split (u8 * s, u8 ** a, u8 ** b) { *a = s; while (*s && *s != ',') s++; if (*s == ',') *s = 0; else return 1; *b = (u8 *) (s + 1); return 0; } /** * @brief Topological sorter for init function chains. * @param head [in/out] address of the listhead to be sorted * @returns 0 on success, otherwise a clib_error_t *. */ clib_error_t *vlib_sort_init_exit_functions (_vlib_init_function_list_elt_t ** head) { uword *index_by_name; uword *reg_by_index; u8 **init_f_names = 0; u8 *init_f_name; char **these_constraints; char *this_constraint_c; u8 **constraints = 0; u8 *constraint_tuple; u8 *this_constraint; char *prev_name; u8 **orig, **closure; uword *p; int i, j, k; u8 *a_name, *b_name; int a_index, b_index; int n_init_fns; u32 *result = 0; _vlib_init_function_list_elt_t *this_reg = 0; hash_pair_t *hp; u8 **keys_to_delete = 0; /* * two hash tables: name to index in init_f_names, and * init function registration pointer by index */ index_by_name = hash_create_string (0, sizeof (uword)); reg_by_index = hash_create (0, sizeof (uword)); this_reg = *head; /* pass 1, collect init fcn names, construct a before b pairs */ while (this_reg) { init_f_name = format (0, "%s%c", this_reg->name, 0); hash_set (reg_by_index, vec_len (init_f_names), (uword) this_reg); hash_set_mem (index_by_name, init_f_name, vec_len (init_f_names)); vec_add1 (init_f_names, init_f_name); these_constraints = this_reg->runs_before; while (these_constraints && these_constraints[0]) { this_constraint_c = these_constraints[0]; constraint_tuple = format (0, "%s,%s%c", init_f_name, this_constraint_c, 0); vec_add1 (constraints, constraint_tuple); these_constraints++; } these_constraints = this_reg->runs_after; while (these_constraints && these_constraints[0]) { this_constraint_c = these_constraints[0]; constraint_tuple = format (0, "%s,%s%c", this_constraint_c, init_f_name, 0); vec_add1 (constraints, constraint_tuple); these_constraints++; } this_reg = this_reg->next_init_function; } /* * pass 2: collect "a then b then c then d" constraints. * all init fcns must be known at this point. */ this_reg = *head; while (this_reg) { these_constraints = this_reg->init_order; prev_name = 0; /* Across the list of constraints */ while (these_constraints && these_constraints[0]) { this_constraint_c = these_constraints[0]; p = hash_get_mem (index_by_name, this_constraint_c); if (p == 0) { clib_warning ("order constraint fcn '%s' not found", this_constraint_c); these_constraints++; continue; } if (prev_name == 0) { prev_name = this_constraint_c; these_constraints++; continue; } constraint_tuple = format (0, "%s,%s%c", prev_name, this_constraint_c, 0); vec_add1 (constraints, constraint_tuple); prev_name = this_constraint_c; these_constraints++; } this_reg = this_reg->next_init_function; } n_init_fns = vec_len (init_f_names); orig = clib_ptclosure_alloc (n_init_fns); for (i = 0; i < vec_len (constraints); i++) { this_constraint = constraints[i]; if (comma_split (this_constraint, &a_name, &b_name)) return clib_error_return (0, "comma_split failed!"); p = hash_get_mem (index_by_name, a_name); /* * Note: the next two errors mean that something is * b0rked. As in: if you code "A runs before on B," and you type * B incorrectly, you lose. Nonexistent init functions are tolerated. */ if (p == 0) { clib_warning ("init function '%s' not found (before '%s')", a_name, b_name); continue; } a_index = p[0]; p = hash_get_mem (index_by_name, b_name); if (p == 0) { clib_warning ("init function '%s' not found (after '%s')", b_name, a_name); continue; } b_index = p[0]; /* add a before b to the original set of constraints */ orig[a_index][b_index] = 1; vec_free (this_constraint); } /* Compute the positive transitive closure of the original constraints */ closure = clib_ptclosure (orig); /* Compute a partial order across feature nodes, if one exists. */ again: for (i = 0; i < n_init_fns; i++) { for (j = 0; j < n_init_fns; j++) { if (closure[i][j]) goto item_constrained; } /* Item i can b
/*
 * tracedump.h - skeleton vpp engine plug-in header file
 *
 * Copyright (c) <current-year> <your-organization>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __included_tracedump_h__
#define __included_tracedump_h__

#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/ethernet/ethernet.h>

#include <vppinfra/hash.h>
#include <vppinfra/error.h>

typedef struct
{
  /* API message ID base */
  u16 msg_id_base;

  /*
   * cached reply data
   * traces [client_id][thread_id][trace]
   */
  vlib_trace_header_t ****traces;

  /* convenience */
  vlib_main_t *vlib_main;
  vnet_main_t *vnet_main;
  ethernet_main_t *ethernet_main;
} tracedump_main_t;

extern tracedump_main_t tracedump_main;

#endif /* __included_tracedump_h__ */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
ASSERT (p != 0); this_reg = (_vlib_init_function_list_elt_t *) p[0]; vlib_cli_output (vm, "[%d] %s", i, this_reg->name); { char **runs_before, **runs_after, **init_order; runs_before = this_reg->runs_before; while (runs_before && runs_before[0]) { _vlib_init_function_list_elt_t *successor; uword successor_index; p = hash_get_mem (index_by_name, runs_before[0]); if (p == 0) { clib_warning ("couldn't find successor '%s'", runs_before[0]); runs_before++; continue; } successor_index = p[0]; p = hash_get (reg_by_index, p[0]); ASSERT (p != 0); successor = (_vlib_init_function_list_elt_t *) p[0]; vlib_cli_output (vm, " before '%s' [%lld]", successor->name, successor_index); runs_before++; } runs_after = this_reg->runs_after; while (runs_after && runs_after[0]) { _vlib_init_function_list_elt_t *predecessor; uword predecessor_index; p = hash_get_mem (index_by_name, runs_after[0]); if (p == 0) { clib_warning ("couldn't find predecessor '%s'", runs_after[0]); runs_after++; continue; } predecessor_index = p[0]; p = hash_get (reg_by_index, p[0]); ASSERT (p != 0); predecessor = (_vlib_init_function_list_elt_t *) p[0]; vlib_cli_output (vm, " after '%s' [%lld]", predecessor->name, predecessor_index); runs_after++; } init_order = this_reg->init_order; while (init_order && init_order[0]) { _vlib_init_function_list_elt_t *inorder; uword inorder_index; p = hash_get_mem (index_by_name, init_order[0]); if (p == 0) { clib_warning ("couldn't find order element'%s'", init_order[0]); init_order++; continue; } inorder_index = p[0]; p = hash_get (reg_by_index, p[0]); ASSERT (p != 0); inorder = (_vlib_init_function_list_elt_t *) p[0]; vlib_cli_output (vm, " in order '%s' [%lld]", inorder->name, inorder_index); init_order++; } } } /* *INDENT-OFF* */ hash_foreach_pair (hp, index_by_name, ({ vec_add1 (keys_to_delete, (u8 *)hp->key); })); /* *INDENT-ON* */ hash_free (index_by_name); for (i = 0; i < vec_len (keys_to_delete); i++) vec_free (keys_to_delete[i]); vec_free (keys_to_delete); hash_free (reg_by_index); return 0; } /*? * Show init function order * * @cliexpar * @cliexstart{show init-function [init | enter | exit] [verbose [nn]]} * @cliexend ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_init_function, static) = { .path = "show init-function", .short_help = "show init-function [init | enter | exit][verbose [nn]]", .function = show_init_function_command_fn, }; /* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */