hs-test: refactor test cases from no-topo suite 66/38166/4
authorMaros Ondrejicka <mondreji@cisco.com>
Tue, 7 Feb 2023 19:40:27 +0000 (20:40 +0100)
committerFlorin Coras <florin.coras@gmail.com>
Fri, 10 Feb 2023 05:23:32 +0000 (05:23 +0000)
This converts remaining tests to configation of VPP from test context.

Type: test
Change-Id: I386714f6b290e03d1757c2a033a25fae0340f5d6
Signed-off-by: Maros Ondrejicka <mondreji@cisco.com>
19 files changed:
extras/hs-test/Makefile
extras/hs-test/actions.go [deleted file]
extras/hs-test/container.go
extras/hs-test/docker/Dockerfile.vpp
extras/hs-test/echo_test.go
extras/hs-test/framework_test.go
extras/hs-test/hst_suite.go
extras/hs-test/http_test.go
extras/hs-test/ldp_test.go
extras/hs-test/linux_iperf_test.go
extras/hs-test/main.go [deleted file]
extras/hs-test/netconfig.go
extras/hs-test/proxy_test.go
extras/hs-test/suite_no_topo_test.go
extras/hs-test/topo-containers/single.yaml
extras/hs-test/topo.go
extras/hs-test/utils.go
extras/hs-test/vcl_test.go
extras/hs-test/vppinstance.go

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