blob: c40627a4d569a5d3ae30c8b28a979359fc73dffd [file] [log] [blame]
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +02001.. _govpp:
2
3==============
4Go api (govpp)
5==============
6
Ondrej Fabry7c111562023-03-15 21:54:53 +01007If you are writing a Go application that needs to control and manage VPP, the `GoVPP <https://github.com/FDio/govpp>`__ is a toolset providing a client library that will allow you to connect to VPP and interact with VPP binary API, Stats API and more.
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +02008
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +01009Components involved
10===================
11
12The 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
19Getting started
20===============
21
22Generating 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::
Ondrej Fabry7c111562023-03-15 21:54:53 +010040
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +010041 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``.
42
43
44This 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``)
45
46Generating the API bindings from the VPP package
47------------------------------------------------
48
49* You should find its corresponding ``api.json`` files present on your system, typically in ``/usr/share/vpp/api/``
50
51.. code:: bash
52
53 # First install the binary API generator
54 # It will be installed to $GOPATH/bin/binapi-generator
55 # or $HOME/go/bin/binapi-generator
Ondrej Fabry7c111562023-03-15 21:54:53 +010056 go install go.fd.io/govpp/cmd/binapi-generator@latest
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +010057
58 # Run the binapi-generator
59 $GOPATH/bin/binapi-generator \
Ondrej Fabry7c111562023-03-15 21:54:53 +010060 --input=/usr/share/vpp/api/ \
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +010061 --output-dir=$HOME/myproject/vppbinapi \
62 --import-prefix=mygit.com/myproject/vppbinapi
63
64This should output the go bindings to ``$HOME/myproject/vppbinapi``
65
66Launch VPP
67==========
68
69.. code:: bash
70
71 mkdir -p /tmp/vpp
72 cat << EOF > /tmp/startup.conf
73 unix {nodaemon cli-listen /tmp/vpp/api.sock}
74 plugins {
75 path /vpp/build-root/install-vpp_debug-native/vpp/lib/x86_64-linux-gnu/vpp_plugins
76 plugin dpdk_plugin.so { disable }
77 }
78 EOF
79
80 # If VPP was built from source:
81 <vpp_repo_dir>/build-root/install-vpp_debug-native/vpp/bin/vpp -c /tmp/startup.conf
82
83 # If VPP was installed from package:
84 vpp -c /tmp/startup.conf
85
86
87Connecting to VPP
88=================
89
90Once you have your go bindings in ``$HOME/myproject/vppbinapi``, you can start building an agent leveraging them. A typical agent would look like this
91
92* Back to your project directory, add govpp as a dependency
93
94.. code:: bash
95
96 cd "$HOME/myproject"
97 go mod init mygit.com/myproject
Ondrej Fabry7c111562023-03-15 21:54:53 +010098 go get go.fd.io/govpp@latest
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +010099
100* Create ``main.go`` in ``$HOME/myproject`` like below :
101
102.. code-block:: go
103
104 package main
105
106 import (
107 "os"
108 "fmt"
109
Ondrej Fabry7c111562023-03-15 21:54:53 +0100110 "go.fd.io/govpp"
111 "go.fd.io/govpp/api"
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +0100112
113 "mygit.com/myproject/vppbinapi/af_packet"
114 interfaces "mygit.com/myproject/vppbinapi/interface"
115 "mygit.com/myproject/vppbinapi/interface_types"
116 )
117
Ondrej Fabry7c111562023-03-15 21:54:53 +0100118 func CreateHostInterface(ch api.Channel, ifName string) (uint32, error) {
Nathan Skrzypczak3d390ba2022-03-10 12:42:01 +0100119 response := &af_packet.AfPacketCreateReply{}
120 request := &af_packet.AfPacketCreate{HostIfName: ifName}
121 err := ch.SendRequest(request).ReceiveReply(response)
122 if err != nil {
123 return 0, err
124 } else if response.Retval != 0 {
125 return 0, fmt.Errorf("AfPacketCreate failed: req %+v reply %+v", request, response)
126 }
127 return uint32(response.SwIfIndex), nil
128 }
129
130 func InterfaceAdminUp(ch api.Channel, swIfIndex uint32) error {
131 request := &interfaces.SwInterfaceSetFlags{
132 SwIfIndex: interface_types.InterfaceIndex(swIfIndex),
133 Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
134 }
135 response := &interfaces.SwInterfaceSetFlagsReply{}
136 err := ch.SendRequest(request).ReceiveReply(response)
137 if err != nil {
138 return err
139 }
140 return nil
141 }
142
143 func main() {
144 // Connect to VPP
145 conn, err := govpp.Connect("/tmp/vpp/api.sock")
146 defer conn.Disconnect()
147 if err != nil {
148 fmt.Printf("Could not connect: %s\n", err)
149 os.Exit(1)
150 }
151
152 // Open channel
153 ch, err := conn.NewAPIChannel()
154 defer ch.Close()
155 if err != nil {
156 fmt.Printf("Could not open API channel: %s\n", err)
157 os.Exit(1)
158 }
159
160 swIfIndex, err := CreateHostInterface(ch, "eth0")
161 if err != nil {
162 fmt.Printf("Could not create host interface: %s\n", err)
163 os.Exit(1)
164 }
165 err = InterfaceAdminUp(ch, swIfIndex)
166 if err != nil {
167 fmt.Printf("Could not set interface up: %s\n", err)
168 os.Exit(1)
169 }
170
171 fmt.Printf("Created host interface & set it up, id=%d\n", swIfIndex)
172 }
173
174* 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
175
176.. code:: bash
177
178 cd "$HOME/myproject"
179 go build
180 ./myproject
181