Stats API: added GetMemory()
[govpp.git] / examples / stream-client / stream_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 // stream-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         "context"
21         "flag"
22         "fmt"
23         "log"
24         "os"
25         "time"
26
27         "git.fd.io/govpp.git"
28         "git.fd.io/govpp.git/adapter/socketclient"
29         "git.fd.io/govpp.git/api"
30         interfaces "git.fd.io/govpp.git/binapi/interface"
31         "git.fd.io/govpp.git/binapi/interface_types"
32         "git.fd.io/govpp.git/binapi/ip"
33         "git.fd.io/govpp.git/binapi/ip_types"
34         "git.fd.io/govpp.git/binapi/mactime"
35         "git.fd.io/govpp.git/binapi/vpe"
36         "git.fd.io/govpp.git/core"
37 )
38
39 var (
40         sockAddr = flag.String("sock", socketclient.DefaultSocketName, "Path to VPP binary API socket file")
41 )
42
43 func main() {
44         flag.Parse()
45
46         fmt.Println("Starting stream client example")
47         fmt.Println()
48
49         // connect to VPP asynchronously
50         conn, connEv, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
51         if err != nil {
52                 log.Fatalln("ERROR:", err)
53         }
54         defer conn.Disconnect()
55
56         // wait for Connected event
57         select {
58         case e := <-connEv:
59                 if e.State != core.Connected {
60                         log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
61                 }
62         }
63
64         // check compatibility of used messages
65         ch, err := conn.NewAPIChannel()
66         if err != nil {
67                 log.Fatalln("ERROR: creating channel failed:", err)
68         }
69         defer ch.Close()
70         if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
71                 log.Fatal(err)
72         }
73         if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
74                 log.Fatal(err)
75         }
76
77         // process errors encountered during the example
78         defer func() {
79                 if len(errors) > 0 {
80                         fmt.Printf("finished with %d errors\n", len(errors))
81                         os.Exit(1)
82                 } else {
83                         fmt.Println("finished successfully")
84                 }
85         }()
86
87         // send and receive messages using stream (low-low level API)
88         stream, err := conn.NewStream(context.Background(),
89                 core.WithRequestSize(50),
90                 core.WithReplySize(50),
91                 core.WithReplyTimeout(2*time.Second))
92         if err != nil {
93                 panic(err)
94         }
95         defer func() {
96                 if err := stream.Close(); err != nil {
97                         logError(err, "closing the stream")
98                 }
99         }()
100         getVppVersionStream(stream)
101         idx := createLoopbackStream(stream)
102         interfaceDumpStream(stream)
103         addIPAddressStream(stream, idx)
104         ipAddressDumpStream(stream, idx)
105         mactimeDump(stream)
106         return
107 }
108
109 func getVppVersionStream(stream api.Stream) {
110         fmt.Println("Retrieving version..")
111
112         req := &vpe.ShowVersion{}
113         if err := stream.SendMsg(req); err != nil {
114                 logError(err, "ShowVersion sending message")
115                 return
116         }
117         recv, err := stream.RecvMsg()
118         if err != nil {
119                 logError(err, "ShowVersion receive message")
120                 return
121         }
122         recvMsg := recv.(*vpe.ShowVersionReply)
123
124         fmt.Printf("Retrieved VPP version: %q\n", recvMsg.Version)
125         fmt.Println("OK")
126         fmt.Println()
127 }
128
129 func createLoopbackStream(stream api.Stream) (ifIdx interface_types.InterfaceIndex) {
130         fmt.Println("Creating the loopback interface..")
131
132         req := &interfaces.CreateLoopback{}
133         if err := stream.SendMsg(req); err != nil {
134                 logError(err, "CreateLoopback sending message")
135                 return
136         }
137         recv, err := stream.RecvMsg()
138         if err != nil {
139                 logError(err, "CreateLoopback receive message")
140                 return
141         }
142         recvMsg := recv.(*interfaces.CreateLoopbackReply)
143
144         fmt.Printf("Loopback interface index: %v\n", recvMsg.SwIfIndex)
145         fmt.Println("OK")
146         fmt.Println()
147
148         return recvMsg.SwIfIndex
149 }
150
151 func interfaceDumpStream(stream api.Stream) {
152         fmt.Println("Dumping interfaces..")
153
154         if err := stream.SendMsg(&interfaces.SwInterfaceDump{
155                 SwIfIndex: ^interface_types.InterfaceIndex(0),
156         }); err != nil {
157                 logError(err, "SwInterfaceDump sending message")
158                 return
159         }
160         if err := stream.SendMsg(&vpe.ControlPing{}); err != nil {
161                 logError(err, "ControlPing sending message")
162                 return
163         }
164
165 Loop:
166         for {
167                 msg, err := stream.RecvMsg()
168                 if err != nil {
169                         logError(err, "SwInterfaceDump receiving message ")
170                         return
171                 }
172
173                 switch msg.(type) {
174                 case *interfaces.SwInterfaceDetails:
175                         fmt.Printf(" - SwInterfaceDetails: %+v\n", msg)
176
177                 case *vpe.ControlPingReply:
178                         fmt.Printf(" - ControlPingReply: %+v\n", msg)
179                         break Loop
180
181                 default:
182                         logError(err, "unexpected message")
183                         return
184                 }
185         }
186
187         fmt.Println("OK")
188         fmt.Println()
189 }
190
191 func addIPAddressStream(stream api.Stream, index interface_types.InterfaceIndex) {
192         fmt.Printf("Adding IP address to the interface index %d..\n", index)
193
194         if err := stream.SendMsg(&interfaces.SwInterfaceAddDelAddress{
195                 SwIfIndex: index,
196                 IsAdd:     true,
197                 Prefix: ip_types.AddressWithPrefix{
198                         Address: ip_types.Address{
199                                 Af: ip_types.ADDRESS_IP4,
200                                 Un: ip_types.AddressUnionIP4(ip_types.IP4Address{10, 10, 0, uint8(index)}),
201                         },
202                         Len: 32,
203                 },
204         }); err != nil {
205                 logError(err, "SwInterfaceAddDelAddress sending message")
206                 return
207         }
208
209         recv, err := stream.RecvMsg()
210         if err != nil {
211                 logError(err, "SwInterfaceAddDelAddressReply receiving message")
212                 return
213         }
214         recvMsg := recv.(*interfaces.SwInterfaceAddDelAddressReply)
215
216         fmt.Printf("Added IP address to interface: %v (return value: %d)\n", index, recvMsg.Retval)
217         fmt.Println("OK")
218         fmt.Println()
219 }
220
221 func ipAddressDumpStream(stream api.Stream, index interface_types.InterfaceIndex) {
222         fmt.Printf("Dumping IP addresses for interface index %d..\n", index)
223
224         if err := stream.SendMsg(&ip.IPAddressDump{
225                 SwIfIndex: index,
226         }); err != nil {
227                 logError(err, "IPAddressDump sending message")
228                 return
229         }
230         if err := stream.SendMsg(&vpe.ControlPing{}); err != nil {
231                 logError(err, "ControlPing sending sending message")
232                 return
233         }
234
235 Loop:
236         for {
237                 msg, err := stream.RecvMsg()
238                 if err != nil {
239                         logError(err, "IPAddressDump receiving message ")
240                         return
241                 }
242
243                 switch msg.(type) {
244                 case *ip.IPAddressDetails:
245                         fmt.Printf(" - IPAddressDetails: %+v\n", msg)
246
247                 case *vpe.ControlPingReply:
248                         fmt.Printf(" - ControlPingReply: %+v\n", msg)
249                         break Loop
250
251                 default:
252                         logError(err, "unexpected message")
253                         return
254                 }
255         }
256
257         fmt.Println("OK")
258         fmt.Println()
259 }
260
261 // Mactime dump uses MactimeDumpReply message as an end of the stream
262 // notification instead of the control ping.
263 func mactimeDump(stream api.Stream, ) {
264         fmt.Println("Sending mactime dump..")
265
266         if err := stream.SendMsg(&mactime.MactimeDump{}); err != nil {
267                 logError(err, "sending mactime dump")
268                 return
269         }
270
271 Loop:
272         for {
273                 msg, err := stream.RecvMsg()
274                 if err != nil {
275                         logError(err, "MactimeDump receiving message")
276                         return
277                 }
278
279                 switch msg.(type) {
280                 case *mactime.MactimeDetails:
281                         fmt.Printf(" - MactimeDetails: %+v\n", msg)
282
283                 case *mactime.MactimeDumpReply:
284                         fmt.Printf(" - MactimeDumpReply: %+v\n", msg)
285                         break Loop
286
287                 default:
288                         logError(err, "unexpected message")
289                         return
290                 }
291         }
292
293         fmt.Println("OK")
294         fmt.Println()
295 }
296
297 var errors []error
298
299 func logError(err error, msg string) {
300         fmt.Printf("ERROR: %s: %v\n", msg, err)
301         errors = append(errors, err)
302 }