| // 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()) |
| } |
| } |
| |
| // 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 { |
| return nil |
| } |
| mutex.Lock() |
| defer mutex.Unlock() |
| defaultNetworks, err := SplitNetworks(defaultAddressPool) |
| if err != nil { |
| return err |
| } |
| predefinedGlobalScopeDefaultNetworks = defaultNetworks |
| return nil |
| } |
| |
| // GetGlobalScopeDefaultNetworks returns a copy of the global-sopce network list. |
| func GetGlobalScopeDefaultNetworks() []*net.IPNet { |
| mutex.Lock() |
| defer mutex.Unlock() |
| return append([]*net.IPNet(nil), predefinedGlobalScopeDefaultNetworks...) |
| } |
| |
| // GetLocalScopeDefaultNetworks returns a copy of the default local-scope network list. |
| func GetLocalScopeDefaultNetworks() []*net.IPNet { |
| return append([]*net.IPNet(nil), 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 |
| } |
| } |