fix govpp, add more checks to makefile
[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         "fmt"
21         "log"
22         "net"
23         "os"
24         "strings"
25
26         "git.fd.io/govpp.git"
27         "git.fd.io/govpp.git/api"
28         "git.fd.io/govpp.git/core"
29         "git.fd.io/govpp.git/examples/bin_api/acl"
30         "git.fd.io/govpp.git/examples/bin_api/interfaces"
31         "git.fd.io/govpp.git/examples/bin_api/ip"
32 )
33
34 func main() {
35         fmt.Println("Starting simple VPP client...")
36
37         // connect to VPP
38         conn, conev, err := govpp.AsyncConnect("", core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
39         if err != nil {
40                 log.Fatalln("ERROR:", err)
41         }
42         defer conn.Disconnect()
43
44         select {
45         case e := <-conev:
46                 if e.State != core.Connected {
47                         log.Fatalf("failed to connect: %v", e.Error)
48                 }
49         }
50
51         // create an API channel that will be used in the examples
52         ch, err := conn.NewAPIChannel()
53         if err != nil {
54                 log.Fatalln("ERROR:", err)
55         }
56         defer ch.Close()
57
58         // individual examples
59         aclVersion(ch)
60         aclConfig(ch)
61         aclDump(ch)
62
63         interfaceDump(ch)
64         ipAddressDump(ch)
65
66         setIpUnnumbered(ch)
67         ipUnnumberedDump(ch)
68
69         interfaceNotifications(ch)
70 }
71
72 // aclVersion is the simplest API example - one empty request message and one reply message.
73 func aclVersion(ch api.Channel) {
74         fmt.Println("ACL getting version")
75
76         req := &acl.ACLPluginGetVersion{}
77         reply := &acl.ACLPluginGetVersionReply{}
78
79         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
80                 fmt.Println("ERROR:", err)
81         } else {
82                 fmt.Printf("ACL version reply: %+v\n", reply)
83         }
84 }
85
86 // aclConfig is another simple API example - in this case, the request contains structured data.
87 func aclConfig(ch api.Channel) {
88         fmt.Println("ACL adding replace")
89
90         req := &acl.ACLAddReplace{
91                 ACLIndex: ^uint32(0),
92                 Tag:      []byte("access list 1"),
93                 R: []acl.ACLRule{
94                         {
95                                 IsPermit:       1,
96                                 SrcIPAddr:      net.ParseIP("10.0.0.0").To4(),
97                                 SrcIPPrefixLen: 8,
98                                 DstIPAddr:      net.ParseIP("192.168.1.0").To4(),
99                                 DstIPPrefixLen: 24,
100                                 Proto:          6,
101                         },
102                         {
103                                 IsPermit:       1,
104                                 SrcIPAddr:      net.ParseIP("8.8.8.8").To4(),
105                                 SrcIPPrefixLen: 32,
106                                 DstIPAddr:      net.ParseIP("172.16.0.0").To4(),
107                                 DstIPPrefixLen: 16,
108                                 Proto:          6,
109                         },
110                 },
111         }
112         reply := &acl.ACLAddReplaceReply{}
113
114         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
115                 fmt.Println("ERROR:", err)
116                 return
117         }
118         if reply.Retval != 0 {
119                 fmt.Println("Retval:", reply.Retval)
120                 return
121         }
122
123         fmt.Printf("ACL add replace reply: %+v\n", reply)
124
125 }
126
127 // aclDump shows an example where SendRequest and ReceiveReply are not chained together.
128 func aclDump(ch api.Channel) {
129         fmt.Println("Dumping ACL")
130
131         req := &acl.ACLDump{}
132         reply := &acl.ACLDetails{}
133
134         reqCtx := ch.SendRequest(req)
135
136         if err := reqCtx.ReceiveReply(reply); err != nil {
137                 fmt.Println("ERROR:", err)
138         } else {
139                 fmt.Printf("ACL details: %+v\n", reply)
140         }
141 }
142
143 // interfaceDump shows an example of multipart request (multiple replies are expected).
144 func interfaceDump(ch api.Channel) {
145         fmt.Println("Dumping interfaces")
146
147         reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
148
149         for {
150                 msg := &interfaces.SwInterfaceDetails{}
151                 stop, err := reqCtx.ReceiveReply(msg)
152                 if stop {
153                         break
154                 }
155                 if err != nil {
156                         fmt.Println("ERROR:", err)
157                 }
158                 ifaceName := strings.TrimFunc(string(msg.InterfaceName), func(r rune) bool {
159                         return r == 0x00
160                 })
161                 fmt.Printf("Interface %q: %+v\n", ifaceName, msg)
162         }
163 }
164
165 func ipAddressDump(ch api.Channel) {
166         fmt.Println("Dumping IP addresses")
167
168         req := &ip.IPAddressDump{
169                 SwIfIndex: 1, //^uint32(0),
170         }
171         reqCtx := ch.SendMultiRequest(req)
172
173         for {
174                 msg := &ip.IPAddressDetails{}
175                 stop, err := reqCtx.ReceiveReply(msg)
176                 if stop {
177                         break
178                 }
179                 if err != nil {
180                         fmt.Println("ERROR:", err)
181                 }
182                 fmt.Printf("ip address details: %d %+v\n", msg.SwIfIndex, msg)
183         }
184 }
185
186 // aclDump shows an example where SendRequest and ReceiveReply are not chained together.
187 func setIpUnnumbered(ch api.Channel) {
188         req := &interfaces.SwInterfaceSetUnnumbered{
189                 SwIfIndex:           1,
190                 UnnumberedSwIfIndex: 2,
191                 IsAdd:               1,
192         }
193         reply := &interfaces.SwInterfaceSetUnnumberedReply{}
194
195         if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
196                 fmt.Println("ERROR:", err)
197         } else {
198                 fmt.Printf("%+v\n", reply)
199         }
200 }
201
202 func ipUnnumberedDump(ch api.Channel) {
203         fmt.Println("Dumping IP unnumbered")
204
205         reqCtx := ch.SendMultiRequest(&ip.IPUnnumberedDump{
206                 SwIfIndex: ^uint32(0),
207         })
208
209         for {
210                 msg := &ip.IPUnnumberedDetails{}
211                 stop, err := reqCtx.ReceiveReply(msg)
212                 if stop {
213                         break
214                 }
215                 if err != nil {
216                         fmt.Println("ERROR:", err)
217                 }
218                 fmt.Printf("IP unnumbered details: %+v\n", msg)
219         }
220 }
221
222 // interfaceNotifications shows the usage of notification API. Note that for notifications,
223 // you are supposed to create your own Go channel with your preferred buffer size. If the channel's
224 // buffer is full, the notifications will not be delivered into it.
225 func interfaceNotifications(ch api.Channel) {
226         fmt.Println("Subscribing to notificaiton events")
227
228         notifChan := make(chan api.Message, 100)
229
230         // subscribe for specific notification message
231         sub, err := ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{})
232         if err != nil {
233                 panic(err)
234         }
235
236         // enable interface events in VPP
237         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
238                 PID:           uint32(os.Getpid()),
239                 EnableDisable: 1,
240         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
241         if err != nil {
242                 panic(err)
243         }
244
245         // generate some events in VPP
246         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
247                 SwIfIndex:   0,
248                 AdminUpDown: 0,
249         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
250         if err != nil {
251                 panic(err)
252         }
253         err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
254                 SwIfIndex:   0,
255                 AdminUpDown: 1,
256         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
257         if err != nil {
258                 panic(err)
259         }
260
261         // receive one notification
262         notif := (<-notifChan).(*interfaces.SwInterfaceEvent)
263         fmt.Printf("incoming event: %+v\n", notif)
264
265         // disable interface events in VPP
266         err = ch.SendRequest(&interfaces.WantInterfaceEvents{
267                 PID:           uint32(os.Getpid()),
268                 EnableDisable: 0,
269         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
270         if err != nil {
271                 panic(err)
272         }
273
274         // unsubscribe from delivery of the notifications
275         err = sub.Unsubscribe()
276         if err != nil {
277                 panic(err)
278         }
279 }