瀏覽代碼

Reimplement create namespace and move interafec to ns without reexec
This removes the dependency on reexec so that libnetwork can be used
as a library.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>

Jana Radhakrishnan 10 年之前
父節點
當前提交
694c5ee788
共有 4 個文件被更改,包括 91 次插入179 次删除
  1. 91 4
      libnetwork/namespace.go
  2. 0 45
      libnetwork/reexec.go
  3. 0 78
      libnetwork/reexec_move_interface.go
  4. 0 52
      libnetwork/reexec_netns_create.go

+ 91 - 4
libnetwork/namespace.go

@@ -1,6 +1,14 @@
 package libnetwork
 package libnetwork
 
 
-import "syscall"
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"syscall"
+
+	"github.com/vishvananda/netlink"
+	"github.com/vishvananda/netns"
+)
 
 
 // The networkNamespace type is the default implementation of the Namespace
 // The networkNamespace type is the default implementation of the Namespace
 // interface. It simply creates a new network namespace, and moves an interface
 // interface. It simply creates a new network namespace, and moves an interface
@@ -11,17 +19,96 @@ type networkNamespace struct {
 }
 }
 
 
 func createNetworkNamespace(path string) (Namespace, error) {
 func createNetworkNamespace(path string) (Namespace, error) {
-	if err := reexec(cmdReexecCreateNamespace, path); err != nil {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	origns, err := netns.Get()
+	if err != nil {
+		return nil, err
+	}
+	defer origns.Close()
+
+	if err := createNamespaceFile(path); err != nil {
+		return nil, err
+	}
+
+	defer netns.Set(origns)
+	newns, err := netns.New()
+	if err != nil {
+		return nil, err
+	}
+	defer newns.Close()
+
+	if err := loopbackUp(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+
+	if err := syscall.Mount("/proc/self/ns/net", path, "bind", syscall.MS_BIND, ""); err != nil {
+		return nil, err
+	}
+
 	return &networkNamespace{path: path}, nil
 	return &networkNamespace{path: path}, nil
 }
 }
 
 
+func createNamespaceFile(path string) (err error) {
+	var f *os.File
+	if f, err = os.Create(path); err == nil {
+		f.Close()
+	}
+	return err
+}
+
+func loopbackUp() error {
+	iface, err := netlink.LinkByName("lo")
+	if err != nil {
+		return err
+	}
+	return netlink.LinkSetUp(iface)
+}
+
 func (n *networkNamespace) AddInterface(i *Interface) error {
 func (n *networkNamespace) AddInterface(i *Interface) error {
-	// TODO Open pipe, pass fd to child and write serialized Interface on it.
-	if err := reexec(cmdReexecMoveInterface, i.SrcName, i.DstName); err != nil {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	origns, err := netns.Get()
+	if err != nil {
+		return err
+	}
+	defer origns.Close()
+
+	f, err := os.OpenFile(n.path, os.O_RDONLY, 0)
+	if err != nil {
+		return fmt.Errorf("failed get network namespace %q: %v", n.path, err)
+	}
+	defer f.Close()
+
+	// Find the network inteerface identified by the SrcName attribute.
+	iface, err := netlink.LinkByName(i.SrcName)
+	if err != nil {
+		return err
+	}
+
+	// Move the network interface to the destination namespace.
+	nsFD := f.Fd()
+	if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
 		return err
 		return err
 	}
 	}
+
+	if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
+		return err
+	}
+	defer netns.Set(origns)
+
+	// Configure the interface now this is moved in the proper namespace.
+	if err := configureInterface(iface, i); err != nil {
+		return err
+	}
+
+	// Up the interface.
+	if err := netlink.LinkSetUp(iface); err != nil {
+		return err
+	}
+
 	n.interfaces = append(n.interfaces, i)
 	n.interfaces = append(n.interfaces, i)
 	return nil
 	return nil
 }
 }

+ 0 - 45
libnetwork/reexec.go

@@ -1,45 +0,0 @@
-package libnetwork
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-
-	dre "github.com/docker/docker/pkg/reexec"
-)
-
-type reexecCommand int
-
-const (
-	cmdReexecCreateNamespace reexecCommand = iota
-	cmdReexecMoveInterface
-)
-
-var reexecCommands = map[reexecCommand]struct {
-	Key        string
-	Entrypoint func()
-}{
-	cmdReexecCreateNamespace: {"netns-create", reexecCreateNamespace},
-	cmdReexecMoveInterface:   {"netns-moveif", reexecMoveInterface},
-}
-
-func init() {
-	for _, reexecCmd := range reexecCommands {
-		dre.Register(reexecCmd.Key, reexecCmd.Entrypoint)
-	}
-}
-
-func reexec(command reexecCommand, params ...string) error {
-	reexecCommand, ok := reexecCommands[command]
-	if !ok {
-		return fmt.Errorf("unknown reexec command %q", command)
-	}
-
-	cmd := &exec.Cmd{
-		Path:   dre.Self(),
-		Args:   append([]string{reexecCommand.Key}, params...),
-		Stdout: os.Stdout,
-		Stderr: os.Stderr,
-	}
-	return cmd.Run()
-}

+ 0 - 78
libnetwork/reexec_move_interface.go

@@ -1,78 +0,0 @@
-package libnetwork
-
-import (
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"runtime"
-	"syscall"
-
-	"github.com/vishvananda/netlink"
-)
-
-type setupError struct {
-	Message string
-}
-
-func (s setupError) Error() string {
-	return s.Message
-}
-
-func reexecMoveInterface() {
-	runtime.LockOSThread()
-
-	var (
-		err  error
-		pipe = os.NewFile(3, "child")
-	)
-
-	defer func() {
-		if err != nil {
-			ioutil.ReadAll(pipe)
-			if err := json.NewEncoder(pipe).Encode(setupError{Message: err.Error()}); err != nil {
-				panic(err)
-			}
-		}
-		pipe.Close()
-	}()
-
-	n := &Interface{}
-	if err = json.NewDecoder(pipe).Decode(n); err == nil {
-		err = setupInNS(os.Args[1], n)
-	}
-}
-
-func setupInNS(nsPath string, settings *Interface) error {
-	f, err := os.OpenFile(nsPath, os.O_RDONLY, 0)
-	if err != nil {
-		return fmt.Errorf("failed get network namespace %q: %v", nsPath, err)
-	}
-
-	// Find the network inteerface identified by the SrcName attribute.
-	iface, err := netlink.LinkByName(settings.SrcName)
-	if err != nil {
-		return err
-	}
-
-	// Move the network interface to the destination namespace.
-	nsFD := f.Fd()
-	if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
-		return err
-	}
-	f.Close()
-
-	// Move the executing code to the destination namespace so we can start
-	// configure the interface.
-	if err := setns(nsFD, syscall.CLONE_NEWNET); err != nil {
-		return err
-	}
-
-	// Configure the interface now this is moved in the proper namespace.
-	if err := configureInterface(iface, settings); err != nil {
-		return err
-	}
-
-	// Up the interface.
-	return netlink.LinkSetUp(iface)
-}

+ 0 - 52
libnetwork/reexec_netns_create.go

@@ -1,52 +0,0 @@
-package libnetwork
-
-import (
-	"os"
-	"runtime"
-	"syscall"
-
-	log "github.com/Sirupsen/logrus"
-	"github.com/vishvananda/netlink"
-)
-
-func reexecCreateNamespace() {
-	runtime.LockOSThread()
-
-	if len(os.Args) < 2 {
-		log.Fatalf("no namespace path provided")
-	}
-
-	if err := createNamespaceFile(os.Args[1]); err != nil {
-		log.Fatal(err)
-	}
-
-	if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
-		log.Fatal(err)
-	}
-
-	if err := loopbackUp(); err != nil {
-		log.Fatal(err)
-	}
-
-	if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
-		log.Fatal(err)
-	}
-
-	os.Exit(0)
-}
-
-func createNamespaceFile(path string) (err error) {
-	var f *os.File
-	if f, err = os.Create(path); err == nil {
-		f.Close()
-	}
-	return err
-}
-
-func loopbackUp() error {
-	iface, err := netlink.LinkByName("lo")
-	if err != nil {
-		return err
-	}
-	return netlink.LinkSetUp(iface)
-}