package main
import (
+ "encoding/json"
"flag"
"fmt"
"log"
"os"
- "strings"
"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/vpe"
"git.fd.io/govpp.git/core"
- "git.fd.io/govpp.git/examples/binapi/interfaces"
- "git.fd.io/govpp.git/examples/binapi/ip"
- "git.fd.io/govpp.git/examples/binapi/vpe"
)
var (
flag.Parse()
fmt.Println("Starting simple client example")
+ fmt.Println()
// connect to VPP asynchronously
- conn, conev, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
+ conn, connEv, err := govpp.AsyncConnect(*sockAddr, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
if err != nil {
log.Fatalln("ERROR:", err)
}
// wait for Connected event
select {
- case e := <-conev:
+ case e := <-connEv:
if e.State != core.Connected {
log.Fatalln("ERROR: connecting to VPP failed:", e.Error)
}
}
- // create an API channel that will be used in the examples
+ // check compatibility of used messages
ch, err := conn.NewAPIChannel()
if err != nil {
log.Fatalln("ERROR: creating channel failed:", err)
}
defer ch.Close()
-
- vppVersion(ch)
-
+ if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
+ log.Fatal(err)
+ }
if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
log.Fatal(err)
}
- createLoopback(ch)
- createLoopback(ch)
+ // 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")
+ }
+ }()
+
+ // use request/reply (channel API)
+ getVppVersion(ch)
+ getSystemTime(ch)
+ idx := createLoopback(ch)
interfaceDump(ch)
+ addIPAddress(ch, idx)
+ ipAddressDump(ch, idx)
+ interfaceNotifications(ch, idx)
+}
- addIPAddress(ch)
- ipAddressDump(ch)
+func getVppVersion(ch api.Channel) {
+ fmt.Println("Retrieving version..")
- interfaceNotifications(ch)
+ req := &vpe.ShowVersion{}
+ reply := &vpe.ShowVersionReply{}
- if len(Errors) > 0 {
- fmt.Printf("finished with %d errors\n", len(Errors))
- os.Exit(1)
- } else {
- fmt.Println("finished successfully")
+ if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
+ logError(err, "retrieving version")
+ return
}
-}
-
-var Errors []error
-func logError(err error, msg string) {
- fmt.Printf("ERROR: %s: %v\n", msg, err)
- Errors = append(Errors, err)
+ fmt.Printf("VPP version: %q\n", reply.Version)
+ fmt.Println("OK")
+ fmt.Println()
}
-// vppVersion is the simplest API example - it retrieves VPP version.
-func vppVersion(ch api.Channel) {
- fmt.Println("Retrieving version")
+func getSystemTime(ch api.Channel) {
+ fmt.Println("Retrieving system time..")
- req := &vpe.ShowVersion{}
- reply := &vpe.ShowVersionReply{}
+ req := &vpe.ShowVpeSystemTime{}
+ reply := &vpe.ShowVpeSystemTimeReply{}
if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
- logError(err, "retrieving version")
+ logError(err, "retrieving system time")
return
}
- fmt.Printf("reply: %+v\n", reply)
- fmt.Printf("VPP version: %q\n", cleanString(reply.Version))
- fmt.Println("ok")
+ fmt.Printf("system time: %v\n", reply.VpeSystemTime)
+ fmt.Println("OK")
+ fmt.Println()
}
-// createLoopback sends request to create loopback interface.
-func createLoopback(ch api.Channel) {
- fmt.Println("Creating loopback interface")
+func createLoopback(ch api.Channel) interface_types.InterfaceIndex {
+ fmt.Println("Creating loopback interface..")
req := &interfaces.CreateLoopback{}
reply := &interfaces.CreateLoopbackReply{}
if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
logError(err, "creating loopback interface")
- return
+ return 0
}
- fmt.Printf("reply: %+v\n", reply)
- fmt.Printf("loopback interface index: %v\n", reply.SwIfIndex)
+ fmt.Printf("interface index: %v\n", reply.SwIfIndex)
fmt.Println("OK")
+ fmt.Println()
+
+ return reply.SwIfIndex
}
-// interfaceDump shows an example of multipart request (multiple replies are expected).
func interfaceDump(ch api.Channel) {
- fmt.Println("Dumping interfaces")
+ fmt.Println("Dumping interfaces..")
- reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
+ n := 0
+ reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{
+ SwIfIndex: ^interface_types.InterfaceIndex(0),
+ })
for {
msg := &interfaces.SwInterfaceDetails{}
stop, err := reqCtx.ReceiveReply(msg)
+ if stop {
+ break
+ }
if err != nil {
logError(err, "dumping interfaces")
return
}
- if stop {
- break
- }
- fmt.Printf(" - interface: %+v\n", msg)
+ n++
+ fmt.Printf(" - interface #%d: %+v\n", n, msg)
+ marshal(msg)
}
fmt.Println("OK")
+ fmt.Println()
}
-// addIPAddress sends request to add IP address to interface.
-func addIPAddress(ch api.Channel) {
- fmt.Println("Adding IP address to interface")
+func addIPAddress(ch api.Channel, index interface_types.InterfaceIndex) {
+ fmt.Printf("Adding IP address to interface index %d\n", index)
req := &interfaces.SwInterfaceAddDelAddress{
- SwIfIndex: 1,
- IsAdd: 1,
- Address: []byte{10, 10, 0, 1},
- AddressLength: 24,
- /* below for 20.01-rc0
+ SwIfIndex: index,
IsAdd: true,
- Prefix: interfaces.Prefix{
- Address: interfaces.Address{
- Af: interfaces.ADDRESS_IP4,
- Un: interfaces.AddressUnionIP4(interfaces.IP4Address{10, 10, 0, 1}),
+ 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: 24,
- },*/
+ Len: 32,
+ },
}
+ marshal(req)
reply := &interfaces.SwInterfaceAddDelAddressReply{}
if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
logError(err, "adding IP address to interface")
return
}
- fmt.Printf("reply: %+v\n", reply)
fmt.Println("OK")
+ fmt.Println()
}
-func ipAddressDump(ch api.Channel) {
- fmt.Println("Dumping IP addresses")
+func ipAddressDump(ch api.Channel, index interface_types.InterfaceIndex) {
+ fmt.Printf("Dumping IP addresses for interface index %d..\n", index)
req := &ip.IPAddressDump{
- SwIfIndex: 1,
+ SwIfIndex: index,
}
reqCtx := ch.SendMultiRequest(req)
break
}
fmt.Printf(" - ip address: %+v\n", msg)
+ marshal(msg)
}
fmt.Println("OK")
+ fmt.Println()
}
// interfaceNotifications shows the usage of notification API. Note that for notifications,
// you are supposed to create your own Go channel with your preferred buffer size. If the channel's
// buffer is full, the notifications will not be delivered into it.
-func interfaceNotifications(ch api.Channel) {
- fmt.Println("Subscribing to notificaiton events")
+func interfaceNotifications(ch api.Channel, index interface_types.InterfaceIndex) {
+ fmt.Printf("Subscribing to notificaiton events for interface index %d\n", index)
notifChan := make(chan api.Message, 100)
return
}
+ // receive notifications
+ go func() {
+ for notif := range notifChan {
+ e := notif.(*interfaces.SwInterfaceEvent)
+ fmt.Printf("incoming event: %+v\n", e)
+ marshal(e)
+ }
+ }()
+
// generate some events in VPP
err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
- SwIfIndex: 1,
+ SwIfIndex: index,
+ Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
}).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
if err != nil {
logError(err, "setting interface flags")
return
}
err = ch.SendRequest(&interfaces.SwInterfaceSetFlags{
- SwIfIndex: 1,
- AdminUpDown: 1,
- /* below for 20.01-rc0
- AdminUpDown: true,
- Flags: interfaces.IF_STATUS_API_FLAG_ADMIN_UP,*/
+ SwIfIndex: index,
+ Flags: 0,
}).ReceiveReply(&interfaces.SwInterfaceSetFlagsReply{})
if err != nil {
logError(err, "setting interface flags")
return
}
- // receive one notification
- notif := (<-notifChan).(*interfaces.SwInterfaceEvent)
- fmt.Printf("incoming event: %+v\n", notif)
-
// disable interface events in VPP
err = ch.SendRequest(&interfaces.WantInterfaceEvents{
PID: uint32(os.Getpid()),
return
}
+ fmt.Println("OK")
fmt.Println()
}
-func cleanString(str string) string {
- return strings.Split(str, "\x00")[0]
+func marshal(v interface{}) {
+ fmt.Printf("GO: %#v\n", v)
+ b, err := json.MarshalIndent(v, "", " ")
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("JSON: %s\n", b)
+}
+
+var Errors []error
+
+func logError(err error, msg string) {
+ fmt.Printf("ERROR: %s: %v\n", msg, err)
+ Errors = append(Errors, err)
}