hs-test: refactor test cases from no-topo suite
This converts remaining tests to configation of VPP from test context. Type: test Change-Id: I386714f6b290e03d1757c2a033a25fae0340f5d6 Signed-off-by: Maros Ondrejicka <mondreji@cisco.com>
This commit is contained in:

committed by
Florin Coras

parent
2908f8cf07
commit
7550dd268f
@ -2,7 +2,6 @@ all: build docker
|
||||
|
||||
build:
|
||||
go build ./tools/http_server
|
||||
go build .
|
||||
|
||||
docker:
|
||||
bash ./script/build.sh
|
||||
|
@ -1,82 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"git.fd.io/govpp.git/api"
|
||||
interfaces "github.com/edwarnicke/govpp/binapi/interface"
|
||||
"github.com/edwarnicke/govpp/binapi/interface_types"
|
||||
ip_types "github.com/edwarnicke/govpp/binapi/ip_types"
|
||||
"github.com/edwarnicke/govpp/binapi/session"
|
||||
"github.com/edwarnicke/govpp/binapi/tapv2"
|
||||
"github.com/edwarnicke/vpphelper"
|
||||
)
|
||||
|
||||
var (
|
||||
workDir, _ = os.Getwd()
|
||||
)
|
||||
|
||||
type ConfFn func(context.Context, api.Connection) error
|
||||
|
||||
type Actions struct {
|
||||
}
|
||||
|
||||
func (a *Actions) ConfigureTap(args []string) *ActionResult {
|
||||
var startup Stanza
|
||||
startup.
|
||||
NewStanza("session").
|
||||
Append("enable").
|
||||
Append("use-app-socket-api").Close()
|
||||
|
||||
ctx, cancel := newVppContext()
|
||||
defer cancel()
|
||||
con, vppErrCh := vpphelper.StartAndDialContext(ctx,
|
||||
vpphelper.WithRootDir(workDir),
|
||||
vpphelper.WithVppConfig(configTemplate+startup.ToString()))
|
||||
exitOnErrCh(ctx, cancel, vppErrCh)
|
||||
ifaceClient := interfaces.NewServiceClient(con)
|
||||
|
||||
pref, err := ip_types.ParseIP4Prefix("10.10.10.2/24")
|
||||
if err != nil {
|
||||
return NewActionResult(err, ActionResultWithDesc("failed to parse ip4 address"))
|
||||
}
|
||||
createTapReply, err := tapv2.NewServiceClient(con).TapCreateV2(ctx, &tapv2.TapCreateV2{
|
||||
HostIfNameSet: true,
|
||||
HostIfName: "tap0",
|
||||
HostIP4PrefixSet: true,
|
||||
HostIP4Prefix: ip_types.IP4AddressWithPrefix(pref),
|
||||
})
|
||||
if err != nil {
|
||||
return NewActionResult(err, ActionResultWithDesc("failed to configure tap"))
|
||||
}
|
||||
ipPrefix, err := ip_types.ParseAddressWithPrefix("10.10.10.1/24")
|
||||
if err != nil {
|
||||
return NewActionResult(err, ActionResultWithDesc("parsing ip address failed"))
|
||||
}
|
||||
ipAddress := &interfaces.SwInterfaceAddDelAddress{
|
||||
IsAdd: true,
|
||||
SwIfIndex: createTapReply.SwIfIndex,
|
||||
Prefix: ipPrefix,
|
||||
}
|
||||
_, errx := ifaceClient.SwInterfaceAddDelAddress(ctx, ipAddress)
|
||||
if errx != nil {
|
||||
return NewActionResult(err, ActionResultWithDesc("configuring ip address failed"))
|
||||
}
|
||||
_, err = ifaceClient.SwInterfaceSetFlags(ctx, &interfaces.SwInterfaceSetFlags{
|
||||
SwIfIndex: createTapReply.SwIfIndex,
|
||||
Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
|
||||
})
|
||||
if err != nil {
|
||||
return NewActionResult(err, ActionResultWithDesc("failed to set interface state"))
|
||||
}
|
||||
_, err = session.NewServiceClient(con).SessionEnableDisable(ctx, &session.SessionEnableDisable{
|
||||
IsEnable: true,
|
||||
})
|
||||
if err != nil {
|
||||
return NewActionResult(err, ActionResultWithDesc("configuration failed"))
|
||||
}
|
||||
writeSyncFile(OkResult())
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
}
|
@ -9,6 +9,10 @@ import (
|
||||
"github.com/edwarnicke/exechelper"
|
||||
)
|
||||
|
||||
var (
|
||||
workDir, _ = os.Getwd()
|
||||
)
|
||||
|
||||
type Volume struct {
|
||||
hostDir string
|
||||
containerDir string
|
||||
@ -114,9 +118,7 @@ func (c *Container) GetContainerWorkDir() (res string) {
|
||||
}
|
||||
|
||||
func (c *Container) getRunCommand() string {
|
||||
syncPath := fmt.Sprintf(" -v %s:/tmp/sync", c.getSyncPath())
|
||||
cmd := "docker run --cap-add=all -d --privileged --network host --rm"
|
||||
cmd += syncPath
|
||||
cmd += c.getVolumesAsCliOption()
|
||||
cmd += c.getEnvVarsAsCliOption()
|
||||
cmd += " --name " + c.name + " " + c.image + " " + c.extraRunningArgs
|
||||
@ -185,10 +187,6 @@ func (c *Container) getEnvVarsAsCliOption() string {
|
||||
return cliOption
|
||||
}
|
||||
|
||||
func (c *Container) getSyncPath() string {
|
||||
return fmt.Sprintf("/tmp/%s/sync", c.name)
|
||||
}
|
||||
|
||||
func (c *Container) newVppInstance(additionalConfig ...Stanza) (*VppInstance, error) {
|
||||
vppConfig := new(VppConfig)
|
||||
vppConfig.CliSocketFilePath = defaultCliSocketFilePath
|
||||
@ -249,30 +247,6 @@ func (c *Container) exec(command string, arguments ...any) string {
|
||||
return string(byteOutput)
|
||||
}
|
||||
|
||||
func (c *Container) execAction(args string) (string, error) {
|
||||
syncFile := c.getSyncPath() + "/rc"
|
||||
os.Remove(syncFile)
|
||||
|
||||
workDir := c.getWorkDirAsCliOption()
|
||||
cmd := fmt.Sprintf("docker exec -d %s %s hs-test %s",
|
||||
workDir,
|
||||
c.name,
|
||||
args)
|
||||
err := exechelper.Run(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res, err := waitForSyncFile(syncFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read sync file while executing 'hs-test %s': %v", args, err)
|
||||
}
|
||||
o := res.StdOutput + res.ErrOutput
|
||||
if res.Code != 0 {
|
||||
return o, fmt.Errorf("cmd resulted in non-zero value %d: %s", res.Code, res.Desc)
|
||||
}
|
||||
return o, err
|
||||
}
|
||||
|
||||
func (c *Container) stop() error {
|
||||
if c.vppInstance != nil && c.vppInstance.apiChannel != nil {
|
||||
c.vppInstance.disconnect()
|
||||
|
@ -20,8 +20,6 @@ COPY \
|
||||
COPY vpp-data/bin/* /usr/bin/
|
||||
COPY vpp-data/lib/* /usr/lib/
|
||||
|
||||
COPY hs-test /usr/local/bin/hs-test
|
||||
|
||||
RUN addgroup vpp
|
||||
|
||||
ENTRYPOINT ["tail", "-f", "/dev/null"]
|
||||
|
@ -6,12 +6,12 @@ func (s *VethsSuite) TestEchoBuiltin() {
|
||||
|
||||
serverVpp.vppctl("test echo server " +
|
||||
" private-segment-size 1g fifo-size 4 no-echo" +
|
||||
" uri tcp://" + serverVeth.Ip4AddressString() + "/1234")
|
||||
" uri tcp://" + serverVeth.IP4AddressString() + "/1234")
|
||||
|
||||
clientVpp := s.getContainerByName("client-vpp").vppInstance
|
||||
|
||||
o := clientVpp.vppctl("test echo client nclients 10000 bytes 1" +
|
||||
" syn-timeout 100 test-timeout 100 no-return private-segment-size 1g" +
|
||||
" fifo-size 4 uri tcp://" + serverVeth.Ip4AddressString() + "/1234")
|
||||
" fifo-size 4 uri tcp://" + serverVeth.IP4AddressString() + "/1234")
|
||||
s.log(o)
|
||||
}
|
||||
|
@ -6,25 +6,6 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
func setupSuite(s *suite.Suite, topologyName string) func() {
|
||||
t := s.T()
|
||||
topology, err := LoadTopology(NetworkTopologyDir, topologyName)
|
||||
if err != nil {
|
||||
t.Fatalf("error on loading topology '%s': %v", topologyName, err)
|
||||
}
|
||||
err = topology.Configure()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to configure %s: %v", topologyName, err)
|
||||
}
|
||||
|
||||
return func() {
|
||||
if IsPersistent() {
|
||||
return
|
||||
}
|
||||
topology.Unconfigure()
|
||||
}
|
||||
}
|
||||
|
||||
func TestTapSuite(t *testing.T) {
|
||||
var m TapSuite
|
||||
suite.Run(t, &m)
|
||||
|
@ -25,7 +25,6 @@ func IsVerbose() bool {
|
||||
|
||||
type HstSuite struct {
|
||||
suite.Suite
|
||||
teardownSuite func()
|
||||
containers map[string]*Container
|
||||
volumes []string
|
||||
netConfigs []NetConfig
|
||||
@ -34,10 +33,6 @@ type HstSuite struct {
|
||||
}
|
||||
|
||||
func (s *HstSuite) TearDownSuite() {
|
||||
if s.teardownSuite != nil {
|
||||
s.teardownSuite() // TODO remove this after config moved to SetupTest() for each suite
|
||||
}
|
||||
|
||||
s.unconfigureNetworkTopology()
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,11 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *NsSuite) TestHttpTps() {
|
||||
iface := s.netInterfaces[clientInterface]
|
||||
client_ip := iface.Ip4AddressString()
|
||||
client_ip := iface.IP4AddressString()
|
||||
port := "8080"
|
||||
finished := make(chan error, 1)
|
||||
|
||||
@ -33,7 +31,7 @@ func (s *VethsSuite) TestHttpCli() {
|
||||
|
||||
serverContainer.vppInstance.vppctl("http cli server")
|
||||
|
||||
uri := "http://" + serverVeth.Ip4AddressString() + "/80"
|
||||
uri := "http://" + serverVeth.IP4AddressString() + "/80"
|
||||
|
||||
o := clientContainer.vppInstance.vppctl("http cli client" +
|
||||
" uri " + uri + " query /show/version")
|
||||
@ -42,33 +40,21 @@ func (s *VethsSuite) TestHttpCli() {
|
||||
s.assertContains(o, "<html>", "<html> not found in the result!")
|
||||
}
|
||||
|
||||
func waitForApp(vppInst *VppInstance, appName string, timeout int) error {
|
||||
for i := 0; i < timeout; i++ {
|
||||
o := vppInst.vppctl("show app")
|
||||
if strings.Contains(o, appName) {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
return fmt.Errorf("Timeout while waiting for app '%s'", appName)
|
||||
}
|
||||
|
||||
func (s *NoTopoSuite) TestNginx() {
|
||||
query := "return_ok"
|
||||
finished := make(chan error, 1)
|
||||
vppCont := s.getContainerByName("vpp")
|
||||
vppInst := NewVppInstance(vppCont)
|
||||
vppInst.actionFuncName = "ConfigureTap"
|
||||
s.assertNil(vppInst.start(), "failed to start vpp")
|
||||
|
||||
nginxCont := s.getContainerByName("nginx")
|
||||
s.assertNil(nginxCont.run())
|
||||
|
||||
err := waitForApp(vppInst, "-app", 5)
|
||||
vpp := s.getContainerByName("vpp").vppInstance
|
||||
err := vpp.waitForApp("-app", 5)
|
||||
s.assertNil(err)
|
||||
|
||||
serverAddress := s.netInterfaces[tapNameVpp].IP4AddressString()
|
||||
|
||||
defer func() { os.Remove(query) }()
|
||||
go startWget(finished, "10.10.10.1", "80", query, "")
|
||||
go startWget(finished, serverAddress, "80", query, "")
|
||||
s.assertNil(<-finished)
|
||||
}
|
||||
|
||||
@ -78,6 +64,8 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error {
|
||||
var args []string
|
||||
var exeName string
|
||||
|
||||
serverAddress := s.netInterfaces[tapNameVpp].IP4AddressString()
|
||||
|
||||
if ab_or_wrk == "ab" {
|
||||
args = []string{"-n", fmt.Sprintf("%d", nRequests), "-c",
|
||||
fmt.Sprintf("%d", nClients)}
|
||||
@ -86,28 +74,25 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error {
|
||||
} else if mode != "cps" {
|
||||
return fmt.Errorf("invalid mode %s; expected cps/rps", mode)
|
||||
}
|
||||
args = append(args, "http://10.10.10.1:80/64B.json")
|
||||
args = append(args, "http://"+serverAddress+":80/64B.json")
|
||||
exeName = "ab"
|
||||
} else {
|
||||
args = []string{"-c", fmt.Sprintf("%d", nClients), "-t", "2", "-d", "30",
|
||||
"http://10.10.10.1:80"}
|
||||
"http://" + serverAddress + ":80"}
|
||||
exeName = "wrk"
|
||||
}
|
||||
|
||||
vppCont := s.getContainerByName("vpp")
|
||||
vppInst := NewVppInstance(vppCont)
|
||||
vppInst.actionFuncName = "ConfigureTap"
|
||||
s.assertNil(vppInst.start(), "failed to start vpp")
|
||||
vpp := s.getContainerByName("vpp").vppInstance
|
||||
|
||||
nginxCont := s.getContainerByName("nginx")
|
||||
s.assertNil(nginxCont.run())
|
||||
err := waitForApp(vppInst, "-app", 5)
|
||||
err := vpp.waitForApp("-app", 5)
|
||||
s.assertNil(err)
|
||||
|
||||
cmd := exec.Command(exeName, args...)
|
||||
fmt.Println(cmd)
|
||||
s.log(cmd)
|
||||
o, _ := cmd.CombinedOutput()
|
||||
fmt.Print(string(o))
|
||||
s.log(string(o))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
|
||||
s.log("attaching client to vpp")
|
||||
var clnRes = make(chan string, 1)
|
||||
clnEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+clientVclFileName)
|
||||
serverVethAddress := s.netInterfaces[serverInterfaceName].Ip4AddressString()
|
||||
serverVethAddress := s.netInterfaces[serverInterfaceName].IP4AddressString()
|
||||
go StartClientApp(serverVethAddress, clnEnv, clnCh, clnRes)
|
||||
s.log(<-clnRes)
|
||||
|
||||
|
@ -14,7 +14,7 @@ func (s *TapSuite) TestLinuxIperf() {
|
||||
s.assertNil(err)
|
||||
s.log("server running")
|
||||
|
||||
ipAddress := s.netInterfaces["tap0"].Ip4AddressString()
|
||||
ipAddress := s.netInterfaces["tap0"].IP4AddressString()
|
||||
go StartClientApp(ipAddress, nil, clnCh, clnRes)
|
||||
s.log("client running")
|
||||
s.log(<-clnRes)
|
||||
|
@ -1,140 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var actions Actions
|
||||
|
||||
func newVppContext() (context.Context, context.CancelFunc) {
|
||||
ctx, cancel := signal.NotifyContext(
|
||||
context.Background(),
|
||||
os.Interrupt,
|
||||
)
|
||||
return ctx, cancel
|
||||
}
|
||||
|
||||
func exitOnErrCh(ctx context.Context, cancel context.CancelFunc, errCh <-chan error) {
|
||||
// If we already have an error, log it and exit
|
||||
select {
|
||||
case err := <-errCh:
|
||||
fmt.Printf("%v", err)
|
||||
default:
|
||||
}
|
||||
go func(ctx context.Context, errCh <-chan error) {
|
||||
<-errCh
|
||||
cancel()
|
||||
}(ctx, errCh)
|
||||
}
|
||||
|
||||
func writeSyncFile(res *ActionResult) error {
|
||||
syncFile := "/tmp/sync/rc"
|
||||
|
||||
var jsonRes JsonResult
|
||||
|
||||
jsonRes.ErrOutput = res.ErrOutput
|
||||
jsonRes.StdOutput = res.StdOutput
|
||||
if res.Err != nil {
|
||||
jsonRes.Code = 1
|
||||
jsonRes.Desc = fmt.Sprintf("%s :%v", res.Desc, res.Err)
|
||||
} else {
|
||||
jsonRes.Code = 0
|
||||
}
|
||||
|
||||
str, err := json.Marshal(jsonRes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshaling json result data! %v", err)
|
||||
}
|
||||
|
||||
_, err = os.Open(syncFile)
|
||||
if err != nil {
|
||||
// expecting the file does not exist
|
||||
f, e := os.Create(syncFile)
|
||||
if e != nil {
|
||||
return fmt.Errorf("failed to open sync file")
|
||||
}
|
||||
defer f.Close()
|
||||
f.Write([]byte(str))
|
||||
} else {
|
||||
return fmt.Errorf("sync file exists, delete the file first")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewActionResult(err error, opts ...ActionResultOptionFn) *ActionResult {
|
||||
res := &ActionResult{
|
||||
Err: err,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(res)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type ActionResultOptionFn func(res *ActionResult)
|
||||
|
||||
func ActionResultWithDesc(s string) ActionResultOptionFn {
|
||||
return func(res *ActionResult) {
|
||||
res.Desc = s
|
||||
}
|
||||
}
|
||||
|
||||
func ActionResultWithStderr(s string) ActionResultOptionFn {
|
||||
return func(res *ActionResult) {
|
||||
res.ErrOutput = s
|
||||
}
|
||||
}
|
||||
|
||||
func ActionResultWithStdout(s string) ActionResultOptionFn {
|
||||
return func(res *ActionResult) {
|
||||
res.StdOutput = s
|
||||
}
|
||||
}
|
||||
|
||||
func OkResult() *ActionResult {
|
||||
return NewActionResult(nil)
|
||||
}
|
||||
|
||||
func processArgs() *ActionResult {
|
||||
nArgs := len(os.Args) - 1 // skip program name
|
||||
if nArgs < 1 {
|
||||
return NewActionResult(fmt.Errorf("internal: no action specified!"))
|
||||
}
|
||||
action := os.Args[1]
|
||||
methodValue := reflect.ValueOf(&actions).MethodByName(action)
|
||||
if !methodValue.IsValid() {
|
||||
return NewActionResult(fmt.Errorf("internal unknown action %s!", action))
|
||||
}
|
||||
methodIface := methodValue.Interface()
|
||||
fn := methodIface.(func([]string) *ActionResult)
|
||||
return fn(os.Args)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("args required")
|
||||
return
|
||||
}
|
||||
|
||||
if os.Args[1] == "rm" {
|
||||
topology, err := LoadTopology(NetworkTopologyDir, os.Args[2])
|
||||
if err != nil {
|
||||
fmt.Printf("falied to load topologies: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
topology.Unconfigure()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
var err error
|
||||
res := processArgs()
|
||||
err = writeSyncFile(res)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to write to sync file: %v\n", err)
|
||||
}
|
||||
}
|
@ -12,16 +12,10 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
MacAddress = ethernet_types.MacAddress
|
||||
AddressWithPrefix = ip_types.AddressWithPrefix
|
||||
InterfaceIndex = interface_types.InterfaceIndex
|
||||
|
||||
LegacyNetConfig struct {
|
||||
Configure func() error
|
||||
Unconfigure func()
|
||||
}
|
||||
|
||||
NetTopology []LegacyNetConfig
|
||||
MacAddress = ethernet_types.MacAddress
|
||||
AddressWithPrefix = ip_types.AddressWithPrefix
|
||||
IP4AddressWithPrefix = ip_types.IP4AddressWithPrefix
|
||||
InterfaceIndex = interface_types.InterfaceIndex
|
||||
|
||||
NetConfig interface {
|
||||
Configure() error
|
||||
@ -38,8 +32,9 @@ type (
|
||||
NetInterface interface {
|
||||
NetConfig
|
||||
SetAddress(string)
|
||||
Ip4AddressWithPrefix() AddressWithPrefix
|
||||
Ip4AddressString() string
|
||||
AddressWithPrefix() AddressWithPrefix
|
||||
IP4AddressWithPrefix() IP4AddressWithPrefix
|
||||
IP4AddressString() string
|
||||
SetIndex(InterfaceIndex)
|
||||
Index() InterfaceIndex
|
||||
HwAddress() MacAddress
|
||||
@ -102,12 +97,18 @@ func (b *NetInterfaceBase) Index() InterfaceIndex {
|
||||
return b.index
|
||||
}
|
||||
|
||||
func (b *NetInterfaceBase) Ip4AddressWithPrefix() AddressWithPrefix {
|
||||
func (b *NetInterfaceBase) AddressWithPrefix() AddressWithPrefix {
|
||||
address, _ := ip_types.ParseAddressWithPrefix(b.ip4address)
|
||||
return address
|
||||
}
|
||||
|
||||
func (b *NetInterfaceBase) Ip4AddressString() string {
|
||||
func (b *NetInterfaceBase) IP4AddressWithPrefix() IP4AddressWithPrefix {
|
||||
IP4Prefix, _ := ip_types.ParseIP4Prefix(b.ip4address)
|
||||
IP4AddressWithPrefix := ip_types.IP4AddressWithPrefix(IP4Prefix)
|
||||
return IP4AddressWithPrefix
|
||||
}
|
||||
|
||||
func (b *NetInterfaceBase) IP4AddressString() string {
|
||||
return strings.Split(b.ip4address, "/")[0]
|
||||
}
|
||||
|
||||
@ -137,136 +138,6 @@ func (iface *NetworkInterfaceVeth) Configure() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceVeth) Unconfigure() {
|
||||
DelLink(iface.name)
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceVeth) PeerIp4AddressString() string {
|
||||
return strings.Split(iface.peerIp4Address, "/")[0]
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceTap) Configure() error {
|
||||
err := AddTap(iface.name, iface.Ip4AddressString())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceTap) Unconfigure() {
|
||||
DelLink(iface.name)
|
||||
}
|
||||
|
||||
func (ns *NetworkNamespace) Configure() error {
|
||||
return addDelNetns(ns.name, true)
|
||||
}
|
||||
|
||||
func (ns *NetworkNamespace) Unconfigure() {
|
||||
addDelNetns(ns.name, false)
|
||||
}
|
||||
|
||||
func (b *NetworkBridge) Configure() error {
|
||||
return AddBridge(b.name, b.interfaces, b.networkNamespace)
|
||||
}
|
||||
|
||||
func (b *NetworkBridge) Unconfigure() {
|
||||
DelBridge(b.name, b.networkNamespace)
|
||||
}
|
||||
|
||||
func (t *NetTopology) Configure() error {
|
||||
for _, c := range *t {
|
||||
err := c.Configure()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *NetTopology) Unconfigure() {
|
||||
for _, c := range *t {
|
||||
c.Unconfigure()
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigFn(cfg NetDevConfig) func() error {
|
||||
t := cfg["type"]
|
||||
if t == "netns" {
|
||||
return func() error { return AddNetns(cfg["name"].(string)) }
|
||||
} else if t == "veth" {
|
||||
return func() error {
|
||||
var peerNs string
|
||||
peer := cfg["peer"].(NetDevConfig)
|
||||
peerName := peer["name"].(string)
|
||||
err := AddVethPair(cfg["name"].(string), peerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if peer["netns"] != nil {
|
||||
peerNs = peer["netns"].(string)
|
||||
if peerNs != "" {
|
||||
err := LinkSetNetns(peerName, peerNs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if peer["ip4"] != nil {
|
||||
err = AddAddress(peerName, peer["ip4"].(string), peerNs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add configure address for %s: %v", peerName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
} else if t == "bridge" {
|
||||
return func() error { return configureBridge(cfg) }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newUnconfigFn(cfg NetDevConfig) func() {
|
||||
t := cfg["type"]
|
||||
name := cfg["name"].(string)
|
||||
|
||||
if t == "netns" {
|
||||
return func() { DelNetns(name) }
|
||||
} else if t == "veth" {
|
||||
return func() { DelLink(name) }
|
||||
} else if t == "bridge" {
|
||||
return func() { DelBridge(name, cfg["netns"].(string)) }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewNetConfig(cfg NetDevConfig) LegacyNetConfig {
|
||||
var nc LegacyNetConfig
|
||||
|
||||
nc.Configure = newConfigFn(cfg)
|
||||
nc.Unconfigure = newUnconfigFn(cfg)
|
||||
|
||||
return nc
|
||||
}
|
||||
|
||||
func NewNetNamespace(cfg NetDevConfig) (NetworkNamespace, error) {
|
||||
var networkNamespace NetworkNamespace
|
||||
networkNamespace.name = cfg["name"].(string)
|
||||
networkNamespace.category = "netns"
|
||||
return networkNamespace, nil
|
||||
}
|
||||
|
||||
func NewBridge(cfg NetDevConfig) (NetworkBridge, error) {
|
||||
var bridge NetworkBridge
|
||||
bridge.name = cfg["name"].(string)
|
||||
bridge.category = "bridge"
|
||||
for _, v := range cfg["interfaces"].([]interface{}) {
|
||||
bridge.interfaces = append(bridge.interfaces, v.(string))
|
||||
}
|
||||
bridge.networkNamespace = cfg["netns"].(string)
|
||||
return bridge, nil
|
||||
}
|
||||
|
||||
func NewVeth(cfg NetDevConfig, a *Addresser) (NetworkInterfaceVeth, error) {
|
||||
var veth NetworkInterfaceVeth
|
||||
var err error
|
||||
@ -300,6 +171,14 @@ func NewVeth(cfg NetDevConfig, a *Addresser) (NetworkInterfaceVeth, error) {
|
||||
return veth, nil
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceVeth) Unconfigure() {
|
||||
DelLink(iface.name)
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceVeth) PeerIp4AddressString() string {
|
||||
return strings.Split(iface.peerIp4Address, "/")[0]
|
||||
}
|
||||
|
||||
func NewTap(cfg NetDevConfig, a *Addresser) (NetworkInterfaceTap, error) {
|
||||
var tap NetworkInterfaceTap
|
||||
tap.addresser = a
|
||||
@ -313,6 +192,52 @@ func NewTap(cfg NetDevConfig, a *Addresser) (NetworkInterfaceTap, error) {
|
||||
return tap, nil
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceTap) Configure() error {
|
||||
err := AddTap(iface.name, iface.IP4AddressString())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (iface *NetworkInterfaceTap) Unconfigure() {
|
||||
DelLink(iface.name)
|
||||
}
|
||||
|
||||
func NewNetNamespace(cfg NetDevConfig) (NetworkNamespace, error) {
|
||||
var networkNamespace NetworkNamespace
|
||||
networkNamespace.name = cfg["name"].(string)
|
||||
networkNamespace.category = "netns"
|
||||
return networkNamespace, nil
|
||||
}
|
||||
|
||||
func (ns *NetworkNamespace) Configure() error {
|
||||
return addDelNetns(ns.name, true)
|
||||
}
|
||||
|
||||
func (ns *NetworkNamespace) Unconfigure() {
|
||||
addDelNetns(ns.name, false)
|
||||
}
|
||||
|
||||
func NewBridge(cfg NetDevConfig) (NetworkBridge, error) {
|
||||
var bridge NetworkBridge
|
||||
bridge.name = cfg["name"].(string)
|
||||
bridge.category = "bridge"
|
||||
for _, v := range cfg["interfaces"].([]interface{}) {
|
||||
bridge.interfaces = append(bridge.interfaces, v.(string))
|
||||
}
|
||||
bridge.networkNamespace = cfg["netns"].(string)
|
||||
return bridge, nil
|
||||
}
|
||||
|
||||
func (b *NetworkBridge) Configure() error {
|
||||
return AddBridge(b.name, b.interfaces, b.networkNamespace)
|
||||
}
|
||||
|
||||
func (b *NetworkBridge) Unconfigure() {
|
||||
DelBridge(b.name, b.networkNamespace)
|
||||
}
|
||||
|
||||
func DelBridge(brName, ns string) error {
|
||||
err := SetDevDown(brName, ns)
|
||||
if err != err {
|
||||
|
@ -35,7 +35,7 @@ func testProxyHttpTcp(s *NsSuite) error {
|
||||
" --retry-on-http-error=503 --tries=10"+
|
||||
" -O %s %s:555/%s",
|
||||
outputFile,
|
||||
clientVeth.Ip4AddressString(),
|
||||
clientVeth.IP4AddressString(),
|
||||
srcFile,
|
||||
)
|
||||
s.log(c)
|
||||
@ -56,7 +56,7 @@ func configureVppProxy(s *NsSuite) error {
|
||||
testVppProxy := s.getContainerByName("vpp").vppInstance
|
||||
output := testVppProxy.vppctl(
|
||||
"test proxy server server-uri tcp://%s/555 client-uri tcp://%s/666",
|
||||
clientVeth.Ip4AddressString(),
|
||||
clientVeth.IP4AddressString(),
|
||||
serverVeth.PeerIp4AddressString(),
|
||||
)
|
||||
s.log("proxy configured...", output)
|
||||
|
@ -1,10 +1,50 @@
|
||||
package main
|
||||
|
||||
const (
|
||||
singleTopoContainerVpp = "vpp"
|
||||
singleTopoContainerNginx = "nginx"
|
||||
|
||||
tapNameVpp = "vppTap"
|
||||
tapNameHost = "hostTap"
|
||||
)
|
||||
|
||||
type NoTopoSuite struct {
|
||||
HstSuite
|
||||
}
|
||||
|
||||
func (s *NoTopoSuite) SetupSuite() {
|
||||
s.teardownSuite = func() {}
|
||||
s.loadContainerTopology("single")
|
||||
|
||||
s.addresser = NewAddresser(&s.HstSuite)
|
||||
|
||||
var vppTapDevConfig = NetDevConfig{"name": tapNameVpp}
|
||||
vppTap, _ := NewTap(vppTapDevConfig, s.addresser)
|
||||
|
||||
var hostTapDevConfig = NetDevConfig{"name": tapNameHost}
|
||||
hostTap, _ := NewTap(hostTapDevConfig, s.addresser)
|
||||
|
||||
s.netInterfaces = make(map[string]NetInterface)
|
||||
s.netInterfaces[vppTap.Name()] = &vppTap
|
||||
s.netInterfaces[hostTap.Name()] = &hostTap
|
||||
}
|
||||
|
||||
func (s *NoTopoSuite) SetupTest() {
|
||||
s.SetupVolumes()
|
||||
s.SetupContainers()
|
||||
|
||||
// Setup test conditions
|
||||
var startupConfig Stanza
|
||||
startupConfig.
|
||||
NewStanza("session").
|
||||
Append("enable").
|
||||
Append("use-app-socket-api").Close()
|
||||
|
||||
container := s.getContainerByName(singleTopoContainerVpp)
|
||||
vpp, _ := container.newVppInstance(startupConfig)
|
||||
vpp.start()
|
||||
|
||||
vppTapAddress := s.netInterfaces[tapNameVpp].AddressWithPrefix()
|
||||
hostTapAddress := s.netInterfaces[tapNameHost].IP4AddressWithPrefix()
|
||||
|
||||
vpp.createTap("tap0", hostTapAddress, vppTapAddress)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
volumes:
|
||||
- volume: &shared-vol
|
||||
host-dir: shared-vol
|
||||
host-dir: /tmp/shared-vol
|
||||
|
||||
containers:
|
||||
- name: "vpp"
|
||||
|
@ -2,11 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type NetDevConfig map[string]interface{}
|
||||
@ -28,52 +23,3 @@ func AddAddress(device, address, ns string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertToNetConfig(t *YamlTopology) (*NetTopology, error) {
|
||||
var topology NetTopology
|
||||
for _, dev := range t.Devices {
|
||||
topology = append(topology, NewNetConfig(dev))
|
||||
}
|
||||
return &topology, nil
|
||||
}
|
||||
|
||||
func loadTopoFile(topoName string) (*NetTopology, error) {
|
||||
var yamlTopo YamlTopology
|
||||
|
||||
data, err := ioutil.ReadFile(topoName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read error: %v", err)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(data, &yamlTopo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing topology data: %v", err)
|
||||
}
|
||||
|
||||
return convertToNetConfig(&yamlTopo)
|
||||
}
|
||||
|
||||
func LoadTopology(path, topoName string) (*NetTopology, error) {
|
||||
dir, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
files, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range files {
|
||||
file := files[i]
|
||||
fileName := file.Name()
|
||||
|
||||
// cut off file extension
|
||||
f := strings.Split(fileName, ".")[0]
|
||||
if f == topoName {
|
||||
return loadTopoFile(path + fileName)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("topology '%s' not found", topoName)
|
||||
}
|
||||
|
@ -1,55 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TODO remove `configTemplate` once its usage has been replaced everywhere with VppConfig
|
||||
const configTemplate = `unix {
|
||||
nodaemon
|
||||
log %[1]s/var/log/vpp/vpp.log
|
||||
full-coredump
|
||||
cli-listen %[1]s/var/run/vpp/cli.sock
|
||||
runtime-dir %[1]s/var/run
|
||||
gid vpp
|
||||
}
|
||||
|
||||
api-trace {
|
||||
on
|
||||
}
|
||||
|
||||
api-segment {
|
||||
gid vpp
|
||||
}
|
||||
|
||||
socksvr {
|
||||
socket-name %[1]s/var/run/vpp/api.sock
|
||||
}
|
||||
|
||||
statseg {
|
||||
socket-name %[1]s/var/run/vpp/stats.sock
|
||||
}
|
||||
|
||||
plugins {
|
||||
plugin default { disable }
|
||||
|
||||
plugin unittest_plugin.so { enable }
|
||||
plugin quic_plugin.so { enable }
|
||||
plugin af_packet_plugin.so { enable }
|
||||
plugin hs_apps_plugin.so { enable }
|
||||
plugin http_plugin.so { enable }
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
const vclTemplate = `vcl {
|
||||
app-socket-api %[1]s/var/run/app_ns_sockets/%[2]s
|
||||
app-scope-global
|
||||
@ -126,29 +86,6 @@ func StartClientApp(ipAddress string, env []string, clnCh chan error, clnRes cha
|
||||
}
|
||||
}
|
||||
|
||||
func waitForSyncFile(fname string) (*JsonResult, error) {
|
||||
var res JsonResult
|
||||
|
||||
for i := 0; i < 360; i++ {
|
||||
f, err := os.Open(fname)
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
|
||||
data, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read error: %v", err)
|
||||
}
|
||||
err = json.Unmarshal(data, &res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("json unmarshal error: %v", err)
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
return nil, fmt.Errorf("no sync file found")
|
||||
}
|
||||
|
||||
func assertFileSize(f1, f2 string) error {
|
||||
fi1, err := os.Stat(f1)
|
||||
if err != nil {
|
||||
|
@ -20,7 +20,7 @@ func (s *VethsSuite) TestVclEchoTcp() {
|
||||
}
|
||||
|
||||
func (s *VethsSuite) testVclEcho(proto string) {
|
||||
serverVethAddress := s.netInterfaces["vppsrv"].Ip4AddressString()
|
||||
serverVethAddress := s.netInterfaces["vppsrv"].IP4AddressString()
|
||||
uri := proto + "://" + serverVethAddress + "/12344"
|
||||
|
||||
echoSrvContainer := s.getContainerByName("server-application")
|
||||
@ -62,7 +62,7 @@ func (s *VethsSuite) testRetryAttach(proto string) {
|
||||
s.log("... Running first echo client test, before disconnect.")
|
||||
|
||||
serverVeth := s.netInterfaces[serverInterfaceName]
|
||||
serverVethAddress := serverVeth.Ip4AddressString()
|
||||
serverVethAddress := serverVeth.IP4AddressString()
|
||||
|
||||
echoClnContainer := s.getTransientContainerByName("client-application")
|
||||
clientVclConfContent := fmt.Sprintf(vclTemplate, echoClnContainer.GetContainerWorkDir(), "2")
|
||||
@ -95,13 +95,13 @@ func (s *VethsSuite) TestTcpWithLoss() {
|
||||
|
||||
serverVeth := s.netInterfaces[serverInterfaceName]
|
||||
serverVpp.vppctl("test echo server uri tcp://%s/20022",
|
||||
serverVeth.Ip4AddressString())
|
||||
serverVeth.IP4AddressString())
|
||||
|
||||
clientVpp := s.getContainerByName("client-vpp").vppInstance
|
||||
|
||||
// Ensure that VPP doesn't abort itself with NSIM enabled
|
||||
// Warning: Removing this ping will make the test fail!
|
||||
clientVpp.vppctl("ping %s", serverVeth.Ip4AddressString())
|
||||
clientVpp.vppctl("ping %s", serverVeth.IP4AddressString())
|
||||
|
||||
// Add loss of packets with Network Delay Simulator
|
||||
clientVpp.vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit" +
|
||||
@ -111,7 +111,7 @@ func (s *VethsSuite) TestTcpWithLoss() {
|
||||
|
||||
// Do echo test from client-vpp container
|
||||
output := clientVpp.vppctl("test echo client uri tcp://%s/20022 mbytes 50",
|
||||
serverVeth.Ip4AddressString())
|
||||
serverVeth.IP4AddressString())
|
||||
s.assertEqual(true, len(output) != 0)
|
||||
s.assertNotContains(output, "failed: timeout")
|
||||
s.log(output)
|
||||
|
@ -1,9 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/edwarnicke/exechelper"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.fd.io/govpp"
|
||||
"go.fd.io/govpp/api"
|
||||
@ -11,6 +12,7 @@ import (
|
||||
interfaces "go.fd.io/govpp/binapi/interface"
|
||||
"go.fd.io/govpp/binapi/interface_types"
|
||||
"go.fd.io/govpp/binapi/session"
|
||||
"go.fd.io/govpp/binapi/tapv2"
|
||||
"go.fd.io/govpp/binapi/vpe"
|
||||
"go.fd.io/govpp/core"
|
||||
)
|
||||
@ -79,14 +81,6 @@ func (vpp *VppInstance) Suite() *HstSuite {
|
||||
return vpp.container.suite
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) setVppProxy() {
|
||||
vpp.actionFuncName = "ConfigureVppProxy"
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) setEnvoyProxy() {
|
||||
vpp.actionFuncName = "ConfigureEnvoyProxy"
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) setCliSocket(filePath string) {
|
||||
vpp.config.CliSocketFilePath = filePath
|
||||
}
|
||||
@ -107,24 +101,7 @@ func (vpp *VppInstance) getEtcDir() string {
|
||||
return vpp.container.GetContainerWorkDir() + "/etc/vpp"
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) legacyStart() error {
|
||||
serializedConfig, err := serializeVppConfig(vpp.config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("serialize vpp config: %v", err)
|
||||
}
|
||||
args := fmt.Sprintf("%s '%s'", vpp.actionFuncName, serializedConfig)
|
||||
_, err = vpp.container.execAction(args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("vpp start failed: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) start() error {
|
||||
if vpp.actionFuncName != "" {
|
||||
return vpp.legacyStart()
|
||||
}
|
||||
|
||||
// Create folders
|
||||
containerWorkDir := vpp.container.GetContainerWorkDir()
|
||||
|
||||
@ -185,33 +162,15 @@ func (vpp *VppInstance) vppctl(command string, arguments ...any) string {
|
||||
return string(output)
|
||||
}
|
||||
|
||||
func NewVppInstance(c *Container) *VppInstance {
|
||||
vppConfig := new(VppConfig)
|
||||
vppConfig.CliSocketFilePath = defaultCliSocketFilePath
|
||||
vpp := new(VppInstance)
|
||||
vpp.container = c
|
||||
vpp.config = vppConfig
|
||||
return vpp
|
||||
}
|
||||
|
||||
func serializeVppConfig(vppConfig *VppConfig) (string, error) {
|
||||
serializedConfig, err := json.Marshal(vppConfig)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("vpp start failed: serializing configuration failed: %s", err)
|
||||
func (vpp *VppInstance) waitForApp(appName string, timeout int) error {
|
||||
for i := 0; i < timeout; i++ {
|
||||
o := vpp.vppctl("show app")
|
||||
if strings.Contains(o, appName) {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
return string(serializedConfig), nil
|
||||
}
|
||||
|
||||
func deserializeVppConfig(input string) (VppConfig, error) {
|
||||
var vppConfig VppConfig
|
||||
err := json.Unmarshal([]byte(input), &vppConfig)
|
||||
if err != nil {
|
||||
// Since input is not a valid JSON it is going be used as a variant value
|
||||
// for compatibility reasons
|
||||
vppConfig.Variant = input
|
||||
vppConfig.CliSocketFilePath = defaultCliSocketFilePath
|
||||
}
|
||||
return vppConfig, nil
|
||||
return fmt.Errorf("Timeout while waiting for app '%s'", appName)
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) createAfPacket(
|
||||
@ -247,29 +206,26 @@ func (vpp *VppInstance) createAfPacket(
|
||||
}
|
||||
|
||||
// Add address
|
||||
if veth.Ip4AddressWithPrefix() == (AddressWithPrefix{}) {
|
||||
if veth.AddressWithPrefix() == (AddressWithPrefix{}) {
|
||||
var err error
|
||||
var ip4Address string
|
||||
if veth.peerNetworkNamespace != "" {
|
||||
ip4Address, err := veth.addresser.
|
||||
ip4Address, err = veth.addresser.
|
||||
NewIp4AddressWithNamespace(veth.peerNetworkNamespace)
|
||||
if err == nil {
|
||||
veth.SetAddress(ip4Address)
|
||||
} else {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
ip4Address, err := veth.addresser.
|
||||
ip4Address, err = veth.addresser.
|
||||
NewIp4Address()
|
||||
if err == nil {
|
||||
veth.SetAddress(ip4Address)
|
||||
} else {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
veth.SetAddress(ip4Address)
|
||||
} else {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
addressReq := &interfaces.SwInterfaceAddDelAddress{
|
||||
IsAdd: true,
|
||||
SwIfIndex: veth.Index(),
|
||||
Prefix: veth.Ip4AddressWithPrefix(),
|
||||
Prefix: veth.AddressWithPrefix(),
|
||||
}
|
||||
addressReply := &interfaces.SwInterfaceAddDelAddressReply{}
|
||||
|
||||
@ -308,6 +264,50 @@ func (vpp *VppInstance) addAppNamespace(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) createTap(
|
||||
hostInterfaceName string,
|
||||
hostIp4Address IP4AddressWithPrefix,
|
||||
vppIp4Address AddressWithPrefix,
|
||||
) error {
|
||||
createTapReq := &tapv2.TapCreateV2{
|
||||
HostIfNameSet: true,
|
||||
HostIfName: hostInterfaceName,
|
||||
HostIP4PrefixSet: true,
|
||||
HostIP4Prefix: hostIp4Address,
|
||||
}
|
||||
createTapReply := &tapv2.TapCreateV2Reply{}
|
||||
|
||||
// Create tap interface
|
||||
if err := vpp.apiChannel.SendRequest(createTapReq).ReceiveReply(createTapReply); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add address
|
||||
addAddressReq := &interfaces.SwInterfaceAddDelAddress{
|
||||
IsAdd: true,
|
||||
SwIfIndex: createTapReply.SwIfIndex,
|
||||
Prefix: vppIp4Address,
|
||||
}
|
||||
addAddressReply := &interfaces.SwInterfaceAddDelAddressReply{}
|
||||
|
||||
if err := vpp.apiChannel.SendRequest(addAddressReq).ReceiveReply(addAddressReply); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set interface to up
|
||||
upReq := &interfaces.SwInterfaceSetFlags{
|
||||
SwIfIndex: createTapReply.SwIfIndex,
|
||||
Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
|
||||
}
|
||||
upReply := &interfaces.SwInterfaceSetFlagsReply{}
|
||||
|
||||
if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vpp *VppInstance) disconnect() {
|
||||
vpp.connection.Disconnect()
|
||||
vpp.apiChannel.Close()
|
||||
|
Reference in New Issue
Block a user