Skip to content

Commit 0a8e5cf

Browse files
authored
Merge pull request moby#3738 from tonistiigi/netns-create-lockthread
cni: simplify netns creation
2 parents ca1bf54 + 486430f commit 0a8e5cf

File tree

3 files changed

+30
-58
lines changed

3 files changed

+30
-58
lines changed

util/network/cniprovider/allowempty.s

Whitespace-only changes.

util/network/cniprovider/cni_unsafe.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

util/network/cniprovider/createns_linux.go

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
package cniprovider
55

66
import (
7+
"fmt"
78
"os"
89
"path/filepath"
10+
"runtime"
911
"syscall"
10-
"unsafe"
1112

1213
"github.com/containerd/containerd/oci"
1314
"github.com/moby/buildkit/util/bklog"
@@ -38,63 +39,51 @@ func cleanOldNamespaces(c *cniProvider) {
3839
}()
3940
}
4041

41-
func createNetNS(c *cniProvider, id string) (string, error) {
42+
// unshareAndMount needs to be called in a separate thread
43+
func unshareAndMountNetNS(target string) error {
44+
if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
45+
return err
46+
}
47+
48+
return syscall.Mount(fmt.Sprintf("/proc/self/task/%d/ns/net", syscall.Gettid()), target, "", syscall.MS_BIND, "")
49+
}
50+
51+
func createNetNS(c *cniProvider, id string) (_ string, err error) {
4252
nsPath := filepath.Join(c.root, "net/cni", id)
4353
if err := os.MkdirAll(filepath.Dir(nsPath), 0700); err != nil {
4454
return "", err
4555
}
4656

4757
f, err := os.Create(nsPath)
4858
if err != nil {
49-
deleteNetNS(nsPath)
5059
return "", err
5160
}
61+
defer func() {
62+
if err != nil {
63+
deleteNetNS(nsPath)
64+
}
65+
}()
5266
if err := f.Close(); err != nil {
53-
deleteNetNS(nsPath)
54-
return "", err
55-
}
56-
procNetNSBytes, err := syscall.BytePtrFromString("/proc/self/ns/net")
57-
if err != nil {
58-
deleteNetNS(nsPath)
5967
return "", err
6068
}
61-
nsPathBytes, err := syscall.BytePtrFromString(nsPath)
62-
if err != nil {
63-
deleteNetNS(nsPath)
64-
return "", err
65-
}
66-
beforeFork()
6769

68-
pid, _, errno := syscall.RawSyscall6(syscall.SYS_CLONE, uintptr(syscall.SIGCHLD)|unix.CLONE_NEWNET, 0, 0, 0, 0, 0)
69-
if errno != 0 {
70-
afterFork()
71-
deleteNetNS(nsPath)
72-
return "", errno
73-
}
70+
errCh := make(chan error)
7471

75-
if pid != 0 {
76-
afterFork()
77-
var ws unix.WaitStatus
78-
_, err = unix.Wait4(int(pid), &ws, 0, nil)
79-
for err == syscall.EINTR {
80-
_, err = unix.Wait4(int(pid), &ws, 0, nil)
81-
}
72+
go func() {
73+
defer close(errCh)
74+
runtime.LockOSThread()
8275

83-
if err != nil {
84-
deleteNetNS(nsPath)
85-
return "", errors.Wrapf(err, "failed to find pid=%d process", pid)
76+
if err := unshareAndMountNetNS(nsPath); err != nil {
77+
errCh <- err
8678
}
87-
errno = syscall.Errno(ws.ExitStatus())
88-
if errno != 0 {
89-
deleteNetNS(nsPath)
90-
return "", errors.Wrapf(errno, "failed to mount %s (pid=%d)", nsPath, pid)
91-
}
92-
return nsPath, nil
79+
80+
// we leave the thread locked so go runtime terminates the thread
81+
}()
82+
83+
if err := <-errCh; err != nil {
84+
return "", err
9385
}
94-
afterForkInChild()
95-
_, _, errno = syscall.RawSyscall6(syscall.SYS_MOUNT, uintptr(unsafe.Pointer(procNetNSBytes)), uintptr(unsafe.Pointer(nsPathBytes)), 0, uintptr(unix.MS_BIND), 0, 0)
96-
syscall.RawSyscall(syscall.SYS_EXIT, uintptr(errno), 0, 0)
97-
panic("unreachable")
86+
return nsPath, nil
9887
}
9988

10089
func setNetNS(s *specs.Spec, nsPath string) error {

0 commit comments

Comments
 (0)