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