Skip to content

Commit 4484ea1

Browse files
committed
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>
1 parent 2459e6f commit 4484ea1

File tree

10 files changed

+185
-34
lines changed

10 files changed

+185
-34
lines changed

libnetwork/config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/docker/libkv/store"
1111
"github.com/docker/libnetwork/cluster"
1212
"github.com/docker/libnetwork/datastore"
13+
"github.com/docker/libnetwork/ipamutils"
1314
"github.com/docker/libnetwork/netlabel"
1415
"github.com/docker/libnetwork/osl"
1516
"github.com/sirupsen/logrus"
@@ -40,6 +41,7 @@ type DaemonCfg struct {
4041
DriverCfg map[string]interface{}
4142
ClusterProvider cluster.Provider
4243
NetworkControlPlaneMTU int
44+
DefaultAddressPool []*ipamutils.NetworkToSplit
4345
}
4446

4547
// ClusterCfg represents cluster configuration
@@ -110,6 +112,13 @@ func OptionDefaultDriver(dd string) Option {
110112
}
111113
}
112114

115+
// OptionDefaultAddressPoolConfig function returns an option setter for default address pool
116+
func OptionDefaultAddressPoolConfig(addressPool []*ipamutils.NetworkToSplit) Option {
117+
return func(c *Config) {
118+
c.Daemon.DefaultAddressPool = addressPool
119+
}
120+
}
121+
113122
// OptionDriverConfig returns an option setter for driver configuration.
114123
func OptionDriverConfig(networkType string, config map[string]interface{}) Option {
115124
return func(c *Config) {

libnetwork/controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
222222
}
223223
}
224224

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 {
226226
return nil, err
227227
}
228228

libnetwork/drivers/bridge/bridge_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
)
2222

2323
func init() {
24-
ipamutils.InitNetworks()
24+
ipamutils.InitNetworks(nil)
2525
}
2626

2727
func TestEndpointMarshalling(t *testing.T) {

libnetwork/drivers_ipam.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import (
66
builtinIpam "github.com/docker/libnetwork/ipams/builtin"
77
nullIpam "github.com/docker/libnetwork/ipams/null"
88
remoteIpam "github.com/docker/libnetwork/ipams/remote"
9+
"github.com/docker/libnetwork/ipamutils"
910
)
1011

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)
1214
for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
1315
builtinIpam.Init,
1416
remoteIpam.Init,

libnetwork/ipam/allocator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func randomLocalStore() (datastore.DataStore, error) {
5151
}
5252

5353
func getAllocator() (*Allocator, error) {
54-
ipamutils.InitNetworks()
54+
ipamutils.InitNetworks(nil)
5555
ds, err := randomLocalStore()
5656
if err != nil {
5757
return nil, err

libnetwork/ipams/builtin/builtin_unix.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ import (
1111
"github.com/docker/libnetwork/ipamutils"
1212
)
1313

14+
var (
15+
// defaultAddressPool Stores user configured subnet list
16+
defaultAddressPool []*ipamutils.NetworkToSplit
17+
)
18+
1419
// Init registers the built-in ipam service with libnetwork
1520
func Init(ic ipamapi.Callback, l, g interface{}) error {
1621
var (
@@ -30,7 +35,7 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
3035
}
3136
}
3237

33-
ipamutils.InitNetworks()
38+
ipamutils.InitNetworks(GetDefaultIPAddressPool())
3439

3540
a, err := ipam.NewAllocator(localDs, globalDs)
3641
if err != nil {
@@ -41,3 +46,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
4146

4247
return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
4348
}
49+
50+
// SetDefaultIPAddressPool stores default address pool.
51+
func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
52+
defaultAddressPool = addressPool
53+
}
54+
55+
// GetDefaultIPAddressPool returns default address pool.
56+
func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
57+
return defaultAddressPool
58+
}

libnetwork/ipams/builtin/builtin_windows.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import (
1313
windowsipam "github.com/docker/libnetwork/ipams/windowsipam"
1414
)
1515

16+
var (
17+
// defaultAddressPool Stores user configured subnet list
18+
defaultAddressPool []*ipamutils.NetworkToSplit
19+
)
20+
1621
// InitDockerDefault registers the built-in ipam service with libnetwork
1722
func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
1823
var (
@@ -32,7 +37,7 @@ func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
3237
}
3338
}
3439

35-
ipamutils.InitNetworks()
40+
ipamutils.InitNetworks(nil)
3641

3742
a, err := ipam.NewAllocator(localDs, globalDs)
3843
if err != nil {
@@ -55,3 +60,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
5560

5661
return initFunc(ic, l, g)
5762
}
63+
64+
// SetDefaultIPAddressPool stores default address pool .
65+
func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
66+
defaultAddressPool = addressPool
67+
}
68+
69+
// GetDefaultIPAddressPool returns default address pool .
70+
func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
71+
return defaultAddressPool
72+
}

libnetwork/ipamutils/utils.go

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
package ipamutils
33

44
import (
5+
"fmt"
56
"net"
67
"sync"
8+
9+
"github.com/sirupsen/logrus"
710
)
811

912
var (
@@ -13,38 +16,81 @@ var (
1316
// PredefinedGranularNetworks contains a list of 64K IPv4 private networks with host size 8
1417
// (10.x.x.x/24) which do not overlap with the networks in `PredefinedBroadNetworks`
1518
PredefinedGranularNetworks []*net.IPNet
19+
initNetworksOnce sync.Once
1620

17-
initNetworksOnce sync.Once
21+
defaultBroadNetwork = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16},
22+
{"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16},
23+
{"192.168.0.0/16", 20}}
24+
defaultGranularNetwork = []*NetworkToSplit{{"10.0.0.0/8", 24}}
1825
)
1926

20-
// InitNetworks initializes the pre-defined networks used by the built-in IP allocator
21-
func InitNetworks() {
27+
// NetworkToSplit represent a network that has to be split in chunks with mask length Size.
28+
// Each subnet in the set is derived from the Base pool. Base is to be passed
29+
// in CIDR format.
30+
// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256
31+
// 10.10.[0-255].0/24 address pools
32+
type NetworkToSplit struct {
33+
Base string `json:"base"`
34+
Size int `json:"size"`
35+
}
36+
37+
// InitNetworks initializes the broad network pool and the granular network pool
38+
func InitNetworks(defaultAddressPool []*NetworkToSplit) {
2239
initNetworksOnce.Do(func() {
23-
PredefinedBroadNetworks = initBroadPredefinedNetworks()
24-
PredefinedGranularNetworks = initGranularPredefinedNetworks()
40+
// error ingnored should never fail
41+
PredefinedGranularNetworks, _ = splitNetworks(defaultGranularNetwork)
42+
if defaultAddressPool == nil {
43+
defaultAddressPool = defaultBroadNetwork
44+
}
45+
var err error
46+
if PredefinedBroadNetworks, err = splitNetworks(defaultAddressPool); err != nil {
47+
logrus.WithError(err).Error("InitAddressPools failed to initialize the default address pool")
48+
}
2549
})
2650
}
2751

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})
52+
// splitNetworks takes a slice of networks, split them accordingly and returns them
53+
func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
54+
localPools := make([]*net.IPNet, 0, len(list))
55+
56+
for _, p := range list {
57+
_, b, err := net.ParseCIDR(p.Base)
58+
if err != nil {
59+
return nil, fmt.Errorf("invalid base pool %q: %v", p.Base, err)
60+
}
61+
ones, _ := b.Mask.Size()
62+
if p.Size <= 0 || p.Size < ones {
63+
return nil, fmt.Errorf("invalid pools size: %d", p.Size)
64+
}
65+
localPools = append(localPools, splitNetwork(p.Size, b)...)
3366
}
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})
67+
return localPools, nil
68+
}
69+
70+
func splitNetwork(size int, base *net.IPNet) []*net.IPNet {
71+
one, bits := base.Mask.Size()
72+
mask := net.CIDRMask(size, bits)
73+
n := 1 << uint(size-one)
74+
s := uint(bits - size)
75+
list := make([]*net.IPNet, 0, n)
76+
77+
for i := 0; i < n; i++ {
78+
ip := copyIP(base.IP)
79+
addIntToIP(ip, uint(i<<s))
80+
list = append(list, &net.IPNet{IP: ip, Mask: mask})
3781
}
38-
return pl
82+
return list
3983
}
4084

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-
}
85+
func copyIP(from net.IP) net.IP {
86+
ip := make([]byte, len(from))
87+
copy(ip, from)
88+
return ip
89+
}
90+
91+
func addIntToIP(array net.IP, ordinal uint) {
92+
for i := len(array) - 1; i >= 0; i-- {
93+
array[i] |= (byte)(ordinal & 0xff)
94+
ordinal >>= 8
4895
}
49-
return pl
5096
}

libnetwork/ipamutils/utils_test.go

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,40 @@
11
package ipamutils
22

33
import (
4+
"net"
5+
"sync"
46
"testing"
57

68
_ "github.com/docker/libnetwork/testutils"
9+
"github.com/stretchr/testify/assert"
710
)
811

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
1134
}
1235

13-
func TestGranularPredefined(t *testing.T) {
36+
func TestDefaultNetwork(t *testing.T) {
37+
InitNetworks(nil)
1438
for _, nw := range PredefinedGranularNetworks {
1539
if ones, bits := nw.Mask.Size(); bits != 32 || ones != 24 {
1640
t.Fatalf("Unexpected size for network in granular list: %v", nw)
@@ -23,4 +47,44 @@ func TestGranularPredefined(t *testing.T) {
2347
}
2448
}
2549

50+
originalBroadNets := initBroadPredefinedNetworks()
51+
m := make(map[string]bool)
52+
for _, v := range originalBroadNets {
53+
m[v.String()] = true
54+
}
55+
for _, nw := range PredefinedBroadNetworks {
56+
_, ok := m[nw.String()]
57+
assert.True(t, ok)
58+
delete(m, nw.String())
59+
}
60+
61+
assert.Len(t, m, 0)
62+
63+
originalGranularNets := initGranularPredefinedNetworks()
64+
65+
m = make(map[string]bool)
66+
for _, v := range originalGranularNets {
67+
m[v.String()] = true
68+
}
69+
for _, nw := range PredefinedGranularNetworks {
70+
_, ok := m[nw.String()]
71+
assert.True(t, ok)
72+
delete(m, nw.String())
73+
}
74+
75+
assert.Len(t, m, 0)
76+
}
77+
78+
func TestInitAddressPools(t *testing.T) {
79+
initNetworksOnce = sync.Once{}
80+
InitNetworks([]*NetworkToSplit{{"172.80.0.0/16", 24}, {"172.90.0.0/16", 24}})
81+
82+
// Check for Random IPAddresses in PredefinedBroadNetworks ex: first , last and middle
83+
assert.Len(t, PredefinedBroadNetworks, 512, "Failed to find PredefinedBroadNetworks")
84+
assert.Equal(t, PredefinedBroadNetworks[0].String(), "172.80.0.0/24")
85+
assert.Equal(t, PredefinedBroadNetworks[127].String(), "172.80.127.0/24")
86+
assert.Equal(t, PredefinedBroadNetworks[255].String(), "172.80.255.0/24")
87+
assert.Equal(t, PredefinedBroadNetworks[256].String(), "172.90.0.0/24")
88+
assert.Equal(t, PredefinedBroadNetworks[383].String(), "172.90.127.0/24")
89+
assert.Equal(t, PredefinedBroadNetworks[511].String(), "172.90.255.0/24")
2690
}

libnetwork/netutils/utils_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
212212

213213
func TestNetworkRequest(t *testing.T) {
214214
defer testutils.SetupTestOSContext(t)()
215-
ipamutils.InitNetworks()
215+
ipamutils.InitNetworks(nil)
216216

217217
nw, err := FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
218218
if err != nil {
@@ -266,7 +266,7 @@ func TestNetworkRequest(t *testing.T) {
266266

267267
func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
268268
defer testutils.SetupTestOSContext(t)()
269-
ipamutils.InitNetworks()
269+
ipamutils.InitNetworks(nil)
270270

271271
nws := []string{"172.101.202.254/16", "172.102.202.254/16"}
272272
createInterface(t, "test", nws...)
@@ -303,7 +303,7 @@ func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
303303

304304
func TestElectInterfaceAddress(t *testing.T) {
305305
defer testutils.SetupTestOSContext(t)()
306-
ipamutils.InitNetworks()
306+
ipamutils.InitNetworks(nil)
307307

308308
nws := "172.101.202.254/16"
309309
createInterface(t, "test", nws)

0 commit comments

Comments
 (0)