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 "go.fd.io/govpp/adapter/socketclient"
30 interfaces "go.fd.io/govpp/binapi/interface"
31 "go.fd.io/govpp/binapi/interface_types"
32 "go.fd.io/govpp/binapi/ip"
33 "go.fd.io/govpp/binapi/ip_types"
34 "go.fd.io/govpp/binapi/mactime"
35 "go.fd.io/govpp/binapi/memclnt"
36 "go.fd.io/govpp/binapi/vpe"
41 sockAddr = flag.String("sock", socketclient.DefaultSocketName, "Path to VPP binary API socket file")
47 fmt.Println("Starting stream client example")
50 // connect to VPP asynchronously
51 conn, connEv, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
53 log.Fatalln("ERROR:", err)
55 defer conn.Disconnect()
57 // wait for Connected event
60 if e.State != core.Connected {
61 log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
65 // check compatibility of used messages
66 ch, err := conn.NewAPIChannel()
68 log.Fatalln("ERROR: creating channel failed:", err)
71 if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
74 if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
78 // process errors encountered during the example
81 fmt.Printf("finished with %d errors\n", len(errors))
84 fmt.Println("finished successfully")
88 // send and receive messages using stream (low-low level API)
89 stream, err := conn.NewStream(context.Background(),
90 core.WithRequestSize(50),
91 core.WithReplySize(50),
92 core.WithReplyTimeout(2*time.Second))
97 if err := stream.Close(); err != nil {
98 logError(err, "closing the stream")
101 getVppVersionStream(stream)
102 idx := createLoopbackStream(stream)
103 interfaceDumpStream(stream)
104 addIPAddressStream(stream, idx)
105 ipAddressDumpStream(stream, idx)
110 func getVppVersionStream(stream api.Stream) {
111 fmt.Println("Retrieving version..")
113 req := &vpe.ShowVersion{}
114 if err := stream.SendMsg(req); err != nil {
115 logError(err, "ShowVersion sending message")
118 recv, err := stream.RecvMsg()
120 logError(err, "ShowVersion receive message")
123 recvMsg := recv.(*vpe.ShowVersionReply)
125 fmt.Printf("Retrieved VPP version: %q\n", recvMsg.Version)
130 func createLoopbackStream(stream api.Stream) (ifIdx interface_types.InterfaceIndex) {
131 fmt.Println("Creating the loopback interface..")
133 req := &interfaces.CreateLoopback{}
134 if err := stream.SendMsg(req); err != nil {
135 logError(err, "CreateLoopback sending message")
138 recv, err := stream.RecvMsg()
140 logError(err, "CreateLoopback receive message")
143 recvMsg := recv.(*interfaces.CreateLoopbackReply)
145 fmt.Printf("Loopback interface index: %v\n", recvMsg.SwIfIndex)
149 return recvMsg.SwIfIndex
152 func interfaceDumpStream(stream api.Stream) {
153 fmt.Println("Dumping interfaces..")
155 if err := stream.SendMsg(&interfaces.SwInterfaceDump{
156 SwIfIndex: ^interface_types.InterfaceIndex(0),
158 logError(err, "SwInterfaceDump sending message")
161 if err := stream.SendMsg(&memclnt.ControlPing{}); err != nil {
162 logError(err, "ControlPing sending message")
168 msg, err := stream.RecvMsg()
170 logError(err, "SwInterfaceDump receiving message ")
175 case *interfaces.SwInterfaceDetails:
176 fmt.Printf(" - SwInterfaceDetails: %+v\n", msg)
178 case *memclnt.ControlPingReply:
179 fmt.Printf(" - ControlPingReply: %+v\n", msg)
183 logError(err, "unexpected message")
192 func addIPAddressStream(stream api.Stream, index interface_types.InterfaceIndex) {
193 fmt.Printf("Adding IP address to the interface index %d..\n", index)
195 if err := stream.SendMsg(&interfaces.SwInterfaceAddDelAddress{
198 Prefix: ip_types.AddressWithPrefix{
199 Address: ip_types.Address{
200 Af: ip_types.ADDRESS_IP4,
201 Un: ip_types.AddressUnionIP4(ip_types.IP4Address{10, 10, 0, uint8(index)}),
206 logError(err, "SwInterfaceAddDelAddress sending message")
210 recv, err := stream.RecvMsg()
212 logError(err, "SwInterfaceAddDelAddressReply receiving message")
215 recvMsg := recv.(*interfaces.SwInterfaceAddDelAddressReply)
217 fmt.Printf("Added IP address to interface: %v (return value: %d)\n", index, recvMsg.Retval)
222 func ipAddressDumpStream(stream api.Stream, index interface_types.InterfaceIndex) {
223 fmt.Printf("Dumping IP addresses for interface index %d..\n", index)
225 if err := stream.SendMsg(&ip.IPAddressDump{
228 logError(err, "IPAddressDump sending message")
231 if err := stream.SendMsg(&memclnt.ControlPing{}); err != nil {
232 logError(err, "ControlPing sending sending message")
238 msg, err := stream.RecvMsg()
240 logError(err, "IPAddressDump receiving message ")
245 case *ip.IPAddressDetails:
246 fmt.Printf(" - IPAddressDetails: %+v\n", msg)
248 case *memclnt.ControlPingReply:
249 fmt.Printf(" - ControlPingReply: %+v\n", msg)
253 logError(err, "unexpected message")
262 // Mactime dump uses MactimeDumpReply message as an end of the stream
263 // notification instead of the control ping.
264 func mactimeDump(stream api.Stream) {
265 fmt.Println("Sending mactime dump..")
267 if err := stream.SendMsg(&mactime.MactimeDump{}); err != nil {
268 logError(err, "sending mactime dump")
274 msg, err := stream.RecvMsg()
276 logError(err, "MactimeDump receiving message")
281 case *mactime.MactimeDetails:
282 fmt.Printf(" - MactimeDetails: %+v\n", msg)
284 case *mactime.MactimeDumpReply:
285 fmt.Printf(" - MactimeDumpReply: %+v\n", msg)
289 logError(err, "unexpected message")
300 func logError(err error, msg string) {
301 fmt.Printf("ERROR: %s: %v\n", msg, err)
302 errors = append(errors, err)