docs: Improve new plugin doc & add govpp API doc 88/28688/4
authorNathan Skrzypczak <nathan.skrzypczak@gmail.com>
Fri, 4 Sep 2020 16:31:23 +0000 (18:31 +0200)
committerAndrew Yourtchenko <ayourtch@gmail.com>
Wed, 9 Sep 2020 20:44:08 +0000 (20:44 +0000)
Type: docs

Change-Id: I5f20ac0232c5cdc3cf64015185b0d0fc5c4a3100
Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
docs/gettingstarted/developers/VPPAPI.md [new symlink]
docs/gettingstarted/developers/add_plugin.rst
docs/gettingstarted/developers/add_plugin_goapi.rst [new file with mode: 0644]
docs/gettingstarted/developers/index.rst

diff --git a/docs/gettingstarted/developers/VPPAPI.md b/docs/gettingstarted/developers/VPPAPI.md
new file mode 120000 (symlink)
index 0000000..a5404c1
--- /dev/null
@@ -0,0 +1 @@
+../../../src/tools/vppapigen/VPPAPI.md
\ No newline at end of file
index 16952e8..19b935b 100644 (file)
@@ -7,7 +7,7 @@ Adding a plugin
 
 Overview
 ________
 
 Overview
 ________
+
 This section shows how a VPP developer can create a new plugin, and
 add it to VPP. We assume that we are starting from the VPP <top-of-workspace>.
 
 This section shows how a VPP developer can create a new plugin, and
 add it to VPP. We assume that we are starting from the VPP <top-of-workspace>.
 
@@ -21,7 +21,7 @@ Create your new plugin
 Change directory to **./src/plugins**, and run the plugin generator:
 
 .. code-block:: console
 Change directory to **./src/plugins**, and run the plugin generator:
 
 .. code-block:: console
-    
+
     $ cd ./src/plugins
     $ ../../extras/emacs/make-plugin.sh
     <snip>
     $ cd ./src/plugins
     $ ../../extras/emacs/make-plugin.sh
     <snip>
@@ -36,7 +36,7 @@ Change directory to **./src/plugins**, and run the plugin generator:
     Plugin name: myplugin
     Dispatch type [dual or qs]: dual
     (Shell command succeeded with no output)
     Plugin name: myplugin
     Dispatch type [dual or qs]: dual
     (Shell command succeeded with no output)
-    
+
     OK...
 
 The plugin generator script asks two questions: the name of the
     OK...
 
 The plugin generator script asks two questions: the name of the
@@ -65,9 +65,8 @@ Here are the generated files. We'll go through them in a moment.
 
     $ cd ./myplugin
     $ ls
 
     $ cd ./myplugin
     $ ls
-    CMakeLists.txt        myplugin.c           myplugin_periodic.c  setup.pg
-    myplugin_all_api_h.h  myplugin.h           myplugin_test.c
-    myplugin.api          myplugin_msg_enum.h  node.c
+    CMakeLists.txt  myplugin.api  myplugin.c  myplugin.h
+    myplugin_periodic.c  myplugin_test.c  node.c  setup.pg
 
 Due to recent build system improvements, you **don't** need to touch
 any other files to integrate your new plugin into the vpp build. Simply
 
 Due to recent build system improvements, you **don't** need to touch
 any other files to integrate your new plugin into the vpp build. Simply
@@ -92,7 +91,7 @@ As a quick sanity check, run vpp and make sure that
 "myplugin_plugin.so" and "myplugin_test_plugin.so" are loaded:
 
 .. code-block:: console
 "myplugin_plugin.so" and "myplugin_test_plugin.so" are loaded:
 
 .. code-block:: console
-    
+
     $ cd <top-of-workspace>
     $ make run
     <snip>
     $ cd <top-of-workspace>
     $ make run
     <snip>
@@ -122,25 +121,21 @@ the copyright notice:
 
 The rest of the build recipe is pretty simple:
 
 
 The rest of the build recipe is pretty simple:
 
-.. code-block:: console
+.. code-block:: CMake
 
     add_vpp_plugin (myplugin
     SOURCES
 
     add_vpp_plugin (myplugin
     SOURCES
-    myplugin.c 
-    node.c 
+    myplugin.c
+    node.c
     myplugin_periodic.c
     myplugin.h
     myplugin_periodic.c
     myplugin.h
-    
+
     MULTIARCH_SOURCES
     MULTIARCH_SOURCES
-    node.c 
-    
+    node.c
+
     API_FILES
     myplugin.api
     API_FILES
     myplugin.api
-    
-    INSTALL_HEADERS
-    myplugin_all_api_h.h
-    myplugin_msg_enum.h
-    
+
     API_TEST_SOURCES
     myplugin_test.c
     )
     API_TEST_SOURCES
     myplugin_test.c
     )
@@ -178,13 +173,13 @@ binary API message dispatcher, and to add its messages to vpp's global
 Vpp itself uses dlsym(...) to track down the vlib_plugin_registration_t
 generated by the VLIB_PLUGIN_REGISTER macro:
 
 Vpp itself uses dlsym(...) to track down the vlib_plugin_registration_t
 generated by the VLIB_PLUGIN_REGISTER macro:
 
-.. code-block:: console
+.. code-block:: C
 
 
-    VLIB_PLUGIN_REGISTER () = 
+    VLIB_PLUGIN_REGISTER () =
       {
         .version = VPP_BUILD_VER,
         .description = "myplugin plugin description goes here",
       {
         .version = VPP_BUILD_VER,
         .description = "myplugin plugin description goes here",
-      };  
+      };
 
 Vpp only loads .so files from the plugin directory which contain an
 instance of this data structure.
 
 Vpp only loads .so files from the plugin directory which contain an
 instance of this data structure.
@@ -193,7 +188,7 @@ You can enable or disable specific vpp plugins from the command
 line. By default, plugins are loaded. To change that behavior, set
 default_disabled in the macro VLIB_PLUGIN_REGISTER:
 
 line. By default, plugins are loaded. To change that behavior, set
 default_disabled in the macro VLIB_PLUGIN_REGISTER:
 
-.. code-block:: console
+.. code-block:: C
 
     VLIB_PLUGIN_REGISTER () =
       {
 
     VLIB_PLUGIN_REGISTER () =
       {
@@ -205,14 +200,14 @@ default_disabled in the macro VLIB_PLUGIN_REGISTER:
 The boilerplate generator places the graph node dispatch function
 onto the "device-input" feature arc. This may or may not be useful.
 
 The boilerplate generator places the graph node dispatch function
 onto the "device-input" feature arc. This may or may not be useful.
 
-.. code-block:: console
+.. code-block:: C
 
     VNET_FEATURE_INIT (myplugin, static) =
     {
       .arc_name = "device-input",
       .node_name = "myplugin",
       .runs_before = VNET_FEATURES ("ethernet-input"),
 
     VNET_FEATURE_INIT (myplugin, static) =
     {
       .arc_name = "device-input",
       .node_name = "myplugin",
       .runs_before = VNET_FEATURES ("ethernet-input"),
-    };  
+    };
 
 As given by the plugin generator, myplugin.c contains the binary API
 message handler for a generic "please enable my feature on such and
 
 As given by the plugin generator, myplugin.c contains the binary API
 message handler for a generic "please enable my feature on such and
@@ -243,20 +238,53 @@ node.c
 This is the generated graph node dispatch function. You'll need to
 rewrite it to solve the problem at hand. It will save considerable
 time and aggravation to retain the **structure** of the node dispatch
 This is the generated graph node dispatch function. You'll need to
 rewrite it to solve the problem at hand. It will save considerable
 time and aggravation to retain the **structure** of the node dispatch
-function. 
+function.
 
 Even for an expert, it's a waste of time to reinvent the *loop
 structure*, enqueue patterns, and so forth. Simply tear out and
 replace the specimen 1x, 2x, 4x packet processing code with code
 relevant to the problem you're trying to solve.
 
 
 Even for an expert, it's a waste of time to reinvent the *loop
 structure*, enqueue patterns, and so forth. Simply tear out and
 replace the specimen 1x, 2x, 4x packet processing code with code
 relevant to the problem you're trying to solve.
 
+myplugin.api
+------------
+
+This contains the API message definition. Here we only have defined
+a single one named ``myplugin_enable_disable`` and an implicit
+``myplugin_enable_disable_reply`` containing only a return value due
+to the ``autoreply`` keyword.
+
+The syntax reference for ``.api`` files can be found at VPP API Language
+
+Addressing the binary API with this message will run the handler defined
+in ``myplugin.c`` as ``vl_api_myplugin_enable_disable_t_handler``.
+It will receive a message pointer ``*mp`` which is the struct defined
+in ``myplugin.api`` and should return another message pointer ``*rmp``,
+of the reply type. That's what ``REPLY_MACRO`` does.
+
+To be noted, all API messages are in net-endian and vpp is host-endian,
+so you will need to use :
+
+* ``u32 value = ntohl(mp->value);``
+* ``rmp->value = htonl(value);``
+
+You can now use this API with :ref:`GoLang bindings <add_plugin_goapi>`
+
+myplugin_periodic.c
+-------------------
+
+This defines a VPP process, a routine that will run indefinitely and
+be woken up intermittently, here to process plugin events.
+
+To be noted, vlib_processes aren't thread-safe, and data structures
+should be locked when shared between workers.
+
 Plugin "Friends with Benefits"
 ------------------------------
 
 In vpp VLIB_INIT_FUNCTION functions, It's reasonably common to see a
 specific init function invoke other init functions:
 
 Plugin "Friends with Benefits"
 ------------------------------
 
 In vpp VLIB_INIT_FUNCTION functions, It's reasonably common to see a
 specific init function invoke other init functions:
 
-.. code-block:: console
+.. code-block:: C
 
     if ((error = vlib_call_init_function (vm, some_other_init_function))
        return error;
 
     if ((error = vlib_call_init_function (vm, some_other_init_function))
        return error;
@@ -264,7 +292,7 @@ specific init function invoke other init functions:
 In the case where one plugin needs to call a init function in another
 plugin, use the vlib_call_plugin_init_function macro:
 
 In the case where one plugin needs to call a init function in another
 plugin, use the vlib_call_plugin_init_function macro:
 
-.. code-block:: console
+.. code-block:: C
 
     if ((error = vlib_call_plugin_init_function (vm, "otherpluginname", some_init_function))
        return error;
 
     if ((error = vlib_call_plugin_init_function (vm, "otherpluginname", some_init_function))
        return error;
@@ -274,7 +302,7 @@ This allows sequencing between plugin init functions.
 If you wish to obtain a pointer to a symbol in another plugin, use the
 vlib_plugin_get_symbol(...) API:
 
 If you wish to obtain a pointer to a symbol in another plugin, use the
 vlib_plugin_get_symbol(...) API:
 
-.. code-block:: console
+.. code-block:: C
 
     void *p = vlib_get_plugin_symbol ("plugin_name", "symbol");
 
 
     void *p = vlib_get_plugin_symbol ("plugin_name", "symbol");
 
diff --git a/docs/gettingstarted/developers/add_plugin_goapi.rst b/docs/gettingstarted/developers/add_plugin_goapi.rst
new file mode 100644 (file)
index 0000000..dce35b8
--- /dev/null
@@ -0,0 +1,83 @@
+.. _add_plugin_goapi:
+
+Add a plugin's GO API
+=====================
+
+In order to use your plugin's API with GO, you will need to use
+a GO client and GO definitions of the API messages that you defined
+in ``myplugin.api`` (go bindings).
+
+These two things can be found in `govpp <https://github.com/FDio/govpp>`_
+
+* The API client lives in `./core`
+* The api-generator lives in `./binapigen`
+* A sample of its output (the go bindings) for VPP's latest version lives in `./binapi`
+
+To generate the go bindings for your plugin. Assuming :
+* ``/home/vpp`` is a VPP clone with your plugin in it.
+* ``/home/controlplane`` is a go controlplane repo
+
+.. code-block:: console
+
+    $ mkdir /home/controlplane/vpp-go-bindings
+    $ git clone https://github.com/FDio/govpp>
+    $ cd govpp
+    $ BINAPI_DIR=/home/controlplane/vpp-go-bindings VPP_DIR=/home/vpp make gen-binapi-from-code
+
+This will generate the go-bindings in ``/home/controlplane/vpp-go-bindings``
+For example ``vpp-go-bindings/myplugin/myplugin.ba.go`` will contain :
+
+.. code-block:: go
+
+    // MypluginEnableDisable defines message 'myplugin_enable_disable'.
+    type MypluginEnableDisable struct {
+           EnableDisable bool                           `binapi:"bool,name=enable_disable" json:"enable_disable,omitempty"`
+           SwIfIndex     interface_types.InterfaceIndex `binapi:"interface_index,name=sw_if_index" json:"sw_if_index,omitempty"`
+    }
+
+
+You can then use the generated go bindings in your go code like this :
+
+.. code-block:: go
+
+    package main
+
+    import (
+           "fmt"
+           "git.fd.io/govpp.git"
+           "git.fd.io/govpp.git/binapi/interfaces"
+           "git.fd.io/govpp.git/binapi/vpe"
+
+           "myplugin.io/controlplane/vpp-go-bindings/myplugin/myplugin"
+    )
+
+    func main() {
+           // Connect to VPP
+           conn, _ := govpp.Connect("/run/vpp/api.sock")
+           defer conn.Disconnect()
+
+           // Open channel
+           ch, _ := conn.NewAPIChannel()
+           defer ch.Close()
+
+           request := &vpe.MypluginEnableDisable{
+               EnableDisable: true,
+           }
+           reply := &vpe.MypluginEnableDisableReply{}
+
+           err := ch.SendRequest(request).ReceiveReply(reply)
+           if err != nil {
+                   fmt.Errorf("SendRequest: %w\n", err)
+           }
+    }
+
+As you will need to import (or ``go get "git.fd.io/govpp.git"``) to leverage the API
+client in your code, you might want to use the api-generator directly from the
+clone ``go build`` fetches for you. You can do this with :
+
+.. code-block:: console
+
+  $ export GOVPP_DIR=$(go list -f '{{.Dir}}' -m git.fd.io/govpp.git)
+  $ cd $GOVPP_DIR && go build -o /some/bin/dir ./cmd/binapi-generator
+  $ # instead of make gen-binapi-from-code you can rewrite the code to target
+  $ # your version ./binapi-generator
index 378b9fb..04d7043 100644 (file)
@@ -22,6 +22,7 @@ The Developers section covers the following areas:
    running_vpp
    gdb_examples
    add_plugin
    running_vpp
    gdb_examples
    add_plugin
+   add_plugin_goapi
    gitreview
    softwarearchitecture
    infrastructure
    gitreview
    softwarearchitecture
    infrastructure
@@ -42,3 +43,4 @@ The Developers section covers the following areas:
    quic_plugin
    cross_compile_macos.rst
    cnat
    quic_plugin
    cross_compile_macos.rst
    cnat
+   VPPAPI.md