github.com/cilium/cilium@v1.16.2/pkg/ipam/allocator/clusterpool/cidralloc/cidralloc.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package cidralloc 5 6 import ( 7 "fmt" 8 "net" 9 "net/netip" 10 11 "github.com/cilium/cilium/pkg/ip" 12 "github.com/cilium/cilium/pkg/ipam/cidrset" 13 ) 14 15 type CIDRAllocator interface { 16 fmt.Stringer 17 18 Occupy(cidr *net.IPNet) error 19 AllocateNext() (*net.IPNet, error) 20 Release(cidr *net.IPNet) error 21 IsAllocated(cidr *net.IPNet) (bool, error) 22 IsFull() bool 23 InRange(cidr *net.IPNet) bool 24 IsClusterCIDR(prefix netip.Prefix) bool 25 Prefix() netip.Prefix 26 } 27 28 type ErrCIDRCollision struct { 29 cidr string 30 allocator CIDRAllocator 31 } 32 33 func (e ErrCIDRCollision) Error() string { 34 return fmt.Sprintf("requested CIDR %s collides with %s", e.cidr, e.allocator) 35 } 36 37 func (e *ErrCIDRCollision) Is(target error) bool { 38 t, ok := target.(*ErrCIDRCollision) 39 if !ok { 40 return false 41 } 42 return t.cidr == e.cidr 43 } 44 45 func NewCIDRSets(isV6 bool, strCIDRs []string, maskSize int) ([]CIDRAllocator, error) { 46 cidrAllocators := make([]CIDRAllocator, 0, len(strCIDRs)) 47 for _, strCIDR := range strCIDRs { 48 addr, cidr, err := net.ParseCIDR(strCIDR) 49 if err != nil { 50 return nil, err 51 } 52 // Check if CIDRs collide with each other. 53 for _, cidrAllocator := range cidrAllocators { 54 if cidrAllocator.InRange(cidr) { 55 return nil, &ErrCIDRCollision{ 56 cidr: strCIDR, 57 allocator: cidrAllocator, 58 } 59 } 60 } 61 62 switch { 63 case isV6 && ip.IsIPv4(addr): 64 return nil, fmt.Errorf("CIDR is not v6 family: %s", cidr) 65 case !isV6 && !ip.IsIPv4(addr): 66 return nil, fmt.Errorf("CIDR is not v4 family: %s", cidr) 67 } 68 cidrSet, err := cidrset.NewCIDRSet(cidr, maskSize) 69 if err != nil { 70 return nil, err 71 } 72 cidrAllocators = append(cidrAllocators, cidrSet) 73 } 74 return cidrAllocators, nil 75 }