Improvements for binapi-generator and support VPP 19.04 in statsclient
[govpp.git] / examples / simple-client / simple_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 // simple-client is an example VPP management application that exercises the
16 // govpp API on real-world use-cases.
17 package main
18
19 import (
20         "flag"
21         "fmt"
22         "log"
23         "net"
24         "os"
25         "strings"
26
27         "git.fd.io/govpp.git"
28         "git.fd.io/govpp.git/adapter/socketclient"
29         "git.fd.io/govpp.git/api"
30         "git.fd.io/govpp.git/core"
31         "git.fd.io/govpp.git/examples/binapi/acl"
32         "git.fd.io/govpp.git/examples/binapi/interfaces"
33         "git.fd.io/govpp.git/examples/binapi/ip"
34 )
35
36 var (
37         sockAddr = flag.String("sock", socketclient.DefaultSocketName, "Path to VPP binary API socket file")
38 )
39
40 func main() {
41         flag.Parse()
42
43         fmt.Println("Starting simple client example")
44
45         // connect to VPP
46         conn, conev, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
47         if err != nil {
48                 log.Fatalln("ERROR:", err)
49         }
50         defer conn.Disconnect()
51
52         select {
53         case e := <-conev:
54                 if e.State != core.Connected {
55                         log.Fatalln("ERROR: connecting to VPP failed:", err)
56                 }
57         }
58
59         // create an API channel that will be used in the examples
60         ch, err := conn.NewAPIChannel()
61         if err != nil {
62                 log.Fatalln("ERROR: creating channel failed:", err)
63         }
64         defer ch.Close()
65
66         // individual examples
67         aclVersion(ch)
68         aclConfig(ch)
69         aclDump(ch)
70
71         interfaceDump(ch)
72         ipAddressDump(ch)
73
74         setIpUnnumbered(ch)
75         ipUnnumberedDump(ch)
76
77         interfaceNotifications(ch)
78 }
79
80 // aclVersion is the simplest API example - one empty request message and one reply message.
81 func aclVersion(ch api.Channel) {
82         fmt.Println("ACL getting version")
83
84         req := &acl.ACLPluginGetVersion{}
85         reply := &acl.ACLPluginGetVersionReply{}
86
87         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
88                 fmt.Println("ERROR:", err)
89         } else {
90                 fmt.Printf("ACL version reply: %+v\n", reply)
91         }
92 }
93
94 // aclConfig is another simple API example - in this case, the request contains structured data.
95 func aclConfig(ch api.Channel) {
96         fmt.Println("ACL adding replace")
97
98         req := &acl.ACLAddReplace{
99                 ACLIndex: ^uint32(0),
100                 Tag:      []byte("access list 1"),
101                 R: []acl.ACLRule{
102                         {
103                                 IsPermit:       1,
104                                 SrcIPAddr:      net.ParseIP("10.0.0.0").To4(),
105                                 SrcIPPrefixLen: 8,
106                                 DstIPAddr:      net.ParseIP("192.168.1.0").To4(),
107                                 DstIPPrefixLen: 24,
108                                 Proto:          6,
109                         },
110                         {
111                                 IsPermit:       1,
112                                 SrcIPAddr:      net.ParseIP("8.8.8.8").To4(),
113                                 SrcIPPrefixLen: 32,
114                                 DstIPAddr:      net.ParseIP("172.16.0.0").To4(),
115                                 DstIPPrefixLen: 16,
116                                 Proto:          6,
117                         },
118                 },
119         }
120         reply := &acl.ACLAddReplaceReply{}
121
122         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
123                 fmt.Println("ERROR:", err)
124                 return
125         }
126
127         fmt.Printf("ACL add replace reply: %+v\n", reply)
128
129 }
130
131 // aclDump shows an example where SendRequest and ReceiveReply are not chained together.
132 func aclDump(ch api.Channel) {
133         fmt.Println("Dumping ACL")
134
135         req := &acl.ACLDump{}
136         reply := &acl.ACLDetails{}
137
138         reqCtx := ch.SendRequest(req)
139
140         if err := reqCtx.ReceiveReply(reply); err != nil {
141                 fmt.Println("ERROR:", err)
142         } else {
143                 fmt.Printf("ACL details: %+v\n", reply)
144         }
145 }
146
147 // interfaceDump shows an example of multipart request (multiple replies are expected).
148 func interfaceDump(ch api.Channel) {
149         fmt.Println("Dumping interfaces")
150
151         reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
152
153         for {
154                 msg := &interfaces.SwInterfaceDetails{}
155                 stop, err := reqCtx.ReceiveReply(msg)
156                 if stop {
157                         break
158                 }
159                 if err != nil {
160                         fmt.Println("ERROR:", err)
161                         return
162                 }
163                 ifaceName := strings.TrimFunc(string(msg.InterfaceName), func(r rune) bool {
164                         return r == 0x00
165                 })
166                 fmt.Printf("Interface %q: %+v\n", ifaceName, msg)
167         }
168 }
169
170 func ipAddressDump(ch api.Channel) {
171         fmt.Println("Dumping IP addresses")
172
173         req := &ip.IPAddressDump{
174                 SwIfIndex: 1, //^uint32(0),
175         }
176         reqCtx := ch.SendMultiRequest(req)
177
178         for {
179                 msg := &ip.IPAddressDetails{}
180                 stop, err := reqCtx.ReceiveReply(msg)
181                 if stop {
182                         break
183                 }
184                 if err != nil {
185                         fmt.Println("ERROR:", err)
186                         return
187                 }
188                 fmt.Printf("ip address details: %d %+v\n", msg.SwIfIndex, msg)
189         }
190 }
191
192 // aclDump shows an example where SendRequest and ReceiveReply are not chained together.
193 func setIpUnnumbered(ch api.Channel) {
194         req := &interfaces.SwInterfaceSetUnnumbered{
195                 SwIfIndex:           1,
196                 UnnumberedSwIfIndex: 2,
197                 IsAdd:               1,
198         }
199         reply := &interfaces.SwInterfaceSetUnnumberedReply{}
200
201         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
202                 fmt.Println("ERROR:", err)
203         } else {
204                 fmt.Printf("%+v\n", reply)
205         }
206 }
207
208 func ipUnnumberedDump(ch api.Channel) {
209         fmt.Println("Dumping IP unnumbered")
210
211         reqCtx := ch.SendMultiRequest(&ip.IPUnnumberedDump{
212                 SwIfIndex: ^uint32(0),
213         })
214
215         for {
216                 msg := &ip.IPUnnumberedDetails{}
217                 stop, err := reqCtx.ReceiveReply(msg)
218                 if stop {
219                         break
220                 }
221                 if err != nil {
222                         fmt.Println("ERROR:", err)
223                         return
224                 }
225                 fmt.Printf("IP unnumbered details: %+v\n", msg)
226         }
227 }
228
229 // interfaceNotifications shows the usage of notification API. Note that for notifications,
230 // you are supposed to create your own Go channel with your preferred buffer size. If the channel's
231 // buffer is full, the notifications will not be delivered into it.
232 func interfaceNotifications(ch api.Channel) {
233         fmt.Println("Subscribing to notificaiton events")
234
235         notifChan := make(chan api.Message, 100)
236
237         // subscribe for specific notification message
238         sub, err := ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{})
239         if err != nil {
240                 panic(err)
241         }
242
243         // enable interface events in VPP
244         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
245                 PID:           uint32(os.Getpid()),
246                 EnableDisable: 1,
247         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
248         if err != nil {
249                 panic(err)
250         }
251
252         // generate some events in VPP
253         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
254                 SwIfIndex:   0,
255                 AdminUpDown: 0,
256         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
257         if err != nil {
258                 panic(err)
259         }
260         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
261                 SwIfIndex:   0,
262                 AdminUpDown: 1,
263         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
264         if err != nil {
265                 panic(err)
266         }
267
268         // receive one notification
269         notif := (<-notifChan).(*interfaces.SwInterfaceEvent)
270         fmt.Printf("incoming event: %+v\n", notif)
271
272         // disable interface events in VPP
273         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
274                 PID:           uint32(os.Getpid()),
275                 EnableDisable: 0,
276         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
277         if err != nil {
278                 panic(err)
279         }
280
281         // unsubscribe from delivery of the notifications
282         err = sub.Unsubscribe()
283         if err != nil {
284                 panic(err)
285         }
286 }