6675853dda85a4ab5e32dedb5ab800da71beb9e6
[vpp.git] / docs / interfacing / go / index.rst
1 .. _govpp:
2
3 ==============
4 Go api (govpp)
5 ==============
6
7 If you are writing a Control plane in GO that interfaces with VPP, `GoVPP <https://github.com/FDio/govpp>`__ is the library that will allow you to connect to VPP, and program it through its binary API socket.
8
9 Components involved
10 ===================
11
12 The API client connecting to VPP consists of several elements :
13
14 * First, everything stems from the api definition living in the VPP repository. The message definitions live in ``*.api`` files that you will find instances of in most VPP plugins.
15 * The repository contains an api generator ``make json-api-files`` that converts those ``.api`` files into ``.json`` files to be consumed by language specific bindings.
16 * The program ingesting these ``.json`` files is called ``binapi-generator`` and lives inside `GoVPP <https://github.com/FDio/govpp>`__. It contains the logic converting them to ``.ba.go`` files with the appropriate struct definitions matching all the api messages defined in the ``.api`` files.
17 * `GoVPP <https://github.com/FDio/govpp>`__'s repo also contains the logic for attaching to VPP's binary API socket, and wrappers for sending and receiving messages over it.
18
19 Getting started
20 ===============
21
22 Generating the API bindings from the VPP source
23 -----------------------------------------------
24
25 * First create your project directory (watch out for path as it is important for go modules) :
26
27 .. code:: bash
28
29     mkdir -p $HOME/myproject
30
31 * Run the bindings generation at the root of the repo :
32
33 .. code:: bash
34
35     cd <vpp_repo_dir>/vpp
36     make ARGS="--output-dir=$HOME/myproject/vppbinapi --import-prefix=mygit.com/myproject/vppbinapi" go-api-files
37
38
39 .. note::
40     The two options are similar but specify two different things. The output-dir option sets the directory where the generated bindings will be stored. The import prefix sets the go package name to be used in the generated bindings, this will be the string to be used in your ``import ( "" )`` in go. Both can or can not match depending on your ``go.mod``.
41
42
43 This should prompt you with the name of the directory were the generated go api bindings live. (e.g. ``Go API bindings were generated to myproject/vppbinapi``)
44
45 Generating the API bindings from the VPP package
46 ------------------------------------------------
47
48 * You should find its corresponding ``api.json`` files present on your system, typically in ``/usr/share/vpp/api/``
49
50 .. code:: bash
51
52     # First install the binary API generator
53     #   It will be installed to $GOPATH/bin/binapi-generator
54     #   or $HOME/go/bin/binapi-generator
55     go install git.fd.io/govpp.git/cmd/binapi-generator@latest
56
57     # Run the binapi-generator
58     $GOPATH/bin/binapi-generator \
59       --input-dir=/usr/share/vpp/api/ \
60       --output-dir=$HOME/myproject/vppbinapi \
61       --import-prefix=mygit.com/myproject/vppbinapi
62
63 This should output the go bindings to ``$HOME/myproject/vppbinapi``
64
65 Launch VPP
66 ==========
67
68 .. code:: bash
69
70     mkdir -p /tmp/vpp
71     cat << EOF > /tmp/startup.conf
72     unix {nodaemon cli-listen /tmp/vpp/api.sock}
73     plugins {
74         path /vpp/build-root/install-vpp_debug-native/vpp/lib/x86_64-linux-gnu/vpp_plugins
75         plugin dpdk_plugin.so { disable }
76     }
77     EOF
78
79     # If VPP was built from source:
80     <vpp_repo_dir>/build-root/install-vpp_debug-native/vpp/bin/vpp -c /tmp/startup.conf
81
82     # If VPP was installed from package:
83     vpp -c /tmp/startup.conf
84
85
86 Connecting to VPP
87 =================
88
89 Once you have your go bindings in ``$HOME/myproject/vppbinapi``, you can start building an agent leveraging them. A typical agent would look like this
90
91 * Back to your project directory, add govpp as a dependency
92
93 .. code:: bash
94
95     cd "$HOME/myproject"
96     go mod init mygit.com/myproject
97     go get git.fd.io/govpp.git@latest
98
99 * Create ``main.go`` in ``$HOME/myproject`` like below :
100
101 .. code-block:: go
102
103     package main
104
105     import (
106         "os"
107         "fmt"
108
109         "git.fd.io/govpp.git"
110         "git.fd.io/govpp.git/api"
111
112         "mygit.com/myproject/vppbinapi/af_packet"
113         interfaces "mygit.com/myproject/vppbinapi/interface"
114         "mygit.com/myproject/vppbinapi/interface_types"
115     )
116
117     func CreateHostInterface (ch api.Channel, ifName string) (uint32, error) {
118         response := &af_packet.AfPacketCreateReply{}
119         request := &af_packet.AfPacketCreate{HostIfName: ifName}
120         err := ch.SendRequest(request).ReceiveReply(response)
121         if err != nil {
122             return 0, err
123         } else if response.Retval != 0 {
124             return 0, fmt.Errorf("AfPacketCreate failed: req %+v reply %+v", request, response)
125         }
126         return uint32(response.SwIfIndex), nil
127     }
128
129     func InterfaceAdminUp(ch api.Channel, swIfIndex uint32) error {
130         request := &interfaces.SwInterfaceSetFlags{
131             SwIfIndex: interface_types.InterfaceIndex(swIfIndex),
132             Flags:     interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
133         }
134         response := &interfaces.SwInterfaceSetFlagsReply{}
135         err := ch.SendRequest(request).ReceiveReply(response)
136         if err != nil {
137             return err
138         }
139         return nil
140     }
141
142     func main() {
143         // Connect to VPP
144         conn, err := govpp.Connect("/tmp/vpp/api.sock")
145         defer conn.Disconnect()
146         if err != nil {
147             fmt.Printf("Could not connect: %s\n", err)
148             os.Exit(1)
149         }
150
151         // Open channel
152         ch, err := conn.NewAPIChannel()
153         defer ch.Close()
154         if err != nil {
155             fmt.Printf("Could not open API channel: %s\n", err)
156             os.Exit(1)
157         }
158
159         swIfIndex, err := CreateHostInterface(ch, "eth0")
160         if err != nil {
161             fmt.Printf("Could not create host interface: %s\n", err)
162             os.Exit(1)
163         }
164         err = InterfaceAdminUp(ch, swIfIndex)
165         if err != nil {
166             fmt.Printf("Could not set interface up: %s\n", err)
167             os.Exit(1)
168         }
169
170         fmt.Printf("Created host interface & set it up, id=%d\n", swIfIndex)
171     }
172
173 *  Finally build and launch application. This will connect to VPP on its API socket ``/tmp/vpp/api.sock``, create an AF_PACKET interface on ``eth0`` and set it up
174
175 .. code:: bash
176
177     cd "$HOME/myproject"
178     go build
179     ./myproject
180