diff --git a/components/engine/daemon/cluster/listen_addr.go b/components/engine/daemon/cluster/listen_addr.go index e1ebfec8df..44ea5fce42 100644 --- a/components/engine/daemon/cluster/listen_addr.go +++ b/components/engine/daemon/cluster/listen_addr.go @@ -3,6 +3,7 @@ package cluster // import "github.com/docker/docker/daemon/cluster" import ( "fmt" "net" + "strings" ) const ( @@ -87,6 +88,41 @@ func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (st return systemAddr.String(), listenAddrPort, nil } +// validateDefaultAddrPool validates default address pool +// it also strips white space from the string before validation +func validateDefaultAddrPool(defaultAddrPool []string, size uint32) error { + if defaultAddrPool == nil { + // defaultAddrPool is not defined + return nil + } + //if size is not set, then we use default value 24 + if size == 0 { + size = 24 + } + // We allow max value as 29. We can have 8 IP addresses for max value 29 + // If we allow 30, then we will get only 4 IP addresses. But with latest + // libnetwork LB scale implementation, we use total of 4 IP addresses for internal use. + // Hence keeping 29 as max value, we will have 8 IP addresses. This will be + // smallest subnet that can be used in overlay network. + if size > 29 { + return fmt.Errorf("subnet size is out of range: %d", size) + } + for i := range defaultAddrPool { + // trim leading and trailing white spaces + defaultAddrPool[i] = strings.TrimSpace(defaultAddrPool[i]) + _, b, err := net.ParseCIDR(defaultAddrPool[i]) + if err != nil { + return fmt.Errorf("invalid base pool %s: %v", defaultAddrPool[i], err) + } + ones, _ := b.Mask.Size() + if size < uint32(ones) { + return fmt.Errorf("invalid CIDR: %q. Subnet size is too small for pool: %d", defaultAddrPool[i], size) + } + } + + return nil +} + func resolveDataPathAddr(dataPathAddr string) (string, error) { if dataPathAddr == "" { // dataPathAddr is not defined diff --git a/components/engine/daemon/cluster/swarm.go b/components/engine/daemon/cluster/swarm.go index d61e22f4fc..65dfe9eb45 100644 --- a/components/engine/daemon/cluster/swarm.go +++ b/components/engine/daemon/cluster/swarm.go @@ -92,6 +92,10 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) { } } + //Validate Default Address Pool input + if err := validateDefaultAddrPool(req.DefaultAddrPool, req.SubnetSize); err != nil { + return "", err + } nr, err := c.newNodeRunner(nodeStartConfig{ forceNewCluster: req.ForceNewCluster, autolock: req.AutoLockManagers, diff --git a/components/engine/integration/network/service_test.go b/components/engine/integration/network/service_test.go index 739a8ecb7d..40823da452 100644 --- a/components/engine/integration/network/service_test.go +++ b/components/engine/integration/network/service_test.go @@ -355,7 +355,7 @@ func TestServiceWithDefaultAddressPoolInit(t *testing.T) { d.Stop(t) // Clean up , set it back to original one to make sure other tests don't fail - ipAddr = []string{"10.10.0.0/8"} + ipAddr = []string{"10.0.0.0/8"} ops = append(ops, daemon.WithSwarmDefaultAddrPool(ipAddr)) ops = append(ops, daemon.WithSwarmDefaultAddrPoolSubnetSize(24)) d = swarm.NewSwarm(t, testEnv, ops...)