moby--moby/libnetwork/ipamutils/utils.go

134 lines
4.4 KiB
Go
Raw Permalink Normal View History

// Package ipamutils provides utility functions for ipam management
package ipamutils
Remove pre-defined networks from package init This moves the initialization of the pre-defined networks to where it's used instead of in package init. This reason for this change is having this be populated in `init()` causes it to always consume cpu, and memory (4.3MB of memory), to populate even if the package is unused (like for instnace, in a re-exec). Here is a memory profile of docker/docker just after starting the daemon of the top 10 largest memory consumers: Before: ``` flat flat% sum% cum cum% 0 0% 0% 11.89MB 95.96% runtime.goexit 0 0% 0% 6.79MB 54.82% runtime.main 0 0% 0% 5.79MB 46.74% main.init 0 0% 0% 4.79MB 38.67% github.com/docker/docker/api/server/router/network.init 0 0% 0% 4.79MB 38.67% github.com/docker/libnetwork.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipam.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipams/builtin.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipamutils.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipamutils.init.1 4.29MB 34.63% 34.63% 4.29MB 34.63% github.com/docker/libnetwork/ipamutils.initGranularPredefinedNetworks ``` After: ``` flat flat% sum% cum cum% 0 0% 0% 4439.37kB 89.66% runtime.goexit 0 0% 0% 4439.37kB 89.66% runtime.main 0 0% 0% 3882.11kB 78.40% github.com/docker/docker/cli.(*Cli).Run 0 0% 0% 3882.11kB 78.40% main.main 3882.11kB 78.40% 78.40% 3882.11kB 78.40% reflect.callMethod 0 0% 78.40% 3882.11kB 78.40% reflect.methodValueCall 0 0% 78.40% 557.26kB 11.25% github.com/docker/docker/api/server.init 557.26kB 11.25% 89.66% 557.26kB 11.25% html.init 0 0% 89.66% 557.26kB 11.25% html/template.init 0 0% 89.66% 557.26kB 11.25% main.init ``` Now, of course the docker daemon will still need to consume this memory, but at least now re-execs and such won't have to re-init these variables. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-04 13:50:26 +00:00
import (
"fmt"
Remove pre-defined networks from package init This moves the initialization of the pre-defined networks to where it's used instead of in package init. This reason for this change is having this be populated in `init()` causes it to always consume cpu, and memory (4.3MB of memory), to populate even if the package is unused (like for instnace, in a re-exec). Here is a memory profile of docker/docker just after starting the daemon of the top 10 largest memory consumers: Before: ``` flat flat% sum% cum cum% 0 0% 0% 11.89MB 95.96% runtime.goexit 0 0% 0% 6.79MB 54.82% runtime.main 0 0% 0% 5.79MB 46.74% main.init 0 0% 0% 4.79MB 38.67% github.com/docker/docker/api/server/router/network.init 0 0% 0% 4.79MB 38.67% github.com/docker/libnetwork.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipam.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipams/builtin.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipamutils.init 0 0% 0% 4.29MB 34.63% github.com/docker/libnetwork/ipamutils.init.1 4.29MB 34.63% 34.63% 4.29MB 34.63% github.com/docker/libnetwork/ipamutils.initGranularPredefinedNetworks ``` After: ``` flat flat% sum% cum cum% 0 0% 0% 4439.37kB 89.66% runtime.goexit 0 0% 0% 4439.37kB 89.66% runtime.main 0 0% 0% 3882.11kB 78.40% github.com/docker/docker/cli.(*Cli).Run 0 0% 0% 3882.11kB 78.40% main.main 3882.11kB 78.40% 78.40% 3882.11kB 78.40% reflect.callMethod 0 0% 78.40% 3882.11kB 78.40% reflect.methodValueCall 0 0% 78.40% 557.26kB 11.25% github.com/docker/docker/api/server.init 557.26kB 11.25% 89.66% 557.26kB 11.25% html.init 0 0% 89.66% 557.26kB 11.25% html/template.init 0 0% 89.66% 557.26kB 11.25% main.init ``` Now, of course the docker daemon will still need to consume this memory, but at least now re-execs and such won't have to re-init these variables. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-04 13:50:26 +00:00
"net"
"sync"
)
var (
// PredefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
// (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGlobalScopeDefaultNetworks`
PredefinedLocalScopeDefaultNetworks []*net.IPNet
// PredefinedGlobalScopeDefaultNetworks 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 `PredefinedLocalScopeDefaultNetworks`
PredefinedGlobalScopeDefaultNetworks []*net.IPNet
mutex sync.Mutex
localScopeDefaultNetworks = []*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}}
globalScopeDefaultNetworks = []*NetworkToSplit{{"10.0.0.0/8", 24}}
)
// 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"`
}
func init() {
var err error
if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); err != nil {
panic("failed to initialize the global scope default address pool: " + err.Error())
}
if PredefinedLocalScopeDefaultNetworks, err = splitNetworks(localScopeDefaultNetworks); err != nil {
panic("failed to initialize the local scope default address pool: " + err.Error())
}
}
// configDefaultNetworks configures local as well global default pool based on input
func configDefaultNetworks(defaultAddressPool []*NetworkToSplit, result *[]*net.IPNet) error {
mutex.Lock()
defer mutex.Unlock()
defaultNetworks, err := splitNetworks(defaultAddressPool)
if err != nil {
return err
}
*result = defaultNetworks
return nil
}
// GetGlobalScopeDefaultNetworks returns PredefinedGlobalScopeDefaultNetworks
func GetGlobalScopeDefaultNetworks() []*net.IPNet {
mutex.Lock()
defer mutex.Unlock()
return PredefinedGlobalScopeDefaultNetworks
}
// GetLocalScopeDefaultNetworks returns PredefinedLocalScopeDefaultNetworks
func GetLocalScopeDefaultNetworks() []*net.IPNet {
mutex.Lock()
defer mutex.Unlock()
return PredefinedLocalScopeDefaultNetworks
}
// ConfigGlobalScopeDefaultNetworks configures global default pool.
// Ideally this will be called from SwarmKit as part of swarm init
func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
if defaultAddressPool == nil {
defaultAddressPool = globalScopeDefaultNetworks
}
return configDefaultNetworks(defaultAddressPool, &PredefinedGlobalScopeDefaultNetworks)
}
// ConfigLocalScopeDefaultNetworks configures local default pool.
// Ideally this will be called during libnetwork init
func ConfigLocalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
if defaultAddressPool == nil {
return nil
}
return configDefaultNetworks(defaultAddressPool, &PredefinedLocalScopeDefaultNetworks)
}
// 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)...)
}
return localPools, nil
}
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
}
}