Fix compatibility with latest master (20.01-rc0)
[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         "os"
24         "strings"
25
26         "git.fd.io/govpp.git"
27         "git.fd.io/govpp.git/adapter/socketclient"
28         "git.fd.io/govpp.git/api"
29         "git.fd.io/govpp.git/core"
30         "git.fd.io/govpp.git/examples/binapi/interfaces"
31         "git.fd.io/govpp.git/examples/binapi/ip"
32         "git.fd.io/govpp.git/examples/binapi/vpe"
33 )
34
35 var (
36         sockAddr = flag.String("sock", socketclient.DefaultSocketName, "Path to VPP binary API socket file")
37 )
38
39 func main() {
40         flag.Parse()
41
42         fmt.Println("Starting simple client example")
43
44         // connect to VPP asynchronously
45         conn, conev, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
46         if err != nil {
47                 log.Fatalln("ERROR:", err)
48         }
49         defer conn.Disconnect()
50
51         // wait for Connected event
52         select {
53         case e := <-conev:
54                 if e.State != core.Connected {
55                         log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
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         vppVersion(ch)
67
68         createLoopback(ch)
69         createLoopback(ch)
70         interfaceDump(ch)
71
72         addIPAddress(ch)
73         ipAddressDump(ch)
74
75         interfaceNotifications(ch)
76
77         if len(Errors) > 0 {
78                 fmt.Printf("finished with %d errors\n", len(Errors))
79                 os.Exit(1)
80         } else {
81                 fmt.Println("finished successfully")
82         }
83 }
84
85 var Errors []error
86
87 func logError(err error, msg string) {
88         fmt.Printf("ERROR: %s: %v\n", msg, err)
89         Errors = append(Errors, err)
90 }
91
92 // vppVersion is the simplest API example - it retrieves VPP version.
93 func vppVersion(ch api.Channel) {
94         fmt.Println("Retrieving version")
95
96         req := &vpe.ShowVersion{}
97         reply := &vpe.ShowVersionReply{}
98
99         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
100                 logError(err, "retrieving version")
101                 return
102         }
103         fmt.Printf("reply: %+v\n", reply)
104
105         fmt.Printf("VPP version: %q\n", cleanString(reply.Version))
106         fmt.Println("ok")
107 }
108
109 // createLoopback sends request to create loopback interface.
110 func createLoopback(ch api.Channel) {
111         fmt.Println("Creating loopback interface")
112
113         req := &interfaces.CreateLoopback{}
114         reply := &interfaces.CreateLoopbackReply{}
115
116         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
117                 logError(err, "creating loopback interface")
118                 return
119         }
120         fmt.Printf("reply: %+v\n", reply)
121
122         fmt.Printf("loopback interface index: %v\n", reply.SwIfIndex)
123         fmt.Println("OK")
124 }
125
126 // interfaceDump shows an example of multipart request (multiple replies are expected).
127 func interfaceDump(ch api.Channel) {
128         fmt.Println("Dumping interfaces")
129
130         reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
131         for {
132                 msg := &interfaces.SwInterfaceDetails{}
133                 stop, err := reqCtx.ReceiveReply(msg)
134                 if err != nil {
135                         logError(err, "dumping interfaces")
136                         return
137                 }
138                 if stop {
139                         break
140                 }
141                 fmt.Printf(" - interface: %+v\n", msg)
142         }
143
144         fmt.Println("OK")
145 }
146
147 // addIPAddress sends request to add IP address to interface.
148 func addIPAddress(ch api.Channel) {
149         fmt.Println("Adding IP address to interface")
150
151         req := &interfaces.SwInterfaceAddDelAddress{
152                 SwIfIndex:     1,
153                 IsAdd:         1,
154                 Address:       []byte{10, 10, 0, 1},
155                 AddressLength: 24,
156                 /* below for 20.01-rc0
157                 IsAdd:     true,
158                 Prefix: interfaces.Prefix{
159                         Address: interfaces.Address{
160                                 Af: interfaces.ADDRESS_IP4,
161                                 Un: interfaces.AddressUnionIP4(interfaces.IP4Address{10, 10, 0, 1}),
162                         },
163                         Len: 24,
164                 },*/
165         }
166         reply := &interfaces.SwInterfaceAddDelAddressReply{}
167
168         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
169                 logError(err, "adding IP address to interface")
170                 return
171         }
172         fmt.Printf("reply: %+v\n", reply)
173
174         fmt.Println("OK")
175 }
176
177 func ipAddressDump(ch api.Channel) {
178         fmt.Println("Dumping IP addresses")
179
180         req := &ip.IPAddressDump{
181                 SwIfIndex: 1,
182         }
183         reqCtx := ch.SendMultiRequest(req)
184
185         for {
186                 msg := &ip.IPAddressDetails{}
187                 stop, err := reqCtx.ReceiveReply(msg)
188                 if err != nil {
189                         logError(err, "dumping IP addresses")
190                         return
191                 }
192                 if stop {
193                         break
194                 }
195                 fmt.Printf(" - ip address: %+v\n", msg)
196         }
197
198         fmt.Println("OK")
199 }
200
201 // interfaceNotifications shows the usage of notification API. Note that for notifications,
202 // you are supposed to create your own Go channel with your preferred buffer size. If the channel's
203 // buffer is full, the notifications will not be delivered into it.
204 func interfaceNotifications(ch api.Channel) {
205         fmt.Println("Subscribing to notificaiton events")
206
207         notifChan := make(chan api.Message, 100)
208
209         // subscribe for specific notification message
210         sub, err := ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{})
211         if err != nil {
212                 logError(err, "subscribing to interface events")
213                 return
214         }
215
216         // enable interface events in VPP
217         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
218                 PID:           uint32(os.Getpid()),
219                 EnableDisable: 1,
220         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
221         if err != nil {
222                 logError(err, "enabling interface events")
223                 return
224         }
225
226         // generate some events in VPP
227         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
228                 SwIfIndex: 1,
229         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
230         if err != nil {
231                 logError(err, "setting interface flags")
232                 return
233         }
234         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
235                 SwIfIndex:   1,
236                 AdminUpDown: 1,
237                 /* below for 20.01-rc0
238                 AdminUpDown: true,
239                 Flags:     interfaces.IF_STATUS_API_FLAG_ADMIN_UP,*/
240         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
241         if err != nil {
242                 logError(err, "setting interface flags")
243                 return
244         }
245
246         // receive one notification
247         notif := (<-notifChan).(*interfaces.SwInterfaceEvent)
248         fmt.Printf("incoming event: %+v\n", notif)
249
250         // disable interface events in VPP
251         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
252                 PID:           uint32(os.Getpid()),
253                 EnableDisable: 0,
254         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
255         if err != nil {
256                 logError(err, "setting interface flags")
257                 return
258         }
259
260         // unsubscribe from delivery of the notifications
261         err = sub.Unsubscribe()
262         if err != nil {
263                 logError(err, "unsubscribing from interface events")
264                 return
265         }
266
267         fmt.Println()
268 }
269
270 func cleanString(str string) string {
271         return strings.Split(str, "\x00")[0]
272 }