瀏覽代碼

Merge pull request #44827 from corhere/libnw/drop-electinterfaceaddresses

libnetwork: reduce usage of shared mutable state in ipamutils
Cory Snider 2 年之前
父節點
當前提交
6c9dd8b650

+ 41 - 0
daemon/daemon_linux.go

@@ -4,16 +4,19 @@ import (
 	"bufio"
 	"fmt"
 	"io"
+	"net"
 	"os"
 	"regexp"
 	"strings"
 
 	"github.com/docker/docker/daemon/config"
+	"github.com/docker/docker/libnetwork/ns"
 	"github.com/docker/docker/libnetwork/resolvconf"
 	"github.com/moby/sys/mount"
 	"github.com/moby/sys/mountinfo"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
+	"github.com/vishvananda/netlink"
 )
 
 // On Linux, plugins use a static path for storing execution state,
@@ -141,3 +144,41 @@ func setupResolvConf(config *config.Config) {
 	}
 	config.ResolvConf = resolvconf.Path()
 }
+
+// ifaceAddrs returns the IPv4 and IPv6 addresses assigned to the network
+// interface with name linkName.
+//
+// No error is returned if the named interface does not exist.
+func ifaceAddrs(linkName string) (v4, v6 []*net.IPNet, err error) {
+	nl := ns.NlHandle()
+	link, err := nl.LinkByName(linkName)
+	if err != nil {
+		if !errors.As(err, new(netlink.LinkNotFoundError)) {
+			return nil, nil, err
+		}
+		return nil, nil, nil
+	}
+
+	get := func(family int) ([]*net.IPNet, error) {
+		addrs, err := nl.AddrList(link, family)
+		if err != nil {
+			return nil, err
+		}
+
+		ipnets := make([]*net.IPNet, len(addrs))
+		for i := range addrs {
+			ipnets[i] = addrs[i].IPNet
+		}
+		return ipnets, nil
+	}
+
+	v4, err = get(netlink.FAMILY_V4)
+	if err != nil {
+		return nil, nil, err
+	}
+	v6, err = get(netlink.FAMILY_V6)
+	if err != nil {
+		return nil, nil, err
+	}
+	return v4, v6, nil
+}

+ 68 - 0
daemon/daemon_linux_test.go

@@ -4,6 +4,7 @@
 package daemon // import "github.com/docker/docker/daemon"
 
 import (
+	"net"
 	"os"
 	"path/filepath"
 	"strings"
@@ -11,8 +12,12 @@ import (
 
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/daemon/config"
+	"github.com/docker/docker/libnetwork/testutils"
+	"github.com/docker/docker/libnetwork/types"
+	"github.com/google/go-cmp/cmp/cmpopts"
 	"github.com/moby/sys/mount"
 	"github.com/moby/sys/mountinfo"
+	"github.com/vishvananda/netlink"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
 )
@@ -343,3 +348,66 @@ func TestRootMountCleanup(t *testing.T) {
 		assert.Assert(t, d.cleanupMounts())
 	})
 }
+
+func TestIfaceAddrs(t *testing.T) {
+	CIDR := func(cidr string) *net.IPNet {
+		t.Helper()
+		nw, err := types.ParseCIDR(cidr)
+		assert.NilError(t, err)
+		return nw
+	}
+
+	for _, tt := range []struct {
+		name string
+		nws  []*net.IPNet
+	}{
+		{
+			name: "Single",
+			nws:  []*net.IPNet{CIDR("172.101.202.254/16")},
+		},
+		{
+			name: "Multiple",
+			nws: []*net.IPNet{
+				CIDR("172.101.202.254/16"),
+				CIDR("172.102.202.254/16"),
+			},
+		},
+	} {
+		t.Run(tt.name, func(t *testing.T) {
+			defer testutils.SetupTestOSContext(t)()
+
+			createBridge(t, "test", tt.nws...)
+
+			ipv4Nw, ipv6Nw, err := ifaceAddrs("test")
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			assert.Check(t, is.DeepEqual(tt.nws, ipv4Nw,
+				cmpopts.SortSlices(func(a, b *net.IPNet) bool { return a.String() < b.String() })))
+			// IPv6 link-local address
+			assert.Check(t, is.Len(ipv6Nw, 1))
+		})
+	}
+}
+
+func createBridge(t *testing.T, name string, bips ...*net.IPNet) {
+	t.Helper()
+
+	link := &netlink.Bridge{
+		LinkAttrs: netlink.LinkAttrs{
+			Name: name,
+		},
+	}
+	if err := netlink.LinkAdd(link); err != nil {
+		t.Fatalf("Failed to create interface via netlink: %v", err)
+	}
+	for _, bip := range bips {
+		if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: bip}); err != nil {
+			t.Fatal(err)
+		}
+	}
+	if err := netlink.LinkSetUp(link); err != nil {
+		t.Fatal(err)
+	}
+}

+ 24 - 18
daemon/daemon_unix.go

@@ -35,7 +35,6 @@ import (
 	nwconfig "github.com/docker/docker/libnetwork/config"
 	"github.com/docker/docker/libnetwork/drivers/bridge"
 	"github.com/docker/docker/libnetwork/netlabel"
-	"github.com/docker/docker/libnetwork/netutils"
 	"github.com/docker/docker/libnetwork/options"
 	lntypes "github.com/docker/docker/libnetwork/types"
 	"github.com/docker/docker/opts"
@@ -950,30 +949,37 @@ func initBridgeDriver(controller *libnetwork.Controller, config *config.Config)
 
 	ipamV4Conf := &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
 
-	nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName)
+	// By default, libnetwork will request an arbitrary available address
+	// pool for the network from the configured IPAM allocator.
+	// Configure it to use the IPv4 network ranges of the existing bridge
+	// interface if one exists with IPv4 addresses assigned to it.
+
+	nwList, nw6List, err := ifaceAddrs(bridgeName)
 	if err != nil {
 		return errors.Wrap(err, "list bridge addresses failed")
 	}
 
-	nw := nwList[0]
-	if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" {
-		_, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR)
-		if err != nil {
-			return errors.Wrap(err, "parse CIDR failed")
-		}
-		// Iterate through in case there are multiple addresses for the bridge
-		for _, entry := range nwList {
-			if fCIDR.Contains(entry.IP) {
-				nw = entry
-				break
+	if len(nwList) > 0 {
+		nw := nwList[0]
+		if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" {
+			_, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR)
+			if err != nil {
+				return errors.Wrap(err, "parse CIDR failed")
+			}
+			// Iterate through in case there are multiple addresses for the bridge
+			for _, entry := range nwList {
+				if fCIDR.Contains(entry.IP) {
+					nw = entry
+					break
+				}
 			}
 		}
-	}
 
-	ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
-	hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
-	if hip.IsGlobalUnicast() {
-		ipamV4Conf.Gateway = nw.IP.String()
+		ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
+		hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
+		if hip.IsGlobalUnicast() {
+			ipamV4Conf.Gateway = nw.IP.String()
+		}
 	}
 
 	if config.BridgeConfig.IP != "" {

+ 13 - 4
libnetwork/drivers/bridge/bridge_test.go

@@ -13,6 +13,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/libnetwork/driverapi"
+	"github.com/docker/docker/libnetwork/ipamutils"
 	"github.com/docker/docker/libnetwork/iptables"
 	"github.com/docker/docker/libnetwork/netlabel"
 	"github.com/docker/docker/libnetwork/netutils"
@@ -169,13 +170,13 @@ func compareBindings(a, b []types.PortBinding) bool {
 
 func getIPv4Data(t *testing.T, iface string) []driverapi.IPAMData {
 	ipd := driverapi.IPAMData{AddressSpace: "full"}
-	nws, _, err := netutils.ElectInterfaceAddresses(iface)
+	nw, err := netutils.FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
-	ipd.Pool = nws[0]
+	ipd.Pool = nw
 	// Set network gateway to X.X.X.1
-	ipd.Gateway = types.GetIPNetCopy(nws[0])
+	ipd.Gateway = types.GetIPNetCopy(nw)
 	ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
 	return []driverapi.IPAMData{ipd}
 }
@@ -1049,7 +1050,15 @@ func TestCreateWithExistingBridge(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 
-	if err := d.CreateNetwork(brName, genericOption, nil, getIPv4Data(t, brName), nil); err != nil {
+	ipv4Data := []driverapi.IPAMData{{
+		AddressSpace: "full",
+		Pool:         types.GetIPNetCopy(addr.IPNet),
+		Gateway:      types.GetIPNetCopy(addr.IPNet),
+	}}
+	// Set network gateway to X.X.X.1
+	ipv4Data[0].Gateway.IP[len(ipv4Data[0].Gateway.IP)-1] = 1
+
+	if err := d.CreateNetwork(brName, genericOption, nil, ipv4Data, nil); err != nil {
 		t.Fatalf("Failed to create bridge network: %v", err)
 	}
 

+ 6 - 1
libnetwork/drivers_ipam.go

@@ -10,7 +10,12 @@ import (
 )
 
 func initIPAMDrivers(r *drvregistry.DrvRegistry, lDs, gDs interface{}, addressPool []*ipamutils.NetworkToSplit) error {
-	builtinIpam.SetDefaultIPAddressPool(addressPool)
+	// TODO: pass address pools as arguments to builtinIpam.Init instead of
+	// indirectly through global mutable state. Swarmkit references that
+	// function so changing its signature breaks the build.
+	if err := builtinIpam.SetDefaultIPAddressPool(addressPool); err != nil {
+		return err
+	}
 	for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
 		builtinIpam.Init,
 		remoteIpam.Init,

+ 3 - 4
libnetwork/ipam/allocator.go

@@ -10,7 +10,6 @@ import (
 	"github.com/docker/docker/libnetwork/datastore"
 	"github.com/docker/docker/libnetwork/discoverapi"
 	"github.com/docker/docker/libnetwork/ipamapi"
-	"github.com/docker/docker/libnetwork/ipamutils"
 	"github.com/docker/docker/libnetwork/types"
 	"github.com/sirupsen/logrus"
 )
@@ -38,14 +37,14 @@ type Allocator struct {
 }
 
 // NewAllocator returns an instance of libnetwork ipam
-func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
+func NewAllocator(lcDs, glDs datastore.DataStore, lcAs, glAs []*net.IPNet) (*Allocator, error) {
 	a := &Allocator{}
 
 	// Load predefined subnet pools
 
 	a.predefined = map[string][]*net.IPNet{
-		localAddressSpace:  ipamutils.GetLocalScopeDefaultNetworks(),
-		globalAddressSpace: ipamutils.GetGlobalScopeDefaultNetworks(),
+		localAddressSpace:  lcAs,
+		globalAddressSpace: glAs,
 	}
 
 	// Initialize asIndices map

+ 8 - 7
libnetwork/ipam/allocator_test.go

@@ -16,6 +16,7 @@ import (
 	"github.com/docker/docker/libnetwork/bitseq"
 	"github.com/docker/docker/libnetwork/datastore"
 	"github.com/docker/docker/libnetwork/ipamapi"
+	"github.com/docker/docker/libnetwork/ipamutils"
 	"github.com/docker/docker/libnetwork/types"
 	"github.com/docker/libkv/store"
 	"github.com/docker/libkv/store/boltdb"
@@ -61,7 +62,7 @@ func getAllocator(store bool) (*Allocator, error) {
 	if err != nil {
 		return nil, err
 	}
-	return NewAllocator(ds, nil)
+	return NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
 }
 
 func TestInt2IP2IntConversion(t *testing.T) {
@@ -1287,7 +1288,7 @@ func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, s
 	ds, err := randomLocalStore(store)
 	assert.NilError(t, err)
 
-	a, err := NewAllocator(ds, nil)
+	a, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1355,7 +1356,7 @@ func TestRetrieveFromStore(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	a, err := NewAllocator(ds, nil)
+	a, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1370,7 +1371,7 @@ func TestRetrieveFromStore(t *testing.T) {
 	}
 
 	// Restore
-	a1, err := NewAllocator(ds, nil)
+	a1, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1392,7 +1393,7 @@ func TestRetrieveFromStore(t *testing.T) {
 	}
 
 	// Restore
-	a2, err := NewAllocator(ds, nil)
+	a2, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1409,7 +1410,7 @@ func TestRetrieveFromStore(t *testing.T) {
 	}
 
 	// Restore
-	a3, err := NewAllocator(ds, nil)
+	a3, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1426,7 +1427,7 @@ func TestRetrieveFromStore(t *testing.T) {
 	}
 
 	// Restore
-	a4, err := NewAllocator(ds, nil)
+	a4, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}

+ 62 - 0
libnetwork/ipams/builtin/builtin.go

@@ -0,0 +1,62 @@
+package builtin
+
+import (
+	"errors"
+	"net"
+
+	"github.com/docker/docker/libnetwork/datastore"
+	"github.com/docker/docker/libnetwork/ipam"
+	"github.com/docker/docker/libnetwork/ipamapi"
+	"github.com/docker/docker/libnetwork/ipamutils"
+)
+
+var (
+	// defaultAddressPool Stores user configured subnet list
+	defaultAddressPool []*net.IPNet
+)
+
+// initBuiltin registers the built-in ipam service with libnetwork
+func initBuiltin(ic ipamapi.Callback, l, g interface{}) error {
+	var (
+		ok                bool
+		localDs, globalDs datastore.DataStore
+	)
+
+	if l != nil {
+		if localDs, ok = l.(datastore.DataStore); !ok {
+			return errors.New("incorrect local datastore passed to built-in ipam init")
+		}
+	}
+
+	if g != nil {
+		if globalDs, ok = g.(datastore.DataStore); !ok {
+			return errors.New("incorrect global datastore passed to built-in ipam init")
+		}
+	}
+
+	var localAddressPool []*net.IPNet
+	if len(defaultAddressPool) > 0 {
+		localAddressPool = append([]*net.IPNet(nil), defaultAddressPool...)
+	} else {
+		localAddressPool = ipamutils.GetLocalScopeDefaultNetworks()
+	}
+
+	a, err := ipam.NewAllocator(localDs, globalDs, localAddressPool, ipamutils.GetGlobalScopeDefaultNetworks())
+	if err != nil {
+		return err
+	}
+
+	cps := &ipamapi.Capability{RequiresRequestReplay: true}
+
+	return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
+}
+
+// SetDefaultIPAddressPool stores default address pool.
+func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) error {
+	nets, err := ipamutils.SplitNetworks(addressPool)
+	if err != nil {
+		return err
+	}
+	defaultAddressPool = nets
+	return nil
+}

+ 2 - 53
libnetwork/ipams/builtin/builtin_unix.go

@@ -3,60 +3,9 @@
 
 package builtin
 
-import (
-	"errors"
-
-	"github.com/docker/docker/libnetwork/datastore"
-	"github.com/docker/docker/libnetwork/ipam"
-	"github.com/docker/docker/libnetwork/ipamapi"
-	"github.com/docker/docker/libnetwork/ipamutils"
-)
-
-var (
-	// defaultAddressPool Stores user configured subnet list
-	defaultAddressPool []*ipamutils.NetworkToSplit
-)
+import "github.com/docker/docker/libnetwork/ipamapi"
 
 // Init registers the built-in ipam service with libnetwork
 func Init(ic ipamapi.Callback, l, g interface{}) error {
-	var (
-		ok                bool
-		localDs, globalDs datastore.DataStore
-	)
-
-	if l != nil {
-		if localDs, ok = l.(datastore.DataStore); !ok {
-			return errors.New("incorrect local datastore passed to built-in ipam init")
-		}
-	}
-
-	if g != nil {
-		if globalDs, ok = g.(datastore.DataStore); !ok {
-			return errors.New("incorrect global datastore passed to built-in ipam init")
-		}
-	}
-
-	err := ipamutils.ConfigLocalScopeDefaultNetworks(GetDefaultIPAddressPool())
-	if err != nil {
-		return err
-	}
-
-	a, err := ipam.NewAllocator(localDs, globalDs)
-	if err != nil {
-		return err
-	}
-
-	cps := &ipamapi.Capability{RequiresRequestReplay: true}
-
-	return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
-}
-
-// SetDefaultIPAddressPool stores default address pool.
-func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
-	defaultAddressPool = addressPool
-}
-
-// GetDefaultIPAddressPool returns default address pool.
-func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
-	return defaultAddressPool
+	return initBuiltin(ic, l, g)
 }

+ 2 - 54
libnetwork/ipams/builtin/builtin_windows.go

@@ -4,70 +4,18 @@
 package builtin
 
 import (
-	"errors"
-
-	"github.com/docker/docker/libnetwork/datastore"
-	"github.com/docker/docker/libnetwork/ipam"
 	"github.com/docker/docker/libnetwork/ipamapi"
-	"github.com/docker/docker/libnetwork/ipamutils"
-
-	windowsipam "github.com/docker/docker/libnetwork/ipams/windowsipam"
-)
-
-var (
-	// defaultAddressPool Stores user configured subnet list
-	defaultAddressPool []*ipamutils.NetworkToSplit
+	"github.com/docker/docker/libnetwork/ipams/windowsipam"
 )
 
-// InitDockerDefault registers the built-in ipam service with libnetwork
-func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
-	var (
-		ok                bool
-		localDs, globalDs datastore.DataStore
-	)
-
-	if l != nil {
-		if localDs, ok = l.(datastore.DataStore); !ok {
-			return errors.New("incorrect local datastore passed to built-in ipam init")
-		}
-	}
-
-	if g != nil {
-		if globalDs, ok = g.(datastore.DataStore); !ok {
-			return errors.New("incorrect global datastore passed to built-in ipam init")
-		}
-	}
-
-	ipamutils.ConfigLocalScopeDefaultNetworks(nil)
-
-	a, err := ipam.NewAllocator(localDs, globalDs)
-	if err != nil {
-		return err
-	}
-
-	cps := &ipamapi.Capability{RequiresRequestReplay: true}
-
-	return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
-}
-
 // Init registers the built-in ipam service with libnetwork
 func Init(ic ipamapi.Callback, l, g interface{}) error {
 	initFunc := windowsipam.GetInit(windowsipam.DefaultIPAM)
 
-	err := InitDockerDefault(ic, l, g)
+	err := initBuiltin(ic, l, g)
 	if err != nil {
 		return err
 	}
 
 	return initFunc(ic, l, g)
 }
-
-// SetDefaultIPAddressPool stores default address pool .
-func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
-	defaultAddressPool = addressPool
-}
-
-// GetDefaultIPAddressPool returns default address pool .
-func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
-	return defaultAddressPool
-}

+ 20 - 36
libnetwork/ipamutils/utils.go

@@ -8,12 +8,12 @@ import (
 )
 
 var (
-	// PredefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
+	// predefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
 	// (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGlobalScopeDefaultNetworks`
-	PredefinedLocalScopeDefaultNetworks []*net.IPNet
-	// PredefinedGlobalScopeDefaultNetworks contains a list of 64K IPv4 private networks with host size 8
+	predefinedLocalScopeDefaultNetworks []*net.IPNet
+	// predefinedGlobalScopeDefaultNetworks contains a list of 64K IPv4 private networks with host size 8
 	// (10.x.x.x/24) which do not overlap with the networks in `PredefinedLocalScopeDefaultNetworks`
-	PredefinedGlobalScopeDefaultNetworks []*net.IPNet
+	predefinedGlobalScopeDefaultNetworks []*net.IPNet
 	mutex                                sync.Mutex
 	localScopeDefaultNetworks            = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16},
 		{"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16},
@@ -33,61 +33,45 @@ type NetworkToSplit struct {
 
 func init() {
 	var err error
-	if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); err != nil {
+	if predefinedGlobalScopeDefaultNetworks, err = SplitNetworks(globalScopeDefaultNetworks); err != nil {
 		panic("failed to initialize the global scope default address pool: " + err.Error())
 	}
 
-	if PredefinedLocalScopeDefaultNetworks, err = splitNetworks(localScopeDefaultNetworks); err != nil {
+	if predefinedLocalScopeDefaultNetworks, err = SplitNetworks(localScopeDefaultNetworks); err != nil {
 		panic("failed to initialize the local scope default address pool: " + err.Error())
 	}
 }
 
-// configDefaultNetworks configures local as well global default pool based on input
-func configDefaultNetworks(defaultAddressPool []*NetworkToSplit, result *[]*net.IPNet) error {
+// ConfigGlobalScopeDefaultNetworks configures global default pool.
+// Ideally this will be called from SwarmKit as part of swarm init
+func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
+	if defaultAddressPool == nil {
+		return nil
+	}
 	mutex.Lock()
 	defer mutex.Unlock()
-	defaultNetworks, err := splitNetworks(defaultAddressPool)
+	defaultNetworks, err := SplitNetworks(defaultAddressPool)
 	if err != nil {
 		return err
 	}
-	*result = defaultNetworks
+	predefinedGlobalScopeDefaultNetworks = defaultNetworks
 	return nil
 }
 
-// GetGlobalScopeDefaultNetworks returns PredefinedGlobalScopeDefaultNetworks
+// GetGlobalScopeDefaultNetworks returns a copy of the global-sopce network list.
 func GetGlobalScopeDefaultNetworks() []*net.IPNet {
 	mutex.Lock()
 	defer mutex.Unlock()
-	return PredefinedGlobalScopeDefaultNetworks
+	return append([]*net.IPNet(nil), predefinedGlobalScopeDefaultNetworks...)
 }
 
-// GetLocalScopeDefaultNetworks returns PredefinedLocalScopeDefaultNetworks
+// GetLocalScopeDefaultNetworks returns a copy of the default local-scope network list.
 func GetLocalScopeDefaultNetworks() []*net.IPNet {
-	mutex.Lock()
-	defer mutex.Unlock()
-	return PredefinedLocalScopeDefaultNetworks
-}
-
-// ConfigGlobalScopeDefaultNetworks configures global default pool.
-// Ideally this will be called from SwarmKit as part of swarm init
-func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
-	if defaultAddressPool == nil {
-		defaultAddressPool = globalScopeDefaultNetworks
-	}
-	return configDefaultNetworks(defaultAddressPool, &PredefinedGlobalScopeDefaultNetworks)
-}
-
-// ConfigLocalScopeDefaultNetworks configures local default pool.
-// Ideally this will be called during libnetwork init
-func ConfigLocalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
-	if defaultAddressPool == nil {
-		return nil
-	}
-	return configDefaultNetworks(defaultAddressPool, &PredefinedLocalScopeDefaultNetworks)
+	return append([]*net.IPNet(nil), predefinedLocalScopeDefaultNetworks...)
 }
 
-// splitNetworks takes a slice of networks, split them accordingly and returns them
-func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
+// SplitNetworks takes a slice of networks, split them accordingly and returns them
+func SplitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
 	localPools := make([]*net.IPNet, 0, len(list))
 
 	for _, p := range list {

+ 5 - 19
libnetwork/ipamutils/utils_test.go

@@ -44,13 +44,13 @@ func initGlobalScopeNetworks() []*net.IPNet {
 }
 
 func TestDefaultNetwork(t *testing.T) {
-	for _, nw := range PredefinedGlobalScopeDefaultNetworks {
+	for _, nw := range GetGlobalScopeDefaultNetworks() {
 		if ones, bits := nw.Mask.Size(); bits != 32 || ones != 24 {
 			t.Fatalf("Unexpected size for network in granular list: %v", nw)
 		}
 	}
 
-	for _, nw := range PredefinedLocalScopeDefaultNetworks {
+	for _, nw := range GetLocalScopeDefaultNetworks() {
 		if ones, bits := nw.Mask.Size(); bits != 32 || (ones != 20 && ones != 16) {
 			t.Fatalf("Unexpected size for network in broad list: %v", nw)
 		}
@@ -61,7 +61,7 @@ func TestDefaultNetwork(t *testing.T) {
 	for _, v := range originalBroadNets {
 		m[v.String()] = true
 	}
-	for _, nw := range PredefinedLocalScopeDefaultNetworks {
+	for _, nw := range GetLocalScopeDefaultNetworks() {
 		_, ok := m[nw.String()]
 		assert.Check(t, ok)
 		delete(m, nw.String())
@@ -75,7 +75,7 @@ func TestDefaultNetwork(t *testing.T) {
 	for _, v := range originalGranularNets {
 		m[v.String()] = true
 	}
-	for _, nw := range PredefinedGlobalScopeDefaultNetworks {
+	for _, nw := range GetGlobalScopeDefaultNetworks() {
 		_, ok := m[nw.String()]
 		assert.Check(t, ok)
 		delete(m, nw.String())
@@ -93,7 +93,7 @@ func TestConfigGlobalScopeDefaultNetworks(t *testing.T) {
 	for _, v := range originalGlobalScopeNetworks {
 		m[v.String()] = true
 	}
-	for _, nw := range PredefinedGlobalScopeDefaultNetworks {
+	for _, nw := range GetGlobalScopeDefaultNetworks() {
 		_, ok := m[nw.String()]
 		assert.Check(t, ok)
 		delete(m, nw.String())
@@ -101,17 +101,3 @@ func TestConfigGlobalScopeDefaultNetworks(t *testing.T) {
 
 	assert.Check(t, is.Len(m, 0))
 }
-
-func TestInitAddressPools(t *testing.T) {
-	err := ConfigLocalScopeDefaultNetworks([]*NetworkToSplit{{"172.80.0.0/16", 24}, {"172.90.0.0/16", 24}})
-	assert.NilError(t, err)
-
-	// Check for Random IPAddresses in PredefinedLocalScopeDefaultNetworks  ex: first , last and middle
-	assert.Check(t, is.Len(PredefinedLocalScopeDefaultNetworks, 512), "Failed to find PredefinedLocalScopeDefaultNetworks")
-	assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[0].String(), "172.80.0.0/24"))
-	assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[127].String(), "172.80.127.0/24"))
-	assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[255].String(), "172.80.255.0/24"))
-	assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[256].String(), "172.90.0.0/24"))
-	assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[383].String(), "172.90.127.0/24"))
-	assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[511].String(), "172.90.255.0/24"))
-}

+ 0 - 41
libnetwork/netutils/utils_linux.go

@@ -9,7 +9,6 @@ import (
 	"net"
 	"os"
 
-	"github.com/docker/docker/libnetwork/ipamutils"
 	"github.com/docker/docker/libnetwork/ns"
 	"github.com/docker/docker/libnetwork/resolvconf"
 	"github.com/docker/docker/libnetwork/types"
@@ -61,46 +60,6 @@ func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, err
 	return "", types.InternalErrorf("could not generate interface name")
 }
 
-// ElectInterfaceAddresses looks for an interface on the OS with the
-// specified name and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
-// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
-// If the interface does not exist, it chooses from a predefined
-// list the first IPv4 address which does not conflict with other
-// interfaces on the system.
-func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
-	var v4Nets, v6Nets []*net.IPNet
-
-	link, _ := ns.NlHandle().LinkByName(name)
-	if link != nil {
-		v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4)
-		if err != nil {
-			return nil, nil, err
-		}
-		v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6)
-		if err != nil {
-			return nil, nil, err
-		}
-		for _, nlAddr := range v4addr {
-			v4Nets = append(v4Nets, nlAddr.IPNet)
-		}
-		for _, nlAddr := range v6addr {
-			v6Nets = append(v6Nets, nlAddr.IPNet)
-		}
-	}
-
-	if link == nil || len(v4Nets) == 0 {
-		// Choose from predefined local scope networks
-		v4Net, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
-		if err != nil {
-			return nil, nil, errors.Wrapf(err, "PredefinedLocalScopeDefaultNetworks List: %+v",
-				ipamutils.PredefinedLocalScopeDefaultNetworks)
-		}
-		v4Nets = append(v4Nets, v4Net)
-	}
-
-	return v4Nets, v6Nets, nil
-}
-
 // FindAvailableNetwork returns a network from the passed list which does not
 // overlap with existing interfaces in the system
 func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {

+ 5 - 66
libnetwork/netutils/utils_linux_test.go

@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"fmt"
 	"net"
-	"sort"
 	"strings"
 	"testing"
 
@@ -250,13 +249,13 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
 func TestNetworkRequest(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 
-	nw, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
+	nw, err := FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	var found bool
-	for _, exp := range ipamutils.PredefinedLocalScopeDefaultNetworks {
+	for _, exp := range ipamutils.GetLocalScopeDefaultNetworks() {
 		if types.CompareIPNet(exp, nw) {
 			found = true
 			break
@@ -267,13 +266,13 @@ func TestNetworkRequest(t *testing.T) {
 		t.Fatalf("Found unexpected broad network %s", nw)
 	}
 
-	nw, err = FindAvailableNetwork(ipamutils.PredefinedGlobalScopeDefaultNetworks)
+	nw, err = FindAvailableNetwork(ipamutils.GetGlobalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	found = false
-	for _, exp := range ipamutils.PredefinedGlobalScopeDefaultNetworks {
+	for _, exp := range ipamutils.GetGlobalScopeDefaultNetworks() {
 		if types.CompareIPNet(exp, nw) {
 			found = true
 			break
@@ -291,7 +290,7 @@ func TestNetworkRequest(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	nw, err = FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
+	nw, err = FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -300,66 +299,6 @@ func TestNetworkRequest(t *testing.T) {
 	}
 }
 
-func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
-
-	nws := []string{"172.101.202.254/16", "172.102.202.254/16"}
-	createInterface(t, "test", nws...)
-
-	ipv4NwList, ipv6NwList, err := ElectInterfaceAddresses("test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if len(ipv4NwList) == 0 {
-		t.Fatal("unexpected empty ipv4 network addresses")
-	}
-
-	if len(ipv6NwList) == 0 {
-		t.Fatal("unexpected empty ipv6 network addresses")
-	}
-
-	nwList := []string{}
-	for _, ipv4Nw := range ipv4NwList {
-		nwList = append(nwList, ipv4Nw.String())
-	}
-	sort.Strings(nws)
-	sort.Strings(nwList)
-
-	if len(nws) != len(nwList) {
-		t.Fatalf("expected %v. got %v", nws, nwList)
-	}
-	for i, nw := range nws {
-		if nw != nwList[i] {
-			t.Fatalf("expected %v. got %v", nw, nwList[i])
-		}
-	}
-}
-
-func TestElectInterfaceAddress(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
-
-	nws := "172.101.202.254/16"
-	createInterface(t, "test", nws)
-
-	ipv4Nw, ipv6Nw, err := ElectInterfaceAddresses("test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if len(ipv4Nw) == 0 {
-		t.Fatal("unexpected empty ipv4 network addresses")
-	}
-
-	if len(ipv6Nw) == 0 {
-		t.Fatal("unexpected empty ipv6 network addresses")
-	}
-
-	if nws != ipv4Nw[0].String() {
-		t.Fatalf("expected %s. got %s", nws, ipv4Nw[0])
-	}
-}
-
 func createInterface(t *testing.T, name string, nws ...string) {
 	// Add interface
 	link := &netlink.Bridge{