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