aboutsummaryrefslogtreecommitdiffstats
path: root/extras/hs-test
diff options
context:
space:
mode:
authorMaros Ondrejicka <mondreji@cisco.com>2023-02-07 20:40:27 +0100
committerFlorin Coras <florin.coras@gmail.com>2023-02-10 05:23:32 +0000
commit7550dd268f80334cbb9127feefe35319b9c7e572 (patch)
tree08350b3d4dcf5453941312565c63303d95735903 /extras/hs-test
parent2908f8cf07c21f385f80d83fdad826a0eea98977 (diff)
hs-test: refactor test cases from no-topo suite
This converts remaining tests to configation of VPP from test context. Type: test Change-Id: I386714f6b290e03d1757c2a033a25fae0340f5d6 Signed-off-by: Maros Ondrejicka <mondreji@cisco.com>
Diffstat (limited to 'extras/hs-test')
-rw-r--r--extras/hs-test/Makefile1
-rw-r--r--extras/hs-test/actions.go82
-rw-r--r--extras/hs-test/container.go34
-rw-r--r--extras/hs-test/docker/Dockerfile.vpp2
-rw-r--r--extras/hs-test/echo_test.go4
-rw-r--r--extras/hs-test/framework_test.go19
-rw-r--r--extras/hs-test/hst_suite.go5
-rw-r--r--extras/hs-test/http_test.go45
-rw-r--r--extras/hs-test/ldp_test.go2
-rw-r--r--extras/hs-test/linux_iperf_test.go2
-rw-r--r--extras/hs-test/main.go140
-rw-r--r--extras/hs-test/netconfig.go213
-rw-r--r--extras/hs-test/proxy_test.go4
-rw-r--r--extras/hs-test/suite_no_topo_test.go42
-rw-r--r--extras/hs-test/topo-containers/single.yaml2
-rw-r--r--extras/hs-test/topo.go54
-rw-r--r--extras/hs-test/utils.go63
-rw-r--r--extras/hs-test/vcl_test.go10
-rw-r--r--extras/hs-test/vppinstance.go132
19 files changed, 207 insertions, 649 deletions
diff --git a/extras/hs-test/Makefile b/extras/hs-test/Makefile
index c50e681915a..cd3a284208f 100644
--- a/extras/hs-test/Makefile
+++ b/extras/hs-test/Makefile
@@ -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
index 9233e2d1ea2..00000000000
--- a/extras/hs-test/actions.go
+++ /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
-}
diff --git a/extras/hs-test/container.go b/extras/hs-test/container.go
index cc2d441f7ec..8ece8a8952b 100644
--- a/extras/hs-test/container.go
+++ b/extras/hs-test/container.go
@@ -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()
diff --git a/extras/hs-test/docker/Dockerfile.vpp b/extras/hs-test/docker/Dockerfile.vpp
index f95df2277c9..d9b3f276442 100644
--- a/extras/hs-test/docker/Dockerfile.vpp
+++ b/extras/hs-test/docker/Dockerfile.vpp
@@ -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"]
diff --git a/extras/hs-test/echo_test.go b/extras/hs-test/echo_test.go
index b32d66ee533..70f9e4c31a1 100644
--- a/extras/hs-test/echo_test.go
+++ b/extras/hs-test/echo_test.go
@@ -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)
}
diff --git a/extras/hs-test/framework_test.go b/extras/hs-test/framework_test.go
index 6de8f167f70..fdce5c45bf7 100644
--- a/extras/hs-test/framework_test.go
+++ b/extras/hs-test/framework_test.go
@@ -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)
diff --git a/extras/hs-test/hst_suite.go b/extras/hs-test/hst_suite.go
index 24b4fc242d4..286536da305 100644
--- a/extras/hs-test/hst_suite.go
+++ b/extras/hs-test/hst_suite.go
@@ -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()
}
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go
index 912c98283b1..5e88fe00cc6 100644
--- a/extras/hs-test/http_test.go
+++ b/extras/hs-test/http_test.go
@@ -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
}
diff --git a/extras/hs-test/ldp_test.go b/extras/hs-test/ldp_test.go
index 17f78ca4db3..59d31e13890 100644
--- a/extras/hs-test/ldp_test.go
+++ b/extras/hs-test/ldp_test.go
@@ -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)
diff --git a/extras/hs-test/linux_iperf_test.go b/extras/hs-test/linux_iperf_test.go
index 154a9b543b9..2c3437fe915 100644
--- a/extras/hs-test/linux_iperf_test.go
+++ b/extras/hs-test/linux_iperf_test.go
@@ -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
index 8fa1458767d..00000000000
--- a/extras/hs-test/main.go
+++ /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)
- }
-}
diff --git a/extras/hs-test/netconfig.go b/extras/hs-test/netconfig.go
index 45ff3790eaf..d94b3269889 100644
--- a/extras/hs-test/netconfig.go
+++ b/extras/hs-test/netconfig.go
@@ -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 {
diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go
index 4c183517c37..d8918f1842b 100644
--- a/extras/hs-test/proxy_test.go
+++ b/extras/hs-test/proxy_test.go
@@ -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)
diff --git a/extras/hs-test/suite_no_topo_test.go b/extras/hs-test/suite_no_topo_test.go
index 421decc1a61..01958b0a804 100644
--- a/extras/hs-test/suite_no_topo_test.go
+++ b/extras/hs-test/suite_no_topo_test.go
@@ -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)
}
diff --git a/extras/hs-test/topo-containers/single.yaml b/extras/hs-test/topo-containers/single.yaml
index 9ecdc904d4d..a8ce48994ea 100644
--- a/extras/hs-test/topo-containers/single.yaml
+++ b/extras/hs-test/topo-containers/single.yaml
@@ -1,7 +1,7 @@
---
volumes:
- volume: &shared-vol
- host-dir: shared-vol
+ host-dir: /tmp/shared-vol
containers:
- name: "vpp"
diff --git a/extras/hs-test/topo.go b/extras/hs-test/topo.go
index b7e883bd773..d77d2dab33f 100644
--- a/extras/hs-test/topo.go
+++ b/extras/hs-test/topo.go
@@ -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)
-}
diff --git a/extras/hs-test/utils.go b/extras/hs-test/utils.go
index c5889035c40..f912880a78a 100644
--- a/extras/hs-test/utils.go
+++ b/extras/hs-test/utils.go
@@ -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 {
diff --git a/extras/hs-test/vcl_test.go b/extras/hs-test/vcl_test.go
index b9ce60afbaf..7cf4ab75dfd 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.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)
diff --git a/extras/hs-test/vppinstance.go b/extras/hs-test/vppinstance.go
index 257798a4f3d..b45ad6028fe 100644
--- a/extras/hs-test/vppinstance.go
+++ b/extras/hs-test/vppinstance.go
@@ -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()