1 // Copyright (c) 2017 Cisco and/or its affiliates.
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:
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 // simple-client is an example VPP management application that exercises the
16 // govpp API on real-world use-cases.
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"
38 sockAddr = flag.String("sock", socketclient.DefaultSocketName, "Path to VPP binary API socket file")
44 fmt.Println("Starting simple client example")
47 // connect to VPP asynchronously
48 conn, connEv, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
50 log.Fatalln("ERROR:", err)
52 defer conn.Disconnect()
54 // wait for Connected event
57 if e.State != core.Connected {
58 log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
62 // check compatibility of used messages
63 ch, err := conn.NewAPIChannel()
65 log.Fatalln("ERROR: creating channel failed:", err)
68 if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
71 if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
75 // process errors encountered during the example
78 fmt.Printf("finished with %d errors\n", len(errors))
81 fmt.Println("finished successfully")
85 // use request/reply (channel API)
88 idx := createLoopback(ch)
91 ipAddressDump(ch, idx)
92 interfaceNotifications(ch, idx)
95 func getVppVersion(ch api.Channel) {
96 fmt.Println("Retrieving version..")
98 req := &vpe.ShowVersion{}
99 reply := &vpe.ShowVersionReply{}
101 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
102 logError(err, "retrieving version")
106 fmt.Printf("VPP version: %q\n", reply.Version)
111 func getSystemTime(ch api.Channel) {
112 fmt.Println("Retrieving system time..")
114 req := &vpe.ShowVpeSystemTime{}
115 reply := &vpe.ShowVpeSystemTimeReply{}
117 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
118 logError(err, "retrieving system time")
122 fmt.Printf("system time: %v\n", reply.VpeSystemTime)
127 func createLoopback(ch api.Channel) interface_types.InterfaceIndex {
128 fmt.Println("Creating loopback interface..")
130 req := &interfaces.CreateLoopback{}
131 reply := &interfaces.CreateLoopbackReply{}
133 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
134 logError(err, "creating loopback interface")
138 fmt.Printf("interface index: %v\n", reply.SwIfIndex)
142 return reply.SwIfIndex
145 func interfaceDump(ch api.Channel) {
146 fmt.Println("Dumping interfaces..")
149 reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{
150 SwIfIndex: ^interface_types.InterfaceIndex(0),
153 msg := &interfaces.SwInterfaceDetails{}
154 stop, err := reqCtx.ReceiveReply(msg)
159 logError(err, "dumping interfaces")
163 fmt.Printf(" - interface #%d: %+v\n", n, msg)
171 func addIPAddress(ch api.Channel, index interface_types.InterfaceIndex) {
172 fmt.Printf("Adding IP address to interface index %d\n", index)
174 req := &interfaces.SwInterfaceAddDelAddress{
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)}),
186 reply := &interfaces.SwInterfaceAddDelAddressReply{}
188 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
189 logError(err, "adding IP address to interface")
197 func ipAddressDump(ch api.Channel, index interface_types.InterfaceIndex) {
198 fmt.Printf("Dumping IP addresses for interface index %d..\n", index)
200 req := &ip.IPAddressDump{
203 reqCtx := ch.SendMultiRequest(req)
206 msg := &ip.IPAddressDetails{}
207 stop, err := reqCtx.ReceiveReply(msg)
209 logError(err, "dumping IP addresses")
215 fmt.Printf(" - ip address: %+v\n", msg)
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)
229 notifChan := make(chan api.Message, 100)
231 // subscribe for specific notification message
232 sub, err := ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{})
234 logError(err, "subscribing to interface events")
238 // enable interface events in VPP
239 err = ch.SendRequest(&interfaces.WantInterfaceEvents{
240 PID: uint32(os.Getpid()),
242 }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
244 logError(err, "enabling interface events")
248 // receive notifications
250 for notif := range notifChan {
251 e := notif.(*interfaces.SwInterfaceEvent)
252 fmt.Printf("incoming event: %+v\n", e)
257 // generate some events in VPP
258 err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
260 Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
261 }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
263 logError(err, "setting interface flags")
266 err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
269 }).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
271 logError(err, "setting interface flags")
275 // disable interface events in VPP
276 err = ch.SendRequest(&interfaces.WantInterfaceEvents{
277 PID: uint32(os.Getpid()),
279 }).ReceiveReply(&interfaces.WantInterfaceEventsReply{})
281 logError(err, "setting interface flags")
285 // unsubscribe from delivery of the notifications
286 err = sub.Unsubscribe()
288 logError(err, "unsubscribing from interface events")
296 func marshal(v interface{}) {
297 fmt.Printf("GO: %#v\n", v)
298 b, err := json.MarshalIndent(v, "", " ")
302 fmt.Printf("JSON: %s\n", b)
307 func logError(err error, msg string) {
308 fmt.Printf("ERROR: %s: %v\n", msg, err)
309 errors = append(errors, err)