Vendoring in libnetwork 2da2dc055de5a474c8540871ad88a48213b0994f

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-05-26 22:29:17 +00:00
parent f5d3311839
commit d429465b37
4 changed files with 113 additions and 24 deletions

View File

@ -55,7 +55,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0
clone hg code.google.com/p/gosqlite 74691fb6f837 clone hg code.google.com/p/gosqlite 74691fb6f837
#get libnetwork packages #get libnetwork packages
clone git github.com/docker/libnetwork 67438080724b17b641b411322822c00d0d3c3201 clone git github.com/docker/libnetwork 2da2dc055de5a474c8540871ad88a48213b0994f
clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6 clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6
clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c

View File

@ -4,17 +4,27 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"os/exec"
"runtime" "runtime"
"sync" "sync"
"syscall" "syscall"
"time"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/reexec"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"github.com/vishvananda/netns" "github.com/vishvananda/netns"
) )
const prefix = "/var/run/docker/netns" const prefix = "/var/run/docker/netns"
var once sync.Once var (
once sync.Once
garbagePathMap = make(map[string]bool)
gpmLock sync.Mutex
gpmWg sync.WaitGroup
gpmCleanupPeriod = 60 * time.Second
)
// The networkNamespace type is the linux implementation of the Sandbox // The networkNamespace type is the linux implementation of the Sandbox
// interface. It represents a linux network namespace, and moves an interface // interface. It represents a linux network namespace, and moves an interface
@ -26,11 +36,49 @@ type networkNamespace struct {
sync.Mutex sync.Mutex
} }
func init() {
reexec.Register("netns-create", reexecCreateNamespace)
}
func createBasePath() { func createBasePath() {
err := os.MkdirAll(prefix, 0644) err := os.MkdirAll(prefix, 0644)
if err != nil && !os.IsExist(err) { if err != nil && !os.IsExist(err) {
panic("Could not create net namespace path directory") panic("Could not create net namespace path directory")
} }
// Start the garbage collection go routine
go removeUnusedPaths()
}
func removeUnusedPaths() {
for range time.Tick(gpmCleanupPeriod) {
gpmLock.Lock()
pathList := make([]string, 0, len(garbagePathMap))
for path := range garbagePathMap {
pathList = append(pathList, path)
}
garbagePathMap = make(map[string]bool)
gpmWg.Add(1)
gpmLock.Unlock()
for _, path := range pathList {
os.Remove(path)
}
gpmWg.Done()
}
}
func addToGarbagePaths(path string) {
gpmLock.Lock()
garbagePathMap[path] = true
gpmLock.Unlock()
}
func removeFromGarbagePaths(path string) {
gpmLock.Lock()
delete(garbagePathMap, path)
gpmLock.Unlock()
} }
// GenerateKey generates a sandbox key based on the passed // GenerateKey generates a sandbox key based on the passed
@ -55,6 +103,20 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
return &networkNamespace{path: key, sinfo: info}, nil return &networkNamespace{path: key, sinfo: info}, nil
} }
func reexecCreateNamespace() {
if len(os.Args) < 2 {
log.Fatal("no namespace path provided")
}
if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
log.Fatal(err)
}
if err := loopbackUp(); err != nil {
log.Fatal(err)
}
}
func createNetworkNamespace(path string, osCreate bool) (*Info, error) { func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
@ -69,23 +131,18 @@ func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
return nil, err return nil, err
} }
cmd := &exec.Cmd{
Path: reexec.Self(),
Args: append([]string{"netns-create"}, path),
Stdout: os.Stdout,
Stderr: os.Stderr,
}
if osCreate { if osCreate {
defer netns.Set(origns) cmd.SysProcAttr = &syscall.SysProcAttr{}
newns, err := netns.New() cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNET
if err != nil {
return nil, err
} }
defer newns.Close() if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("namespace creation reexec command failed: %v", err)
if err := loopbackUp(); err != nil {
return nil, err
}
}
procNet := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())
if err := syscall.Mount(procNet, path, "bind", syscall.MS_BIND, ""); err != nil {
return nil, err
} }
interfaces := []*Interface{} interfaces := []*Interface{}
@ -93,10 +150,9 @@ func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
return info, nil return info, nil
} }
func cleanupNamespaceFile(path string) { func unmountNamespaceFile(path string) {
if _, err := os.Stat(path); err == nil { if _, err := os.Stat(path); err == nil {
n := &networkNamespace{path: path} syscall.Unmount(path, syscall.MNT_DETACH)
n.Destroy()
} }
} }
@ -104,11 +160,20 @@ func createNamespaceFile(path string) (err error) {
var f *os.File var f *os.File
once.Do(createBasePath) once.Do(createBasePath)
// cleanup namespace file if it already exists because of a previous ungraceful exit. // Remove it from garbage collection list if present
cleanupNamespaceFile(path) removeFromGarbagePaths(path)
// If the path is there unmount it first
unmountNamespaceFile(path)
// wait for garbage collection to complete if it is in progress
// before trying to create the file.
gpmWg.Wait()
if f, err = os.Create(path); err == nil { if f, err = os.Create(path); err == nil {
f.Close() f.Close()
} }
return err return err
} }
@ -269,5 +334,7 @@ func (n *networkNamespace) Destroy() error {
return err return err
} }
return os.Remove(n.path) // Stash it into the garbage collection list
addToGarbagePaths(n.path)
return nil
} }

View File

@ -6,6 +6,7 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"testing" "testing"
"time"
"github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/netutils"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
@ -31,6 +32,9 @@ func newKey(t *testing.T) (string, error) {
return "", err return "", err
} }
// Set the rpmCleanupPeriod to be low to make the test run quicker
gpmCleanupPeriod = 2 * time.Second
return name, nil return name, nil
} }
@ -137,3 +141,10 @@ func verifySandbox(t *testing.T, s Sandbox) {
err) err)
} }
} }
func verifyCleanup(t *testing.T, s Sandbox) {
time.Sleep(time.Duration(gpmCleanupPeriod * 2))
if _, err := os.Stat(s.Key()); err == nil {
t.Fatalf("The sandbox path %s is not getting cleanup event after twice the cleanup period", s.Key())
}
}

View File

@ -2,9 +2,19 @@ package sandbox
import ( import (
"net" "net"
"os"
"testing" "testing"
"github.com/docker/docker/pkg/reexec"
) )
func TestMain(m *testing.M) {
if reexec.Init() {
return
}
os.Exit(m.Run())
}
func TestSandboxCreate(t *testing.T) { func TestSandboxCreate(t *testing.T) {
key, err := newKey(t) key, err := newKey(t)
if err != nil { if err != nil {
@ -44,6 +54,7 @@ func TestSandboxCreate(t *testing.T) {
verifySandbox(t, s) verifySandbox(t, s)
s.Destroy() s.Destroy()
verifyCleanup(t, s)
} }
func TestSandboxCreateTwice(t *testing.T) { func TestSandboxCreateTwice(t *testing.T) {