From: Adrian Villin Date: Tue, 29 Apr 2025 13:25:26 +0000 (+0200) Subject: hs-test: added ipv6 support and tests X-Git-Tag: v25.10-rc0~35 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F78%2F42878%2F9;p=vpp.git hs-test: added ipv6 support and tests - tests: http client get http/https, nginx perf rps, tcp with loss Type: test Change-Id: Ibd07067df6c7c27e420e67e91f6ce7206546fa25 Signed-off-by: Adrian Villin --- diff --git a/extras/hs-test/Makefile b/extras/hs-test/Makefile index 58018915886..ac663866070 100644 --- a/extras/hs-test/Makefile +++ b/extras/hs-test/Makefile @@ -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 \ diff --git a/extras/hs-test/echo_test.go b/extras/hs-test/echo_test.go index 27de77ccb10..3c59f95fe55 100644 --- a/extras/hs-test/echo_test.go +++ b/extras/hs-test/echo_test.go @@ -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) +} diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index b9fcd39b0ff..bd686d7780a 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -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 := "hello world" + size := len(response) + httpClientGet6(s, response, size, "http") +} + +func HttpClientGetTlsResponseBody6Test(s *NoTopo6Suite) { + response := "hello world" + 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()) diff --git a/extras/hs-test/infra/address_allocator.go b/extras/hs-test/infra/address_allocator.go index cb647024412..bf8075a95f5 100644 --- a/extras/hs-test/infra/address_allocator.go +++ b/extras/hs-test/infra/address_allocator.go @@ -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 +} diff --git a/extras/hs-test/infra/hst_suite.go b/extras/hs-test/infra/hst_suite.go index b3ad70cc81e..84e8089b0bf 100644 --- a/extras/hs-test/infra/hst_suite.go +++ b/extras/hs-test/infra/hst_suite.go @@ -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: { diff --git a/extras/hs-test/infra/netconfig.go b/extras/hs-test/infra/netconfig.go index 3f3d3e3e84c..d263b4b43ef 100644 --- a/extras/hs-test/infra/netconfig.go +++ b/extras/hs-test/infra/netconfig.go @@ -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 } diff --git a/extras/hs-test/infra/suite_envoy_proxy.go b/extras/hs-test/infra/suite_envoy_proxy.go index c20cf291388..dcafc87b750 100644 --- a/extras/hs-test/infra/suite_envoy_proxy.go +++ b/extras/hs-test/infra/suite_envoy_proxy.go @@ -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) diff --git a/extras/hs-test/infra/suite_h2.go b/extras/hs-test/infra/suite_h2.go index ba99286d8e0..95f5c0c0460 100644 --- a/extras/hs-test/infra/suite_h2.go +++ b/extras/hs-test/infra/suite_h2.go @@ -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() diff --git a/extras/hs-test/infra/suite_ldp.go b/extras/hs-test/infra/suite_ldp.go index 53fe10086d0..ddf756fa582 100644 --- a/extras/hs-test/infra/suite_ldp.go +++ b/extras/hs-test/infra/suite_ldp.go @@ -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) } diff --git a/extras/hs-test/infra/suite_nginx_proxy.go b/extras/hs-test/infra/suite_nginx_proxy.go index 1b6d9f61aae..7913ffa9987 100644 --- a/extras/hs-test/infra/suite_nginx_proxy.go +++ b/extras/hs-test/infra/suite_nginx_proxy.go @@ -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() diff --git a/extras/hs-test/infra/suite_no_topo.go b/extras/hs-test/infra/suite_no_topo.go index d084413f7e6..c74c5a060ea 100644 --- a/extras/hs-test/infra/suite_no_topo.go +++ b/extras/hs-test/infra/suite_no_topo.go @@ -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 index 00000000000..abc00585f24 --- /dev/null +++ b/extras/hs-test/infra/suite_no_topo6.go @@ -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)) + } + } +}) diff --git a/extras/hs-test/infra/suite_veth.go b/extras/hs-test/infra/suite_veth.go index c13f3e4cdf8..c8f56402827 100644 --- a/extras/hs-test/infra/suite_veth.go +++ b/extras/hs-test/infra/suite_veth.go @@ -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 index 00000000000..f81414b5a5b --- /dev/null +++ b/extras/hs-test/infra/suite_veth6.go @@ -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)) + } + } +}) diff --git a/extras/hs-test/infra/suite_vpp_proxy.go b/extras/hs-test/infra/suite_vpp_proxy.go index 137bbb679d8..60230d728d5 100644 --- a/extras/hs-test/infra/suite_vpp_proxy.go +++ b/extras/hs-test/infra/suite_vpp_proxy.go @@ -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() diff --git a/extras/hs-test/infra/suite_vpp_udp_proxy.go b/extras/hs-test/infra/suite_vpp_udp_proxy.go index 62bf3ddd466..46d5388a605 100644 --- a/extras/hs-test/infra/suite_vpp_udp_proxy.go +++ b/extras/hs-test/infra/suite_vpp_udp_proxy.go @@ -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 diff --git a/extras/hs-test/infra/vppinstance.go b/extras/hs-test/infra/vppinstance.go index 1d07c74b6d5..41bcb66ee49 100644 --- a/extras/hs-test/infra/vppinstance.go +++ b/extras/hs-test/infra/vppinstance.go @@ -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 } diff --git a/extras/hs-test/nginx_test.go b/extras/hs-test/nginx_test.go index 12aa2487c2d..f5f10cc49d1 100644 --- a/extras/hs-test/nginx_test.go +++ b/extras/hs-test/nginx_test.go @@ -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)) +} diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go index b6b4df5d0cd..e12b38e4084 100644 --- a/extras/hs-test/proxy_test.go +++ b/extras/hs-test/proxy_test.go @@ -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) diff --git a/extras/hs-test/resources/nginx/nginx.conf b/extras/hs-test/resources/nginx/nginx.conf index 956a13138eb..04f5f2bd1f8 100644 --- a/extras/hs-test/resources/nginx/nginx.conf +++ b/extras/hs-test/resources/nginx/nginx.conf @@ -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 index 00000000000..139d9964d08 --- /dev/null +++ b/extras/hs-test/topo-network/2peerVeth6.yaml @@ -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 index 00000000000..36498c6783f --- /dev/null +++ b/extras/hs-test/topo-network/tap6.yaml @@ -0,0 +1,11 @@ +--- +devices: + - name: "htaphost" + type: "tap" + ipv6: true + ip6: + network: 1 + peer: + name: "" + ip6: + network: 1