Browse code

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 authored on 2018/01/19 07:30:51
Showing 10 changed files
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"github.com/docker/libkv/store"
11 11
 	"github.com/docker/libnetwork/cluster"
12 12
 	"github.com/docker/libnetwork/datastore"
13
+	"github.com/docker/libnetwork/ipamutils"
13 14
 	"github.com/docker/libnetwork/netlabel"
14 15
 	"github.com/docker/libnetwork/osl"
15 16
 	"github.com/sirupsen/logrus"
... ...
@@ -40,6 +41,7 @@ type DaemonCfg struct {
40 40
 	DriverCfg              map[string]interface{}
41 41
 	ClusterProvider        cluster.Provider
42 42
 	NetworkControlPlaneMTU int
43
+	DefaultAddressPool     []*ipamutils.NetworkToSplit
43 44
 }
44 45
 
45 46
 // ClusterCfg represents cluster configuration
... ...
@@ -110,6 +112,13 @@ func OptionDefaultDriver(dd string) Option {
110 110
 	}
111 111
 }
112 112
 
113
+// OptionDefaultAddressPoolConfig function returns an option setter for default address pool
114
+func OptionDefaultAddressPoolConfig(addressPool []*ipamutils.NetworkToSplit) Option {
115
+	return func(c *Config) {
116
+		c.Daemon.DefaultAddressPool = addressPool
117
+	}
118
+}
119
+
113 120
 // OptionDriverConfig returns an option setter for driver configuration.
114 121
 func OptionDriverConfig(networkType string, config map[string]interface{}) Option {
115 122
 	return func(c *Config) {
... ...
@@ -222,7 +222,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
222 222
 		}
223 223
 	}
224 224
 
225
-	if err = initIPAMDrivers(drvRegistry, nil, c.getStore(datastore.GlobalScope)); err != nil {
225
+	if err = initIPAMDrivers(drvRegistry, nil, c.getStore(datastore.GlobalScope), c.cfg.Daemon.DefaultAddressPool); err != nil {
226 226
 		return nil, err
227 227
 	}
228 228
 
... ...
@@ -21,7 +21,7 @@ import (
21 21
 )
22 22
 
23 23
 func init() {
24
-	ipamutils.InitNetworks()
24
+	ipamutils.InitNetworks(nil)
25 25
 }
26 26
 
27 27
 func TestEndpointMarshalling(t *testing.T) {
... ...
@@ -6,9 +6,11 @@ import (
6 6
 	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
7 7
 	nullIpam "github.com/docker/libnetwork/ipams/null"
8 8
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
9
+	"github.com/docker/libnetwork/ipamutils"
9 10
 )
10 11
 
11
-func initIPAMDrivers(r *drvregistry.DrvRegistry, lDs, gDs interface{}) error {
12
+func initIPAMDrivers(r *drvregistry.DrvRegistry, lDs, gDs interface{}, addressPool []*ipamutils.NetworkToSplit) error {
13
+	builtinIpam.SetDefaultIPAddressPool(addressPool)
12 14
 	for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
13 15
 		builtinIpam.Init,
14 16
 		remoteIpam.Init,
... ...
@@ -51,7 +51,7 @@ func randomLocalStore() (datastore.DataStore, error) {
51 51
 }
52 52
 
53 53
 func getAllocator() (*Allocator, error) {
54
-	ipamutils.InitNetworks()
54
+	ipamutils.InitNetworks(nil)
55 55
 	ds, err := randomLocalStore()
56 56
 	if err != nil {
57 57
 		return nil, err
... ...
@@ -11,6 +11,11 @@ import (
11 11
 	"github.com/docker/libnetwork/ipamutils"
12 12
 )
13 13
 
14
+var (
15
+	// defaultAddressPool Stores user configured subnet list
16
+	defaultAddressPool []*ipamutils.NetworkToSplit
17
+)
18
+
14 19
 // Init registers the built-in ipam service with libnetwork
15 20
 func Init(ic ipamapi.Callback, l, g interface{}) error {
16 21
 	var (
... ...
@@ -30,7 +35,7 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
30 30
 		}
31 31
 	}
32 32
 
33
-	ipamutils.InitNetworks()
33
+	ipamutils.InitNetworks(GetDefaultIPAddressPool())
34 34
 
35 35
 	a, err := ipam.NewAllocator(localDs, globalDs)
36 36
 	if err != nil {
... ...
@@ -41,3 +46,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
41 41
 
42 42
 	return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
43 43
 }
44
+
45
+// SetDefaultIPAddressPool stores default address pool.
46
+func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
47
+	defaultAddressPool = addressPool
48
+}
49
+
50
+// GetDefaultIPAddressPool returns default address pool.
51
+func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
52
+	return defaultAddressPool
53
+}
... ...
@@ -13,6 +13,11 @@ import (
13 13
 	windowsipam "github.com/docker/libnetwork/ipams/windowsipam"
14 14
 )
15 15
 
16
+var (
17
+	// defaultAddressPool Stores user configured subnet list
18
+	defaultAddressPool []*ipamutils.NetworkToSplit
19
+)
20
+
16 21
 // InitDockerDefault registers the built-in ipam service with libnetwork
17 22
 func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
18 23
 	var (
... ...
@@ -32,7 +37,7 @@ func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
32 32
 		}
33 33
 	}
34 34
 
35
-	ipamutils.InitNetworks()
35
+	ipamutils.InitNetworks(nil)
36 36
 
37 37
 	a, err := ipam.NewAllocator(localDs, globalDs)
38 38
 	if err != nil {
... ...
@@ -55,3 +60,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
55 55
 
56 56
 	return initFunc(ic, l, g)
57 57
 }
58
+
59
+// SetDefaultIPAddressPool stores default address pool .
60
+func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
61
+	defaultAddressPool = addressPool
62
+}
63
+
64
+// GetDefaultIPAddressPool returns default address pool .
65
+func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
66
+	return defaultAddressPool
67
+}
... ...
@@ -2,8 +2,11 @@
2 2
 package ipamutils
3 3
 
4 4
 import (
5
+	"fmt"
5 6
 	"net"
6 7
 	"sync"
8
+
9
+	"github.com/sirupsen/logrus"
7 10
 )
8 11
 
9 12
 var (
... ...
@@ -13,38 +16,81 @@ var (
13 13
 	// PredefinedGranularNetworks contains a list of 64K IPv4 private networks with host size 8
14 14
 	// (10.x.x.x/24) which do not overlap with the networks in `PredefinedBroadNetworks`
15 15
 	PredefinedGranularNetworks []*net.IPNet
16
+	initNetworksOnce           sync.Once
16 17
 
17
-	initNetworksOnce sync.Once
18
+	defaultBroadNetwork = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16},
19
+		{"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16},
20
+		{"192.168.0.0/16", 20}}
21
+	defaultGranularNetwork = []*NetworkToSplit{{"10.0.0.0/8", 24}}
18 22
 )
19 23
 
20
-// InitNetworks initializes the pre-defined networks used by the built-in IP allocator
21
-func InitNetworks() {
24
+// NetworkToSplit represent a network that has to be split in chunks with mask length Size.
25
+// Each subnet in the set is derived from the Base pool. Base is to be passed
26
+// in CIDR format.
27
+// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256
28
+// 10.10.[0-255].0/24 address pools
29
+type NetworkToSplit struct {
30
+	Base string `json:"base"`
31
+	Size int    `json:"size"`
32
+}
33
+
34
+// InitNetworks initializes the broad network pool and the granular network pool
35
+func InitNetworks(defaultAddressPool []*NetworkToSplit) {
22 36
 	initNetworksOnce.Do(func() {
23
-		PredefinedBroadNetworks = initBroadPredefinedNetworks()
24
-		PredefinedGranularNetworks = initGranularPredefinedNetworks()
37
+		// error ingnored should never fail
38
+		PredefinedGranularNetworks, _ = splitNetworks(defaultGranularNetwork)
39
+		if defaultAddressPool == nil {
40
+			defaultAddressPool = defaultBroadNetwork
41
+		}
42
+		var err error
43
+		if PredefinedBroadNetworks, err = splitNetworks(defaultAddressPool); err != nil {
44
+			logrus.WithError(err).Error("InitAddressPools failed to initialize the default address pool")
45
+		}
25 46
 	})
26 47
 }
27 48
 
28
-func initBroadPredefinedNetworks() []*net.IPNet {
29
-	pl := make([]*net.IPNet, 0, 31)
30
-	mask := []byte{255, 255, 0, 0}
31
-	for i := 17; i < 32; i++ {
32
-		pl = append(pl, &net.IPNet{IP: []byte{172, byte(i), 0, 0}, Mask: mask})
49
+// splitNetworks takes a slice of networks, split them accordingly and returns them
50
+func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
51
+	localPools := make([]*net.IPNet, 0, len(list))
52
+
53
+	for _, p := range list {
54
+		_, b, err := net.ParseCIDR(p.Base)
55
+		if err != nil {
56
+			return nil, fmt.Errorf("invalid base pool %q: %v", p.Base, err)
57
+		}
58
+		ones, _ := b.Mask.Size()
59
+		if p.Size <= 0 || p.Size < ones {
60
+			return nil, fmt.Errorf("invalid pools size: %d", p.Size)
61
+		}
62
+		localPools = append(localPools, splitNetwork(p.Size, b)...)
33 63
 	}
34
-	mask20 := []byte{255, 255, 240, 0}
35
-	for i := 0; i < 16; i++ {
36
-		pl = append(pl, &net.IPNet{IP: []byte{192, 168, byte(i << 4), 0}, Mask: mask20})
64
+	return localPools, nil
65
+}
66
+
67
+func splitNetwork(size int, base *net.IPNet) []*net.IPNet {
68
+	one, bits := base.Mask.Size()
69
+	mask := net.CIDRMask(size, bits)
70
+	n := 1 << uint(size-one)
71
+	s := uint(bits - size)
72
+	list := make([]*net.IPNet, 0, n)
73
+
74
+	for i := 0; i < n; i++ {
75
+		ip := copyIP(base.IP)
76
+		addIntToIP(ip, uint(i<<s))
77
+		list = append(list, &net.IPNet{IP: ip, Mask: mask})
37 78
 	}
38
-	return pl
79
+	return list
39 80
 }
40 81
 
41
-func initGranularPredefinedNetworks() []*net.IPNet {
42
-	pl := make([]*net.IPNet, 0, 256*256)
43
-	mask := []byte{255, 255, 255, 0}
44
-	for i := 0; i < 256; i++ {
45
-		for j := 0; j < 256; j++ {
46
-			pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), byte(j), 0}, Mask: mask})
47
-		}
82
+func copyIP(from net.IP) net.IP {
83
+	ip := make([]byte, len(from))
84
+	copy(ip, from)
85
+	return ip
86
+}
87
+
88
+func addIntToIP(array net.IP, ordinal uint) {
89
+	for i := len(array) - 1; i >= 0; i-- {
90
+		array[i] |= (byte)(ordinal & 0xff)
91
+		ordinal >>= 8
48 92
 	}
49
-	return pl
50 93
 }
... ...
@@ -1,16 +1,40 @@
1 1
 package ipamutils
2 2
 
3 3
 import (
4
+	"net"
5
+	"sync"
4 6
 	"testing"
5 7
 
6 8
 	_ "github.com/docker/libnetwork/testutils"
9
+	"github.com/stretchr/testify/assert"
7 10
 )
8 11
 
9
-func init() {
10
-	InitNetworks()
12
+func initBroadPredefinedNetworks() []*net.IPNet {
13
+	pl := make([]*net.IPNet, 0, 31)
14
+	mask := []byte{255, 255, 0, 0}
15
+	for i := 17; i < 32; i++ {
16
+		pl = append(pl, &net.IPNet{IP: []byte{172, byte(i), 0, 0}, Mask: mask})
17
+	}
18
+	mask20 := []byte{255, 255, 240, 0}
19
+	for i := 0; i < 16; i++ {
20
+		pl = append(pl, &net.IPNet{IP: []byte{192, 168, byte(i << 4), 0}, Mask: mask20})
21
+	}
22
+	return pl
23
+}
24
+
25
+func initGranularPredefinedNetworks() []*net.IPNet {
26
+	pl := make([]*net.IPNet, 0, 256*256)
27
+	mask := []byte{255, 255, 255, 0}
28
+	for i := 0; i < 256; i++ {
29
+		for j := 0; j < 256; j++ {
30
+			pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), byte(j), 0}, Mask: mask})
31
+		}
32
+	}
33
+	return pl
11 34
 }
12 35
 
13
-func TestGranularPredefined(t *testing.T) {
36
+func TestDefaultNetwork(t *testing.T) {
37
+	InitNetworks(nil)
14 38
 	for _, nw := range PredefinedGranularNetworks {
15 39
 		if ones, bits := nw.Mask.Size(); bits != 32 || ones != 24 {
16 40
 			t.Fatalf("Unexpected size for network in granular list: %v", nw)
... ...
@@ -23,4 +47,44 @@ func TestGranularPredefined(t *testing.T) {
23 23
 		}
24 24
 	}
25 25
 
26
+	originalBroadNets := initBroadPredefinedNetworks()
27
+	m := make(map[string]bool)
28
+	for _, v := range originalBroadNets {
29
+		m[v.String()] = true
30
+	}
31
+	for _, nw := range PredefinedBroadNetworks {
32
+		_, ok := m[nw.String()]
33
+		assert.True(t, ok)
34
+		delete(m, nw.String())
35
+	}
36
+
37
+	assert.Len(t, m, 0)
38
+
39
+	originalGranularNets := initGranularPredefinedNetworks()
40
+
41
+	m = make(map[string]bool)
42
+	for _, v := range originalGranularNets {
43
+		m[v.String()] = true
44
+	}
45
+	for _, nw := range PredefinedGranularNetworks {
46
+		_, ok := m[nw.String()]
47
+		assert.True(t, ok)
48
+		delete(m, nw.String())
49
+	}
50
+
51
+	assert.Len(t, m, 0)
52
+}
53
+
54
+func TestInitAddressPools(t *testing.T) {
55
+	initNetworksOnce = sync.Once{}
56
+	InitNetworks([]*NetworkToSplit{{"172.80.0.0/16", 24}, {"172.90.0.0/16", 24}})
57
+
58
+	// Check for Random IPAddresses in PredefinedBroadNetworks  ex: first , last and middle
59
+	assert.Len(t, PredefinedBroadNetworks, 512, "Failed to find PredefinedBroadNetworks")
60
+	assert.Equal(t, PredefinedBroadNetworks[0].String(), "172.80.0.0/24")
61
+	assert.Equal(t, PredefinedBroadNetworks[127].String(), "172.80.127.0/24")
62
+	assert.Equal(t, PredefinedBroadNetworks[255].String(), "172.80.255.0/24")
63
+	assert.Equal(t, PredefinedBroadNetworks[256].String(), "172.90.0.0/24")
64
+	assert.Equal(t, PredefinedBroadNetworks[383].String(), "172.90.127.0/24")
65
+	assert.Equal(t, PredefinedBroadNetworks[511].String(), "172.90.255.0/24")
26 66
 }
... ...
@@ -212,7 +212,7 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
212 212
 
213 213
 func TestNetworkRequest(t *testing.T) {
214 214
 	defer testutils.SetupTestOSContext(t)()
215
-	ipamutils.InitNetworks()
215
+	ipamutils.InitNetworks(nil)
216 216
 
217 217
 	nw, err := FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
218 218
 	if err != nil {
... ...
@@ -266,7 +266,7 @@ func TestNetworkRequest(t *testing.T) {
266 266
 
267 267
 func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
268 268
 	defer testutils.SetupTestOSContext(t)()
269
-	ipamutils.InitNetworks()
269
+	ipamutils.InitNetworks(nil)
270 270
 
271 271
 	nws := []string{"172.101.202.254/16", "172.102.202.254/16"}
272 272
 	createInterface(t, "test", nws...)
... ...
@@ -303,7 +303,7 @@ func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
303 303
 
304 304
 func TestElectInterfaceAddress(t *testing.T) {
305 305
 	defer testutils.SetupTestOSContext(t)()
306
-	ipamutils.InitNetworks()
306
+	ipamutils.InitNetworks(nil)
307 307
 
308 308
 	nws := "172.101.202.254/16"
309 309
 	createInterface(t, "test", nws)