diff options
author | Zeling Feng <zeling@google.com> | 2020-11-23 18:11:00 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-11-23 18:13:07 -0800 |
commit | d4951e05a00a9ec84b8065311836aa9c844f63f6 (patch) | |
tree | c7d6791ea7f22cf650acc11796abc1b16012e6ec /test/packetimpact/testbench/testbench.go | |
parent | 986683124c41e3ba2d24420a95d7cdb945055381 (diff) |
[1/3] Support isolated containers for parallel packetimpact tests
Summary of the approach: the test runner will set up a few DUTs according to
a flag and pass all the test networks to the testbench. The testbench will only
reside in a single container. The testbench will put all the test networks into
a buffered channel which served as a semaphore and now the user can freely use
t.Parallel() in (sub)tests and the true parallelism will be determined by how
many DUTs are configured. Creating DUTs on demand is not supported yet, the
test author should determine the number of DUTs to be used statically.
Specifically in this change:
- Don't export any global variables about the test network in testbench.
- Sniffer only binds on the local interface because it will be possible to have
multiple interfaces to multiple DUTs in a single testbench container.
- Migrate existing tests to stop using global variables.
PiperOrigin-RevId: 343965962
Diffstat (limited to 'test/packetimpact/testbench/testbench.go')
-rw-r--r-- | test/packetimpact/testbench/testbench.go | 165 |
1 files changed, 116 insertions, 49 deletions
diff --git a/test/packetimpact/testbench/testbench.go b/test/packetimpact/testbench/testbench.go index c1db95d8c..92200add9 100644 --- a/test/packetimpact/testbench/testbench.go +++ b/test/packetimpact/testbench/testbench.go @@ -31,64 +31,120 @@ import ( var ( // Native indicates that the test is being run natively. Native = false - // LocalDevice is the device that testbench uses to inject traffic. - LocalDevice = "" - // RemoteDevice is the device name on the DUT, individual tests can - // use the name to construct tests. - RemoteDevice = "" + // RPCKeepalive is the gRPC keepalive. + RPCKeepalive = 10 * time.Second + // RPCTimeout is the gRPC timeout. + RPCTimeout = 100 * time.Millisecond + // dutTestNets is the pool among which the testbench can choose a DUT to work + // with. + dutTestNets chan *DUTTestNet + + // TODO(zeling): Remove the following variables once the test runner side is + // ready. + localDevice = "" + remoteDevice = "" + localIPv4 = "" + remoteIPv4 = "" + ipv4PrefixLength = 0 + localIPv6 = "" + remoteIPv6 = "" + localInterfaceID uint32 + remoteInterfaceID uint64 + localMAC = "" + remoteMAC = "" + posixServerIP = "" + posixServerPort = 40000 +) + +// DUTTestNet describes the test network setup on dut and how the testbench +// should connect with an existing DUT. +type DUTTestNet struct { + // LocalMAC is the local MAC address on the test network. + LocalMAC net.HardwareAddr + // RemoteMAC is the DUT's MAC address on the test network. + RemoteMAC net.HardwareAddr // LocalIPv4 is the local IPv4 address on the test network. - LocalIPv4 = "" + LocalIPv4 net.IP // RemoteIPv4 is the DUT's IPv4 address on the test network. - RemoteIPv4 = "" + RemoteIPv4 net.IP // IPv4PrefixLength is the network prefix length of the IPv4 test network. - IPv4PrefixLength = 0 - + IPv4PrefixLength int // LocalIPv6 is the local IPv6 address on the test network. - LocalIPv6 = "" + LocalIPv6 net.IP // RemoteIPv6 is the DUT's IPv6 address on the test network. - RemoteIPv6 = "" - - // LocalInterfaceID is the ID of the local interface on the test network. - LocalInterfaceID uint32 - // RemoteInterfaceID is the ID of the remote interface on the test network. - // - // Not using uint32 because package flag does not support uint32. - RemoteInterfaceID uint64 + RemoteIPv6 net.IP + // LocalDevID is the ID of the local interface on the test network. + LocalDevID uint32 + // RemoteDevID is the ID of the remote interface on the test network. + RemoteDevID uint32 + // LocalDevName is the device that testbench uses to inject traffic. + LocalDevName string + // RemoteDevName is the device name on the DUT, individual tests can + // use the name to construct tests. + RemoteDevName string - // LocalMAC is the local MAC address on the test network. - LocalMAC = "" - // RemoteMAC is the DUT's MAC address on the test network. - RemoteMAC = "" + // The following two fields on actually on the control network instead + // of the test network, including them for convenience. // POSIXServerIP is the POSIX server's IP address on the control network. - POSIXServerIP = "" + POSIXServerIP net.IP // POSIXServerPort is the UDP port the POSIX server is bound to on the // control network. - POSIXServerPort = 40000 - - // RPCKeepalive is the gRPC keepalive. - RPCKeepalive = 10 * time.Second - // RPCTimeout is the gRPC timeout. - RPCTimeout = 100 * time.Millisecond -) + POSIXServerPort uint16 +} -// RegisterFlags defines flags and associates them with the package-level +// registerFlags defines flags and associates them with the package-level // exported variables above. It should be called by tests in their init // functions. -func RegisterFlags(fs *flag.FlagSet) { - fs.StringVar(&POSIXServerIP, "posix_server_ip", POSIXServerIP, "ip address to listen to for UDP commands") - fs.IntVar(&POSIXServerPort, "posix_server_port", POSIXServerPort, "port to listen to for UDP commands") +func registerFlags(fs *flag.FlagSet) { + fs.StringVar(&posixServerIP, "posix_server_ip", posixServerIP, "ip address to listen to for UDP commands") + fs.IntVar(&posixServerPort, "posix_server_port", posixServerPort, "port to listen to for UDP commands") + fs.StringVar(&localIPv4, "local_ipv4", localIPv4, "local IPv4 address for test packets") + fs.StringVar(&remoteIPv4, "remote_ipv4", remoteIPv4, "remote IPv4 address for test packets") + fs.StringVar(&remoteIPv6, "remote_ipv6", remoteIPv6, "remote IPv6 address for test packets") + fs.StringVar(&remoteMAC, "remote_mac", remoteMAC, "remote mac address for test packets") + fs.StringVar(&localDevice, "local_device", localDevice, "local device to inject traffic") + fs.StringVar(&remoteDevice, "remote_device", remoteDevice, "remote device on the DUT") + fs.Uint64Var(&remoteInterfaceID, "remote_interface_id", remoteInterfaceID, "remote interface ID for test packets") + + fs.BoolVar(&Native, "native", Native, "whether the test is running natively") fs.DurationVar(&RPCTimeout, "rpc_timeout", RPCTimeout, "gRPC timeout") fs.DurationVar(&RPCKeepalive, "rpc_keepalive", RPCKeepalive, "gRPC keepalive") - fs.StringVar(&LocalIPv4, "local_ipv4", LocalIPv4, "local IPv4 address for test packets") - fs.StringVar(&RemoteIPv4, "remote_ipv4", RemoteIPv4, "remote IPv4 address for test packets") - fs.StringVar(&RemoteIPv6, "remote_ipv6", RemoteIPv6, "remote IPv6 address for test packets") - fs.StringVar(&RemoteMAC, "remote_mac", RemoteMAC, "remote mac address for test packets") - fs.StringVar(&LocalDevice, "local_device", LocalDevice, "local device to inject traffic") - fs.StringVar(&RemoteDevice, "remote_device", RemoteDevice, "remote device on the DUT") - fs.BoolVar(&Native, "native", Native, "whether the test is running natively") - fs.Uint64Var(&RemoteInterfaceID, "remote_interface_id", RemoteInterfaceID, "remote interface ID for test packets") +} + +// Initialize initializes the testbench, it parse the flags and sets up the +// pool of test networks for testbench's later use. +func Initialize(fs *flag.FlagSet) { + registerFlags(fs) + flag.Parse() + if err := genPseudoFlags(); err != nil { + panic(err) + } + var dut DUTTestNet + var err error + dut.LocalMAC, err = net.ParseMAC(localMAC) + if err != nil { + panic(err) + } + dut.RemoteMAC, err = net.ParseMAC(remoteMAC) + if err != nil { + panic(err) + } + dut.LocalIPv4 = net.ParseIP(localIPv4).To4() + dut.LocalIPv6 = net.ParseIP(localIPv6).To16() + dut.RemoteIPv4 = net.ParseIP(remoteIPv4).To4() + dut.RemoteIPv6 = net.ParseIP(remoteIPv6).To16() + dut.LocalDevID = uint32(localInterfaceID) + dut.RemoteDevID = uint32(remoteInterfaceID) + dut.LocalDevName = localDevice + dut.RemoteDevName = remoteDevice + dut.POSIXServerIP = net.ParseIP(posixServerIP) + dut.POSIXServerPort = uint16(posixServerPort) + dut.IPv4PrefixLength = ipv4PrefixLength + + dutTestNets = make(chan *DUTTestNet, 1) + dutTestNets <- &dut } // genPseudoFlags populates flag-like global config based on real flags. @@ -104,21 +160,20 @@ func genPseudoFlags() error { return fmt.Errorf("parsing devices: %w", err) } - _, deviceInfo, err := netdevs.FindDeviceByIP(net.ParseIP(LocalIPv4), devs) + _, deviceInfo, err := netdevs.FindDeviceByIP(net.ParseIP(localIPv4), devs) if err != nil { return fmt.Errorf("can't find deviceInfo: %w", err) } - LocalMAC = deviceInfo.MAC.String() - LocalIPv6 = deviceInfo.IPv6Addr.String() - LocalInterfaceID = deviceInfo.ID + localMAC = deviceInfo.MAC.String() + localIPv6 = deviceInfo.IPv6Addr.String() + localInterfaceID = deviceInfo.ID if deviceInfo.IPv4Net != nil { - IPv4PrefixLength, _ = deviceInfo.IPv4Net.Mask.Size() + ipv4PrefixLength, _ = deviceInfo.IPv4Net.Mask.Size() } else { - IPv4PrefixLength, _ = net.ParseIP(LocalIPv4).DefaultMask().Size() + ipv4PrefixLength, _ = net.ParseIP(localIPv4).DefaultMask().Size() } - return nil } @@ -132,3 +187,15 @@ func GenerateRandomPayload(t *testing.T, n int) []byte { } return buf } + +// GetDUTTestNet gets a usable DUTTestNet, the function will block until any +// becomes available. +func GetDUTTestNet() *DUTTestNet { + return <-dutTestNets +} + +// Release releases the DUTTestNet back to the pool so that some other test +// can use. +func (n *DUTTestNet) Release() { + dutTestNets <- n +} |