Skip to content

Commit 99b2c78

Browse files
authored
Merge pull request #379 from AkihiroSuda/carry-362
[Carry 362] support detach-netns
2 parents 3f63619 + 9874e7d commit 99b2c78

File tree

21 files changed

+278
-93
lines changed

21 files changed

+278
-93
lines changed

.github/workflows/main.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,20 @@ jobs:
4848
run: |
4949
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
5050
rootlesskit:test-integration ./benchmark-iperf3-net.sh slirp4netns 1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto
51+
- name: "Benchmark: Network (MTU=1500, network driver=slirp4netns with sandbox and seccomp) with detach-netns"
52+
run: |
53+
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
54+
rootlesskit:test-integration ./benchmark-iperf3-net.sh slirp4netns 1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --detach-netns
5155
# NOTE: MTU greater than 16424 is known not to work for VPNKit.
5256
# Also, MTU greather than 4K might not be effective for VPNKit: https://twitter.com/mugofsoup/status/1017665057738641408
5357
- name: "Benchmark: Network (MTU=1500, network driver=vpnkit)"
5458
run: |
5559
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
5660
rootlesskit:test-integration ./benchmark-iperf3-net.sh vpnkit 1500
61+
- name: "Benchmark: Network (MTU=1500, network driver=vpnkit) with detach-netns"
62+
run: |
63+
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
64+
rootlesskit:test-integration ./benchmark-iperf3-net.sh vpnkit 1500 --detach-netns
5765
- name: "Benchmark: Network (MTU=1500, network driver=lxc-user-nic)"
5866
run: |
5967
docker run --rm --privileged \
@@ -84,15 +92,35 @@ jobs:
8492
run: |
8593
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
8694
rootlesskit:test-integration ./benchmark-iperf3-port.sh slirp4netns
95+
- name: "Benchmark: TCP Ports (port driver=slirp4netns) with detach-netns"
96+
run: |
97+
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
98+
rootlesskit:test-integration ./benchmark-iperf3-port.sh slirp4netns --detach-netns
8799
- name: "Benchmark: TCP Ports (port driver=builtin)"
88100
run: |
89101
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
90102
rootlesskit:test-integration ./benchmark-iperf3-port.sh builtin
103+
- name: "Benchmark: TCP Ports (port driver=builtin) with detach-netns"
104+
run: |
105+
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
106+
rootlesskit:test-integration ./benchmark-iperf3-port.sh builtin --detach-netns
91107
# ===== Benchmark: UDP Ports =====
108+
- name: "Benchmark: UDP Ports (port driver=slirp4netns)"
109+
run: |
110+
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
111+
rootlesskit:test-integration ./benchmark-iperf3-port-udp.sh slirp4netns
112+
- name: "Benchmark: UDP Ports (port driver=slirp4netns) with detach-netns"
113+
run: |
114+
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
115+
rootlesskit:test-integration ./benchmark-iperf3-port-udp.sh slirp4netns --detach-netns
92116
- name: "Benchmark: UDP Ports (port driver=builtin)"
93117
run: |
94118
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
95119
rootlesskit:test-integration ./benchmark-iperf3-port-udp.sh builtin
120+
- name: "Benchmark: UDP Ports (port driver=builtin) with detach-netns"
121+
run: |
122+
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined --device /dev/net/tun \
123+
rootlesskit:test-integration ./benchmark-iperf3-port-udp.sh builtin --detach-netns
96124
test-integration-docker:
97125
name: "Integration test (Docker)"
98126
runs-on: ubuntu-latest

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ The following files will be created in the state directory, which can be specifi
234234
* `lock`: lock file
235235
* `child_pid`: decimal PID text that can be used for `nsenter(1)`.
236236
* `api.sock`: REST API socket. See [`./docs/api.md`](./docs/api.md) and [`./docs/port.md`](./docs/port.md).
237+
* `netns`: Detached NetNS. Created only with `--detach-netns`. Valid only in the child mount namespace.
237238

238239
If `--state-dir` is not specified, RootlessKit creates a temporary state directory on `/tmp` and removes it on exit.
239240

cmd/rootlesskit/main.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ See https://rootlesscontaine.rs/getting-started/common/ .
166166
Name: "ipcns",
167167
Usage: "create an IPC namespace",
168168
}, CategoryProcess),
169+
Categorize(&cli.BoolFlag{
170+
Name: "detach-netns",
171+
Usage: "detach network namespaces ",
172+
}, CategoryNetwork),
169173
Categorize(&cli.StringFlag{
170174
Name: "propagation",
171175
Usage: "mount propagation [rprivate, rslave]",
@@ -280,6 +284,7 @@ func createParentOpt(clicontext *cli.Context, pipeFDEnvKey, stateDirEnvKey, pare
280284
CreateCgroupNS: clicontext.Bool("cgroupns"),
281285
CreateUTSNS: clicontext.Bool("utsns"),
282286
CreateIPCNS: clicontext.Bool("ipcns"),
287+
DetachNetNS: clicontext.Bool("detach-netns"),
283288
ParentEUIDEnvKey: parentEUIDEnvKey,
284289
ParentEGIDEnvKey: parentEGIDEnvKey,
285290
Propagation: clicontext.String("propagation"),
@@ -375,15 +380,21 @@ func createParentOpt(clicontext *cli.Context, pipeFDEnvKey, stateDirEnvKey, pare
375380
enableSandbox := false
376381
switch s := clicontext.String("slirp4netns-sandbox"); s {
377382
case "auto":
378-
// this might not work when /etc/resolv.conf is a symlink to a file outside /etc or /run
383+
// Sandbox might not work when /etc/resolv.conf is a symlink to a file outside /etc or /run
379384
// https://github.com/rootless-containers/slirp4netns/issues/116
380-
enableSandbox = features.SupportsEnableSandbox
385+
386+
// Sandbox is known to be incompatible with detach-netns
387+
// https://github.com/rootless-containers/slirp4netns/issues/317
388+
enableSandbox = features.SupportsEnableSandbox && !opt.DetachNetNS
381389
case "true":
382390
enableSandbox = true
383391
if !features.SupportsEnableSandbox {
384392
// NOTREACHED
385393
return opt, errors.New("unsupported slirp4netns version: lacks SupportsEnableSandbox")
386394
}
395+
if opt.DetachNetNS {
396+
return opt, errors.New("--slirp4netns-sandbox conflicts with --detach-netns (https://github.com/rootless-containers/slirp4netns/issues/317)")
397+
}
387398
case "false", "": // default
388399
// NOP
389400
default:
@@ -492,11 +503,13 @@ func (w *logrusDebugWriter) Write(p []byte) (int, error) {
492503

493504
func createChildOpt(clicontext *cli.Context, pipeFDEnvKey, stateDirEnvKey string, targetCmd []string) (child.Opt, error) {
494505
pidns := clicontext.Bool("pidns")
506+
detachNetNS := clicontext.Bool("detach-netns")
495507
opt := child.Opt{
496508
PipeFDEnvKey: pipeFDEnvKey,
497509
StateDirEnvKey: stateDirEnvKey,
498510
TargetCmd: targetCmd,
499511
MountProcfs: pidns,
512+
DetachNetNS: detachNetNS,
500513
Propagation: clicontext.String("propagation"),
501514
EvacuateCgroup2: clicontext.String("evacuate-cgroup2") != "",
502515
}

docs/internal.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Common:
55
- `lock`
66
- `child_pid`
77
- `api.sock`
8+
- `netns` (detached netns)
89

910
Network driver `slirp4netns`:
1011
- `.s4nn.sock`

docs/network.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ Cons:
151151
* Less secure
152152
* Needs `/etc/lxc/lxc-usernet` configuration
153153
* No support for IPv6.
154+
* No support for `--detach-netns`
154155

155156
To use `lxc-user-nic`, you need to install `liblxc-common` package:
156157
```console
@@ -176,3 +177,9 @@ Currently, the MAC address is always set to a random address.
176177

177178
The `--ipv6` flag (since v0.14.0, EXPERIMENTAL) enables IPv6 routing for slirp4netns network driver.
178179
This flag is unrelated to port forwarding.
180+
181+
## Detaching network namespace
182+
The `--detach-netns` flag (since v2.0.0) detaches network namespaces into `$ROOTLESSKIT_STATE_DIR/netns`
183+
and executes the child command in the host's network namespace.
184+
185+
The child command can enter `$ROOTLESSKIT_STATE_DIR/netns` by itself to create nested network namespaces.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/rootless-containers/rootlesskit
33
go 1.19
44

55
require (
6+
github.com/containernetworking/plugins v1.3.0
67
github.com/gofrs/flock v0.8.1
78
github.com/google/uuid v1.3.0
89
github.com/gorilla/mux v1.8.0

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1+
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
2+
github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q6mVDp5H1HnjM=
3+
github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0=
14
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
25
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
36
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
47
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
58
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9+
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
10+
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
611
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
712
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
813
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
914
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
1015
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
16+
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk=
1117
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
1218
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
1319
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
@@ -21,6 +27,8 @@ github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vyg
2127
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
2228
github.com/moby/vpnkit v0.5.0 h1:VcDpS9y+PmT9itf+mH5Qdh9GME7ungLMt9yjf9o4REY=
2329
github.com/moby/vpnkit v0.5.0/go.mod h1:KyjUrL9cb6ZSNNAUwZfqRjhwwgJ3BJN+kXh0t43WTUQ=
30+
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
31+
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
2432
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
2533
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
2634
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
@@ -64,9 +72,11 @@ golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
6472
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6573
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
6674
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
75+
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
6776
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
6877
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
6978
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
79+
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
7080
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
7181
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
7282
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

hack/benchmark-iperf3-net.sh

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,38 @@
22
source $(realpath $(dirname $0))/common.inc.sh
33
function benchmark::iperf3::slirp4netns() {
44
INFO "[benchmark:iperf3] slirp4netns ($@)"
5+
statedir=$(mktemp -d)
6+
if echo "$@" | grep -q -- --detach-netns; then
7+
IPERF3C="nsenter -n${statedir}/netns $IPERF3C"
8+
fi
59
set -x
6-
$ROOTLESSKIT --net=slirp4netns $@ -- $IPERF3C 10.0.2.2
10+
$ROOTLESSKIT --state-dir=$statedir --net=slirp4netns $@ -- $IPERF3C 10.0.2.2
711
set +x
812
}
913

1014
function benchmark::iperf3::vpnkit() {
1115
INFO "[benchmark:iperf3] vpnkit ($@)"
16+
statedir=$(mktemp -d)
17+
if echo "$@" | grep -q -- --detach-netns; then
18+
IPERF3C="nsenter -n${statedir}/netns $IPERF3C"
19+
fi
1220
set -x
13-
$ROOTLESSKIT --net=vpnkit $@ -- $IPERF3C 192.168.65.2
21+
$ROOTLESSKIT --state-dir=$statedir --net=vpnkit $@ -- $IPERF3C 192.168.65.2
1422
set +x
1523
}
1624

1725
function benchmark::iperf3::lxc-user-nic() {
1826
INFO "[benchmark:iperf3] lxc-user-nic ($@)"
27+
statedir=$(mktemp -d)
28+
if echo "$@" | grep -q -- --detach-netns; then
29+
IPERF3C="nsenter -n${statedir}/netns $IPERF3C"
30+
fi
1931
dev=lxcbr0
2032
set -x
2133
# ignore "lxc-net is already running" error
2234
sudo /usr/lib/$(uname -m)-linux-gnu/lxc/lxc-net start || true
2335
ip=$(ip -4 -o addr show $dev | awk '{print $4}' | cut -d "/" -f 1)
24-
$ROOTLESSKIT --net=lxc-user-nic $@ -- $IPERF3C $ip
36+
$ROOTLESSKIT --state-dir=$statedir --net=lxc-user-nic $@ -- $IPERF3C $ip
2537
set +x
2638
}
2739

hack/benchmark-iperf3-port-udp.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ source $(realpath $(dirname $0))/common.inc.sh
33
function benchmark::iperf3::port::udp() {
44
statedir=$(mktemp -d)
55
INFO "[benchmark:iperf3::port::udp] $@"
6-
$ROOTLESSKIT --state-dir=$statedir $@ iperf3 -s >/dev/null &
6+
IPERF3="iperf3"
7+
if echo "$@" | grep -q -- --detach-netns; then
8+
IPERF3="nsenter -n${statedir}/netns $IPERF3"
9+
fi
10+
$ROOTLESSKIT --state-dir=$statedir $@ $IPERF3 -s >/dev/null &
711
rkpid=$!
812
# wait for socket to be available
913
sleep 3

hack/benchmark-iperf3-port.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ source $(realpath $(dirname $0))/common.inc.sh
33
function benchmark::iperf3::port() {
44
statedir=$(mktemp -d)
55
INFO "[benchmark:iperf3::port] $@"
6-
$ROOTLESSKIT --state-dir=$statedir $@ iperf3 -s >/dev/null &
6+
IPERF3="iperf3"
7+
if echo "$@" | grep -q -- --detach-netns; then
8+
IPERF3="nsenter -n${statedir}/netns $IPERF3"
9+
fi
10+
$ROOTLESSKIT --state-dir=$statedir $@ $IPERF3 -s >/dev/null &
711
rkpid=$!
812
# wait for socket to be available
913
sleep 3

0 commit comments

Comments
 (0)