github.com/cilium/cilium@v1.16.2/pkg/ipam/allocator/multipool/pool.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package multipool 5 6 import ( 7 "errors" 8 "fmt" 9 "net/netip" 10 11 "go4.org/netipx" 12 13 "github.com/cilium/cilium/pkg/ipam" 14 "github.com/cilium/cilium/pkg/ipam/allocator/clusterpool/cidralloc" 15 ) 16 17 var ( 18 errPoolEmpty = errors.New("pool empty") 19 ) 20 21 func allocFirstFreeCIDR(allocators []cidralloc.CIDRAllocator) (netip.Prefix, error) { 22 for _, alloc := range allocators { 23 if alloc.IsFull() { 24 continue 25 } 26 27 ipnet, err := alloc.AllocateNext() 28 if err != nil { 29 return netip.Prefix{}, err 30 } 31 32 prefix, ok := netipx.FromStdIPNet(ipnet) 33 if !ok { 34 return netip.Prefix{}, fmt.Errorf("invalid cidr %s allocated", ipnet) 35 } 36 return prefix, nil 37 } 38 39 return netip.Prefix{}, errPoolEmpty 40 } 41 42 func occupyCIDR(allocators []cidralloc.CIDRAllocator, cidr netip.Prefix) error { 43 ipnet := netipx.PrefixIPNet(cidr) 44 for _, alloc := range allocators { 45 if !alloc.InRange(ipnet) { 46 continue 47 } 48 if alloc.IsFull() { 49 return errPoolEmpty 50 } 51 allocated, err := alloc.IsAllocated(ipnet) 52 if err != nil { 53 return err 54 } 55 if allocated { 56 return fmt.Errorf("cidr %s has already been allocated", cidr) 57 } 58 59 return alloc.Occupy(ipnet) 60 } 61 62 return fmt.Errorf("cidr %s is not part of the requested pool", cidr) 63 } 64 65 func releaseCIDR(allocators []cidralloc.CIDRAllocator, cidr netip.Prefix) error { 66 ipnet := netipx.PrefixIPNet(cidr) 67 for _, alloc := range allocators { 68 if !alloc.InRange(ipnet) { 69 continue 70 } 71 72 allocated, err := alloc.IsAllocated(ipnet) 73 if err != nil { 74 return err 75 } 76 if !allocated { 77 return nil // not an error to release a cidr twice 78 } 79 80 return alloc.Release(ipnet) 81 } 82 83 return fmt.Errorf("released cidr %s was not part the pool", cidr) 84 } 85 86 func hasCIDR(allocators []cidralloc.CIDRAllocator, cidr netip.Prefix) bool { 87 for _, alloc := range allocators { 88 if alloc.IsClusterCIDR(cidr) { 89 return true 90 } 91 } 92 return false 93 } 94 95 func (c *cidrPool) allocCIDR(family ipam.Family) (netip.Prefix, error) { 96 switch family { 97 case ipam.IPv4: 98 return allocFirstFreeCIDR(c.v4) 99 case ipam.IPv6: 100 return allocFirstFreeCIDR(c.v6) 101 default: 102 return netip.Prefix{}, fmt.Errorf("invalid cidr family: %s", family) 103 } 104 } 105 106 func (c *cidrPool) occupyCIDR(cidr netip.Prefix) error { 107 if cidr.Addr().Is4() { 108 return occupyCIDR(c.v4, cidr) 109 } else { 110 return occupyCIDR(c.v6, cidr) 111 } 112 } 113 114 func (c *cidrPool) releaseCIDR(cidr netip.Prefix) error { 115 if cidr.Addr().Is4() { 116 return releaseCIDR(c.v4, cidr) 117 } else { 118 return releaseCIDR(c.v6, cidr) 119 } 120 } 121 122 func (c *cidrPool) hasCIDR(cidr netip.Prefix) bool { 123 if cidr.Addr().Is4() { 124 return hasCIDR(c.v4, cidr) 125 } else { 126 return hasCIDR(c.v6, cidr) 127 } 128 }