Skip to content

Commit 093d944

Browse files
kerumetogvisor-bot
authored andcommitted
Create Nftables docker tests.
PiperOrigin-RevId: 800603329
1 parent 096b420 commit 093d944

File tree

13 files changed

+1921
-1
lines changed

13 files changed

+1921
-1
lines changed

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,13 @@ iptables-tests: load-iptables $(RUNTIME_BIN)
420420
@$(call test_runtime,$(RUNTIME)-nftables,--test_env=TEST_NET_RAW=true --test_output=all //test/iptables:nftables_test)
421421
.PHONY: iptables-tests
422422

423+
nftables-tests: load-nftables $(RUNTIME_BIN)
424+
@sudo modprobe nfnetlink
425+
@sudo modprobe nf_tables
426+
@$(call install_runtime,$(RUNTIME),--net-raw --TESTONLY-nftables)
427+
@$(call test_runtime,$(RUNTIME),--test_env=TEST_NET_RAW=true //test/nftables:nftables_test)
428+
.PHONY: nftables-tests
429+
423430
packetdrill-tests: load-packetdrill $(RUNTIME_BIN)
424431
@$(call install_runtime,$(RUNTIME),) # Clear flags.
425432
@$(call test_runtime,$(RUNTIME),//test/packetdrill:all_tests)

images/nftables/Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM ubuntu:24.04
2+
3+
# Install the nftables package.
4+
# It provides the 'nft' command-line utility for managing the nftables firewall.
5+
RUN apt update && apt install -y nftables

test/netutils/BUILD

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ go_library(
99
name = "netutils",
1010
testonly = 1,
1111
srcs = ["utils.go"],
12-
visibility = ["//test/iptables:__subpackages__"],
12+
visibility = [
13+
"//test/iptables:__subpackages__",
14+
"//test/nftables:__subpackages__",
15+
],
1316
deps = ["//pkg/test/testutil"],
1417
)

test/nftables/BUILD

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
load("//tools:defs.bzl", "go_library", "go_test")
2+
3+
package(
4+
default_applicable_licenses = ["//:license"],
5+
licenses = ["notice"],
6+
)
7+
8+
go_library(
9+
name = "nftables",
10+
testonly = 1,
11+
srcs = [
12+
"filter_input.go",
13+
"filter_input_iptables.go",
14+
"iptables_util.go",
15+
"nftables.go",
16+
"nftables_util.go",
17+
],
18+
visibility = ["//test/nftables:__subpackages__"],
19+
deps = ["//test/netutils"],
20+
)
21+
22+
go_test(
23+
name = "nftables_test",
24+
size = "large",
25+
srcs = ["nftables_test.go"],
26+
data = ["//test/nftables/runner"],
27+
library = ":nftables",
28+
tags = [
29+
"local",
30+
"manual",
31+
],
32+
deps = [
33+
"//pkg/log",
34+
"//pkg/test/dockerutil",
35+
"//pkg/test/testutil",
36+
],
37+
)

test/nftables/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# nftables Tests
2+
3+
nftables tests are run via `make nftables-tests`.
4+
5+
nftables require some extra Docker configuration to work. Enable IPv6 in
6+
`/etc/docker/daemon.json` (make sure to restart Docker if you change this file):
7+
8+
```json
9+
{
10+
"experimental": true,
11+
"fixed-cidr-v6": "2001:db8:1::/64",
12+
"ipv6": true,
13+
// Runtimes and other Docker config...
14+
}
15+
```
16+
17+
And if you're running manually (i.e. not using the `make` target), you'll need
18+
to:
19+
20+
* Enable nftables via `modprobe nfnetlink && modprobe nf_tables`.
21+
* Enable `--net-raw` in your chosen runtime in `/etc/docker/daemon.json` (make
22+
sure to restart Docker if you change this file).
23+
24+
The resulting runtime should look something like this:
25+
26+
```json
27+
"runsc": {
28+
"path": "/tmp/nftables/runsc",
29+
"runtimeArgs": [
30+
"--debug-log",
31+
"/tmp/nftables/logs/runsc.log.%TEST%.%TIMESTAMP%.%COMMAND%",
32+
"--net-raw"
33+
]
34+
},
35+
// ...
36+
```
37+
38+
## Test Structure
39+
40+
Each test implements `TestCase`, providing (1) a function to run inside the
41+
container and (2) a function to run locally. Those processes are given each
42+
others' IP addresses. The test succeeds when both functions succeed.
43+
44+
The function inside the container (`ContainerAction`) typically sets some
45+
nftables rules and then tries to send or receive packets. The local function
46+
(`LocalAction`) will typically just send or receive packets.
47+
48+
### Adding Tests
49+
50+
1) Add your test to the `nftables` package.
51+
52+
2) Register the test in an `init` function via `RegisterTestCase` (see
53+
`filter_input.go` as an example).
54+
55+
3) Add it to `nftables_test.go` (see the other tests in that file).
56+
57+
Your test is now runnable with bazel!
58+
59+
## Run individual tests
60+
61+
Build and install `runsc`. Re-run this when you modify gVisor:
62+
63+
```bash
64+
$ bazel build //runsc && sudo cp bazel-out/k8-fastbuild-ST-4c64f0b3d5c7/bin/runsc/runsc_/runsc $(which runsc)
65+
```
66+
67+
Build the testing Docker container. Re-run this when you modify the test code in
68+
this directory:
69+
70+
```bash
71+
$ make load-nftables
72+
```
73+
74+
Run an individual test via:
75+
76+
```bash
77+
$ bazel test //test/nftables:nftables_test --test_filter=<TESTNAME>
78+
```
79+
80+
To run an individual test with `runc`:
81+
82+
```bash
83+
$ bazel test //test/nftables:nftables_test --test_filter=<TESTNAME> --test_env=RUNTIME=runc
84+
```

test/nftables/filter_input.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2025 The gVisor Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package nftables
16+
17+
import (
18+
"context"
19+
"errors"
20+
"fmt"
21+
"net"
22+
"time"
23+
24+
"gvisor.dev/gvisor/test/netutils"
25+
)
26+
27+
const (
28+
dropPort = 2401
29+
acceptPort = 2402
30+
sendloopDuration = 2 * time.Second
31+
chainName = "foochain"
32+
)
33+
34+
func init() {
35+
RegisterTestCase(&FilterInputDropAll{})
36+
}
37+
38+
// FilterInputDropAll tests that we can drop all traffic to the INPUT chain.
39+
type FilterInputDropAll struct{ containerCase }
40+
41+
var _ TestCase = (*FilterInputDropAll)(nil)
42+
43+
// Name implements TestCase.Name.
44+
func (*FilterInputDropAll) Name() string {
45+
return "FilterInputDropAll"
46+
}
47+
48+
// ContainerAction implements TestCase.ContainerAction.
49+
func (*FilterInputDropAll) ContainerAction(ctx context.Context, ip net.IP, ipv6 bool) error {
50+
if err := createDropAllTable(ipv6, "filterTab"); err != nil {
51+
return err
52+
}
53+
54+
// Listen for all packets on dropPort.
55+
timedCtx, cancel := context.WithTimeout(ctx, NegativeTimeout)
56+
defer cancel()
57+
if err := netutils.ListenUDP(timedCtx, dropPort, ipv6); err == nil {
58+
return fmt.Errorf("packets should have been dropped, but got a packet")
59+
} else if !errors.Is(err, context.DeadlineExceeded) {
60+
return fmt.Errorf("error reading: %v", err)
61+
}
62+
63+
// At this point we know that reading timed out and never received a
64+
// packet.
65+
return nil
66+
}
67+
68+
// LocalAction implements TestCase.LocalAction.
69+
func (*FilterInputDropAll) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) error {
70+
return netutils.SendUDPLoop(ctx, ip, dropPort, ipv6)
71+
}

0 commit comments

Comments
 (0)