binapi-generator renamed & moved, finished documentation
[govpp.git] / examples / example_client.go
1 // Copyright (c) 2017 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Example VPP management application that exercises the govpp API on real-world use-cases.
16 package main
17
18 // Generates Go bindings for all VPP APIs located in the json directory.
19 //go:generate binapi-generator --input-dir=bin_api --output-dir=bin_api
20
21 import (
22         "fmt"
23         "net"
24         "os"
25         "os/signal"
26
27         "git.fd.io/govpp.git"
28         "git.fd.io/govpp.git/api"
29         "git.fd.io/govpp.git/api/ifcounters"
30         "git.fd.io/govpp.git/core/bin_api/vpe"
31         "git.fd.io/govpp.git/examples/bin_api/acl"
32         "git.fd.io/govpp.git/examples/bin_api/interfaces"
33         "git.fd.io/govpp.git/examples/bin_api/tap"
34 )
35
36 func main() {
37         fmt.Println("Starting example VPP client...")
38
39         // connect to VPP
40         conn, err := govpp.Connect()
41         if err != nil {
42                 fmt.Println("Error:", err)
43                 os.Exit(1)
44         }
45         defer conn.Disconnect()
46
47         // create an API channel that will be used in the examples
48         ch, err := conn.NewAPIChannel()
49         if err != nil {
50                 fmt.Println("Error:", err)
51                 os.Exit(1)
52         }
53         defer ch.Close()
54
55         // check whether the VPP supports our version of some messages
56         compatibilityCheck(ch)
57
58         // individual examples
59         aclVersion(ch)
60         aclConfig(ch)
61         aclDump(ch)
62
63         tapConnect(ch)
64
65         interfaceDump(ch)
66         interfaceNotifications(ch)
67
68         //interfaceCounters(ch)
69 }
70
71 // compatibilityCheck shows how an management application can check whether generated API messages are
72 // compatible with the version of VPP which the library is connected to.
73 func compatibilityCheck(ch *api.Channel) {
74         err := ch.CheckMessageCompatibility(
75                 &interfaces.SwInterfaceDump{},
76                 &interfaces.SwInterfaceDetails{},
77         )
78         if err != nil {
79                 fmt.Println(err)
80                 os.Exit(1)
81         }
82 }
83
84 // aclVersion is the simplest API example - one empty request message and one reply message.
85 func aclVersion(ch *api.Channel) {
86         req := &acl.ACLPluginGetVersion{}
87         reply := &acl.ACLPluginGetVersionReply{}
88
89         err := ch.SendRequest(req).ReceiveReply(reply)
90
91         if err != nil {
92                 fmt.Println("Error:", err)
93         } else {
94                 fmt.Printf("%+v\n", reply)
95         }
96 }
97
98 // aclConfig is another simple API example - in this case, the request contains structured data.
99 func aclConfig(ch *api.Channel) {
100         req := &acl.ACLAddReplace{
101                 ACLIndex: ^uint32(0),
102                 Tag:      []byte("access list 1"),
103                 R: []acl.ACLRule{
104                         {
105                                 IsPermit:       1,
106                                 SrcIPAddr:      net.ParseIP("10.0.0.0").To4(),
107                                 SrcIPPrefixLen: 8,
108                                 DstIPAddr:      net.ParseIP("192.168.1.0").To4(),
109                                 DstIPPrefixLen: 24,
110                                 Proto:          6,
111                         },
112                         {
113                                 IsPermit:       1,
114                                 SrcIPAddr:      net.ParseIP("8.8.8.8").To4(),
115                                 SrcIPPrefixLen: 32,
116                                 DstIPAddr:      net.ParseIP("172.16.0.0").To4(),
117                                 DstIPPrefixLen: 16,
118                                 Proto:          6,
119                         },
120                 },
121         }
122         reply := &acl.ACLAddReplaceReply{}
123
124         err := ch.SendRequest(req).ReceiveReply(reply)
125
126         if err != nil {
127                 fmt.Println("Error:", err)
128         } else {
129                 fmt.Printf("%+v\n", reply)
130         }
131 }
132
133 // aclDump shows an example where SendRequest and ReceiveReply are not chained together.
134 func aclDump(ch *api.Channel) {
135         req := &acl.ACLDump{}
136         reply := &acl.ACLDetails{}
137
138         reqCtx := ch.SendRequest(req)
139         err := reqCtx.ReceiveReply(reply)
140
141         if err != nil {
142                 fmt.Println("Error:", err)
143         } else {
144                 fmt.Printf("%+v\n", reply)
145         }
146 }
147
148 // tapConnect example shows how the Go channels in the API channel can be accessed directly instead
149 // of using SendRequest and ReceiveReply wrappers.
150 func tapConnect(ch *api.Channel) {
151         req := &tap.TapConnect{
152                 TapName:      []byte("testtap"),
153                 UseRandomMac: 1,
154         }
155
156         // send the request to the request go channel
157         ch.ReqChan <- &api.VppRequest{Message: req}
158
159         // receive a reply from the reply go channel
160         vppReply := <-ch.ReplyChan
161         if vppReply.Error != nil {
162                 fmt.Println("Error:", vppReply.Error)
163                 return
164         }
165
166         // decode the message
167         reply := &tap.TapConnectReply{}
168         err := ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
169
170         if err != nil {
171                 fmt.Println("Error:", err)
172         } else {
173                 fmt.Printf("%+v\n", reply)
174         }
175 }
176
177 // interfaceDump shows an example of multipart request (multiple replies are expected).
178 func interfaceDump(ch *api.Channel) {
179         req := &interfaces.SwInterfaceDump{}
180         reqCtx := ch.SendMultiRequest(req)
181
182         for {
183                 msg := &interfaces.SwInterfaceDetails{}
184                 stop, err := reqCtx.ReceiveReply(msg)
185                 if stop {
186                         break // break out of the loop
187                 }
188                 if err != nil {
189                         fmt.Println("Error:", err)
190                 }
191                 fmt.Printf("%+v\n", msg)
192         }
193 }
194
195 // interfaceNotifications shows the usage of notification API. Note that for notifications,
196 // you are supposed to create your own Go channel with your preferred buffer size. If the channel's
197 // buffer is full, the notifications will not be delivered into it.
198 func interfaceNotifications(ch *api.Channel) {
199         // subscribe for specific notification message
200         notifChan := make(chan api.Message, 100)
201         subs, _ := ch.SubscribeNotification(notifChan, interfaces.NewSwInterfaceSetFlags)
202
203         // enable interface events in VPP
204         ch.SendRequest(&interfaces.WantInterfaceEvents{
205                 Pid:           uint32(os.Getpid()),
206                 EnableDisable: 1,
207         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
208
209         // generate some events in VPP
210         ch.SendRequest(&interfaces.SwInterfaceSetFlags{
211                 SwIfIndex:   0,
212                 AdminUpDown: 0,
213         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
214         ch.SendRequest(&interfaces.SwInterfaceSetFlags{
215                 SwIfIndex:   0,
216                 AdminUpDown: 1,
217         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
218
219         // receive one notification
220         notif := (<-notifChan).(*interfaces.SwInterfaceSetFlags)
221         fmt.Printf("%+v\n", notif)
222
223         // unsubscribe from delivery of the notifications
224         ch.UnsubscribeNotification(subs)
225 }
226
227 // interfaceCounters is an example of using notification API to periodically retrieve interface statistics.
228 // The ifcounters package contains the API that can be used to decode the strange VnetInterfaceCounters message.
229 func interfaceCounters(ch *api.Channel) {
230         // subscribe for interface counters notifications
231         notifChan := make(chan api.Message, 100)
232         subs, _ := ch.SubscribeNotification(notifChan, interfaces.NewVnetInterfaceCounters)
233
234         // enable interface counters notifications from VPP
235         ch.SendRequest(&vpe.WantStats{
236                 Pid:           uint32(os.Getpid()),
237                 EnableDisable: 1,
238         }).ReceiveReply(&vpe.WantStatsReply{})
239
240         // create channel for Interrupt signal
241         sigChan := make(chan os.Signal, 1)
242         signal.Notify(sigChan, os.Interrupt)
243
244         // loop until Interrupt signal is received
245 loop:
246         for {
247                 select {
248                 case <-sigChan:
249                         // interrupt received
250                         break loop
251                 case notifMsg := <-notifChan:
252                         notif := notifMsg.(*interfaces.VnetInterfaceCounters)
253                         // notification received
254                         fmt.Printf("%+v\n", notif)
255
256                         if notif.IsCombined == 0 {
257                                 // simple counter
258                                 counters, err := ifcounters.DecodeCounters(ifcounters.VnetInterfaceCounters(*notif))
259                                 if err != nil {
260                                         fmt.Println("Error:", err)
261                                 } else {
262                                         fmt.Printf("%+v\n", counters)
263                                 }
264                         } else {
265                                 // combined counter
266                                 counters, err := ifcounters.DecodeCombinedCounters(ifcounters.VnetInterfaceCounters(*notif))
267                                 if err != nil {
268                                         fmt.Println("Error:", err)
269                                 } else {
270                                         fmt.Printf("%+v\n", counters)
271                                 }
272                         }
273                 }
274         }
275
276         // unsubscribe from delivery of the notifications
277         ch.UnsubscribeNotification(subs)
278 }