1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #2058 from selansen/master

Allow user to specify default address pools for docker networks
This commit is contained in:
Flavio Crisciani 2018-02-22 17:59:20 -08:00 committed by GitHub
commit f8a7f2e7be
10 changed files with 186 additions and 35 deletions

View file

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

View file

@ -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
}

View file

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

View file

@ -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,

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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 pl
return localPools, nil
}
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 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 list
}
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
}

View file

@ -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 TestGranularPredefined(t *testing.T) {
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 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")
}

View file

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