aboutsummaryrefslogtreecommitdiffstats
path: root/src/vlibapi
diff options
context:
space:
mode:
authorNathan Skrzypczak <nathan.skrzypczak@gmail.com>2021-10-08 14:01:27 +0200
committerDave Wallace <dwallacelf@gmail.com>2021-10-13 15:32:33 +0000
commitd4a70647e6b8de2cb81cbea3c53d08c299b65cc5 (patch)
tree4c9e695232b110ea95326ecb86f706d34c065289 /src/vlibapi
parenta2c9509a4ab22380937a2b613fcc518da22f5166 (diff)
docs: convert vpp doc md->rst
Type: improvement Change-Id: If453321785b04f9c16e8cea36fb1910efaeb2c59 Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
Diffstat (limited to 'src/vlibapi')
-rw-r--r--src/vlibapi/api_doc.md352
-rw-r--r--src/vlibapi/api_doc.rst342
2 files changed, 342 insertions, 352 deletions
diff --git a/src/vlibapi/api_doc.md b/src/vlibapi/api_doc.md
deleted file mode 100644
index 2e7ae09a722..00000000000
--- a/src/vlibapi/api_doc.md
+++ /dev/null
@@ -1,352 +0,0 @@
-# Binary API support {#api_doc}
-
-VPP provides a binary API scheme to allow a wide variety of client codes to
-program data-plane tables. As of this writing, there are hundreds of binary
-APIs.
-
-Messages are defined in `*.api` files. Today, there are about 50 api files,
-with more arriving as folks add programmable features. The API file compiler
-sources reside in @ref src/tools/vppapigen.
-
-From @ref src/vnet/interface.api, here's a typical request/response message
-definition:
-
-```{.c}
- autoreply define sw_interface_set_flags
- {
- u32 client_index;
- u32 context;
- u32 sw_if_index;
- /* 1 = up, 0 = down */
- u8 admin_up_down;
- };
-```
-
-To a first approximation, the API compiler renders this definition into
-`build-root/.../vpp/include/vnet/interface.api.h` as follows:
-
-```{.c}
- /****** Message ID / handler enum ******/
- #ifdef vl_msg_id
- vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS, vl_api_sw_interface_set_flags_t_handler)
- vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS_REPLY, vl_api_sw_interface_set_flags_reply_t_handler)
- #endif
-
- /****** Message names ******/
- #ifdef vl_msg_name
- vl_msg_name(vl_api_sw_interface_set_flags_t, 1)
- vl_msg_name(vl_api_sw_interface_set_flags_reply_t, 1)
- #endif
-
- /****** Message name, crc list ******/
- #ifdef vl_msg_name_crc_list
- #define foreach_vl_msg_name_crc_interface \
- _(VL_API_SW_INTERFACE_SET_FLAGS, sw_interface_set_flags, f890584a) \
- _(VL_API_SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply, dfbf3afa) \
- #endif
-
- /****** Typedefs *****/
- #ifdef vl_typedefs
- typedef VL_API_PACKED(struct _vl_api_sw_interface_set_flags {
- u16 _vl_msg_id;
- u32 client_index;
- u32 context;
- u32 sw_if_index;
- u8 admin_up_down;
- }) vl_api_sw_interface_set_flags_t;
-
- typedef VL_API_PACKED(struct _vl_api_sw_interface_set_flags_reply {
- u16 _vl_msg_id;
- u32 context;
- i32 retval;
- }) vl_api_sw_interface_set_flags_reply_t;
-
- ...
- #endif /* vl_typedefs */
-```
-
-To change the admin state of an interface, a binary api client sends a
-@ref vl_api_sw_interface_set_flags_t to VPP, which will respond with a
-@ref vl_api_sw_interface_set_flags_reply_t message.
-
-Multiple layers of software, transport types, and shared libraries
-implement a variety of features:
-
-* API message allocation, tracing, pretty-printing, and replay.
-* Message transport via global shared memory, pairwise/private shared
- memory, and sockets.
-* Barrier synchronization of worker threads across thread-unsafe
- message handlers.
-
-Correctly-coded message handlers know nothing about the transport used to
-deliver messages to/from VPP. It's reasonably straighforward to use multiple
-API message transport types simultaneously.
-
-For historical reasons, binary api messages are (putatively) sent in network
-byte order. As of this writing, we're seriously considering whether that
-choice makes sense.
-
-
-## Message Allocation
-
-Since binary API messages are always processed in order, we allocate messages
-using a ring allocator whenever possible. This scheme is extremely fast when
-compared with a traditional memory allocator, and doesn't cause heap
-fragmentation. See
-@ref src/vlibmemory/memory_shared.c @ref vl_msg_api_alloc_internal().
-
-Regardless of transport, binary api messages always follow a @ref msgbuf_t
-header:
-
-```{.c}
- typedef struct msgbuf_
- {
- unix_shared_memory_queue_t *q;
- u32 data_len;
- u32 gc_mark_timestamp;
- u8 data[0];
- } msgbuf_t;
-```
-
-This structure makes it easy to trace messages without having to
-decode them - simply save data_len bytes - and allows
-@ref vl_msg_api_free() to rapidly dispose of message buffers:
-
-```{.c}
- void
- vl_msg_api_free (void *a)
- {
- msgbuf_t *rv;
- api_main_t *am = &api_main;
-
- rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
-
- /*
- * Here's the beauty of the scheme. Only one proc/thread has
- * control of a given message buffer. To free a buffer, we just
- * clear the queue field, and leave. No locks, no hits, no errors...
- */
- if (rv->q)
- {
- rv->q = 0;
- rv->gc_mark_timestamp = 0;
- return;
- }
- <snip>
- }
-```
-
-## Message Tracing and Replay
-
-It's extremely important that VPP can capture and replay sizeable binary API
-traces. System-level issues involving hundreds of thousands of API
-transactions can be re-run in a second or less. Partial replay allows one to
-binary-search for the point where the wheels fall off. One can add scaffolding
-to the data plane, to trigger when complex conditions obtain.
-
-With binary API trace, print, and replay, system-level bug reports of the form
-"after 300,000 API transactions, the VPP data-plane stopped forwarding
-traffic, FIX IT!" can be solved offline.
-
-More often than not, one discovers that a control-plane client
-misprograms the data plane after a long time or under complex
-circumstances. Without direct evidence, "it's a data-plane problem!"
-
-See @ref src/vlibmemory/memory_vlib.c @ref vl_msg_api_process_file(),
-and @ref src/vlibapi/api_shared.c. See also the debug CLI command "api trace"
-
-## Client connection details
-
-Establishing a binary API connection to VPP from a C-language client
-is easy:
-
-```{.c}
- int
- connect_to_vpe (char *client_name, int client_message_queue_length)
- {
- vat_main_t *vam = &vat_main;
- api_main_t *am = &api_main;
-
- if (vl_client_connect_to_vlib ("/vpe-api", client_name,
- client_message_queue_length) < 0)
- return -1;
-
- /* Memorize vpp's binary API message input queue address */
- vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
- /* And our client index */
- vam->my_client_index = am->my_client_index;
- return 0;
- }
-```
-
-32 is a typical value for client_message_queue_length. VPP cannot
-block when it needs to send an API message to a binary API client, and
-the VPP-side binary API message handlers are very fast. When sending
-asynchronous messages, make sure to scrape the binary API rx ring with
-some enthusiasm.
-
-### binary API message RX pthread
-
-Calling @ref vl_client_connect_to_vlib spins up a binary API message RX
-pthread:
-
-```{.c}
- static void *
- rx_thread_fn (void *arg)
- {
- unix_shared_memory_queue_t *q;
- memory_client_main_t *mm = &memory_client_main;
- api_main_t *am = &api_main;
-
- q = am->vl_input_queue;
-
- /* So we can make the rx thread terminate cleanly */
- if (setjmp (mm->rx_thread_jmpbuf) == 0)
- {
- mm->rx_thread_jmpbuf_valid = 1;
- while (1)
- {
- vl_msg_api_queue_handler (q);
- }
- }
- pthread_exit (0);
- }
-```
-
-To handle the binary API message queue yourself, use
-@ref vl_client_connect_to_vlib_no_rx_pthread.
-
-In turn, vl_msg_api_queue_handler(...) uses mutex/condvar signalling
-to wake up, process VPP -> client traffic, then sleep. VPP supplies a
-condvar broadcast when the VPP -> client API message queue transitions
-from empty to nonempty.
-
-VPP checks its own binary API input queue at a very high rate. VPP
-invokes message handlers in "process" context [aka cooperative
-multitasking thread context] at a variable rate, depending on
-data-plane packet processing requirements.
-
-## Client disconnection details
-
-To disconnect from VPP, call @ref vl_client_disconnect_from_vlib.
-Please arrange to call this function if the client application
-terminates abnormally. VPP makes every effort to hold a decent funeral
-for dead clients, but VPP can't guarantee to free leaked memory in the
-shared binary API segment.
-
-## Sending binary API messages to VPP
-
-The point of the exercise is to send binary API messages to VPP, and
-to receive replies from VPP. Many VPP binary APIs comprise a client
-request message, and a simple status reply. For example, to
-set the admin status of an interface, one codes:
-
-```{.c}
- vl_api_sw_interface_set_flags_t *mp;
-
- mp = vl_msg_api_alloc (sizeof (*mp));
- memset (mp, 0, sizeof (*mp));
- mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SW_INTERFACE_SET_FLAGS);
- mp->client_index = api_main.my_client_index;
- mp->sw_if_index = clib_host_to_net_u32 (<interface-sw-if-index>);
- vl_msg_api_send (api_main.shmem_hdr->vl_input_queue, (u8 *)mp);
-```
-
-Key points:
-
-* Use @ref vl_msg_api_alloc to allocate message buffers
-
-* Allocated message buffers are not initialized, and must be presumed
- to contain trash.
-
-* Don't forget to set the _vl_msg_id field!
-
-* As of this writing, binary API message IDs and data are sent in
- network byte order
-
-* The client-library global data structure @ref api_main keeps track
- of sufficient pointers and handles used to communicate with VPP
-
-## Receiving binary API messages from VPP
-
-Unless you've made other arrangements (see @ref
-vl_client_connect_to_vlib_no_rx_pthread), *messages are received on a
-separate rx pthread*. Synchronization with the client application main
-thread is the responsibility of the application!
-
-Set up message handlers about as follows:
-
-```{.c}
- #define vl_typedefs /* define message structures */
- #include <vpp/api/vpe_all_api_h.h>
- #undef vl_typedefs
-
- /* declare message handlers for each api */
-
- #define vl_endianfun /* define message structures */
- #include <vpp/api/vpe_all_api_h.h>
- #undef vl_endianfun
-
- /* instantiate all the print functions we know about */
- #define vl_print(handle, ...)
- #define vl_printfun
- #include <vpp/api/vpe_all_api_h.h>
- #undef vl_printfun
-
- /* Define a list of all message that the client handles */
- #define foreach_vpe_api_reply_msg \
- _(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply)
-
- static clib_error_t *
- my_api_hookup (vlib_main_t * vm)
- {
- api_main_t *am = &api_main;
-
- #define _(N,n) \
- vl_msg_api_set_handlers(VL_API_##N, #n, \
- vl_api_##n##_t_handler, \
- vl_noop_handler, \
- vl_api_##n##_t_endian, \
- vl_api_##n##_t_print, \
- sizeof(vl_api_##n##_t), 1);
- foreach_vpe_api_msg;
- #undef _
-
- return 0;
- }
-```
-
-The key API used to establish message handlers is @ref
-vl_msg_api_set_handlers , which sets values in multiple parallel
-vectors in the @ref api_main_t structure. As of this writing: not all
-vector element values can be set through the API. You'll see sporadic
-API message registrations followed by minor adjustments of this form:
-
-```{.c}
- /*
- * Thread-safe API messages
- */
- am->is_mp_safe[VL_API_IP_ADD_DEL_ROUTE] = 1;
- am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1;
-```
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/vlibapi/api_doc.rst b/src/vlibapi/api_doc.rst
new file mode 100644
index 00000000000..7d2b80a2e06
--- /dev/null
+++ b/src/vlibapi/api_doc.rst
@@ -0,0 +1,342 @@
+.. _api_doc:
+
+Writing API handlers
+====================
+
+VPP provides a binary API scheme to allow a wide variety of client codes
+to program data-plane tables. As of this writing, there are hundreds of
+binary APIs.
+
+Messages are defined in ``*.api`` files. Today, there are about 50 api
+files, with more arriving as folks add programmable features. The API
+file compiler sources reside in @ref src/tools/vppapigen.
+
+From @ref src/vnet/interface.api, here’s a typical request/response
+message definition:
+
+.. code:: c
+
+ autoreply define sw_interface_set_flags
+ {
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ /* 1 = up, 0 = down */
+ u8 admin_up_down;
+ };
+
+To a first approximation, the API compiler renders this definition into
+``build-root/.../vpp/include/vnet/interface.api.h`` as follows:
+
+.. code:: c
+
+ /****** Message ID / handler enum ******/
+ #ifdef vl_msg_id
+ vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS, vl_api_sw_interface_set_flags_t_handler)
+ vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS_REPLY, vl_api_sw_interface_set_flags_reply_t_handler)
+ #endif
+
+ /****** Message names ******/
+ #ifdef vl_msg_name
+ vl_msg_name(vl_api_sw_interface_set_flags_t, 1)
+ vl_msg_name(vl_api_sw_interface_set_flags_reply_t, 1)
+ #endif
+
+ /****** Message name, crc list ******/
+ #ifdef vl_msg_name_crc_list
+ #define foreach_vl_msg_name_crc_interface \
+ _(VL_API_SW_INTERFACE_SET_FLAGS, sw_interface_set_flags, f890584a) \
+ _(VL_API_SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply, dfbf3afa) \
+ #endif
+
+ /****** Typedefs *****/
+ #ifdef vl_typedefs
+ typedef VL_API_PACKED(struct _vl_api_sw_interface_set_flags {
+ u16 _vl_msg_id;
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u8 admin_up_down;
+ }) vl_api_sw_interface_set_flags_t;
+
+ typedef VL_API_PACKED(struct _vl_api_sw_interface_set_flags_reply {
+ u16 _vl_msg_id;
+ u32 context;
+ i32 retval;
+ }) vl_api_sw_interface_set_flags_reply_t;
+
+ ...
+ #endif /* vl_typedefs */
+
+To change the admin state of an interface, a binary api client sends a
+@ref vl_api_sw_interface_set_flags_t to VPP, which will respond with a
+@ref vl_api_sw_interface_set_flags_reply_t message.
+
+Multiple layers of software, transport types, and shared libraries
+implement a variety of features:
+
+- API message allocation, tracing, pretty-printing, and replay.
+- Message transport via global shared memory, pairwise/private shared
+ memory, and sockets.
+- Barrier synchronization of worker threads across thread-unsafe
+ message handlers.
+
+Correctly-coded message handlers know nothing about the transport used
+to deliver messages to/from VPP. It’s reasonably straightforward to use
+multiple API message transport types simultaneously.
+
+For historical reasons, binary api messages are (putatively) sent in
+network byte order. As of this writing, we’re seriously considering
+whether that choice makes sense.
+
+Message Allocation
+------------------
+
+Since binary API messages are always processed in order, we allocate
+messages using a ring allocator whenever possible. This scheme is
+extremely fast when compared with a traditional memory allocator, and
+doesn’t cause heap fragmentation. See @ref
+src/vlibmemory/memory_shared.c @ref vl_msg_api_alloc_internal().
+
+Regardless of transport, binary api messages always follow a @ref
+msgbuf_t header:
+
+.. code:: c
+
+ typedef struct msgbuf_
+ {
+ unix_shared_memory_queue_t *q;
+ u32 data_len;
+ u32 gc_mark_timestamp;
+ u8 data[0];
+ } msgbuf_t;
+
+This structure makes it easy to trace messages without having to decode
+them - simply save data_len bytes - and allows @ref vl_msg_api_free() to
+rapidly dispose of message buffers:
+
+.. code:: c
+
+ void
+ vl_msg_api_free (void *a)
+ {
+ msgbuf_t *rv;
+ api_main_t *am = &api_main;
+
+ rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
+
+ /*
+ * Here's the beauty of the scheme. Only one proc/thread has
+ * control of a given message buffer. To free a buffer, we just
+ * clear the queue field, and leave. No locks, no hits, no errors...
+ */
+ if (rv->q)
+ {
+ rv->q = 0;
+ rv->gc_mark_timestamp = 0;
+ return;
+ }
+ <snip>
+ }
+
+Message Tracing and Replay
+--------------------------
+
+It’s extremely important that VPP can capture and replay sizeable binary
+API traces. System-level issues involving hundreds of thousands of API
+transactions can be re-run in a second or less. Partial replay allows
+one to binary-search for the point where the wheels fall off. One can
+add scaffolding to the data plane, to trigger when complex conditions
+obtain.
+
+With binary API trace, print, and replay, system-level bug reports of
+the form “after 300,000 API transactions, the VPP data-plane stopped
+forwarding traffic, FIX IT!” can be solved offline.
+
+More often than not, one discovers that a control-plane client
+misprograms the data plane after a long time or under complex
+circumstances. Without direct evidence, “it’s a data-plane problem!”
+
+See @ref src/vlibmemory/memory_vlib.c @ref vl_msg_api_process_file(),
+and @ref src/vlibapi/api_shared.c. See also the debug CLI command “api
+trace”
+
+Client connection details
+-------------------------
+
+Establishing a binary API connection to VPP from a C-language client is
+easy:
+
+.. code:: c
+
+ int
+ connect_to_vpe (char *client_name, int client_message_queue_length)
+ {
+ vat_main_t *vam = &vat_main;
+ api_main_t *am = &api_main;
+
+ if (vl_client_connect_to_vlib ("/vpe-api", client_name,
+ client_message_queue_length) < 0)
+ return -1;
+
+ /* Memorize vpp's binary API message input queue address */
+ vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
+ /* And our client index */
+ vam->my_client_index = am->my_client_index;
+ return 0;
+ }
+
+32 is a typical value for client_message_queue_length. VPP cannot block
+when it needs to send an API message to a binary API client, and the
+VPP-side binary API message handlers are very fast. When sending
+asynchronous messages, make sure to scrape the binary API rx ring with
+some enthusiasm.
+
+binary API message RX pthread
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Calling @ref vl_client_connect_to_vlib spins up a binary API message RX
+pthread:
+
+.. code:: c
+
+ static void *
+ rx_thread_fn (void *arg)
+ {
+ unix_shared_memory_queue_t *q;
+ memory_client_main_t *mm = &memory_client_main;
+ api_main_t *am = &api_main;
+
+ q = am->vl_input_queue;
+
+ /* So we can make the rx thread terminate cleanly */
+ if (setjmp (mm->rx_thread_jmpbuf) == 0)
+ {
+ mm->rx_thread_jmpbuf_valid = 1;
+ while (1)
+ {
+ vl_msg_api_queue_handler (q);
+ }
+ }
+ pthread_exit (0);
+ }
+
+To handle the binary API message queue yourself, use @ref
+vl_client_connect_to_vlib_no_rx_pthread.
+
+In turn, vl_msg_api_queue_handler(…) uses mutex/condvar signalling to
+wake up, process VPP -> client traffic, then sleep. VPP supplies a
+condvar broadcast when the VPP -> client API message queue transitions
+from empty to nonempty.
+
+VPP checks its own binary API input queue at a very high rate. VPP
+invokes message handlers in “process” context [aka cooperative
+multitasking thread context] at a variable rate, depending on data-plane
+packet processing requirements.
+
+Client disconnection details
+----------------------------
+
+To disconnect from VPP, call @ref vl_client_disconnect_from_vlib. Please
+arrange to call this function if the client application terminates
+abnormally. VPP makes every effort to hold a decent funeral for dead
+clients, but VPP can’t guarantee to free leaked memory in the shared
+binary API segment.
+
+Sending binary API messages to VPP
+----------------------------------
+
+The point of the exercise is to send binary API messages to VPP, and to
+receive replies from VPP. Many VPP binary APIs comprise a client request
+message, and a simple status reply. For example, to set the admin status
+of an interface, one codes:
+
+.. code:: c
+
+ vl_api_sw_interface_set_flags_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SW_INTERFACE_SET_FLAGS);
+ mp->client_index = api_main.my_client_index;
+ mp->sw_if_index = clib_host_to_net_u32 (<interface-sw-if-index>);
+ vl_msg_api_send (api_main.shmem_hdr->vl_input_queue, (u8 *)mp);
+
+Key points:
+
+- Use @ref vl_msg_api_alloc to allocate message buffers
+
+- Allocated message buffers are not initialized, and must be presumed
+ to contain trash.
+
+- Don’t forget to set the \_vl_msg_id field!
+
+- As of this writing, binary API message IDs and data are sent in
+ network byte order
+
+- The client-library global data structure @ref api_main keeps track of
+ sufficient pointers and handles used to communicate with VPP
+
+Receiving binary API messages from VPP
+--------------------------------------
+
+Unless you’ve made other arrangements (see @ref
+vl_client_connect_to_vlib_no_rx_pthread), *messages are received on a
+separate rx pthread*. Synchronization with the client application main
+thread is the responsibility of the application!
+
+Set up message handlers about as follows:
+
+.. code:: c
+
+ #define vl_typedefs /* define message structures */
+ #include <vpp/api/vpe_all_api_h.h>
+ #undef vl_typedefs
+
+ /* declare message handlers for each api */
+
+ #define vl_endianfun /* define message structures */
+ #include <vpp/api/vpe_all_api_h.h>
+ #undef vl_endianfun
+
+ /* instantiate all the print functions we know about */
+ #define vl_print(handle, ...)
+ #define vl_printfun
+ #include <vpp/api/vpe_all_api_h.h>
+ #undef vl_printfun
+
+ /* Define a list of all message that the client handles */
+ #define foreach_vpe_api_reply_msg \
+ _(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply)
+
+ static clib_error_t *
+ my_api_hookup (vlib_main_t * vm)
+ {
+ api_main_t *am = &api_main;
+
+ #define _(N,n) \
+ vl_msg_api_set_handlers(VL_API_##N, #n, \
+ vl_api_##n##_t_handler, \
+ vl_noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_vpe_api_msg;
+ #undef _
+
+ return 0;
+ }
+
+The key API used to establish message handlers is @ref
+vl_msg_api_set_handlers , which sets values in multiple parallel vectors
+in the @ref api_main_t structure. As of this writing: not all vector
+element values can be set through the API. You’ll see sporadic API
+message registrations followed by minor adjustments of this form:
+
+.. code:: c
+
+ /*
+ * Thread-safe API messages
+ */
+ am->is_mp_safe[VL_API_IP_ADD_DEL_ROUTE] = 1;
+ am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1;