浏览代码

Allow user to specify default address pools for docker networks
This is new feature that allows user to specify which subnetwork
Docker contrainer should choose from when it creates bridge network.

This libnetwork commit is to address moby PR 36054
Signed-off-by: selansen <elango.siva@docker.com>

selansen 7 年之前
父节点
当前提交
4484ea17c3

+ 9 - 0
libnetwork/config/config.go

@@ -10,6 +10,7 @@ import (
 	"github.com/docker/libkv/store"
 	"github.com/docker/libnetwork/cluster"
 	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/ipamutils"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/osl"
 	"github.com/sirupsen/logrus"
@@ -40,6 +41,7 @@ type DaemonCfg struct {
 	DriverCfg              map[string]interface{}
 	ClusterProvider        cluster.Provider
 	NetworkControlPlaneMTU int
+	DefaultAddressPool     []*ipamutils.NetworkToSplit
 }
 
 // ClusterCfg represents cluster configuration
@@ -110,6 +112,13 @@ func OptionDefaultDriver(dd string) Option {
 	}
 }
 
+// OptionDefaultAddressPoolConfig function returns an option setter for default address pool
+func OptionDefaultAddressPoolConfig(addressPool []*ipamutils.NetworkToSplit) Option {
+	return func(c *Config) {
+		c.Daemon.DefaultAddressPool = addressPool
+	}
+}
+
 // OptionDriverConfig returns an option setter for driver configuration.
 func OptionDriverConfig(networkType string, config map[string]interface{}) Option {
 	return func(c *Config) {

+ 1 - 1
libnetwork/controller.go

@@ -222,7 +222,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 		}
 	}
 
-	if err = initIPAMDrivers(drvRegistry, nil, c.getStore(datastore.GlobalScope)); err != nil {
+	if err = initIPAMDrivers(drvRegistry, nil, c.getStore(datastore.GlobalScope), c.cfg.Daemon.DefaultAddressPool); err != nil {
 		return nil, err
 	}
 

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

@@ -21,7 +21,7 @@ import (
 )
 
 func init() {
-	ipamutils.InitNetworks()
+	ipamutils.InitNetworks(nil)
 }
 
 func TestEndpointMarshalling(t *testing.T) {

+ 3 - 1
libnetwork/drivers_ipam.go

@@ -6,9 +6,11 @@ import (
 	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
 	nullIpam "github.com/docker/libnetwork/ipams/null"
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
+	"github.com/docker/libnetwork/ipamutils"
 )
 
-func initIPAMDrivers(r *drvregistry.DrvRegistry, lDs, gDs interface{}) error {
+func initIPAMDrivers(r *drvregistry.DrvRegistry, lDs, gDs interface{}, addressPool []*ipamutils.NetworkToSplit) error {
+	builtinIpam.SetDefaultIPAddressPool(addressPool)
 	for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
 		builtinIpam.Init,
 		remoteIpam.Init,

+ 1 - 1
libnetwork/ipam/allocator_test.go

@@ -51,7 +51,7 @@ func randomLocalStore() (datastore.DataStore, error) {
 }
 
 func getAllocator() (*Allocator, error) {
-	ipamutils.InitNetworks()
+	ipamutils.InitNetworks(nil)
 	ds, err := randomLocalStore()
 	if err != nil {
 		return nil, err

+ 16 - 1
libnetwork/ipams/builtin/builtin_unix.go

@@ -11,6 +11,11 @@ import (
 	"github.com/docker/libnetwork/ipamutils"
 )
 
+var (
+	// defaultAddressPool Stores user configured subnet list
+	defaultAddressPool []*ipamutils.NetworkToSplit
+)
+
 // Init registers the built-in ipam service with libnetwork
 func Init(ic ipamapi.Callback, l, g interface{}) error {
 	var (
@@ -30,7 +35,7 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
 		}
 	}
 
-	ipamutils.InitNetworks()
+	ipamutils.InitNetworks(GetDefaultIPAddressPool())
 
 	a, err := ipam.NewAllocator(localDs, globalDs)
 	if err != nil {
@@ -41,3 +46,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
 
 	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
+}

+ 16 - 1
libnetwork/ipams/builtin/builtin_windows.go

@@ -13,6 +13,11 @@ import (
 	windowsipam "github.com/docker/libnetwork/ipams/windowsipam"
 )
 
+var (
+	// defaultAddressPool Stores user configured subnet list
+	defaultAddressPool []*ipamutils.NetworkToSplit
+)
+
 // InitDockerDefault registers the built-in ipam service with libnetwork
 func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
 	var (
@@ -32,7 +37,7 @@ func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
 		}
 	}
 
-	ipamutils.InitNetworks()
+	ipamutils.InitNetworks(nil)
 
 	a, err := ipam.NewAllocator(localDs, globalDs)
 	if err != nil {
@@ -55,3 +60,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
 
 	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
+}

+ 68 - 22
libnetwork/ipamutils/utils.go

@@ -2,8 +2,11 @@
 package ipamutils
 
 import (
+	"fmt"
 	"net"
 	"sync"
+
+	"github.com/sirupsen/logrus"
 )
 
 var (
@@ -13,38 +16,81 @@ var (
 	// PredefinedGranularNetworks 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 `PredefinedBroadNetworks`
 	PredefinedGranularNetworks []*net.IPNet
+	initNetworksOnce           sync.Once
 
-	initNetworksOnce sync.Once
+	defaultBroadNetwork = []*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},
+		{"192.168.0.0/16", 20}}
+	defaultGranularNetwork = []*NetworkToSplit{{"10.0.0.0/8", 24}}
 )
 
-// InitNetworks initializes the pre-defined networks used by the built-in IP allocator
-func InitNetworks() {
+// NetworkToSplit represent a network that has to be split in chunks with mask length Size.
+// Each subnet in the set is derived from the Base pool. Base is to be passed
+// in CIDR format.
+// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256
+// 10.10.[0-255].0/24 address pools
+type NetworkToSplit struct {
+	Base string `json:"base"`
+	Size int    `json:"size"`
+}
+
+// InitNetworks initializes the broad network pool and the granular network pool
+func InitNetworks(defaultAddressPool []*NetworkToSplit) {
 	initNetworksOnce.Do(func() {
-		PredefinedBroadNetworks = initBroadPredefinedNetworks()
-		PredefinedGranularNetworks = initGranularPredefinedNetworks()
+		// error ingnored should never fail
+		PredefinedGranularNetworks, _ = splitNetworks(defaultGranularNetwork)
+		if defaultAddressPool == nil {
+			defaultAddressPool = defaultBroadNetwork
+		}
+		var err error
+		if PredefinedBroadNetworks, err = splitNetworks(defaultAddressPool); err != nil {
+			logrus.WithError(err).Error("InitAddressPools failed to initialize the default address pool")
+		}
 	})
 }
 
-func initBroadPredefinedNetworks() []*net.IPNet {
-	pl := make([]*net.IPNet, 0, 31)
-	mask := []byte{255, 255, 0, 0}
-	for i := 17; i < 32; i++ {
-		pl = append(pl, &net.IPNet{IP: []byte{172, byte(i), 0, 0}, Mask: mask})
+// 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 {
+		_, b, err := net.ParseCIDR(p.Base)
+		if err != nil {
+			return nil, fmt.Errorf("invalid base pool %q: %v", p.Base, err)
+		}
+		ones, _ := b.Mask.Size()
+		if p.Size <= 0 || p.Size < ones {
+			return nil, fmt.Errorf("invalid pools size: %d", p.Size)
+		}
+		localPools = append(localPools, splitNetwork(p.Size, b)...)
 	}
-	mask20 := []byte{255, 255, 240, 0}
-	for i := 0; i < 16; i++ {
-		pl = append(pl, &net.IPNet{IP: []byte{192, 168, byte(i << 4), 0}, Mask: mask20})
+	return localPools, nil
+}
+
+func splitNetwork(size int, base *net.IPNet) []*net.IPNet {
+	one, bits := base.Mask.Size()
+	mask := net.CIDRMask(size, bits)
+	n := 1 << uint(size-one)
+	s := uint(bits - size)
+	list := make([]*net.IPNet, 0, n)
+
+	for i := 0; i < n; i++ {
+		ip := copyIP(base.IP)
+		addIntToIP(ip, uint(i<<s))
+		list = append(list, &net.IPNet{IP: ip, Mask: mask})
 	}
-	return pl
+	return list
 }
 
-func initGranularPredefinedNetworks() []*net.IPNet {
-	pl := make([]*net.IPNet, 0, 256*256)
-	mask := []byte{255, 255, 255, 0}
-	for i := 0; i < 256; i++ {
-		for j := 0; j < 256; j++ {
-			pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), byte(j), 0}, Mask: mask})
-		}
+func copyIP(from net.IP) net.IP {
+	ip := make([]byte, len(from))
+	copy(ip, from)
+	return ip
+}
+
+func addIntToIP(array net.IP, ordinal uint) {
+	for i := len(array) - 1; i >= 0; i-- {
+		array[i] |= (byte)(ordinal & 0xff)
+		ordinal >>= 8
 	}
-	return pl
 }

+ 67 - 3
libnetwork/ipamutils/utils_test.go

@@ -1,16 +1,40 @@
 package ipamutils
 
 import (
+	"net"
+	"sync"
 	"testing"
 
 	_ "github.com/docker/libnetwork/testutils"
+	"github.com/stretchr/testify/assert"
 )
 
-func init() {
-	InitNetworks()
+func initBroadPredefinedNetworks() []*net.IPNet {
+	pl := make([]*net.IPNet, 0, 31)
+	mask := []byte{255, 255, 0, 0}
+	for i := 17; i < 32; i++ {
+		pl = append(pl, &net.IPNet{IP: []byte{172, byte(i), 0, 0}, Mask: mask})
+	}
+	mask20 := []byte{255, 255, 240, 0}
+	for i := 0; i < 16; i++ {
+		pl = append(pl, &net.IPNet{IP: []byte{192, 168, byte(i << 4), 0}, Mask: mask20})
+	}
+	return pl
+}
+
+func initGranularPredefinedNetworks() []*net.IPNet {
+	pl := make([]*net.IPNet, 0, 256*256)
+	mask := []byte{255, 255, 255, 0}
+	for i := 0; i < 256; i++ {
+		for j := 0; j < 256; j++ {
+			pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), byte(j), 0}, Mask: mask})
+		}
+	}
+	return pl
 }
 
-func TestGranularPredefined(t *testing.T) {
+func TestDefaultNetwork(t *testing.T) {
+	InitNetworks(nil)
 	for _, nw := range PredefinedGranularNetworks {
 		if ones, bits := nw.Mask.Size(); bits != 32 || ones != 24 {
 			t.Fatalf("Unexpected size for network in granular list: %v", nw)
@@ -23,4 +47,44 @@ func TestGranularPredefined(t *testing.T) {
 		}
 	}
 
+	originalBroadNets := initBroadPredefinedNetworks()
+	m := make(map[string]bool)
+	for _, v := range originalBroadNets {
+		m[v.String()] = true
+	}
+	for _, nw := range PredefinedBroadNetworks {
+		_, ok := m[nw.String()]
+		assert.True(t, ok)
+		delete(m, nw.String())
+	}
+
+	assert.Len(t, m, 0)
+
+	originalGranularNets := initGranularPredefinedNetworks()
+
+	m = make(map[string]bool)
+	for _, v := range originalGranularNets {
+		m[v.String()] = true
+	}
+	for _, nw := range PredefinedGranularNetworks {
+		_, ok := m[nw.String()]
+		assert.True(t, ok)
+		delete(m, nw.String())
+	}
+
+	assert.Len(t, m, 0)
+}
+
+func TestInitAddressPools(t *testing.T) {
+	initNetworksOnce = sync.Once{}
+	InitNetworks([]*NetworkToSplit{{"172.80.0.0/16", 24}, {"172.90.0.0/16", 24}})
+
+	// Check for Random IPAddresses in PredefinedBroadNetworks  ex: first , last and middle
+	assert.Len(t, PredefinedBroadNetworks, 512, "Failed to find PredefinedBroadNetworks")
+	assert.Equal(t, PredefinedBroadNetworks[0].String(), "172.80.0.0/24")
+	assert.Equal(t, PredefinedBroadNetworks[127].String(), "172.80.127.0/24")
+	assert.Equal(t, PredefinedBroadNetworks[255].String(), "172.80.255.0/24")
+	assert.Equal(t, PredefinedBroadNetworks[256].String(), "172.90.0.0/24")
+	assert.Equal(t, PredefinedBroadNetworks[383].String(), "172.90.127.0/24")
+	assert.Equal(t, PredefinedBroadNetworks[511].String(), "172.90.255.0/24")
 }

+ 3 - 3
libnetwork/netutils/utils_test.go

@@ -212,7 +212,7 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
 
 func TestNetworkRequest(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
-	ipamutils.InitNetworks()
+	ipamutils.InitNetworks(nil)
 
 	nw, err := FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
 	if err != nil {
@@ -266,7 +266,7 @@ func TestNetworkRequest(t *testing.T) {
 
 func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
-	ipamutils.InitNetworks()
+	ipamutils.InitNetworks(nil)
 
 	nws := []string{"172.101.202.254/16", "172.102.202.254/16"}
 	createInterface(t, "test", nws...)
@@ -303,7 +303,7 @@ func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
 
 func TestElectInterfaceAddress(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
-	ipamutils.InitNetworks()
+	ipamutils.InitNetworks(nil)
 
 	nws := "172.101.202.254/16"
 	createInterface(t, "test", nws)