aboutsummaryrefslogtreecommitdiffstats
path: root/examples/multi-vpp/multi_vpp.go
diff options
context:
space:
mode:
Diffstat (limited to 'examples/multi-vpp/multi_vpp.go')
-rw-r--r--examples/multi-vpp/multi_vpp.go220
1 files changed, 220 insertions, 0 deletions
diff --git a/examples/multi-vpp/multi_vpp.go b/examples/multi-vpp/multi_vpp.go
new file mode 100644
index 0000000..244dd03
--- /dev/null
+++ b/examples/multi-vpp/multi_vpp.go
@@ -0,0 +1,220 @@
+// Copyright (c) 2020 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.
+
+// multi-vpp is an example of managing multiple VPPs in single application.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "git.fd.io/govpp.git"
+ "git.fd.io/govpp.git/adapter/socketclient"
+ "git.fd.io/govpp.git/api"
+ "git.fd.io/govpp.git/core"
+ "git.fd.io/govpp.git/examples/binapi/interface_types"
+ "git.fd.io/govpp.git/examples/binapi/interfaces"
+ "git.fd.io/govpp.git/examples/binapi/ip"
+ "git.fd.io/govpp.git/examples/binapi/ip_types"
+ "git.fd.io/govpp.git/examples/binapi/vpe"
+ "log"
+ "os"
+)
+
+var (
+ sockAddrVpp1 = flag.String("sock1", socketclient.DefaultSocketName, "Path to binary API socket file of the first VPP instance")
+ sockAddrVpp2 = flag.String("sock2", socketclient.DefaultSocketName, "Path to binary API socket file of the second VPP instance")
+)
+
+func main() {
+ flag.Parse()
+ fmt.Println("Starting multi-vpp example")
+
+ // since both of them default to the same value
+ if *sockAddrVpp1 == *sockAddrVpp2 {
+ log.Fatalln("ERROR: identical VPP sockets defined, set at least one of them to non-default path")
+ }
+
+ // connect VPP1
+ conn1, err := connectToVPP(*sockAddrVpp1, 1)
+ if err != nil {
+ log.Fatalf("ERROR: connecting VPP failed (socket %s): %v\n", *sockAddrVpp1, err)
+ }
+ defer conn1.Disconnect()
+ ch1, err := getAPIChannel(conn1)
+ if err != nil {
+ log.Fatalf("ERROR: creating channel failed (socket: %s): %v\n", *sockAddrVpp1, err)
+ }
+ defer ch1.Close()
+
+ // connect VPP2
+ conn2, err := connectToVPP(*sockAddrVpp2, 2)
+ if err != nil {
+ log.Fatalf("ERROR: connecting VPP failed (socket %s): %v\n", *sockAddrVpp2, err)
+ }
+ defer conn2.Disconnect()
+ ch2, err := getAPIChannel(conn2)
+ if err != nil {
+ log.Fatalf("ERROR: creating channel failed (socket: %s): %v\n", *sockAddrVpp2, err)
+ }
+ defer ch2.Close()
+
+ // configure VPPs
+ ifIdx1 := createLoopback(ch1)
+ addIPToInterface(ch1, ifIdx1, "10.10.0.1/24")
+ ifIdx2 := createLoopback(ch2)
+ addIPToInterface(ch2, ifIdx2, "20.10.0.1/24")
+
+ // retrieve configuration from the VPPs
+ retrieveIPAddresses(ch1, ifIdx1)
+ retrieveIPAddresses(ch2, ifIdx2)
+
+ if len(Errors) > 0 {
+ fmt.Printf("finished with %d errors\n", len(Errors))
+ os.Exit(1)
+ } else {
+ fmt.Println("finished successfully")
+ }
+}
+
+func connectToVPP(socket string, attempts int) (*core.Connection, error) {
+ connection, event, err := govpp.AsyncConnect(socket, attempts, core.DefaultReconnectInterval)
+ if err != nil {
+ return nil, err
+ }
+
+ // handle connection event
+ select {
+ case e := <-event:
+ if e.State != core.Connected {
+ return nil, err
+ }
+ }
+ return connection, nil
+}
+
+func getAPIChannel(conn *core.Connection) (api.Channel, error) {
+ ch, err := conn.NewAPIChannel()
+ if err != nil {
+ return nil, err
+ }
+
+ if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
+ return nil, err
+ }
+
+ getVppVersion(ch)
+
+ if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
+ return nil, err
+ }
+ return ch, nil
+}
+
+// getVppVersion returns VPP version (simple API usage)
+func getVppVersion(ch api.Channel) {
+ fmt.Println("Retrieving version")
+
+ req := &vpe.ShowVersion{}
+ reply := &vpe.ShowVersionReply{}
+
+ if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
+ logError(err, "retrieving version")
+ return
+ }
+ fmt.Printf("reply: %+v\n", reply)
+
+ fmt.Printf("VPP version: %q\n", reply.Version)
+ 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)
+}
+
+// createLoopback sends request to create a loopback interface
+func createLoopback(ch api.Channel) interface_types.InterfaceIndex {
+ fmt.Println("Adding loopback interface")
+
+ req := &interfaces.CreateLoopback{}
+ reply := &interfaces.CreateLoopbackReply{}
+
+ if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
+ logError(err, "adding loopback interface")
+ return 0
+ }
+ fmt.Printf("reply: %+v\n", reply)
+
+ fmt.Printf("interface index: %v\n", reply.SwIfIndex)
+ fmt.Println("OK")
+ fmt.Println()
+
+ return reply.SwIfIndex
+}
+
+// addIPToInterface sends request to add an IP address to an interface.
+func addIPToInterface(ch api.Channel, index interface_types.InterfaceIndex, ip string) {
+ fmt.Printf("Setting up IP address to the interface with index %d\n", index)
+ prefix, err := ip_types.ParsePrefix(ip)
+ if err != nil {
+ logError(err, "attempt to add invalid IP address")
+ return
+ }
+
+
+ req := &interfaces.SwInterfaceAddDelAddress{
+ SwIfIndex: index,
+ IsAdd: true,
+ Prefix: ip_types.AddressWithPrefix(prefix),
+ }
+ 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 retrieveIPAddresses(ch api.Channel, index interface_types.InterfaceIndex) {
+ fmt.Printf("Retrieving IP addresses for interface index %d\n", index)
+
+ req := &ip.IPAddressDump{
+ SwIfIndex: index,
+ }
+ reqCtx := ch.SendMultiRequest(req)
+
+ for {
+ msg := &ip.IPAddressDetails{}
+ stop, err := reqCtx.ReceiveReply(msg)
+ if err != nil {
+ logError(err, "dumping IP addresses")
+ return
+ }
+ if stop {
+ break
+ }
+ prefix := ip_types.Prefix(msg.Prefix)
+ fmt.Printf(" - ip address: %+v\n", prefix.ToString())
+ }
+
+ fmt.Println("OK")
+ fmt.Println()
+}