Stats API: added GetMemory()
[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         "encoding/json"
21         "flag"
22         "fmt"
23         "log"
24         "os"
25
26         "git.fd.io/govpp.git"
27         "git.fd.io/govpp.git/adapter/socketclient"
28         "git.fd.io/govpp.git/api"
29         interfaces "git.fd.io/govpp.git/binapi/interface"
30         "git.fd.io/govpp.git/binapi/interface_types"
31         "git.fd.io/govpp.git/binapi/ip"
32         "git.fd.io/govpp.git/binapi/ip_types"
33         "git.fd.io/govpp.git/binapi/vpe"
34         "git.fd.io/govpp.git/core"
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         fmt.Println()
46
47         // connect to VPP asynchronously
48         conn, connEv, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
49         if err != nil {
50                 log.Fatalln("ERROR:", err)
51         }
52         defer conn.Disconnect()
53
54         // wait for Connected event
55         select {
56         case e := <-connEv:
57                 if e.State != core.Connected {
58                         log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
59                 }
60         }
61
62         // check compatibility of used messages
63         ch, err := conn.NewAPIChannel()
64         if err != nil {
65                 log.Fatalln("ERROR: creating channel failed:", err)
66         }
67         defer ch.Close()
68         if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
69                 log.Fatal(err)
70         }
71         if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
72                 log.Fatal(err)
73         }
74
75         // process errors encountered during the example
76         defer func() {
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         // use request/reply (channel API)
86         getVppVersion(ch)
87         getSystemTime(ch)
88         idx := createLoopback(ch)
89         interfaceDump(ch)
90         addIPAddress(ch, idx)
91         ipAddressDump(ch, idx)
92         interfaceNotifications(ch, idx)
93 }
94
95 func getVppVersion(ch api.Channel) {
96         fmt.Println("Retrieving version..")
97
98         req := &vpe.ShowVersion{}
99         reply := &vpe.ShowVersionReply{}
100
101         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
102                 logError(err, "retrieving version")
103                 return
104         }
105
106         fmt.Printf("VPP version: %q\n", reply.Version)
107         fmt.Println("OK")
108         fmt.Println()
109 }
110
111 func getSystemTime(ch api.Channel) {
112         fmt.Println("Retrieving system time..")
113
114         req := &vpe.ShowVpeSystemTime{}
115         reply := &vpe.ShowVpeSystemTimeReply{}
116
117         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
118                 logError(err, "retrieving system time")
119                 return
120         }
121
122         fmt.Printf("system time: %v\n", reply.VpeSystemTime)
123         fmt.Println("OK")
124         fmt.Println()
125 }
126
127 func createLoopback(ch api.Channel) interface_types.InterfaceIndex {
128         fmt.Println("Creating loopback interface..")
129
130         req := &interfaces.CreateLoopback{}
131         reply := &interfaces.CreateLoopbackReply{}
132
133         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
134                 logError(err, "creating loopback interface")
135                 return 0
136         }
137
138         fmt.Printf("interface index: %v\n", reply.SwIfIndex)
139         fmt.Println("OK")
140         fmt.Println()
141
142         return reply.SwIfIndex
143 }
144
145 func interfaceDump(ch api.Channel) {
146         fmt.Println("Dumping interfaces..")
147
148         n := 0
149         reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{
150                 SwIfIndex: ^interface_types.InterfaceIndex(0),
151         })
152         for {
153                 msg := &interfaces.SwInterfaceDetails{}
154                 stop, err := reqCtx.ReceiveReply(msg)
155                 if stop {
156                         break
157                 }
158                 if err != nil {
159                         logError(err, "dumping interfaces")
160                         return
161                 }
162                 n++
163                 fmt.Printf(" - interface #%d: %+v\n", n, msg)
164                 marshal(msg)
165         }
166
167         fmt.Println("OK")
168         fmt.Println()
169 }
170
171 func addIPAddress(ch api.Channel, index interface_types.InterfaceIndex) {
172         fmt.Printf("Adding IP address to interface index %d\n", index)
173
174         req := &interfaces.SwInterfaceAddDelAddress{
175                 SwIfIndex: index,
176                 IsAdd:     true,
177                 Prefix: ip_types.AddressWithPrefix{
178                         Address: ip_types.Address{
179                                 Af: ip_types.ADDRESS_IP4,
180                                 Un: ip_types.AddressUnionIP4(ip_types.IP4Address{10, 10, 0, uint8(index)}),
181                         },
182                         Len: 32,
183                 },
184         }
185         marshal(req)
186         reply := &interfaces.SwInterfaceAddDelAddressReply{}
187
188         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
189                 logError(err, "adding IP address to interface")
190                 return
191         }
192
193         fmt.Println("OK")
194         fmt.Println()
195 }
196
197 func ipAddressDump(ch api.Channel, index interface_types.InterfaceIndex) {
198         fmt.Printf("Dumping IP addresses for interface index %d..\n", index)
199
200         req := &ip.IPAddressDump{
201                 SwIfIndex: index,
202         }
203         reqCtx := ch.SendMultiRequest(req)
204
205         for {
206                 msg := &ip.IPAddressDetails{}
207                 stop, err := reqCtx.ReceiveReply(msg)
208                 if err != nil {
209                         logError(err, "dumping IP addresses")
210                         return
211                 }
212                 if stop {
213                         break
214                 }
215                 fmt.Printf(" - ip address: %+v\n", msg)
216                 marshal(msg)
217         }
218
219         fmt.Println("OK")
220         fmt.Println()
221 }
222
223 // interfaceNotifications shows the usage of notification API. Note that for notifications,
224 // you are supposed to create your own Go channel with your preferred buffer size. If the channel's
225 // buffer is full, the notifications will not be delivered into it.
226 func interfaceNotifications(ch api.Channel, index interface_types.InterfaceIndex) {
227         fmt.Printf("Subscribing to notificaiton events for interface index %d\n", index)
228
229         notifChan := make(chan api.Message, 100)
230
231         // subscribe for specific notification message
232         sub, err := ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{})
233         if err != nil {
234                 logError(err, "subscribing to interface events")
235                 return
236         }
237
238         // enable interface events in VPP
239         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
240                 PID:           uint32(os.Getpid()),
241                 EnableDisable: 1,
242         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
243         if err != nil {
244                 logError(err, "enabling interface events")
245                 return
246         }
247
248         // receive notifications
249         go func() {
250                 for notif := range notifChan {
251                         e := notif.(*interfaces.SwInterfaceEvent)
252                         fmt.Printf("incoming event: %+v\n", e)
253                         marshal(e)
254                 }
255         }()
256
257         // generate some events in VPP
258         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
259                 SwIfIndex: index,
260                 Flags:     interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
261         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
262         if err != nil {
263                 logError(err, "setting interface flags")
264                 return
265         }
266         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
267                 SwIfIndex: index,
268                 Flags:     0,
269         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
270         if err != nil {
271                 logError(err, "setting interface flags")
272                 return
273         }
274
275         // disable interface events in VPP
276         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
277                 PID:           uint32(os.Getpid()),
278                 EnableDisable: 0,
279         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
280         if err != nil {
281                 logError(err, "setting interface flags")
282                 return
283         }
284
285         // unsubscribe from delivery of the notifications
286         err = sub.Unsubscribe()
287         if err != nil {
288                 logError(err, "unsubscribing from interface events")
289                 return
290         }
291
292         fmt.Println("OK")
293         fmt.Println()
294 }
295
296 func marshal(v interface{}) {
297         fmt.Printf("GO: %#v\n", v)
298         b, err := json.MarshalIndent(v, "", "  ")
299         if err != nil {
300                 panic(err)
301         }
302         fmt.Printf("JSON: %s\n", b)
303 }
304
305 var errors []error
306
307 func logError(err error, msg string) {
308         fmt.Printf("ERROR: %s: %v\n", msg, err)
309         errors = append(errors, err)
310 }