// Package ipamutils provides utility functions for ipam management package ipamutils import ( "fmt" "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<= 0; i-- { array[i] |= (byte)(ordinal & 0xff) ordinal >>= 8 } }