diff --git a/libnetwork/sandbox/configure_linux.go b/libnetwork/sandbox/configure_linux.go index 761e016ef4..f3682a2b78 100644 --- a/libnetwork/sandbox/configure_linux.go +++ b/libnetwork/sandbox/configure_linux.go @@ -3,8 +3,11 @@ package sandbox import ( "fmt" "net" + "os" + "runtime" "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" ) func configureInterface(iface netlink.Link, settings *Interface) error { @@ -26,7 +29,28 @@ func configureInterface(iface netlink.Link, settings *Interface) error { return nil } -func setGatewayIP(gw net.IP) error { +func setGatewayIP(path string, gw net.IP) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + origns, err := netns.Get() + if err != nil { + return err + } + defer origns.Close() + + f, err := os.OpenFile(path, os.O_RDONLY, 0) + if err != nil { + return fmt.Errorf("failed get network namespace %q: %v", path, err) + } + defer f.Close() + + nsFD := f.Fd() + if err = netns.Set(netns.NsHandle(nsFD)); err != nil { + return err + } + defer netns.Set(origns) + return netlink.RouteAdd(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, Gw: gw, @@ -39,7 +63,10 @@ func setInterfaceIP(iface netlink.Link, settings *Interface) error { } func setInterfaceIPv6(iface netlink.Link, settings *Interface) error { - ipAddr := &netlink.Addr{IPNet: settings.Address, Label: ""} + if settings.AddressIPv6 == nil { + return nil + } + ipAddr := &netlink.Addr{IPNet: settings.AddressIPv6, Label: ""} return netlink.AddrAdd(iface, ipAddr) } diff --git a/libnetwork/sandbox/namespace_linux.go b/libnetwork/sandbox/namespace_linux.go index 47d5204a5d..76b0b5bf7a 100644 --- a/libnetwork/sandbox/namespace_linux.go +++ b/libnetwork/sandbox/namespace_linux.go @@ -50,11 +50,15 @@ func createNetworkNamespace(path string) (Sandbox, error) { return nil, err } - if err := syscall.Mount("/proc/self/ns/net", path, "bind", syscall.MS_BIND, ""); err != nil { + 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 } - return &networkNamespace{path: path}, nil + interfaces := []*Interface{} + sinfo := &Info{Interfaces: interfaces} + return &networkNamespace{path: path, sinfo: sinfo}, nil } func createNamespaceFile(path string) (err error) { @@ -106,6 +110,11 @@ func (n *networkNamespace) AddInterface(i *Interface) error { } defer netns.Set(origns) + // Down the interface before configuring + if err := netlink.LinkSetDown(iface); err != nil { + return err + } + // Configure the interface now this is moved in the proper namespace. if err := configureInterface(iface, i); err != nil { return err @@ -121,7 +130,7 @@ func (n *networkNamespace) AddInterface(i *Interface) error { } func (n *networkNamespace) SetGateway(gw net.IP) error { - err := setGatewayIP(gw) + err := setGatewayIP(n.path, gw) if err == nil { n.sinfo.Gateway = gw } @@ -130,7 +139,11 @@ func (n *networkNamespace) SetGateway(gw net.IP) error { } func (n *networkNamespace) SetGatewayIPv6(gw net.IP) error { - err := setGatewayIP(gw) + if len(gw) == 0 { + return nil + } + + err := setGatewayIP(n.path, gw) if err == nil { n.sinfo.GatewayIPv6 = gw } diff --git a/libnetwork/sandbox/sandbox.go b/libnetwork/sandbox/sandbox.go index 45405e08a4..254e3417b0 100644 --- a/libnetwork/sandbox/sandbox.go +++ b/libnetwork/sandbox/sandbox.go @@ -28,6 +28,9 @@ type Sandbox interface { // Set default IPv6 gateway for the sandbox SetGatewayIPv6(gw net.IP) error + + // Destroy the sandbox + Destroy() error } // Info represents all possible information that diff --git a/libnetwork/sandbox/sandbox_linux_test.go b/libnetwork/sandbox/sandbox_linux_test.go index c07cb6b2a0..0372399637 100644 --- a/libnetwork/sandbox/sandbox_linux_test.go +++ b/libnetwork/sandbox/sandbox_linux_test.go @@ -1,15 +1,23 @@ package sandbox import ( + "net" "os" "path/filepath" "runtime" "testing" "github.com/docker/libnetwork/netutils" + "github.com/vishvananda/netlink" "github.com/vishvananda/netns" ) +const ( + vethName1 = "wierdlongname1" + vethName2 = "wierdlongname2" + sboxIfaceName = "containername" +) + func newKey(t *testing.T) (string, error) { name, err := netutils.GenerateRandomName("netns", 12) if err != nil { @@ -24,6 +32,42 @@ func newKey(t *testing.T) (string, error) { return name, nil } +func newInfo(t *testing.T) (*Info, error) { + veth := &netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0}, + PeerName: vethName2} + err := netlink.LinkAdd(veth) + if err != nil { + return nil, err + } + + // Store the sandbox side pipe interface + // This is needed for cleanup on DeleteEndpoint() + intf := &Interface{} + intf.SrcName = vethName2 + intf.DstName = sboxIfaceName + + ip4, addr, err := net.ParseCIDR("192.168.1.100/24") + if err != nil { + return nil, err + } + intf.Address = addr + intf.Address.IP = ip4 + + ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48") + if err != nil { + return nil, err + } + intf.AddressIPv6 = addrv6 + intf.AddressIPv6.IP = ip6 + + sinfo := &Info{Interfaces: []*Interface{intf}} + sinfo.Gateway = net.ParseIP("192.168.1.1") + sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1") + + return sinfo, nil +} + func verifySandbox(t *testing.T, s Sandbox) { _, ok := s.(*networkNamespace) if !ok { @@ -49,6 +93,11 @@ func verifySandbox(t *testing.T, s Sandbox) { if err = netns.Set(netns.NsHandle(nsFD)); err != nil { t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", s.Key(), err) } + defer netns.Set(origns) - netns.Set(origns) + _, err = netlink.LinkByName(sboxIfaceName) + if err != nil { + t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName, + err) + } } diff --git a/libnetwork/sandbox/sandbox_test.go b/libnetwork/sandbox/sandbox_test.go index 460ac30181..e803a8fe8d 100644 --- a/libnetwork/sandbox/sandbox_test.go +++ b/libnetwork/sandbox/sandbox_test.go @@ -20,7 +20,30 @@ func TestSandboxCreate(t *testing.T) { t.Fatalf("s.Key() returned %s. Expected %s", s.Key(), key) } + info, err := newInfo(t) + if err != nil { + t.Fatalf("Failed to generate new sandbox info: %v", err) + } + + for _, i := range info.Interfaces { + err = s.AddInterface(i) + if err != nil { + t.Fatalf("Failed to add interfaces to sandbox: %v", err) + } + } + + err = s.SetGateway(info.Gateway) + if err != nil { + t.Fatalf("Failed to set gateway to sandbox: %v", err) + } + + err = s.SetGatewayIPv6(info.GatewayIPv6) + if err != nil { + t.Fatalf("Failed to set ipv6 gateway to sandbox: %v", err) + } + verifySandbox(t, s) + s.Destroy() } func TestInterfaceEqual(t *testing.T) {