hs-test: added ipv6 support and tests 78/42878/9
authorAdrian Villin <[email protected]>
Tue, 29 Apr 2025 13:25:26 +0000 (15:25 +0200)
committerFlorin Coras <[email protected]>
Tue, 6 May 2025 06:48:54 +0000 (06:48 +0000)
- tests: http client get http/https, nginx perf rps,
  tcp with loss

Type: test

Change-Id: Ibd07067df6c7c27e420e67e91f6ce7206546fa25
Signed-off-by: Adrian Villin <[email protected]>
22 files changed:
extras/hs-test/Makefile
extras/hs-test/echo_test.go
extras/hs-test/http_test.go
extras/hs-test/infra/address_allocator.go
extras/hs-test/infra/hst_suite.go
extras/hs-test/infra/netconfig.go
extras/hs-test/infra/suite_envoy_proxy.go
extras/hs-test/infra/suite_h2.go
extras/hs-test/infra/suite_ldp.go
extras/hs-test/infra/suite_nginx_proxy.go
extras/hs-test/infra/suite_no_topo.go
extras/hs-test/infra/suite_no_topo6.go [new file with mode: 0644]
extras/hs-test/infra/suite_veth.go
extras/hs-test/infra/suite_veth6.go [new file with mode: 0644]
extras/hs-test/infra/suite_vpp_proxy.go
extras/hs-test/infra/suite_vpp_udp_proxy.go
extras/hs-test/infra/vppinstance.go
extras/hs-test/nginx_test.go
extras/hs-test/proxy_test.go
extras/hs-test/resources/nginx/nginx.conf
extras/hs-test/topo-network/2peerVeth6.yaml [new file with mode: 0644]
extras/hs-test/topo-network/tap6.yaml [new file with mode: 0644]

index 5801891..ac66386 100644 (file)
@@ -259,6 +259,7 @@ cleanup-hst:
        @echo "****************************"
        @echo "Removing IP address files:"
        @find . -type f -regextype egrep -regex '.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' -exec sudo rm -v {} \;
+       @find . -type f -name "fd00:0*" -exec sudo rm -v {} \;
        @echo "****************************"
        @echo "Removing network namespaces:"
        @for ns in $$(ip netns list | grep $$(cat .last_hst_ppid) | awk '{print $$1}'); do \
index 27de77c..3c59f95 100644 (file)
@@ -10,6 +10,7 @@ import (
 func init() {
        RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest)
        RegisterSoloVethTests(TcpWithLossTest)
+       RegisterVeth6Tests(TcpWithLoss6Test)
 }
 
 func EchoBuiltinTest(s *VethsSuite) {
@@ -77,3 +78,25 @@ func TcpWithLossTest(s *VethsSuite) {
        s.AssertNotEqual(len(output), 0)
        s.AssertNotContains(output, "failed", output)
 }
+
+func TcpWithLoss6Test(s *Veths6Suite) {
+       serverVpp := s.Containers.ServerVpp.VppInstance
+
+       serverVpp.Vppctl("test echo server uri tcp://%s/20022",
+               s.Interfaces.Server.Ip6AddressString())
+
+       clientVpp := s.Containers.ClientVpp.VppInstance
+
+       // Add loss of packets with Network Delay Simulator
+       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-" + s.Interfaces.Server.Name())
+
+       // Do echo test from client-vpp container
+       output := clientVpp.Vppctl("test echo client uri tcp://%s/20022 verbose echo-bytes bytes 50m",
+               s.Interfaces.Server.Ip6AddressString())
+       s.Log(output)
+       s.AssertNotEqual(len(output), 0)
+       s.AssertNotContains(output, "failed", output)
+}
index b9fcd39..bd686d7 100644 (file)
@@ -40,6 +40,7 @@ func init() {
        RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest,
                PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest,
                PromConsecutiveConnectionsTest, HttpGetTpsTlsTest, HttpPostTpsTlsTest, HttpClientGetRepeatMTTest, HttpClientPtrGetRepeatMTTest)
+       RegisterNoTopo6Tests(HttpClientGetResponseBody6Test, HttpClientGetTlsResponseBody6Test)
 }
 
 const wwwRootPath = "/tmp/www_root"
@@ -456,6 +457,68 @@ func httpClientGet(s *NoTopoSuite, response string, size int, proto string) {
        s.AssertContains(file_contents, response)
 }
 
+func HttpClientGetResponseBody6Test(s *NoTopo6Suite) {
+       response := "<body>hello world</body>"
+       size := len(response)
+       httpClientGet6(s, response, size, "http")
+}
+
+func HttpClientGetTlsResponseBody6Test(s *NoTopo6Suite) {
+       response := "<body>hello world</body>"
+       size := len(response)
+       httpClientGet6(s, response, size, "https")
+}
+
+func httpClientGet6(s *NoTopo6Suite, response string, size int, proto string) {
+       var l net.Listener
+       var err error
+       var port string
+
+       vpp := s.Containers.Vpp.VppInstance
+       server := ghttp.NewUnstartedServer()
+       serverAddress := "[" + s.HostAddr() + "]"
+
+       if proto == "https" {
+               certFile := "resources/cert/localhost.crt"
+               keyFile := "resources/cert/localhost.key"
+               cer, err := tls.LoadX509KeyPair(certFile, keyFile)
+               s.AssertNil(err)
+               tlsConfig := &tls.Config{Certificates: []tls.Certificate{cer}}
+               server.HTTPTestServer.TLS = tlsConfig
+               port = "443"
+               l, err = tls.Listen("tcp", serverAddress+":443", tlsConfig)
+       } else {
+               port = "80"
+               l, err = net.Listen("tcp", serverAddress+":80")
+       }
+       s.AssertNil(err, fmt.Sprint(err))
+
+       server.HTTPTestServer.Listener = l
+       server.AppendHandlers(
+               ghttp.CombineHandlers(
+                       s.LogHttpReq(false),
+                       ghttp.VerifyRequest("GET", "/"),
+                       ghttp.VerifyHeaderKV("Hello", "World"),
+                       ghttp.VerifyHeaderKV("Test-H2", "Test-K2"),
+                       ghttp.RespondWith(http.StatusOK, string(response), http.Header{"Content-Length": {strconv.Itoa(size)}}),
+               ))
+       server.Start()
+       defer server.Close()
+
+       uri := proto + "://" + serverAddress + ":" + port + "/"
+       cmd := "http client use-ptr verbose header Hello:World header Test-H2:Test-K2 save-to response.txt uri " + uri
+
+       o := vpp.Vppctl(cmd)
+       s.Log(o)
+       s.AssertContains(o, "200 OK")
+       s.AssertContains(o, response)
+       s.AssertContains(o, "Content-Length: "+strconv.Itoa(size))
+
+       file_contents, err := vpp.Container.Exec(false, "cat /tmp/response.txt")
+       s.AssertNil(err)
+       s.AssertContains(file_contents, response)
+}
+
 func HttpClientGetRepeatMTTest(s *NoTopoSuite) {
        httpClientRepeat(s, "", "sessions 2")
 }
@@ -483,7 +546,7 @@ func httpClientRepeat(s *NoTopoSuite, requestMethod string, clientArgs string) {
 
        // recreate interfaces with RX-queues
        s.AssertNil(vpp.DeleteTap(s.Interfaces.Tap))
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, 2, 2))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, false, 2, 2))
 
        s.CreateNginxServer()
        s.AssertNil(s.Containers.NginxServer.Start())
index cb64702..bf8075a 100644 (file)
@@ -48,7 +48,7 @@ func (a *Ip4AddressAllocator) NewIp4InterfaceAddress(inputNetworkNumber ...int)
 // If an address is not in use, 'counter' is then copied to 'chosenOctet' and it is used for the remaining tests.
 // Also checks host IP addresses.
 func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error) {
-       hostIps, _ := exechelper.CombinedOutput("ip a")
+       hostIps, _ := exechelper.CombinedOutput("ip -4 a")
        counter := 10
        var address string
 
@@ -96,3 +96,86 @@ func NewIp4AddressAllocator() *Ip4AddressAllocator {
        ip4AddrAllocator.AddNetwork(0)
        return ip4AddrAllocator
 }
+
+type Ip6AddressAllocator struct {
+       networks      map[int]AddressCounter
+       chosenSegment string
+       assignedIps   []string
+}
+
+func (a *Ip6AddressAllocator) AddNetwork(networkNumber int) {
+       a.networks[networkNumber] = 1
+}
+
+func (a *Ip6AddressAllocator) NewIp6InterfaceAddress(inputNetworkNumber ...int) (string, error) {
+       var networkNumber int = 0
+       if len(inputNetworkNumber) > 0 {
+               networkNumber = inputNetworkNumber[0]
+       }
+
+       if _, ok := a.networks[networkNumber]; !ok {
+               a.AddNetwork(networkNumber)
+       }
+
+       numberOfAddresses := a.networks[networkNumber]
+
+       if numberOfAddresses == 65535 {
+               return "", fmt.Errorf("no available IPv6 addresses")
+       }
+
+       address, err := a.createIpAddress(networkNumber, numberOfAddresses)
+
+       a.networks[networkNumber] = numberOfAddresses + 1
+
+       return address + "/64", err
+}
+
+func (a *Ip6AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error) {
+       hostIps, _ := exechelper.CombinedOutput("ip -6 a")
+       counter := 0xAAAA
+       var address string
+
+       for {
+               if a.chosenSegment != "" {
+                       address = fmt.Sprintf("fd00:0:%s:%x::%x", a.chosenSegment, networkNumber, numberOfAddresses)
+                       file, err := os.Create(address)
+                       if err != nil {
+                               return "", errors.New("unable to create file: " + fmt.Sprint(err))
+                       }
+                       file.Close()
+                       break
+               } else {
+                       address = fmt.Sprintf("fd00:0:%x:%x::%x", counter, networkNumber, numberOfAddresses)
+                       _, err := os.Stat(address)
+                       if err == nil || strings.Contains(string(hostIps), address) {
+                               counter++
+                       } else if os.IsNotExist(err) {
+                               file, err := os.Create(address)
+                               if err != nil {
+                                       return "", errors.New("unable to create file: " + fmt.Sprint(err))
+                               }
+                               file.Close()
+                               a.chosenSegment = fmt.Sprintf("%x", counter)
+                               break
+                       } else {
+                               return "", errors.New("an error occurred while checking if a file exists: " + fmt.Sprint(err))
+                       }
+               }
+       }
+
+       a.assignedIps = append(a.assignedIps, address)
+       return address, nil
+}
+
+func (a *Ip6AddressAllocator) DeleteIpAddresses() {
+       for ip := range a.assignedIps {
+               os.Remove(a.assignedIps[ip])
+       }
+}
+
+func NewIp6AddressAllocator() *Ip6AddressAllocator {
+       var ip6AddrAllocator = new(Ip6AddressAllocator)
+       ip6AddrAllocator.networks = make(map[int]AddressCounter)
+       ip6AddrAllocator.AddNetwork(0)
+       return ip6AddrAllocator
+}
index b3ad70c..84e8089 100644 (file)
@@ -56,6 +56,7 @@ type HstSuite struct {
        NetConfigs        []NetConfig
        NetInterfaces     map[string]*NetInterface
        Ip4AddrAllocator  *Ip4AddressAllocator
+       Ip6AddrAllocator  *Ip6AddressAllocator
        TestIds           map[string]string
        CpuAllocator      *CpuAllocatorT
        CpuContexts       []*CpuContext
@@ -253,6 +254,10 @@ func (s *HstSuite) TearDownTest() {
                s.Ip4AddrAllocator.DeleteIpAddresses()
        }
 
+       if s.Ip6AddrAllocator != nil {
+               s.Ip6AddrAllocator.DeleteIpAddresses()
+       }
+
        if coreDump {
                Fail("VPP crashed")
        }
@@ -628,10 +633,16 @@ func (s *HstSuite) LoadNetworkTopology(topologyName string) {
                Fail("unmarshal error: " + fmt.Sprint(err))
        }
 
+       s.Ip6AddrAllocator = NewIp6AddressAllocator()
        s.Ip4AddrAllocator = NewIp4AddressAllocator()
        s.NetInterfaces = make(map[string]*NetInterface)
 
        for _, elem := range yamlTopo.Devices {
+               if _, ok := elem["ipv6"]; ok {
+                       elem["ipv6"] = elem["ipv6"].(bool)
+               } else {
+                       elem["ipv6"] = false
+               }
                if _, ok := elem["name"]; ok {
                        elem["name"] = s.ProcessIndex + elem["name"].(string) + s.Ppid
                }
@@ -667,12 +678,22 @@ func (s *HstSuite) LoadNetworkTopology(topologyName string) {
                        }
                case Veth, Tap:
                        {
-                               if netIf, err := newNetworkInterface(elem, s.Ip4AddrAllocator); err == nil {
-                                       s.NetConfigs = append(s.NetConfigs, netIf)
-                                       s.NetInterfaces[netIf.Name()] = netIf
+                               if elem["ipv6"].(bool) {
+                                       if netIf, err := newNetworkInterface6(elem, s.Ip6AddrAllocator); err == nil {
+                                               s.NetConfigs = append(s.NetConfigs, netIf)
+                                               s.NetInterfaces[netIf.Name()] = netIf
+                                       } else {
+                                               Fail("network config error: " + fmt.Sprint(err))
+                                       }
                                } else {
-                                       Fail("network config error: " + fmt.Sprint(err))
+                                       if netIf, err := newNetworkInterface(elem, s.Ip4AddrAllocator); err == nil {
+                                               s.NetConfigs = append(s.NetConfigs, netIf)
+                                               s.NetInterfaces[netIf.Name()] = netIf
+                                       } else {
+                                               Fail("network config error: " + fmt.Sprint(err))
+                                       }
                                }
+
                        }
                case Bridge:
                        {
index 3f3d3e3..d263b4b 100644 (file)
@@ -16,6 +16,7 @@ type (
        MacAddress           = ethernet_types.MacAddress
        AddressWithPrefix    = ip_types.AddressWithPrefix
        IP4AddressWithPrefix = ip_types.IP4AddressWithPrefix
+       IP6AddressWithPrefix = ip_types.IP6AddressWithPrefix
        InterfaceIndex       = interface_types.InterfaceIndex
 
        NetConfig interface {
@@ -34,6 +35,8 @@ type (
                NetConfigBase
                Ip4AddrAllocator *Ip4AddressAllocator
                Ip4Address       string
+               Ip6AddrAllocator *Ip6AddressAllocator
+               Ip6Address       string
                Index            InterfaceIndex
                HwAddress        MacAddress
                NetworkNamespace string
@@ -119,6 +122,53 @@ func newNetworkInterface(cfg NetDevConfig, a *Ip4AddressAllocator) (*NetInterfac
        return newInterface, nil
 }
 
+func newNetworkInterface6(cfg NetDevConfig, a *Ip6AddressAllocator) (*NetInterface, error) {
+       var newInterface *NetInterface = &NetInterface{}
+       var err error
+       newInterface.Ip6AddrAllocator = a
+       newInterface.name = cfg["name"].(string)
+       newInterface.NetworkNumber = DEFAULT_NETWORK_NUM
+
+       if interfaceType, ok := cfg["type"]; ok {
+               newInterface.category = interfaceType.(string)
+       }
+
+       if presetHwAddress, ok := cfg["preset-hw-address"]; ok {
+               newInterface.HwAddress, err = ethernet_types.ParseMacAddress(presetHwAddress.(string))
+               if err != nil {
+                       return &NetInterface{}, err
+               }
+       }
+
+       if netns, ok := cfg["netns"]; ok {
+               newInterface.NetworkNamespace = netns.(string)
+       }
+
+       if ip, ok := cfg["ip6"]; ok {
+               if n, ok := ip.(NetDevConfig)["network"]; ok {
+                       newInterface.NetworkNumber = n.(int)
+               }
+               newInterface.Ip6Address, err = newInterface.Ip6AddrAllocator.NewIp6InterfaceAddress(
+                       newInterface.NetworkNumber,
+               )
+               if err != nil {
+                       return &NetInterface{}, err
+               }
+       }
+
+       if _, ok := cfg["peer"]; !ok {
+               return newInterface, nil
+       }
+
+       peer := cfg["peer"].(NetDevConfig)
+
+       if newInterface.Peer, err = newNetworkInterface6(peer, a); err != nil {
+               return &NetInterface{}, err
+       }
+
+       return newInterface, nil
+}
+
 func (n *NetInterface) configureUpState() error {
        err := setDevUp(n.Name(), "")
        if err != nil {
@@ -199,8 +249,13 @@ func (n *NetInterface) Type() string {
        return n.category
 }
 
-func (n *NetInterface) AddressWithPrefix() AddressWithPrefix {
-       address, _ := ip_types.ParseAddressWithPrefix(n.Ip4Address)
+func (n *NetInterface) AddressWithPrefix(IPv6 bool) AddressWithPrefix {
+       var address ip_types.AddressWithPrefix
+       if IPv6 {
+               address, _ = ip_types.ParseAddressWithPrefix(n.Ip6Address)
+       } else {
+               address, _ = ip_types.ParseAddressWithPrefix(n.Ip4Address)
+       }
        return address
 }
 
@@ -210,10 +265,20 @@ func (n *NetInterface) Ip4AddressWithPrefix() IP4AddressWithPrefix {
        return Ip4AddressWithPrefix
 }
 
+func (n *NetInterface) Ip6AddressWithPrefix() IP6AddressWithPrefix {
+       ip6Prefix, _ := ip_types.ParseIP6Prefix(n.Ip6Address)
+       Ip6AddressWithPrefix := ip_types.IP6AddressWithPrefix(ip6Prefix)
+       return Ip6AddressWithPrefix
+}
+
 func (n *NetInterface) Ip4AddressString() string {
        return strings.Split(n.Ip4Address, "/")[0]
 }
 
+func (n *NetInterface) Ip6AddressString() string {
+       return strings.Split(n.Ip6Address, "/")[0]
+}
+
 func (b *NetConfigBase) Name() string {
        return b.name
 }
index c20cf29..dcafc87 100644 (file)
@@ -120,8 +120,8 @@ func (s *EnvoyProxySuite) SetupTest() {
        s.AssertNil(vpp.Start())
        // wait for VPP to start
        time.Sleep(time.Second * 1)
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, 1, 1))
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, 1, 2))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, false, 1, 1))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, false, 1, 2))
        s.Containers.Vpp.Exec(false, "chmod 777 -R %s", s.Containers.Vpp.GetContainerWorkDir())
 
        // Add Ipv4 ARP entry for nginx HTTP server, otherwise first request fail (HTTP error 503)
index ba99286..95f5c0c 100644 (file)
@@ -59,7 +59,7 @@ func (s *H2Suite) SetupTest() {
        vpp, _ := s.Containers.Vpp.newVppInstance(s.Containers.Vpp.AllocatedCpus, memoryConfig, sessionConfig)
 
        s.AssertNil(vpp.Start())
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, 1, 1), "failed to create tap interface")
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, false, 1, 1), "failed to create tap interface")
 
        if *DryRun {
                s.LogStartedContainers()
index 53fe100..ddf756f 100644 (file)
@@ -132,7 +132,7 @@ func (s *LdpSuite) SetupServerVpp(serverContainer *Container) {
        serverVpp := serverContainer.VppInstance
        s.AssertNil(serverVpp.Start())
 
-       idx, err := serverVpp.createAfPacket(s.Interfaces.Server)
+       idx, err := serverVpp.createAfPacket(s.Interfaces.Server, false)
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertNotEqual(0, idx)
 }
@@ -141,7 +141,7 @@ func (s *LdpSuite) setupClientVpp(clientContainer *Container) {
        clientVpp := clientContainer.VppInstance
        s.AssertNil(clientVpp.Start())
 
-       idx, err := clientVpp.createAfPacket(s.Interfaces.Client)
+       idx, err := clientVpp.createAfPacket(s.Interfaces.Client, false)
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertNotEqual(0, idx)
 }
index 1b6d9f6..7913ffa 100644 (file)
@@ -88,8 +88,8 @@ func (s *NginxProxySuite) SetupTest() {
        )
 
        s.AssertNil(vpp.Start())
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, 1, 1))
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, 1, 2))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, false, 1, 1))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, false, 1, 2))
 
        if *DryRun {
                s.LogStartedContainers()
index d084413..c74c5a0 100644 (file)
@@ -70,7 +70,7 @@ func (s *NoTopoSuite) SetupTest() {
        vpp, _ := s.Containers.Vpp.newVppInstance(s.Containers.Vpp.AllocatedCpus, sessionConfig)
 
        s.AssertNil(vpp.Start())
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, 1, 1), "failed to create tap interface")
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, false, 1, 1), "failed to create tap interface")
 
        if *DryRun {
                s.LogStartedContainers()
diff --git a/extras/hs-test/infra/suite_no_topo6.go b/extras/hs-test/infra/suite_no_topo6.go
new file mode 100644 (file)
index 0000000..abc0058
--- /dev/null
@@ -0,0 +1,234 @@
+package hst
+
+import (
+       "fmt"
+       "reflect"
+       "runtime"
+       "strings"
+
+       . "github.com/onsi/ginkgo/v2"
+)
+
+var noTopo6Tests = map[string][]func(s *NoTopo6Suite){}
+var noTopo6SoloTests = map[string][]func(s *NoTopo6Suite){}
+
+type NoTopo6Suite struct {
+       HstSuite
+       Interfaces struct {
+               Tap *NetInterface
+       }
+       Containers struct {
+               Vpp         *Container
+               Nginx       *Container
+               NginxHttp3  *Container
+               NginxServer *Container
+               Wrk         *Container
+               Curl        *Container
+               Ab          *Container
+       }
+       NginxServerPort string
+}
+
+func RegisterNoTopo6Tests(tests ...func(s *NoTopo6Suite)) {
+       noTopo6Tests[getTestFilename()] = tests
+}
+func RegisterNoTopo6SoloTests(tests ...func(s *NoTopo6Suite)) {
+       noTopo6SoloTests[getTestFilename()] = tests
+}
+
+func (s *NoTopo6Suite) SetupSuite() {
+       s.HstSuite.SetupSuite()
+       s.LoadNetworkTopology("tap6")
+       s.LoadContainerTopology("single")
+       s.Interfaces.Tap = s.GetInterfaceByName("htaphost")
+       s.Containers.Vpp = s.GetContainerByName("vpp")
+       s.Containers.Nginx = s.GetContainerByName("nginx")
+       s.Containers.NginxHttp3 = s.GetContainerByName("nginx-http3")
+       s.Containers.NginxServer = s.GetTransientContainerByName("nginx-server")
+       s.Containers.Wrk = s.GetContainerByName("wrk")
+       s.Containers.Curl = s.GetContainerByName("curl")
+       s.Containers.Ab = s.GetContainerByName("ab")
+}
+
+func (s *NoTopo6Suite) SetupTest() {
+       s.HstSuite.SetupTest()
+
+       // Setup test conditions
+       var sessionConfig Stanza
+       sessionConfig.
+               NewStanza("session").
+               Append("enable").
+               Append("use-app-socket-api")
+
+       if strings.Contains(CurrentSpecReport().LeafNodeText, "InterruptMode") {
+               sessionConfig.Append("use-private-rx-mqs").Close()
+               s.Log("**********************INTERRUPT MODE**********************")
+       } else {
+               sessionConfig.Close()
+       }
+
+       vpp, _ := s.Containers.Vpp.newVppInstance(s.Containers.Vpp.AllocatedCpus, sessionConfig)
+
+       s.AssertNil(vpp.Start())
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, true, 1, 1), "failed to create tap interface")
+
+       if *DryRun {
+               s.LogStartedContainers()
+               s.Skip("Dry run mode = true")
+       }
+}
+
+func (s *NoTopo6Suite) TearDownTest() {
+       if CurrentSpecReport().Failed() {
+               s.CollectNginxLogs(s.Containers.NginxHttp3)
+       }
+       s.HstSuite.TearDownTest()
+}
+
+func (s *NoTopo6Suite) CreateNginxConfig(container *Container, multiThreadWorkers bool) {
+       var workers uint8
+       if multiThreadWorkers {
+               workers = 2
+       } else {
+               workers = 1
+       }
+       values := struct {
+               Workers uint8
+       }{
+               Workers: workers,
+       }
+       container.CreateConfigFromTemplate(
+               "/nginx.conf",
+               "./resources/nginx/nginx.conf",
+               values,
+       )
+}
+
+// Creates container and config.
+func (s *NoTopo6Suite) CreateNginxServer() {
+       s.AssertNil(s.Containers.NginxServer.Create())
+       s.NginxServerPort = s.GetPortFromPpid()
+       nginxSettings := struct {
+               LogPrefix string
+               Address   string
+               Port      string
+               Timeout   int
+       }{
+               LogPrefix: s.Containers.NginxServer.Name,
+               Address:   "[" + s.Interfaces.Tap.Ip6AddressString() + "]",
+               Port:      s.NginxServerPort,
+               Timeout:   600,
+       }
+       s.Containers.NginxServer.CreateConfigFromTemplate(
+               "/nginx.conf",
+               "./resources/nginx/nginx_server.conf",
+               nginxSettings,
+       )
+}
+
+func (s *NoTopo6Suite) AddNginxVclConfig(multiThreadWorkers bool) {
+       vclFileName := s.Containers.Nginx.GetHostWorkDir() + "/vcl.conf"
+       appSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default",
+               s.Containers.Nginx.GetContainerWorkDir())
+
+       var vclConf Stanza
+       vclConf.
+               NewStanza("vcl").
+               Append("heapsize 64M").
+               Append("rx-fifo-size 4000000").
+               Append("tx-fifo-size 4000000").
+               Append("segment-size 4000000000").
+               Append("add-segment-size 4000000000").
+               Append("event-queue-size 100000").
+               Append("use-mq-eventfd").
+               Append(appSocketApi)
+       if multiThreadWorkers {
+               vclConf.Append("multi-thread-workers")
+       }
+
+       err := vclConf.Close().SaveToFile(vclFileName)
+       s.AssertNil(err, fmt.Sprint(err))
+}
+
+func (s *NoTopo6Suite) VppAddr() string {
+       return s.Interfaces.Tap.Peer.Ip6AddressString()
+}
+
+func (s *NoTopo6Suite) VppIfName() string {
+       return s.Interfaces.Tap.Peer.Name()
+}
+
+func (s *NoTopo6Suite) HostAddr() string {
+       return s.Interfaces.Tap.Ip6AddressString()
+}
+
+func (s *NoTopo6Suite) CreateNginxHttp3Config(container *Container) {
+       nginxSettings := struct {
+               LogPrefix string
+       }{
+               LogPrefix: container.Name,
+       }
+       container.CreateConfigFromTemplate(
+               "/nginx.conf",
+               "./resources/nginx/nginx_http3.conf",
+               nginxSettings,
+       )
+}
+
+var _ = Describe("NoTopo6Suite", Ordered, ContinueOnFailure, Label("IPv6"), func() {
+       var s NoTopo6Suite
+       BeforeAll(func() {
+               s.SetupSuite()
+       })
+       BeforeEach(func() {
+               s.SetupTest()
+       })
+       AfterAll(func() {
+               s.TearDownSuite()
+       })
+       AfterEach(func() {
+               s.TearDownTest()
+       })
+
+       for filename, tests := range noTopo6Tests {
+               for _, test := range tests {
+                       test := test
+                       pc := reflect.ValueOf(test).Pointer()
+                       funcValue := runtime.FuncForPC(pc)
+                       testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+                       It(testName, func(ctx SpecContext) {
+                               s.Log(testName + ": BEGIN")
+                               test(&s)
+                       }, SpecTimeout(TestTimeout))
+               }
+       }
+})
+
+var _ = Describe("NoTopo6SuiteSolo", Ordered, ContinueOnFailure, Serial, Label("IPv6"), func() {
+       var s NoTopo6Suite
+       BeforeAll(func() {
+               s.SetupSuite()
+       })
+       BeforeEach(func() {
+               s.SetupTest()
+       })
+       AfterAll(func() {
+               s.TearDownSuite()
+       })
+       AfterEach(func() {
+               s.TearDownTest()
+       })
+
+       for filename, tests := range noTopo6SoloTests {
+               for _, test := range tests {
+                       test := test
+                       pc := reflect.ValueOf(test).Pointer()
+                       funcValue := runtime.FuncForPC(pc)
+                       testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+                       It(testName, Label("SOLO"), func(ctx SpecContext) {
+                               s.Log(testName + ": BEGIN")
+                               test(&s)
+                       }, SpecTimeout(TestTimeout))
+               }
+       }
+})
index c13f3e4..c8f5640 100644 (file)
@@ -84,7 +84,7 @@ func (s *VethsSuite) SetupServerVpp() {
        serverVpp := s.Containers.ServerVpp.VppInstance
        s.AssertNil(serverVpp.Start())
 
-       idx, err := serverVpp.createAfPacket(s.Interfaces.Server)
+       idx, err := serverVpp.createAfPacket(s.Interfaces.Server, false)
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertNotEqual(0, idx)
 }
@@ -93,7 +93,7 @@ func (s *VethsSuite) setupClientVpp() {
        clientVpp := s.GetContainerByName("client-vpp").VppInstance
        s.AssertNil(clientVpp.Start())
 
-       idx, err := clientVpp.createAfPacket(s.Interfaces.Client)
+       idx, err := clientVpp.createAfPacket(s.Interfaces.Client, false)
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertNotEqual(0, idx)
 }
diff --git a/extras/hs-test/infra/suite_veth6.go b/extras/hs-test/infra/suite_veth6.go
new file mode 100644 (file)
index 0000000..f81414b
--- /dev/null
@@ -0,0 +1,160 @@
+package hst
+
+import (
+       "fmt"
+       "reflect"
+       "runtime"
+       "strings"
+       "time"
+
+       . "github.com/onsi/ginkgo/v2"
+)
+
+var veth6Tests = map[string][]func(s *Veths6Suite){}
+var veth6SoloTests = map[string][]func(s *Veths6Suite){}
+
+type Veths6Suite struct {
+       HstSuite
+       Interfaces struct {
+               Server *NetInterface
+               Client *NetInterface
+       }
+       Containers struct {
+               ServerVpp *Container
+               ClientVpp *Container
+               ServerApp *Container
+               ClientApp *Container
+       }
+}
+
+func RegisterVeth6Tests(tests ...func(s *Veths6Suite)) {
+       veth6Tests[getTestFilename()] = tests
+}
+func RegisterSoloVeth6Tests(tests ...func(s *Veths6Suite)) {
+       veth6SoloTests[getTestFilename()] = tests
+}
+
+func (s *Veths6Suite) SetupSuite() {
+       time.Sleep(1 * time.Second)
+       s.HstSuite.SetupSuite()
+       s.ConfigureNetworkTopology("2peerVeth6")
+       s.LoadContainerTopology("2peerVeth")
+       s.Interfaces.Client = s.GetInterfaceByName("cln")
+       s.Interfaces.Server = s.GetInterfaceByName("srv")
+       s.Containers.ServerVpp = s.GetContainerByName("server-vpp")
+       s.Containers.ClientVpp = s.GetContainerByName("client-vpp")
+       s.Containers.ServerApp = s.GetContainerByName("server-app")
+       s.Containers.ClientApp = s.GetContainerByName("client-app")
+}
+
+func (s *Veths6Suite) SetupTest() {
+       s.HstSuite.SetupTest()
+
+       // Setup test conditions
+       var sessionConfig Stanza
+       sessionConfig.
+               NewStanza("session").
+               Append("enable").
+               Append("use-app-socket-api")
+
+       if strings.Contains(CurrentSpecReport().LeafNodeText, "InterruptMode") {
+               sessionConfig.Append("use-private-rx-mqs").Close()
+               s.Log("**********************INTERRUPT MODE**********************")
+       } else {
+               sessionConfig.Close()
+       }
+
+       // ... For server
+       serverVpp, err := s.Containers.ServerVpp.newVppInstance(s.Containers.ServerVpp.AllocatedCpus, sessionConfig)
+       s.AssertNotNil(serverVpp, fmt.Sprint(err))
+
+       // ... For client
+       clientVpp, err := s.Containers.ClientVpp.newVppInstance(s.Containers.ClientVpp.AllocatedCpus, sessionConfig)
+       s.AssertNotNil(clientVpp, fmt.Sprint(err))
+
+       s.SetupServerVpp()
+       s.setupClientVpp()
+       if *DryRun {
+               s.LogStartedContainers()
+               s.Skip("Dry run mode = true")
+       }
+}
+
+func (s *Veths6Suite) SetupServerVpp() {
+       serverVpp := s.Containers.ServerVpp.VppInstance
+       s.AssertNil(serverVpp.Start())
+
+       idx, err := serverVpp.createAfPacket(s.Interfaces.Server, true)
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertNotEqual(0, idx)
+}
+
+func (s *Veths6Suite) setupClientVpp() {
+       clientVpp := s.GetContainerByName("client-vpp").VppInstance
+       s.AssertNil(clientVpp.Start())
+
+       idx, err := clientVpp.createAfPacket(s.Interfaces.Client, true)
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertNotEqual(0, idx)
+}
+
+var _ = Describe("Veths6Suite", Ordered, ContinueOnFailure, func() {
+       var s Veths6Suite
+       BeforeAll(func() {
+               s.SetupSuite()
+       })
+       BeforeEach(func() {
+               s.SetupTest()
+       })
+       AfterAll(func() {
+               s.TearDownSuite()
+
+       })
+       AfterEach(func() {
+               s.TearDownTest()
+       })
+
+       // https://onsi.github.io/ginkgo/#dynamically-generating-specs
+       for filename, tests := range veth6Tests {
+               for _, test := range tests {
+                       test := test
+                       pc := reflect.ValueOf(test).Pointer()
+                       funcValue := runtime.FuncForPC(pc)
+                       testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+                       It(testName, func(ctx SpecContext) {
+                               s.Log(testName + ": BEGIN")
+                               test(&s)
+                       }, SpecTimeout(TestTimeout))
+               }
+       }
+})
+
+var _ = Describe("Veths6SuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+       var s Veths6Suite
+       BeforeAll(func() {
+               s.SetupSuite()
+       })
+       BeforeEach(func() {
+               s.SetupTest()
+       })
+       AfterAll(func() {
+               s.TearDownSuite()
+       })
+       AfterEach(func() {
+               s.TearDownTest()
+       })
+
+       // https://onsi.github.io/ginkgo/#dynamically-generating-specs
+       for filename, tests := range veth6SoloTests {
+               for _, test := range tests {
+                       test := test
+                       pc := reflect.ValueOf(test).Pointer()
+                       funcValue := runtime.FuncForPC(pc)
+                       testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+                       It(testName, Label("SOLO"), func(ctx SpecContext) {
+                               s.Log(testName + ": BEGIN")
+                               test(&s)
+                       }, SpecTimeout(TestTimeout))
+               }
+       }
+})
index 137bbb6..60230d7 100644 (file)
@@ -78,8 +78,8 @@ func (s *VppProxySuite) SetupTest() {
        s.AssertNotNil(vpp, fmt.Sprint(err))
 
        s.AssertNil(vpp.Start())
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, 1, 1))
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, 1, 2))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, false, 1, 1))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, false, 1, 2))
 
        if *DryRun {
                s.LogStartedContainers()
index 62bf3dd..46d5388 100644 (file)
@@ -62,8 +62,8 @@ func (s *VppUdpProxySuite) SetupTest() {
        s.AssertNotNil(vpp, fmt.Sprint(err))
 
        s.AssertNil(vpp.Start())
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, 1, 1))
-       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, 1, 2))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Client, false, 1, 1))
+       s.AssertNil(vpp.CreateTap(s.Interfaces.Server, false, 1, 2))
 
        s.proxyPort = 8080
        s.serverPort = 80
index 1d07c74..41bcb66 100644 (file)
@@ -3,6 +3,7 @@ package hst
 import (
        "context"
        "encoding/json"
+       "errors"
        "fmt"
        "io"
        "net"
@@ -310,26 +311,36 @@ func (vpp *VppInstance) WaitForApp(appName string, timeout int) {
        vpp.getSuite().AssertNil(1, "Timeout while waiting for app '%s'", appName)
 }
 
-func (vpp *VppInstance) createAfPacket(
-       veth *NetInterface,
-) (interface_types.InterfaceIndex, error) {
+func (vpp *VppInstance) createAfPacket(veth *NetInterface, IPv6 bool) (interface_types.InterfaceIndex, error) {
+       var ipAddress string
+       var err error
+
        if *DryRun {
-               if ip4Address, err := veth.Ip4AddrAllocator.NewIp4InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
-                       veth.Ip4Address = ip4Address
+               if IPv6 {
+                       if ipAddress, err = veth.Ip6AddrAllocator.NewIp6InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
+                               veth.Ip6Address = ipAddress
+                       }
                } else {
+                       if ipAddress, err = veth.Ip4AddrAllocator.NewIp4InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
+                               veth.Ip4Address = ipAddress
+                       }
+               }
+               if err != nil {
                        return 0, err
                }
+
                vppCliConfig := fmt.Sprintf(
                        "create host-interface name %s\n"+
                                "set int state host-%s up\n"+
                                "set int ip addr host-%s %s\n",
                        veth.Name(),
                        veth.Name(),
-                       veth.Name(), veth.Ip4Address)
+                       veth.Name(), ipAddress)
                vpp.AppendToCliConfig(vppCliConfig)
                vpp.getSuite().Log("%s* Interface added:\n%s%s", Colors.grn, vppCliConfig, Colors.rst)
                return 1, nil
        }
+
        createReq := &af_packet.AfPacketCreateV3{
                Mode:            1,
                UseRandomHwAddr: true,
@@ -378,22 +389,27 @@ func (vpp *VppInstance) createAfPacket(
        }
 
        // Add address
-       if veth.AddressWithPrefix() == (AddressWithPrefix{}) {
-               var err error
-               var ip4Address string
-               if ip4Address, err = veth.Ip4AddrAllocator.NewIp4InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
-                       veth.Ip4Address = ip4Address
+       if veth.AddressWithPrefix(IPv6) == (AddressWithPrefix{}) {
+               if IPv6 {
+                       if ipAddress, err = veth.Ip6AddrAllocator.NewIp6InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
+                               veth.Ip6Address = ipAddress
+                       }
                } else {
+                       if ipAddress, err = veth.Ip4AddrAllocator.NewIp4InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
+                               veth.Ip4Address = ipAddress
+                       }
+               }
+               if err != nil {
                        return 0, err
                }
        }
        addressReq := &interfaces.SwInterfaceAddDelAddress{
                IsAdd:     true,
                SwIfIndex: veth.Index,
-               Prefix:    veth.AddressWithPrefix(),
+               Prefix:    veth.AddressWithPrefix(IPv6),
        }
 
-       vpp.getSuite().Log("af-packet interface " + veth.Name() + " add address " + veth.Ip4Address)
+       vpp.getSuite().Log("af-packet interface " + veth.Name() + " add address " + ipAddress)
        if err := vpp.ApiStream.SendMsg(addressReq); err != nil {
                return 0, err
        }
@@ -456,27 +472,40 @@ func (vpp *VppInstance) addAppNamespace(
        return nil
 }
 
-func (vpp *VppInstance) CreateTap(tap *NetInterface, numRxQueues uint16, tapId uint32, flags ...uint32) error {
+func (vpp *VppInstance) CreateTap(tap *NetInterface, IPv6 bool, numRxQueues uint16, tapId uint32, flags ...uint32) error {
        var tapFlags uint32 = 0
+
        if len(flags) > 0 {
                tapFlags = flags[0]
        }
 
        if *DryRun {
                flagsCli := ""
+               ipAddress := ""
+               ipAddressPeer := ""
+
                if tapFlags == Consistent_qp {
                        flagsCli = "consistent-qp"
                }
-               vppCliConfig := fmt.Sprintf("create tap id %d host-if-name %s host-ip4-addr %s num-rx-queues %d %s\n"+
+
+               if IPv6 {
+                       ipAddress = "host-ip6-addr " + tap.Ip6Address
+                       ipAddressPeer = tap.Peer.Ip6Address
+               } else {
+                       ipAddress = "host-ip4-addr " + tap.Ip4Address
+                       ipAddressPeer = tap.Peer.Ip4Address
+               }
+
+               vppCliConfig := fmt.Sprintf("create tap id %d host-if-name %s %s num-rx-queues %d %s\n"+
                        "set int ip addr tap%d %s\n"+
                        "set int state tap%d up\n",
                        tapId,
                        tap.name,
-                       tap.Ip4Address,
+                       ipAddress,
                        numRxQueues,
                        flagsCli,
                        tapId,
-                       tap.Peer.Ip4Address,
+                       ipAddressPeer,
                        tapId,
                )
                vpp.AppendToCliConfig(vppCliConfig)
@@ -490,6 +519,8 @@ func (vpp *VppInstance) CreateTap(tap *NetInterface, numRxQueues uint16, tapId u
                HostIfName:       tap.Name(),
                HostIP4PrefixSet: true,
                HostIP4Prefix:    tap.Ip4AddressWithPrefix(),
+               HostIP6PrefixSet: true,
+               HostIP6Prefix:    tap.Ip6AddressWithPrefix(),
                NumRxQueues:      numRxQueues,
                TapFlags:         tapv2.TapFlags(tapFlags),
        }
@@ -527,7 +558,7 @@ func (vpp *VppInstance) CreateTap(tap *NetInterface, numRxQueues uint16, tapId u
        addAddressReq := &interfaces.SwInterfaceAddDelAddress{
                IsAdd:     true,
                SwIfIndex: reply.SwIfIndex,
-               Prefix:    tap.Peer.AddressWithPrefix(),
+               Prefix:    tap.Peer.AddressWithPrefix(IPv6),
        }
 
        vpp.getSuite().Log("tap interface " + tap.Name() + " add address " + tap.Peer.Ip4Address)
@@ -568,6 +599,27 @@ func (vpp *VppInstance) CreateTap(tap *NetInterface, numRxQueues uint16, tapId u
                tap.HwAddress, _ = ethernet_types.ParseMacAddress(netIntf.HardwareAddr.String())
        }
 
+       if IPv6 {
+               timeoutCounter := 1.0
+               for {
+                       if timeoutCounter <= 5 {
+                               vpp.getSuite().Log("Waiting for 'tentative' flag to disappear [%vs/5s]", timeoutCounter)
+                               out, err := vpp.Container.Exec(false, "ip -6 addr show dev %s", tap.Name())
+                               if err != nil {
+                                       vpp.getSuite().Log(out)
+                                       return err
+                               }
+                               if !strings.Contains(out, "tentative") {
+                                       break
+                               }
+                               time.Sleep(time.Millisecond * 500)
+                               timeoutCounter += 0.5
+                       } else {
+                               return errors.New("tentative flag did not disappear in time")
+                       }
+               }
+       }
+
        return nil
 }
 
index 12aa248..f5f10cc 100644 (file)
@@ -13,6 +13,7 @@ func init() {
        RegisterNoTopoTests(NginxHttp3Test, NginxAsServerTest, NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest,
                NginxPerfCpsInterruptModeTest, NginxPerfRpsInterruptModeTest, NginxPerfWrkInterruptModeTest)
        RegisterNoTopoSoloTests(NginxPerfRpsMultiThreadTest, NginxPerfCpsMultiThreadTest)
+       RegisterNoTopo6Tests(NginxPerfRps6Test)
 }
 
 func NginxHttp3Test(s *NoTopoSuite) {
@@ -147,3 +148,52 @@ func NginxPerfWrkInterruptModeTest(s *NoTopoSuite) {
 func NginxPerfWrkTest(s *NoTopoSuite) {
        s.AssertNil(runNginxPerf(s, "", "wrk", false))
 }
+
+func runNginxPerf6(s *NoTopo6Suite, mode, ab_or_wrk string, multiThreadWorkers bool) error {
+       nRequests := 1000000
+       nClients := 1000
+
+       serverAddress := "[" + s.VppAddr() + "]"
+       vpp := s.Containers.Vpp.VppInstance
+
+       s.Containers.Nginx.Create()
+       s.AddNginxVclConfig(multiThreadWorkers)
+       s.CreateNginxConfig(s.Containers.Nginx, multiThreadWorkers)
+       s.Containers.Nginx.Start()
+       vpp.WaitForApp("nginx-", 5)
+
+       if ab_or_wrk == "ab" {
+               args := fmt.Sprintf("-n %d -c %d", nRequests, nClients)
+               if mode == "rps" {
+                       args += " -k"
+               } else if mode != "cps" {
+                       return fmt.Errorf("invalid mode %s; expected cps/rps", mode)
+               }
+               // don't exit on socket receive errors
+               args += " -r"
+               args += " http://" + serverAddress + ":80/64B.json"
+               s.Containers.Ab.ExtraRunningArgs = args
+               s.Log("Test might take up to 2 minutes to finish. Please wait")
+               s.Containers.Ab.Run()
+               o, err := s.Containers.Ab.GetOutput()
+               rps := parseString(o, "Requests per second:")
+               s.Log(rps)
+               s.AssertContains(err, "Finished "+fmt.Sprint(nRequests))
+       } else {
+               args := fmt.Sprintf("-c %d -t 2 -d 30 http://%s:80/64B.json", nClients,
+                       serverAddress)
+               s.Containers.Wrk.ExtraRunningArgs = args
+               s.Containers.Wrk.Run()
+               s.Log("Please wait for 30s, test is running.")
+               o, err := s.Containers.Wrk.GetOutput()
+               rps := parseString(o, "requests")
+               s.Log(rps)
+               s.Log(err)
+               s.AssertEmpty(err, "err: '%s', output: '%s'", err, o)
+       }
+       return nil
+}
+
+func NginxPerfRps6Test(s *NoTopo6Suite) {
+       s.AssertNil(runNginxPerf6(s, "rps", "ab", false))
+}
index b6b4df5..e12b38e 100644 (file)
@@ -69,10 +69,10 @@ func vppProxyIperfMTTest(s *VppProxySuite, proto string) {
        // tap interfaces are created on test setup with 1 rx-queue,
        // need to recreate them with 2 + consistent-qp
        s.AssertNil(vppProxy.DeleteTap(s.Interfaces.Server))
-       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Server, 2, uint32(s.Interfaces.Server.Peer.Index), Consistent_qp))
+       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Server, false, 2, uint32(s.Interfaces.Server.Peer.Index), Consistent_qp))
 
        s.AssertNil(vppProxy.DeleteTap(s.Interfaces.Client))
-       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Client, 2, uint32(s.Interfaces.Client.Peer.Index), Consistent_qp))
+       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Client, false, 2, uint32(s.Interfaces.Client.Peer.Index), Consistent_qp))
 
        configureVppProxy(s, "tcp", uint16(proxyPort))
        if proto == "udp" {
@@ -338,9 +338,9 @@ func VppConnectProxyStressMTTest(s *VppProxySuite) {
        // tap interfaces are created on test setup with 1 rx-queue,
        // need to recreate them with 2 + consistent-qp
        s.AssertNil(vppProxy.DeleteTap(s.Interfaces.Server))
-       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Server, 2, uint32(s.Interfaces.Server.Peer.Index), Consistent_qp))
+       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Server, false, 2, uint32(s.Interfaces.Server.Peer.Index), Consistent_qp))
        s.AssertNil(vppProxy.DeleteTap(s.Interfaces.Client))
-       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Client, 2, uint32(s.Interfaces.Client.Peer.Index), Consistent_qp))
+       s.AssertNil(vppProxy.CreateTap(s.Interfaces.Client, false, 2, uint32(s.Interfaces.Client.Peer.Index), Consistent_qp))
 
        configureVppProxy(s, "http", proxyPort)
 
index 956a131..04f5f2b 100644 (file)
@@ -16,6 +16,7 @@ http {
   sendfile on;
   server {
     listen 80;
+    listen [::]:80;
     root /usr/share/nginx;
     index index.html index.htm;
     location /return_ok
diff --git a/extras/hs-test/topo-network/2peerVeth6.yaml b/extras/hs-test/topo-network/2peerVeth6.yaml
new file mode 100644 (file)
index 0000000..139d996
--- /dev/null
@@ -0,0 +1,27 @@
+---
+devices:
+  - name: "hsns"
+    type: "netns"
+
+  - name: "srv"
+    ipv6: true
+    type: "veth"
+    preset-hw-address: "00:00:5e:00:53:01"
+    peer:
+      name: "srv_veth"
+      netns: "hsns"
+
+  - name: "cln"
+    ipv6: true
+    type: "veth"
+    peer:
+      name: "cln_veth"
+      netns: "hsns"
+
+  - name: "br"
+    type: "bridge"
+    netns: "hsns"
+    interfaces:
+      - srv_veth
+      - cln_veth
+
diff --git a/extras/hs-test/topo-network/tap6.yaml b/extras/hs-test/topo-network/tap6.yaml
new file mode 100644 (file)
index 0000000..36498c6
--- /dev/null
@@ -0,0 +1,11 @@
+---
+devices:
+  - name: "htaphost"
+    type: "tap"
+    ipv6: true
+    ip6:
+      network: 1
+    peer:
+      name: ""
+      ip6:
+        network: 1