1 # Binary API support {#api_doc}
3 VPP provides a binary API scheme to allow a wide variety of client codes to
4 program data-plane tables. As of this writing, there are hundreds of binary
7 Messages are defined in `*.api` files. Today, there are about 50 api files,
8 with more arriving as folks add programmable features. The API file compiler
9 sources reside in @ref src/tools/vppapigen.
11 From @ref src/vnet/interface.api, here's a typical request/response message
15 autoreply define sw_interface_set_flags
20 /* 1 = up, 0 = down */
25 To a first approximation, the API compiler renders this definition into
26 `build-root/.../vpp/include/vnet/interface.api.h` as follows:
29 /****** Message ID / handler enum ******/
31 vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS, vl_api_sw_interface_set_flags_t_handler)
32 vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS_REPLY, vl_api_sw_interface_set_flags_reply_t_handler)
35 /****** Message names ******/
37 vl_msg_name(vl_api_sw_interface_set_flags_t, 1)
38 vl_msg_name(vl_api_sw_interface_set_flags_reply_t, 1)
41 /****** Message name, crc list ******/
42 #ifdef vl_msg_name_crc_list
43 #define foreach_vl_msg_name_crc_interface \
44 _(VL_API_SW_INTERFACE_SET_FLAGS, sw_interface_set_flags, f890584a) \
45 _(VL_API_SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply, dfbf3afa) \
48 /****** Typedefs *****/
50 typedef VL_API_PACKED(struct _vl_api_sw_interface_set_flags {
56 }) vl_api_sw_interface_set_flags_t;
58 typedef VL_API_PACKED(struct _vl_api_sw_interface_set_flags_reply {
62 }) vl_api_sw_interface_set_flags_reply_t;
65 #endif /* vl_typedefs */
68 To change the admin state of an interface, a binary api client sends a
69 @ref vl_api_sw_interface_set_flags_t to VPP, which will respond with a
70 @ref vl_api_sw_interface_set_flags_reply_t message.
72 Multiple layers of software, transport types, and shared libraries
73 implement a variety of features:
75 * API message allocation, tracing, pretty-printing, and replay.
76 * Message transport via global shared memory, pairwise/private shared
78 * Barrier synchronization of worker threads across thread-unsafe
81 Correctly-coded message handlers know nothing about the transport used to
82 deliver messages to/from VPP. It's reasonably straighforward to use multiple
83 API message transport types simultaneously.
85 For historical reasons, binary api messages are (putatively) sent in network
86 byte order. As of this writing, we're seriously considering whether that
92 Since binary API messages are always processed in order, we allocate messages
93 using a ring allocator whenever possible. This scheme is extremely fast when
94 compared with a traditional memory allocator, and doesn't cause heap
96 @ref src/vlibmemory/memory_shared.c @ref vl_msg_api_alloc_internal().
98 Regardless of transport, binary api messages always follow a @ref msgbuf_t
102 typedef struct msgbuf_
104 unix_shared_memory_queue_t *q;
106 u32 gc_mark_timestamp;
111 This structure makes it easy to trace messages without having to
112 decode them - simply save data_len bytes - and allows
113 @ref vl_msg_api_free() to rapidly dispose of message buffers:
117 vl_msg_api_free (void *a)
120 api_main_t *am = &api_main;
122 rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
125 * Here's the beauty of the scheme. Only one proc/thread has
126 * control of a given message buffer. To free a buffer, we just
127 * clear the queue field, and leave. No locks, no hits, no errors...
132 rv->gc_mark_timestamp = 0;
139 ## Message Tracing and Replay
141 It's extremely important that VPP can capture and replay sizeable binary API
142 traces. System-level issues involving hundreds of thousands of API
143 transactions can be re-run in a second or less. Partial replay allows one to
144 binary-search for the point where the wheels fall off. One can add scaffolding
145 to the data plane, to trigger when complex conditions obtain.
147 With binary API trace, print, and replay, system-level bug reports of the form
148 "after 300,000 API transactions, the VPP data-plane stopped forwarding
149 traffic, FIX IT!" can be solved offline.
151 More often than not, one discovers that a control-plane client
152 misprograms the data plane after a long time or under complex
153 circumstances. Without direct evidence, "it's a data-plane problem!"
155 See @ref src/vlibmemory/memory_vlib.c @ref vl_msg_api_process_file(),
156 and @ref src/vlibapi/api_shared.c. See also the debug CLI command "api trace"
158 ## Client connection details
160 Establishing a binary API connection to VPP from a C-language client
165 connect_to_vpe (char *client_name, int client_message_queue_length)
167 vat_main_t *vam = &vat_main;
168 api_main_t *am = &api_main;
170 if (vl_client_connect_to_vlib ("/vpe-api", client_name,
171 client_message_queue_length) < 0)
174 /* Memorize vpp's binary API message input queue address */
175 vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
176 /* And our client index */
177 vam->my_client_index = am->my_client_index;
182 32 is a typical value for client_message_queue_length. VPP cannot
183 block when it needs to send an API message to a binary API client, and
184 the VPP-side binary API message handlers are very fast. When sending
185 asynchronous messages, make sure to scrape the binary API rx ring with
188 ### binary API message RX pthread
190 Calling @ref vl_client_connect_to_vlib spins up a binary API message RX
195 rx_thread_fn (void *arg)
197 unix_shared_memory_queue_t *q;
198 memory_client_main_t *mm = &memory_client_main;
199 api_main_t *am = &api_main;
201 q = am->vl_input_queue;
203 /* So we can make the rx thread terminate cleanly */
204 if (setjmp (mm->rx_thread_jmpbuf) == 0)
206 mm->rx_thread_jmpbuf_valid = 1;
209 vl_msg_api_queue_handler (q);
216 To handle the binary API message queue yourself, use
217 @ref vl_client_connect_to_vlib_no_rx_pthread.
219 In turn, vl_msg_api_queue_handler(...) uses mutex/condvar signalling
220 to wake up, process VPP -> client traffic, then sleep. VPP supplies a
221 condvar broadcast when the VPP -> client API message queue transitions
222 from empty to nonempty.
224 VPP checks its own binary API input queue at a very high rate. VPP
225 invokes message handlers in "process" context [aka cooperative
226 multitasking thread context] at a variable rate, depending on
227 data-plane packet processing requirements.
229 ## Client disconnection details
231 To disconnect from VPP, call @ref vl_client_disconnect_from_vlib.
232 Please arrange to call this function if the client application
233 terminates abnormally. VPP makes every effort to hold a decent funeral
234 for dead clients, but VPP can't guarantee to free leaked memory in the
235 shared binary API segment.
237 ## Sending binary API messages to VPP
239 The point of the exercise is to send binary API messages to VPP, and
240 to receive replies from VPP. Many VPP binary APIs comprise a client
241 request message, and a simple status reply. For example, to
242 set the admin status of an interface, one codes:
245 vl_api_sw_interface_set_flags_t *mp;
247 mp = vl_msg_api_alloc (sizeof (*mp));
248 memset (mp, 0, sizeof (*mp));
249 mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SW_INTERFACE_SET_FLAGS);
250 mp->client_index = api_main.my_client_index;
251 mp->sw_if_index = clib_host_to_net_u32 (<interface-sw-if-index>);
252 vl_msg_api_send (api_main.shmem_hdr->vl_input_queue, (u8 *)mp);
257 * Use @ref vl_msg_api_alloc to allocate message buffers
259 * Allocated message buffers are not initialized, and must be presumed
262 * Don't forget to set the _vl_msg_id field!
264 * As of this writing, binary API message IDs and data are sent in
267 * The client-library global data structure @ref api_main keeps track
268 of sufficient pointers and handles used to communicate with VPP
270 ## Receiving binary API messages from VPP
272 Unless you've made other arrangements (see @ref
273 vl_client_connect_to_vlib_no_rx_pthread), *messages are received on a
274 separate rx pthread*. Synchronization with the client application main
275 thread is the responsibility of the application!
277 Set up message handlers about as follows:
280 #define vl_typedefs /* define message structures */
281 #include <vpp/api/vpe_all_api_h.h>
284 /* declare message handlers for each api */
286 #define vl_endianfun /* define message structures */
287 #include <vpp/api/vpe_all_api_h.h>
290 /* instantiate all the print functions we know about */
291 #define vl_print(handle, ...)
293 #include <vpp/api/vpe_all_api_h.h>
296 /* Define a list of all message that the client handles */
297 #define foreach_vpe_api_reply_msg \
298 _(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply)
300 static clib_error_t *
301 my_api_hookup (vlib_main_t * vm)
303 api_main_t *am = &api_main;
306 vl_msg_api_set_handlers(VL_API_##N, #n, \
307 vl_api_##n##_t_handler, \
309 vl_api_##n##_t_endian, \
310 vl_api_##n##_t_print, \
311 sizeof(vl_api_##n##_t), 1);
319 The key API used to establish message handlers is @ref
320 vl_msg_api_set_handlers , which sets values in multiple parallel
321 vectors in the @ref api_main_t structure. As of this writing: not all
322 vector element values can be set through the API. You'll see sporadic
323 API message registrations followed by minor adjustments of this form:
327 * Thread-safe API messages
329 am->is_mp_safe[VL_API_IP_ADD_DEL_ROUTE] = 1;
330 am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1;