11 This section shows how a VPP developer can create a new plugin, and
12 add it to VPP. We assume that we are starting from the VPP <top-of-workspace>.
14 As an example, we will use the **make-plugin.sh** tool found in
15 **./extras/emacs**. make-plugin.sh is a simple wrapper for a comprehensive
16 plugin generator constructed from a set of emacs-lisp skeletons.
18 Create your new plugin
19 ----------------------
21 Change directory to **./src/plugins**, and run the plugin generator:
23 .. code-block:: console
26 $ ../../extras/emacs/make-plugin.sh
28 Loading /scratch/vpp-docs/extras/emacs/tunnel-c-skel.el (source)...
29 Loading /scratch/vpp-docs/extras/emacs/tunnel-decap-skel.el (source)...
30 Loading /scratch/vpp-docs/extras/emacs/tunnel-encap-skel.el (source)...
31 Loading /scratch/vpp-docs/extras/emacs/tunnel-h-skel.el (source)...
32 Loading /scratch/vpp-docs/extras/emacs/elog-4-int-skel.el (source)...
33 Loading /scratch/vpp-docs/extras/emacs/elog-4-int-track-skel.el (source)...
34 Loading /scratch/vpp-docs/extras/emacs/elog-enum-skel.el (source)...
35 Loading /scratch/vpp-docs/extras/emacs/elog-one-datum-skel.el (source)...
37 Dispatch type [dual or qs]: dual
38 (Shell command succeeded with no output)
42 The plugin generator script asks two questions: the name of the
43 plugin, and which of two dispatch types to use. Since the plugin name
44 finds its way into quite a number of places - filenames, typedef
45 names, graph arc names - it pays to think for a moment.
47 The dispatch type refers to the coding pattern used to construct
48 **node.c**, the *pro forma* data-plane node. The **dual** option
49 constructs a dual-single loop pair with speculative enqueueing. This
50 is the traditional coding pattern for load-store intensive graph
53 The **qs** option generates a quad-single loop pair which uses
54 vlib_get_buffers(...) and vlib_buffer_enqueue_to_next(...). These
55 operators make excellent use of available SIMD vector unit
56 operations. It's very simple to change a quad-single loop-pair to a
57 dual-single loop pair if you decide to do so later.
62 Here are the generated files. We'll go through them in a moment.
64 .. code-block:: console
68 CMakeLists.txt myplugin.c myplugin_periodic.c setup.pg
69 myplugin_all_api_h.h myplugin.h myplugin_test.c
70 myplugin.api myplugin_msg_enum.h node.c
72 Due to recent build system improvements, you **don't** need to touch
73 any other files to integrate your new plugin into the vpp build. Simply
74 rebuild your workspace from scratch, and the new plugin will appear.
76 Rebuild your workspace
77 ----------------------
79 This is the straightforward way to reconfigure and rebuild your workspace:
81 .. code-block:: console
83 $ cd <top-of-workspace>
84 $ make rebuild [or rebuild-release]
86 Thanks to ccache, this operation doesn't take an annoying amount of time.
91 As a quick sanity check, run vpp and make sure that
92 "myplugin_plugin.so" and "myplugin_test_plugin.so" are loaded:
94 .. code-block:: console
96 $ cd <top-of-workspace>
99 load_one_plugin:189: Loaded plugin: myplugin_plugin.so (myplugin description goes here)
101 load_one_vat_plugin:67: Loaded plugin: myplugin_test_plugin.so
105 If this simple test fails, please seek assistance.
107 Generated Files in Detail
108 _________________________
110 This section discusses the generated files in some detail. It's fine to
111 skim this section, and return later for more detail.
116 This is the build system recipe for building your plugin. Please fix
117 the copyright notice:
119 .. code-block:: console
121 # Copyright (c) <current-year> <your-organization>
123 The rest of the build recipe is pretty simple:
125 .. code-block:: console
127 add_vpp_plugin (myplugin
148 As you can see, the build recipe consists of several lists of
149 files. **SOURCES** is a list of C source files. **API_FILES** is a
150 list of the plugin's binary API definition files [one such file is
151 usually plenty], and so forth.
153 **MULTIARCH_SOURCES** lists data plane graph node dispatch function
154 source files considered to be performance-critical. Specific functions
155 in these files are compiled multiple times, so that they can leverage
156 CPU-specific features. More on this in a moment.
158 If you add source files, simply add them to the indicated list(s).
163 This is the primary #include file for the new plugin. Among other
164 things, it defines the plugin's *main_t* data structure. This is the
165 right place to add problem-specific data structures. Please **resist
166 the temptation** to create a set of static or [worse yet] global
167 variables in your plugin. Refereeing name-collisions between plugins
168 is not anyone's idea of a good time.
173 For want of a better way to describe it, myplugin.c is the vpp plugin
174 equivalent of "main.c". Its job is to hook the plugin into the vpp
175 binary API message dispatcher, and to add its messages to vpp's global
176 "message-name_crc" hash table. See "myplugin_init (...")"
178 Vpp itself uses dlsym(...) to track down the vlib_plugin_registration_t
179 generated by the VLIB_PLUGIN_REGISTER macro:
181 .. code-block:: console
183 VLIB_PLUGIN_REGISTER () =
185 .version = VPP_BUILD_VER,
186 .description = "myplugin plugin description goes here",
189 Vpp only loads .so files from the plugin directory which contain an
190 instance of this data structure.
192 You can enable or disable specific vpp plugins from the command
193 line. By default, plugins are loaded. To change that behavior, set
194 default_disabled in the macro VLIB_PLUGIN_REGISTER:
196 .. code-block:: console
198 VLIB_PLUGIN_REGISTER () =
200 .version = VPP_BUILD_VER,
201 .default_disabled = 1
202 .description = "myplugin plugin description goes here",
205 The boilerplate generator places the graph node dispatch function
206 onto the "device-input" feature arc. This may or may not be useful.
208 .. code-block:: console
210 VNET_FEATURE_INIT (myplugin, static) =
212 .arc_name = "device-input",
213 .node_name = "myplugin",
214 .runs_before = VNET_FEATURES ("ethernet-input"),
217 As given by the plugin generator, myplugin.c contains the binary API
218 message handler for a generic "please enable my feature on such and
219 such an interface" binary API message. As you'll see, setting up the
220 vpp message API tables is simple. Big fat warning: the scheme is
221 intolerant of minor mistakes. Example: forgetting to add
222 mainp->msg_id_base can lead to very confusing failures.
224 If you stick to modifying the generated boilerplate with care -
225 instead of trying to build code from first principles - you'll save
226 yourself a bunch of time and aggravation
231 This file contains binary API message **generation** code, which is
232 compiled into a separate .so file. The "vpp_api_test" program loads
233 these plugins, yielding immediate access to your plugin APIs for
234 external client binary API testing.
236 vpp itself loads test plugins, and makes the code available via the
237 "binary-api" debug CLI. This is a favorite way to unit-test binary
238 APIs prior to integration testing.
243 This is the generated graph node dispatch function. You'll need to
244 rewrite it to solve the problem at hand. It will save considerable
245 time and aggravation to retain the **structure** of the node dispatch
248 Even for an expert, it's a waste of time to reinvent the *loop
249 structure*, enqueue patterns, and so forth. Simply tear out and
250 replace the specimen 1x, 2x, 4x packet processing code with code
251 relevant to the problem you're trying to solve.
253 Plugin "Friends with Benefits"
254 ------------------------------
256 In vpp VLIB_INIT_FUNCTION functions, It's reasonably common to see a
257 specific init function invoke other init functions:
259 .. code-block:: console
261 if ((error = vlib_call_init_function (vm, some_other_init_function))
264 In the case where one plugin needs to call a init function in another
265 plugin, use the vlib_call_plugin_init_function macro:
267 .. code-block:: console
269 if ((error = vlib_call_plugin_init_function (vm, "otherpluginname", some_init_function))
272 This allows sequencing between plugin init functions.
274 If you wish to obtain a pointer to a symbol in another plugin, use the
275 vlib_plugin_get_symbol(...) API:
277 .. code-block:: console
279 void *p = vlib_get_plugin_symbol ("plugin_name", "symbol");
284 For more information you can read many example plugins in the directory "./src/plugins".