Skip to content

Commit 008d17a

Browse files
committed
Fix handling of namespaces in multi-threaded processes.
GetFromPid gets the namespace of the main thread, so previously Get returned the wrong value if run from any other thread. Add a new GetFromThread which uses the Linux thread id and switch Get to it.
1 parent e14a2d4 commit 008d17a

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

netns_linux.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func New() (ns NsHandle, err error) {
4747

4848
// Get gets a handle to the current threads network namespace.
4949
func Get() (NsHandle, error) {
50-
return GetFromPid(os.Getpid())
50+
return GetFromThread(os.Getpid(), syscall.Gettid())
5151
}
5252

5353
// GetFromName gets a handle to a named network namespace such as one
@@ -60,7 +60,7 @@ func GetFromName(name string) (NsHandle, error) {
6060
return NsHandle(fd), nil
6161
}
6262

63-
// GetFromName gets a handle to the network namespace of a given pid.
63+
// GetFromPid gets a handle to the network namespace of a given pid.
6464
func GetFromPid(pid int) (NsHandle, error) {
6565
fd, err := syscall.Open(fmt.Sprintf("/proc/%d/ns/net", pid), syscall.O_RDONLY, 0)
6666
if err != nil {
@@ -69,7 +69,17 @@ func GetFromPid(pid int) (NsHandle, error) {
6969
return NsHandle(fd), nil
7070
}
7171

72-
// GetFromName gets a handle to the network namespace of a docker container.
72+
// GetFromThread gets a handle to the network namespace of a given pid and tid.
73+
func GetFromThread(pid, tid int) (NsHandle, error) {
74+
name := fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid)
75+
fd, err := syscall.Open(name, syscall.O_RDONLY, 0)
76+
if err != nil {
77+
return -1, err
78+
}
79+
return NsHandle(fd), nil
80+
}
81+
82+
// GetFromDocker gets a handle to the network namespace of a docker container.
7383
// Id is prefixed matched against the running docker containers, so a short
7484
// identifier can be used as long as it isn't ambiguous.
7585
func GetFromDocker(id string) (NsHandle, error) {
@@ -169,7 +179,7 @@ func getPidForContainer(id string) (int, error) {
169179
return pid, fmt.Errorf("Ambiguous id supplied: %v", filenames)
170180
} else if len(filenames) == 1 {
171181
filename = filenames[0]
172-
break;
182+
break
173183
}
174184
}
175185

netns_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package netns
22

33
import (
44
"runtime"
5+
"sync"
56
"testing"
67
)
78

@@ -42,3 +43,24 @@ func TestNone(t *testing.T) {
4243
t.Fatal("None ns is open", ns)
4344
}
4445
}
46+
47+
func TestThreaded(t *testing.T) {
48+
ncpu := runtime.GOMAXPROCS(-1)
49+
if ncpu < 2 {
50+
t.Skip("-cpu=2 or larger required")
51+
}
52+
53+
// Lock this thread simply to ensure other threads get used.
54+
runtime.LockOSThread()
55+
defer runtime.UnlockOSThread()
56+
57+
wg := &sync.WaitGroup{}
58+
for i := 0; i < ncpu; i++ {
59+
wg.Add(1)
60+
go func() {
61+
defer wg.Done()
62+
TestGetNewSetDelete(t)
63+
}()
64+
}
65+
wg.Wait()
66+
}

0 commit comments

Comments
 (0)