From 2908f8cf07c21f385f80d83fdad826a0eea98977 Mon Sep 17 00:00:00 2001 From: Maros Ondrejicka Date: Thu, 2 Feb 2023 08:58:04 +0100 Subject: [PATCH] hs-test: refactor test cases from ns suite This converts more tests to configure VPP from test context. Type: test Signed-off-by: Maros Ondrejicka Change-Id: Idf26b0c16f87e87c97b198412af39b99d947ced6 --- extras/hs-test/actions.go | 247 ------------------------------ extras/hs-test/container.go | 24 ++- extras/hs-test/echo_test.go | 12 +- extras/hs-test/hst_suite.go | 128 ++++++++-------- extras/hs-test/http_test.go | 31 ++-- extras/hs-test/ldp_test.go | 27 ++-- extras/hs-test/linux_iperf_test.go | 4 +- extras/hs-test/main.go | 11 -- extras/hs-test/netconfig.go | 122 ++++++++++----- extras/hs-test/proxy_test.go | 39 ++--- extras/hs-test/resources/envoy/proxy.yaml | 3 +- extras/hs-test/suite_ns_test.go | 37 ++++- extras/hs-test/suite_tap_test.go | 3 +- extras/hs-test/suite_veth_test.go | 16 +- extras/hs-test/topo-containers/ns.yaml | 2 +- extras/hs-test/topo-network/ns.yaml | 8 +- extras/hs-test/topo-network/tap.yaml | 1 - extras/hs-test/utils.go | 9 +- extras/hs-test/vcl_test.go | 65 +++----- extras/hs-test/vppinstance.go | 68 ++++---- 20 files changed, 333 insertions(+), 524 deletions(-) diff --git a/extras/hs-test/actions.go b/extras/hs-test/actions.go index 60398704763..9233e2d1ea2 100644 --- a/extras/hs-test/actions.go +++ b/extras/hs-test/actions.go @@ -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. diff --git a/extras/hs-test/container.go b/extras/hs-test/container.go index 91ca2c2b0b1..cc2d441f7ec 100644 --- a/extras/hs-test/container.go +++ b/extras/hs-test/container.go @@ -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) { diff --git a/extras/hs-test/echo_test.go b/extras/hs-test/echo_test.go index 1b24e08466d..b32d66ee533 100644 --- a/extras/hs-test/echo_test.go +++ b/extras/hs-test/echo_test.go @@ -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) } diff --git a/extras/hs-test/hst_suite.go b/extras/hs-test/hst_suite.go index 9cf38d95895..24b4fc242d4 100644 --- a/extras/hs-test/hst_suite.go +++ b/extras/hs-test/hst_suite.go @@ -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 } diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index 52b7c39fa77..912c98283b1 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -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, "", " 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 } diff --git a/extras/hs-test/ldp_test.go b/extras/hs-test/ldp_test.go index cbba227c328..17f78ca4db3 100644 --- a/extras/hs-test/ldp_test.go +++ b/extras/hs-test/ldp_test.go @@ -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 diff --git a/extras/hs-test/linux_iperf_test.go b/extras/hs-test/linux_iperf_test.go index 833fb2c2c4a..154a9b543b9 100644 --- a/extras/hs-test/linux_iperf_test.go +++ b/extras/hs-test/linux_iperf_test.go @@ -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 diff --git a/extras/hs-test/main.go b/extras/hs-test/main.go index 98627a53e12..8fa1458767d 100644 --- a/extras/hs-test/main.go +++ b/extras/hs-test/main.go @@ -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 { diff --git a/extras/hs-test/netconfig.go b/extras/hs-test/netconfig.go index b93e460b44d..45ff3790eaf 100644 --- a/extras/hs-test/netconfig.go +++ b/extras/hs-test/netconfig.go @@ -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 } diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go index f592426cf47..4c183517c37 100644 --- a/extras/hs-test/proxy_test.go +++ b/extras/hs-test/proxy_test.go @@ -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() } diff --git a/extras/hs-test/resources/envoy/proxy.yaml b/extras/hs-test/resources/envoy/proxy.yaml index e4a5b81ff65..2093b5613ae 100644 --- a/extras/hs-test/resources/envoy/proxy.yaml +++ b/extras/hs-test/resources/envoy/proxy.yaml @@ -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 diff --git a/extras/hs-test/suite_ns_test.go b/extras/hs-test/suite_ns_test.go index cf7f0ec98f1..5bc45c7f80c 100644 --- a/extras/hs-test/suite_ns_test.go +++ b/extras/hs-test/suite_ns_test.go @@ -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()) +} diff --git a/extras/hs-test/suite_tap_test.go b/extras/hs-test/suite_tap_test.go index 26f5224d148..96f475c4c5a 100644 --- a/extras/hs-test/suite_tap_test.go +++ b/extras/hs-test/suite_tap_test.go @@ -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") } diff --git a/extras/hs-test/suite_veth_test.go b/extras/hs-test/suite_veth_test.go index 81a21a2ce5f..ff79dfae799 100644 --- a/extras/hs-test/suite_veth_test.go +++ b/extras/hs-test/suite_veth_test.go @@ -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) diff --git a/extras/hs-test/topo-containers/ns.yaml b/extras/hs-test/topo-containers/ns.yaml index 9416937fdb6..fddf2d8e37a 100644 --- a/extras/hs-test/topo-containers/ns.yaml +++ b/extras/hs-test/topo-containers/ns.yaml @@ -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: diff --git a/extras/hs-test/topo-network/ns.yaml b/extras/hs-test/topo-network/ns.yaml index 2f7ed39d2e2..c01836507a6 100644 --- a/extras/hs-test/topo-network/ns.yaml +++ b/extras/hs-test/topo-network/ns.yaml @@ -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 diff --git a/extras/hs-test/topo-network/tap.yaml b/extras/hs-test/topo-network/tap.yaml index 4cd95d6e48a..6f041325987 100644 --- a/extras/hs-test/topo-network/tap.yaml +++ b/extras/hs-test/topo-network/tap.yaml @@ -2,4 +2,3 @@ devices: - name: "tap0" type: "tap" - ip4: "10.10.10.1/24" diff --git a/extras/hs-test/utils.go b/extras/hs-test/utils.go index cf30ecec4e0..c5889035c40 100644 --- a/extras/hs-test/utils.go +++ b/extras/hs-test/utils.go @@ -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 } diff --git a/extras/hs-test/vcl_test.go b/extras/hs-test/vcl_test.go index 6c809f4caec..b9ce60afbaf 100644 --- a/extras/hs-test/vcl_test.go +++ b/extras/hs-test/vcl_test.go @@ -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) diff --git a/extras/hs-test/vppinstance.go b/extras/hs-test/vppinstance.go index 3f9ea871565..257798a4f3d 100644 --- a/extras/hs-test/vppinstance.go +++ b/extras/hs-test/vppinstance.go @@ -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( -- 2.16.6