6030469e1a99d76d50f6bb1b19ba79a146ec5538
[govpp.git] / examples / example_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 // Example VPP management application that exercises the govpp API on real-world use-cases.
16 package main
17
18 // Generates Go bindings for all VPP APIs located in the json directory.
19 //go:generate binapi_generator --input-dir=bin_api --output-dir=bin_api
20
21 import (
22         "fmt"
23         "net"
24         "os"
25         "os/signal"
26
27         "git.fd.io/govpp.git"
28         "git.fd.io/govpp.git/api"
29         "git.fd.io/govpp.git/api/ifcounters"
30         "git.fd.io/govpp.git/core/bin_api/vpe"
31         "git.fd.io/govpp.git/examples/bin_api/acl"
32         "git.fd.io/govpp.git/examples/bin_api/interfaces"
33         "git.fd.io/govpp.git/examples/bin_api/tap"
34 )
35
36 func main() {
37         fmt.Println("Starting example VPP client...")
38
39         // connect to VPP and create an API channel that will be used in the examples
40         conn, _ := govpp.Connect()
41         defer conn.Disconnect()
42
43         ch, _ := conn.NewAPIChannel()
44         defer ch.Close()
45
46         // check whether the VPP supports our version of some messages
47         compatibilityCheck(ch)
48
49         // individual examples
50         aclVersion(ch)
51         aclConfig(ch)
52         aclDump(ch)
53
54         tapConnect(ch)
55
56         interfaceDump(ch)
57         interfaceNotifications(ch)
58
59         //interfaceCounters(ch)
60 }
61
62 // compatibilityCheck shows how an management application can check whether generated API messages are
63 // compatible with the version of VPP which the library is connected to.
64 func compatibilityCheck(ch *api.Channel) {
65         err := ch.CheckMessageCompatibility(
66                 &interfaces.SwInterfaceDump{},
67                 &interfaces.SwInterfaceDetails{},
68         )
69         if err != nil {
70                 fmt.Println(err)
71                 os.Exit(1)
72         }
73 }
74
75 // aclVersion is the simplest API example - one empty request message and one reply message.
76 func aclVersion(ch *api.Channel) {
77         req := &acl.ACLPluginGetVersion{}
78         reply := &acl.ACLPluginGetVersionReply{}
79
80         err := ch.SendRequest(req).ReceiveReply(reply)
81
82         if err != nil {
83                 fmt.Println("Error:", err)
84         } else {
85                 fmt.Printf("%+v\n", reply)
86         }
87 }
88
89 // aclConfig is another simple API example - in this case, the request contains structured data.
90 func aclConfig(ch *api.Channel) {
91         req := &acl.ACLAddReplace{
92                 ACLIndex: ^uint32(0),
93                 Tag:      []byte("access list 1"),
94                 R: []acl.ACLRule{
95                         {
96                                 IsPermit:       1,
97                                 SrcIPAddr:      net.ParseIP("10.0.0.0").To4(),
98                                 SrcIPPrefixLen: 8,
99                                 DstIPAddr:      net.ParseIP("192.168.1.0").To4(),
100                                 DstIPPrefixLen: 24,
101                                 Proto:          6,
102                         },
103                         {
104                                 IsPermit:       1,
105                                 SrcIPAddr:      net.ParseIP("8.8.8.8").To4(),
106                                 SrcIPPrefixLen: 32,
107                                 DstIPAddr:      net.ParseIP("172.16.0.0").To4(),
108                                 DstIPPrefixLen: 16,
109                                 Proto:          6,
110                         },
111                 },
112         }
113         reply := &acl.ACLAddReplaceReply{}
114
115         err := ch.SendRequest(req).ReceiveReply(reply)
116
117         if err != nil {
118                 fmt.Println("Error:", err)
119         } else {
120                 fmt.Printf("%+v\n", reply)
121         }
122 }
123
124 // aclDump shows an example where SendRequest and ReceiveReply are not chained together.
125 func aclDump(ch *api.Channel) {
126         req := &acl.ACLDump{}
127         reply := &acl.ACLDetails{}
128
129         reqCtx := ch.SendRequest(req)
130         err := reqCtx.ReceiveReply(reply)
131
132         if err != nil {
133                 fmt.Println("Error:", err)
134         } else {
135                 fmt.Printf("%+v\n", reply)
136         }
137 }
138
139 // tapConnect example shows how the Go channels in the API channel can be accessed directly instead
140 // of using SendRequest and ReceiveReply wrappers.
141 func tapConnect(ch *api.Channel) {
142         req := &tap.TapConnect{
143                 TapName:      []byte("testtap"),
144                 UseRandomMac: 1,
145         }
146
147         // send the request to the request go channel
148         ch.ReqChan <- &api.VppRequest{Message: req}
149
150         // receive a reply from the reply go channel
151         vppReply := <-ch.ReplyChan
152         if vppReply.Error != nil {
153                 fmt.Println("Error:", vppReply.Error)
154                 return
155         }
156
157         // decode the message
158         reply := &tap.TapConnectReply{}
159         err := ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
160
161         if err != nil {
162                 fmt.Println("Error:", err)
163         } else {
164                 fmt.Printf("%+v\n", reply)
165         }
166 }
167
168 // interfaceDump shows an example of multipart request (multiple replies are expected).
169 func interfaceDump(ch *api.Channel) {
170         req := &interfaces.SwInterfaceDump{}
171         reqCtx := ch.SendMultiRequest(req)
172
173         for {
174                 msg := &interfaces.SwInterfaceDetails{}
175                 stop, err := reqCtx.ReceiveReply(msg)
176                 if stop {
177                         break // break out of the loop
178                 }
179                 if err != nil {
180                         fmt.Println("Error:", err)
181                 }
182                 fmt.Printf("%+v\n", msg)
183         }
184 }
185
186 // interfaceNotifications shows the usage of notification API. Note that for notifications,
187 // you are supposed to create your own Go channel with your preferred buffer size. If the channel's
188 // buffer is full, the notifications will not be delivered into it.
189 func interfaceNotifications(ch *api.Channel) {
190         // subscribe for specific notification message
191         notifChan := make(chan api.Message, 100)
192         subs, _ := ch.SubscribeNotification(notifChan, interfaces.NewSwInterfaceSetFlags)
193
194         // enable interface events in VPP
195         ch.SendRequest(&interfaces.WantInterfaceEvents{
196                 Pid:           uint32(os.Getpid()),
197                 EnableDisable: 1,
198         }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
199
200         // generate some events in VPP
201         ch.SendRequest(&interfaces.SwInterfaceSetFlags{
202                 SwIfIndex:   0,
203                 AdminUpDown: 0,
204         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
205         ch.SendRequest(&interfaces.SwInterfaceSetFlags{
206                 SwIfIndex:   0,
207                 AdminUpDown: 1,
208         }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
209
210         // receive one notification
211         notif := (<-notifChan).(*interfaces.SwInterfaceSetFlags)
212         fmt.Printf("%+v\n", notif)
213
214         // unsubscribe from delivery of the notifications
215         ch.UnsubscribeNotification(subs)
216 }
217
218 // interfaceCounters is an example of using notification API to periodically retrieve interface statistics.
219 // The ifcounters package contains the API that can be used to decode the strange VnetInterfaceCounters message.
220 func interfaceCounters(ch *api.Channel) {
221         // subscribe for interface counters notifications
222         notifChan := make(chan api.Message, 100)
223         subs, _ := ch.SubscribeNotification(notifChan, interfaces.NewVnetInterfaceCounters)
224
225         // enable interface counters notifications from VPP
226         ch.SendRequest(&vpe.WantStats{
227                 Pid:           uint32(os.Getpid()),
228                 EnableDisable: 1,
229         }).ReceiveReply(&vpe.WantStatsReply{})
230
231         // create channel for Interrupt signal
232         sigChan := make(chan os.Signal, 1)
233         signal.Notify(sigChan, os.Interrupt)
234
235         // loop until Interrupt signal is received
236 loop:
237         for {
238                 select {
239                 case <-sigChan:
240                         // interrupt received
241                         break loop
242                 case notifMsg := <-notifChan:
243                         notif := notifMsg.(*interfaces.VnetInterfaceCounters)
244                         // notification received
245                         fmt.Printf("%+v\n", notif)
246
247                         if notif.IsCombined == 0 {
248                                 // simple counter
249                                 counters, err := ifcounters.DecodeCounters(ifcounters.VnetInterfaceCounters(*notif))
250                                 if err != nil {
251                                         fmt.Println("Error:", err)
252                                 } else {
253                                         fmt.Printf("%+v\n", counters)
254                                 }
255                         } else {
256                                 // combined counter
257                                 counters, err := ifcounters.DecodeCombinedCounters(ifcounters.VnetInterfaceCounters(*notif))
258                                 if err != nil {
259                                         fmt.Println("Error:", err)
260                                 } else {
261                                         fmt.Printf("%+v\n", counters)
262                                 }
263                         }
264                 }
265         }
266
267         // unsubscribe from delivery of the notifications
268         ch.UnsubscribeNotification(subs)
269 }