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