summaryrefslogtreecommitdiffhomepage
path: root/test/packetimpact/runner
diff options
context:
space:
mode:
Diffstat (limited to 'test/packetimpact/runner')
-rw-r--r--test/packetimpact/runner/BUILD38
-rw-r--r--test/packetimpact/runner/defs.bzl315
-rw-r--r--test/packetimpact/runner/dut.go663
-rw-r--r--test/packetimpact/runner/packetimpact_test.go32
4 files changed, 0 insertions, 1048 deletions
diff --git a/test/packetimpact/runner/BUILD b/test/packetimpact/runner/BUILD
deleted file mode 100644
index 888c44343..000000000
--- a/test/packetimpact/runner/BUILD
+++ /dev/null
@@ -1,38 +0,0 @@
-load("//tools:defs.bzl", "bzl_library", "go_library", "go_test")
-
-package(
- default_visibility = ["//test/packetimpact:__subpackages__"],
- licenses = ["notice"],
-)
-
-go_test(
- name = "packetimpact_test",
- srcs = [
- "packetimpact_test.go",
- ],
- tags = [
- # Not intended to be run directly.
- "local",
- "manual",
- ],
- deps = [":runner"],
-)
-
-bzl_library(
- name = "defs_bzl",
- srcs = ["defs.bzl"],
- visibility = ["//test/packetimpact:__subpackages__"],
-)
-
-go_library(
- name = "runner",
- testonly = True,
- srcs = ["dut.go"],
- visibility = ["//test/packetimpact:__subpackages__"],
- deps = [
- "//pkg/test/dockerutil",
- "//test/packetimpact/netdevs",
- "//test/packetimpact/testbench",
- "@com_github_docker_docker//api/types/mount:go_default_library",
- ],
-)
diff --git a/test/packetimpact/runner/defs.bzl b/test/packetimpact/runner/defs.bzl
deleted file mode 100644
index 19f6cc0e0..000000000
--- a/test/packetimpact/runner/defs.bzl
+++ /dev/null
@@ -1,315 +0,0 @@
-"""Defines rules for packetimpact test targets."""
-
-load("//tools:defs.bzl", "go_test")
-
-def _packetimpact_test_impl(ctx):
- test_runner = ctx.executable._test_runner
- bench = ctx.actions.declare_file("%s-bench" % ctx.label.name)
- bench_content = "\n".join([
- "#!/bin/bash",
- # This test will run part in a distinct user namespace. This can cause
- # permission problems, because all runfiles may not be owned by the
- # current user, and no other users will be mapped in that namespace.
- # Make sure that everything is readable here.
- "find . -type f -or -type d -exec chmod a+rx {} \\;",
- "%s %s --testbench_binary %s --num_duts %d $@\n" % (
- test_runner.short_path,
- " ".join(ctx.attr.flags),
- ctx.files.testbench_binary[0].short_path,
- ctx.attr.num_duts,
- ),
- ])
- ctx.actions.write(bench, bench_content, is_executable = True)
-
- transitive_files = []
- if hasattr(ctx.attr._test_runner, "data_runfiles"):
- transitive_files.append(ctx.attr._test_runner.data_runfiles.files)
- files = [test_runner] + ctx.files.testbench_binary + ctx.files._posix_server
- runfiles = ctx.runfiles(
- files = files,
- transitive_files = depset(transitive = transitive_files),
- collect_default = True,
- collect_data = True,
- )
- return [DefaultInfo(executable = bench, runfiles = runfiles)]
-
-_packetimpact_test = rule(
- attrs = {
- "_test_runner": attr.label(
- executable = True,
- cfg = "target",
- default = ":packetimpact_test",
- ),
- "_posix_server": attr.label(
- cfg = "target",
- default = "//test/packetimpact/dut:posix_server",
- ),
- "testbench_binary": attr.label(
- cfg = "target",
- mandatory = True,
- ),
- "flags": attr.string_list(
- mandatory = False,
- default = [],
- ),
- "num_duts": attr.int(
- mandatory = False,
- default = 1,
- ),
- },
- test = True,
- implementation = _packetimpact_test_impl,
-)
-
-PACKETIMPACT_TAGS = [
- "local",
- "manual",
- "packetimpact",
-]
-
-def packetimpact_native_test(
- name,
- testbench_binary,
- expect_failure = False,
- **kwargs):
- """Add a native packetimpact test.
-
- Args:
- name: name of the test
- testbench_binary: the testbench binary
- expect_failure: the test must fail
- **kwargs: all the other args, forwarded to _packetimpact_test
- """
- expect_failure_flag = ["--expect_failure"] if expect_failure else []
- _packetimpact_test(
- name = name + "_native_test",
- testbench_binary = testbench_binary,
- flags = ["--native"] + expect_failure_flag,
- tags = PACKETIMPACT_TAGS,
- **kwargs
- )
-
-def packetimpact_netstack_test(
- name,
- testbench_binary,
- expect_failure = False,
- **kwargs):
- """Add a packetimpact test on netstack.
-
- Args:
- name: name of the test
- testbench_binary: the testbench binary
- expect_failure: the test must fail
- **kwargs: all the other args, forwarded to _packetimpact_test
- """
- expect_failure_flag = []
- if expect_failure:
- expect_failure_flag = ["--expect_failure"]
- _packetimpact_test(
- name = name + "_netstack_test",
- testbench_binary = testbench_binary,
- # Note that a distinct runtime must be provided in the form
- # --test_arg=--runtime=other when invoking bazel.
- flags = expect_failure_flag,
- tags = PACKETIMPACT_TAGS,
- **kwargs
- )
-
-def packetimpact_go_test(name, expect_native_failure = False, expect_netstack_failure = False, num_duts = 1, **kwargs):
- """Add packetimpact tests written in go.
-
- Args:
- name: name of the test
- expect_native_failure: the test must fail natively
- expect_netstack_failure: the test must fail for Netstack
- num_duts: how many DUTs are needed for the test
- **kwargs: all the other args, forwarded to packetimpact_native_test and packetimpact_netstack_test
- """
- testbench_binary = name + "_test"
- packetimpact_native_test(
- name = name,
- expect_failure = expect_native_failure,
- num_duts = num_duts,
- testbench_binary = testbench_binary,
- **kwargs
- )
- packetimpact_netstack_test(
- name = name,
- expect_failure = expect_netstack_failure,
- num_duts = num_duts,
- testbench_binary = testbench_binary,
- **kwargs
- )
-
-def packetimpact_testbench(name, size = "small", pure = True, **kwargs):
- """Build packetimpact testbench written in go.
-
- Args:
- name: name of the test
- size: size of the test
- pure: make a static go binary
- **kwargs: all the other args, forwarded to go_test
- """
- go_test(
- name = name + "_test",
- size = size,
- pure = pure,
- nogo = False, # FIXME(gvisor.dev/issue/3374): Not working with all build systems.
- tags = [
- "local",
- "manual",
- ],
- **kwargs
- )
-
-PacketimpactTestInfo = provider(
- doc = "Provide information for packetimpact tests",
- fields = [
- "name",
- "timeout",
- "expect_netstack_failure",
- "num_duts",
- ],
-)
-
-ALL_TESTS = [
- PacketimpactTestInfo(
- name = "fin_wait2_timeout",
- ),
- PacketimpactTestInfo(
- name = "ipv4_id_uniqueness",
- ),
- PacketimpactTestInfo(
- name = "udp_discard_mcast_source_addr",
- ),
- PacketimpactTestInfo(
- name = "udp_any_addr_recv_unicast",
- ),
- PacketimpactTestInfo(
- name = "udp_icmp_error_propagation",
- ),
- PacketimpactTestInfo(
- name = "tcp_window_shrink",
- ),
- PacketimpactTestInfo(
- name = "tcp_zero_window_probe",
- ),
- PacketimpactTestInfo(
- name = "tcp_zero_window_probe_retransmit",
- ),
- PacketimpactTestInfo(
- name = "tcp_zero_window_probe_usertimeout",
- ),
- PacketimpactTestInfo(
- name = "tcp_retransmits",
- ),
- PacketimpactTestInfo(
- name = "tcp_outside_the_window",
- ),
- PacketimpactTestInfo(
- name = "tcp_noaccept_close_rst",
- ),
- PacketimpactTestInfo(
- name = "tcp_send_window_sizes_piggyback",
- ),
- PacketimpactTestInfo(
- name = "tcp_unacc_seq_ack",
- ),
- PacketimpactTestInfo(
- name = "tcp_paws_mechanism",
- # TODO(b/156682000): Fix netstack then remove the line below.
- expect_netstack_failure = True,
- ),
- PacketimpactTestInfo(
- name = "tcp_user_timeout",
- ),
- PacketimpactTestInfo(
- name = "tcp_zero_receive_window",
- ),
- PacketimpactTestInfo(
- name = "tcp_queue_send_recv_in_syn_sent",
- ),
- PacketimpactTestInfo(
- name = "tcp_synsent_reset",
- ),
- PacketimpactTestInfo(
- name = "tcp_synrcvd_reset",
- ),
- PacketimpactTestInfo(
- name = "tcp_network_unreachable",
- ),
- PacketimpactTestInfo(
- name = "tcp_cork_mss",
- ),
- PacketimpactTestInfo(
- name = "tcp_handshake_window_size",
- ),
- PacketimpactTestInfo(
- name = "tcp_timewait_reset",
- # TODO(b/168523247): Fix netstack then remove the line below.
- expect_netstack_failure = True,
- ),
- PacketimpactTestInfo(
- name = "tcp_listen_backlog",
- ),
- PacketimpactTestInfo(
- name = "tcp_syncookie",
- ),
- PacketimpactTestInfo(
- name = "tcp_connect_icmp_error",
- ),
- PacketimpactTestInfo(
- name = "icmpv6_param_problem",
- ),
- PacketimpactTestInfo(
- name = "ipv6_unknown_options_action",
- ),
- PacketimpactTestInfo(
- name = "ipv4_fragment_reassembly",
- ),
- PacketimpactTestInfo(
- name = "ipv6_fragment_reassembly",
- ),
- PacketimpactTestInfo(
- name = "ipv6_fragment_icmp_error",
- num_duts = 3,
- ),
- PacketimpactTestInfo(
- name = "tcp_linger",
- ),
- PacketimpactTestInfo(
- name = "tcp_rcv_buf_space",
- ),
- PacketimpactTestInfo(
- name = "tcp_rack",
- expect_netstack_failure = True,
- ),
- PacketimpactTestInfo(
- name = "tcp_info",
- ),
- PacketimpactTestInfo(
- name = "tcp_fin_retransmission",
- ),
- PacketimpactTestInfo(
- name = "generic_dgram_socket_send_recv",
- timeout = "long",
- ),
-]
-
-def validate_all_tests():
- """
- Make sure that ALL_TESTS list is in sync with the rules in BUILD.
-
- This function is order-dependent, it is intended to be used after
- all packetimpact_testbench rules and before using ALL_TESTS list
- at the end of BUILD.
- """
- all_tests_dict = {} # there is no set, using dict to approximate.
- for test in ALL_TESTS:
- rule_name = test.name + "_test"
- all_tests_dict[rule_name] = True
- if not native.existing_rule(rule_name):
- fail("%s does not have a packetimpact_testbench rule in BUILD" % test.name)
- for name in native.existing_rules():
- if name.endswith("_test") and name not in all_tests_dict:
- fail("%s is not declared in ALL_TESTS list in defs.bzl" % name[:-5])
diff --git a/test/packetimpact/runner/dut.go b/test/packetimpact/runner/dut.go
deleted file mode 100644
index f27e52f93..000000000
--- a/test/packetimpact/runner/dut.go
+++ /dev/null
@@ -1,663 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package runner starts docker containers and networking for a packetimpact test.
-package runner
-
-import (
- "context"
- "encoding/json"
- "flag"
- "fmt"
- "io/ioutil"
- "log"
- "math/rand"
- "net"
- "os"
- "os/exec"
- "path"
- "path/filepath"
- "strings"
- "testing"
- "time"
-
- "github.com/docker/docker/api/types/mount"
- "gvisor.dev/gvisor/pkg/test/dockerutil"
- "gvisor.dev/gvisor/test/packetimpact/netdevs"
- "gvisor.dev/gvisor/test/packetimpact/testbench"
-)
-
-// stringList implements flag.Value.
-type stringList []string
-
-// String implements flag.Value.String.
-func (l *stringList) String() string {
- return strings.Join(*l, ",")
-}
-
-// Set implements flag.Value.Set.
-func (l *stringList) Set(value string) error {
- *l = append(*l, value)
- return nil
-}
-
-var (
- native = false
- testbenchBinary = ""
- tshark = false
- extraTestArgs = stringList{}
- expectFailure = false
- numDUTs = 1
-
- // DUTAddr is the IP addres for DUT.
- DUTAddr = net.IPv4(0, 0, 0, 10)
- testbenchAddr = net.IPv4(0, 0, 0, 20)
-)
-
-// 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.BoolVar(&native, "native", false, "whether the test should be run natively")
- fs.StringVar(&testbenchBinary, "testbench_binary", "", "path to the testbench binary")
- fs.BoolVar(&tshark, "tshark", false, "use more verbose tshark in logs instead of tcpdump")
- fs.Var(&extraTestArgs, "extra_test_arg", "extra arguments to pass to the testbench")
- fs.BoolVar(&expectFailure, "expect_failure", false, "expect that the test will fail when run")
- fs.IntVar(&numDUTs, "num_duts", numDUTs, "the number of duts to create")
-}
-
-const (
- // CtrlPort is the port that posix_server listens on.
- CtrlPort uint16 = 40000
- // testOutputDir is the directory in each container that holds test output.
- testOutputDir = "/tmp/testoutput"
-)
-
-// logger implements testutil.Logger.
-//
-// Labels logs based on their source and formats multi-line logs.
-type logger string
-
-// Name implements testutil.Logger.Name.
-func (l logger) Name() string {
- return string(l)
-}
-
-// Logf implements testutil.Logger.Logf.
-func (l logger) Logf(format string, args ...interface{}) {
- lines := strings.Split(fmt.Sprintf(format, args...), "\n")
- log.Printf("%s: %s", l, lines[0])
- for _, line := range lines[1:] {
- log.Printf("%*s %s", len(l), "", line)
- }
-}
-
-// dutInfo encapsulates all the essential information to set up testbench
-// container.
-type dutInfo struct {
- dut DUT
- ctrlNet, testNet *dockerutil.Network
- netInfo *testbench.DUTTestNet
- uname *testbench.DUTUname
-}
-
-// setUpDUT will set up one DUT and return information for setting up the
-// container for testbench.
-func setUpDUT(ctx context.Context, t *testing.T, id int, mkDevice func(*dockerutil.Container) DUT) (dutInfo, error) {
- // Create the networks needed for the test. One control network is needed
- // for the gRPC control packets and one test network on which to transmit
- // the test packets.
- var info dutInfo
- ctrlNet := dockerutil.NewNetwork(ctx, logger("ctrlNet"))
- testNet := dockerutil.NewNetwork(ctx, logger("testNet"))
- for _, dn := range []*dockerutil.Network{ctrlNet, testNet} {
- for {
- if err := createDockerNetwork(ctx, dn); err != nil {
- t.Log("creating docker network:", err)
- const wait = 100 * time.Millisecond
- t.Logf("sleeping %s and will try creating docker network again", wait)
- // This can fail if another docker network claimed the same IP so we
- // will just try again.
- time.Sleep(wait)
- continue
- }
- break
- }
- dn := dn
- t.Cleanup(func() {
- if err := dn.Cleanup(ctx); err != nil {
- t.Errorf("failed to cleanup network %s: %s", dn.Name, err)
- }
- })
- // Sanity check.
- if inspect, err := dn.Inspect(ctx); err != nil {
- return dutInfo{}, fmt.Errorf("failed to inspect network %s: %w", dn.Name, err)
- } else if inspect.Name != dn.Name {
- return dutInfo{}, fmt.Errorf("name mismatch for network want: %s got: %s", dn.Name, inspect.Name)
- }
- }
- info.ctrlNet = ctrlNet
- info.testNet = testNet
-
- // Create the Docker container for the DUT.
- makeContainer := dockerutil.MakeContainer
- if native {
- makeContainer = dockerutil.MakeNativeContainer
- }
- dutContainer := makeContainer(ctx, logger(fmt.Sprintf("dut-%d", id)))
- t.Cleanup(func() {
- dutContainer.CleanUp(ctx)
- })
- info.dut = mkDevice(dutContainer)
-
- runOpts := dockerutil.RunOpts{
- Image: "packetimpact",
- CapAdd: []string{"NET_ADMIN"},
- }
- if _, err := MountTempDirectory(t, &runOpts, "dut-output", testOutputDir); err != nil {
- return dutInfo{}, err
- }
-
- ipv4PrefixLength, _ := testNet.Subnet.Mask.Size()
- remoteIPv6, remoteMAC, dutDeviceID, dutTestNetDev, err := info.dut.Prepare(ctx, t, runOpts, ctrlNet, testNet)
- if err != nil {
- return dutInfo{}, err
- }
- info.netInfo = &testbench.DUTTestNet{
- RemoteMAC: remoteMAC,
- RemoteIPv4: AddressInSubnet(DUTAddr, *testNet.Subnet),
- RemoteIPv6: remoteIPv6,
- RemoteDevID: dutDeviceID,
- RemoteDevName: dutTestNetDev,
- LocalIPv4: AddressInSubnet(testbenchAddr, *testNet.Subnet),
- IPv4PrefixLength: ipv4PrefixLength,
- POSIXServerIP: AddressInSubnet(DUTAddr, *ctrlNet.Subnet),
- POSIXServerPort: CtrlPort,
- }
- info.uname, err = info.dut.Uname(ctx)
- if err != nil {
- return dutInfo{}, fmt.Errorf("failed to get uname information on DUT: %w", err)
- }
- return info, nil
-}
-
-// TestWithDUT runs a packetimpact test with the given information.
-func TestWithDUT(ctx context.Context, t *testing.T, mkDevice func(*dockerutil.Container) DUT) {
- if testbenchBinary == "" {
- t.Fatal("--testbench_binary is missing")
- }
- dockerutil.EnsureSupportedDockerVersion()
-
- dutInfoChan := make(chan dutInfo, numDUTs)
- errChan := make(chan error, numDUTs)
- var dockerNetworks []*dockerutil.Network
- var dutInfos []*testbench.DUTInfo
- var duts []DUT
-
- setUpCtx, cancelSetup := context.WithCancel(ctx)
- t.Cleanup(cancelSetup)
- for i := 0; i < numDUTs; i++ {
- go func(i int) {
- info, err := setUpDUT(setUpCtx, t, i, mkDevice)
- if err != nil {
- errChan <- err
- } else {
- dutInfoChan <- info
- }
- }(i)
- }
- for i := 0; i < numDUTs; i++ {
- select {
- case info := <-dutInfoChan:
- dockerNetworks = append(dockerNetworks, info.ctrlNet, info.testNet)
- dutInfos = append(dutInfos, &testbench.DUTInfo{
- Net: info.netInfo,
- Uname: info.uname,
- })
- duts = append(duts, info.dut)
- case err := <-errChan:
- t.Fatal(err)
- }
- }
-
- // Create the Docker container for the testbench.
- testbenchContainer := dockerutil.MakeNativeContainer(ctx, logger("testbench"))
- t.Cleanup(func() {
- testbenchContainer.CleanUp(ctx)
- })
-
- runOpts := dockerutil.RunOpts{
- Image: "packetimpact",
- CapAdd: []string{"NET_ADMIN"},
- }
- if _, err := MountTempDirectory(t, &runOpts, "testbench-output", testOutputDir); err != nil {
- t.Fatal(err)
- }
- tbb := path.Base(testbenchBinary)
- containerTestbenchBinary := filepath.Join("/packetimpact", tbb)
- testbenchContainer.CopyFiles(&runOpts, "/packetimpact", filepath.Join("test/packetimpact/tests", tbb))
-
- if err := StartContainer(
- ctx,
- runOpts,
- testbenchContainer,
- testbenchAddr,
- dockerNetworks,
- nil, /* sysctls */
- "tail", "-f", "/dev/null",
- ); err != nil {
- t.Fatalf("cannot start testbench container: %s", err)
- }
-
- for i := range dutInfos {
- name, info, err := deviceByIP(ctx, testbenchContainer, dutInfos[i].Net.LocalIPv4)
- if err != nil {
- t.Fatalf("failed to get the device name associated with %s: %s", dutInfos[i].Net.LocalIPv4, err)
- }
- dutInfos[i].Net.LocalDevName = name
- dutInfos[i].Net.LocalDevID = info.ID
- dutInfos[i].Net.LocalMAC = info.MAC
- localIPv6, err := getOrAssignIPv6Addr(ctx, testbenchContainer, name)
- if err != nil {
- t.Fatalf("failed to get IPV6 address on %s: %s", testbenchContainer.Name, err)
- }
- dutInfos[i].Net.LocalIPv6 = localIPv6
- }
- dutInfosBytes, err := json.Marshal(dutInfos)
- if err != nil {
- t.Fatalf("failed to marshal %v into json: %s", dutInfos, err)
- }
-
- baseSnifferArgs := []string{
- "tcpdump",
- "-vvv",
- "--absolute-tcp-sequence-numbers",
- "--packet-buffered",
- // Disable DNS resolution.
- "-n",
- // run tcpdump as root since the output directory is owned by root. From
- // `man tcpdump`:
- //
- // -Z user
- // --relinquish-privileges=user
- // If tcpdump is running as root, after opening the capture device
- // or input savefile, change the user ID to user and the group ID to
- // the primary group of user.
- // This behavior is enabled by default (-Z tcpdump), and can be
- // disabled by -Z root.
- "-Z", "root",
- }
- if tshark {
- baseSnifferArgs = []string{
- "tshark",
- "-V",
- "-o", "tcp.check_checksum:TRUE",
- "-o", "udp.check_checksum:TRUE",
- // Disable buffering.
- "-l",
- // Disable DNS resolution.
- "-n",
- }
- }
- for _, info := range dutInfos {
- n := info.Net
- snifferArgs := append(baseSnifferArgs, "-i", n.LocalDevName)
- if !tshark {
- snifferArgs = append(
- snifferArgs,
- "-w",
- filepath.Join(testOutputDir, fmt.Sprintf("%s.pcap", n.LocalDevName)),
- )
- }
- p, err := testbenchContainer.ExecProcess(ctx, dockerutil.ExecOpts{}, snifferArgs...)
- if err != nil {
- t.Fatalf("failed to start exec a sniffer on %s: %s", n.LocalDevName, err)
- }
- t.Cleanup(func() {
- if snifferOut, err := p.Logs(); err != nil {
- t.Errorf("sniffer logs failed: %s\n%s", err, snifferOut)
- } else {
- t.Logf("sniffer logs:\n%s", snifferOut)
- }
- })
- }
-
- // Arm the cleanup hook before we do anthing else. Otherwise failures below
- // can cause the test to hang in the cleanup hook above.
- t.Cleanup(func() {
- // Wait 1 second before killing tcpdump to give it time to flush
- // any packets. On linux tests killing it immediately can
- // sometimes result in partial pcaps.
- time.Sleep(1 * time.Second)
- if logs, err := testbenchContainer.Exec(ctx, dockerutil.ExecOpts{}, "killall", baseSnifferArgs[0]); err != nil {
- t.Errorf("failed to kill all sniffers: %s, logs: %s", err, logs)
- }
- })
-
- for _, info := range dutInfos {
- n := info.Net
- // When the Linux kernel receives a SYN-ACK for a SYN it didn't send, it
- // will respond with an RST. In most packetimpact tests, the SYN is sent
- // by the raw socket, the kernel knows nothing about the connection, this
- // behavior will break lots of TCP related packetimpact tests. To prevent
- // this, we can install the following iptables rules. The raw socket that
- // packetimpact tests use will still be able to see everything.
- for _, bin := range []string{"iptables", "ip6tables"} {
- if logs, err := testbenchContainer.Exec(ctx, dockerutil.ExecOpts{}, bin, "-A", "INPUT", "-i", n.LocalDevName, "-p", "tcp", "-j", "DROP"); err != nil {
- t.Fatalf("unable to Exec %s on container %s: %s, logs from testbench:\n%s", bin, testbenchContainer.Name, err, logs)
- }
- }
- }
-
- // FIXME(b/156449515): Some piece of the system has a race. The old
- // bash script version had a sleep, so we have one too. The race should
- // be fixed and this sleep removed.
- time.Sleep(time.Second)
-
- // Start a packetimpact test on the test bench. The packetimpact test sends
- // and receives packets and also sends POSIX socket commands to the
- // posix_server to be executed on the DUT.
- testArgs := []string{containerTestbenchBinary}
- if testing.Verbose() {
- testArgs = append(testArgs, "-test.v")
- }
- testArgs = append(testArgs, extraTestArgs...)
- testArgs = append(testArgs,
- fmt.Sprintf("--native=%t", native),
- "--dut_infos_json", string(dutInfosBytes),
- )
- testbenchLogs, err := testbenchContainer.Exec(ctx, dockerutil.ExecOpts{}, testArgs...)
- var dutLogs string
- for i, dut := range duts {
- logs, err := dut.Logs(ctx)
- if err != nil {
- logs = fmt.Sprintf("failed to fetch DUT logs: %s", err)
- }
- dutLogs = fmt.Sprintf(`%s====== Begin of DUT-%d Logs ======
-
-%s
-
-====== End of DUT-%d Logs ======
-
-`, dutLogs, i, logs, i)
- }
- testLogs := fmt.Sprintf(`
-%s====== Begin of Testbench Logs ======
-
-%s
-
-====== End of Testbench Logs ======`, dutLogs, testbenchLogs)
- if (err != nil) != expectFailure {
- t.Errorf(`test error: %v, expect failure: %t
-%s`, err, expectFailure, testLogs)
- } else if expectFailure {
- t.Logf(`test failed as expected: %v
-%s`, err, testLogs)
- } else if testing.Verbose() {
- t.Log(testLogs)
- }
-}
-
-// DUT describes how to setup/teardown the dut for packetimpact tests.
-type DUT interface {
- // Prepare prepares the dut, starts posix_server and returns the IPv6, MAC
- // address, the interface ID, and the interface name for the testNet on DUT.
- // The t parameter is supposed to be used for t.Cleanup. Don't use it for
- // t.Fatal/FailNow functions.
- Prepare(ctx context.Context, t *testing.T, runOpts dockerutil.RunOpts, ctrlNet, testNet *dockerutil.Network) (net.IP, net.HardwareAddr, uint32, string, error)
-
- // Uname gathers information of DUT using command uname.
- Uname(ctx context.Context) (*testbench.DUTUname, error)
-
- // Logs retrieves the logs from the dut.
- Logs(ctx context.Context) (string, error)
-}
-
-// DockerDUT describes a docker based DUT.
-type DockerDUT struct {
- c *dockerutil.Container
-}
-
-// NewDockerDUT creates a docker based DUT.
-func NewDockerDUT(c *dockerutil.Container) DUT {
- return &DockerDUT{
- c: c,
- }
-}
-
-// Prepare implements DUT.Prepare.
-func (dut *DockerDUT) Prepare(ctx context.Context, _ *testing.T, runOpts dockerutil.RunOpts, ctrlNet, testNet *dockerutil.Network) (net.IP, net.HardwareAddr, uint32, string, error) {
- const containerPosixServerBinary = "/packetimpact/posix_server"
- dut.c.CopyFiles(&runOpts, "/packetimpact", "test/packetimpact/dut/posix_server")
-
- if err := StartContainer(
- ctx,
- runOpts,
- dut.c,
- DUTAddr,
- []*dockerutil.Network{ctrlNet, testNet},
- map[string]string{
- // This enables creating ICMP sockets on Linux.
- "net.ipv4.ping_group_range": "0 0",
- },
- containerPosixServerBinary,
- "--ip=0.0.0.0",
- fmt.Sprintf("--port=%d", CtrlPort),
- ); err != nil {
- return nil, nil, 0, "", fmt.Errorf("failed to start docker container for DUT: %w", err)
- }
-
- if _, err := dut.c.WaitForOutput(ctx, "Server listening.*\n", 60*time.Second); err != nil {
- return nil, nil, 0, "", fmt.Errorf("%s on container %s never listened: %s", containerPosixServerBinary, dut.c.Name, err)
- }
-
- dutTestDevice, dutDeviceInfo, err := deviceByIP(ctx, dut.c, AddressInSubnet(DUTAddr, *testNet.Subnet))
- if err != nil {
- return nil, nil, 0, "", err
- }
-
- remoteIPv6, err := getOrAssignIPv6Addr(ctx, dut.c, dutTestDevice)
- if err != nil {
- return nil, nil, 0, "", fmt.Errorf("failed to get IPv6 address on %s: %s", dut.c.Name, err)
- }
- const testNetDev = "eth2"
-
- return remoteIPv6, dutDeviceInfo.MAC, dutDeviceInfo.ID, testNetDev, nil
-}
-
-// Uname implements DUT.Uname.
-func (dut *DockerDUT) Uname(ctx context.Context) (*testbench.DUTUname, error) {
- machine, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-m")
- if err != nil {
- return nil, err
- }
- kernelRelease, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-r")
- if err != nil {
- return nil, err
- }
- kernelVersion, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-v")
- if err != nil {
- return nil, err
- }
- kernelName, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-s")
- if err != nil {
- return nil, err
- }
- // TODO(gvisor.dev/issues/5586): -o is not supported on macOS.
- operatingSystem, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-o")
- if err != nil {
- return nil, err
- }
- return &testbench.DUTUname{
- Machine: strings.TrimRight(machine, "\n"),
- KernelName: strings.TrimRight(kernelName, "\n"),
- KernelRelease: strings.TrimRight(kernelRelease, "\n"),
- KernelVersion: strings.TrimRight(kernelVersion, "\n"),
- OperatingSystem: strings.TrimRight(operatingSystem, "\n"),
- }, nil
-}
-
-// Logs implements DUT.Logs.
-func (dut *DockerDUT) Logs(ctx context.Context) (string, error) {
- logs, err := dut.c.Logs(ctx)
- if err != nil {
- return "", err
- }
- return logs, nil
-}
-
-// AddNetworks connects docker network with the container and assigns the specific IP.
-func AddNetworks(ctx context.Context, d *dockerutil.Container, addr net.IP, networks []*dockerutil.Network) error {
- for _, dn := range networks {
- ip := AddressInSubnet(addr, *dn.Subnet)
- // Connect to the network with the specified IP address.
- if err := dn.Connect(ctx, d, ip.String(), ""); err != nil {
- return fmt.Errorf("unable to connect container %s to network %s: %w", d.Name, dn.Name, err)
- }
- }
- return nil
-}
-
-// AddressInSubnet combines the subnet provided with the address and returns a
-// new address. The return address bits come from the subnet where the mask is
-// 1 and from the ip address where the mask is 0.
-func AddressInSubnet(addr net.IP, subnet net.IPNet) net.IP {
- var octets net.IP
- for i := 0; i < 4; i++ {
- octets = append(octets, (subnet.IP.To4()[i]&subnet.Mask[i])+(addr.To4()[i]&(^subnet.Mask[i])))
- }
- return octets
-}
-
-// devicesInfo will run "ip addr show" on the container and parse the output
-// to a map[string]netdevs.DeviceInfo.
-func devicesInfo(ctx context.Context, d *dockerutil.Container) (map[string]netdevs.DeviceInfo, error) {
- out, err := d.Exec(ctx, dockerutil.ExecOpts{}, "ip", "addr", "show")
- if err != nil {
- return map[string]netdevs.DeviceInfo{}, fmt.Errorf("listing devices on %s container: %w\n%s", d.Name, err, out)
- }
- devs, err := netdevs.ParseDevices(out)
- if err != nil {
- return map[string]netdevs.DeviceInfo{}, fmt.Errorf("parsing devices from %s container: %w\n%s", d.Name, err, out)
- }
- return devs, nil
-}
-
-// deviceByIP finds a deviceInfo and device name from an IP address.
-func deviceByIP(ctx context.Context, d *dockerutil.Container, ip net.IP) (string, netdevs.DeviceInfo, error) {
- devs, err := devicesInfo(ctx, d)
- if err != nil {
- return "", netdevs.DeviceInfo{}, err
- }
- testDevice, deviceInfo, err := netdevs.FindDeviceByIP(ip, devs)
- if err != nil {
- return "", netdevs.DeviceInfo{}, fmt.Errorf("can't find deviceInfo for container %s: %w", d.Name, err)
- }
- return testDevice, deviceInfo, nil
-}
-
-// getOrAssignIPv6Addr will try to get the IPv6 address for the interface; if an
-// address was not assigned, a link-local address based on MAC will be assigned
-// to that interface.
-func getOrAssignIPv6Addr(ctx context.Context, d *dockerutil.Container, iface string) (net.IP, error) {
- devs, err := devicesInfo(ctx, d)
- if err != nil {
- return net.IP{}, err
- }
- info := devs[iface]
- if info.IPv6Addr != nil {
- return info.IPv6Addr, nil
- }
- if info.MAC == nil {
- return nil, fmt.Errorf("unable to find MAC address of %s", iface)
- }
- if logs, err := d.Exec(ctx, dockerutil.ExecOpts{}, "ip", "addr", "add", netdevs.MACToIP(info.MAC).String(), "scope", "link", "dev", iface); err != nil {
- return net.IP{}, fmt.Errorf("unable to ip addr add on container %s: %w, logs: %s", d.Name, err, logs)
- }
- // Now try again, to make sure that it worked.
- devs, err = devicesInfo(ctx, d)
- if err != nil {
- return net.IP{}, err
- }
- info = devs[iface]
- if info.IPv6Addr == nil {
- return net.IP{}, fmt.Errorf("unable to set IPv6 address on container %s", d.Name)
- }
- return info.IPv6Addr, nil
-}
-
-// createDockerNetwork makes a randomly-named network that will start with the
-// namePrefix. The network will be a random /24 subnet.
-func createDockerNetwork(ctx context.Context, n *dockerutil.Network) error {
- randSource := rand.NewSource(time.Now().UnixNano())
- r1 := rand.New(randSource)
- // Class C, 192.0.0.0 to 223.255.255.255, transitionally has mask 24.
- ip := net.IPv4(byte(r1.Intn(224-192)+192), byte(r1.Intn(256)), byte(r1.Intn(256)), 0)
- n.Subnet = &net.IPNet{
- IP: ip,
- Mask: ip.DefaultMask(),
- }
- return n.Create(ctx)
-}
-
-// StartContainer will create a container instance from runOpts, connect it
-// with the specified docker networks and start executing the specified cmd.
-func StartContainer(ctx context.Context, runOpts dockerutil.RunOpts, c *dockerutil.Container, containerAddr net.IP, ns []*dockerutil.Network, sysctls map[string]string, cmd ...string) error {
- conf, hostconf, netconf := c.ConfigsFrom(runOpts, cmd...)
- _ = netconf
- hostconf.Sysctls = map[string]string{"net.ipv6.conf.all.disable_ipv6": "0"}
- for k, v := range sysctls {
- hostconf.Sysctls[k] = v
- }
-
- if err := c.CreateFrom(ctx, runOpts.Image, conf, hostconf, nil); err != nil {
- return fmt.Errorf("unable to create container %s: %w", c.Name, err)
- }
-
- if err := AddNetworks(ctx, c, containerAddr, ns); err != nil {
- return fmt.Errorf("unable to connect the container with the networks: %w", err)
- }
-
- if err := c.Start(ctx); err != nil {
- return fmt.Errorf("unable to start container %s: %w", c.Name, err)
- }
- return nil
-}
-
-// MountTempDirectory creates a temporary directory on host with the template
-// and then mounts it into the container under the name provided. The temporary
-// directory name is returned. Content in that directory will be copied to
-// TEST_UNDECLARED_OUTPUTS_DIR in cleanup phase.
-func MountTempDirectory(t *testing.T, runOpts *dockerutil.RunOpts, hostDirTemplate, containerDir string) (string, error) {
- t.Helper()
- tmpDir, err := ioutil.TempDir("", hostDirTemplate)
- if err != nil {
- return "", fmt.Errorf("failed to create a temp dir: %w", err)
- }
- t.Cleanup(func() {
- if err := exec.Command("/bin/cp", "-r", tmpDir, os.Getenv("TEST_UNDECLARED_OUTPUTS_DIR")).Run(); err != nil {
- t.Errorf("unable to copy container output files: %s", err)
- }
- if err := os.RemoveAll(tmpDir); err != nil {
- t.Errorf("failed to remove tmpDir %s: %s", tmpDir, err)
- }
- })
- runOpts.Mounts = append(runOpts.Mounts, mount.Mount{
- Type: mount.TypeBind,
- Source: tmpDir,
- Target: containerDir,
- ReadOnly: false,
- })
- return tmpDir, nil
-}
diff --git a/test/packetimpact/runner/packetimpact_test.go b/test/packetimpact/runner/packetimpact_test.go
deleted file mode 100644
index 46334b7ab..000000000
--- a/test/packetimpact/runner/packetimpact_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// The runner starts docker containers and networking for a packetimpact test.
-package packetimpact_test
-
-import (
- "context"
- "flag"
- "testing"
-
- "gvisor.dev/gvisor/test/packetimpact/runner"
-)
-
-func init() {
- runner.RegisterFlags(flag.CommandLine)
-}
-
-func TestOne(t *testing.T) {
- runner.TestWithDUT(context.Background(), t, runner.NewDockerDUT)
-}