hs-test: refactor test cases from ns suite 38/38138/9
authorMaros Ondrejicka <maros.ondrejicka@pantheon.tech>
Thu, 2 Feb 2023 07:58:04 +0000 (08:58 +0100)
committerFlorin Coras <florin.coras@gmail.com>
Fri, 10 Feb 2023 05:23:19 +0000 (05:23 +0000)
This converts more tests to configure VPP from test context.

Type: test
Signed-off-by: Maros Ondrejicka <maros.ondrejicka@pantheon.tech>
Change-Id: Idf26b0c16f87e87c97b198412af39b99d947ced6

20 files changed:
extras/hs-test/actions.go
extras/hs-test/container.go
extras/hs-test/echo_test.go
extras/hs-test/hst_suite.go
extras/hs-test/http_test.go
extras/hs-test/ldp_test.go
extras/hs-test/linux_iperf_test.go
extras/hs-test/main.go
extras/hs-test/netconfig.go
extras/hs-test/proxy_test.go
extras/hs-test/resources/envoy/proxy.yaml
extras/hs-test/suite_ns_test.go
extras/hs-test/suite_tap_test.go
extras/hs-test/suite_veth_test.go
extras/hs-test/topo-containers/ns.yaml
extras/hs-test/topo-network/ns.yaml
extras/hs-test/topo-network/tap.yaml
extras/hs-test/utils.go
extras/hs-test/vcl_test.go
extras/hs-test/vppinstance.go

index 6039870..9233e2d 100644 (file)
@@ -2,20 +2,14 @@ package main
 
 import (
        "context"
-       "fmt"
        "os"
-       "path/filepath"
 
        "git.fd.io/govpp.git/api"
-       "github.com/edwarnicke/exechelper"
-       "github.com/edwarnicke/govpp/binapi/af_packet"
-       "github.com/edwarnicke/govpp/binapi/ethernet_types"
        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/govpp/binapi/vlib"
        "github.com/edwarnicke/vpphelper"
 )
 
@@ -28,247 +22,6 @@ type ConfFn func(context.Context, api.Connection) error
 type Actions struct {
 }
 
-func configureProxyTcp(ifName0, ipAddr0, ifName1, ipAddr1 string) ConfFn {
-       return func(ctx context.Context,
-               vppConn api.Connection) error {
-
-               _, err := configureAfPacket(ctx, vppConn, ifName0, ipAddr0)
-               if err != nil {
-                       fmt.Printf("failed to create af packet: %v", err)
-                       return err
-               }
-               _, err = configureAfPacket(ctx, vppConn, ifName1, ipAddr1)
-               if err != nil {
-                       fmt.Printf("failed to create af packet: %v", err)
-                       return err
-               }
-               return nil
-       }
-}
-
-func (a *Actions) ConfigureVppProxy(args []string) *ActionResult {
-       ctx, cancel := newVppContext()
-       defer cancel()
-
-       con, vppErrCh := vpphelper.StartAndDialContext(ctx,
-               vpphelper.WithVppConfig(configTemplate),
-               vpphelper.WithRootDir(workDir))
-       exitOnErrCh(ctx, cancel, vppErrCh)
-
-       confFn := configureProxyTcp("vpp0", "10.0.0.2/24", "vpp1", "10.0.1.2/24")
-       err := confFn(ctx, con)
-       if err != nil {
-               return NewActionResult(err, ActionResultWithDesc("configuration failed"))
-       }
-       writeSyncFile(OkResult())
-       <-ctx.Done()
-       return nil
-}
-
-func (a *Actions) ConfigureEnvoyProxy(args []string) *ActionResult {
-       var startup Stanza
-       startup.
-               NewStanza("session").
-               Append("enable").
-               Append("use-app-socket-api").
-               Append("evt_qs_memfd_seg").
-               Append("event-queue-length 100000").Close()
-       ctx, cancel := newVppContext()
-       defer cancel()
-
-       con, vppErrCh := vpphelper.StartAndDialContext(ctx,
-               vpphelper.WithVppConfig(configTemplate+startup.ToString()),
-               vpphelper.WithRootDir(workDir))
-       exitOnErrCh(ctx, cancel, vppErrCh)
-
-       confFn := configureProxyTcp("vpp0", "10.0.0.2/24", "vpp1", "10.0.1.2/24")
-       err := confFn(ctx, con)
-       if err != nil {
-               return NewActionResult(err, ActionResultWithDesc("configuration failed"))
-       }
-       err0 := exechelper.Run("chmod 777 -R " + workDir)
-       if err0 != nil {
-               return NewActionResult(err, ActionResultWithDesc("setting permissions failed"))
-       }
-       writeSyncFile(OkResult())
-       <-ctx.Done()
-       return nil
-}
-
-func getArgs() string {
-       s := ""
-       for i := 2; i < len(os.Args); i++ {
-               s = s + " " + os.Args[i]
-       }
-       return s
-}
-
-func ApiCliInband(root, cmd string) *ActionResult {
-       ctx, _ := newVppContext()
-       con := vpphelper.DialContext(ctx, filepath.Join(root, "/var/run/vpp/api.sock"))
-       cliInband := vlib.CliInband{Cmd: cmd}
-       cliInbandReply, err := vlib.NewServiceClient(con).CliInband(ctx, &cliInband)
-       return NewActionResult(err, ActionResultWithStdout(cliInbandReply.Reply))
-}
-
-func (a *Actions) RunEchoSrvInternal(args []string) *ActionResult {
-       cmd := fmt.Sprintf("test echo server %s uri tcp://10.10.10.1/1234", getArgs())
-       return ApiCliInband(workDir, cmd)
-}
-
-func (a *Actions) RunEchoClnInternal(args []string) *ActionResult {
-       cmd := fmt.Sprintf("test echo client %s uri tcp://10.10.10.1/1234", getArgs())
-       return ApiCliInband(workDir, cmd)
-}
-
-func configure2vethsTopo(ifName, interfaceAddress, namespaceId string, secret uint64, optionalHardwareAddress ...string) ConfFn {
-       return func(ctx context.Context,
-               vppConn api.Connection) error {
-
-               var swIfIndex interface_types.InterfaceIndex
-               var err error
-               if optionalHardwareAddress == nil {
-                       swIfIndex, err = configureAfPacket(ctx, vppConn, ifName, interfaceAddress)
-               } else {
-                       swIfIndex, err = configureAfPacket(ctx, vppConn, ifName, interfaceAddress, optionalHardwareAddress[0])
-               }
-               if err != nil {
-                       fmt.Printf("failed to create af packet: %v", err)
-               }
-               _, er := session.NewServiceClient(vppConn).AppNamespaceAddDelV2(ctx, &session.AppNamespaceAddDelV2{
-                       Secret:      secret,
-                       SwIfIndex:   swIfIndex,
-                       NamespaceID: namespaceId,
-               })
-               if er != nil {
-                       fmt.Printf("add app namespace: %v", err)
-                       return err
-               }
-
-               _, er1 := session.NewServiceClient(vppConn).SessionEnableDisable(ctx, &session.SessionEnableDisable{
-                       IsEnable: true,
-               })
-               if er1 != nil {
-                       fmt.Printf("session enable %v", err)
-                       return err
-               }
-               return nil
-       }
-}
-
-func (a *Actions) Configure2Veths(args []string) *ActionResult {
-       var startup Stanza
-       startup.
-               NewStanza("session").
-               Append("enable").
-               Append("use-app-socket-api").Close()
-
-       ctx, cancel := newVppContext()
-       defer cancel()
-
-       vppConfig, err := deserializeVppConfig(args[2])
-       if err != nil {
-               return NewActionResult(err, ActionResultWithDesc("deserializing configuration failed"))
-       }
-
-       con, vppErrCh := vpphelper.StartAndDialContext(ctx,
-               vpphelper.WithVppConfig(vppConfig.getTemplate()+startup.ToString()),
-               vpphelper.WithRootDir(workDir))
-       exitOnErrCh(ctx, cancel, vppErrCh)
-
-       var fn func(context.Context, api.Connection) error
-       switch vppConfig.Variant {
-       case "srv":
-               fn = configure2vethsTopo("vppsrv", "10.10.10.1/24", "1", 1)
-       case "srv-with-preset-hw-addr":
-               fn = configure2vethsTopo("vppsrv", "10.10.10.1/24", "1", 1, "00:00:5e:00:53:01")
-       case "cln":
-               fallthrough
-       default:
-               fn = configure2vethsTopo("vppcln", "10.10.10.2/24", "2", 2)
-       }
-       err = fn(ctx, con)
-       if err != nil {
-               return NewActionResult(err, ActionResultWithDesc("configuration failed"))
-       }
-       writeSyncFile(OkResult())
-       <-ctx.Done()
-       return nil
-}
-
-func configureAfPacket(ctx context.Context, vppCon api.Connection,
-       name, interfaceAddress string, optionalHardwareAddress ...string) (interface_types.InterfaceIndex, error) {
-       var err error
-       ifaceClient := interfaces.NewServiceClient(vppCon)
-       afPacketCreate := af_packet.AfPacketCreateV2{
-               UseRandomHwAddr: true,
-               HostIfName:      name,
-               NumRxQueues:     1,
-       }
-       if len(optionalHardwareAddress) > 0 {
-               afPacketCreate.HwAddr, err = ethernet_types.ParseMacAddress(optionalHardwareAddress[0])
-               if err != nil {
-                       fmt.Printf("failed to parse mac address: %v", err)
-                       return 0, err
-               }
-               afPacketCreate.UseRandomHwAddr = false
-       }
-       afPacketCreateRsp, err := af_packet.NewServiceClient(vppCon).AfPacketCreateV2(ctx, &afPacketCreate)
-       if err != nil {
-               fmt.Printf("failed to create af packet: %v", err)
-               return 0, err
-       }
-       _, err = ifaceClient.SwInterfaceSetFlags(ctx, &interfaces.SwInterfaceSetFlags{
-               SwIfIndex: afPacketCreateRsp.SwIfIndex,
-               Flags:     interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
-       })
-       if err != nil {
-               fmt.Printf("set interface state up failed: %v\n", err)
-               return 0, err
-       }
-       ipPrefix, err := ip_types.ParseAddressWithPrefix(interfaceAddress)
-       if err != nil {
-               fmt.Printf("parse ip address %v\n", err)
-               return 0, err
-       }
-       ipAddress := &interfaces.SwInterfaceAddDelAddress{
-               IsAdd:     true,
-               SwIfIndex: afPacketCreateRsp.SwIfIndex,
-               Prefix:    ipPrefix,
-       }
-       _, errx := ifaceClient.SwInterfaceAddDelAddress(ctx, ipAddress)
-       if errx != nil {
-               fmt.Printf("add ip address %v\n", err)
-               return 0, err
-       }
-       return afPacketCreateRsp.SwIfIndex, nil
-}
-
-func (a *Actions) ConfigureHttpTps(args []string) *ActionResult {
-       ctx, cancel := newVppContext()
-       defer cancel()
-       con, vppErrCh := vpphelper.StartAndDialContext(ctx,
-               vpphelper.WithVppConfig(configTemplate))
-       exitOnErrCh(ctx, cancel, vppErrCh)
-
-       confFn := configureProxyTcp("vpp0", "10.0.0.2/24", "vpp1", "10.0.1.2/24")
-       err := confFn(ctx, con)
-       if err != nil {
-               return NewActionResult(err, ActionResultWithDesc("configuration failed"))
-       }
-
-       _, err = session.NewServiceClient(con).SessionEnableDisable(ctx, &session.SessionEnableDisable{
-               IsEnable: true,
-       })
-       if err != nil {
-               return NewActionResult(err, ActionResultWithDesc("configuration failed"))
-       }
-       Vppcli("", "http tps uri tcp://0.0.0.0/8080")
-       writeSyncFile(OkResult())
-       <-ctx.Done()
-       return nil
-}
-
 func (a *Actions) ConfigureTap(args []string) *ActionResult {
        var startup Stanza
        startup.
index 91ca2c2..cc2d441 100644 (file)
@@ -84,6 +84,10 @@ func NewContainer(yamlInput ContainerConfig) (*Container, error) {
        return container, nil
 }
 
+func (c *Container) Suite() *HstSuite {
+       return c.suite
+}
+
 func (c *Container) getWorkDirVolume() (res Volume, exists bool) {
        for _, v := range c.volumes {
                if v.isDefaultWorkDir {
@@ -227,14 +231,22 @@ func (c *Container) createFile(destFileName string, content string) error {
  * Executes in detached mode so that the started application can continue to run
  * without blocking execution of test
  */
-func (c *Container) execServer(command string) error {
-       return exechelper.Run("docker exec -d" + c.getEnvVarsAsCliOption() + " " + c.name + " " + command)
+func (c *Container) execServer(command string, arguments ...any) {
+       serverCommand := fmt.Sprintf(command, arguments...)
+       containerExecCommand := "docker exec -d" + c.getEnvVarsAsCliOption() +
+               " " + c.name + " " + serverCommand
+       c.Suite().log(containerExecCommand)
+       c.Suite().assertNil(exechelper.Run(containerExecCommand))
 }
 
-func (c *Container) exec(command string) (string, error) {
-       cliCommand := "docker exec" + c.getEnvVarsAsCliOption() + " " + c.name + " " + command
-       byteOutput, err := exechelper.CombinedOutput(cliCommand)
-       return string(byteOutput), err
+func (c *Container) exec(command string, arguments ...any) string {
+       cliCommand := fmt.Sprintf(command, arguments...)
+       containerExecCommand := "docker exec" + c.getEnvVarsAsCliOption() +
+               " " + c.name + " " + cliCommand
+       c.Suite().log(containerExecCommand)
+       byteOutput, err := exechelper.CombinedOutput(containerExecCommand)
+       c.Suite().assertNil(err)
+       return string(byteOutput)
 }
 
 func (c *Container) execAction(args string) (string, error) {
index 1b24e08..b32d66e 100644 (file)
@@ -2,18 +2,16 @@ package main
 
 func (s *VethsSuite) TestEchoBuiltin() {
        serverVpp := s.getContainerByName("server-vpp").vppInstance
-       serverVeth := s.veths["vppsrv"]
+       serverVeth := s.netInterfaces["vppsrv"]
 
-       _, err := serverVpp.vppctl("test echo server " +
+       serverVpp.vppctl("test echo server " +
                " private-segment-size 1g fifo-size 4 no-echo" +
-               " uri tcp://" + serverVeth.Address() + "/1234")
-       s.assertNil(err)
+               " uri tcp://" + serverVeth.Ip4AddressString() + "/1234")
 
        clientVpp := s.getContainerByName("client-vpp").vppInstance
 
-       o, err := clientVpp.vppctl("test echo client nclients 10000 bytes 1" +
+       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.Address() + "/1234")
-       s.assertNil(err)
+               " fifo-size 4 uri tcp://" + serverVeth.Ip4AddressString() + "/1234")
        s.log(o)
 }
index 9cf38d9..24b4fc2 100644 (file)
@@ -8,10 +8,13 @@ import (
        "github.com/edwarnicke/exechelper"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/suite"
-       "go.fd.io/govpp/binapi/ip_types"
        "gopkg.in/yaml.v3"
 )
 
+const (
+       defaultNamespaceName string = "default"
+)
+
 func IsPersistent() bool {
        return os.Getenv("HST_PERSIST") == "1"
 }
@@ -22,14 +25,12 @@ func IsVerbose() bool {
 
 type HstSuite struct {
        suite.Suite
-       teardownSuite     func()
-       containers        map[string]*Container
-       volumes           []string
-       networkNamespaces map[string]*NetworkNamespace
-       veths             map[string]*NetworkInterfaceVeth
-       taps              map[string]*NetworkInterfaceTap
-       bridges           map[string]*NetworkBridge
-       numberOfAddresses int
+       teardownSuite func()
+       containers    map[string]*Container
+       volumes       []string
+       netConfigs    []NetConfig
+       netInterfaces map[string]NetInterface
+       addresser     *Addresser
 }
 
 func (s *HstSuite) TearDownSuite() {
@@ -138,9 +139,11 @@ func (s *HstSuite) getContainerByName(name string) *Container {
        return s.containers[name]
 }
 
-func (s *HstSuite) getContainerCopyByName(name string) *Container {
-       // Create a copy and return its address, so that individial tests which call this
-       // are not able to modify the original container and affect other tests by doing that
+/*
+ * Create a copy and return its address, so that individial tests which call this
+ * are not able to modify the original container and affect other tests by doing that
+ */
+func (s *HstSuite) getTransientContainerByName(name string) *Container {
        containerCopy := *s.containers[name]
        return &containerCopy
 }
@@ -185,32 +188,32 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
                s.T().Fatalf("unmarshal error: %v", err)
        }
 
-       s.networkNamespaces = make(map[string]*NetworkNamespace)
-       s.veths = make(map[string]*NetworkInterfaceVeth)
-       s.taps = make(map[string]*NetworkInterfaceTap)
-       s.bridges = make(map[string]*NetworkBridge)
+       s.addresser = NewAddresser(s)
+       s.netInterfaces = make(map[string]NetInterface)
        for _, elem := range yamlTopo.Devices {
                switch elem["type"].(string) {
                case NetNs:
                        {
                                if namespace, err := NewNetNamespace(elem); err == nil {
-                                       s.networkNamespaces[namespace.Name()] = &namespace
+                                       s.netConfigs = append(s.netConfigs, &namespace)
                                } else {
                                        s.T().Fatalf("network config error: %v", err)
                                }
                        }
                case Veth:
                        {
-                               if veth, err := NewVeth(elem); err == nil {
-                                       s.veths[veth.Name()] = &veth
+                               if veth, err := NewVeth(elem, s.addresser); err == nil {
+                                       s.netConfigs = append(s.netConfigs, &veth)
+                                       s.netInterfaces[veth.Name()] = &veth
                                } else {
                                        s.T().Fatalf("network config error: %v", err)
                                }
                        }
                case Tap:
                        {
-                               if tap, err := NewTap(elem); err == nil {
-                                       s.taps[tap.Name()] = &tap
+                               if tap, err := NewTap(elem, s.addresser); err == nil {
+                                       s.netConfigs = append(s.netConfigs, &tap)
+                                       s.netInterfaces[tap.Name()] = &tap
                                } else {
                                        s.T().Fatalf("network config error: %v", err)
                                }
@@ -218,7 +221,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
                case Bridge:
                        {
                                if bridge, err := NewBridge(elem); err == nil {
-                                       s.bridges[bridge.Name()] = &bridge
+                                       s.netConfigs = append(s.netConfigs, &bridge)
                                } else {
                                        s.T().Fatalf("network config error: %v", err)
                                }
@@ -230,23 +233,8 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
 func (s *HstSuite) configureNetworkTopology(topologyName string) {
        s.loadNetworkTopology(topologyName)
 
-       for _, ns := range s.networkNamespaces {
-               if err := ns.Configure(); err != nil {
-                       s.T().Fatalf("network config error: %v", err)
-               }
-       }
-       for _, veth := range s.veths {
-               if err := veth.Configure(); err != nil {
-                       s.T().Fatalf("network config error: %v", err)
-               }
-       }
-       for _, tap := range s.taps {
-               if err := tap.Configure(); err != nil {
-                       s.T().Fatalf("network config error: %v", err)
-               }
-       }
-       for _, bridge := range s.bridges {
-               if err := bridge.Configure(); err != nil {
+       for _, nc := range s.netConfigs {
+               if err := nc.Configure(); err != nil {
                        s.T().Fatalf("network config error: %v", err)
                }
        }
@@ -256,34 +244,52 @@ func (s *HstSuite) unconfigureNetworkTopology() {
        if IsPersistent() {
                return
        }
-       for _, ns := range s.networkNamespaces {
-               ns.Unconfigure()
-       }
-       for _, veth := range s.veths {
-               veth.Unconfigure()
-       }
-       for _, tap := range s.taps {
-               tap.Unconfigure()
-       }
-       for _, bridge := range s.bridges {
-               bridge.Unconfigure()
+       for _, nc := range s.netConfigs {
+               nc.Unconfigure()
        }
 }
 
-func (s *HstSuite) NewAddress() (AddressWithPrefix, error) {
-       var ipPrefix AddressWithPrefix
-       var err error
+type NamespaceAddresses struct {
+       namespace         string
+       numberOfAddresses int
+}
 
-       if s.numberOfAddresses == 255 {
-               s.T().Fatalf("no available IPv4 addresses")
+type Addresser struct {
+       namespaces []*NamespaceAddresses
+       suite      *HstSuite
+}
+
+func (a *Addresser) AddNamespace(name string) {
+       var newNamespace = &NamespaceAddresses{
+               namespace:         name,
+               numberOfAddresses: 0,
        }
+       a.namespaces = append(a.namespaces, newNamespace)
+}
 
-       address := fmt.Sprintf("10.10.10.%v/24", s.numberOfAddresses+1)
-       ipPrefix, err = ip_types.ParseAddressWithPrefix(address)
-       if err != nil {
-               return AddressWithPrefix{}, err
+func (a *Addresser) NewIp4Address() (string, error) {
+       return a.NewIp4AddressWithNamespace(defaultNamespaceName)
+}
+
+func (a *Addresser) NewIp4AddressWithNamespace(namespace string) (string, error) {
+       for i, val := range a.namespaces {
+               if val.namespace != namespace {
+                       continue
+               }
+               if val.numberOfAddresses == 255 {
+                       return "", fmt.Errorf("no available IPv4 addresses")
+               }
+               address := fmt.Sprintf("10.10.%v.%v/24", i, val.numberOfAddresses+1)
+               val.numberOfAddresses++
+               return address, nil
        }
-       s.numberOfAddresses++
+       a.AddNamespace(namespace)
+       return a.NewIp4AddressWithNamespace(namespace)
+}
 
-       return ipPrefix, nil
+func NewAddresser(suite *HstSuite) *Addresser {
+       var addresser = new(Addresser)
+       addresser.suite = suite
+       addresser.AddNamespace(defaultNamespaceName)
+       return addresser
 }
index 52b7c39..912c982 100644 (file)
@@ -9,21 +9,19 @@ import (
 )
 
 func (s *NsSuite) TestHttpTps() {
-       finished := make(chan error, 1)
-       server_ip := "10.0.0.2"
+       iface := s.netInterfaces[clientInterface]
+       client_ip := iface.Ip4AddressString()
        port := "8080"
+       finished := make(chan error, 1)
 
        container := s.getContainerByName("vpp")
 
-       s.log("starting vpp..")
-
-       // start & configure vpp in the container
-       _, err := container.execAction("ConfigureHttpTps")
-       s.assertNil(err)
+       // configure vpp in the container
+       container.vppInstance.vppctl("http tps uri tcp://0.0.0.0/8080")
 
-       go startWget(finished, server_ip, port, "test_file_10M", "client")
+       go startWget(finished, client_ip, port, "test_file_10M", "client")
        // wait for client
-       err = <-finished
+       err := <-finished
        s.assertNil(err)
 }
 
@@ -31,16 +29,14 @@ func (s *VethsSuite) TestHttpCli() {
        serverContainer := s.getContainerByName("server-vpp")
        clientContainer := s.getContainerByName("client-vpp")
 
-       serverVeth := s.veths["vppsrv"]
+       serverVeth := s.netInterfaces[serverInterfaceName]
 
-       _, err := serverContainer.vppInstance.vppctl("http cli server")
-       s.assertNil(err)
+       serverContainer.vppInstance.vppctl("http cli server")
 
-       uri := "http://" + serverVeth.Address() + "/80"
+       uri := "http://" + serverVeth.Ip4AddressString() + "/80"
 
-       o, err := clientContainer.vppInstance.vppctl("http cli client" +
+       o := clientContainer.vppInstance.vppctl("http cli client" +
                " uri " + uri + " query /show/version")
-       s.assertNil(err)
 
        s.log(o)
        s.assertContains(o, "<html>", "<html> not found in the result!")
@@ -48,10 +44,7 @@ func (s *VethsSuite) TestHttpCli() {
 
 func waitForApp(vppInst *VppInstance, appName string, timeout int) error {
        for i := 0; i < timeout; i++ {
-               o, err := vppInst.vppctl("show app")
-               if err != nil {
-                       return fmt.Errorf("Error ocurred during 'show app'")
-               }
+               o := vppInst.vppctl("show app")
                if strings.Contains(o, appName) {
                        return nil
                }
index cbba227..17f78ca 100644 (file)
@@ -3,17 +3,16 @@ package main
 import (
        "fmt"
        "os"
-       "time"
 )
 
 func (s *VethsSuite) TestLDPreloadIperfVpp() {
        var clnVclConf, srvVclConf Stanza
 
        serverContainer := s.getContainerByName("server-vpp")
-       srvVcl := serverContainer.GetHostWorkDir() + "/vcl_srv.conf"
+       serverVclFileName := serverContainer.GetHostWorkDir() + "/vcl_srv.conf"
 
        clientContainer := s.getContainerByName("client-vpp")
-       clnVcl := clientContainer.GetHostWorkDir() + "/vcl_cln.conf"
+       clientVclFileName := clientContainer.GetHostWorkDir() + "/vcl_cln.conf"
 
        ldpreload := os.Getenv("HST_LDPRELOAD")
        s.assertNotEqual("", ldpreload)
@@ -26,15 +25,9 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
 
        s.log("starting VPPs")
 
-       _, err := serverContainer.execAction("Configure2Veths srv")
-       s.assertNil(err)
-
-       _, err = clientContainer.execAction("Configure2Veths cln")
-       s.assertNil(err)
-
        clientAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/2",
                clientContainer.GetContainerWorkDir())
-       err = clnVclConf.
+       err := clnVclConf.
                NewStanza("vcl").
                Append("rx-fifo-size 4000000").
                Append("tx-fifo-size 4000000").
@@ -42,7 +35,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
                Append("app-scope-global").
                Append("use-mq-eventfd").
                Append(clientAppSocketApi).Close().
-               SaveToFile(clnVcl)
+               SaveToFile(clientVclFileName)
        s.assertNil(err)
 
        serverAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/1",
@@ -55,15 +48,12 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
                Append("app-scope-global").
                Append("use-mq-eventfd").
                Append(serverAppSocketApi).Close().
-               SaveToFile(srvVcl)
+               SaveToFile(serverVclFileName)
        s.assertNil(err)
 
        s.log("attaching server to vpp")
 
-       // FIXME
-       time.Sleep(5 * time.Second)
-
-       srvEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+srvVcl)
+       srvEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+serverVclFileName)
        go StartServerApp(srvCh, stopServerCh, srvEnv)
 
        err = <-srvCh
@@ -71,8 +61,9 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
 
        s.log("attaching client to vpp")
        var clnRes = make(chan string, 1)
-       clnEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+clnVcl)
-       go StartClientApp(clnEnv, clnCh, clnRes)
+       clnEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+clientVclFileName)
+       serverVethAddress := s.netInterfaces[serverInterfaceName].Ip4AddressString()
+       go StartClientApp(serverVethAddress, clnEnv, clnCh, clnRes)
        s.log(<-clnRes)
 
        // wait for client's result
index 833fb2c..154a9b5 100644 (file)
@@ -13,7 +13,9 @@ func (s *TapSuite) TestLinuxIperf() {
        err := <-srvCh
        s.assertNil(err)
        s.log("server running")
-       go StartClientApp(nil, clnCh, clnRes)
+
+       ipAddress := s.netInterfaces["tap0"].Ip4AddressString()
+       go StartClientApp(ipAddress, nil, clnCh, clnRes)
        s.log("client running")
        s.log(<-clnRes)
        err = <-clnCh
index 98627a5..8fa1458 100644 (file)
@@ -5,7 +5,6 @@ import (
        "encoding/json"
        "fmt"
        "os"
-       "os/exec"
        "os/signal"
        "reflect"
 )
@@ -20,16 +19,6 @@ func newVppContext() (context.Context, context.CancelFunc) {
        return ctx, cancel
 }
 
-func Vppcli(runDir, command string) (string, error) {
-       cmd := exec.Command("vppctl", "-s", fmt.Sprintf("%s/var/run/vpp/cli.sock", runDir), command)
-       o, err := cmd.CombinedOutput()
-       if err != nil {
-               fmt.Printf("failed to execute command: '%v'.\n", err)
-       }
-       fmt.Printf("Command output %s", string(o))
-       return string(o), err
-}
-
 func exitOnErrCh(ctx context.Context, cancel context.CancelFunc, errCh <-chan error) {
        // If we already have an error, log it and exit
        select {
index b93e460..45ff379 100644 (file)
@@ -12,35 +12,56 @@ import (
 )
 
 type (
-       AddressWithPrefix = ip_types.AddressWithPrefix
        MacAddress        = ethernet_types.MacAddress
+       AddressWithPrefix = ip_types.AddressWithPrefix
+       InterfaceIndex    = interface_types.InterfaceIndex
 
-       NetConfig struct {
+       LegacyNetConfig struct {
                Configure   func() error
                Unconfigure func()
        }
 
-       NetTopology []NetConfig
+       NetTopology []LegacyNetConfig
+
+       NetConfig interface {
+               Configure() error
+               Unconfigure()
+               Name() string
+               Type() string
+       }
 
        NetConfigBase struct {
                name     string
                category string // what else to call this when `type` is reserved?
        }
 
-       NetworkInterfaceVeth struct {
+       NetInterface interface {
+               NetConfig
+               SetAddress(string)
+               Ip4AddressWithPrefix() AddressWithPrefix
+               Ip4AddressString() string
+               SetIndex(InterfaceIndex)
+               Index() InterfaceIndex
+               HwAddress() MacAddress
+       }
+
+       NetInterfaceBase struct {
                NetConfigBase
-               index                interface_types.InterfaceIndex
+               addresser  *Addresser
+               ip4address string // this will have form 10.10.10.1/24
+               index      InterfaceIndex
+               hwAddress  MacAddress
+       }
+
+       NetworkInterfaceVeth struct {
+               NetInterfaceBase
                peerNetworkNamespace string
                peerName             string
                peerIp4Address       string
-               ip4Address           ip_types.AddressWithPrefix
-               hwAddress            ethernet_types.MacAddress
        }
 
        NetworkInterfaceTap struct {
-               NetConfigBase
-               index      interface_types.InterfaceIndex
-               ip4Address string
+               NetInterfaceBase
        }
 
        NetworkNamespace struct {
@@ -61,15 +82,40 @@ const (
        Bridge string = "bridge"
 )
 
-func (b NetConfigBase) Name() string {
+func (b *NetConfigBase) Name() string {
        return b.name
 }
 
-func (b NetConfigBase) Type() string {
+func (b *NetConfigBase) Type() string {
        return b.category
 }
 
-func (iface NetworkInterfaceVeth) Configure() error {
+func (b *NetInterfaceBase) SetAddress(address string) {
+       b.ip4address = address
+}
+
+func (b *NetInterfaceBase) SetIndex(index InterfaceIndex) {
+       b.index = index
+}
+
+func (b *NetInterfaceBase) Index() InterfaceIndex {
+       return b.index
+}
+
+func (b *NetInterfaceBase) Ip4AddressWithPrefix() AddressWithPrefix {
+       address, _ := ip_types.ParseAddressWithPrefix(b.ip4address)
+       return address
+}
+
+func (b *NetInterfaceBase) Ip4AddressString() string {
+       return strings.Split(b.ip4address, "/")[0]
+}
+
+func (b *NetInterfaceBase) HwAddress() MacAddress {
+       return b.hwAddress
+}
+
+func (iface *NetworkInterfaceVeth) Configure() error {
        err := AddVethPair(iface.name, iface.peerName)
        if err != nil {
                return err
@@ -91,39 +137,39 @@ func (iface NetworkInterfaceVeth) Configure() error {
        return nil
 }
 
-func (iface NetworkInterfaceVeth) Unconfigure() {
+func (iface *NetworkInterfaceVeth) Unconfigure() {
        DelLink(iface.name)
 }
 
-func (iface NetworkInterfaceVeth) Address() string {
-       return strings.Split(iface.ip4Address.String(), "/")[0]
+func (iface *NetworkInterfaceVeth) PeerIp4AddressString() string {
+       return strings.Split(iface.peerIp4Address, "/")[0]
 }
 
-func (iface NetworkInterfaceTap) Configure() error {
-       err := AddTap(iface.name, iface.ip4Address)
+func (iface *NetworkInterfaceTap) Configure() error {
+       err := AddTap(iface.name, iface.Ip4AddressString())
        if err != nil {
                return err
        }
        return nil
 }
 
-func (iface NetworkInterfaceTap) Unconfigure() {
+func (iface *NetworkInterfaceTap) Unconfigure() {
        DelLink(iface.name)
 }
 
-func (ns NetworkNamespace) Configure() error {
+func (ns *NetworkNamespace) Configure() error {
        return addDelNetns(ns.name, true)
 }
 
-func (ns NetworkNamespace) Unconfigure() {
+func (ns *NetworkNamespace) Unconfigure() {
        addDelNetns(ns.name, false)
 }
 
-func (b NetworkBridge) Configure() error {
+func (b *NetworkBridge) Configure() error {
        return AddBridge(b.name, b.interfaces, b.networkNamespace)
 }
 
-func (b NetworkBridge) Unconfigure() {
+func (b *NetworkBridge) Unconfigure() {
        DelBridge(b.name, b.networkNamespace)
 }
 
@@ -176,8 +222,6 @@ func newConfigFn(cfg NetDevConfig) func() error {
                }
        } else if t == "bridge" {
                return func() error { return configureBridge(cfg) }
-       } else if t == "tap" {
-               return func() error { return configureTap(cfg) }
        }
        return nil
 }
@@ -186,9 +230,7 @@ func newUnconfigFn(cfg NetDevConfig) func() {
        t := cfg["type"]
        name := cfg["name"].(string)
 
-       if t == "tap" {
-               return func() { DelLink(name) }
-       } else if t == "netns" {
+       if t == "netns" {
                return func() { DelNetns(name) }
        } else if t == "veth" {
                return func() { DelLink(name) }
@@ -198,8 +240,8 @@ func newUnconfigFn(cfg NetDevConfig) func() {
        return nil
 }
 
-func NewNetConfig(cfg NetDevConfig) NetConfig {
-       var nc NetConfig
+func NewNetConfig(cfg NetDevConfig) LegacyNetConfig {
+       var nc LegacyNetConfig
 
        nc.Configure = newConfigFn(cfg)
        nc.Unconfigure = newUnconfigFn(cfg)
@@ -225,9 +267,10 @@ func NewBridge(cfg NetDevConfig) (NetworkBridge, error) {
        return bridge, nil
 }
 
-func NewVeth(cfg NetDevConfig) (NetworkInterfaceVeth, error) {
+func NewVeth(cfg NetDevConfig, a *Addresser) (NetworkInterfaceVeth, error) {
        var veth NetworkInterfaceVeth
        var err error
+       veth.addresser = a
        veth.name = cfg["name"].(string)
        veth.category = "veth"
 
@@ -246,18 +289,27 @@ func NewVeth(cfg NetDevConfig) (NetworkInterfaceVeth, error) {
                veth.peerNetworkNamespace = peer["netns"].(string)
        }
 
-       if peer["ip4"] != nil {
-               veth.peerIp4Address = peer["ip4"].(string)
+       if peer["ip4"] != nil && peer["ip4"].(bool) == true {
+               veth.peerIp4Address, err = veth.addresser.
+                       NewIp4AddressWithNamespace(veth.peerNetworkNamespace)
+               if err != nil {
+                       return NetworkInterfaceVeth{}, err
+               }
        }
 
        return veth, nil
 }
 
-func NewTap(cfg NetDevConfig) (NetworkInterfaceTap, error) {
+func NewTap(cfg NetDevConfig, a *Addresser) (NetworkInterfaceTap, error) {
        var tap NetworkInterfaceTap
+       tap.addresser = a
        tap.name = cfg["name"].(string)
        tap.category = "tap"
-       tap.ip4Address = cfg["ip4"].(string)
+       ip4Address, err := tap.addresser.NewIp4Address()
+       if err != nil {
+               return NetworkInterfaceTap{}, err
+       }
+       tap.SetAddress(ip4Address)
        return tap, nil
 }
 
index f592426..4c18351 100644 (file)
@@ -18,7 +18,7 @@ func testProxyHttpTcp(s *NsSuite) error {
        s.assertNil(err, "failed to run truncate command")
        defer func() { os.Remove(srcFile) }()
 
-       s.log("Test file created...")
+       s.log("test file created...")
 
        go startHttpServer(serverRunning, stopServer, ":666", "server")
        // TODO better error handling and recovery
@@ -30,7 +30,15 @@ func testProxyHttpTcp(s *NsSuite) error {
 
        s.log("http server started...")
 
-       c := fmt.Sprintf("ip netns exec client wget --no-proxy --retry-connrefused --retry-on-http-error=503 --tries=10 -O %s 10.0.0.2:555/%s", outputFile, srcFile)
+       clientVeth := s.netInterfaces[clientInterface]
+       c := fmt.Sprintf("ip netns exec client wget --no-proxy --retry-connrefused"+
+               " --retry-on-http-error=503 --tries=10"+
+               " -O %s %s:555/%s",
+               outputFile,
+               clientVeth.Ip4AddressString(),
+               srcFile,
+       )
+       s.log(c)
        _, err = exechelper.CombinedOutput(c)
        s.assertNil(err, "failed to run wget")
        stopServer <- struct{}{}
@@ -42,16 +50,17 @@ func testProxyHttpTcp(s *NsSuite) error {
 }
 
 func configureVppProxy(s *NsSuite) error {
-       container := s.getContainerByName("vpp")
-       testVppProxy := NewVppInstance(container)
-       testVppProxy.setVppProxy()
-       err := testVppProxy.start()
-       s.assertNil(err, "failed to start and configure VPP")
-       s.log("VPP running and configured...")
-
-       output, err := testVppProxy.vppctl("test proxy server server-uri tcp://10.0.0.2/555 client-uri tcp://10.0.1.1/666")
-       s.log("Proxy configured...", string(output))
-       return err
+       serverVeth := s.netInterfaces[serverInterface].(*NetworkInterfaceVeth)
+       clientVeth := s.netInterfaces[clientInterface]
+
+       testVppProxy := s.getContainerByName("vpp").vppInstance
+       output := testVppProxy.vppctl(
+               "test proxy server server-uri tcp://%s/555 client-uri tcp://%s/666",
+               clientVeth.Ip4AddressString(),
+               serverVeth.PeerIp4AddressString(),
+       )
+       s.log("proxy configured...", output)
+       return nil
 }
 
 func (s *NsSuite) TestVppProxyHttpTcp() {
@@ -62,12 +71,6 @@ func (s *NsSuite) TestVppProxyHttpTcp() {
 }
 
 func configureEnvoyProxy(s *NsSuite) error {
-       vppContainer := s.getContainerByName("vpp")
-       testVppForEnvoyProxy := NewVppInstance(vppContainer)
-       testVppForEnvoyProxy.setEnvoyProxy()
-       err := testVppForEnvoyProxy.start()
-       s.assertNil(err, "failed to start and configure VPP")
-
        envoyContainer := s.getContainerByName("envoy")
        return envoyContainer.run()
 }
index e4a5b81..2093b56 100644 (file)
@@ -43,7 +43,8 @@ static_resources:
         - endpoint:
             address:
               socket_address:
-                address: 10.0.1.1
+                # following address will be generated by Addresser during test run
+                address: 10.10.2.1
                 port_value: 666
 bootstrap_extensions:
   - name: envoy.extensions.vcl.vcl_socket_interface
index cf7f0ec..5bc45c7 100644 (file)
@@ -1,10 +1,45 @@
 package main
 
+const (
+       // These correspond to names used in yaml config
+       clientInterface = "hst_client_vpp"
+       serverInterface = "hst_server_vpp"
+)
+
 type NsSuite struct {
        HstSuite
 }
 
 func (s *NsSuite) SetupSuite() {
-       s.teardownSuite = setupSuite(&s.Suite, "ns")
+       s.configureNetworkTopology("ns")
+
        s.loadContainerTopology("ns")
 }
+
+func (s *NsSuite) SetupTest() {
+       s.SetupVolumes()
+       s.SetupContainers()
+
+       // Setup test conditions
+       var startupConfig Stanza
+       startupConfig.
+               NewStanza("session").
+               Append("enable").
+               Append("use-app-socket-api").
+               Append("evt_qs_memfd_seg").
+               Append("event-queue-length 100000").Close()
+
+       container := s.getContainerByName("vpp")
+       vpp, _ := container.newVppInstance(startupConfig)
+       vpp.start()
+
+       idx, err := vpp.createAfPacket(s.netInterfaces[serverInterface])
+       s.assertNil(err)
+       s.assertNotEqual(0, idx)
+
+       idx, err = vpp.createAfPacket(s.netInterfaces[clientInterface])
+       s.assertNil(err)
+       s.assertNotEqual(0, idx)
+
+       container.exec("chmod 777 -R %s", container.GetContainerWorkDir())
+}
index 26f5224..96f475c 100644 (file)
@@ -10,5 +10,6 @@ type TapSuite struct {
 
 func (s *TapSuite) SetupSuite() {
        time.Sleep(1 * time.Second)
-       s.teardownSuite = setupSuite(&s.Suite, "tap")
+
+       s.configureNetworkTopology("tap")
 }
index 81a21a2..ff79dfa 100644 (file)
@@ -14,13 +14,6 @@ type VethsSuite struct {
        HstSuite
 }
 
-var ConvertedTests = map[string]any{
-       "TestVeths/TestEchoBuiltin":    "",
-       "TestVeths/TestHttpCli":        "",
-       "TestVeths/TestVclEchoTcp":     "",
-       "TestVeths/TestVclRetryAttach": "",
-}
-
 func (s *VethsSuite) SetupSuite() {
        time.Sleep(1 * time.Second)
 
@@ -33,11 +26,6 @@ func (s *VethsSuite) SetupTest() {
        s.SetupVolumes()
        s.SetupContainers()
 
-       // TODO remove this after all tests are converted to configuration from test suite
-       if _, ok := ConvertedTests[s.T().Name()]; !ok {
-               return
-       }
-
        // Setup test conditions
 
        var startupConfig Stanza
@@ -69,7 +57,7 @@ func (s *VethsSuite) setupServerVpp() {
        err := serverVpp.start()
        s.assertNil(err)
 
-       serverVeth := s.veths["vppsrv"]
+       serverVeth := s.netInterfaces[serverInterfaceName]
        idx, err := serverVpp.createAfPacket(serverVeth)
        s.assertNil(err)
        s.assertNotEqual(0, idx)
@@ -86,7 +74,7 @@ func (s *VethsSuite) setupClientVpp() {
        err := clientVpp.start()
        s.assertNil(err)
 
-       clientVeth := s.veths["vppcln"]
+       clientVeth := s.netInterfaces[clientInterfaceName]
        idx, err := clientVpp.createAfPacket(clientVeth)
        s.assertNil(err)
        s.assertNotEqual(0, idx)
index 9416937..fddf2d8 100644 (file)
@@ -1,7 +1,7 @@
 ---
 volumes:
   - volume: &shared-vol
-      host-dir: shared-vol
+      host-dir: /tmp/shared-vol
 
 # $HST_DIR will be replaced during runtime by path to hs-test directory
 containers:
index 2f7ed39..c018365 100644 (file)
@@ -6,16 +6,16 @@ devices:
   - name: "server"
     type: "netns"
 
-  - name: "vpp0"
+  - name: "hst_client_vpp"
     type: "veth"
     peer:
       name: "client"
       netns: "client"
-      ip4: "10.0.0.1/24"
+      ip4: true
 
-  - name: "vpp1"
+  - name: "hst_server_vpp"
     type: "veth"
     peer:
       name: "server"
       netns: "server"
-      ip4: "10.0.1.1/24"
+      ip4: true
index 4cd95d6..6f04132 100644 (file)
@@ -2,4 +2,3 @@
 devices:
   - name: "tap0"
     type: "tap"
-    ip4: "10.10.10.1/24"
index cf30ece..c588903 100644 (file)
@@ -98,7 +98,7 @@ func StartServerApp(running chan error, done chan struct{}, env []string) {
        cmd.Process.Kill()
 }
 
-func StartClientApp(env []string, clnCh chan error, clnRes chan string) {
+func StartClientApp(ipAddress string, env []string, clnCh chan error, clnRes chan string) {
        defer func() {
                clnCh <- nil
        }()
@@ -106,7 +106,7 @@ func StartClientApp(env []string, clnCh chan error, clnRes chan string) {
        nTries := 0
 
        for {
-               cmd := exec.Command("iperf3", "-c", "10.10.10.1", "-u", "-l", "1460", "-b", "10g")
+               cmd := exec.Command("iperf3", "-c", ipAddress, "-u", "-l", "1460", "-b", "10g")
                if env != nil {
                        cmd.Env = env
                }
@@ -183,12 +183,15 @@ func startWget(finished chan error, server_ip, port, query, netNs string) {
                finished <- errors.New("wget error")
        }()
 
-       cmd := NewCommand([]string{"wget", "--no-proxy", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + query},
+       cmd := NewCommand([]string{"wget", "--timeout=10", "--no-proxy", "--tries=5", "-O", "/dev/null", server_ip + ":" + port + "/" + query},
                netNs)
        o, err := cmd.CombinedOutput()
        if err != nil {
                finished <- fmt.Errorf("wget error: '%v\n\n%s'", err, o)
                return
+       } else if strings.Contains(string(o), "200 OK") == false {
+               finished <- fmt.Errorf("wget error: response not 200 OK")
+               return
        }
        finished <- nil
 }
index 6c809f4..b9ce60a 100644 (file)
@@ -20,7 +20,7 @@ func (s *VethsSuite) TestVclEchoTcp() {
 }
 
 func (s *VethsSuite) testVclEcho(proto string) {
-       serverVethAddress := s.veths["vppsrv"].Address()
+       serverVethAddress := s.netInterfaces["vppsrv"].Ip4AddressString()
        uri := proto + "://" + serverVethAddress + "/12344"
 
        echoSrvContainer := s.getContainerByName("server-application")
@@ -29,8 +29,7 @@ func (s *VethsSuite) testVclEcho(proto string) {
                " use-app-socket-api" +
                " uri " + uri
        s.log(serverCommand)
-       err := echoSrvContainer.execServer(serverCommand)
-       s.assertNil(err)
+       echoSrvContainer.execServer(serverCommand)
 
        echoClnContainer := s.getContainerByName("client-application")
 
@@ -38,8 +37,7 @@ func (s *VethsSuite) testVclEcho(proto string) {
                " socket-name " + echoClnContainer.GetContainerWorkDir() + "/var/run/app_ns_sockets/2" +
                " use-app-socket-api uri " + uri
        s.log(clientCommand)
-       o, err := echoClnContainer.exec(clientCommand)
-       s.assertNil(err)
+       o := echoClnContainer.exec(clientCommand)
 
        s.log(o)
 }
@@ -50,7 +48,7 @@ func (s *VethsSuite) TestVclRetryAttach() {
 }
 
 func (s *VethsSuite) testRetryAttach(proto string) {
-       srvVppContainer := s.getContainerCopyByName("server-vpp")
+       srvVppContainer := s.getTransientContainerByName("server-vpp")
 
        echoSrvContainer := s.getContainerByName("server-application")
 
@@ -58,31 +56,28 @@ func (s *VethsSuite) testRetryAttach(proto string) {
        echoSrvContainer.createFile("/vcl.conf", serverVclConfContent)
 
        echoSrvContainer.addEnvVar("VCL_CONFIG", "/vcl.conf")
-       err := echoSrvContainer.execServer("vcl_test_server -p " + proto + " 12346")
-       s.assertNil(err)
+       echoSrvContainer.execServer("vcl_test_server -p " + proto + " 12346")
 
        s.log("This whole test case can take around 3 minutes to run. Please be patient.")
        s.log("... Running first echo client test, before disconnect.")
 
-       serverVeth := s.veths[serverInterfaceName]
-       serverVethAddress := serverVeth.Address()
+       serverVeth := s.netInterfaces[serverInterfaceName]
+       serverVethAddress := serverVeth.Ip4AddressString()
 
-       echoClnContainer := s.getContainerCopyByName("client-application")
+       echoClnContainer := s.getTransientContainerByName("client-application")
        clientVclConfContent := fmt.Sprintf(vclTemplate, echoClnContainer.GetContainerWorkDir(), "2")
        echoClnContainer.createFile("/vcl.conf", clientVclConfContent)
 
        testClientCommand := "vcl_test_client -U -p " + proto + " " + serverVethAddress + " 12346"
        echoClnContainer.addEnvVar("VCL_CONFIG", "/vcl.conf")
-       o, err := echoClnContainer.exec(testClientCommand)
+       o := echoClnContainer.exec(testClientCommand)
        s.log(o)
-       s.assertNil(err)
        s.log("... First test ended. Stopping VPP server now.")
 
        // Stop server-vpp-instance, start it again and then run vcl-test-client once more
        srvVppContainer.vppInstance.disconnect()
        stopVppCommand := "/bin/bash -c 'ps -C vpp_main -o pid= | xargs kill -9'"
-       _, err = srvVppContainer.exec(stopVppCommand)
-       s.assertNil(err)
+       srvVppContainer.exec(stopVppCommand)
 
        s.setupServerVpp()
 
@@ -90,47 +85,33 @@ func (s *VethsSuite) testRetryAttach(proto string) {
        time.Sleep(30 * time.Second) // Wait a moment for the re-attachment to happen
 
        s.log("... Running second echo client test, after disconnect and re-attachment.")
-       o, err = echoClnContainer.exec(testClientCommand)
+       o = echoClnContainer.exec(testClientCommand)
        s.log(o)
-       s.assertNil(err)
        s.log("Done.")
 }
 
 func (s *VethsSuite) TestTcpWithLoss() {
-       serverContainer := s.getContainerByName("server-vpp")
+       serverVpp := s.getContainerByName("server-vpp").vppInstance
 
-       serverVpp := NewVppInstance(serverContainer)
-       s.assertNotNil(serverVpp)
-       serverVpp.set2VethsServer()
-       err := serverVpp.start()
-       s.assertNil(err, "starting VPP failed")
+       serverVeth := s.netInterfaces[serverInterfaceName]
+       serverVpp.vppctl("test echo server uri tcp://%s/20022",
+               serverVeth.Ip4AddressString())
 
-       serverVeth := s.veths[serverInterfaceName]
-       _, err = serverVpp.vppctl("test echo server uri tcp://%s/20022", serverVeth.Address())
-       s.assertNil(err, "starting echo server failed")
-
-       clientContainer := s.getContainerByName("client-vpp")
-
-       clientVpp := NewVppInstance(clientContainer)
-       s.assertNotNil(clientVpp)
-       clientVpp.set2VethsClient()
-       err = clientVpp.start()
-       s.assertNil(err, "starting VPP failed")
+       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!
-       _, err = serverVpp.vppctl("ping 10.10.10.2")
-       s.assertNil(err, "ping failed")
+       clientVpp.vppctl("ping %s", serverVeth.Ip4AddressString())
 
        // Add loss of packets with Network Delay Simulator
-       _, err = clientVpp.vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit packet-size 1400 packets-per-drop 1000")
-       s.assertNil(err, "configuring NSIM failed")
-       _, err = clientVpp.vppctl("nsim output-feature enable-disable host-vppcln")
-       s.assertNil(err, "enabling NSIM failed")
+       clientVpp.vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit" +
+               " packet-size 1400 packets-per-drop 1000")
+
+       clientVpp.vppctl("nsim output-feature enable-disable host-vppcln")
 
        // Do echo test from client-vpp container
-       output, err := clientVpp.vppctl("test echo client uri tcp://10.10.10.1/20022 mbytes 50")
-       s.assertNil(err)
+       output := clientVpp.vppctl("test echo client uri tcp://%s/20022 mbytes 50",
+               serverVeth.Ip4AddressString())
        s.assertEqual(true, len(output) != 0)
        s.assertNotContains(output, "failed: timeout")
        s.log(output)
index 3f9ea87..257798a 100644 (file)
@@ -75,14 +75,8 @@ func (vc *VppConfig) getTemplate() string {
        return fmt.Sprintf(vppConfigTemplate, "%[1]s", vc.CliSocketFilePath)
 }
 
-func (vpp *VppInstance) set2VethsServer() {
-       vpp.actionFuncName = "Configure2Veths"
-       vpp.config.Variant = "srv"
-}
-
-func (vpp *VppInstance) set2VethsClient() {
-       vpp.actionFuncName = "Configure2Veths"
-       vpp.config.Variant = "cln"
+func (vpp *VppInstance) Suite() *HstSuite {
+       return vpp.container.suite
 }
 
 func (vpp *VppInstance) setVppProxy() {
@@ -114,10 +108,6 @@ func (vpp *VppInstance) getEtcDir() string {
 }
 
 func (vpp *VppInstance) legacyStart() error {
-       if vpp.actionFuncName == "" {
-               return fmt.Errorf("vpp start failed: action function name must not be blank")
-       }
-
        serializedConfig, err := serializeVppConfig(vpp.config)
        if err != nil {
                return fmt.Errorf("serialize vpp config: %v", err)
@@ -149,9 +139,7 @@ func (vpp *VppInstance) start() error {
        vpp.container.createFile(startupFileName, configContent)
 
        // Start VPP
-       if err := vpp.container.execServer("vpp -c " + startupFileName); err != nil {
-               return err
-       }
+       vpp.container.execServer("vpp -c " + startupFileName)
 
        // Connect to VPP and store the connection
        sockAddress := vpp.container.GetHostWorkDir() + defaultApiSocketFilePath
@@ -186,16 +174,15 @@ func (vpp *VppInstance) start() error {
        return nil
 }
 
-func (vpp *VppInstance) vppctl(command string, arguments ...any) (string, error) {
+func (vpp *VppInstance) vppctl(command string, arguments ...any) string {
        vppCliCommand := fmt.Sprintf(command, arguments...)
        containerExecCommand := fmt.Sprintf("docker exec --detach=false %[1]s vppctl -s %[2]s %[3]s",
                vpp.container.name, vpp.getCliSocket(), vppCliCommand)
+       vpp.Suite().log(containerExecCommand)
        output, err := exechelper.CombinedOutput(containerExecCommand)
-       if err != nil {
-               return "", fmt.Errorf("vppctl failed: %s", err)
-       }
+       vpp.Suite().assertNil(err)
 
-       return string(output), nil
+       return string(output)
 }
 
 func NewVppInstance(c *Container) *VppInstance {
@@ -228,26 +215,29 @@ func deserializeVppConfig(input string) (VppConfig, error) {
 }
 
 func (vpp *VppInstance) createAfPacket(
-       veth *NetworkInterfaceVeth,
+       netInterface NetInterface,
 ) (interface_types.InterfaceIndex, error) {
+       var veth *NetworkInterfaceVeth
+       veth = netInterface.(*NetworkInterfaceVeth)
+
        createReq := &af_packet.AfPacketCreateV2{
                UseRandomHwAddr: true,
                HostIfName:      veth.Name(),
        }
-       if veth.hwAddress != (MacAddress{}) {
+       if veth.HwAddress() != (MacAddress{}) {
                createReq.UseRandomHwAddr = false
-               createReq.HwAddr = veth.hwAddress
+               createReq.HwAddr = veth.HwAddress()
        }
        createReply := &af_packet.AfPacketCreateV2Reply{}
 
        if err := vpp.apiChannel.SendRequest(createReq).ReceiveReply(createReply); err != nil {
                return 0, err
        }
-       veth.index = createReply.SwIfIndex
+       veth.SetIndex(createReply.SwIfIndex)
 
        // Set to up
        upReq := &interfaces.SwInterfaceSetFlags{
-               SwIfIndex: veth.index,
+               SwIfIndex: veth.Index(),
                Flags:     interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
        }
        upReply := &interfaces.SwInterfaceSetFlagsReply{}
@@ -257,17 +247,29 @@ func (vpp *VppInstance) createAfPacket(
        }
 
        // Add address
-       if veth.ip4Address == (AddressWithPrefix{}) {
-               ipPrefix, err := vpp.container.suite.NewAddress()
-               if err != nil {
-                       return 0, err
+       if veth.Ip4AddressWithPrefix() == (AddressWithPrefix{}) {
+               if veth.peerNetworkNamespace != "" {
+                       ip4Address, err := veth.addresser.
+                               NewIp4AddressWithNamespace(veth.peerNetworkNamespace)
+                       if err == nil {
+                               veth.SetAddress(ip4Address)
+                       } else {
+                               return 0, err
+                       }
+               } else {
+                       ip4Address, err := veth.addresser.
+                               NewIp4Address()
+                       if err == nil {
+                               veth.SetAddress(ip4Address)
+                       } else {
+                               return 0, err
+                       }
                }
-               veth.ip4Address = ipPrefix
        }
        addressReq := &interfaces.SwInterfaceAddDelAddress{
                IsAdd:     true,
-               SwIfIndex: veth.index,
-               Prefix:    veth.ip4Address,
+               SwIfIndex: veth.Index(),
+               Prefix:    veth.Ip4AddressWithPrefix(),
        }
        addressReply := &interfaces.SwInterfaceAddDelAddressReply{}
 
@@ -275,7 +277,7 @@ func (vpp *VppInstance) createAfPacket(
                return 0, err
        }
 
-       return veth.index, nil
+       return veth.Index(), nil
 }
 
 func (vpp *VppInstance) addAppNamespace(