summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/benchmarks/fs/BUILD11
-rw-r--r--test/benchmarks/fs/bazel_test.go30
-rw-r--r--test/benchmarks/fs/fio_test.go369
-rw-r--r--test/benchmarks/media/ffmpeg_test.go1
-rw-r--r--test/benchmarks/ml/BUILD21
-rw-r--r--test/benchmarks/ml/ml.go31
-rw-r--r--test/benchmarks/ml/tensorflow_test.go69
-rw-r--r--test/benchmarks/network/BUILD1
-rw-r--r--test/benchmarks/network/node_test.go261
-rw-r--r--test/e2e/integration_test.go32
-rw-r--r--test/iptables/BUILD1
-rw-r--r--test/iptables/filter_input.go145
-rw-r--r--test/iptables/filter_output.go122
-rw-r--r--test/iptables/iptables.go4
-rw-r--r--test/iptables/iptables_test.go29
-rw-r--r--test/iptables/iptables_util.go64
-rw-r--r--test/iptables/nat.go121
-rw-r--r--test/iptables/runner/main.go9
-rw-r--r--test/packetimpact/tests/BUILD13
-rw-r--r--test/packetimpact/tests/udp_any_addr_recv_unicast_test.go51
-rw-r--r--test/packetimpact/tests/udp_icmp_error_propagation_test.go8
-rw-r--r--test/packetimpact/tests/udp_recv_mcast_bcast_test.go16
-rw-r--r--test/packetimpact/tests/udp_send_recv_dgram_test.go6
-rw-r--r--test/runtimes/BUILD4
-rw-r--r--test/runtimes/exclude_go1.12.csv11
-rw-r--r--test/runtimes/exclude_nodejs12.4.0.csv1
-rw-r--r--test/runtimes/exclude_php7.3.6.csv2
-rw-r--r--test/runtimes/proctor/go.go4
-rw-r--r--test/syscalls/linux/epoll.cc22
-rw-r--r--test/syscalls/linux/fcntl.cc38
-rw-r--r--test/syscalls/linux/packet_socket.cc4
-rw-r--r--test/syscalls/linux/packet_socket_raw.cc4
-rw-r--r--test/syscalls/linux/socket_inet_loopback_nogotsan.cc5
33 files changed, 1230 insertions, 280 deletions
diff --git a/test/benchmarks/fs/BUILD b/test/benchmarks/fs/BUILD
index 2874cdbb3..79327b57c 100644
--- a/test/benchmarks/fs/BUILD
+++ b/test/benchmarks/fs/BUILD
@@ -12,12 +12,19 @@ go_library(
go_test(
name = "fs_test",
size = "large",
- srcs = ["bazel_test.go"],
+ srcs = [
+ "bazel_test.go",
+ "fio_test.go",
+ ],
library = ":fs",
tags = [
# Requires docker and runsc to be configured before test runs.
"local",
"manual",
],
- deps = ["//pkg/test/dockerutil"],
+ deps = [
+ "//pkg/test/dockerutil",
+ "//test/benchmarks/harness",
+ "@com_github_docker_docker//api/types/mount:go_default_library",
+ ],
)
diff --git a/test/benchmarks/fs/bazel_test.go b/test/benchmarks/fs/bazel_test.go
index 9b652fd43..f4236ba37 100644
--- a/test/benchmarks/fs/bazel_test.go
+++ b/test/benchmarks/fs/bazel_test.go
@@ -20,10 +20,22 @@ import (
"testing"
"gvisor.dev/gvisor/pkg/test/dockerutil"
+ "gvisor.dev/gvisor/test/benchmarks/harness"
)
// Note: CleanCache versions of this test require running with root permissions.
-func BenchmarkABSL(b *testing.B) {
+func BenchmarkBuildABSL(b *testing.B) {
+ runBuildBenchmark(b, "benchmarks/absl", "/abseil-cpp", "absl/base/...")
+}
+
+// Note: CleanCache versions of this test require running with root permissions.
+// Note: This test takes on the order of 10m per permutation for runsc on kvm.
+func BenchmarkBuildRunsc(b *testing.B) {
+ runBuildBenchmark(b, "benchmarks/runsc", "/gvisor", "runsc:runsc")
+}
+
+func runBuildBenchmark(b *testing.B, image, workdir, target string) {
+ b.Helper()
// Get a machine from the Harness on which to run.
machine, err := h.GetMachine()
if err != nil {
@@ -50,20 +62,18 @@ func BenchmarkABSL(b *testing.B) {
container := machine.GetContainer(ctx, b)
defer container.CleanUp(ctx)
- workdir := "/abseil-cpp"
-
// Start a container and sleep by an order of b.N.
if err := container.Spawn(ctx, dockerutil.RunOpts{
- Image: "benchmarks/absl",
+ Image: image,
}, "sleep", fmt.Sprintf("%d", 1000000)); err != nil {
b.Fatalf("run failed with: %v", err)
}
// If we are running on a tmpfs, copy to /tmp which is a tmpfs.
if bm.tmpfs {
- if _, err := container.Exec(ctx, dockerutil.ExecOpts{},
- "cp", "-r", "/abseil-cpp", "/tmp/."); err != nil {
- b.Fatal("failed to copy directory: %v", err)
+ if out, err := container.Exec(ctx, dockerutil.ExecOpts{},
+ "cp", "-r", workdir, "/tmp/."); err != nil {
+ b.Fatal("failed to copy directory: %v %s", err, out)
}
workdir = "/tmp" + workdir
}
@@ -77,15 +87,15 @@ func BenchmarkABSL(b *testing.B) {
b.StopTimer()
// Drop Caches for clear cache runs.
if bm.clearCache {
- if out, err := machine.RunCommand("/bin/sh", "-c", "sync && sysctl vm.drop_caches=3"); err != nil {
- b.Skipf("failed to drop caches: %v %s. You probably need root.", err, out)
+ if err := harness.DropCaches(machine); err != nil {
+ b.Skipf("failed to drop caches: %v. You probably need root.", err)
}
}
b.StartTimer()
got, err := container.Exec(ctx, dockerutil.ExecOpts{
WorkDir: workdir,
- }, "bazel", "build", "-c", "opt", "absl/base/...")
+ }, "bazel", "build", "-c", "opt", target)
if err != nil {
b.Fatalf("build failed with: %v", err)
}
diff --git a/test/benchmarks/fs/fio_test.go b/test/benchmarks/fs/fio_test.go
new file mode 100644
index 000000000..75d52726a
--- /dev/null
+++ b/test/benchmarks/fs/fio_test.go
@@ -0,0 +1,369 @@
+// 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 fs
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "testing"
+
+ "github.com/docker/docker/api/types/mount"
+ "gvisor.dev/gvisor/pkg/test/dockerutil"
+ "gvisor.dev/gvisor/test/benchmarks/harness"
+)
+
+type fioTestCase struct {
+ test string // test to run: read, write, randread, randwrite.
+ size string // total size to be read/written of format N[GMK] (e.g. 5G).
+ blocksize string // blocksize to be read/write of format N[GMK] (e.g. 4K).
+ iodepth int // iodepth for reads/writes.
+ time int // time to run the test in seconds, usually for rand(read/write).
+}
+
+// makeCmdFromTestcase makes a fio command.
+func (f *fioTestCase) makeCmdFromTestcase(filename string) []string {
+ cmd := []string{"fio", "--output-format=json", "--ioengine=sync"}
+ cmd = append(cmd, fmt.Sprintf("--name=%s", f.test))
+ cmd = append(cmd, fmt.Sprintf("--size=%s", f.size))
+ cmd = append(cmd, fmt.Sprintf("--blocksize=%s", f.blocksize))
+ cmd = append(cmd, fmt.Sprintf("--filename=%s", filename))
+ cmd = append(cmd, fmt.Sprintf("--iodepth=%d", f.iodepth))
+ cmd = append(cmd, fmt.Sprintf("--rw=%s", f.test))
+ if f.time != 0 {
+ cmd = append(cmd, "--time_based")
+ cmd = append(cmd, fmt.Sprintf("--runtime=%d", f.time))
+ }
+ return cmd
+}
+
+// BenchmarkFio runs fio on the runtime under test. There are 4 basic test
+// cases each run on a tmpfs mount and a bind mount. Fio requires root so that
+// caches can be dropped.
+func BenchmarkFio(b *testing.B) {
+ testCases := []fioTestCase{
+ fioTestCase{
+ test: "write",
+ size: "5G",
+ blocksize: "1M",
+ iodepth: 4,
+ },
+ fioTestCase{
+ test: "read",
+ size: "5G",
+ blocksize: "1M",
+ iodepth: 4,
+ },
+ fioTestCase{
+ test: "randwrite",
+ size: "5G",
+ blocksize: "4K",
+ iodepth: 4,
+ time: 30,
+ },
+ fioTestCase{
+ test: "randread",
+ size: "5G",
+ blocksize: "4K",
+ iodepth: 4,
+ time: 30,
+ },
+ }
+
+ machine, err := h.GetMachine()
+ if err != nil {
+ b.Fatalf("failed to get machine with: %v", err)
+ }
+ defer machine.CleanUp()
+
+ for _, fsType := range []mount.Type{mount.TypeBind, mount.TypeTmpfs} {
+ for _, tc := range testCases {
+ testName := strings.Title(tc.test) + strings.Title(string(fsType))
+ b.Run(testName, func(b *testing.B) {
+ ctx := context.Background()
+ container := machine.GetContainer(ctx, b)
+ defer container.CleanUp(ctx)
+
+ // Directory and filename inside container where fio will read/write.
+ outdir := "/data"
+ outfile := filepath.Join(outdir, "test.txt")
+
+ // Make the required mount and grab a cleanup for bind mounts
+ // as they are backed by a temp directory (mktemp).
+ mnt, mountCleanup, err := makeMount(machine, fsType, outdir)
+ if err != nil {
+ b.Fatalf("failed to make mount: %v", err)
+ }
+ defer mountCleanup()
+ cmd := tc.makeCmdFromTestcase(outfile)
+
+ // Start the container with the mount.
+ if err := container.Spawn(
+ ctx,
+ dockerutil.RunOpts{
+ Image: "benchmarks/fio",
+ Mounts: []mount.Mount{
+ mnt,
+ },
+ },
+ // Sleep on the order of b.N.
+ "sleep", fmt.Sprintf("%d", 1000*b.N),
+ ); err != nil {
+ b.Fatalf("failed to start fio container with: %v", err)
+ }
+
+ // For reads, we need a file to read so make one inside the container.
+ if strings.Contains(tc.test, "read") {
+ fallocateCmd := fmt.Sprintf("fallocate -l %s %s", tc.size, outfile)
+ if out, err := container.Exec(ctx, dockerutil.ExecOpts{},
+ strings.Split(fallocateCmd, " ")...); err != nil {
+ b.Fatalf("failed to create readable file on mount: %v, %s", err, out)
+ }
+ }
+
+ // Drop caches just before running.
+ if err := harness.DropCaches(machine); err != nil {
+ b.Skipf("failed to drop caches with %v. You probably need root.", err)
+ }
+ container.RestartProfiles()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ // Run fio.
+ data, err := container.Exec(ctx, dockerutil.ExecOpts{}, cmd...)
+ if err != nil {
+ b.Fatalf("failed to run cmd %v: %v", cmd, err)
+ }
+ b.StopTimer()
+ // Parse the output and report the metrics.
+ isRead := strings.Contains(tc.test, "read")
+ bw, err := parseBandwidth(data, isRead)
+ if err != nil {
+ b.Fatalf("failed to parse bandwidth from %s with: %v", data, err)
+ }
+ b.ReportMetric(bw, "bandwidth") // in b/s.
+
+ iops, err := parseIOps(data, isRead)
+ if err != nil {
+ b.Fatalf("failed to parse iops from %s with: %v", data, err)
+ }
+ b.ReportMetric(iops, "iops")
+ // If b.N is used (i.e. we run for an hour), we should drop caches
+ // after each run.
+ if err := harness.DropCaches(machine); err != nil {
+ b.Fatalf("failed to drop caches: %v", err)
+ }
+ b.StartTimer()
+ }
+ })
+ }
+ }
+}
+
+// makeMount makes a mount and cleanup based on the requested type. Bind
+// and volume mounts are backed by a temp directory made with mktemp.
+// tmpfs mounts require no such backing and are just made.
+// It is up to the caller to call the returned cleanup.
+func makeMount(machine harness.Machine, mountType mount.Type, target string) (mount.Mount, func(), error) {
+ switch mountType {
+ case mount.TypeVolume, mount.TypeBind:
+ dir, err := machine.RunCommand("mktemp", "-d")
+ if err != nil {
+ return mount.Mount{}, func() {}, fmt.Errorf("failed to create tempdir: %v", err)
+ }
+ dir = strings.TrimSuffix(dir, "\n")
+
+ out, err := machine.RunCommand("chmod", "777", dir)
+ if err != nil {
+ machine.RunCommand("rm", "-rf", dir)
+ return mount.Mount{}, func() {}, fmt.Errorf("failed modify directory: %v %s", err, out)
+ }
+ return mount.Mount{
+ Target: target,
+ Source: dir,
+ Type: mount.TypeBind,
+ }, func() { machine.RunCommand("rm", "-rf", dir) }, nil
+ case mount.TypeTmpfs:
+ return mount.Mount{
+ Target: target,
+ Type: mount.TypeTmpfs,
+ }, func() {}, nil
+ default:
+ return mount.Mount{}, func() {}, fmt.Errorf("illegal mount time not supported: %v", mountType)
+ }
+}
+
+// parseBandwidth reports the bandwidth in b/s.
+func parseBandwidth(data string, isRead bool) (float64, error) {
+ if isRead {
+ result, err := parseFioJSON(data, "read", "bw")
+ if err != nil {
+ return 0, err
+ }
+ return 1024 * result, nil
+ }
+ result, err := parseFioJSON(data, "write", "bw")
+ if err != nil {
+ return 0, err
+ }
+ return 1024 * result, nil
+}
+
+// parseIOps reports the write IO per second metric.
+func parseIOps(data string, isRead bool) (float64, error) {
+ if isRead {
+ return parseFioJSON(data, "read", "iops")
+ }
+ return parseFioJSON(data, "write", "iops")
+}
+
+// fioResult is for parsing FioJSON.
+type fioResult struct {
+ Jobs []fioJob
+}
+
+// fioJob is for parsing FioJSON.
+type fioJob map[string]json.RawMessage
+
+// fioMetrics is for parsing FioJSON.
+type fioMetrics map[string]json.RawMessage
+
+// parseFioJSON parses data and grabs "op" (read or write) and "metric"
+// (bw or iops) from the JSON.
+func parseFioJSON(data, op, metric string) (float64, error) {
+ var result fioResult
+ if err := json.Unmarshal([]byte(data), &result); err != nil {
+ return 0, fmt.Errorf("could not unmarshal data: %v", err)
+ }
+
+ if len(result.Jobs) < 1 {
+ return 0, fmt.Errorf("no jobs present to parse")
+ }
+
+ var metrics fioMetrics
+ if err := json.Unmarshal(result.Jobs[0][op], &metrics); err != nil {
+ return 0, fmt.Errorf("could not unmarshal jobs: %v", err)
+ }
+
+ if _, ok := metrics[metric]; !ok {
+ return 0, fmt.Errorf("no metric found for op: %s", op)
+ }
+ return strconv.ParseFloat(string(metrics[metric]), 64)
+}
+
+// TestParsers tests that the parsers work on sampleData.
+func TestParsers(t *testing.T) {
+ sampleData := `
+{
+ "fio version" : "fio-3.1",
+ "timestamp" : 1554837456,
+ "timestamp_ms" : 1554837456621,
+ "time" : "Tue Apr 9 19:17:36 2019",
+ "jobs" : [
+ {
+ "jobname" : "test",
+ "groupid" : 0,
+ "error" : 0,
+ "eta" : 2147483647,
+ "elapsed" : 1,
+ "job options" : {
+ "name" : "test",
+ "ioengine" : "sync",
+ "size" : "1073741824",
+ "filename" : "/disk/file.dat",
+ "iodepth" : "4",
+ "bs" : "4096",
+ "rw" : "write"
+ },
+ "read" : {
+ "io_bytes" : 0,
+ "io_kbytes" : 0,
+ "bw" : 123456,
+ "iops" : 1234.5678,
+ "runtime" : 0,
+ "total_ios" : 0,
+ "short_ios" : 0,
+ "bw_min" : 0,
+ "bw_max" : 0,
+ "bw_agg" : 0.000000,
+ "bw_mean" : 0.000000,
+ "bw_dev" : 0.000000,
+ "bw_samples" : 0,
+ "iops_min" : 0,
+ "iops_max" : 0,
+ "iops_mean" : 0.000000,
+ "iops_stddev" : 0.000000,
+ "iops_samples" : 0
+ },
+ "write" : {
+ "io_bytes" : 1073741824,
+ "io_kbytes" : 1048576,
+ "bw" : 1753471,
+ "iops" : 438367.892977,
+ "runtime" : 598,
+ "total_ios" : 262144,
+ "bw_min" : 1731120,
+ "bw_max" : 1731120,
+ "bw_agg" : 98.725328,
+ "bw_mean" : 1731120.000000,
+ "bw_dev" : 0.000000,
+ "bw_samples" : 1,
+ "iops_min" : 432780,
+ "iops_max" : 432780,
+ "iops_mean" : 432780.000000,
+ "iops_stddev" : 0.000000,
+ "iops_samples" : 1
+ }
+ }
+ ]
+}
+`
+ // WriteBandwidth.
+ got, err := parseBandwidth(sampleData, false)
+ var want float64 = 1753471.0 * 1024
+ if err != nil {
+ t.Fatalf("parse failed with err: %v", err)
+ } else if got != want {
+ t.Fatalf("got: %f, want: %f", got, want)
+ }
+
+ // ReadBandwidth.
+ got, err = parseBandwidth(sampleData, true)
+ want = 123456 * 1024
+ if err != nil {
+ t.Fatalf("parse failed with err: %v", err)
+ } else if got != want {
+ t.Fatalf("got: %f, want: %f", got, want)
+ }
+
+ // WriteIOps.
+ got, err = parseIOps(sampleData, false)
+ want = 438367.892977
+ if err != nil {
+ t.Fatalf("parse failed with err: %v", err)
+ } else if got != want {
+ t.Fatalf("got: %f, want: %f", got, want)
+ }
+
+ // ReadIOps.
+ got, err = parseIOps(sampleData, true)
+ want = 1234.5678
+ if err != nil {
+ t.Fatalf("parse failed with err: %v", err)
+ } else if got != want {
+ t.Fatalf("got: %f, want: %f", got, want)
+ }
+}
diff --git a/test/benchmarks/media/ffmpeg_test.go b/test/benchmarks/media/ffmpeg_test.go
index bfcfbab80..7822dfad7 100644
--- a/test/benchmarks/media/ffmpeg_test.go
+++ b/test/benchmarks/media/ffmpeg_test.go
@@ -33,6 +33,7 @@ func BenchmarkFfmpeg(b *testing.B) {
ctx := context.Background()
container := machine.GetContainer(ctx, b)
+ defer container.CleanUp(ctx)
cmd := strings.Split("ffmpeg -i video.mp4 -c:v libx264 -preset veryslow output.mp4", " ")
b.ResetTimer()
diff --git a/test/benchmarks/ml/BUILD b/test/benchmarks/ml/BUILD
new file mode 100644
index 000000000..2430b60a7
--- /dev/null
+++ b/test/benchmarks/ml/BUILD
@@ -0,0 +1,21 @@
+load("//tools:defs.bzl", "go_library", "go_test")
+
+package(licenses = ["notice"])
+
+go_library(
+ name = "ml",
+ testonly = 1,
+ srcs = ["ml.go"],
+ deps = ["//test/benchmarks/harness"],
+)
+
+go_test(
+ name = "ml_test",
+ size = "large",
+ srcs = ["tensorflow_test.go"],
+ library = ":ml",
+ deps = [
+ "//pkg/test/dockerutil",
+ "//test/benchmarks/harness",
+ ],
+)
diff --git a/test/benchmarks/ml/ml.go b/test/benchmarks/ml/ml.go
new file mode 100644
index 000000000..13282d7bb
--- /dev/null
+++ b/test/benchmarks/ml/ml.go
@@ -0,0 +1,31 @@
+// 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 ml holds benchmarks around machine learning performance.
+package ml
+
+import (
+ "os"
+ "testing"
+
+ "gvisor.dev/gvisor/test/benchmarks/harness"
+)
+
+var h harness.Harness
+
+// TestMain is the main method for package ml.
+func TestMain(m *testing.M) {
+ h.Init()
+ os.Exit(m.Run())
+}
diff --git a/test/benchmarks/ml/tensorflow_test.go b/test/benchmarks/ml/tensorflow_test.go
new file mode 100644
index 000000000..f7746897d
--- /dev/null
+++ b/test/benchmarks/ml/tensorflow_test.go
@@ -0,0 +1,69 @@
+// 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 ml
+
+import (
+ "context"
+ "testing"
+
+ "gvisor.dev/gvisor/pkg/test/dockerutil"
+ "gvisor.dev/gvisor/test/benchmarks/harness"
+)
+
+// BenchmarkTensorflow runs workloads from a TensorFlow tutorial.
+// See: https://github.com/aymericdamien/TensorFlow-Examples
+func BenchmarkTensorflow(b *testing.B) {
+ workloads := map[string]string{
+ "GradientDecisionTree": "2_BasicModels/gradient_boosted_decision_tree.py",
+ "Kmeans": "2_BasicModels/kmeans.py",
+ "LogisticRegression": "2_BasicModels/logistic_regression.py",
+ "NearestNeighbor": "2_BasicModels/nearest_neighbor.py",
+ "RandomForest": "2_BasicModels/random_forest.py",
+ "ConvolutionalNetwork": "3_NeuralNetworks/convolutional_network.py",
+ "MultilayerPerceptron": "3_NeuralNetworks/multilayer_perceptron.py",
+ "NeuralNetwork": "3_NeuralNetworks/neural_network.py",
+ }
+
+ machine, err := h.GetMachine()
+ if err != nil {
+ b.Fatalf("failed to get machine: %v", err)
+ }
+ defer machine.CleanUp()
+
+ for name, workload := range workloads {
+ b.Run(name, func(b *testing.B) {
+ ctx := context.Background()
+ container := machine.GetContainer(ctx, b)
+ defer container.CleanUp(ctx)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ b.StopTimer()
+ if err := harness.DropCaches(machine); err != nil {
+ b.Skipf("failed to drop caches: %v. You probably need root.", err)
+ }
+ b.StartTimer()
+
+ if out, err := container.Run(ctx, dockerutil.RunOpts{
+ Image: "benchmarks/tensorflow",
+ Env: []string{"PYTHONPATH=$PYTHONPATH:/TensorFlow-Examples/examples"},
+ WorkDir: "/TensorFlow-Examples/examples",
+ }, "python", workload); err != nil {
+ b.Fatalf("failed to run container: %v logs: %s", err, out)
+ }
+ }
+ })
+ }
+
+}
diff --git a/test/benchmarks/network/BUILD b/test/benchmarks/network/BUILD
index 363041fb7..b47400590 100644
--- a/test/benchmarks/network/BUILD
+++ b/test/benchmarks/network/BUILD
@@ -15,6 +15,7 @@ go_test(
srcs = [
"httpd_test.go",
"iperf_test.go",
+ "node_test.go",
],
library = ":network",
tags = [
diff --git a/test/benchmarks/network/node_test.go b/test/benchmarks/network/node_test.go
new file mode 100644
index 000000000..f9278ab66
--- /dev/null
+++ b/test/benchmarks/network/node_test.go
@@ -0,0 +1,261 @@
+// 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 network
+
+import (
+ "context"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+
+ "gvisor.dev/gvisor/pkg/test/dockerutil"
+ "gvisor.dev/gvisor/test/benchmarks/harness"
+)
+
+// BenchmarkNode runs 10K requests using 'hey' against a Node server run on
+// 'runtime'. The server responds to requests by grabbing some data in a
+// redis instance and returns the data in its reponse. The test loops through
+// increasing amounts of concurency for requests.
+func BenchmarkNode(b *testing.B) {
+ requests := 10000
+ concurrency := []int{1, 5, 10, 25}
+
+ for _, c := range concurrency {
+ b.Run(fmt.Sprintf("Concurrency%d", c), func(b *testing.B) {
+ runNode(b, requests, c)
+ })
+ }
+}
+
+// runNode runs the test for a given # of requests and concurrency.
+func runNode(b *testing.B, requests, concurrency int) {
+ b.Helper()
+
+ // The machine to hold Redis and the Node Server.
+ serverMachine, err := h.GetMachine()
+ if err != nil {
+ b.Fatal("failed to get machine with: %v", err)
+ }
+ defer serverMachine.CleanUp()
+
+ // The machine to run 'hey'.
+ clientMachine, err := h.GetMachine()
+ if err != nil {
+ b.Fatal("failed to get machine with: %v", err)
+ }
+ defer clientMachine.CleanUp()
+
+ ctx := context.Background()
+
+ // Spawn a redis instance for the app to use.
+ redis := serverMachine.GetNativeContainer(ctx, b)
+ if err := redis.Spawn(ctx, dockerutil.RunOpts{
+ Image: "benchmarks/redis",
+ }); err != nil {
+ b.Fatalf("failed to spwan redis instance: %v", err)
+ }
+ defer redis.CleanUp(ctx)
+
+ if out, err := redis.WaitForOutput(ctx, "Ready to accept connections", 3*time.Second); err != nil {
+ b.Fatalf("failed to start redis server: %v %s", err, out)
+ }
+ redisIP, err := redis.FindIP(ctx, false)
+ if err != nil {
+ b.Fatalf("failed to get IP from redis instance: %v", err)
+ }
+
+ // Node runs on port 8080.
+ port := 8080
+
+ // Start-up the Node server.
+ nodeApp := serverMachine.GetContainer(ctx, b)
+ if err := nodeApp.Spawn(ctx, dockerutil.RunOpts{
+ Image: "benchmarks/node",
+ WorkDir: "/usr/src/app",
+ Links: []string{redis.MakeLink("redis")},
+ Ports: []int{port},
+ }, "node", "index.js", redisIP.String()); err != nil {
+ b.Fatalf("failed to spawn node instance: %v", err)
+ }
+ defer nodeApp.CleanUp(ctx)
+
+ servingIP, err := serverMachine.IPAddress()
+ if err != nil {
+ b.Fatalf("failed to get ip from server: %v", err)
+ }
+
+ servingPort, err := nodeApp.FindPort(ctx, port)
+ if err != nil {
+ b.Fatalf("failed to port from node instance: %v", err)
+ }
+
+ // Wait until the Client sees the server as up.
+ harness.WaitUntilServing(ctx, clientMachine, servingIP, servingPort)
+
+ heyCmd := strings.Split(fmt.Sprintf("hey -n %d -c %d http://%s:%d/", requests, concurrency, servingIP, servingPort), " ")
+
+ nodeApp.RestartProfiles()
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ // the client should run on Native.
+ client := clientMachine.GetNativeContainer(ctx, b)
+ out, err := client.Run(ctx, dockerutil.RunOpts{
+ Image: "benchmarks/hey",
+ }, heyCmd...)
+ if err != nil {
+ b.Fatalf("hey container failed: %v logs: %s", err, out)
+ }
+
+ // Stop the timer to parse the data and report stats.
+ b.StopTimer()
+ requests, err := parseHeyRequestsPerSecond(out)
+ if err != nil {
+ b.Fatalf("failed to parse requests per second: %v", err)
+ }
+ b.ReportMetric(requests, "requests_per_second")
+
+ bw, err := parseHeyBandwidth(out)
+ if err != nil {
+ b.Fatalf("failed to parse bandwidth: %v", err)
+ }
+ b.ReportMetric(bw, "bandwidth")
+
+ ave, err := parseHeyAverageLatency(out)
+ if err != nil {
+ b.Fatalf("failed to parse average latency: %v", err)
+ }
+ b.ReportMetric(ave, "average_latency")
+ b.StartTimer()
+ }
+}
+
+var heyReqPerSecondRE = regexp.MustCompile(`Requests/sec:\s*(\d+\.?\d+?)\s+`)
+
+// parseHeyRequestsPerSecond finds requests per second from hey output.
+func parseHeyRequestsPerSecond(data string) (float64, error) {
+ match := heyReqPerSecondRE.FindStringSubmatch(data)
+ if len(match) < 2 {
+ return 0, fmt.Errorf("failed get bandwidth: %s", data)
+ }
+ return strconv.ParseFloat(match[1], 64)
+}
+
+var heyAverageLatencyRE = regexp.MustCompile(`Average:\s*(\d+\.?\d+?)\s+secs`)
+
+// parseHeyAverageLatency finds Average Latency in seconds form hey output.
+func parseHeyAverageLatency(data string) (float64, error) {
+ match := heyAverageLatencyRE.FindStringSubmatch(data)
+ if len(match) < 2 {
+ return 0, fmt.Errorf("failed get average latency match%d : %s", len(match), data)
+ }
+ return strconv.ParseFloat(match[1], 64)
+}
+
+var heySizePerRequestRE = regexp.MustCompile(`Size/request:\s*(\d+\.?\d+?)\s+bytes`)
+
+// parseHeyBandwidth computes bandwidth from request/sec * bytes/request
+// and reports in bytes/second.
+func parseHeyBandwidth(data string) (float64, error) {
+ match := heyReqPerSecondRE.FindStringSubmatch(data)
+ if len(match) < 2 {
+ return 0, fmt.Errorf("failed get requests per second: %s", data)
+ }
+ reqPerSecond, err := strconv.ParseFloat(match[1], 64)
+ if err != nil {
+ return 0, fmt.Errorf("failed to convert %s to float", match[1])
+ }
+
+ match = heySizePerRequestRE.FindStringSubmatch(data)
+ if len(match) < 2 {
+ return 0, fmt.Errorf("failed get average latency: %s", data)
+ }
+ requestSize, err := strconv.ParseFloat(match[1], 64)
+ return requestSize * reqPerSecond, err
+}
+
+// TestHeyParsers tests that the parsers work with sample output.
+func TestHeyParsers(t *testing.T) {
+ sampleData := `
+ Summary:
+ Total: 2.2391 secs
+ Slowest: 1.6292 secs
+ Fastest: 0.0066 secs
+ Average: 0.5351 secs
+ Requests/sec: 89.3202
+
+ Total data: 841200 bytes
+ Size/request: 4206 bytes
+
+ Response time histogram:
+ 0.007 [1] |
+ 0.169 [0] |
+ 0.331 [149] |â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– 
+ 0.493 [0] |
+ 0.656 [0] |
+ 0.818 [0] |
+ 0.980 [0] |
+ 1.142 [0] |
+ 1.305 [0] |
+ 1.467 [49] |â– â– â– â– â– â– â– â– â– â– â– â– â– 
+ 1.629 [1] |
+
+
+ Latency distribution:
+ 10% in 0.2149 secs
+ 25% in 0.2449 secs
+ 50% in 0.2703 secs
+ 75% in 1.3315 secs
+ 90% in 1.4045 secs
+ 95% in 1.4232 secs
+ 99% in 1.4362 secs
+
+ Details (average, fastest, slowest):
+ DNS+dialup: 0.0002 secs, 0.0066 secs, 1.6292 secs
+ DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0000 secs
+ req write: 0.0000 secs, 0.0000 secs, 0.0012 secs
+ resp wait: 0.5225 secs, 0.0064 secs, 1.4346 secs
+ resp read: 0.0122 secs, 0.0001 secs, 0.2006 secs
+
+ Status code distribution:
+ [200] 200 responses
+ `
+ want := 89.3202
+ got, err := parseHeyRequestsPerSecond(sampleData)
+ if err != nil {
+ t.Fatalf("failed to parse request per second with: %v", err)
+ } else if got != want {
+ t.Fatalf("got: %f, want: %f", got, want)
+ }
+
+ want = 89.3202 * 4206
+ got, err = parseHeyBandwidth(sampleData)
+ if err != nil {
+ t.Fatalf("failed to parse bandwidth with: %v", err)
+ } else if got != want {
+ t.Fatalf("got: %f, want: %f", got, want)
+ }
+
+ want = 0.5351
+ got, err = parseHeyAverageLatency(sampleData)
+ if err != nil {
+ t.Fatalf("failed to parse average latency with: %v", err)
+ } else if got != want {
+ t.Fatalf("got: %f, want: %f", got, want)
+ }
+
+}
diff --git a/test/e2e/integration_test.go b/test/e2e/integration_test.go
index ef42b689a..6fe6d304f 100644
--- a/test/e2e/integration_test.go
+++ b/test/e2e/integration_test.go
@@ -431,11 +431,39 @@ func TestHostOverlayfsCopyUp(t *testing.T) {
d := dockerutil.MakeContainer(ctx, t)
defer d.CleanUp(ctx)
- if _, err := d.Run(ctx, dockerutil.RunOpts{
+ if got, err := d.Run(ctx, dockerutil.RunOpts{
Image: "basic/hostoverlaytest",
WorkDir: "/root",
- }, "./test"); err != nil {
+ }, "./test_copy_up"); err != nil {
t.Fatalf("docker run failed: %v", err)
+ } else if got != "" {
+ t.Errorf("test failed:\n%s", got)
+ }
+}
+
+// TestHostOverlayfsRewindDir tests that rewinddir() "causes the directory
+// stream to refer to the current state of the corresponding directory, as a
+// call to opendir() would have done" as required by POSIX, when the directory
+// in question is host overlayfs.
+//
+// This test specifically targets host overlayfs because, per POSIX, "if a file
+// is removed from or added to the directory after the most recent call to
+// opendir() or rewinddir(), whether a subsequent call to readdir() returns an
+// entry for that file is unspecified"; the host filesystems used by other
+// automated tests yield newly-added files from readdir() even if the fsgofer
+// does not explicitly rewinddir(), but overlayfs does not.
+func TestHostOverlayfsRewindDir(t *testing.T) {
+ ctx := context.Background()
+ d := dockerutil.MakeContainer(ctx, t)
+ defer d.CleanUp(ctx)
+
+ if got, err := d.Run(ctx, dockerutil.RunOpts{
+ Image: "basic/hostoverlaytest",
+ WorkDir: "/root",
+ }, "./test_rewinddir"); err != nil {
+ t.Fatalf("docker run failed: %v", err)
+ } else if got != "" {
+ t.Errorf("test failed:\n%s", got)
}
}
diff --git a/test/iptables/BUILD b/test/iptables/BUILD
index 3e29ca90d..40b63ebbe 100644
--- a/test/iptables/BUILD
+++ b/test/iptables/BUILD
@@ -20,6 +20,7 @@ go_library(
go_test(
name = "iptables_test",
+ size = "large",
srcs = [
"iptables_test.go",
],
diff --git a/test/iptables/filter_input.go b/test/iptables/filter_input.go
index af4355ba8..5737ee317 100644
--- a/test/iptables/filter_input.go
+++ b/test/iptables/filter_input.go
@@ -25,7 +25,6 @@ const (
dropPort = 2401
acceptPort = 2402
sendloopDuration = 2 * time.Second
- network = "udp4"
chainName = "foochain"
)
@@ -62,8 +61,8 @@ func (FilterInputDropUDP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDropUDP) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-p", "udp", "-j", "DROP"); err != nil {
+func (FilterInputDropUDP) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-p", "udp", "-j", "DROP"); err != nil {
return err
}
@@ -80,7 +79,7 @@ func (FilterInputDropUDP) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDropUDP) LocalAction(ip net.IP) error {
+func (FilterInputDropUDP) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, dropPort, sendloopDuration)
}
@@ -93,8 +92,8 @@ func (FilterInputDropOnlyUDP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDropOnlyUDP) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-p", "udp", "-j", "DROP"); err != nil {
+func (FilterInputDropOnlyUDP) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-p", "udp", "-j", "DROP"); err != nil {
return err
}
@@ -107,7 +106,7 @@ func (FilterInputDropOnlyUDP) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDropOnlyUDP) LocalAction(ip net.IP) error {
+func (FilterInputDropOnlyUDP) LocalAction(ip net.IP, ipv6 bool) error {
// Try to establish a TCP connection with the container, which should
// succeed.
return connectTCP(ip, acceptPort, sendloopDuration)
@@ -122,8 +121,8 @@ func (FilterInputDropUDPPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDropUDPPort) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-p", "udp", "-m", "udp", "--destination-port", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
+func (FilterInputDropUDPPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-p", "udp", "-m", "udp", "--destination-port", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
return err
}
@@ -140,7 +139,7 @@ func (FilterInputDropUDPPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDropUDPPort) LocalAction(ip net.IP) error {
+func (FilterInputDropUDPPort) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, dropPort, sendloopDuration)
}
@@ -154,8 +153,8 @@ func (FilterInputDropDifferentUDPPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDropDifferentUDPPort) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-p", "udp", "-m", "udp", "--destination-port", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
+func (FilterInputDropDifferentUDPPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-p", "udp", "-m", "udp", "--destination-port", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
return err
}
@@ -168,7 +167,7 @@ func (FilterInputDropDifferentUDPPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDropDifferentUDPPort) LocalAction(ip net.IP) error {
+func (FilterInputDropDifferentUDPPort) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -181,8 +180,8 @@ func (FilterInputDropTCPDestPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDropTCPDestPort) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
+func (FilterInputDropTCPDestPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
return err
}
@@ -195,7 +194,7 @@ func (FilterInputDropTCPDestPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDropTCPDestPort) LocalAction(ip net.IP) error {
+func (FilterInputDropTCPDestPort) LocalAction(ip net.IP, ipv6 bool) error {
// Ensure we cannot connect to the container.
for start := time.Now(); time.Since(start) < sendloopDuration; {
if err := connectTCP(ip, dropPort, sendloopDuration-time.Since(start)); err == nil {
@@ -215,9 +214,9 @@ func (FilterInputDropTCPSrcPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDropTCPSrcPort) ContainerAction(ip net.IP) error {
+func (FilterInputDropTCPSrcPort) ContainerAction(ip net.IP, ipv6 bool) error {
// Drop anything from an ephemeral port.
- if err := filterTable("-A", "INPUT", "-p", "tcp", "-m", "tcp", "--sport", "1024:65535", "-j", "DROP"); err != nil {
+ if err := filterTable(ipv6, "-A", "INPUT", "-p", "tcp", "-m", "tcp", "--sport", "1024:65535", "-j", "DROP"); err != nil {
return err
}
@@ -230,7 +229,7 @@ func (FilterInputDropTCPSrcPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDropTCPSrcPort) LocalAction(ip net.IP) error {
+func (FilterInputDropTCPSrcPort) LocalAction(ip net.IP, ipv6 bool) error {
// Ensure we cannot connect to the container.
for start := time.Now(); time.Since(start) < sendloopDuration; {
if err := connectTCP(ip, acceptPort, sendloopDuration-time.Since(start)); err == nil {
@@ -250,8 +249,8 @@ func (FilterInputDropAll) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDropAll) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-j", "DROP"); err != nil {
+func (FilterInputDropAll) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-j", "DROP"); err != nil {
return err
}
@@ -268,7 +267,7 @@ func (FilterInputDropAll) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDropAll) LocalAction(ip net.IP) error {
+func (FilterInputDropAll) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, dropPort, sendloopDuration)
}
@@ -284,17 +283,17 @@ func (FilterInputMultiUDPRules) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputMultiUDPRules) ContainerAction(ip net.IP) error {
+func (FilterInputMultiUDPRules) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-A", "INPUT", "-p", "udp", "-m", "udp", "--destination-port", fmt.Sprintf("%d", dropPort), "-j", "DROP"},
{"-A", "INPUT", "-p", "udp", "-m", "udp", "--destination-port", fmt.Sprintf("%d", acceptPort), "-j", "ACCEPT"},
{"-L"},
}
- return filterTableRules(rules)
+ return filterTableRules(ipv6, rules)
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputMultiUDPRules) LocalAction(ip net.IP) error {
+func (FilterInputMultiUDPRules) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -309,14 +308,14 @@ func (FilterInputRequireProtocolUDP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputRequireProtocolUDP) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-m", "udp", "--destination-port", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err == nil {
+func (FilterInputRequireProtocolUDP) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-m", "udp", "--destination-port", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err == nil {
return errors.New("expected iptables to fail with out \"-p udp\", but succeeded")
}
return nil
}
-func (FilterInputRequireProtocolUDP) LocalAction(ip net.IP) error {
+func (FilterInputRequireProtocolUDP) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -330,18 +329,18 @@ func (FilterInputCreateUserChain) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputCreateUserChain) ContainerAction(ip net.IP) error {
+func (FilterInputCreateUserChain) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
// Create a chain.
{"-N", chainName},
// Add a simple rule to the chain.
{"-A", chainName, "-j", "DROP"},
}
- return filterTableRules(rules)
+ return filterTableRules(ipv6, rules)
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputCreateUserChain) LocalAction(ip net.IP) error {
+func (FilterInputCreateUserChain) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -355,16 +354,16 @@ func (FilterInputDefaultPolicyAccept) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDefaultPolicyAccept) ContainerAction(ip net.IP) error {
+func (FilterInputDefaultPolicyAccept) ContainerAction(ip net.IP, ipv6 bool) error {
// Set the default policy to accept, then receive a packet.
- if err := filterTable("-P", "INPUT", "ACCEPT"); err != nil {
+ if err := filterTable(ipv6, "-P", "INPUT", "ACCEPT"); err != nil {
return err
}
return listenUDP(acceptPort, sendloopDuration)
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDefaultPolicyAccept) LocalAction(ip net.IP) error {
+func (FilterInputDefaultPolicyAccept) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -377,8 +376,8 @@ func (FilterInputDefaultPolicyDrop) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDefaultPolicyDrop) ContainerAction(ip net.IP) error {
- if err := filterTable("-P", "INPUT", "DROP"); err != nil {
+func (FilterInputDefaultPolicyDrop) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-P", "INPUT", "DROP"); err != nil {
return err
}
@@ -395,7 +394,7 @@ func (FilterInputDefaultPolicyDrop) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDefaultPolicyDrop) LocalAction(ip net.IP) error {
+func (FilterInputDefaultPolicyDrop) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -409,7 +408,7 @@ func (FilterInputReturnUnderflow) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputReturnUnderflow) ContainerAction(ip net.IP) error {
+func (FilterInputReturnUnderflow) ContainerAction(ip net.IP, ipv6 bool) error {
// Add a RETURN rule followed by an unconditional accept, and set the
// default policy to DROP.
rules := [][]string{
@@ -417,7 +416,7 @@ func (FilterInputReturnUnderflow) ContainerAction(ip net.IP) error {
{"-A", "INPUT", "-j", "DROP"},
{"-P", "INPUT", "ACCEPT"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -427,7 +426,7 @@ func (FilterInputReturnUnderflow) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputReturnUnderflow) LocalAction(ip net.IP) error {
+func (FilterInputReturnUnderflow) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -440,18 +439,18 @@ func (FilterInputSerializeJump) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputSerializeJump) ContainerAction(ip net.IP) error {
+func (FilterInputSerializeJump) ContainerAction(ip net.IP, ipv6 bool) error {
// Write a JUMP rule, the serialize it with `-L`.
rules := [][]string{
{"-N", chainName},
{"-A", "INPUT", "-j", chainName},
{"-L"},
}
- return filterTableRules(rules)
+ return filterTableRules(ipv6, rules)
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputSerializeJump) LocalAction(ip net.IP) error {
+func (FilterInputSerializeJump) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -465,14 +464,14 @@ func (FilterInputJumpBasic) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputJumpBasic) ContainerAction(ip net.IP) error {
+func (FilterInputJumpBasic) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-P", "INPUT", "DROP"},
{"-N", chainName},
{"-A", "INPUT", "-j", chainName},
{"-A", chainName, "-j", "ACCEPT"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -481,7 +480,7 @@ func (FilterInputJumpBasic) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputJumpBasic) LocalAction(ip net.IP) error {
+func (FilterInputJumpBasic) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -494,7 +493,7 @@ func (FilterInputJumpReturn) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputJumpReturn) ContainerAction(ip net.IP) error {
+func (FilterInputJumpReturn) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-N", chainName},
{"-P", "INPUT", "ACCEPT"},
@@ -502,7 +501,7 @@ func (FilterInputJumpReturn) ContainerAction(ip net.IP) error {
{"-A", chainName, "-j", "RETURN"},
{"-A", chainName, "-j", "DROP"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -511,7 +510,7 @@ func (FilterInputJumpReturn) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputJumpReturn) LocalAction(ip net.IP) error {
+func (FilterInputJumpReturn) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -524,14 +523,14 @@ func (FilterInputJumpReturnDrop) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputJumpReturnDrop) ContainerAction(ip net.IP) error {
+func (FilterInputJumpReturnDrop) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-N", chainName},
{"-A", "INPUT", "-j", chainName},
{"-A", "INPUT", "-j", "DROP"},
{"-A", chainName, "-j", "RETURN"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -548,7 +547,7 @@ func (FilterInputJumpReturnDrop) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputJumpReturnDrop) LocalAction(ip net.IP) error {
+func (FilterInputJumpReturnDrop) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, dropPort, sendloopDuration)
}
@@ -561,15 +560,15 @@ func (FilterInputJumpBuiltin) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputJumpBuiltin) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "INPUT", "-j", "OUTPUT"); err == nil {
+func (FilterInputJumpBuiltin) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "INPUT", "-j", "OUTPUT"); err == nil {
return fmt.Errorf("iptables should be unable to jump to a built-in chain")
}
return nil
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputJumpBuiltin) LocalAction(ip net.IP) error {
+func (FilterInputJumpBuiltin) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -583,7 +582,7 @@ func (FilterInputJumpTwice) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputJumpTwice) ContainerAction(ip net.IP) error {
+func (FilterInputJumpTwice) ContainerAction(ip net.IP, ipv6 bool) error {
const chainName2 = chainName + "2"
rules := [][]string{
{"-P", "INPUT", "DROP"},
@@ -593,7 +592,7 @@ func (FilterInputJumpTwice) ContainerAction(ip net.IP) error {
{"-A", chainName, "-j", chainName2},
{"-A", "INPUT", "-j", "ACCEPT"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -603,7 +602,7 @@ func (FilterInputJumpTwice) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputJumpTwice) LocalAction(ip net.IP) error {
+func (FilterInputJumpTwice) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -617,8 +616,8 @@ func (FilterInputDestination) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputDestination) ContainerAction(ip net.IP) error {
- addrs, err := localAddrs(false)
+func (FilterInputDestination) ContainerAction(ip net.IP, ipv6 bool) error {
+ addrs, err := localAddrs(ipv6)
if err != nil {
return err
}
@@ -629,7 +628,7 @@ func (FilterInputDestination) ContainerAction(ip net.IP) error {
for _, addr := range addrs {
rules = append(rules, []string{"-A", "INPUT", "-d", addr, "-j", "ACCEPT"})
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -637,7 +636,7 @@ func (FilterInputDestination) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputDestination) LocalAction(ip net.IP) error {
+func (FilterInputDestination) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -651,14 +650,14 @@ func (FilterInputInvertDestination) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputInvertDestination) ContainerAction(ip net.IP) error {
+func (FilterInputInvertDestination) ContainerAction(ip net.IP, ipv6 bool) error {
// Make INPUT's default action DROP, then ACCEPT all packets not bound
// for 127.0.0.1.
rules := [][]string{
{"-P", "INPUT", "DROP"},
- {"-A", "INPUT", "!", "-d", localIP, "-j", "ACCEPT"},
+ {"-A", "INPUT", "!", "-d", localIP(ipv6), "-j", "ACCEPT"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -666,7 +665,7 @@ func (FilterInputInvertDestination) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputInvertDestination) LocalAction(ip net.IP) error {
+func (FilterInputInvertDestination) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -680,14 +679,14 @@ func (FilterInputSource) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputSource) ContainerAction(ip net.IP) error {
+func (FilterInputSource) ContainerAction(ip net.IP, ipv6 bool) error {
// Make INPUT's default action DROP, then ACCEPT all packets from this
// machine.
rules := [][]string{
{"-P", "INPUT", "DROP"},
{"-A", "INPUT", "-s", fmt.Sprintf("%v", ip), "-j", "ACCEPT"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -695,7 +694,7 @@ func (FilterInputSource) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputSource) LocalAction(ip net.IP) error {
+func (FilterInputSource) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -709,14 +708,14 @@ func (FilterInputInvertSource) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterInputInvertSource) ContainerAction(ip net.IP) error {
+func (FilterInputInvertSource) ContainerAction(ip net.IP, ipv6 bool) error {
// Make INPUT's default action DROP, then ACCEPT all packets not bound
// for 127.0.0.1.
rules := [][]string{
{"-P", "INPUT", "DROP"},
- {"-A", "INPUT", "!", "-s", localIP, "-j", "ACCEPT"},
+ {"-A", "INPUT", "!", "-s", localIP(ipv6), "-j", "ACCEPT"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -724,6 +723,6 @@ func (FilterInputInvertSource) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterInputInvertSource) LocalAction(ip net.IP) error {
+func (FilterInputInvertSource) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
diff --git a/test/iptables/filter_output.go b/test/iptables/filter_output.go
index ba0d6fc29..c1d83b471 100644
--- a/test/iptables/filter_output.go
+++ b/test/iptables/filter_output.go
@@ -52,8 +52,8 @@ func (FilterOutputDropTCPDestPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputDropTCPDestPort) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--dport", "1024:65535", "-j", "DROP"); err != nil {
+func (FilterOutputDropTCPDestPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--dport", "1024:65535", "-j", "DROP"); err != nil {
return err
}
@@ -66,7 +66,7 @@ func (FilterOutputDropTCPDestPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputDropTCPDestPort) LocalAction(ip net.IP) error {
+func (FilterOutputDropTCPDestPort) LocalAction(ip net.IP, ipv6 bool) error {
if err := connectTCP(ip, acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("connection on port %d should not be accepted, but got accepted", dropPort)
}
@@ -84,8 +84,8 @@ func (FilterOutputDropTCPSrcPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputDropTCPSrcPort) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--sport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
+func (FilterOutputDropTCPSrcPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--sport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil {
return err
}
@@ -98,7 +98,7 @@ func (FilterOutputDropTCPSrcPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputDropTCPSrcPort) LocalAction(ip net.IP) error {
+func (FilterOutputDropTCPSrcPort) LocalAction(ip net.IP, ipv6 bool) error {
if err := connectTCP(ip, dropPort, sendloopDuration); err == nil {
return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", dropPort)
}
@@ -115,8 +115,8 @@ func (FilterOutputAcceptTCPOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputAcceptTCPOwner) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--uid-owner", "root", "-j", "ACCEPT"); err != nil {
+func (FilterOutputAcceptTCPOwner) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--uid-owner", "root", "-j", "ACCEPT"); err != nil {
return err
}
@@ -125,7 +125,7 @@ func (FilterOutputAcceptTCPOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputAcceptTCPOwner) LocalAction(ip net.IP) error {
+func (FilterOutputAcceptTCPOwner) LocalAction(ip net.IP, ipv6 bool) error {
return connectTCP(ip, acceptPort, sendloopDuration)
}
@@ -138,8 +138,8 @@ func (FilterOutputDropTCPOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputDropTCPOwner) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--uid-owner", "root", "-j", "DROP"); err != nil {
+func (FilterOutputDropTCPOwner) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--uid-owner", "root", "-j", "DROP"); err != nil {
return err
}
@@ -152,7 +152,7 @@ func (FilterOutputDropTCPOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputDropTCPOwner) LocalAction(ip net.IP) error {
+func (FilterOutputDropTCPOwner) LocalAction(ip net.IP, ipv6 bool) error {
if err := connectTCP(ip, acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("connection destined to port %d should be dropped, but got accepted", acceptPort)
}
@@ -169,8 +169,8 @@ func (FilterOutputAcceptUDPOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputAcceptUDPOwner) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "udp", "-m", "owner", "--uid-owner", "root", "-j", "ACCEPT"); err != nil {
+func (FilterOutputAcceptUDPOwner) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "udp", "-m", "owner", "--uid-owner", "root", "-j", "ACCEPT"); err != nil {
return err
}
@@ -179,7 +179,7 @@ func (FilterOutputAcceptUDPOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputAcceptUDPOwner) LocalAction(ip net.IP) error {
+func (FilterOutputAcceptUDPOwner) LocalAction(ip net.IP, ipv6 bool) error {
// Listen for UDP packets on acceptPort.
return listenUDP(acceptPort, sendloopDuration)
}
@@ -193,8 +193,8 @@ func (FilterOutputDropUDPOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputDropUDPOwner) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "udp", "-m", "owner", "--uid-owner", "root", "-j", "DROP"); err != nil {
+func (FilterOutputDropUDPOwner) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "udp", "-m", "owner", "--uid-owner", "root", "-j", "DROP"); err != nil {
return err
}
@@ -203,7 +203,7 @@ func (FilterOutputDropUDPOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputDropUDPOwner) LocalAction(ip net.IP) error {
+func (FilterOutputDropUDPOwner) LocalAction(ip net.IP, ipv6 bool) error {
// Listen for UDP packets on dropPort.
if err := listenUDP(dropPort, sendloopDuration); err == nil {
return fmt.Errorf("packets should not be received")
@@ -222,8 +222,8 @@ func (FilterOutputOwnerFail) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputOwnerFail) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "udp", "-m", "owner", "-j", "ACCEPT"); err == nil {
+func (FilterOutputOwnerFail) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "udp", "-m", "owner", "-j", "ACCEPT"); err == nil {
return fmt.Errorf("Invalid argument")
}
@@ -231,7 +231,7 @@ func (FilterOutputOwnerFail) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputOwnerFail) LocalAction(ip net.IP) error {
+func (FilterOutputOwnerFail) LocalAction(ip net.IP, ipv6 bool) error {
// no-op.
return nil
}
@@ -245,8 +245,8 @@ func (FilterOutputAcceptGIDOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputAcceptGIDOwner) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--gid-owner", "root", "-j", "ACCEPT"); err != nil {
+func (FilterOutputAcceptGIDOwner) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--gid-owner", "root", "-j", "ACCEPT"); err != nil {
return err
}
@@ -255,7 +255,7 @@ func (FilterOutputAcceptGIDOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputAcceptGIDOwner) LocalAction(ip net.IP) error {
+func (FilterOutputAcceptGIDOwner) LocalAction(ip net.IP, ipv6 bool) error {
return connectTCP(ip, acceptPort, sendloopDuration)
}
@@ -268,8 +268,8 @@ func (FilterOutputDropGIDOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputDropGIDOwner) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--gid-owner", "root", "-j", "DROP"); err != nil {
+func (FilterOutputDropGIDOwner) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-m", "owner", "--gid-owner", "root", "-j", "DROP"); err != nil {
return err
}
@@ -282,7 +282,7 @@ func (FilterOutputDropGIDOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputDropGIDOwner) LocalAction(ip net.IP) error {
+func (FilterOutputDropGIDOwner) LocalAction(ip net.IP, ipv6 bool) error {
if err := connectTCP(ip, acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", acceptPort)
}
@@ -299,12 +299,12 @@ func (FilterOutputInvertGIDOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInvertGIDOwner) ContainerAction(ip net.IP) error {
+func (FilterOutputInvertGIDOwner) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-A", "OUTPUT", "-p", "tcp", "-m", "owner", "!", "--gid-owner", "root", "-j", "ACCEPT"},
{"-A", "OUTPUT", "-p", "tcp", "-j", "DROP"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -317,7 +317,7 @@ func (FilterOutputInvertGIDOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInvertGIDOwner) LocalAction(ip net.IP) error {
+func (FilterOutputInvertGIDOwner) LocalAction(ip net.IP, ipv6 bool) error {
if err := connectTCP(ip, acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", acceptPort)
}
@@ -334,12 +334,12 @@ func (FilterOutputInvertUIDOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInvertUIDOwner) ContainerAction(ip net.IP) error {
+func (FilterOutputInvertUIDOwner) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-A", "OUTPUT", "-p", "tcp", "-m", "owner", "!", "--uid-owner", "root", "-j", "DROP"},
{"-A", "OUTPUT", "-p", "tcp", "-j", "ACCEPT"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -348,7 +348,7 @@ func (FilterOutputInvertUIDOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInvertUIDOwner) LocalAction(ip net.IP) error {
+func (FilterOutputInvertUIDOwner) LocalAction(ip net.IP, ipv6 bool) error {
return connectTCP(ip, acceptPort, sendloopDuration)
}
@@ -362,12 +362,12 @@ func (FilterOutputInvertUIDAndGIDOwner) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInvertUIDAndGIDOwner) ContainerAction(ip net.IP) error {
+func (FilterOutputInvertUIDAndGIDOwner) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-A", "OUTPUT", "-p", "tcp", "-m", "owner", "!", "--uid-owner", "root", "!", "--gid-owner", "root", "-j", "ACCEPT"},
{"-A", "OUTPUT", "-p", "tcp", "-j", "DROP"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -380,7 +380,7 @@ func (FilterOutputInvertUIDAndGIDOwner) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInvertUIDAndGIDOwner) LocalAction(ip net.IP) error {
+func (FilterOutputInvertUIDAndGIDOwner) LocalAction(ip net.IP, ipv6 bool) error {
if err := connectTCP(ip, acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", acceptPort)
}
@@ -398,12 +398,12 @@ func (FilterOutputDestination) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputDestination) ContainerAction(ip net.IP) error {
+func (FilterOutputDestination) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
{"-A", "OUTPUT", "-d", ip.String(), "-j", "ACCEPT"},
{"-P", "OUTPUT", "DROP"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -411,7 +411,7 @@ func (FilterOutputDestination) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputDestination) LocalAction(ip net.IP) error {
+func (FilterOutputDestination) LocalAction(ip net.IP, ipv6 bool) error {
return listenUDP(acceptPort, sendloopDuration)
}
@@ -425,12 +425,12 @@ func (FilterOutputInvertDestination) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInvertDestination) ContainerAction(ip net.IP) error {
+func (FilterOutputInvertDestination) ContainerAction(ip net.IP, ipv6 bool) error {
rules := [][]string{
- {"-A", "OUTPUT", "!", "-d", localIP, "-j", "ACCEPT"},
+ {"-A", "OUTPUT", "!", "-d", localIP(ipv6), "-j", "ACCEPT"},
{"-P", "OUTPUT", "DROP"},
}
- if err := filterTableRules(rules); err != nil {
+ if err := filterTableRules(ipv6, rules); err != nil {
return err
}
@@ -438,7 +438,7 @@ func (FilterOutputInvertDestination) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInvertDestination) LocalAction(ip net.IP) error {
+func (FilterOutputInvertDestination) LocalAction(ip net.IP, ipv6 bool) error {
return listenUDP(acceptPort, sendloopDuration)
}
@@ -452,12 +452,12 @@ func (FilterOutputInterfaceAccept) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInterfaceAccept) ContainerAction(ip net.IP) error {
+func (FilterOutputInterfaceAccept) ContainerAction(ip net.IP, ipv6 bool) error {
ifname, ok := getInterfaceName()
if !ok {
return fmt.Errorf("no interface is present, except loopback")
}
- if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", ifname, "-j", "ACCEPT"); err != nil {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "udp", "-o", ifname, "-j", "ACCEPT"); err != nil {
return err
}
@@ -465,7 +465,7 @@ func (FilterOutputInterfaceAccept) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInterfaceAccept) LocalAction(ip net.IP) error {
+func (FilterOutputInterfaceAccept) LocalAction(ip net.IP, ipv6 bool) error {
return listenUDP(acceptPort, sendloopDuration)
}
@@ -479,12 +479,12 @@ func (FilterOutputInterfaceDrop) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInterfaceDrop) ContainerAction(ip net.IP) error {
+func (FilterOutputInterfaceDrop) ContainerAction(ip net.IP, ipv6 bool) error {
ifname, ok := getInterfaceName()
if !ok {
return fmt.Errorf("no interface is present, except loopback")
}
- if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", ifname, "-j", "DROP"); err != nil {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "udp", "-o", ifname, "-j", "DROP"); err != nil {
return err
}
@@ -492,7 +492,7 @@ func (FilterOutputInterfaceDrop) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInterfaceDrop) LocalAction(ip net.IP) error {
+func (FilterOutputInterfaceDrop) LocalAction(ip net.IP, ipv6 bool) error {
if err := listenUDP(acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("packets should not be received on port %v, but are received", acceptPort)
}
@@ -510,8 +510,8 @@ func (FilterOutputInterface) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInterface) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", "lo", "-j", "DROP"); err != nil {
+func (FilterOutputInterface) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "udp", "-o", "lo", "-j", "DROP"); err != nil {
return err
}
@@ -519,7 +519,7 @@ func (FilterOutputInterface) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInterface) LocalAction(ip net.IP) error {
+func (FilterOutputInterface) LocalAction(ip net.IP, ipv6 bool) error {
return listenUDP(acceptPort, sendloopDuration)
}
@@ -533,8 +533,8 @@ func (FilterOutputInterfaceBeginsWith) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInterfaceBeginsWith) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", "e+", "-j", "DROP"); err != nil {
+func (FilterOutputInterfaceBeginsWith) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "udp", "-o", "e+", "-j", "DROP"); err != nil {
return err
}
@@ -542,7 +542,7 @@ func (FilterOutputInterfaceBeginsWith) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInterfaceBeginsWith) LocalAction(ip net.IP) error {
+func (FilterOutputInterfaceBeginsWith) LocalAction(ip net.IP, ipv6 bool) error {
if err := listenUDP(acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("packets should not be received on port %v, but are received", acceptPort)
}
@@ -560,8 +560,8 @@ func (FilterOutputInterfaceInvertDrop) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInterfaceInvertDrop) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "!", "-o", "lo", "-j", "DROP"); err != nil {
+func (FilterOutputInterfaceInvertDrop) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "!", "-o", "lo", "-j", "DROP"); err != nil {
return err
}
@@ -574,7 +574,7 @@ func (FilterOutputInterfaceInvertDrop) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInterfaceInvertDrop) LocalAction(ip net.IP) error {
+func (FilterOutputInterfaceInvertDrop) LocalAction(ip net.IP, ipv6 bool) error {
if err := connectTCP(ip, acceptPort, sendloopDuration); err == nil {
return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", acceptPort)
}
@@ -592,8 +592,8 @@ func (FilterOutputInterfaceInvertAccept) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (FilterOutputInterfaceInvertAccept) ContainerAction(ip net.IP) error {
- if err := filterTable("-A", "OUTPUT", "-p", "tcp", "!", "-o", "lo", "-j", "ACCEPT"); err != nil {
+func (FilterOutputInterfaceInvertAccept) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "!", "-o", "lo", "-j", "ACCEPT"); err != nil {
return err
}
@@ -602,6 +602,6 @@ func (FilterOutputInterfaceInvertAccept) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (FilterOutputInterfaceInvertAccept) LocalAction(ip net.IP) error {
+func (FilterOutputInterfaceInvertAccept) LocalAction(ip net.IP, ipv6 bool) error {
return connectTCP(ip, acceptPort, sendloopDuration)
}
diff --git a/test/iptables/iptables.go b/test/iptables/iptables.go
index 16cb4f4da..dfbd80cd1 100644
--- a/test/iptables/iptables.go
+++ b/test/iptables/iptables.go
@@ -40,10 +40,10 @@ type TestCase interface {
// ContainerAction runs inside the container. It receives the IP of the
// local process.
- ContainerAction(ip net.IP) error
+ ContainerAction(ip net.IP, ipv6 bool) error
// LocalAction runs locally. It receives the IP of the container.
- LocalAction(ip net.IP) error
+ LocalAction(ip net.IP, ipv6 bool) error
}
// Tests maps test names to TestCase.
diff --git a/test/iptables/iptables_test.go b/test/iptables/iptables_test.go
index f303030aa..550b6198a 100644
--- a/test/iptables/iptables_test.go
+++ b/test/iptables/iptables_test.go
@@ -35,6 +35,18 @@ import (
// Container output is logged to $TEST_UNDECLARED_OUTPUTS_DIR if it exists, or
// to stderr.
func singleTest(t *testing.T, test TestCase) {
+ for _, tc := range []bool{false, true} {
+ subtest := "IPv4"
+ if tc {
+ subtest = "IPv6"
+ }
+ t.Run(subtest, func(t *testing.T) {
+ iptablesTest(t, test, tc)
+ })
+ }
+}
+
+func iptablesTest(t *testing.T, test TestCase, ipv6 bool) {
if _, ok := Tests[test.Name()]; !ok {
t.Fatalf("no test found with name %q. Has it been registered?", test.Name())
}
@@ -43,18 +55,27 @@ func singleTest(t *testing.T, test TestCase) {
d := dockerutil.MakeContainer(ctx, t)
defer d.CleanUp(ctx)
+ // TODO(gvisor.dev/issue/170): Skipping IPv6 gVisor tests.
+ if ipv6 && dockerutil.Runtime() != "runc" {
+ t.Skip("gVisor ip6tables not yet implemented")
+ }
+
// Create and start the container.
opts := dockerutil.RunOpts{
Image: "iptables",
CapAdd: []string{"NET_ADMIN"},
}
d.CopyFiles(&opts, "/runner", "test/iptables/runner/runner")
- if err := d.Spawn(ctx, opts, "/runner/runner", "-name", test.Name()); err != nil {
+ args := []string{"/runner/runner", "-name", test.Name()}
+ if ipv6 {
+ args = append(args, "-ipv6")
+ }
+ if err := d.Spawn(ctx, opts, args...); err != nil {
t.Fatalf("docker run failed: %v", err)
}
// Get the container IP.
- ip, err := d.FindIP(ctx)
+ ip, err := d.FindIP(ctx, ipv6)
if err != nil {
t.Fatalf("failed to get container IP: %v", err)
}
@@ -65,7 +86,7 @@ func singleTest(t *testing.T, test TestCase) {
}
// Run our side of the test.
- if err := test.LocalAction(ip); err != nil {
+ if err := test.LocalAction(ip, ipv6); err != nil {
t.Fatalf("LocalAction failed: %v", err)
}
@@ -86,7 +107,7 @@ func sendIP(ip net.IP) error {
// The container may not be listening when we first connect, so retry
// upon error.
cb := func() error {
- c, err := net.DialTCP("tcp4", nil, &contAddr)
+ c, err := net.DialTCP("tcp", nil, &contAddr)
conn = c
return err
}
diff --git a/test/iptables/iptables_util.go b/test/iptables/iptables_util.go
index 174694002..ca80a4b5f 100644
--- a/test/iptables/iptables_util.go
+++ b/test/iptables/iptables_util.go
@@ -24,22 +24,23 @@ import (
"gvisor.dev/gvisor/pkg/test/testutil"
)
-const iptablesBinary = "iptables"
-const localIP = "127.0.0.1"
-
-// filterTable calls `iptables -t filter` with the given args.
-func filterTable(args ...string) error {
- return tableCmd("filter", args)
+// filterTable calls `ip{6}tables -t filter` with the given args.
+func filterTable(ipv6 bool, args ...string) error {
+ return tableCmd(ipv6, "filter", args)
}
-// natTable calls `iptables -t nat` with the given args.
-func natTable(args ...string) error {
- return tableCmd("nat", args)
+// natTable calls `ip{6}tables -t nat` with the given args.
+func natTable(ipv6 bool, args ...string) error {
+ return tableCmd(ipv6, "nat", args)
}
-func tableCmd(table string, args []string) error {
+func tableCmd(ipv6 bool, table string, args []string) error {
args = append([]string{"-t", table}, args...)
- cmd := exec.Command(iptablesBinary, args...)
+ binary := "iptables"
+ if ipv6 {
+ binary = "ip6tables"
+ }
+ cmd := exec.Command(binary, args...)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("error running iptables with args %v\nerror: %v\noutput: %s", args, err, string(out))
}
@@ -47,18 +48,18 @@ func tableCmd(table string, args []string) error {
}
// filterTableRules is like filterTable, but runs multiple iptables commands.
-func filterTableRules(argsList [][]string) error {
- return tableRules("filter", argsList)
+func filterTableRules(ipv6 bool, argsList [][]string) error {
+ return tableRules(ipv6, "filter", argsList)
}
// natTableRules is like natTable, but runs multiple iptables commands.
-func natTableRules(argsList [][]string) error {
- return tableRules("nat", argsList)
+func natTableRules(ipv6 bool, argsList [][]string) error {
+ return tableRules(ipv6, "nat", argsList)
}
-func tableRules(table string, argsList [][]string) error {
+func tableRules(ipv6 bool, table string, argsList [][]string) error {
for _, args := range argsList {
- if err := tableCmd(table, args); err != nil {
+ if err := tableCmd(ipv6, table, args); err != nil {
return err
}
}
@@ -71,7 +72,7 @@ func listenUDP(port int, timeout time.Duration) error {
localAddr := net.UDPAddr{
Port: port,
}
- conn, err := net.ListenUDP(network, &localAddr)
+ conn, err := net.ListenUDP("udp", &localAddr)
if err != nil {
return err
}
@@ -112,7 +113,7 @@ func connectUDP(ip net.IP, port int) (net.Conn, error) {
IP: ip,
Port: port,
}
- conn, err := net.DialUDP(network, nil, &remote)
+ conn, err := net.DialUDP("udp", nil, &remote)
if err != nil {
return nil, err
}
@@ -143,7 +144,7 @@ func listenTCP(port int, timeout time.Duration) error {
}
// Starts listening on port.
- lConn, err := net.ListenTCP("tcp4", &localAddr)
+ lConn, err := net.ListenTCP("tcp", &localAddr)
if err != nil {
return err
}
@@ -191,7 +192,14 @@ func localAddrs(ipv6 bool) ([]string, error) {
}
addrStrs := make([]string, 0, len(addrs))
for _, addr := range addrs {
- addrStrs = append(addrStrs, addr.String())
+ // Add only IPv4 or only IPv6 addresses.
+ parts := strings.Split(addr.String(), "/")
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("bad interface address: %q", addr.String())
+ }
+ if isIPv6 := net.ParseIP(parts[0]).To4() == nil; isIPv6 == ipv6 {
+ addrStrs = append(addrStrs, addr.String())
+ }
}
return filterAddrs(addrStrs, ipv6), nil
}
@@ -222,3 +230,17 @@ func getInterfaceName() (string, bool) {
return ifname, ifname != ""
}
+
+func localIP(ipv6 bool) string {
+ if ipv6 {
+ return "::1"
+ }
+ return "127.0.0.1"
+}
+
+func nowhereIP(ipv6 bool) string {
+ if ipv6 {
+ return "2001:db8::1"
+ }
+ return "192.0.2.1"
+}
diff --git a/test/iptables/nat.go b/test/iptables/nat.go
index 23288577d..ac0d91bb2 100644
--- a/test/iptables/nat.go
+++ b/test/iptables/nat.go
@@ -53,8 +53,8 @@ func (NATPreRedirectUDPPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATPreRedirectUDPPort) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "PREROUTING", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", redirectPort)); err != nil {
+func (NATPreRedirectUDPPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", redirectPort)); err != nil {
return err
}
@@ -66,7 +66,7 @@ func (NATPreRedirectUDPPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATPreRedirectUDPPort) LocalAction(ip net.IP) error {
+func (NATPreRedirectUDPPort) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -79,8 +79,8 @@ func (NATPreRedirectTCPPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATPreRedirectTCPPort) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "PREROUTING", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err != nil {
+func (NATPreRedirectTCPPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err != nil {
return err
}
@@ -89,7 +89,7 @@ func (NATPreRedirectTCPPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATPreRedirectTCPPort) LocalAction(ip net.IP) error {
+func (NATPreRedirectTCPPort) LocalAction(ip net.IP, ipv6 bool) error {
return connectTCP(ip, dropPort, sendloopDuration)
}
@@ -103,9 +103,9 @@ func (NATPreRedirectTCPOutgoing) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATPreRedirectTCPOutgoing) ContainerAction(ip net.IP) error {
+func (NATPreRedirectTCPOutgoing) ContainerAction(ip net.IP, ipv6 bool) error {
// Redirect all incoming TCP traffic to a closed port.
- if err := natTable("-A", "PREROUTING", "-p", "tcp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", dropPort)); err != nil {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "tcp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", dropPort)); err != nil {
return err
}
@@ -114,7 +114,7 @@ func (NATPreRedirectTCPOutgoing) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATPreRedirectTCPOutgoing) LocalAction(ip net.IP) error {
+func (NATPreRedirectTCPOutgoing) LocalAction(ip net.IP, ipv6 bool) error {
return listenTCP(acceptPort, sendloopDuration)
}
@@ -128,9 +128,9 @@ func (NATOutRedirectTCPIncoming) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATOutRedirectTCPIncoming) ContainerAction(ip net.IP) error {
+func (NATOutRedirectTCPIncoming) ContainerAction(ip net.IP, ipv6 bool) error {
// Redirect all outgoing TCP traffic to a closed port.
- if err := natTable("-A", "OUTPUT", "-p", "tcp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", dropPort)); err != nil {
+ if err := natTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", dropPort)); err != nil {
return err
}
@@ -139,7 +139,7 @@ func (NATOutRedirectTCPIncoming) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATOutRedirectTCPIncoming) LocalAction(ip net.IP) error {
+func (NATOutRedirectTCPIncoming) LocalAction(ip net.IP, ipv6 bool) error {
return connectTCP(ip, acceptPort, sendloopDuration)
}
@@ -152,13 +152,12 @@ func (NATOutRedirectUDPPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATOutRedirectUDPPort) ContainerAction(ip net.IP) error {
- dest := []byte{200, 0, 0, 1}
- return loopbackTest(dest, "-A", "OUTPUT", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort))
+func (NATOutRedirectUDPPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ return loopbackTest(ipv6, net.ParseIP(nowhereIP(ipv6)), "-A", "OUTPUT", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort))
}
// LocalAction implements TestCase.LocalAction.
-func (NATOutRedirectUDPPort) LocalAction(ip net.IP) error {
+func (NATOutRedirectUDPPort) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -173,8 +172,8 @@ func (NATDropUDP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATDropUDP) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "PREROUTING", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", redirectPort)); err != nil {
+func (NATDropUDP) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", redirectPort)); err != nil {
return err
}
@@ -186,7 +185,7 @@ func (NATDropUDP) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATDropUDP) LocalAction(ip net.IP) error {
+func (NATDropUDP) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -199,8 +198,8 @@ func (NATAcceptAll) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATAcceptAll) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "PREROUTING", "-p", "udp", "-j", "ACCEPT"); err != nil {
+func (NATAcceptAll) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "udp", "-j", "ACCEPT"); err != nil {
return err
}
@@ -212,7 +211,7 @@ func (NATAcceptAll) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATAcceptAll) LocalAction(ip net.IP) error {
+func (NATAcceptAll) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -226,14 +225,17 @@ func (NATOutRedirectIP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATOutRedirectIP) ContainerAction(ip net.IP) error {
+func (NATOutRedirectIP) ContainerAction(ip net.IP, ipv6 bool) error {
// Redirect OUTPUT packets to a listening localhost port.
- dest := net.IP([]byte{200, 0, 0, 2})
- return loopbackTest(dest, "-A", "OUTPUT", "-d", dest.String(), "-p", "udp", "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", acceptPort))
+ return loopbackTest(ipv6, net.ParseIP(nowhereIP(ipv6)),
+ "-A", "OUTPUT",
+ "-d", nowhereIP(ipv6),
+ "-p", "udp",
+ "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", acceptPort))
}
// LocalAction implements TestCase.LocalAction.
-func (NATOutRedirectIP) LocalAction(ip net.IP) error {
+func (NATOutRedirectIP) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -248,15 +250,15 @@ func (NATOutDontRedirectIP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATOutDontRedirectIP) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "OUTPUT", "-d", localIP, "-p", "udp", "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", dropPort)); err != nil {
+func (NATOutDontRedirectIP) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "OUTPUT", "-d", localIP(ipv6), "-p", "udp", "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", dropPort)); err != nil {
return err
}
return sendUDPLoop(ip, acceptPort, sendloopDuration)
}
// LocalAction implements TestCase.LocalAction.
-func (NATOutDontRedirectIP) LocalAction(ip net.IP) error {
+func (NATOutDontRedirectIP) LocalAction(ip net.IP, ipv6 bool) error {
return listenUDP(acceptPort, sendloopDuration)
}
@@ -269,15 +271,21 @@ func (NATOutRedirectInvert) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATOutRedirectInvert) ContainerAction(ip net.IP) error {
+func (NATOutRedirectInvert) ContainerAction(ip net.IP, ipv6 bool) error {
// Redirect OUTPUT packets to a listening localhost port.
- dest := []byte{200, 0, 0, 3}
- destStr := "200.0.0.2"
- return loopbackTest(dest, "-A", "OUTPUT", "!", "-d", destStr, "-p", "udp", "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", acceptPort))
+ dest := "192.0.2.2"
+ if ipv6 {
+ dest = "2001:db8::2"
+ }
+ return loopbackTest(ipv6, net.ParseIP(nowhereIP(ipv6)),
+ "-A", "OUTPUT",
+ "!", "-d", dest,
+ "-p", "udp",
+ "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", acceptPort))
}
// LocalAction implements TestCase.LocalAction.
-func (NATOutRedirectInvert) LocalAction(ip net.IP) error {
+func (NATOutRedirectInvert) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -292,8 +300,8 @@ func (NATPreRedirectIP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATPreRedirectIP) ContainerAction(ip net.IP) error {
- addrs, err := localAddrs(false)
+func (NATPreRedirectIP) ContainerAction(ip net.IP, ipv6 bool) error {
+ addrs, err := localAddrs(ipv6)
if err != nil {
return err
}
@@ -302,14 +310,14 @@ func (NATPreRedirectIP) ContainerAction(ip net.IP) error {
for _, addr := range addrs {
rules = append(rules, []string{"-A", "PREROUTING", "-p", "udp", "-d", addr, "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)})
}
- if err := natTableRules(rules); err != nil {
+ if err := natTableRules(ipv6, rules); err != nil {
return err
}
return listenUDP(acceptPort, sendloopDuration)
}
// LocalAction implements TestCase.LocalAction.
-func (NATPreRedirectIP) LocalAction(ip net.IP) error {
+func (NATPreRedirectIP) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, dropPort, sendloopDuration)
}
@@ -323,15 +331,15 @@ func (NATPreDontRedirectIP) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATPreDontRedirectIP) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "PREROUTING", "-p", "udp", "-d", localIP, "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", dropPort)); err != nil {
+func (NATPreDontRedirectIP) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "udp", "-d", localIP(ipv6), "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", dropPort)); err != nil {
return err
}
return listenUDP(acceptPort, sendloopDuration)
}
// LocalAction implements TestCase.LocalAction.
-func (NATPreDontRedirectIP) LocalAction(ip net.IP) error {
+func (NATPreDontRedirectIP) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, acceptPort, sendloopDuration)
}
@@ -344,15 +352,15 @@ func (NATPreRedirectInvert) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATPreRedirectInvert) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "PREROUTING", "-p", "udp", "!", "-d", localIP, "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err != nil {
+func (NATPreRedirectInvert) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "udp", "!", "-d", localIP(ipv6), "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err != nil {
return err
}
return listenUDP(acceptPort, sendloopDuration)
}
// LocalAction implements TestCase.LocalAction.
-func (NATPreRedirectInvert) LocalAction(ip net.IP) error {
+func (NATPreRedirectInvert) LocalAction(ip net.IP, ipv6 bool) error {
return spawnUDPLoop(ip, dropPort, sendloopDuration)
}
@@ -366,15 +374,15 @@ func (NATRedirectRequiresProtocol) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATRedirectRequiresProtocol) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "PREROUTING", "-d", localIP, "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err == nil {
+func (NATRedirectRequiresProtocol) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-d", localIP(ipv6), "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err == nil {
return errors.New("expected an error using REDIRECT --to-ports without a protocol")
}
return nil
}
// LocalAction implements TestCase.LocalAction.
-func (NATRedirectRequiresProtocol) LocalAction(ip net.IP) error {
+func (NATRedirectRequiresProtocol) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
@@ -388,15 +396,14 @@ func (NATOutRedirectTCPPort) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATOutRedirectTCPPort) ContainerAction(ip net.IP) error {
- if err := natTable("-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err != nil {
+func (NATOutRedirectTCPPort) ContainerAction(ip net.IP, ipv6 bool) error {
+ if err := natTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", acceptPort)); err != nil {
return err
}
timeout := 20 * time.Second
- dest := []byte{127, 0, 0, 1}
localAddr := net.TCPAddr{
- IP: dest,
+ IP: net.ParseIP(localIP(ipv6)),
Port: acceptPort,
}
@@ -424,7 +431,7 @@ func (NATOutRedirectTCPPort) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATOutRedirectTCPPort) LocalAction(ip net.IP) error {
+func (NATOutRedirectTCPPort) LocalAction(ip net.IP, ipv6 bool) error {
return nil
}
@@ -438,10 +445,10 @@ func (NATLoopbackSkipsPrerouting) Name() string {
}
// ContainerAction implements TestCase.ContainerAction.
-func (NATLoopbackSkipsPrerouting) ContainerAction(ip net.IP) error {
+func (NATLoopbackSkipsPrerouting) ContainerAction(ip net.IP, ipv6 bool) error {
// Redirect anything sent to localhost to an unused port.
dest := []byte{127, 0, 0, 1}
- if err := natTable("-A", "PREROUTING", "-p", "tcp", "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", dropPort)); err != nil {
+ if err := natTable(ipv6, "-A", "PREROUTING", "-p", "tcp", "-j", "REDIRECT", "--to-port", fmt.Sprintf("%d", dropPort)); err != nil {
return err
}
@@ -459,15 +466,15 @@ func (NATLoopbackSkipsPrerouting) ContainerAction(ip net.IP) error {
}
// LocalAction implements TestCase.LocalAction.
-func (NATLoopbackSkipsPrerouting) LocalAction(ip net.IP) error {
+func (NATLoopbackSkipsPrerouting) LocalAction(ip net.IP, ipv6 bool) error {
// No-op.
return nil
}
// loopbackTests runs an iptables rule and ensures that packets sent to
// dest:dropPort are received by localhost:acceptPort.
-func loopbackTest(dest net.IP, args ...string) error {
- if err := natTable(args...); err != nil {
+func loopbackTest(ipv6 bool, dest net.IP, args ...string) error {
+ if err := natTable(ipv6, args...); err != nil {
return err
}
sendCh := make(chan error)
diff --git a/test/iptables/runner/main.go b/test/iptables/runner/main.go
index 6f77c0684..69d3ef121 100644
--- a/test/iptables/runner/main.go
+++ b/test/iptables/runner/main.go
@@ -24,7 +24,10 @@ import (
"gvisor.dev/gvisor/test/iptables"
)
-var name = flag.String("name", "", "name of the test to run")
+var (
+ name = flag.String("name", "", "name of the test to run")
+ ipv6 = flag.Bool("ipv6", false, "whether the test utilizes ip6tables")
+)
func main() {
flag.Parse()
@@ -43,7 +46,7 @@ func main() {
}
// Run the test.
- if err := test.ContainerAction(ip); err != nil {
+ if err := test.ContainerAction(ip, *ipv6); err != nil {
log.Fatalf("Failed running test %q: %v", *name, err)
}
@@ -57,7 +60,7 @@ func getIP() (net.IP, error) {
localAddr := net.TCPAddr{
Port: iptables.IPExchangePort,
}
- listener, err := net.ListenTCP("tcp4", &localAddr)
+ listener, err := net.ListenTCP("tcp", &localAddr)
if err != nil {
return net.IP{}, fmt.Errorf("failed listening for IP: %v", err)
}
diff --git a/test/packetimpact/tests/BUILD b/test/packetimpact/tests/BUILD
index 27905dcff..0c2a05380 100644
--- a/test/packetimpact/tests/BUILD
+++ b/test/packetimpact/tests/BUILD
@@ -46,6 +46,18 @@ packetimpact_go_test(
"//pkg/tcpip",
"//pkg/tcpip/header",
"//test/packetimpact/testbench",
+ "@com_github_google_go_cmp//cmp:go_default_library",
+ "@org_golang_x_sys//unix:go_default_library",
+ ],
+)
+
+packetimpact_go_test(
+ name = "udp_any_addr_recv_unicast",
+ srcs = ["udp_any_addr_recv_unicast_test.go"],
+ deps = [
+ "//pkg/tcpip",
+ "//test/packetimpact/testbench",
+ "@com_github_google_go_cmp//cmp:go_default_library",
"@org_golang_x_sys//unix:go_default_library",
],
)
@@ -294,6 +306,7 @@ packetimpact_go_test(
srcs = ["udp_send_recv_dgram_test.go"],
deps = [
"//test/packetimpact/testbench",
+ "@com_github_google_go_cmp//cmp:go_default_library",
"@org_golang_x_sys//unix:go_default_library",
],
)
diff --git a/test/packetimpact/tests/udp_any_addr_recv_unicast_test.go b/test/packetimpact/tests/udp_any_addr_recv_unicast_test.go
new file mode 100644
index 000000000..17f32ef65
--- /dev/null
+++ b/test/packetimpact/tests/udp_any_addr_recv_unicast_test.go
@@ -0,0 +1,51 @@
+// 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 udp_any_addr_recv_unicast_test
+
+import (
+ "flag"
+ "net"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "golang.org/x/sys/unix"
+ "gvisor.dev/gvisor/pkg/tcpip"
+ "gvisor.dev/gvisor/test/packetimpact/testbench"
+)
+
+func init() {
+ testbench.RegisterFlags(flag.CommandLine)
+}
+
+func TestAnyRecvUnicastUDP(t *testing.T) {
+ dut := testbench.NewDUT(t)
+ defer dut.TearDown()
+ boundFD, remotePort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.IPv4zero)
+ defer dut.Close(t, boundFD)
+ conn := testbench.NewUDPIPv4(t, testbench.UDP{DstPort: &remotePort}, testbench.UDP{SrcPort: &remotePort})
+ defer conn.Close(t)
+
+ payload := testbench.GenerateRandomPayload(t, 1<<10 /* 1 KiB */)
+ conn.SendIP(
+ t,
+ testbench.IPv4{DstAddr: testbench.Address(tcpip.Address(net.ParseIP(testbench.RemoteIPv4).To4()))},
+ testbench.UDP{},
+ &testbench.Payload{Bytes: payload},
+ )
+ got, want := dut.Recv(t, boundFD, int32(len(payload)+1), 0), payload
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Errorf("received payload does not match sent payload, diff (-want, +got):\n%s", diff)
+ }
+}
diff --git a/test/packetimpact/tests/udp_icmp_error_propagation_test.go b/test/packetimpact/tests/udp_icmp_error_propagation_test.go
index 715e8f5b5..b47ddb6c3 100644
--- a/test/packetimpact/tests/udp_icmp_error_propagation_test.go
+++ b/test/packetimpact/tests/udp_icmp_error_propagation_test.go
@@ -227,12 +227,12 @@ func TestUDPICMPErrorPropagation(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
- remoteFD, remotePort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.ParseIP("0.0.0.0"))
+ remoteFD, remotePort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.IPv4zero)
defer dut.Close(t, remoteFD)
// Create a second, clean socket on the DUT to ensure that the ICMP
// error messages only affect the sockets they are intended for.
- cleanFD, cleanPort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.ParseIP("0.0.0.0"))
+ cleanFD, cleanPort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.IPv4zero)
defer dut.Close(t, cleanFD)
conn := testbench.NewUDPIPv4(t, testbench.UDP{DstPort: &remotePort}, testbench.UDP{SrcPort: &remotePort})
@@ -281,12 +281,12 @@ func TestICMPErrorDuringUDPRecv(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
- remoteFD, remotePort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.ParseIP("0.0.0.0"))
+ remoteFD, remotePort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.IPv4zero)
defer dut.Close(t, remoteFD)
// Create a second, clean socket on the DUT to ensure that the ICMP
// error messages only affect the sockets they are intended for.
- cleanFD, cleanPort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.ParseIP("0.0.0.0"))
+ cleanFD, cleanPort := dut.CreateBoundSocket(t, unix.SOCK_DGRAM, unix.IPPROTO_UDP, net.IPv4zero)
defer dut.Close(t, cleanFD)
conn := testbench.NewUDPIPv4(t, testbench.UDP{DstPort: &remotePort}, testbench.UDP{SrcPort: &remotePort})
diff --git a/test/packetimpact/tests/udp_recv_mcast_bcast_test.go b/test/packetimpact/tests/udp_recv_mcast_bcast_test.go
index df972b33d..526173969 100644
--- a/test/packetimpact/tests/udp_recv_mcast_bcast_test.go
+++ b/test/packetimpact/tests/udp_recv_mcast_bcast_test.go
@@ -22,6 +22,7 @@ import (
"syscall"
"testing"
+ "github.com/google/go-cmp/cmp"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/test/packetimpact/testbench"
@@ -37,9 +38,9 @@ func TestUDPRecvMcastBcast(t *testing.T) {
for _, v := range []struct {
bound, to net.IP
}{
- {bound: net.IPv4(0, 0, 0, 0), to: subnetBcastAddr},
- {bound: net.IPv4(0, 0, 0, 0), to: net.IPv4bcast},
- {bound: net.IPv4(0, 0, 0, 0), to: net.IPv4allsys},
+ {bound: net.IPv4zero, to: subnetBcastAddr},
+ {bound: net.IPv4zero, to: net.IPv4bcast},
+ {bound: net.IPv4zero, to: net.IPv4allsys},
{bound: subnetBcastAddr, to: subnetBcastAddr},
{bound: subnetBcastAddr, to: net.IPv4bcast},
@@ -55,15 +56,16 @@ func TestUDPRecvMcastBcast(t *testing.T) {
conn := testbench.NewUDPIPv4(t, testbench.UDP{DstPort: &remotePort}, testbench.UDP{SrcPort: &remotePort})
defer conn.Close(t)
- payload := testbench.GenerateRandomPayload(t, 1<<10)
+ payload := testbench.GenerateRandomPayload(t, 1<<10 /* 1 KiB */)
conn.SendIP(
t,
testbench.IPv4{DstAddr: testbench.Address(tcpip.Address(v.to.To4()))},
testbench.UDP{},
&testbench.Payload{Bytes: payload},
)
- if got, want := string(dut.Recv(t, boundFD, int32(len(payload)), 0)), string(payload); got != want {
- t.Errorf("received payload does not match sent payload got: %s, want: %s", got, want)
+ got, want := dut.Recv(t, boundFD, int32(len(payload)+1), 0), payload
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Errorf("received payload does not match sent payload, diff (-want, +got):\n%s", diff)
}
})
}
@@ -84,7 +86,7 @@ func TestUDPDoesntRecvMcastBcastOnUnicastAddr(t *testing.T) {
net.IPv4(224, 0, 0, 1),
} {
t.Run(fmt.Sprint("to=%s", to), func(t *testing.T) {
- payload := testbench.GenerateRandomPayload(t, 1<<10)
+ payload := testbench.GenerateRandomPayload(t, 1<<10 /* 1 KiB */)
conn.SendIP(
t,
testbench.IPv4{DstAddr: testbench.Address(tcpip.Address(to.To4()))},
diff --git a/test/packetimpact/tests/udp_send_recv_dgram_test.go b/test/packetimpact/tests/udp_send_recv_dgram_test.go
index dc20275d6..91b967400 100644
--- a/test/packetimpact/tests/udp_send_recv_dgram_test.go
+++ b/test/packetimpact/tests/udp_send_recv_dgram_test.go
@@ -20,6 +20,7 @@ import (
"testing"
"time"
+ "github.com/google/go-cmp/cmp"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/test/packetimpact/testbench"
)
@@ -82,8 +83,9 @@ func TestUDP(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Run("Send", func(t *testing.T) {
conn.Send(t, testbench.UDP{}, &testbench.Payload{Bytes: tc.payload})
- if got, want := string(dut.Recv(t, boundFD, int32(len(tc.payload)), 0)), string(tc.payload); got != want {
- t.Fatalf("received payload does not match sent payload got: %s, want: %s", got, want)
+ got, want := dut.Recv(t, boundFD, int32(len(tc.payload)+1), 0), tc.payload
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Fatalf("received payload does not match sent payload, diff (-want, +got):\n%s", diff)
}
})
t.Run("Recv", func(t *testing.T) {
diff --git a/test/runtimes/BUILD b/test/runtimes/BUILD
index f98d02e00..1728161ce 100644
--- a/test/runtimes/BUILD
+++ b/test/runtimes/BUILD
@@ -13,14 +13,14 @@ runtime_test(
name = "java11",
exclude_file = "exclude_java11.csv",
lang = "java",
- shard_count = 10,
+ shard_count = 20,
)
runtime_test(
name = "nodejs12.4.0",
exclude_file = "exclude_nodejs12.4.0.csv",
lang = "nodejs",
- shard_count = 5,
+ shard_count = 10,
)
runtime_test(
diff --git a/test/runtimes/exclude_go1.12.csv b/test/runtimes/exclude_go1.12.csv
index 8c8ae0c5d..81e02cf64 100644
--- a/test/runtimes/exclude_go1.12.csv
+++ b/test/runtimes/exclude_go1.12.csv
@@ -2,15 +2,12 @@ test name,bug id,comment
cgo_errors,,FLAKY
cgo_test,,FLAKY
go_test:cmd/go,,FLAKY
-go_test:cmd/vendor/golang.org/x/sys/unix,b/118783622,/dev devices missing
-go_test:net,b/118784196,socket: invalid argument. Works as intended: see bug.
+go_test:net,b/162473575,setsockopt: protocol not available.
go_test:os,b/118780122,we have a pollable filesystem but that's a surprise
-go_test:os/signal,b/118780860,/dev/pts not properly supported
-go_test:runtime,b/118782341,sigtrap not reported or caught or something
-go_test:syscall,b/118781998,bad bytes -- bad mem addr
-race,b/118782931,thread sanitizer. Works as intended: b/62219744.
+go_test:os/signal,b/118780860,/dev/pts not properly supported. Also being tracked in b/29356795.
+go_test:runtime,b/118782341,sigtrap not reported or caught or something. Also being tracked in b/33003106.
+go_test:syscall,b/118781998,bad bytes -- bad mem addr; FcntlFlock(F_GETLK) not supported.
runtime:cpu124,b/118778254,segmentation fault
test:0_1,,FLAKY
-testasan,,
testcarchive,b/118782924,no sigpipe
testshared,,FLAKY
diff --git a/test/runtimes/exclude_nodejs12.4.0.csv b/test/runtimes/exclude_nodejs12.4.0.csv
index e7edfa0a5..4eb0a4807 100644
--- a/test/runtimes/exclude_nodejs12.4.0.csv
+++ b/test/runtimes/exclude_nodejs12.4.0.csv
@@ -47,4 +47,5 @@ pseudo-tty/test-tty-window-size.js,,
pseudo-tty/test-tty-wrap.js,,
pummel/test-net-pingpong.js,,
pummel/test-vm-memleak.js,,
+sequential/test-net-bytes-per-incoming-chunk-overhead.js,,flaky - timeout
tick-processor/test-tick-processor-builtin.js,,
diff --git a/test/runtimes/exclude_php7.3.6.csv b/test/runtimes/exclude_php7.3.6.csv
index f3606bfe8..0bef786c0 100644
--- a/test/runtimes/exclude_php7.3.6.csv
+++ b/test/runtimes/exclude_php7.3.6.csv
@@ -11,6 +11,7 @@ ext/mbstring/tests/mb_strrpos_encoding_3rd_param.phpt,,
ext/session/tests/session_set_save_handler_class_018.phpt,,
ext/session/tests/session_set_save_handler_iface_003.phpt,,
ext/session/tests/session_set_save_handler_variation4.phpt,,
+ext/session/tests/session_set_save_handler_variation5.phpt,,
ext/standard/tests/file/filetype_variation.phpt,,
ext/standard/tests/file/fopen_variation19.phpt,,
ext/standard/tests/file/php_fd_wrapper_01.phpt,,
@@ -26,6 +27,7 @@ ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt,,
ext/standard/tests/network/bug20134.phpt,,
ext/standard/tests/streams/stream_socket_sendto.phpt,,
ext/standard/tests/strings/007.phpt,,
+sapi/cli/tests/upload_2G.phpt,,
tests/output/stream_isatty_err.phpt,b/68720279,
tests/output/stream_isatty_in-err.phpt,b/68720282,
tests/output/stream_isatty_in-out-err.phpt,,
diff --git a/test/runtimes/proctor/go.go b/test/runtimes/proctor/go.go
index 073c2959d..d0ae844e6 100644
--- a/test/runtimes/proctor/go.go
+++ b/test/runtimes/proctor/go.go
@@ -81,13 +81,13 @@ func (goRunner) TestCmds(tests []string) []*exec.Cmd {
if strings.HasSuffix(test, ".go") {
onDiskTests = append(onDiskTests, test)
} else {
- toolTests = append(toolTests, test)
+ toolTests = append(toolTests, "^"+test+"$")
}
}
var cmds []*exec.Cmd
if len(toolTests) > 0 {
- cmds = append(cmds, exec.Command("go", "tool", "dist", "test", "-run", strings.Join(toolTests, "\\|")))
+ cmds = append(cmds, exec.Command("go", "tool", "dist", "test", "-v", "-no-rebuild", "-run", strings.Join(toolTests, "\\|")))
}
if len(onDiskTests) > 0 {
cmd := exec.Command("go", append([]string{"run", "run.go", "-v", "--"}, onDiskTests...)...)
diff --git a/test/syscalls/linux/epoll.cc b/test/syscalls/linux/epoll.cc
index f57d38dc7..2101e5c9f 100644
--- a/test/syscalls/linux/epoll.cc
+++ b/test/syscalls/linux/epoll.cc
@@ -422,6 +422,28 @@ TEST(EpollTest, CloseFile) {
SyscallSucceedsWithValue(0));
}
+TEST(EpollTest, PipeReaderHupAfterWriterClosed) {
+ auto epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
+ int pipefds[2];
+ ASSERT_THAT(pipe(pipefds), SyscallSucceeds());
+ FileDescriptor rfd(pipefds[0]);
+ FileDescriptor wfd(pipefds[1]);
+
+ ASSERT_NO_ERRNO(RegisterEpollFD(epollfd.get(), rfd.get(), 0, kMagicConstant));
+ struct epoll_event result[kFDsPerEpoll];
+ // Initially, rfd should not generate any events of interest.
+ ASSERT_THAT(epoll_wait(epollfd.get(), result, kFDsPerEpoll, 0),
+ SyscallSucceedsWithValue(0));
+ // Close the write end of the pipe.
+ wfd.reset();
+ // rfd should now generate EPOLLHUP, which EPOLL_CTL_ADD unconditionally adds
+ // to the set of events of interest.
+ ASSERT_THAT(epoll_wait(epollfd.get(), result, kFDsPerEpoll, 0),
+ SyscallSucceedsWithValue(1));
+ EXPECT_EQ(result[0].events, EPOLLHUP);
+ EXPECT_EQ(result[0].data.u64, kMagicConstant);
+}
+
} // namespace
} // namespace testing
diff --git a/test/syscalls/linux/fcntl.cc b/test/syscalls/linux/fcntl.cc
index 5467fa2c8..34016d4bd 100644
--- a/test/syscalls/linux/fcntl.cc
+++ b/test/syscalls/linux/fcntl.cc
@@ -1004,7 +1004,8 @@ TEST(FcntlTest, SetOwnPid) {
pid_t pid;
EXPECT_THAT(pid = getpid(), SyscallSucceeds());
- ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, pid), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, pid),
+ SyscallSucceedsWithValue(0));
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(pid));
@@ -1018,7 +1019,8 @@ TEST(FcntlTest, SetOwnPgrp) {
pid_t pgid;
EXPECT_THAT(pgid = getpgrp(), SyscallSucceeds());
- ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, -pgid), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, -pgid),
+ SyscallSucceedsWithValue(0));
// Verify with F_GETOWN_EX; using F_GETOWN on Linux may incorrectly treat the
// negative return value as an error, converting the return value to -1 and
@@ -1038,8 +1040,10 @@ TEST(FcntlTest, SetOwnUnset) {
// Set and unset pid.
pid_t pid;
EXPECT_THAT(pid = getpid(), SyscallSucceeds());
- ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, pid), SyscallSucceeds());
- ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, pid),
+ SyscallSucceedsWithValue(0));
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0),
+ SyscallSucceedsWithValue(0));
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
@@ -1047,8 +1051,10 @@ TEST(FcntlTest, SetOwnUnset) {
// Set and unset pgid.
pid_t pgid;
EXPECT_THAT(pgid = getpgrp(), SyscallSucceeds());
- ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, -pgid), SyscallSucceeds());
- ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, -pgid),
+ SyscallSucceedsWithValue(0));
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0),
+ SyscallSucceedsWithValue(0));
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
@@ -1120,7 +1126,7 @@ TEST(FcntlTest, SetOwnExTid) {
EXPECT_THAT(owner.pid = syscall(__NR_gettid), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(owner.pid));
@@ -1136,7 +1142,7 @@ TEST(FcntlTest, SetOwnExPid) {
EXPECT_THAT(owner.pid = getpid(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(owner.pid));
@@ -1152,7 +1158,7 @@ TEST(FcntlTest, SetOwnExPgrp) {
EXPECT_THAT(set_owner.pid = getpgrp(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &set_owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
// Verify with F_GETOWN_EX; using F_GETOWN on Linux may incorrectly treat the
// negative return value as an error, converting the return value to -1 and
@@ -1176,10 +1182,10 @@ TEST(FcntlTest, SetOwnExUnset) {
owner.type = F_OWNER_PID;
EXPECT_THAT(owner.pid = getpid(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
owner.pid = 0;
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
@@ -1188,10 +1194,10 @@ TEST(FcntlTest, SetOwnExUnset) {
owner.type = F_OWNER_PGRP;
EXPECT_THAT(owner.pid = getpgrp(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
owner.pid = 0;
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
@@ -1207,7 +1213,7 @@ TEST(FcntlTest, GetOwnExTid) {
EXPECT_THAT(set_owner.pid = syscall(__NR_gettid), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &set_owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
f_owner_ex got_owner = {};
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN_EX, &got_owner),
@@ -1225,7 +1231,7 @@ TEST(FcntlTest, GetOwnExPid) {
EXPECT_THAT(set_owner.pid = getpid(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &set_owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
f_owner_ex got_owner = {};
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN_EX, &got_owner),
@@ -1243,7 +1249,7 @@ TEST(FcntlTest, GetOwnExPgrp) {
EXPECT_THAT(set_owner.pid = getpgrp(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &set_owner),
- SyscallSucceeds());
+ SyscallSucceedsWithValue(0));
f_owner_ex got_owner = {};
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN_EX, &got_owner),
diff --git a/test/syscalls/linux/packet_socket.cc b/test/syscalls/linux/packet_socket.cc
index 40aa9326d..861617ff7 100644
--- a/test/syscalls/linux/packet_socket.cc
+++ b/test/syscalls/linux/packet_socket.cc
@@ -188,7 +188,7 @@ void ReceiveMessage(int sock, int ifindex) {
// sizeof(sockaddr_ll).
ASSERT_THAT(src_len, AnyOf(Eq(sizeof(src)), Eq(sizeof(src) - 2)));
- // TODO(b/129292371): Verify protocol once we return it.
+ // TODO(gvisor.dev/issue/173): Verify protocol once we return it.
// Verify the source address.
EXPECT_EQ(src.sll_family, AF_PACKET);
EXPECT_EQ(src.sll_ifindex, ifindex);
@@ -234,7 +234,7 @@ TEST_P(CookedPacketTest, Receive) {
// Send via a packet socket.
TEST_P(CookedPacketTest, Send) {
- // TODO(b/129292371): Remove once we support packet socket writing.
+ // TODO(gvisor.dev/issue/173): Remove once we support packet socket writing.
SKIP_IF(IsRunningOnGvisor());
// Let's send a UDP packet and receive it using a regular UDP socket.
diff --git a/test/syscalls/linux/packet_socket_raw.cc b/test/syscalls/linux/packet_socket_raw.cc
index 2fca9fe4d..a11a03415 100644
--- a/test/syscalls/linux/packet_socket_raw.cc
+++ b/test/syscalls/linux/packet_socket_raw.cc
@@ -195,7 +195,7 @@ TEST_P(RawPacketTest, Receive) {
// sizeof(sockaddr_ll).
ASSERT_THAT(src_len, AnyOf(Eq(sizeof(src)), Eq(sizeof(src) - 2)));
- // TODO(b/129292371): Verify protocol once we return it.
+ // TODO(gvisor.dev/issue/173): Verify protocol once we return it.
// Verify the source address.
EXPECT_EQ(src.sll_family, AF_PACKET);
EXPECT_EQ(src.sll_ifindex, GetLoopbackIndex());
@@ -240,7 +240,7 @@ TEST_P(RawPacketTest, Receive) {
// Send via a packet socket.
TEST_P(RawPacketTest, Send) {
- // TODO(b/129292371): Remove once we support packet socket writing.
+ // TODO(gvisor.dev/issue/173): Remove once we support packet socket writing.
SKIP_IF(IsRunningOnGvisor());
// Let's send a UDP packet and receive it using a regular UDP socket.
diff --git a/test/syscalls/linux/socket_inet_loopback_nogotsan.cc b/test/syscalls/linux/socket_inet_loopback_nogotsan.cc
index 2324c7f6a..791e2bd51 100644
--- a/test/syscalls/linux/socket_inet_loopback_nogotsan.cc
+++ b/test/syscalls/linux/socket_inet_loopback_nogotsan.cc
@@ -82,8 +82,11 @@ using SocketInetLoopbackTest = ::testing::TestWithParam<TestParam>;
// This test verifies that connect returns EADDRNOTAVAIL if all local ephemeral
// ports are already in use for a given destination ip/port.
+//
// We disable S/R because this test creates a large number of sockets.
-TEST_P(SocketInetLoopbackTest, TestTCPPortExhaustion_NoRandomSave) {
+//
+// FIXME(b/162475855): This test is failing reliably.
+TEST_P(SocketInetLoopbackTest, DISABLED_TestTCPPortExhaustion_NoRandomSave) {
auto const& param = GetParam();
TestAddress const& listener = param.listener;
TestAddress const& connector = param.connector;