blob: f0632380f34004bb6c0460206ace0278a6580ef8 [file] [log] [blame]
Dave Barachf9faf242018-10-04 17:12:26 -04001.. _add_plugin:
2
3Adding a plugin
4===============
5
6.. toctree::
7
Dave Barach331016a2020-09-14 10:21:11 -04008Strategic Choices
9_________________
10
11Plugins may implement lightly-used, experimental, or test
12functionality. In such cases, please disable the plugin by default:
13
14.. code-block:: console
15
16 /* *INDENT-OFF* */
17 VLIB_PLUGIN_REGISTER () =
18 {
19 .version = VPP_BUILD_VER,
20 .description = "Plugin Disabled by Default...",
21 .default_disabled = 1,
22 };
23 /* *INDENT-ON* */
24
25Please do not create processes, or other dynamic data structures
26unless the plugin is configured by API or debug CLI.
27
28Specifically, please don't initialize bihash tables from
29VLIB_INIT_FUNCTIONS, *especially* if the bihash template involved
30doesn't #define BIHASH_LAZY_INSTANTIATE 1.
31
32.. code-block:: console
33
34 static clib_error_t * sample_init (vlib_main_t * vm)
35 {
36 <snip>
37 /* DONT DO THIS! */
38 BV(clib_bihash_init (h, ...))
39 <snip>
40 }
41 VLIB_INIT_FUNCTION (sample_init);
42
43Instead, please add a feature_init function:
44
45.. code-block:: console
46
47 static void
48 feature_init (my_main_t * mm)
49 {
50 if (mm->feature_initialized == 0)
51 {
52 BV(clib_bihash_init)(mm->hash_table, ...)
53 /* Create Other Things, e.g a periodic process */
54 mm->feature_initialized = 1;
55 }
56 }
57
58And call it from debug CLI and API message handlers any time the feature
59is enabled.
60
61How to create a new plugin
62__________________________
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +020063
Dave Barachf9faf242018-10-04 17:12:26 -040064This section shows how a VPP developer can create a new plugin, and
jdenisco390036e2018-10-31 14:24:31 -040065add it to VPP. We assume that we are starting from the VPP <top-of-workspace>.
Dave Barachf9faf242018-10-04 17:12:26 -040066
67As an example, we will use the **make-plugin.sh** tool found in
jdenisco390036e2018-10-31 14:24:31 -040068**./extras/emacs**. make-plugin.sh is a simple wrapper for a comprehensive
Dave Barachf9faf242018-10-04 17:12:26 -040069plugin generator constructed from a set of emacs-lisp skeletons.
70
jdenisco390036e2018-10-31 14:24:31 -040071Change directory to **./src/plugins**, and run the plugin generator:
Dave Barachf9faf242018-10-04 17:12:26 -040072
73.. code-block:: console
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +020074
jdenisco390036e2018-10-31 14:24:31 -040075 $ cd ./src/plugins
Dave Barachf9faf242018-10-04 17:12:26 -040076 $ ../../extras/emacs/make-plugin.sh
77 <snip>
78 Loading /scratch/vpp-docs/extras/emacs/tunnel-c-skel.el (source)...
79 Loading /scratch/vpp-docs/extras/emacs/tunnel-decap-skel.el (source)...
80 Loading /scratch/vpp-docs/extras/emacs/tunnel-encap-skel.el (source)...
81 Loading /scratch/vpp-docs/extras/emacs/tunnel-h-skel.el (source)...
82 Loading /scratch/vpp-docs/extras/emacs/elog-4-int-skel.el (source)...
83 Loading /scratch/vpp-docs/extras/emacs/elog-4-int-track-skel.el (source)...
84 Loading /scratch/vpp-docs/extras/emacs/elog-enum-skel.el (source)...
85 Loading /scratch/vpp-docs/extras/emacs/elog-one-datum-skel.el (source)...
86 Plugin name: myplugin
87 Dispatch type [dual or qs]: dual
88 (Shell command succeeded with no output)
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +020089
Dave Barachf9faf242018-10-04 17:12:26 -040090 OK...
91
92The plugin generator script asks two questions: the name of the
93plugin, and which of two dispatch types to use. Since the plugin name
94finds its way into quite a number of places - filenames, typedef
95names, graph arc names - it pays to think for a moment.
96
97The dispatch type refers to the coding pattern used to construct
98**node.c**, the *pro forma* data-plane node. The **dual** option
99constructs a dual-single loop pair with speculative enqueueing. This
100is the traditional coding pattern for load-store intensive graph
101nodes.
102
103The **qs** option generates a quad-single loop pair which uses
104vlib_get_buffers(...) and vlib_buffer_enqueue_to_next(...). These
105operators make excellent use of available SIMD vector unit
106operations. It's very simple to change a quad-single loop-pair to a
107dual-single loop pair if you decide to do so later.
108
109Generated Files
110---------------
111
112Here are the generated files. We'll go through them in a moment.
113
114.. code-block:: console
115
jdenisco390036e2018-10-31 14:24:31 -0400116 $ cd ./myplugin
Dave Barachf9faf242018-10-04 17:12:26 -0400117 $ ls
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200118 CMakeLists.txt myplugin.api myplugin.c myplugin.h
119 myplugin_periodic.c myplugin_test.c node.c setup.pg
Dave Barachf9faf242018-10-04 17:12:26 -0400120
121Due to recent build system improvements, you **don't** need to touch
122any other files to integrate your new plugin into the vpp build. Simply
123rebuild your workspace from scratch, and the new plugin will appear.
124
125Rebuild your workspace
126----------------------
127
128This is the straightforward way to reconfigure and rebuild your workspace:
129
130.. code-block:: console
131
132 $ cd <top-of-workspace>
133 $ make rebuild [or rebuild-release]
134
135Thanks to ccache, this operation doesn't take an annoying amount of time.
136
137Sanity check: run vpp
138---------------------
139
140As a quick sanity check, run vpp and make sure that
141"myplugin_plugin.so" and "myplugin_test_plugin.so" are loaded:
142
143.. code-block:: console
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200144
Dave Barachf9faf242018-10-04 17:12:26 -0400145 $ cd <top-of-workspace>
146 $ make run
147 <snip>
148 load_one_plugin:189: Loaded plugin: myplugin_plugin.so (myplugin description goes here)
149 <snip>
150 load_one_vat_plugin:67: Loaded plugin: myplugin_test_plugin.so
151 <snip>
152 DBGvpp#
153
154If this simple test fails, please seek assistance.
155
156Generated Files in Detail
157_________________________
158
159This section discusses the generated files in some detail. It's fine to
160skim this section, and return later for more detail.
161
162CMakeLists.txt
163--------------
164
165This is the build system recipe for building your plugin. Please fix
166the copyright notice:
167
168.. code-block:: console
169
170 # Copyright (c) <current-year> <your-organization>
171
172The rest of the build recipe is pretty simple:
173
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200174.. code-block:: CMake
Dave Barachf9faf242018-10-04 17:12:26 -0400175
176 add_vpp_plugin (myplugin
177 SOURCES
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200178 myplugin.c
179 node.c
Dave Barachf9faf242018-10-04 17:12:26 -0400180 myplugin_periodic.c
181 myplugin.h
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200182
Dave Barachf9faf242018-10-04 17:12:26 -0400183 MULTIARCH_SOURCES
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200184 node.c
185
Dave Barachf9faf242018-10-04 17:12:26 -0400186 API_FILES
187 myplugin.api
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200188
Dave Barachf9faf242018-10-04 17:12:26 -0400189 API_TEST_SOURCES
190 myplugin_test.c
191 )
192
193As you can see, the build recipe consists of several lists of
194files. **SOURCES** is a list of C source files. **API_FILES** is a
195list of the plugin's binary API definition files [one such file is
196usually plenty], and so forth.
197
198**MULTIARCH_SOURCES** lists data plane graph node dispatch function
199source files considered to be performance-critical. Specific functions
200in these files are compiled multiple times, so that they can leverage
201CPU-specific features. More on this in a moment.
202
203If you add source files, simply add them to the indicated list(s).
204
205myplugin.h
206----------
207
208This is the primary #include file for the new plugin. Among other
209things, it defines the plugin's *main_t* data structure. This is the
210right place to add problem-specific data structures. Please **resist
211the temptation** to create a set of static or [worse yet] global
212variables in your plugin. Refereeing name-collisions between plugins
213is not anyone's idea of a good time.
214
215myplugin.c
216----------
217
218For want of a better way to describe it, myplugin.c is the vpp plugin
219equivalent of "main.c". Its job is to hook the plugin into the vpp
220binary API message dispatcher, and to add its messages to vpp's global
221"message-name_crc" hash table. See "myplugin_init (...")"
222
223Vpp itself uses dlsym(...) to track down the vlib_plugin_registration_t
224generated by the VLIB_PLUGIN_REGISTER macro:
225
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200226.. code-block:: C
Dave Barachf9faf242018-10-04 17:12:26 -0400227
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200228 VLIB_PLUGIN_REGISTER () =
Dave Barachf9faf242018-10-04 17:12:26 -0400229 {
230 .version = VPP_BUILD_VER,
231 .description = "myplugin plugin description goes here",
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200232 };
Dave Barachf9faf242018-10-04 17:12:26 -0400233
234Vpp only loads .so files from the plugin directory which contain an
235instance of this data structure.
236
237You can enable or disable specific vpp plugins from the command
238line. By default, plugins are loaded. To change that behavior, set
jdenisco390036e2018-10-31 14:24:31 -0400239default_disabled in the macro VLIB_PLUGIN_REGISTER:
Dave Barachf9faf242018-10-04 17:12:26 -0400240
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200241.. code-block:: C
Dave Barachf9faf242018-10-04 17:12:26 -0400242
jdenisco390036e2018-10-31 14:24:31 -0400243 VLIB_PLUGIN_REGISTER () =
244 {
245 .version = VPP_BUILD_VER,
246 .default_disabled = 1
247 .description = "myplugin plugin description goes here",
248 };
Dave Barachf9faf242018-10-04 17:12:26 -0400249
250The boilerplate generator places the graph node dispatch function
251onto the "device-input" feature arc. This may or may not be useful.
252
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200253.. code-block:: C
Dave Barachf9faf242018-10-04 17:12:26 -0400254
255 VNET_FEATURE_INIT (myplugin, static) =
256 {
257 .arc_name = "device-input",
258 .node_name = "myplugin",
259 .runs_before = VNET_FEATURES ("ethernet-input"),
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200260 };
Dave Barachf9faf242018-10-04 17:12:26 -0400261
262As given by the plugin generator, myplugin.c contains the binary API
263message handler for a generic "please enable my feature on such and
264such an interface" binary API message. As you'll see, setting up the
265vpp message API tables is simple. Big fat warning: the scheme is
266intolerant of minor mistakes. Example: forgetting to add
267mainp->msg_id_base can lead to very confusing failures.
268
269If you stick to modifying the generated boilerplate with care -
270instead of trying to build code from first principles - you'll save
271yourself a bunch of time and aggravation
272
273myplugin_test.c
274---------------
275
276This file contains binary API message **generation** code, which is
277compiled into a separate .so file. The "vpp_api_test" program loads
278these plugins, yielding immediate access to your plugin APIs for
279external client binary API testing.
280
281vpp itself loads test plugins, and makes the code available via the
282"binary-api" debug CLI. This is a favorite way to unit-test binary
283APIs prior to integration testing.
284
285node.c
286------
287
288This is the generated graph node dispatch function. You'll need to
289rewrite it to solve the problem at hand. It will save considerable
290time and aggravation to retain the **structure** of the node dispatch
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200291function.
Dave Barachf9faf242018-10-04 17:12:26 -0400292
293Even for an expert, it's a waste of time to reinvent the *loop
294structure*, enqueue patterns, and so forth. Simply tear out and
295replace the specimen 1x, 2x, 4x packet processing code with code
296relevant to the problem you're trying to solve.
297
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200298myplugin.api
299------------
300
301This contains the API message definition. Here we only have defined
302a single one named ``myplugin_enable_disable`` and an implicit
303``myplugin_enable_disable_reply`` containing only a return value due
304to the ``autoreply`` keyword.
305
306The syntax reference for ``.api`` files can be found at VPP API Language
307
308Addressing the binary API with this message will run the handler defined
309in ``myplugin.c`` as ``vl_api_myplugin_enable_disable_t_handler``.
310It will receive a message pointer ``*mp`` which is the struct defined
311in ``myplugin.api`` and should return another message pointer ``*rmp``,
312of the reply type. That's what ``REPLY_MACRO`` does.
313
314To be noted, all API messages are in net-endian and vpp is host-endian,
315so you will need to use :
316
317* ``u32 value = ntohl(mp->value);``
318* ``rmp->value = htonl(value);``
319
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +0100320You can now use this API with :ref:`GoLang bindings <govpp>`
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200321
322myplugin_periodic.c
323-------------------
324
325This defines a VPP process, a routine that will run indefinitely and
326be woken up intermittently, here to process plugin events.
327
328To be noted, vlib_processes aren't thread-safe, and data structures
329should be locked when shared between workers.
330
Dave Barachf9faf242018-10-04 17:12:26 -0400331Plugin "Friends with Benefits"
332------------------------------
333
334In vpp VLIB_INIT_FUNCTION functions, It's reasonably common to see a
335specific init function invoke other init functions:
336
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200337.. code-block:: C
Dave Barachf9faf242018-10-04 17:12:26 -0400338
339 if ((error = vlib_call_init_function (vm, some_other_init_function))
340 return error;
341
342In the case where one plugin needs to call a init function in another
343plugin, use the vlib_call_plugin_init_function macro:
344
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200345.. code-block:: C
Dave Barachf9faf242018-10-04 17:12:26 -0400346
347 if ((error = vlib_call_plugin_init_function (vm, "otherpluginname", some_init_function))
348 return error;
349
350This allows sequencing between plugin init functions.
351
352If you wish to obtain a pointer to a symbol in another plugin, use the
353vlib_plugin_get_symbol(...) API:
354
Nathan Skrzypczakc4781a32020-09-04 18:31:23 +0200355.. code-block:: C
Dave Barachf9faf242018-10-04 17:12:26 -0400356
357 void *p = vlib_get_plugin_symbol ("plugin_name", "symbol");
358
jdenisco390036e2018-10-31 14:24:31 -0400359More Examples
360-------------
361
362For more information you can read many example plugins in the directory "./src/plugins".