Просмотр исходного кода

Merge pull request #1174 from aboch/hnd-migr

Migrate libnetwork to use netlink.Handle
Madhu Venugopal 9 лет назад
Родитель
Сommit
bb4798d669
37 измененных файлов с 592 добавлено и 486 удалено
  1. 30 21
      libnetwork/drivers/bridge/bridge.go
  2. 1 1
      libnetwork/drivers/bridge/bridge_store.go
  3. 29 7
      libnetwork/drivers/bridge/bridge_test.go
  4. 14 8
      libnetwork/drivers/bridge/interface.go
  5. 10 2
      libnetwork/drivers/bridge/interface_test.go
  6. 7 5
      libnetwork/drivers/bridge/setup_device.go
  7. 24 6
      libnetwork/drivers/bridge/setup_device_test.go
  8. 14 2
      libnetwork/drivers/bridge/setup_ip_tables_test.go
  9. 2 2
      libnetwork/drivers/bridge/setup_ipv4.go
  10. 17 5
      libnetwork/drivers/bridge/setup_ipv4_test.go
  11. 1 1
      libnetwork/drivers/bridge/setup_ipv6.go
  12. 15 3
      libnetwork/drivers/bridge/setup_ipv6_test.go
  13. 4 2
      libnetwork/drivers/bridge/setup_verify.go
  14. 6 2
      libnetwork/drivers/bridge/setup_verify_test.go
  15. 3 3
      libnetwork/drivers/ipvlan/ipvlan_endpoint.go
  16. 2 1
      libnetwork/drivers/ipvlan/ipvlan_joinleave.go
  17. 14 13
      libnetwork/drivers/ipvlan/ipvlan_setup.go
  18. 3 3
      libnetwork/drivers/macvlan/macvlan_endpoint.go
  19. 2 1
      libnetwork/drivers/macvlan/macvlan_joinleave.go
  20. 14 13
      libnetwork/drivers/macvlan/macvlan_setup.go
  21. 8 6
      libnetwork/drivers/overlay/joinleave.go
  22. 5 3
      libnetwork/drivers/overlay/ov_endpoint.go
  23. 8 7
      libnetwork/drivers/overlay/ov_network.go
  24. 13 23
      libnetwork/drivers/overlay/ov_utils.go
  25. 8 40
      libnetwork/libnetwork_test.go
  26. 15 7
      libnetwork/netutils/utils_linux.go
  27. 1 5
      libnetwork/netutils/utils_test.go
  28. 24 3
      libnetwork/ns/init_linux.go
  29. 114 121
      libnetwork/osl/interface_linux.go
  30. 53 27
      libnetwork/osl/namespace_linux.go
  31. 67 59
      libnetwork/osl/neigh_linux.go
  32. 39 45
      libnetwork/osl/route_linux.go
  33. 18 25
      libnetwork/osl/sandbox_linux_test.go
  34. 3 12
      libnetwork/osl/sandbox_test.go
  35. 1 1
      libnetwork/sandbox_dns_unix.go
  36. 1 1
      libnetwork/store_test.go
  37. 2 0
      libnetwork/testutils/context_unix.go

+ 30 - 21
libnetwork/drivers/bridge/bridge.go

@@ -19,6 +19,7 @@ import (
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/portmapper"
@@ -119,6 +120,7 @@ type driver struct {
 	isolationChain *iptables.ChainInfo
 	networks       map[string]*bridgeNetwork
 	store          datastore.DataStore
+	nlh            *netlink.Handle
 	sync.Mutex
 }
 
@@ -615,8 +617,15 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
 		}
 	}()
 
+	// Initialize handle when needed
+	d.Lock()
+	if d.nlh == nil {
+		d.nlh = ns.NlHandle()
+	}
+	d.Unlock()
+
 	// Create or retrieve the bridge L3 interface
-	bridgeIface := newInterface(config)
+	bridgeIface := newInterface(d.nlh, config)
 	network.bridge = bridgeIface
 
 	// Verify the network configuration does not conflict with previously installed
@@ -758,7 +767,7 @@ func (d *driver) DeleteNetwork(nid string) error {
 
 	// We only delete the bridge when it's not the default bridge. This is keep the backward compatible behavior.
 	if !config.DefaultBridge {
-		if err := netlink.LinkDel(n.bridge.Link); err != nil {
+		if err := d.nlh.LinkDel(n.bridge.Link); err != nil {
 			logrus.Warnf("Failed to remove bridge interface %s on network %s delete: %v", config.BridgeName, nid, err)
 		}
 	}
@@ -772,12 +781,12 @@ func (d *driver) DeleteNetwork(nid string) error {
 	return d.storeDelete(config)
 }
 
-func addToBridge(ifaceName, bridgeName string) error {
-	link, err := netlink.LinkByName(ifaceName)
+func addToBridge(nlh *netlink.Handle, ifaceName, bridgeName string) error {
+	link, err := nlh.LinkByName(ifaceName)
 	if err != nil {
 		return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
 	}
-	if err = netlink.LinkSetMaster(link,
+	if err = nlh.LinkSetMaster(link,
 		&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}); err != nil {
 		logrus.Debugf("Failed to add %s to bridge via netlink.Trying ioctl: %v", ifaceName, err)
 		iface, err := net.InterfaceByName(ifaceName)
@@ -795,8 +804,8 @@ func addToBridge(ifaceName, bridgeName string) error {
 	return nil
 }
 
-func setHairpinMode(link netlink.Link, enable bool) error {
-	err := netlink.LinkSetHairpin(link, enable)
+func setHairpinMode(nlh *netlink.Handle, link netlink.Link, enable bool) error {
+	err := nlh.LinkSetHairpin(link, enable)
 	if err != nil && err != syscall.EINVAL {
 		// If error is not EINVAL something else went wrong, bail out right away
 		return fmt.Errorf("unable to set hairpin mode on %s via netlink: %v",
@@ -887,13 +896,13 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 	}()
 
 	// Generate a name for what will be the host side pipe interface
-	hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	hostIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
 	if err != nil {
 		return err
 	}
 
 	// Generate a name for what will be the sandbox side pipe interface
-	containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	containerIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
 	if err != nil {
 		return err
 	}
@@ -902,29 +911,29 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 	veth := &netlink.Veth{
 		LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
 		PeerName:  containerIfName}
-	if err = netlink.LinkAdd(veth); err != nil {
+	if err = d.nlh.LinkAdd(veth); err != nil {
 		return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err)
 	}
 
 	// Get the host side pipe interface handler
-	host, err := netlink.LinkByName(hostIfName)
+	host, err := d.nlh.LinkByName(hostIfName)
 	if err != nil {
 		return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
 	}
 	defer func() {
 		if err != nil {
-			netlink.LinkDel(host)
+			d.nlh.LinkDel(host)
 		}
 	}()
 
 	// Get the sandbox side pipe interface handler
-	sbox, err := netlink.LinkByName(containerIfName)
+	sbox, err := d.nlh.LinkByName(containerIfName)
 	if err != nil {
 		return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
 	}
 	defer func() {
 		if err != nil {
-			netlink.LinkDel(sbox)
+			d.nlh.LinkDel(sbox)
 		}
 	}()
 
@@ -934,23 +943,23 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 
 	// Add bridge inherited attributes to pipe interfaces
 	if config.Mtu != 0 {
-		err = netlink.LinkSetMTU(host, config.Mtu)
+		err = d.nlh.LinkSetMTU(host, config.Mtu)
 		if err != nil {
 			return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err)
 		}
-		err = netlink.LinkSetMTU(sbox, config.Mtu)
+		err = d.nlh.LinkSetMTU(sbox, config.Mtu)
 		if err != nil {
 			return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err)
 		}
 	}
 
 	// Attach host side pipe interface into the bridge
-	if err = addToBridge(hostIfName, config.BridgeName); err != nil {
+	if err = addToBridge(d.nlh, hostIfName, config.BridgeName); err != nil {
 		return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
 	}
 
 	if !dconfig.EnableUserlandProxy {
-		err = setHairpinMode(host, true)
+		err = setHairpinMode(d.nlh, host, true)
 		if err != nil {
 			return err
 		}
@@ -971,7 +980,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 	}
 
 	// Up the host interface after finishing all netlink configuration
-	if err = netlink.LinkSetUp(host); err != nil {
+	if err = d.nlh.LinkSetUp(host); err != nil {
 		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
 	}
 
@@ -1056,8 +1065,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 
 	// Try removal of link. Discard error: it is a best effort.
 	// Also make sure defer does not see this error either.
-	if link, err := netlink.LinkByName(ep.srcName); err == nil {
-		netlink.LinkDel(link)
+	if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
+		d.nlh.LinkDel(link)
 	}
 
 	return nil

+ 1 - 1
libnetwork/drivers/bridge/bridge_store.go

@@ -46,7 +46,7 @@ func (d *driver) populateNetworks() error {
 	for _, kvo := range kvol {
 		ncfg := kvo.(*networkConfiguration)
 		if err = d.createNetwork(ncfg); err != nil {
-			logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state", ncfg.ID, ncfg.BridgeName)
+			logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err)
 		}
 	}
 

+ 29 - 7
libnetwork/drivers/bridge/bridge_test.go

@@ -88,7 +88,9 @@ func TestCreateFullOptions(t *testing.T) {
 }
 
 func TestCreateNoConfig(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
 	d := newDriver()
 
 	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
@@ -101,7 +103,9 @@ func TestCreateNoConfig(t *testing.T) {
 }
 
 func TestCreateFullOptionsLabels(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
 	d := newDriver()
 
 	config := &configuration{
@@ -200,7 +204,10 @@ func TestCreateFullOptionsLabels(t *testing.T) {
 }
 
 func TestCreate(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
+
 	d := newDriver()
 
 	if err := d.configure(nil); err != nil {
@@ -225,7 +232,10 @@ func TestCreate(t *testing.T) {
 }
 
 func TestCreateFail(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
+
 	d := newDriver()
 
 	if err := d.configure(nil); err != nil {
@@ -242,7 +252,10 @@ func TestCreateFail(t *testing.T) {
 }
 
 func TestCreateMultipleNetworks(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
+
 	d := newDriver()
 
 	config := &configuration{
@@ -445,6 +458,7 @@ func TestQueryEndpointInfoHairpin(t *testing.T) {
 
 func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
 	defer testutils.SetupTestOSContext(t)()
+
 	d := newDriver()
 
 	config := &configuration{
@@ -545,7 +559,9 @@ func getPortMapping() []types.PortBinding {
 }
 
 func TestLinkContainers(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
 
 	d := newDriver()
 
@@ -698,6 +714,9 @@ func TestLinkContainers(t *testing.T) {
 }
 
 func TestValidateConfig(t *testing.T) {
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
 
 	// Test mtu
 	c := networkConfiguration{Mtu: -2}
@@ -768,7 +787,10 @@ func TestValidateConfig(t *testing.T) {
 }
 
 func TestSetDefaultGw(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
+	if !testutils.IsRunningInContainer() {
+		defer testutils.SetupTestOSContext(t)()
+	}
+
 	d := newDriver()
 
 	if err := d.configure(nil); err != nil {

+ 14 - 8
libnetwork/drivers/bridge/interface.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"net"
 
+	"github.com/Sirupsen/logrus"
 	"github.com/vishvananda/netlink"
 )
 
@@ -20,14 +21,16 @@ type bridgeInterface struct {
 	bridgeIPv6  *net.IPNet
 	gatewayIPv4 net.IP
 	gatewayIPv6 net.IP
+	nlh         *netlink.Handle
 }
 
 // newInterface creates a new bridge interface structure. It attempts to find
 // an already existing device identified by the configuration BridgeName field,
 // or the default bridge name when unspecified, but doesn't attempt to create
 // one when missing
-func newInterface(config *networkConfiguration) *bridgeInterface {
-	i := &bridgeInterface{}
+func newInterface(nlh *netlink.Handle, config *networkConfiguration) *bridgeInterface {
+	var err error
+	i := &bridgeInterface{nlh: nlh}
 
 	// Initialize the bridge name to the default if unspecified.
 	if config.BridgeName == "" {
@@ -35,7 +38,10 @@ func newInterface(config *networkConfiguration) *bridgeInterface {
 	}
 
 	// Attempt to find an existing bridge named with the specified name.
-	i.Link, _ = netlink.LinkByName(config.BridgeName)
+	i.Link, err = nlh.LinkByName(config.BridgeName)
+	if err != nil {
+		logrus.Debugf("Did not find any interface with name %s: %v", config.BridgeName, err)
+	}
 	return i
 }
 
@@ -47,14 +53,14 @@ func (i *bridgeInterface) exists() bool {
 // addresses returns a single IPv4 address and all IPv6 addresses for the
 // bridge interface.
 func (i *bridgeInterface) addresses() (netlink.Addr, []netlink.Addr, error) {
-	v4addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V4)
+	v4addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V4)
 	if err != nil {
-		return netlink.Addr{}, nil, err
+		return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err)
 	}
 
-	v6addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V6)
+	v6addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V6)
 	if err != nil {
-		return netlink.Addr{}, nil, err
+		return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err)
 	}
 
 	if len(v4addr) == 0 {
@@ -72,7 +78,7 @@ func (i *bridgeInterface) programIPv6Address() error {
 	if findIPv6Address(nlAddr, nlAddressList) {
 		return nil
 	}
-	if err := netlink.AddrAdd(i.Link, &nlAddr); err != nil {
+	if err := i.nlh.AddrAdd(i.Link, &nlAddr); err != nil {
 		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
 	}
 	return nil

+ 10 - 2
libnetwork/drivers/bridge/interface_test.go

@@ -10,8 +10,12 @@ import (
 func TestInterfaceDefaultName(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
 	config := &networkConfiguration{}
-	if _ = newInterface(config); config.BridgeName != DefaultBridgeName {
+	if _ = newInterface(nh, config); config.BridgeName != DefaultBridgeName {
 		t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName)
 	}
 }
@@ -19,7 +23,11 @@ func TestInterfaceDefaultName(t *testing.T) {
 func TestAddressesEmptyInterface(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
-	inf := newInterface(&networkConfiguration{})
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	inf := newInterface(nh, &networkConfiguration{})
 	addrv4, addrsv6, err := inf.addresses()
 	if err != nil {
 		t.Fatalf("Failed to get addresses of default interface: %v", err)

+ 7 - 5
libnetwork/drivers/bridge/setup_device.go

@@ -35,14 +35,14 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
 		setMac = kv.Kernel > 3 || (kv.Kernel == 3 && kv.Major >= 3)
 	}
 
-	if err = netlink.LinkAdd(i.Link); err != nil {
+	if err = i.nlh.LinkAdd(i.Link); err != nil {
 		logrus.Debugf("Failed to create bridge %s via netlink. Trying ioctl", config.BridgeName)
 		return ioctlCreateBridge(config.BridgeName, setMac)
 	}
 
 	if setMac {
 		hwAddr := netutils.GenerateRandomMAC()
-		if err = netlink.LinkSetHardwareAddr(i.Link, hwAddr); err != nil {
+		if err = i.nlh.LinkSetHardwareAddr(i.Link, hwAddr); err != nil {
 			return fmt.Errorf("failed to set bridge mac-address %s : %s", hwAddr, err.Error())
 		}
 		logrus.Debugf("Setting bridge mac address to %s", hwAddr)
@@ -52,15 +52,17 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
 
 // SetupDeviceUp ups the given bridge interface.
 func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error {
-	err := netlink.LinkSetUp(i.Link)
+	err := i.nlh.LinkSetUp(i.Link)
 	if err != nil {
-		return err
+		return fmt.Errorf("Failed to set link up for %s: %v", config.BridgeName, err)
 	}
 
 	// Attempt to update the bridge interface to refresh the flags status,
 	// ignoring any failure to do so.
-	if lnk, err := netlink.LinkByName(config.BridgeName); err == nil {
+	if lnk, err := i.nlh.LinkByName(config.BridgeName); err == nil {
 		i.Link = lnk
+	} else {
+		logrus.Warnf("Failed to retrieve link for interface (%s): %v", config.BridgeName, err)
 	}
 	return nil
 }

+ 24 - 6
libnetwork/drivers/bridge/setup_device_test.go

@@ -13,8 +13,14 @@ import (
 func TestSetupNewBridge(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nh.Delete()
+
 	config := &networkConfiguration{BridgeName: DefaultBridgeName}
-	br := &bridgeInterface{}
+	br := &bridgeInterface{nlh: nh}
 
 	if err := setupDevice(config, br); err != nil {
 		t.Fatalf("Bridge creation failed: %v", err)
@@ -22,7 +28,7 @@ func TestSetupNewBridge(t *testing.T) {
 	if br.Link == nil {
 		t.Fatal("bridgeInterface link is nil (expected valid link)")
 	}
-	if _, err := netlink.LinkByName(DefaultBridgeName); err != nil {
+	if _, err := nh.LinkByName(DefaultBridgeName); err != nil {
 		t.Fatalf("Failed to retrieve bridge device: %v", err)
 	}
 	if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp {
@@ -33,10 +39,16 @@ func TestSetupNewBridge(t *testing.T) {
 func TestSetupNewNonDefaultBridge(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nh.Delete()
+
 	config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true}
-	br := &bridgeInterface{}
+	br := &bridgeInterface{nlh: nh}
 
-	err := setupDevice(config, br)
+	err = setupDevice(config, br)
 	if err == nil {
 		t.Fatal("Expected bridge creation failure with \"non default name\", succeeded")
 	}
@@ -49,8 +61,14 @@ func TestSetupNewNonDefaultBridge(t *testing.T) {
 func TestSetupDeviceUp(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nh.Delete()
+
 	config := &networkConfiguration{BridgeName: DefaultBridgeName}
-	br := &bridgeInterface{}
+	br := &bridgeInterface{nlh: nh}
 
 	if err := setupDevice(config, br); err != nil {
 		t.Fatalf("Bridge creation failed: %v", err)
@@ -59,7 +77,7 @@ func TestSetupDeviceUp(t *testing.T) {
 		t.Fatalf("Failed to up bridge device: %v", err)
 	}
 
-	lnk, _ := netlink.LinkByName(DefaultBridgeName)
+	lnk, _ := nh.LinkByName(DefaultBridgeName)
 	if lnk.Attrs().Flags&net.FlagUp != net.FlagUp {
 		t.Fatalf("bridgeInterface should be up")
 	}

+ 14 - 2
libnetwork/drivers/bridge/setup_ip_tables_test.go

@@ -7,6 +7,7 @@ import (
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/portmapper"
 	"github.com/docker/libnetwork/testutils"
+	"github.com/vishvananda/netlink"
 )
 
 const (
@@ -16,7 +17,13 @@ const (
 func TestProgramIPTable(t *testing.T) {
 	// Create a test bridge with a basic bridge configuration (name + IPv4).
 	defer testutils.SetupTestOSContext(t)()
-	createTestBridge(getBasicTestConfig(), &bridgeInterface{}, t)
+
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	createTestBridge(getBasicTestConfig(), &bridgeInterface{nlh: nh}, t)
 
 	// Store various iptables chain rules we care for.
 	rules := []struct {
@@ -41,6 +48,11 @@ func TestSetupIPChains(t *testing.T) {
 	// Create a test bridge with a basic bridge configuration (name + IPv4).
 	defer testutils.SetupTestOSContext(t)()
 
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+
 	driverconfig := &configuration{
 		EnableIPTables: true,
 	}
@@ -50,7 +62,7 @@ func TestSetupIPChains(t *testing.T) {
 	assertChainConfig(d, t)
 
 	config := getBasicTestConfig()
-	br := &bridgeInterface{}
+	br := &bridgeInterface{nlh: nh}
 	createTestBridge(config, br, t)
 
 	assertBridgeConfig(config, br, d, t)

+ 2 - 2
libnetwork/drivers/bridge/setup_ipv4.go

@@ -18,12 +18,12 @@ func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
 
 	if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
 		if addrv4.IPNet != nil {
-			if err := netlink.AddrDel(i.Link, &addrv4); err != nil {
+			if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil {
 				return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
 			}
 		}
 		log.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
-		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
+		if err := i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
 			return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
 		}
 	}

+ 17 - 5
libnetwork/drivers/bridge/setup_ipv4_test.go

@@ -8,10 +8,10 @@ import (
 	"github.com/vishvananda/netlink"
 )
 
-func setupTestInterface(t *testing.T) (*networkConfiguration, *bridgeInterface) {
+func setupTestInterface(t *testing.T, nh *netlink.Handle) (*networkConfiguration, *bridgeInterface) {
 	config := &networkConfiguration{
 		BridgeName: DefaultBridgeName}
-	br := &bridgeInterface{}
+	br := &bridgeInterface{nlh: nh}
 
 	if err := setupDevice(config, br); err != nil {
 		t.Fatalf("Bridge creation failed: %v", err)
@@ -27,13 +27,19 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
 		t.Fatalf("Failed to parse bridge IPv4: %v", err)
 	}
 
-	config, br := setupTestInterface(t)
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nh.Delete()
+
+	config, br := setupTestInterface(t, nh)
 	config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
 	if err := setupBridgeIPv4(config, br); err != nil {
 		t.Fatalf("Failed to setup bridge IPv4: %v", err)
 	}
 
-	addrsv4, err := netlink.AddrList(br.Link, netlink.FAMILY_V4)
+	addrsv4, err := nh.AddrList(br.Link, netlink.FAMILY_V4)
 	if err != nil {
 		t.Fatalf("Failed to list device IPv4 addresses: %v", err)
 	}
@@ -54,6 +60,12 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
 func TestSetupGatewayIPv4(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nh.Delete()
+
 	ip, nw, _ := net.ParseCIDR("192.168.0.24/16")
 	nw.IP = ip
 	gw := net.ParseIP("192.168.2.254")
@@ -62,7 +74,7 @@ func TestSetupGatewayIPv4(t *testing.T) {
 		BridgeName:         DefaultBridgeName,
 		DefaultGatewayIPv4: gw}
 
-	br := &bridgeInterface{bridgeIPv4: nw}
+	br := &bridgeInterface{bridgeIPv4: nw, nlh: nh}
 
 	if err := setupGatewayIPv4(config, br); err != nil {
 		t.Fatalf("Set Default Gateway failed: %v", err)

+ 1 - 1
libnetwork/drivers/bridge/setup_ipv6.go

@@ -64,7 +64,7 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
 
 	// Setting route to global IPv6 subnet
 	logrus.Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
-	err = netlink.RouteAdd(&netlink.Route{
+	err = i.nlh.RouteAdd(&netlink.Route{
 		Scope:     netlink.SCOPE_UNIVERSE,
 		LinkIndex: i.Link.Attrs().Index,
 		Dst:       config.AddressIPv6,

+ 15 - 3
libnetwork/drivers/bridge/setup_ipv6_test.go

@@ -14,7 +14,13 @@ import (
 func TestSetupIPv6(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
-	config, br := setupTestInterface(t)
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nh.Delete()
+
+	config, br := setupTestInterface(t, nh)
 	if err := setupBridgeIPv6(config, br); err != nil {
 		t.Fatalf("Failed to setup bridge IPv6: %v", err)
 	}
@@ -28,7 +34,7 @@ func TestSetupIPv6(t *testing.T) {
 		t.Fatalf("Invalid kernel setting disable_ipv6: expected %q, got %q", string(expected), string(procSetting))
 	}
 
-	addrsv6, err := netlink.AddrList(br.Link, netlink.FAMILY_V6)
+	addrsv6, err := nh.AddrList(br.Link, netlink.FAMILY_V6)
 	if err != nil {
 		t.Fatalf("Failed to list device IPv6 addresses: %v", err)
 	}
@@ -58,7 +64,13 @@ func TestSetupGatewayIPv6(t *testing.T) {
 		AddressIPv6:        nw,
 		DefaultGatewayIPv6: gw}
 
-	br := &bridgeInterface{}
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nh.Delete()
+
+	br := &bridgeInterface{nlh: nh}
 
 	if err := setupGatewayIPv6(config, br); err != nil {
 		t.Fatalf("Set Default Gateway failed: %v", err)

+ 4 - 2
libnetwork/drivers/bridge/setup_verify.go

@@ -1,6 +1,8 @@
 package bridge
 
 import (
+	"fmt"
+
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
@@ -10,7 +12,7 @@ func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) e
 	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
 	addrv4, addrsv6, err := i.addresses()
 	if err != nil {
-		return err
+		return fmt.Errorf("Failed to verify ip addresses: %v", err)
 	}
 
 	// Verify that the bridge does have an IPv4 address.
@@ -32,7 +34,7 @@ func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) e
 	// Release any residual IPv6 address that might be there because of older daemon instances
 	for _, addrv6 := range addrsv6 {
 		if addrv6.IP.IsGlobalUnicast() && !types.CompareIPNet(addrv6.IPNet, i.bridgeIPv6) {
-			if err := netlink.AddrDel(i.Link, &addrv6); err != nil {
+			if err := i.nlh.AddrDel(i.Link, &addrv6); err != nil {
 				log.Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err)
 			}
 		}

+ 6 - 2
libnetwork/drivers/bridge/setup_verify_test.go

@@ -9,11 +9,15 @@ import (
 )
 
 func setupVerifyTest(t *testing.T) *bridgeInterface {
-	inf := &bridgeInterface{}
+	nh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	inf := &bridgeInterface{nlh: nh}
 
 	br := netlink.Bridge{}
 	br.LinkAttrs.Name = "default0"
-	if err := netlink.LinkAdd(&br); err == nil {
+	if err := nh.LinkAdd(&br); err == nil {
 		inf.Link = &br
 	} else {
 		t.Fatalf("Failed to create bridge interface: %v", err)

+ 3 - 3
libnetwork/drivers/ipvlan/ipvlan_endpoint.go

@@ -6,9 +6,9 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
-	"github.com/vishvananda/netlink"
 )
 
 // CreateEndpoint assigns the mac, ip and endpoint id for the new container
@@ -70,8 +70,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 	if ep == nil {
 		return fmt.Errorf("endpoint id %q not found", eid)
 	}
-	if link, err := netlink.LinkByName(ep.srcName); err == nil {
-		netlink.LinkDel(link)
+	if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
+		ns.NlHandle().LinkDel(link)
 	}
 
 	return nil

+ 2 - 1
libnetwork/drivers/ipvlan/ipvlan_joinleave.go

@@ -7,6 +7,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
 )
@@ -34,7 +35,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return fmt.Errorf("could not find endpoint with id %s", eid)
 	}
 	// generate a name for the iface that will be renamed to eth0 in the sbox
-	containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen)
 	if err != nil {
 		return fmt.Errorf("error generating an interface name: %v", err)
 	}

+ 14 - 13
libnetwork/drivers/ipvlan/ipvlan_setup.go

@@ -6,6 +6,7 @@ import (
 	"strings"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/ns"
 	"github.com/vishvananda/netlink"
 )
 
@@ -27,7 +28,7 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
 		return "", fmt.Errorf("the requested parent interface %s was not found on the Docker host", parent)
 	}
 	// Get the link for the master index (Example: the docker host eth iface)
-	parentLink, err := netlink.LinkByName(parent)
+	parentLink, err := ns.NlHandle().LinkByName(parent)
 	if err != nil {
 		return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", ipvlanType, parent, err)
 	}
@@ -39,7 +40,7 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
 		},
 		Mode: mode,
 	}
-	if err := netlink.LinkAdd(ipvlan); err != nil {
+	if err := ns.NlHandle().LinkAdd(ipvlan); err != nil {
 		// If a user creates a macvlan and ipvlan on same parent, only one slave iface can be active at a time.
 		return "", fmt.Errorf("failed to create the %s port: %v", ipvlanType, err)
 	}
@@ -61,7 +62,7 @@ func setIPVlanMode(mode string) (netlink.IPVlanMode, error) {
 
 // parentExists check if the specified interface exists in the default namespace
 func parentExists(ifaceStr string) bool {
-	_, err := netlink.LinkByName(ifaceStr)
+	_, err := ns.NlHandle().LinkByName(ifaceStr)
 	if err != nil {
 		return false
 	}
@@ -81,7 +82,7 @@ func createVlanLink(parentName string) error {
 			return fmt.Errorf("vlan id must be between 1-4094, received: %d", vidInt)
 		}
 		// get the parent link to attach a vlan subinterface
-		parentLink, err := netlink.LinkByName(parent)
+		parentLink, err := ns.NlHandle().LinkByName(parent)
 		if err != nil {
 			return fmt.Errorf("failed to find master interface %s on the Docker host: %v", parent, err)
 		}
@@ -93,11 +94,11 @@ func createVlanLink(parentName string) error {
 			VlanId: vidInt,
 		}
 		// create the subinterface
-		if err := netlink.LinkAdd(vlanLink); err != nil {
+		if err := ns.NlHandle().LinkAdd(vlanLink); err != nil {
 			return fmt.Errorf("failed to create %s vlan link: %v", vlanLink.Name, err)
 		}
 		// Bring the new netlink iface up
-		if err := netlink.LinkSetUp(vlanLink); err != nil {
+		if err := ns.NlHandle().LinkSetUp(vlanLink); err != nil {
 			return fmt.Errorf("failed to enable %s the ipvlan parent link %v", vlanLink.Name, err)
 		}
 		logrus.Debugf("Added a vlan tagged netlink subinterface: %s with a vlan id: %d", parentName, vidInt)
@@ -115,7 +116,7 @@ func delVlanLink(linkName string) error {
 			return err
 		}
 		// delete the vlan subinterface
-		vlanLink, err := netlink.LinkByName(linkName)
+		vlanLink, err := ns.NlHandle().LinkByName(linkName)
 		if err != nil {
 			return fmt.Errorf("failed to find interface %s on the Docker host : %v", linkName, err)
 		}
@@ -124,7 +125,7 @@ func delVlanLink(linkName string) error {
 			return fmt.Errorf("interface %s does not appear to be a slave device: %v", linkName, err)
 		}
 		// delete the ipvlan slave device
-		if err := netlink.LinkDel(vlanLink); err != nil {
+		if err := ns.NlHandle().LinkDel(vlanLink); err != nil {
 			return fmt.Errorf("failed to delete  %s link: %v", linkName, err)
 		}
 		logrus.Debugf("Deleted a vlan tagged netlink subinterface: %s", linkName)
@@ -163,15 +164,15 @@ func createDummyLink(dummyName, truncNetID string) error {
 			Name: dummyName,
 		},
 	}
-	if err := netlink.LinkAdd(parent); err != nil {
+	if err := ns.NlHandle().LinkAdd(parent); err != nil {
 		return err
 	}
-	parentDummyLink, err := netlink.LinkByName(dummyName)
+	parentDummyLink, err := ns.NlHandle().LinkByName(dummyName)
 	if err != nil {
 		return fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", ipvlanType, dummyName, err)
 	}
 	// bring the new netlink iface up
-	if err := netlink.LinkSetUp(parentDummyLink); err != nil {
+	if err := ns.NlHandle().LinkSetUp(parentDummyLink); err != nil {
 		return fmt.Errorf("failed to enable %s the ipvlan parent link: %v", dummyName, err)
 	}
 
@@ -181,7 +182,7 @@ func createDummyLink(dummyName, truncNetID string) error {
 // delDummyLink deletes the link type dummy used when -o parent is not passed
 func delDummyLink(linkName string) error {
 	// delete the vlan subinterface
-	dummyLink, err := netlink.LinkByName(linkName)
+	dummyLink, err := ns.NlHandle().LinkByName(linkName)
 	if err != nil {
 		return fmt.Errorf("failed to find link %s on the Docker host : %v", linkName, err)
 	}
@@ -190,7 +191,7 @@ func delDummyLink(linkName string) error {
 		return fmt.Errorf("link %s is not a parent dummy interface", linkName)
 	}
 	// delete the ipvlan dummy device
-	if err := netlink.LinkDel(dummyLink); err != nil {
+	if err := ns.NlHandle().LinkDel(dummyLink); err != nil {
 		return fmt.Errorf("failed to delete the dummy %s link: %v", linkName, err)
 	}
 	logrus.Debugf("Deleted a dummy parent link: %s", linkName)

+ 3 - 3
libnetwork/drivers/macvlan/macvlan_endpoint.go

@@ -7,9 +7,9 @@ import (
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
-	"github.com/vishvananda/netlink"
 )
 
 // CreateEndpoint assigns the mac, ip and endpoint id for the new container
@@ -74,8 +74,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 	if ep == nil {
 		return fmt.Errorf("endpoint id %q not found", eid)
 	}
-	if link, err := netlink.LinkByName(ep.srcName); err == nil {
-		netlink.LinkDel(link)
+	if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
+		ns.NlHandle().LinkDel(link)
 	}
 
 	return nil

+ 2 - 1
libnetwork/drivers/macvlan/macvlan_joinleave.go

@@ -7,6 +7,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/osl"
 )
 
@@ -22,7 +23,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return fmt.Errorf("could not find endpoint with id %s", eid)
 	}
 	// generate a name for the iface that will be renamed to eth0 in the sbox
-	containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen)
 	if err != nil {
 		return fmt.Errorf("error generating an interface name: %s", err)
 	}

+ 14 - 13
libnetwork/drivers/macvlan/macvlan_setup.go

@@ -6,6 +6,7 @@ import (
 	"strings"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/ns"
 	"github.com/vishvananda/netlink"
 )
 
@@ -27,7 +28,7 @@ func createMacVlan(containerIfName, parent, macvlanMode string) (string, error)
 		return "", fmt.Errorf("the requested parent interface %s was not found on the Docker host", parent)
 	}
 	// Get the link for the master index (Example: the docker host eth iface)
-	parentLink, err := netlink.LinkByName(parent)
+	parentLink, err := ns.NlHandle().LinkByName(parent)
 	if err != nil {
 		return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, parent, err)
 	}
@@ -39,7 +40,7 @@ func createMacVlan(containerIfName, parent, macvlanMode string) (string, error)
 		},
 		Mode: mode,
 	}
-	if err := netlink.LinkAdd(macvlan); err != nil {
+	if err := ns.NlHandle().LinkAdd(macvlan); err != nil {
 		// If a user creates a macvlan and ipvlan on same parent, only one slave iface can be active at a time.
 		return "", fmt.Errorf("failed to create the %s port: %v", macvlanType, err)
 	}
@@ -65,7 +66,7 @@ func setMacVlanMode(mode string) (netlink.MacvlanMode, error) {
 
 // parentExists check if the specified interface exists in the default namespace
 func parentExists(ifaceStr string) bool {
-	_, err := netlink.LinkByName(ifaceStr)
+	_, err := ns.NlHandle().LinkByName(ifaceStr)
 	if err != nil {
 		return false
 	}
@@ -85,7 +86,7 @@ func createVlanLink(parentName string) error {
 			return fmt.Errorf("vlan id must be between 1-4094, received: %d", vidInt)
 		}
 		// get the parent link to attach a vlan subinterface
-		parentLink, err := netlink.LinkByName(parent)
+		parentLink, err := ns.NlHandle().LinkByName(parent)
 		if err != nil {
 			return fmt.Errorf("failed to find master interface %s on the Docker host: %v", parent, err)
 		}
@@ -97,11 +98,11 @@ func createVlanLink(parentName string) error {
 			VlanId: vidInt,
 		}
 		// create the subinterface
-		if err := netlink.LinkAdd(vlanLink); err != nil {
+		if err := ns.NlHandle().LinkAdd(vlanLink); err != nil {
 			return fmt.Errorf("failed to create %s vlan link: %v", vlanLink.Name, err)
 		}
 		// Bring the new netlink iface up
-		if err := netlink.LinkSetUp(vlanLink); err != nil {
+		if err := ns.NlHandle().LinkSetUp(vlanLink); err != nil {
 			return fmt.Errorf("failed to enable %s the macvlan parent link %v", vlanLink.Name, err)
 		}
 		logrus.Debugf("Added a vlan tagged netlink subinterface: %s with a vlan id: %d", parentName, vidInt)
@@ -119,7 +120,7 @@ func delVlanLink(linkName string) error {
 			return err
 		}
 		// delete the vlan subinterface
-		vlanLink, err := netlink.LinkByName(linkName)
+		vlanLink, err := ns.NlHandle().LinkByName(linkName)
 		if err != nil {
 			return fmt.Errorf("failed to find interface %s on the Docker host : %v", linkName, err)
 		}
@@ -128,7 +129,7 @@ func delVlanLink(linkName string) error {
 			return fmt.Errorf("interface %s does not appear to be a slave device: %v", linkName, err)
 		}
 		// delete the macvlan slave device
-		if err := netlink.LinkDel(vlanLink); err != nil {
+		if err := ns.NlHandle().LinkDel(vlanLink); err != nil {
 			return fmt.Errorf("failed to delete  %s link: %v", linkName, err)
 		}
 		logrus.Debugf("Deleted a vlan tagged netlink subinterface: %s", linkName)
@@ -167,15 +168,15 @@ func createDummyLink(dummyName, truncNetID string) error {
 			Name: dummyName,
 		},
 	}
-	if err := netlink.LinkAdd(parent); err != nil {
+	if err := ns.NlHandle().LinkAdd(parent); err != nil {
 		return err
 	}
-	parentDummyLink, err := netlink.LinkByName(dummyName)
+	parentDummyLink, err := ns.NlHandle().LinkByName(dummyName)
 	if err != nil {
 		return fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, dummyName, err)
 	}
 	// bring the new netlink iface up
-	if err := netlink.LinkSetUp(parentDummyLink); err != nil {
+	if err := ns.NlHandle().LinkSetUp(parentDummyLink); err != nil {
 		return fmt.Errorf("failed to enable %s the macvlan parent link: %v", dummyName, err)
 	}
 
@@ -185,7 +186,7 @@ func createDummyLink(dummyName, truncNetID string) error {
 // delDummyLink deletes the link type dummy used when -o parent is not passed
 func delDummyLink(linkName string) error {
 	// delete the vlan subinterface
-	dummyLink, err := netlink.LinkByName(linkName)
+	dummyLink, err := ns.NlHandle().LinkByName(linkName)
 	if err != nil {
 		return fmt.Errorf("failed to find link %s on the Docker host : %v", linkName, err)
 	}
@@ -194,7 +195,7 @@ func delDummyLink(linkName string) error {
 		return fmt.Errorf("link %s is not a parent dummy interface", linkName)
 	}
 	// delete the macvlan dummy device
-	if err := netlink.LinkDel(dummyLink); err != nil {
+	if err := ns.NlHandle().LinkDel(dummyLink); err != nil {
 		return fmt.Errorf("failed to delete the dummy %s link: %v", linkName, err)
 	}
 	logrus.Debugf("Deleted a dummy parent link: %s", linkName)

+ 8 - 6
libnetwork/drivers/overlay/joinleave.go

@@ -6,9 +6,9 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/types"
 	"github.com/gogo/protobuf/proto"
-	"github.com/vishvananda/netlink"
 )
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
@@ -61,14 +61,16 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 
 	ep.ifName = containerIfName
 
+	nlh := ns.NlHandle()
+
 	// Set the container interface and its peer MTU to 1450 to allow
 	// for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) +
 	// outer UDP(8) + vxlan header(8))
-	veth, err := netlink.LinkByName(overlayIfName)
+	veth, err := nlh.LinkByName(overlayIfName)
 	if err != nil {
 		return fmt.Errorf("cound not find link by name %s: %v", overlayIfName, err)
 	}
-	err = netlink.LinkSetMTU(veth, vxlanVethMTU)
+	err = nlh.LinkSetMTU(veth, vxlanVethMTU)
 	if err != nil {
 		return err
 	}
@@ -78,16 +80,16 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err)
 	}
 
-	veth, err = netlink.LinkByName(containerIfName)
+	veth, err = nlh.LinkByName(containerIfName)
 	if err != nil {
 		return fmt.Errorf("could not find link by name %s: %v", containerIfName, err)
 	}
-	err = netlink.LinkSetMTU(veth, vxlanVethMTU)
+	err = nlh.LinkSetMTU(veth, vxlanVethMTU)
 	if err != nil {
 		return err
 	}
 
-	if err := netlink.LinkSetHardwareAddr(veth, ep.mac); err != nil {
+	if err := nlh.LinkSetHardwareAddr(veth, ep.mac); err != nil {
 		return fmt.Errorf("could not set mac address (%v) to the container interface: %v", ep.mac, err)
 	}
 

+ 5 - 3
libnetwork/drivers/overlay/ov_endpoint.go

@@ -7,7 +7,7 @@ import (
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netutils"
-	"github.com/vishvananda/netlink"
+	"github.com/docker/libnetwork/ns"
 )
 
 type endpointTable map[string]*endpoint
@@ -84,6 +84,8 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 }
 
 func (d *driver) DeleteEndpoint(nid, eid string) error {
+	nlh := ns.NlHandle()
+
 	if err := validateID(nid, eid); err != nil {
 		return err
 	}
@@ -104,12 +106,12 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 		return nil
 	}
 
-	link, err := netlink.LinkByName(ep.ifName)
+	link, err := nlh.LinkByName(ep.ifName)
 	if err != nil {
 		log.Debugf("Failed to retrieve interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err)
 		return nil
 	}
-	if err := netlink.LinkDel(link); err != nil {
+	if err := nlh.LinkDel(link); err != nil {
 		log.Debugf("Failed to delete interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err)
 	}
 

+ 8 - 7
libnetwork/drivers/overlay/ov_network.go

@@ -16,6 +16,7 @@ import (
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/types"
@@ -323,24 +324,24 @@ func networkOnceInit() {
 	defer deleteInterface("testvxlan")
 
 	path := "/proc/self/ns/net"
-	f, err := os.OpenFile(path, os.O_RDONLY, 0)
+	hNs, err := netns.GetFromPath(path)
 	if err != nil {
-		logrus.Errorf("Failed to open path %s for network namespace for setting host mode: %v", path, err)
+		logrus.Errorf("Failed to get network namespace from path %s while setting host mode: %v", path, err)
 		return
 	}
-	defer f.Close()
+	defer hNs.Close()
 
-	nsFD := f.Fd()
+	nlh := ns.NlHandle()
 
-	iface, err := netlink.LinkByName("testvxlan")
+	iface, err := nlh.LinkByName("testvxlan")
 	if err != nil {
-		logrus.Errorf("Failed to get link testvxlan: %v", err)
+		logrus.Errorf("Failed to get link testvxlan while setting host mode: %v", err)
 		return
 	}
 
 	// If we are not able to move the vxlan interface to a namespace
 	// then fallback to host mode
-	if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
+	if err := nlh.LinkSetNsFd(iface, int(hNs)); err != nil {
 		hostMode = true
 	}
 }

+ 13 - 23
libnetwork/drivers/overlay/ov_utils.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/osl"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netns"
@@ -23,15 +24,16 @@ func validateID(nid, eid string) error {
 
 func createVethPair() (string, string, error) {
 	defer osl.InitOSContext()()
+	nlh := ns.NlHandle()
 
 	// Generate a name for what will be the host side pipe interface
-	name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	name1, err := netutils.GenerateIfaceName(nlh, vethPrefix, vethLen)
 	if err != nil {
 		return "", "", fmt.Errorf("error generating veth name1: %v", err)
 	}
 
 	// Generate a name for what will be the sandbox side pipe interface
-	name2, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	name2, err := netutils.GenerateIfaceName(nlh, vethPrefix, vethLen)
 	if err != nil {
 		return "", "", fmt.Errorf("error generating veth name2: %v", err)
 	}
@@ -40,7 +42,7 @@ func createVethPair() (string, string, error) {
 	veth := &netlink.Veth{
 		LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
 		PeerName:  name2}
-	if err := netlink.LinkAdd(veth); err != nil {
+	if err := nlh.LinkAdd(veth); err != nil {
 		return "", "", fmt.Errorf("error creating veth pair: %v", err)
 	}
 
@@ -60,7 +62,7 @@ func createVxlan(name string, vni uint32) error {
 		L2miss:    true,
 	}
 
-	if err := netlink.LinkAdd(vxlan); err != nil {
+	if err := ns.NlHandle().LinkAdd(vxlan); err != nil {
 		return fmt.Errorf("error creating vxlan interface: %v", err)
 	}
 
@@ -70,12 +72,12 @@ func createVxlan(name string, vni uint32) error {
 func deleteInterface(name string) error {
 	defer osl.InitOSContext()()
 
-	link, err := netlink.LinkByName(name)
+	link, err := ns.NlHandle().LinkByName(name)
 	if err != nil {
 		return fmt.Errorf("failed to find interface with name %s: %v", name, err)
 	}
 
-	if err := netlink.LinkDel(link); err != nil {
+	if err := ns.NlHandle().LinkDel(link); err != nil {
 		return fmt.Errorf("error deleting interface with name %s: %v", name, err)
 	}
 
@@ -85,20 +87,9 @@ func deleteInterface(name string) error {
 func deleteVxlanByVNI(path string, vni uint32) error {
 	defer osl.InitOSContext()()
 
-	var nlh *netlink.Handle
-	if path == "" {
-		var err error
-		nlh, err = netlink.NewHandle()
-		if err != nil {
-			return fmt.Errorf("failed to get netlink handle for current ns: %v", err)
-		}
-	} else {
-		var (
-			err error
-			ns  netns.NsHandle
-		)
-
-		ns, err = netns.GetFromPath(path)
+	nlh := ns.NlHandle()
+	if path != "" {
+		ns, err := netns.GetFromPath(path)
 		if err != nil {
 			return fmt.Errorf("failed to get ns handle for %s: %v", path, err)
 		}
@@ -108,8 +99,8 @@ func deleteVxlanByVNI(path string, vni uint32) error {
 		if err != nil {
 			return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err)
 		}
+		defer nlh.Delete()
 	}
-	defer nlh.Delete()
 
 	links, err := nlh.LinkList()
 	if err != nil {
@@ -118,11 +109,10 @@ func deleteVxlanByVNI(path string, vni uint32) error {
 
 	for _, l := range links {
 		if l.Type() == "vxlan" && (vni == 0 || l.(*netlink.Vxlan).VxlanId == int(vni)) {
-			err = netlink.LinkDel(l)
+			err = nlh.LinkDel(l)
 			if err != nil {
 				return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err)
 			}
-
 			return nil
 		}
 	}

+ 8 - 40
libnetwork/libnetwork_test.go

@@ -969,34 +969,24 @@ func TestNetworkQuery(t *testing.T) {
 const containerID = "valid_c"
 
 func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
-	origns, err := netns.Get()
-	if err != nil {
-		t.Fatalf("Could not get the current netns: %v", err)
-	}
-	defer origns.Close()
-
 	key := info.Sandbox().Key()
-	f, err := os.OpenFile(key, os.O_RDONLY, 0)
+	sbNs, err := netns.GetFromPath(key)
 	if err != nil {
-		t.Fatalf("Failed to open network namespace path %q: %v", key, err)
+		t.Fatalf("Failed to get network namespace path %q: %v", key, err)
 	}
-	defer f.Close()
-
-	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
+	defer sbNs.Close()
 
-	nsFD := f.Fd()
-	if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
-		t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", key, err)
+	nh, err := netlink.NewHandleAt(sbNs)
+	if err != nil {
+		t.Fatal(err)
 	}
-	defer netns.Set(origns)
 
-	_, err = netlink.LinkByName("eth0")
+	_, err = nh.LinkByName("eth0")
 	if err != nil {
 		t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
 	}
 
-	_, err = netlink.LinkByName("eth1")
+	_, err = nh.LinkByName("eth1")
 	if err != nil {
 		t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err)
 	}
@@ -1093,13 +1083,11 @@ func TestEndpointJoin(t *testing.T) {
 	}()
 
 	err = ep1.Join(sb)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
 		err = ep1.Leave(sb)
-		runtime.LockOSThread()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1162,10 +1150,8 @@ func TestEndpointJoin(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	runtime.LockOSThread()
 	defer func() {
 		err = ep2.Leave(sb)
-		runtime.LockOSThread()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1291,13 +1277,11 @@ func externalKeyTest(t *testing.T, reexec bool) {
 
 	// Join endpoint to sandbox before SetKey
 	err = ep.Join(cnt)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
 		err = ep.Leave(cnt)
-		runtime.LockOSThread()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1347,10 +1331,8 @@ func externalKeyTest(t *testing.T, reexec bool) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	runtime.LockOSThread()
 	defer func() {
 		err = ep2.Leave(sbox)
-		runtime.LockOSThread()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1426,13 +1408,11 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) {
 	}()
 
 	err = ep.Join(cnt)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
 		err = ep.Leave(cnt)
-		runtime.LockOSThread()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1492,17 +1472,14 @@ func TestEndpointMultipleJoins(t *testing.T) {
 		if err := sbx2.Delete(); err != nil {
 			t.Fatal(err)
 		}
-		runtime.LockOSThread()
 	}()
 
 	err = ep.Join(sbx1)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
 		err = ep.Leave(sbx1)
-		runtime.LockOSThread()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1558,13 +1535,11 @@ func TestLeaveAll(t *testing.T) {
 	if err != nil {
 		t.Fatalf("Failed to join ep1: %v", err)
 	}
-	runtime.LockOSThread()
 
 	err = ep2.Join(cnt)
 	if err != nil {
 		t.Fatalf("Failed to join ep2: %v", err)
 	}
-	runtime.LockOSThread()
 
 	err = cnt.Delete()
 	if err != nil {
@@ -1695,13 +1670,11 @@ func TestEndpointUpdateParent(t *testing.T) {
 	}()
 
 	err = ep1.Join(sbx1)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	err = ep2.Join(sbx2)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1924,7 +1897,6 @@ func TestResolvConf(t *testing.T) {
 	}()
 
 	err = ep.Join(sb1)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1950,7 +1922,6 @@ func TestResolvConf(t *testing.T) {
 	}
 
 	err = ep.Leave(sb1)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1970,7 +1941,6 @@ func TestResolvConf(t *testing.T) {
 	}()
 
 	err = ep.Join(sb2)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1989,13 +1959,11 @@ func TestResolvConf(t *testing.T) {
 	}
 
 	err = ep.Leave(sb2)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	err = ep.Join(sb2)
-	runtime.LockOSThread()
 	if err != nil {
 		t.Fatal(err)
 	}

+ 15 - 7
libnetwork/netutils/utils_linux.go

@@ -9,6 +9,7 @@ import (
 	"strings"
 
 	"github.com/docker/libnetwork/ipamutils"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/types"
@@ -16,16 +17,18 @@ import (
 )
 
 var (
-	networkGetRoutesFct = netlink.RouteList
+	networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
 )
 
 // CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
 func CheckRouteOverlaps(toCheck *net.IPNet) error {
+	if networkGetRoutesFct == nil {
+		networkGetRoutesFct = ns.NlHandle().RouteList
+	}
 	networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4)
 	if err != nil {
 		return err
 	}
-
 	for _, network := range networks {
 		if network.Dst != nil && NetworkOverlaps(toCheck, network.Dst) {
 			return ErrNetworkOverlaps
@@ -37,13 +40,18 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error {
 // GenerateIfaceName returns an interface name using the passed in
 // prefix and the length of random bytes. The api ensures that the
 // there are is no interface which exists with that name.
-func GenerateIfaceName(prefix string, len int) (string, error) {
+func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, error) {
+	linkByName := netlink.LinkByName
+	if nlh != nil {
+		linkByName = nlh.LinkByName
+	}
 	for i := 0; i < 3; i++ {
 		name, err := GenerateRandomName(prefix, len)
 		if err != nil {
 			continue
 		}
-		if _, err := netlink.LinkByName(name); err != nil {
+		_, err = linkByName(name)
+		if err != nil {
 			if strings.Contains(err.Error(), "not found") {
 				return name, nil
 			}
@@ -67,13 +75,13 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
 
 	defer osl.InitOSContext()()
 
-	link, _ := netlink.LinkByName(name)
+	link, _ := ns.NlHandle().LinkByName(name)
 	if link != nil {
-		v4addr, err := netlink.AddrList(link, netlink.FAMILY_V4)
+		v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4)
 		if err != nil {
 			return nil, nil, err
 		}
-		v6addr, err := netlink.AddrList(link, netlink.FAMILY_V6)
+		v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6)
 		if err != nil {
 			return nil, nil, err
 		}

+ 1 - 5
libnetwork/netutils/utils_test.go

@@ -40,13 +40,8 @@ func TestOverlapingNameservers(t *testing.T) {
 }
 
 func TestCheckRouteOverlaps(t *testing.T) {
-	orig := networkGetRoutesFct
-	defer func() {
-		networkGetRoutesFct = orig
-	}()
 	networkGetRoutesFct = func(netlink.Link, int) ([]netlink.Route, error) {
 		routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
-
 		routes := []netlink.Route{}
 		for _, addr := range routesData {
 			_, netX, _ := net.ParseCIDR(addr)
@@ -54,6 +49,7 @@ func TestCheckRouteOverlaps(t *testing.T) {
 		}
 		return routes, nil
 	}
+	defer func() { networkGetRoutesFct = nil }()
 
 	_, netX, _ := net.ParseCIDR("172.16.0.1/24")
 	if err := CheckRouteOverlaps(netX); err != nil {

+ 24 - 3
libnetwork/ns/init_linux.go

@@ -3,13 +3,19 @@ package ns
 import (
 	"fmt"
 	"os"
+	"sync"
 	"syscall"
 
 	log "github.com/Sirupsen/logrus"
+	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netns"
 )
 
-var initNs netns.NsHandle
+var (
+	initNs   netns.NsHandle
+	initNl   *netlink.Handle
+	initOnce sync.Once
+)
 
 // Init initializes a new network namespace
 func Init() {
@@ -18,6 +24,10 @@ func Init() {
 	if err != nil {
 		log.Errorf("could not get initial namespace: %v", err)
 	}
+	initNl, err = netlink.NewHandle()
+	if err != nil {
+		log.Errorf("could not create netlink handle on initial namespace: %v", err)
+	}
 }
 
 // SetNamespace sets the initial namespace handler
@@ -27,7 +37,6 @@ func SetNamespace() error {
 		if linkErr != nil {
 			linkInfo = linkErr.Error()
 		}
-
 		return fmt.Errorf("failed to set to initial namespace, %v, initns fd %d: %v", linkInfo, initNs, err)
 	}
 	return nil
@@ -35,9 +44,21 @@ func SetNamespace() error {
 
 // ParseHandlerInt transforms the namespace handler into an integer
 func ParseHandlerInt() int {
-	return int(initNs)
+	return int(getHandler())
+}
+
+// GetHandler returns the namespace handler
+func getHandler() netns.NsHandle {
+	initOnce.Do(Init)
+	return initNs
 }
 
 func getLink() (string, error) {
 	return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
 }
+
+// NlHandle returns the netlink handler
+func NlHandle() *netlink.Handle {
+	initOnce.Do(Init)
+	return initNl
+}

+ 114 - 121
libnetwork/osl/interface_linux.go

@@ -3,14 +3,15 @@ package osl
 import (
 	"fmt"
 	"net"
-	"os/exec"
 	"regexp"
 	"sync"
 	"syscall"
 
 	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
+	"github.com/vishvananda/netns"
 )
 
 // IfaceOption is a function option type to set interface options
@@ -126,52 +127,50 @@ func (i *nwIface) Remove() error {
 	i.Unlock()
 
 	n.Lock()
-	path := n.path
 	isDefault := n.isDefault
+	nlh := n.nlHandle
 	n.Unlock()
 
-	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
-		// Find the network inteerface identified by the DstName attribute.
-		iface, err := netlink.LinkByName(i.DstName())
-		if err != nil {
-			return err
-		}
+	// Find the network inteerface identified by the DstName attribute.
+	iface, err := nlh.LinkByName(i.DstName())
+	if err != nil {
+		return err
+	}
 
-		// Down the interface before configuring
-		if err := netlink.LinkSetDown(iface); err != nil {
-			return err
-		}
+	// Down the interface before configuring
+	if err := nlh.LinkSetDown(iface); err != nil {
+		return err
+	}
 
-		err = netlink.LinkSetName(iface, i.SrcName())
-		if err != nil {
-			log.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err)
-			return err
-		}
+	err = nlh.LinkSetName(iface, i.SrcName())
+	if err != nil {
+		log.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err)
+		return err
+	}
 
-		// if it is a bridge just delete it.
-		if i.Bridge() {
-			if err := netlink.LinkDel(iface); err != nil {
-				return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
-			}
-		} else if !isDefault {
-			// Move the network interface to caller namespace.
-			if err := netlink.LinkSetNsFd(iface, callerFD); err != nil {
-				log.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err)
-				return err
-			}
+	// if it is a bridge just delete it.
+	if i.Bridge() {
+		if err := nlh.LinkDel(iface); err != nil {
+			return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
 		}
+	} else if !isDefault {
+		// Move the network interface to caller namespace.
+		if err := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); err != nil {
+			log.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err)
+			return err
+		}
+	}
 
-		n.Lock()
-		for index, intf := range n.iFaces {
-			if intf == i {
-				n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...)
-				break
-			}
+	n.Lock()
+	for index, intf := range n.iFaces {
+		if intf == i {
+			n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...)
+			break
 		}
-		n.Unlock()
+	}
+	n.Unlock()
 
-		return nil
-	})
+	return nil
 }
 
 // Returns the sandbox's side veth interface statistics
@@ -180,28 +179,24 @@ func (i *nwIface) Statistics() (*types.InterfaceStatistics, error) {
 	n := i.ns
 	i.Unlock()
 
-	n.Lock()
-	path := n.path
-	n.Unlock()
-
-	s := &types.InterfaceStatistics{}
-
-	err := nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
-		// For some reason ioutil.ReadFile(netStatsFile) reads the file in
-		// the default netns when this code is invoked from docker.
-		// Executing "cat <netStatsFile>" works as expected.
-		data, err := exec.Command("cat", netStatsFile).Output()
-		if err != nil {
-			return fmt.Errorf("failure opening %s: %v", netStatsFile, err)
-		}
-		return scanInterfaceStats(string(data), i.DstName(), s)
-	})
-
+	l, err := n.nlHandle.LinkByName(i.DstName())
 	if err != nil {
-		err = fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), path, err)
+		return nil, fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), n.path, err)
 	}
 
-	return s, err
+	stats := l.Attrs().Statistics
+	if stats == nil {
+		return nil, fmt.Errorf("no statistics were returned")
+	}
+
+	return &types.InterfaceStatistics{
+		RxBytes:   uint64(stats.RxBytes),
+		TxBytes:   uint64(stats.TxBytes),
+		RxPackets: uint64(stats.RxPackets),
+		TxPackets: uint64(stats.TxPackets),
+		RxDropped: uint64(stats.RxDropped),
+		TxDropped: uint64(stats.TxDropped),
+	}, nil
 }
 
 func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
@@ -241,17 +236,24 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
 
 	path := n.path
 	isDefault := n.isDefault
+	nlh := n.nlHandle
+	nlhHost := ns.NlHandle()
 	n.Unlock()
 
-	return nsInvoke(path, func(nsFD int) error {
-		// If it is a bridge interface we have to create the bridge inside
-		// the namespace so don't try to lookup the interface using srcName
-		if i.bridge {
-			return nil
+	// If it is a bridge interface we have to create the bridge inside
+	// the namespace so don't try to lookup the interface using srcName
+	if i.bridge {
+		link := &netlink.Bridge{
+			LinkAttrs: netlink.LinkAttrs{
+				Name: i.srcName,
+			},
 		}
-
+		if err := nlh.LinkAdd(link); err != nil {
+			return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
+		}
+	} else {
 		// Find the network interface identified by the SrcName attribute.
-		iface, err := netlink.LinkByName(i.srcName)
+		iface, err := nlhHost.LinkByName(i.srcName)
 		if err != nil {
 			return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
 		}
@@ -260,63 +262,54 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
 		// namespace only if the namespace is not a default
 		// type
 		if !isDefault {
-			if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
-				return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
-			}
-		}
-
-		return nil
-	}, func(callerFD int) error {
-		if i.bridge {
-			link := &netlink.Bridge{
-				LinkAttrs: netlink.LinkAttrs{
-					Name: i.srcName,
-				},
+			newNs, err := netns.GetFromPath(path)
+			if err != nil {
+				return fmt.Errorf("failed get network namespace %q: %v", path, err)
 			}
-
-			if err := netlink.LinkAdd(link); err != nil {
-				return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
+			defer newNs.Close()
+			if err := nlhHost.LinkSetNsFd(iface, int(newNs)); err != nil {
+				return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
 			}
 		}
+	}
 
-		// Find the network interface identified by the SrcName attribute.
-		iface, err := netlink.LinkByName(i.srcName)
-		if err != nil {
-			return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
-		}
+	// Find the network interface identified by the SrcName attribute.
+	iface, err := nlh.LinkByName(i.srcName)
+	if err != nil {
+		return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
+	}
 
-		// Down the interface before configuring
-		if err := netlink.LinkSetDown(iface); err != nil {
-			return fmt.Errorf("failed to set link down: %v", err)
-		}
+	// Down the interface before configuring
+	if err := nlh.LinkSetDown(iface); err != nil {
+		return fmt.Errorf("failed to set link down: %v", err)
+	}
 
-		// Configure the interface now this is moved in the proper namespace.
-		if err := configureInterface(iface, i); err != nil {
-			return err
-		}
+	// Configure the interface now this is moved in the proper namespace.
+	if err := configureInterface(nlh, iface, i); err != nil {
+		return err
+	}
 
-		// Up the interface.
-		if err := netlink.LinkSetUp(iface); err != nil {
-			return fmt.Errorf("failed to set link up: %v", err)
-		}
+	// Up the interface.
+	if err := nlh.LinkSetUp(iface); err != nil {
+		return fmt.Errorf("failed to set link up: %v", err)
+	}
 
-		// Set the routes on the interface. This can only be done when the interface is up.
-		if err := setInterfaceRoutes(iface, i); err != nil {
-			return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err)
-		}
+	// Set the routes on the interface. This can only be done when the interface is up.
+	if err := setInterfaceRoutes(nlh, iface, i); err != nil {
+		return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err)
+	}
 
-		n.Lock()
-		n.iFaces = append(n.iFaces, i)
-		n.Unlock()
+	n.Lock()
+	n.iFaces = append(n.iFaces, i)
+	n.Unlock()
 
-		return nil
-	})
+	return nil
 }
 
-func configureInterface(iface netlink.Link, i *nwIface) error {
+func configureInterface(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	ifaceName := iface.Attrs().Name
 	ifaceConfigurators := []struct {
-		Fn         func(netlink.Link, *nwIface) error
+		Fn         func(*netlink.Handle, netlink.Link, *nwIface) error
 		ErrMessage string
 	}{
 		{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
@@ -328,63 +321,63 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
 	}
 
 	for _, config := range ifaceConfigurators {
-		if err := config.Fn(iface, i); err != nil {
+		if err := config.Fn(nlh, iface, i); err != nil {
 			return fmt.Errorf("%s: %v", config.ErrMessage, err)
 		}
 	}
 	return nil
 }
 
-func setInterfaceMaster(iface netlink.Link, i *nwIface) error {
+func setInterfaceMaster(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	if i.DstMaster() == "" {
 		return nil
 	}
 
-	return netlink.LinkSetMaster(iface, &netlink.Bridge{
+	return nlh.LinkSetMaster(iface, &netlink.Bridge{
 		LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
 }
 
-func setInterfaceMAC(iface netlink.Link, i *nwIface) error {
+func setInterfaceMAC(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	if i.MacAddress() == nil {
 		return nil
 	}
-	return netlink.LinkSetHardwareAddr(iface, i.MacAddress())
+	return nlh.LinkSetHardwareAddr(iface, i.MacAddress())
 }
 
-func setInterfaceIP(iface netlink.Link, i *nwIface) error {
+func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	if i.Address() == nil {
 		return nil
 	}
 
 	ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
-	return netlink.AddrAdd(iface, ipAddr)
+	return nlh.AddrAdd(iface, ipAddr)
 }
 
-func setInterfaceIPv6(iface netlink.Link, i *nwIface) error {
+func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	if i.AddressIPv6() == nil {
 		return nil
 	}
 	ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
-	return netlink.AddrAdd(iface, ipAddr)
+	return nlh.AddrAdd(iface, ipAddr)
 }
 
-func setInterfaceLinkLocalIPs(iface netlink.Link, i *nwIface) error {
+func setInterfaceLinkLocalIPs(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	for _, llIP := range i.LinkLocalAddresses() {
 		ipAddr := &netlink.Addr{IPNet: llIP}
-		if err := netlink.AddrAdd(iface, ipAddr); err != nil {
+		if err := nlh.AddrAdd(iface, ipAddr); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
-func setInterfaceName(iface netlink.Link, i *nwIface) error {
-	return netlink.LinkSetName(iface, i.DstName())
+func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
+	return nlh.LinkSetName(iface, i.DstName())
 }
 
-func setInterfaceRoutes(iface netlink.Link, i *nwIface) error {
+func setInterfaceRoutes(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	for _, route := range i.Routes() {
-		err := netlink.RouteAdd(&netlink.Route{
+		err := nlh.RouteAdd(&netlink.Route{
 			Scope:     netlink.SCOPE_LINK,
 			LinkIndex: iface.Attrs().Index,
 			Dst:       route,

+ 53 - 27
libnetwork/osl/namespace_linux.go

@@ -42,6 +42,7 @@ type networkNamespace struct {
 	neighbors    []*neigh
 	nextIfIndex  int
 	isDefault    bool
+	nlHandle     *netlink.Handle
 	sync.Mutex
 }
 
@@ -147,7 +148,25 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
 		return nil, err
 	}
 
-	return &networkNamespace{path: key, isDefault: !osCreate}, nil
+	n := &networkNamespace{path: key, isDefault: !osCreate}
+
+	sboxNs, err := netns.GetFromPath(n.path)
+	if err != nil {
+		return nil, fmt.Errorf("failed get network namespace %q: %v", n.path, err)
+	}
+	defer sboxNs.Close()
+
+	n.nlHandle, err = netlink.NewHandleAt(sboxNs)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create a netlink handle: %v", err)
+	}
+
+	if err = n.loopbackUp(); err != nil {
+		n.nlHandle.Delete()
+		return nil, err
+	}
+
+	return n, nil
 }
 
 func (n *networkNamespace) InterfaceOptions() IfaceOptionSetter {
@@ -159,30 +178,37 @@ func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
 }
 
 func mountNetworkNamespace(basePath string, lnPath string) error {
-	if err := syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, ""); err != nil {
-		return err
-	}
-
-	if err := loopbackUp(); err != nil {
-		return err
-	}
-	return nil
+	return syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, "")
 }
 
 // GetSandboxForExternalKey returns sandbox object for the supplied path
 func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
-	var err error
-	if err = createNamespaceFile(key); err != nil {
+	if err := createNamespaceFile(key); err != nil {
 		return nil, err
 	}
-	n := &networkNamespace{path: basePath}
-	n.InvokeFunc(func() {
-		err = mountNetworkNamespace(basePath, key)
-	})
+
+	if err := mountNetworkNamespace(basePath, key); err != nil {
+		return nil, err
+	}
+	n := &networkNamespace{path: key}
+
+	sboxNs, err := netns.GetFromPath(n.path)
+	if err != nil {
+		return nil, fmt.Errorf("failed get network namespace %q: %v", n.path, err)
+	}
+	defer sboxNs.Close()
+
+	n.nlHandle, err = netlink.NewHandleAt(sboxNs)
 	if err != nil {
+		return nil, fmt.Errorf("failed to create a netlink handle: %v", err)
+	}
+
+	if err = n.loopbackUp(); err != nil {
+		n.nlHandle.Delete()
 		return nil, err
 	}
-	return &networkNamespace{path: key}, nil
+
+	return n, nil
 }
 
 func reexecCreateNamespace() {
@@ -243,12 +269,12 @@ func createNamespaceFile(path string) (err error) {
 	return err
 }
 
-func loopbackUp() error {
-	iface, err := netlink.LinkByName("lo")
+func (n *networkNamespace) loopbackUp() error {
+	iface, err := n.nlHandle.LinkByName("lo")
 	if err != nil {
 		return err
 	}
-	return netlink.LinkSetUp(iface)
+	return n.nlHandle.LinkSetUp(iface)
 }
 
 func (n *networkNamespace) InvokeFunc(f func()) error {
@@ -260,33 +286,30 @@ func (n *networkNamespace) InvokeFunc(f func()) error {
 
 // InitOSContext initializes OS context while configuring network resources
 func InitOSContext() func() {
-	runtime.LockOSThread()
 	nsOnce.Do(ns.Init)
+	runtime.LockOSThread()
 	if err := ns.SetNamespace(); err != nil {
 		log.Error(err)
 	}
-
 	return runtime.UnlockOSThread
 }
 
 func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error {
 	defer InitOSContext()()
 
-	f, err := os.OpenFile(path, os.O_RDONLY, 0)
+	newNs, err := netns.GetFromPath(path)
 	if err != nil {
 		return fmt.Errorf("failed get network namespace %q: %v", path, err)
 	}
-	defer f.Close()
-
-	nsFD := f.Fd()
+	defer newNs.Close()
 
 	// Invoked before the namespace switch happens but after the namespace file
 	// handle is obtained.
-	if err := prefunc(int(nsFD)); err != nil {
+	if err := prefunc(int(newNs)); err != nil {
 		return fmt.Errorf("failed in prefunc: %v", err)
 	}
 
-	if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
+	if err = netns.Set(newNs); err != nil {
 		return err
 	}
 	defer ns.SetNamespace()
@@ -311,6 +334,9 @@ func (n *networkNamespace) Key() string {
 }
 
 func (n *networkNamespace) Destroy() error {
+	if n.nlHandle != nil {
+		n.nlHandle.Delete()
+	}
 	// Assuming no running process is executing in this network namespace,
 	// unmounting is sufficient to destroy it.
 	if err := syscall.Unmount(n.path, syscall.MNT_DETACH); err != nil {

+ 67 - 59
libnetwork/osl/neigh_linux.go

@@ -33,53 +33,62 @@ func (n *networkNamespace) findNeighbor(dstIP net.IP, dstMac net.HardwareAddr) *
 }
 
 func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr) error {
+	var (
+		iface netlink.Link
+		err   error
+	)
+
 	nh := n.findNeighbor(dstIP, dstMac)
 	if nh == nil {
 		return fmt.Errorf("could not find the neighbor entry to delete")
 	}
 
-	return nsInvoke(n.nsPath(), func(nsFD int) error { return nil }, func(callerFD int) error {
-		var iface netlink.Link
-
-		if nh.linkDst != "" {
-			var err error
-			iface, err = netlink.LinkByName(nh.linkDst)
-			if err != nil {
-				return fmt.Errorf("could not find interface with destination name %s: %v",
-					nh.linkDst, err)
-			}
+	n.Lock()
+	nlh := n.nlHandle
+	n.Unlock()
+
+	if nh.linkDst != "" {
+		iface, err = nlh.LinkByName(nh.linkDst)
+		if err != nil {
+			return fmt.Errorf("could not find interface with destination name %s: %v",
+				nh.linkDst, err)
 		}
+	}
 
-		nlnh := &netlink.Neigh{
-			IP:     dstIP,
-			State:  netlink.NUD_PERMANENT,
-			Family: nh.family,
-		}
+	nlnh := &netlink.Neigh{
+		IP:     dstIP,
+		State:  netlink.NUD_PERMANENT,
+		Family: nh.family,
+	}
 
-		if nlnh.Family > 0 {
-			nlnh.HardwareAddr = dstMac
-			nlnh.Flags = netlink.NTF_SELF
-		}
+	if nlnh.Family > 0 {
+		nlnh.HardwareAddr = dstMac
+		nlnh.Flags = netlink.NTF_SELF
+	}
 
-		if nh.linkDst != "" {
-			nlnh.LinkIndex = iface.Attrs().Index
-		}
+	if nh.linkDst != "" {
+		nlnh.LinkIndex = iface.Attrs().Index
+	}
 
-		if err := netlink.NeighDel(nlnh); err != nil {
-			return fmt.Errorf("could not delete neighbor entry: %v", err)
-		}
+	if err := nlh.NeighDel(nlnh); err != nil {
+		return fmt.Errorf("could not delete neighbor entry: %v", err)
+	}
 
-		for i, nh := range n.neighbors {
-			if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
-				n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...)
-			}
+	for i, nh := range n.neighbors {
+		if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
+			n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...)
 		}
+	}
 
-		return nil
-	})
+	return nil
 }
 
 func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, options ...NeighOption) error {
+	var (
+		iface netlink.Link
+		err   error
+	)
+
 	nh := n.findNeighbor(dstIP, dstMac)
 	if nh != nil {
 		// If it exists silently return
@@ -100,39 +109,38 @@ func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, op
 		}
 	}
 
-	return nsInvoke(n.nsPath(), func(nsFD int) error { return nil }, func(callerFD int) error {
-		var iface netlink.Link
-
-		if nh.linkDst != "" {
-			var err error
-			iface, err = netlink.LinkByName(nh.linkDst)
-			if err != nil {
-				return fmt.Errorf("could not find interface with destination name %s: %v",
-					nh.linkDst, err)
-			}
+	n.Lock()
+	nlh := n.nlHandle
+	n.Unlock()
+
+	if nh.linkDst != "" {
+		iface, err = nlh.LinkByName(nh.linkDst)
+		if err != nil {
+			return fmt.Errorf("could not find interface with destination name %s: %v",
+				nh.linkDst, err)
 		}
+	}
 
-		nlnh := &netlink.Neigh{
-			IP:           dstIP,
-			HardwareAddr: dstMac,
-			State:        netlink.NUD_PERMANENT,
-			Family:       nh.family,
-		}
+	nlnh := &netlink.Neigh{
+		IP:           dstIP,
+		HardwareAddr: dstMac,
+		State:        netlink.NUD_PERMANENT,
+		Family:       nh.family,
+	}
 
-		if nlnh.Family > 0 {
-			nlnh.Flags = netlink.NTF_SELF
-		}
+	if nlnh.Family > 0 {
+		nlnh.Flags = netlink.NTF_SELF
+	}
 
-		if nh.linkDst != "" {
-			nlnh.LinkIndex = iface.Attrs().Index
-		}
+	if nh.linkDst != "" {
+		nlnh.LinkIndex = iface.Attrs().Index
+	}
 
-		if err := netlink.NeighSet(nlnh); err != nil {
-			return fmt.Errorf("could not add neighbor entry: %v", err)
-		}
+	if err := nlh.NeighSet(nlnh); err != nil {
+		return fmt.Errorf("could not add neighbor entry: %v", err)
+	}
 
-		n.neighbors = append(n.neighbors, nh)
+	n.neighbors = append(n.neighbors, nh)
 
-		return nil
-	})
+	return nil
 }

+ 39 - 45
libnetwork/osl/route_linux.go

@@ -53,7 +53,7 @@ func (n *networkNamespace) SetGateway(gw net.IP) error {
 		return nil
 	}
 
-	err := programGateway(n.nsPath(), gw, true)
+	err := n.programGateway(gw, true)
 	if err == nil {
 		n.setGateway(gw)
 	}
@@ -69,7 +69,7 @@ func (n *networkNamespace) UnsetGateway() error {
 		return nil
 	}
 
-	err := programGateway(n.nsPath(), gw, false)
+	err := n.programGateway(gw, false)
 	if err == nil {
 		n.setGateway(net.IP{})
 	}
@@ -77,60 +77,54 @@ func (n *networkNamespace) UnsetGateway() error {
 	return err
 }
 
-func programGateway(path string, gw net.IP, isAdd bool) error {
-	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
-		gwRoutes, err := netlink.RouteGet(gw)
-		if err != nil {
-			return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
-		}
-
-		if isAdd {
-			return netlink.RouteAdd(&netlink.Route{
-				Scope:     netlink.SCOPE_UNIVERSE,
-				LinkIndex: gwRoutes[0].LinkIndex,
-				Gw:        gw,
-			})
-		}
+func (n *networkNamespace) programGateway(gw net.IP, isAdd bool) error {
+	gwRoutes, err := n.nlHandle.RouteGet(gw)
+	if err != nil {
+		return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
+	}
 
-		return netlink.RouteDel(&netlink.Route{
+	if isAdd {
+		return n.nlHandle.RouteAdd(&netlink.Route{
 			Scope:     netlink.SCOPE_UNIVERSE,
 			LinkIndex: gwRoutes[0].LinkIndex,
 			Gw:        gw,
 		})
+	}
+
+	return n.nlHandle.RouteDel(&netlink.Route{
+		Scope:     netlink.SCOPE_UNIVERSE,
+		LinkIndex: gwRoutes[0].LinkIndex,
+		Gw:        gw,
 	})
 }
 
 // Program a route in to the namespace routing table.
-func programRoute(path string, dest *net.IPNet, nh net.IP) error {
-	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
-		gwRoutes, err := netlink.RouteGet(nh)
-		if err != nil {
-			return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
-		}
+func (n *networkNamespace) programRoute(path string, dest *net.IPNet, nh net.IP) error {
+	gwRoutes, err := n.nlHandle.RouteGet(nh)
+	if err != nil {
+		return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
+	}
 
-		return netlink.RouteAdd(&netlink.Route{
-			Scope:     netlink.SCOPE_UNIVERSE,
-			LinkIndex: gwRoutes[0].LinkIndex,
-			Gw:        nh,
-			Dst:       dest,
-		})
+	return n.nlHandle.RouteAdd(&netlink.Route{
+		Scope:     netlink.SCOPE_UNIVERSE,
+		LinkIndex: gwRoutes[0].LinkIndex,
+		Gw:        nh,
+		Dst:       dest,
 	})
 }
 
 // Delete a route from the namespace routing table.
-func removeRoute(path string, dest *net.IPNet, nh net.IP) error {
-	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
-		gwRoutes, err := netlink.RouteGet(nh)
-		if err != nil {
-			return fmt.Errorf("route for the next hop could not be found: %v", err)
-		}
+func (n *networkNamespace) removeRoute(path string, dest *net.IPNet, nh net.IP) error {
+	gwRoutes, err := n.nlHandle.RouteGet(nh)
+	if err != nil {
+		return fmt.Errorf("route for the next hop could not be found: %v", err)
+	}
 
-		return netlink.RouteDel(&netlink.Route{
-			Scope:     netlink.SCOPE_UNIVERSE,
-			LinkIndex: gwRoutes[0].LinkIndex,
-			Gw:        nh,
-			Dst:       dest,
-		})
+	return n.nlHandle.RouteDel(&netlink.Route{
+		Scope:     netlink.SCOPE_UNIVERSE,
+		LinkIndex: gwRoutes[0].LinkIndex,
+		Gw:        nh,
+		Dst:       dest,
 	})
 }
 
@@ -140,7 +134,7 @@ func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error {
 		return nil
 	}
 
-	err := programGateway(n.nsPath(), gwv6, true)
+	err := n.programGateway(gwv6, true)
 	if err == nil {
 		n.setGatewayIPv6(gwv6)
 	}
@@ -156,7 +150,7 @@ func (n *networkNamespace) UnsetGatewayIPv6() error {
 		return nil
 	}
 
-	err := programGateway(n.nsPath(), gwv6, false)
+	err := n.programGateway(gwv6, false)
 	if err == nil {
 		n.Lock()
 		n.gwv6 = net.IP{}
@@ -167,7 +161,7 @@ func (n *networkNamespace) UnsetGatewayIPv6() error {
 }
 
 func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
-	err := programRoute(n.nsPath(), r.Destination, r.NextHop)
+	err := n.programRoute(n.nsPath(), r.Destination, r.NextHop)
 	if err == nil {
 		n.Lock()
 		n.staticRoutes = append(n.staticRoutes, r)
@@ -178,7 +172,7 @@ func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
 
 func (n *networkNamespace) RemoveStaticRoute(r *types.StaticRoute) error {
 
-	err := removeRoute(n.nsPath(), r.Destination, r.NextHop)
+	err := n.removeRoute(n.nsPath(), r.Destination, r.NextHop)
 	if err == nil {
 		n.Lock()
 		lastIndex := len(n.staticRoutes) - 1

+ 18 - 25
libnetwork/osl/sandbox_linux_test.go

@@ -7,7 +7,6 @@ import (
 	"net"
 	"os"
 	"path/filepath"
-	"runtime"
 	"syscall"
 	"testing"
 	"time"
@@ -54,11 +53,11 @@ func newKey(t *testing.T) (string, error) {
 	return name, nil
 }
 
-func newInfo(t *testing.T) (Sandbox, error) {
+func newInfo(hnd *netlink.Handle, t *testing.T) (Sandbox, error) {
 	veth := &netlink.Veth{
 		LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0},
 		PeerName:  vethName2}
-	if err := netlink.LinkAdd(veth); err != nil {
+	if err := hnd.LinkAdd(veth); err != nil {
 		return nil, err
 	}
 
@@ -99,7 +98,7 @@ func newInfo(t *testing.T) (Sandbox, error) {
 		LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
 		PeerName:  vethName4}
 
-	if err := netlink.LinkAdd(veth); err != nil {
+	if err := hnd.LinkAdd(veth); err != nil {
 		return nil, err
 	}
 
@@ -123,29 +122,20 @@ func verifySandbox(t *testing.T, s Sandbox, ifaceSuffixes []string) {
 		t.Fatalf("The sandox interface returned is not of type networkNamespace")
 	}
 
-	origns, err := netns.Get()
-	if err != nil {
-		t.Fatalf("Could not get the current netns: %v", err)
-	}
-	defer origns.Close()
-
-	f, err := os.OpenFile(s.Key(), os.O_RDONLY, 0)
+	sbNs, err := netns.GetFromPath(s.Key())
 	if err != nil {
 		t.Fatalf("Failed top open network namespace path %q: %v", s.Key(), err)
 	}
-	defer f.Close()
+	defer sbNs.Close()
 
-	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
-
-	nsFD := f.Fd()
-	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)
+	nh, err := netlink.NewHandleAt(sbNs)
+	if err != nil {
+		t.Fatal(err)
 	}
-	defer netns.Set(origns)
+	defer nh.Delete()
 
 	for _, suffix := range ifaceSuffixes {
-		_, err = netlink.LinkByName(sboxIfaceName + suffix)
+		_, err = nh.LinkByName(sboxIfaceName + suffix)
 		if err != nil {
 			t.Fatalf("Could not find the interface %s inside the sandbox: %v",
 				sboxIfaceName+suffix, err)
@@ -207,23 +197,26 @@ func TestDisableIPv6DAD(t *testing.T) {
 		LinkAttrs: netlink.LinkAttrs{Name: "sideA"},
 		PeerName:  "sideB",
 	}
-
-	err := netlink.LinkAdd(veth)
+	nlh, err := netlink.NewHandle()
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = nlh.LinkAdd(veth)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	link, err := netlink.LinkByName("sideA")
+	link, err := nlh.LinkByName("sideA")
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	err = setInterfaceIPv6(link, iface)
+	err = setInterfaceIPv6(nlh, link, iface)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	addrList, err := netlink.AddrList(link, nl.FAMILY_V6)
+	addrList, err := nlh.AddrList(link, nl.FAMILY_V6)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 3 - 12
libnetwork/osl/sandbox_test.go

@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/pkg/reexec"
+	"github.com/docker/libnetwork/ns"
 	"github.com/docker/libnetwork/testutils"
 )
 
@@ -34,7 +35,7 @@ func TestSandboxCreate(t *testing.T) {
 		t.Fatalf("s.Key() returned %s. Expected %s", s.Key(), key)
 	}
 
-	tbox, err := newInfo(t)
+	tbox, err := newInfo(ns.NlHandle(), t)
 	if err != nil {
 		t.Fatalf("Failed to generate new sandbox info: %v", err)
 	}
@@ -47,23 +48,19 @@ func TestSandboxCreate(t *testing.T) {
 		if err != nil {
 			t.Fatalf("Failed to add interfaces to sandbox: %v", err)
 		}
-		runtime.LockOSThread()
 	}
 
 	err = s.SetGateway(tbox.Info().Gateway())
 	if err != nil {
 		t.Fatalf("Failed to set gateway to sandbox: %v", err)
 	}
-	runtime.LockOSThread()
 
 	err = s.SetGatewayIPv6(tbox.Info().GatewayIPv6())
 	if err != nil {
 		t.Fatalf("Failed to set ipv6 gateway to sandbox: %v", err)
 	}
-	runtime.LockOSThread()
 
 	verifySandbox(t, s, []string{"0", "1", "2"})
-	runtime.LockOSThread()
 
 	err = s.Destroy()
 	if err != nil {
@@ -140,7 +137,7 @@ func TestAddRemoveInterface(t *testing.T) {
 		t.Fatalf("s.Key() returned %s. Expected %s", s.Key(), key)
 	}
 
-	tbox, err := newInfo(t)
+	tbox, err := newInfo(ns.NlHandle(), t)
 	if err != nil {
 		t.Fatalf("Failed to generate new sandbox info: %v", err)
 	}
@@ -153,20 +150,16 @@ func TestAddRemoveInterface(t *testing.T) {
 		if err != nil {
 			t.Fatalf("Failed to add interfaces to sandbox: %v", err)
 		}
-		runtime.LockOSThread()
 	}
 
 	verifySandbox(t, s, []string{"0", "1", "2"})
-	runtime.LockOSThread()
 
 	interfaces := s.Info().Interfaces()
 	if err := interfaces[0].Remove(); err != nil {
 		t.Fatalf("Failed to remove interfaces from sandbox: %v", err)
 	}
-	runtime.LockOSThread()
 
 	verifySandbox(t, s, []string{"1", "2"})
-	runtime.LockOSThread()
 
 	i := tbox.Info().Interfaces()[0]
 	if err := s.AddInterface(i.SrcName(), i.DstName(),
@@ -175,10 +168,8 @@ func TestAddRemoveInterface(t *testing.T) {
 		tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6())); err != nil {
 		t.Fatalf("Failed to add interfaces to sandbox: %v", err)
 	}
-	runtime.LockOSThread()
 
 	verifySandbox(t, s, []string{"1", "2", "3"})
-	runtime.LockOSThread()
 
 	err = s.Destroy()
 	if err != nil {

+ 1 - 1
libnetwork/sandbox_dns_unix.go

@@ -239,7 +239,7 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
 	if currHash != "" && currHash != currRC.Hash {
 		// Seems the user has changed the container resolv.conf since the last time
 		// we checked so return without doing anything.
-		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
+		//log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
 		return nil
 	}
 

+ 1 - 1
libnetwork/store_test.go

@@ -13,7 +13,7 @@ import (
 	"github.com/docker/libnetwork/options"
 )
 
-func TestZooKeeperBackend(t *testing.T) {
+func testZooKeeperBackend(t *testing.T) {
 	c, err := testNewController(t, "zk", "127.0.0.1:2181/custom_prefix")
 	if err != nil {
 		t.Fatal(err)

+ 2 - 0
libnetwork/testutils/context_unix.go

@@ -33,6 +33,8 @@ func SetupTestOSContext(t *testing.T) func() {
 	// sure to re-initialize initNs context
 	ns.Init()
 
+	runtime.LockOSThread()
+
 	return func() {
 		if err := syscall.Close(fd); err != nil {
 			t.Logf("Warning: netns closing failed (%v)", err)