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 // stream-client is an example VPP management application that exercises the
16 // govpp API on real-world use-cases.
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"
40 sockAddr = flag.String("sock", socketclient.DefaultSocketName, "Path to VPP binary API socket file")
46 fmt.Println("Starting stream client example")
49 // connect to VPP asynchronously
50 conn, connEv, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
52 log.Fatalln("ERROR:", err)
54 defer conn.Disconnect()
56 // wait for Connected event
59 if e.State != core.Connected {
60 log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
64 // check compatibility of used messages
65 ch, err := conn.NewAPIChannel()
67 log.Fatalln("ERROR: creating channel failed:", err)
70 if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
73 if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
77 // process errors encountered during the example
80 fmt.Printf("finished with %d errors\n", len(errors))
83 fmt.Println("finished successfully")
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))
96 if err := stream.Close(); err != nil {
97 logError(err, "closing the stream")
100 getVppVersionStream(stream)
101 idx := createLoopbackStream(stream)
102 interfaceDumpStream(stream)
103 addIPAddressStream(stream, idx)
104 ipAddressDumpStream(stream, idx)
109 func getVppVersionStream(stream api.Stream) {
110 fmt.Println("Retrieving version..")
112 req := &vpe.ShowVersion{}
113 if err := stream.SendMsg(req); err != nil {
114 logError(err, "ShowVersion sending message")
117 recv, err := stream.RecvMsg()
119 logError(err, "ShowVersion receive message")
122 recvMsg := recv.(*vpe.ShowVersionReply)
124 fmt.Printf("Retrieved VPP version: %q\n", recvMsg.Version)
129 func createLoopbackStream(stream api.Stream) (ifIdx interface_types.InterfaceIndex) {
130 fmt.Println("Creating the loopback interface..")
132 req := &interfaces.CreateLoopback{}
133 if err := stream.SendMsg(req); err != nil {
134 logError(err, "CreateLoopback sending message")
137 recv, err := stream.RecvMsg()
139 logError(err, "CreateLoopback receive message")
142 recvMsg := recv.(*interfaces.CreateLoopbackReply)
144 fmt.Printf("Loopback interface index: %v\n", recvMsg.SwIfIndex)
148 return recvMsg.SwIfIndex
151 func interfaceDumpStream(stream api.Stream) {
152 fmt.Println("Dumping interfaces..")
154 if err := stream.SendMsg(&interfaces.SwInterfaceDump{
155 SwIfIndex: ^interface_types.InterfaceIndex(0),
157 logError(err, "SwInterfaceDump sending message")
160 if err := stream.SendMsg(&vpe.ControlPing{}); err != nil {
161 logError(err, "ControlPing sending message")
167 msg, err := stream.RecvMsg()
169 logError(err, "SwInterfaceDump receiving message ")
174 case *interfaces.SwInterfaceDetails:
175 fmt.Printf(" - SwInterfaceDetails: %+v\n", msg)
177 case *vpe.ControlPingReply:
178 fmt.Printf(" - ControlPingReply: %+v\n", msg)
182 logError(err, "unexpected message")
191 func addIPAddressStream(stream api.Stream, index interface_types.InterfaceIndex) {
192 fmt.Printf("Adding IP address to the interface index %d..\n", index)
194 if err := stream.SendMsg(&interfaces.SwInterfaceAddDelAddress{
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)}),
205 logError(err, "SwInterfaceAddDelAddress sending message")
209 recv, err := stream.RecvMsg()
211 logError(err, "SwInterfaceAddDelAddressReply receiving message")
214 recvMsg := recv.(*interfaces.SwInterfaceAddDelAddressReply)
216 fmt.Printf("Added IP address to interface: %v (return value: %d)\n", index, recvMsg.Retval)
221 func ipAddressDumpStream(stream api.Stream, index interface_types.InterfaceIndex) {
222 fmt.Printf("Dumping IP addresses for interface index %d..\n", index)
224 if err := stream.SendMsg(&ip.IPAddressDump{
227 logError(err, "IPAddressDump sending message")
230 if err := stream.SendMsg(&vpe.ControlPing{}); err != nil {
231 logError(err, "ControlPing sending sending message")
237 msg, err := stream.RecvMsg()
239 logError(err, "IPAddressDump receiving message ")
244 case *ip.IPAddressDetails:
245 fmt.Printf(" - IPAddressDetails: %+v\n", msg)
247 case *vpe.ControlPingReply:
248 fmt.Printf(" - ControlPingReply: %+v\n", msg)
252 logError(err, "unexpected message")
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..")
266 if err := stream.SendMsg(&mactime.MactimeDump{}); err != nil {
267 logError(err, "sending mactime dump")
273 msg, err := stream.RecvMsg()
275 logError(err, "MactimeDump receiving message")
280 case *mactime.MactimeDetails:
281 fmt.Printf(" - MactimeDetails: %+v\n", msg)
283 case *mactime.MactimeDumpReply:
284 fmt.Printf(" - MactimeDumpReply: %+v\n", msg)
288 logError(err, "unexpected message")
299 func logError(err error, msg string) {
300 fmt.Printf("ERROR: %s: %v\n", msg, err)
301 errors = append(errors, err)