aboutsummaryrefslogtreecommitdiffstats
path: root/examples/stream-client/stream_client.go
diff options
context:
space:
mode:
Diffstat (limited to 'examples/stream-client/stream_client.go')
-rw-r--r--examples/stream-client/stream_client.go302
1 files changed, 302 insertions, 0 deletions
diff --git a/examples/stream-client/stream_client.go b/examples/stream-client/stream_client.go
new file mode 100644
index 0000000..fadfe23
--- /dev/null
+++ b/examples/stream-client/stream_client.go
@@ -0,0 +1,302 @@
+// Copyright (c) 2017 Cisco and/or its affiliates.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// stream-client is an example VPP management application that exercises the
+// govpp API on real-world use-cases.
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "time"
+
+ "git.fd.io/govpp.git"
+ "git.fd.io/govpp.git/adapter/socketclient"
+ "git.fd.io/govpp.git/api"
+ interfaces "git.fd.io/govpp.git/binapi/interface"
+ "git.fd.io/govpp.git/binapi/interface_types"
+ "git.fd.io/govpp.git/binapi/ip"
+ "git.fd.io/govpp.git/binapi/ip_types"
+ "git.fd.io/govpp.git/binapi/mactime"
+ "git.fd.io/govpp.git/binapi/vpe"
+ "git.fd.io/govpp.git/core"
+)
+
+var (
+ sockAddr = flag.String("sock", socketclient.DefaultSocketName, "Path to VPP binary API socket file")
+)
+
+func main() {
+ flag.Parse()
+
+ fmt.Println("Starting stream client example")
+ fmt.Println()
+
+ // connect to VPP asynchronously
+ conn, connEv, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
+ if err != nil {
+ log.Fatalln("ERROR:", err)
+ }
+ defer conn.Disconnect()
+
+ // wait for Connected event
+ select {
+ case e := <-connEv:
+ if e.State != core.Connected {
+ log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
+ }
+ }
+
+ // check compatibility of used messages
+ ch, err := conn.NewAPIChannel()
+ if err != nil {
+ log.Fatalln("ERROR: creating channel failed:", err)
+ }
+ defer ch.Close()
+ if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
+ log.Fatal(err)
+ }
+ if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
+ log.Fatal(err)
+ }
+
+ // process errors encountered during the example
+ defer func() {
+ if len(Errors) > 0 {
+ fmt.Printf("finished with %d errors\n", len(Errors))
+ os.Exit(1)
+ } else {
+ fmt.Println("finished successfully")
+ }
+ }()
+
+ // send and receive messages using stream (low-low level API)
+ stream, err := conn.NewStream(context.Background(),
+ core.WithRequestSize(50),
+ core.WithReplySize(50),
+ core.WithReplyTimeout(2*time.Second))
+ if err != nil {
+ panic(err)
+ }
+ defer func() {
+ if err := stream.Close(); err != nil {
+ logError(err, "closing the stream")
+ }
+ }()
+ getVppVersionStream(stream)
+ idx := createLoopbackStream(stream)
+ interfaceDumpStream(stream)
+ addIPAddressStream(stream, idx)
+ ipAddressDumpStream(stream, idx)
+ mactimeDump(stream)
+ return
+}
+
+func getVppVersionStream(stream api.Stream) {
+ fmt.Println("Retrieving version..")
+
+ req := &vpe.ShowVersion{}
+ if err := stream.SendMsg(req); err != nil {
+ logError(err, "ShowVersion sending message")
+ return
+ }
+ recv, err := stream.RecvMsg()
+ if err != nil {
+ logError(err, "ShowVersion receive message")
+ return
+ }
+ recvMsg := recv.(*vpe.ShowVersionReply)
+
+ fmt.Printf("Retrieved VPP version: %q\n", recvMsg.Version)
+ fmt.Println("OK")
+ fmt.Println()
+}
+
+func createLoopbackStream(stream api.Stream) (ifIdx interface_types.InterfaceIndex) {
+ fmt.Println("Creating the loopback interface..")
+
+ req := &interfaces.CreateLoopback{}
+ if err := stream.SendMsg(req); err != nil {
+ logError(err, "CreateLoopback sending message")
+ return
+ }
+ recv, err := stream.RecvMsg()
+ if err != nil {
+ logError(err, "CreateLoopback receive message")
+ return
+ }
+ recvMsg := recv.(*interfaces.CreateLoopbackReply)
+
+ fmt.Printf("Loopback interface index: %v\n", recvMsg.SwIfIndex)
+ fmt.Println("OK")
+ fmt.Println()
+
+ return recvMsg.SwIfIndex
+}
+
+func interfaceDumpStream(stream api.Stream) {
+ fmt.Println("Dumping interfaces..")
+
+ if err := stream.SendMsg(&interfaces.SwInterfaceDump{
+ SwIfIndex: ^interface_types.InterfaceIndex(0),
+ }); err != nil {
+ logError(err, "SwInterfaceDump sending message")
+ return
+ }
+ if err := stream.SendMsg(&vpe.ControlPing{}); err != nil {
+ logError(err, "ControlPing sending message")
+ return
+ }
+
+Loop:
+ for {
+ msg, err := stream.RecvMsg()
+ if err != nil {
+ logError(err, "SwInterfaceDump receiving message ")
+ return
+ }
+
+ switch msg.(type) {
+ case *interfaces.SwInterfaceDetails:
+ fmt.Printf(" - SwInterfaceDetails: %+v\n", msg)
+
+ case *vpe.ControlPingReply:
+ fmt.Printf(" - ControlPingReply: %+v\n", msg)
+ break Loop
+
+ default:
+ logError(err, "unexpected message")
+ return
+ }
+ }
+
+ fmt.Println("OK")
+ fmt.Println()
+}
+
+func addIPAddressStream(stream api.Stream, index interface_types.InterfaceIndex) {
+ fmt.Printf("Adding IP address to the interface index %d..\n", index)
+
+ if err := stream.SendMsg(&interfaces.SwInterfaceAddDelAddress{
+ SwIfIndex: index,
+ IsAdd: true,
+ Prefix: ip_types.AddressWithPrefix{
+ Address: ip_types.Address{
+ Af: ip_types.ADDRESS_IP4,
+ Un: ip_types.AddressUnionIP4(ip_types.IP4Address{10, 10, 0, uint8(index)}),
+ },
+ Len: 32,
+ },
+ }); err != nil {
+ logError(err, "SwInterfaceAddDelAddress sending message")
+ return
+ }
+
+ recv, err := stream.RecvMsg()
+ if err != nil {
+ logError(err, "SwInterfaceAddDelAddressReply receiving message")
+ return
+ }
+ recvMsg := recv.(*interfaces.SwInterfaceAddDelAddressReply)
+
+ fmt.Printf("Added IP address to interface: %v (return value: %d)\n", index, recvMsg.Retval)
+ fmt.Println("OK")
+ fmt.Println()
+}
+
+func ipAddressDumpStream(stream api.Stream, index interface_types.InterfaceIndex) {
+ fmt.Printf("Dumping IP addresses for interface index %d..\n", index)
+
+ if err := stream.SendMsg(&ip.IPAddressDump{
+ SwIfIndex: index,
+ }); err != nil {
+ logError(err, "IPAddressDump sending message")
+ return
+ }
+ if err := stream.SendMsg(&vpe.ControlPing{}); err != nil {
+ logError(err, "ControlPing sending sending message")
+ return
+ }
+
+Loop:
+ for {
+ msg, err := stream.RecvMsg()
+ if err != nil {
+ logError(err, "IPAddressDump receiving message ")
+ return
+ }
+
+ switch msg.(type) {
+ case *ip.IPAddressDetails:
+ fmt.Printf(" - IPAddressDetails: %+v\n", msg)
+
+ case *vpe.ControlPingReply:
+ fmt.Printf(" - ControlPingReply: %+v\n", msg)
+ break Loop
+
+ default:
+ logError(err, "unexpected message")
+ return
+ }
+ }
+
+ fmt.Println("OK")
+ fmt.Println()
+}
+
+// Mactime dump uses MactimeDumpReply message as an end of the stream
+// notification instead of the control ping.
+func mactimeDump(stream api.Stream, ) {
+ fmt.Println("Sending mactime dump..")
+
+ if err := stream.SendMsg(&mactime.MactimeDump{}); err != nil {
+ logError(err, "sending mactime dump")
+ return
+ }
+
+Loop:
+ for {
+ msg, err := stream.RecvMsg()
+ if err != nil {
+ logError(err, "MactimeDump receiving message")
+ return
+ }
+
+ switch msg.(type) {
+ case *mactime.MactimeDetails:
+ fmt.Printf(" - MactimeDetails: %+v\n", msg)
+
+ case *mactime.MactimeDumpReply:
+ fmt.Printf(" - MactimeDumpReply: %+v\n", msg)
+ break Loop
+
+ default:
+ logError(err, "unexpected message")
+ return
+ }
+ }
+
+ fmt.Println("OK")
+ fmt.Println()
+}
+
+var Errors []error
+
+func logError(err error, msg string) {
+ fmt.Printf("ERROR: %s: %v\n", msg, err)
+ Errors = append(Errors, err)
+}