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 <maros.ondrejicka@pantheon.tech> Change-Id: Idf26b0c16f87e87c97b198412af39b99d947ced6
This commit is contained in:

committed by
Florin Coras

parent
0a192ea93d
commit
2908f8cf07
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
if s.numberOfAddresses == 255 {
|
||||
s.T().Fatalf("no available IPv4 addresses")
|
||||
}
|
||||
|
||||
address := fmt.Sprintf("10.10.10.%v/24", s.numberOfAddresses+1)
|
||||
ipPrefix, err = ip_types.ParseAddressWithPrefix(address)
|
||||
if err != nil {
|
||||
return AddressWithPrefix{}, err
|
||||
}
|
||||
s.numberOfAddresses++
|
||||
|
||||
return ipPrefix, nil
|
||||
type NamespaceAddresses struct {
|
||||
namespace string
|
||||
numberOfAddresses int
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
a.AddNamespace(namespace)
|
||||
return a.NewIp4AddressWithNamespace(namespace)
|
||||
}
|
||||
|
||||
func NewAddresser(suite *HstSuite) *Addresser {
|
||||
var addresser = new(Addresser)
|
||||
addresser.suite = suite
|
||||
addresser.AddNamespace(defaultNamespaceName)
|
||||
return addresser
|
||||
}
|
||||
|
@ -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..")
|
||||
// configure vpp in the container
|
||||
container.vppInstance.vppctl("http tps uri tcp://0.0.0.0/8080")
|
||||
|
||||
// start & configure vpp in the container
|
||||
_, err := container.execAction("ConfigureHttpTps")
|
||||
s.assertNil(err)
|
||||
|
||||
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, "<html>", "<html> 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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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...")
|
||||
serverVeth := s.netInterfaces[serverInterface].(*NetworkInterfaceVeth)
|
||||
clientVeth := s.netInterfaces[clientInterface]
|
||||
|
||||
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
|
||||
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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -2,4 +2,3 @@
|
||||
devices:
|
||||
- name: "tap0"
|
||||
type: "tap"
|
||||
ip4: "10.10.10.1/24"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
Reference in New Issue
Block a user