Skip to content

Commit

Permalink
Fix handling of namespaces in multi-threaded processes.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
marineam committed Jan 27, 2015
1 parent e14a2d4 commit 008d17a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
18 changes: 14 additions & 4 deletions netns_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func New() (ns NsHandle, err error) {

// Get gets a handle to the current threads network namespace.
func Get() (NsHandle, error) {
return GetFromPid(os.Getpid())
return GetFromThread(os.Getpid(), syscall.Gettid())
}

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

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

// GetFromName gets a handle to the network namespace of a docker container.
// GetFromThread gets a handle to the network namespace of a given pid and tid.
func GetFromThread(pid, tid int) (NsHandle, error) {
name := fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid)
fd, err := syscall.Open(name, syscall.O_RDONLY, 0)
if err != nil {
return -1, err
}
return NsHandle(fd), nil
}

// GetFromDocker gets a handle to the network namespace of a docker container.
// Id is prefixed matched against the running docker containers, so a short
// identifier can be used as long as it isn't ambiguous.
func GetFromDocker(id string) (NsHandle, error) {
Expand Down Expand Up @@ -169,7 +179,7 @@ func getPidForContainer(id string) (int, error) {
return pid, fmt.Errorf("Ambiguous id supplied: %v", filenames)
} else if len(filenames) == 1 {
filename = filenames[0]
break;
break
}
}

Expand Down
22 changes: 22 additions & 0 deletions netns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package netns

import (
"runtime"
"sync"
"testing"
)

Expand Down Expand Up @@ -42,3 +43,24 @@ func TestNone(t *testing.T) {
t.Fatal("None ns is open", ns)
}
}

func TestThreaded(t *testing.T) {
ncpu := runtime.GOMAXPROCS(-1)
if ncpu < 2 {
t.Skip("-cpu=2 or larger required")
}

// Lock this thread simply to ensure other threads get used.
runtime.LockOSThread()
defer runtime.UnlockOSThread()

wg := &sync.WaitGroup{}
for i := 0; i < ncpu; i++ {
wg.Add(1)
go func() {
defer wg.Done()
TestGetNewSetDelete(t)
}()
}
wg.Wait()
}

0 comments on commit 008d17a

Please sign in to comment.