Skip to content

Commit fd4b5dc

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 <[email protected]>
1 parent 20dd462 commit fd4b5dc

File tree

10 files changed

+152
-16
lines changed

10 files changed

+152
-16
lines changed

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.PredefinedPools
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.PredefinedPools) 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) {

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

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) {

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

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

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.PredefinedPools
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.PredefinedPools) {
52+
defaultAddressPool = addressPool
53+
}
54+
55+
// GetDefaultIPAddressPool returns default address pool.
56+
func GetDefaultIPAddressPool() []*ipamutils.PredefinedPools {
57+
return defaultAddressPool
58+
}

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.PredefinedPools
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.PredefinedPools) {
66+
defaultAddressPool = addressPool
67+
}
68+
69+
// GetDefaultIPAddressPool returns default address pool .
70+
func GetDefaultIPAddressPool() []*ipamutils.PredefinedPools {
71+
return defaultAddressPool
72+
}

ipamutils/utils.go

Lines changed: 77 additions & 6 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,18 +16,34 @@ 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
16-
17-
initNetworksOnce sync.Once
19+
initNetworksOnce sync.Once
1820
)
1921

20-
// InitNetworks initializes the pre-defined networks used by the built-in IP allocator
21-
func InitNetworks() {
22+
// PredefinedPools represent a set of address pools with prefix length Size.
23+
// Each pool in the set is derived from the Base pool. Base is to be passed
24+
// in CIDR format.Currently we support only local scope networks
25+
// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256
26+
// 10.10.[0-255].0/24 address pools
27+
type PredefinedPools struct {
28+
Base string `json:"base"`
29+
Size int `json:"size"`
30+
}
31+
32+
// InitNetworks initializes the local predefined address pools
33+
// with the default values.
34+
func InitNetworks(defaultAddressPool []*PredefinedPools) {
2235
initNetworksOnce.Do(func() {
23-
PredefinedBroadNetworks = initBroadPredefinedNetworks()
36+
if defaultAddressPool != nil {
37+
if err := InitAddressPools(defaultAddressPool); err != nil {
38+
logrus.Error("InitAddressPools failed to initialize default address pool %v", err)
39+
}
40+
41+
} else {
42+
PredefinedBroadNetworks = initBroadPredefinedNetworks()
43+
}
2444
PredefinedGranularNetworks = initGranularPredefinedNetworks()
2545
})
2646
}
27-
2847
func initBroadPredefinedNetworks() []*net.IPNet {
2948
pl := make([]*net.IPNet, 0, 31)
3049
mask := []byte{255, 255, 0, 0}
@@ -48,3 +67,55 @@ func initGranularPredefinedNetworks() []*net.IPNet {
4867
}
4968
return pl
5069
}
70+
71+
// InitAddressPools allows to initialize the local and global scope predefined
72+
// address pools to the desired values. It fails is invalid input is passed
73+
// or if the predefined pools were already initialized.
74+
func InitAddressPools(list []*PredefinedPools) error {
75+
localPools := make([]*net.IPNet, 0, len(list))
76+
77+
for _, p := range list {
78+
if p == nil {
79+
continue
80+
}
81+
_, b, err := net.ParseCIDR(p.Base)
82+
if err != nil {
83+
return fmt.Errorf("invalid base pool %q: %v", p.Base, err)
84+
}
85+
ones, _ := b.Mask.Size()
86+
if p.Size <= 0 || p.Size < ones {
87+
return fmt.Errorf("invalid pools size: %d", p.Size)
88+
}
89+
localPools = append(localPools, initPools(p.Size, b)...)
90+
}
91+
PredefinedBroadNetworks = localPools
92+
return nil
93+
}
94+
95+
func initPools(size int, base *net.IPNet) []*net.IPNet {
96+
one, bits := base.Mask.Size()
97+
mask := net.CIDRMask(size, bits)
98+
n := 1 << uint(size-one)
99+
s := uint(bits - size)
100+
list := make([]*net.IPNet, 0, n)
101+
102+
for i := 0; i < n; i++ {
103+
ip := copyIP(base.IP)
104+
addIntToIP(ip, uint(i<<s))
105+
list = append(list, &net.IPNet{IP: ip, Mask: mask})
106+
}
107+
return list
108+
}
109+
110+
func copyIP(from net.IP) net.IP {
111+
ip := make([]byte, len(from))
112+
copy(ip, from)
113+
return ip
114+
}
115+
116+
func addIntToIP(array net.IP, ordinal uint) {
117+
for i := len(array) - 1; i >= 0; i-- {
118+
array[i] |= (byte)(ordinal & 0xff)
119+
ordinal >>= 8
120+
}
121+
}

ipamutils/utils_test.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package ipamutils
22

33
import (
4+
"sync"
45
"testing"
56

67
_ "github.com/docker/libnetwork/testutils"
8+
"github.com/stretchr/testify/assert"
79
)
810

911
func init() {
10-
InitNetworks()
12+
InitNetworks(nil)
13+
1114
}
1215

1316
func TestGranularPredefined(t *testing.T) {
@@ -24,3 +27,24 @@ func TestGranularPredefined(t *testing.T) {
2427
}
2528

2629
}
30+
31+
func TestInitAddressPools(t *testing.T) {
32+
prePool1 := &PredefinedPools{"172.80.0.0/16", 24}
33+
prePool2 := &PredefinedPools{"172.90.0.0/16", 24}
34+
DefaultAddressPools := []*PredefinedPools{prePool1, prePool2}
35+
initNetworksOnce = sync.Once{}
36+
InitNetworks(DefaultAddressPools)
37+
38+
// Check for Random IPAddresses in PredefinedBroadNetworks ex: first , last and middle
39+
if len(PredefinedBroadNetworks) == 512 {
40+
assert.Equal(t, PredefinedBroadNetworks[0].String(), "172.80.0.0/24")
41+
assert.Equal(t, PredefinedBroadNetworks[127].String(), "172.80.127.0/24")
42+
assert.Equal(t, PredefinedBroadNetworks[255].String(), "172.80.255.0/24")
43+
assert.Equal(t, PredefinedBroadNetworks[256].String(), "172.90.0.0/24")
44+
assert.Equal(t, PredefinedBroadNetworks[383].String(), "172.90.127.0/24")
45+
assert.Equal(t, PredefinedBroadNetworks[511].String(), "172.90.255.0/24")
46+
47+
} else {
48+
t.Fatal(" Failed to find PredefinedBroadNetworks")
49+
}
50+
}

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)