VLIB (Vector Processing Library) ================================ The files associated with vlib are located in the ./src/{vlib, vlibapi, vlibmemory} folders. These libraries provide vector processing support including graph-node scheduling, reliable multicast support, ultra-lightweight cooperative multi-tasking threads, a CLI, plug in .DLL support, physical memory and Linux epoll support. Parts of this library embody US Patent 7,961,636. Init function discovery ----------------------- vlib applications register for various [initialization] events by placing structures and \__attribute__((constructor)) functions into the image. At appropriate times, the vlib framework walks constructor-generated singly-linked structure lists, performs a topological sort based on specified constraints, and calls the indicated functions. Vlib applications create graph nodes, add CLI functions, start cooperative multi-tasking threads, etc. etc. using this mechanism. vlib applications invariably include a number of VLIB_INIT_FUNCTION (my_init_function) macros. Each init / configure / etc. function has the return type clib_error_t \*. Make sure that the function returns 0 if all is well, otherwise the framework will announce an error and exit. vlib applications must link against vppinfra, and often link against other libraries such as VNET. In the latter case, it may be necessary to explicitly reference symbol(s) otherwise large portions of the library may be AWOL at runtime. Init function construction and constraint specification ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It’s easy to add an init function: .. code:: c static clib_error_t *my_init_function (vlib_main_t *vm) { /* ... initialize things ... */ return 0; // or return clib_error_return (0, "BROKEN!"); } VLIB_INIT_FUNCTION(my_init_function); As given, my_init_function will be executed “at some point,” but with no ordering guarantees. Specifying ordering constraints is easy: .. code:: c VLIB_INIT_FUNCTION(my_init_function) = { .runs_before = VLIB_INITS("we_run_before_function_1", "we_run_before_function_2"), .runs_after = VLIB_INITS("we_run_after_function_1", "we_run_after_function_2), }; It’s also easy to specify bulk ordering constraints of the form “a then b then c then d”: .. code:: c VLIB_INIT_FUNCTION(my_init_function) = { .init_order = VLIB_INITS("a", "b", "c", "d"), }; It’s OK to specify all three sorts of ordering constraints for a single init function, although it’s hard to imagine why it would be necessary. Node Graph Initialization ------------------------- vlib packet-processing applications invariably define a set of graph nodes to process packets. One constructs a vlib_node_registration_t, most often via the VLIB_REGISTER_NODE macro. At runtime, the framework processes the set of such registrations into a directed graph. It is easy enough to add nodes to the graph at runtime. The framework does not support removing nodes. vlib provides several types of vector-processing graph nodes, primarily to control framework dispatch behaviors. The type member of the vlib_node_registration_t functions as follows: - VLIB_NODE_TYPE_PRE_INPUT - run before all other node types - VLIB_NODE_TYPE_INPUT - run as often as possible, after pre_input nodes - VLIB_NODE_TYPE_INTERNAL - only when explicitly made runnable by adding pending frames for processing - VLIB_NODE_TYPE_PROCESS - only when explicitly made runnable. “Process” nodes are actually cooperative multi-tasking threads. They **must** explicitly suspend after a reasonably short period of time. For a precise understanding of the graph node dispatcher, please read ./src/vlib/main.c:vlib_main_loop. Graph node dispatcher --------------------- Vlib_main_loop() dispatches graph nodes. The basic vector processing algorithm is diabolically simple, but may not be obvious from even a long stare at the code. Here’s how it works: some input node, or set of input nodes, produce a vector of work to process. The graph node dispatcher pushes the work vector through the directed graph, subdividing it as needed, until the original work vector has been completely processed. At that point, the process recurs. This scheme yields a stable equilibrium in frame size, by construction. Here’s why: as the frame size increases, the per-frame-element processing time decreases. There are several related forces at work; the simplest to describe is the effect of vector processing on the CPU L1 I-cache. The first frame element [packet] processed by a given node warms up the node dispatch function in the L1 I-cache. All subsequent frame elements profit. As we increase the number of frame elements, the cost per element goes down. Under light load, it is a crazy waste of CPU cycles to run the graph node dispatcher flat-out. So, the graph node dispatcher arranges to wait for work by sitting in a timed epoll wait if the prevailing frame size is lo
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Copyright (c) 2016 Comcast Cable Communications Management, LLC.
*
* 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.
*/
/* Doxygen directory documentation */
/**
@dir
@brief VLIB application library.
*/