From 6d3fa9e0f28fc3a479358426f8654b4f7ba75d24 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 16 May 2016 11:51:40 -0700 Subject: [PATCH] Migrate libnetwork to use netlink.Handle Signed-off-by: Alessandro Boch --- libnetwork/drivers/bridge/bridge.go | 51 ++-- libnetwork/drivers/bridge/bridge_store.go | 2 +- libnetwork/drivers/bridge/bridge_test.go | 36 ++- libnetwork/drivers/bridge/interface.go | 22 +- libnetwork/drivers/bridge/interface_test.go | 12 +- libnetwork/drivers/bridge/setup_device.go | 12 +- .../drivers/bridge/setup_device_test.go | 32 ++- .../drivers/bridge/setup_ip_tables_test.go | 16 +- libnetwork/drivers/bridge/setup_ipv4.go | 4 +- libnetwork/drivers/bridge/setup_ipv4_test.go | 22 +- libnetwork/drivers/bridge/setup_ipv6.go | 2 +- libnetwork/drivers/bridge/setup_ipv6_test.go | 18 +- libnetwork/drivers/bridge/setup_verify.go | 6 +- .../drivers/bridge/setup_verify_test.go | 8 +- libnetwork/drivers/ipvlan/ipvlan_endpoint.go | 6 +- libnetwork/drivers/ipvlan/ipvlan_joinleave.go | 3 +- libnetwork/drivers/ipvlan/ipvlan_setup.go | 27 +- .../drivers/macvlan/macvlan_endpoint.go | 6 +- .../drivers/macvlan/macvlan_joinleave.go | 3 +- libnetwork/drivers/macvlan/macvlan_setup.go | 27 +- libnetwork/drivers/overlay/joinleave.go | 14 +- libnetwork/drivers/overlay/ov_endpoint.go | 8 +- libnetwork/drivers/overlay/ov_network.go | 15 +- libnetwork/drivers/overlay/ov_utils.go | 36 +-- libnetwork/libnetwork_test.go | 48 +--- libnetwork/netutils/utils_linux.go | 22 +- libnetwork/netutils/utils_test.go | 6 +- libnetwork/ns/init_linux.go | 27 +- libnetwork/osl/interface_linux.go | 239 +++++++++--------- libnetwork/osl/namespace_linux.go | 80 ++++-- libnetwork/osl/neigh_linux.go | 130 +++++----- libnetwork/osl/route_linux.go | 84 +++--- libnetwork/osl/sandbox_linux_test.go | 43 ++-- libnetwork/osl/sandbox_test.go | 15 +- libnetwork/sandbox_dns_unix.go | 2 +- libnetwork/store_test.go | 2 +- libnetwork/testutils/context_unix.go | 2 + 37 files changed, 597 insertions(+), 491 deletions(-) diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index baa38db5a4..4064e6272a 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/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 diff --git a/libnetwork/drivers/bridge/bridge_store.go b/libnetwork/drivers/bridge/bridge_store.go index de9635289a..e10a429ed2 100644 --- a/libnetwork/drivers/bridge/bridge_store.go +++ b/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) } } diff --git a/libnetwork/drivers/bridge/bridge_test.go b/libnetwork/drivers/bridge/bridge_test.go index 988df41ac5..53445d1412 100644 --- a/libnetwork/drivers/bridge/bridge_test.go +++ b/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 { diff --git a/libnetwork/drivers/bridge/interface.go b/libnetwork/drivers/bridge/interface.go index 3207cf9ebf..4a5dbfcbe5 100644 --- a/libnetwork/drivers/bridge/interface.go +++ b/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 diff --git a/libnetwork/drivers/bridge/interface_test.go b/libnetwork/drivers/bridge/interface_test.go index 2e44b65ba3..48b479ca49 100644 --- a/libnetwork/drivers/bridge/interface_test.go +++ b/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) diff --git a/libnetwork/drivers/bridge/setup_device.go b/libnetwork/drivers/bridge/setup_device.go index ddd9e452d0..0961bea55d 100644 --- a/libnetwork/drivers/bridge/setup_device.go +++ b/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 } diff --git a/libnetwork/drivers/bridge/setup_device_test.go b/libnetwork/drivers/bridge/setup_device_test.go index aaaed15a32..aeb2c3fde3 100644 --- a/libnetwork/drivers/bridge/setup_device_test.go +++ b/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)() - config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true} - br := &bridgeInterface{} + nh, err := netlink.NewHandle() + if err != nil { + t.Fatal(err) + } + defer nh.Delete() - err := setupDevice(config, br) + config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true} + br := &bridgeInterface{nlh: nh} + + 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") } diff --git a/libnetwork/drivers/bridge/setup_ip_tables_test.go b/libnetwork/drivers/bridge/setup_ip_tables_test.go index 983f225f36..20c70734ae 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables_test.go +++ b/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) diff --git a/libnetwork/drivers/bridge/setup_ipv4.go b/libnetwork/drivers/bridge/setup_ipv4.go index db913909c1..f11adc2cb1 100644 --- a/libnetwork/drivers/bridge/setup_ipv4.go +++ b/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} } } diff --git a/libnetwork/drivers/bridge/setup_ipv4_test.go b/libnetwork/drivers/bridge/setup_ipv4_test.go index 785de6ee45..aa408cb626 100644 --- a/libnetwork/drivers/bridge/setup_ipv4_test.go +++ b/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) diff --git a/libnetwork/drivers/bridge/setup_ipv6.go b/libnetwork/drivers/bridge/setup_ipv6.go index 3f07a0af8f..ee3d753ac1 100644 --- a/libnetwork/drivers/bridge/setup_ipv6.go +++ b/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, diff --git a/libnetwork/drivers/bridge/setup_ipv6_test.go b/libnetwork/drivers/bridge/setup_ipv6_test.go index 8ab9225859..11c3a9d6a7 100644 --- a/libnetwork/drivers/bridge/setup_ipv6_test.go +++ b/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) diff --git a/libnetwork/drivers/bridge/setup_verify.go b/libnetwork/drivers/bridge/setup_verify.go index 4564d46ded..f6ef7ae552 100644 --- a/libnetwork/drivers/bridge/setup_verify.go +++ b/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) } } diff --git a/libnetwork/drivers/bridge/setup_verify_test.go b/libnetwork/drivers/bridge/setup_verify_test.go index 3222c407d6..6ea668a9da 100644 --- a/libnetwork/drivers/bridge/setup_verify_test.go +++ b/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) diff --git a/libnetwork/drivers/ipvlan/ipvlan_endpoint.go b/libnetwork/drivers/ipvlan/ipvlan_endpoint.go index c192408e2e..204c83f74b 100644 --- a/libnetwork/drivers/ipvlan/ipvlan_endpoint.go +++ b/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 diff --git a/libnetwork/drivers/ipvlan/ipvlan_joinleave.go b/libnetwork/drivers/ipvlan/ipvlan_joinleave.go index 771f126d0b..b0be3d68d7 100644 --- a/libnetwork/drivers/ipvlan/ipvlan_joinleave.go +++ b/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) } diff --git a/libnetwork/drivers/ipvlan/ipvlan_setup.go b/libnetwork/drivers/ipvlan/ipvlan_setup.go index 60d3d965ca..97db98c56f 100644 --- a/libnetwork/drivers/ipvlan/ipvlan_setup.go +++ b/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) diff --git a/libnetwork/drivers/macvlan/macvlan_endpoint.go b/libnetwork/drivers/macvlan/macvlan_endpoint.go index ee52ec54b1..3187a54562 100644 --- a/libnetwork/drivers/macvlan/macvlan_endpoint.go +++ b/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 diff --git a/libnetwork/drivers/macvlan/macvlan_joinleave.go b/libnetwork/drivers/macvlan/macvlan_joinleave.go index 04df3723c4..3656fdfe3f 100644 --- a/libnetwork/drivers/macvlan/macvlan_joinleave.go +++ b/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) } diff --git a/libnetwork/drivers/macvlan/macvlan_setup.go b/libnetwork/drivers/macvlan/macvlan_setup.go index 8a56e88589..a3e17f28e2 100644 --- a/libnetwork/drivers/macvlan/macvlan_setup.go +++ b/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) diff --git a/libnetwork/drivers/overlay/joinleave.go b/libnetwork/drivers/overlay/joinleave.go index 9e513feaaa..618c407fa7 100644 --- a/libnetwork/drivers/overlay/joinleave.go +++ b/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. @@ -57,14 +57,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 } @@ -74,16 +76,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) } diff --git a/libnetwork/drivers/overlay/ov_endpoint.go b/libnetwork/drivers/overlay/ov_endpoint.go index 2dd288fd26..96757abc4e 100644 --- a/libnetwork/drivers/overlay/ov_endpoint.go +++ b/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) } diff --git a/libnetwork/drivers/overlay/ov_network.go b/libnetwork/drivers/overlay/ov_network.go index d1cf940491..14d0571c89 100644 --- a/libnetwork/drivers/overlay/ov_network.go +++ b/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" @@ -308,24 +309,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 } } diff --git a/libnetwork/drivers/overlay/ov_utils.go b/libnetwork/drivers/overlay/ov_utils.go index b9266f4188..46e84518db 100644 --- a/libnetwork/drivers/overlay/ov_utils.go +++ b/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 } } diff --git a/libnetwork/libnetwork_test.go b/libnetwork/libnetwork_test.go index b63ff0f801..b27bde9fe8 100644 --- a/libnetwork/libnetwork_test.go +++ b/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() + 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", 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) } diff --git a/libnetwork/netutils/utils_linux.go b/libnetwork/netutils/utils_linux.go index f1e73d2297..7781bc6a09 100644 --- a/libnetwork/netutils/utils_linux.go +++ b/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 } diff --git a/libnetwork/netutils/utils_test.go b/libnetwork/netutils/utils_test.go index 961e8d48a2..a81effde0d 100644 --- a/libnetwork/netutils/utils_test.go +++ b/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 { diff --git a/libnetwork/ns/init_linux.go b/libnetwork/ns/init_linux.go index 2292cb6877..ea0cfc0593 100644 --- a/libnetwork/ns/init_linux.go +++ b/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 +} diff --git a/libnetwork/osl/interface_linux.go b/libnetwork/osl/interface_linux.go index a535b37500..63fcf5561d 100644 --- a/libnetwork/osl/interface_linux.go +++ b/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 { + // 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 := nlh.LinkSetDown(iface); err != nil { + 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 := 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 } + } - // Down the interface before configuring - if err := netlink.LinkSetDown(iface); err != nil { - 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.Unlock() - err = netlink.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 - } - } - - n.Lock() - for index, intf := range n.iFaces { - if intf == i { - n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...) - break - } - } - 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 " 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 { + newNs, err := netns.GetFromPath(path) + if err != nil { + return fmt.Errorf("failed get network namespace %q: %v", path, 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) } } + } - return nil - }, func(callerFD int) error { - if i.bridge { - link := &netlink.Bridge{ - LinkAttrs: netlink.LinkAttrs{ - Name: i.srcName, - }, - } + // 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) + } - if err := netlink.LinkAdd(link); err != nil { - return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err) - } - } + // Down the interface before configuring + if err := nlh.LinkSetDown(iface); err != nil { + return fmt.Errorf("failed to set link down: %v", 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) - } + // Configure the interface now this is moved in the proper namespace. + if err := configureInterface(nlh, iface, i); err != nil { + return err + } - // Down the interface before configuring - if err := netlink.LinkSetDown(iface); err != nil { - return fmt.Errorf("failed to set link down: %v", err) - } + // Up the interface. + if err := nlh.LinkSetUp(iface); err != nil { + return fmt.Errorf("failed to set link up: %v", err) + } - // Configure the interface now this is moved in the proper namespace. - if err := configureInterface(iface, i); err != nil { - return 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) + } - // Up the interface. - if err := netlink.LinkSetUp(iface); err != nil { - return fmt.Errorf("failed to set link up: %v", err) - } + n.Lock() + n.iFaces = append(n.iFaces, i) + n.Unlock() - // 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) - } - - 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, diff --git a/libnetwork/osl/namespace_linux.go b/libnetwork/osl/namespace_linux.go index 07b725c290..c804caf783 100644 --- a/libnetwork/osl/namespace_linux.go +++ b/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 { diff --git a/libnetwork/osl/neigh_linux.go b/libnetwork/osl/neigh_linux.go index a221e712da..c5c6c103d0 100644 --- a/libnetwork/osl/neigh_linux.go +++ b/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 + n.Lock() + nlh := n.nlHandle + n.Unlock() - 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) - } + 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 nh.linkDst != "" { + nlnh.LinkIndex = iface.Attrs().Index + } + + 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:]...) } + } - if nlnh.Family > 0 { - nlnh.HardwareAddr = dstMac - nlnh.Flags = netlink.NTF_SELF - } - - 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) - } - - 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 + n.Lock() + nlh := n.nlHandle + n.Unlock() - 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) - } + 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 } diff --git a/libnetwork/osl/route_linux.go b/libnetwork/osl/route_linux.go index 09a0a45f89..78d1f9a14f 100644 --- a/libnetwork/osl/route_linux.go +++ b/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) - } +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) + } - if isAdd { - return netlink.RouteAdd(&netlink.Route{ - Scope: netlink.SCOPE_UNIVERSE, - LinkIndex: gwRoutes[0].LinkIndex, - Gw: gw, - }) - } - - 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 diff --git a/libnetwork/osl/sandbox_linux_test.go b/libnetwork/osl/sandbox_linux_test.go index 7414e0a5d8..1c5373e134 100644 --- a/libnetwork/osl/sandbox_linux_test.go +++ b/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) } diff --git a/libnetwork/osl/sandbox_test.go b/libnetwork/osl/sandbox_test.go index 469c9604d8..019ec0e09e 100644 --- a/libnetwork/osl/sandbox_test.go +++ b/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 { diff --git a/libnetwork/sandbox_dns_unix.go b/libnetwork/sandbox_dns_unix.go index 8d59e3d66a..5a3edba498 100644 --- a/libnetwork/sandbox_dns_unix.go +++ b/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 } diff --git a/libnetwork/store_test.go b/libnetwork/store_test.go index 7741004423..9ef9fcef68 100644 --- a/libnetwork/store_test.go +++ b/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) diff --git a/libnetwork/testutils/context_unix.go b/libnetwork/testutils/context_unix.go index 5908c05be6..17ce4fef95 100644 --- a/libnetwork/testutils/context_unix.go +++ b/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)