1 // Copyright (c) 2020 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 // multi-vpp is an example of managing multiple VPPs in single application.
22 "git.fd.io/govpp.git/adapter/socketclient"
23 "git.fd.io/govpp.git/api"
24 "git.fd.io/govpp.git/core"
25 "git.fd.io/govpp.git/examples/binapi/interface_types"
26 "git.fd.io/govpp.git/examples/binapi/interfaces"
27 "git.fd.io/govpp.git/examples/binapi/ip"
28 "git.fd.io/govpp.git/examples/binapi/ip_types"
29 "git.fd.io/govpp.git/examples/binapi/vpe"
35 sockAddrVpp1 = flag.String("sock1", socketclient.DefaultSocketName, "Path to binary API socket file of the first VPP instance")
36 sockAddrVpp2 = flag.String("sock2", socketclient.DefaultSocketName, "Path to binary API socket file of the second VPP instance")
41 fmt.Println("Starting multi-vpp example")
43 // since both of them default to the same value
44 if *sockAddrVpp1 == *sockAddrVpp2 {
45 log.Fatalln("ERROR: identical VPP sockets defined, set at least one of them to non-default path")
49 conn1, err := connectToVPP(*sockAddrVpp1, 1)
51 log.Fatalf("ERROR: connecting VPP failed (socket %s): %v\n", *sockAddrVpp1, err)
53 defer conn1.Disconnect()
54 ch1, err := getAPIChannel(conn1)
56 log.Fatalf("ERROR: creating channel failed (socket: %s): %v\n", *sockAddrVpp1, err)
61 conn2, err := connectToVPP(*sockAddrVpp2, 2)
63 log.Fatalf("ERROR: connecting VPP failed (socket %s): %v\n", *sockAddrVpp2, err)
65 defer conn2.Disconnect()
66 ch2, err := getAPIChannel(conn2)
68 log.Fatalf("ERROR: creating channel failed (socket: %s): %v\n", *sockAddrVpp2, err)
73 ifIdx1 := createLoopback(ch1)
74 addIPToInterface(ch1, ifIdx1, "10.10.0.1/24")
75 ifIdx2 := createLoopback(ch2)
76 addIPToInterface(ch2, ifIdx2, "20.10.0.1/24")
78 // retrieve configuration from the VPPs
79 retrieveIPAddresses(ch1, ifIdx1)
80 retrieveIPAddresses(ch2, ifIdx2)
83 fmt.Printf("finished with %d errors\n", len(Errors))
86 fmt.Println("finished successfully")
90 func connectToVPP(socket string, attempts int) (*core.Connection, error) {
91 connection, event, err := govpp.AsyncConnect(socket, attempts, core.DefaultReconnectInterval)
96 // handle connection event
99 if e.State != core.Connected {
103 return connection, nil
106 func getAPIChannel(conn *core.Connection) (api.Channel, error) {
107 ch, err := conn.NewAPIChannel()
112 if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
118 if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
124 // getVppVersion returns VPP version (simple API usage)
125 func getVppVersion(ch api.Channel) {
126 fmt.Println("Retrieving version")
128 req := &vpe.ShowVersion{}
129 reply := &vpe.ShowVersionReply{}
131 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
132 logError(err, "retrieving version")
135 fmt.Printf("reply: %+v\n", reply)
137 fmt.Printf("VPP version: %q\n", reply.Version)
144 func logError(err error, msg string) {
145 fmt.Printf("ERROR: %s: %v\n", msg, err)
146 Errors = append(Errors, err)
149 // createLoopback sends request to create a loopback interface
150 func createLoopback(ch api.Channel) interface_types.InterfaceIndex {
151 fmt.Println("Adding loopback interface")
153 req := &interfaces.CreateLoopback{}
154 reply := &interfaces.CreateLoopbackReply{}
156 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
157 logError(err, "adding loopback interface")
160 fmt.Printf("reply: %+v\n", reply)
162 fmt.Printf("interface index: %v\n", reply.SwIfIndex)
166 return reply.SwIfIndex
169 // addIPToInterface sends request to add an IP address to an interface.
170 func addIPToInterface(ch api.Channel, index interface_types.InterfaceIndex, ip string) {
171 fmt.Printf("Setting up IP address to the interface with index %d\n", index)
172 prefix, err := ip_types.ParsePrefix(ip)
174 logError(err, "attempt to add invalid IP address")
179 req := &interfaces.SwInterfaceAddDelAddress{
182 Prefix: ip_types.AddressWithPrefix(prefix),
184 reply := &interfaces.SwInterfaceAddDelAddressReply{}
186 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
187 logError(err, "adding IP address to interface")
190 fmt.Printf("reply: %+v\n", reply)
196 func retrieveIPAddresses(ch api.Channel, index interface_types.InterfaceIndex) {
197 fmt.Printf("Retrieving IP addresses for interface index %d\n", index)
199 req := &ip.IPAddressDump{
202 reqCtx := ch.SendMultiRequest(req)
205 msg := &ip.IPAddressDetails{}
206 stop, err := reqCtx.ReceiveReply(msg)
208 logError(err, "dumping IP addresses")
214 prefix := ip_types.Prefix(msg.Prefix)
215 fmt.Printf(" - ip address: %+v\n", prefix.ToString())