|
@@ -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
|
|
}
|
|
}
|