github.com/rawahars/moby@v24.0.4+incompatible/libnetwork/ipam/structures.go (about) 1 package ipam 2 3 import ( 4 "fmt" 5 "net/netip" 6 "strings" 7 "sync" 8 9 "github.com/docker/docker/libnetwork/bitmap" 10 "github.com/docker/docker/libnetwork/ipamapi" 11 "github.com/docker/docker/libnetwork/types" 12 ) 13 14 // PoolID is the pointer to the configured pools in each address space 15 type PoolID struct { 16 AddressSpace string 17 SubnetKey 18 } 19 20 // PoolData contains the configured pool data 21 type PoolData struct { 22 addrs *bitmap.Bitmap 23 children map[netip.Prefix]struct{} 24 25 // Whether to implicitly release the pool once it no longer has any children. 26 autoRelease bool 27 } 28 29 // SubnetKey is the composite key to an address pool within an address space. 30 type SubnetKey struct { 31 Subnet, ChildSubnet netip.Prefix 32 } 33 34 // addrSpace contains the pool configurations for the address space 35 type addrSpace struct { 36 // Master subnet pools, indexed by the value's stringified PoolData.Pool field. 37 subnets map[netip.Prefix]*PoolData 38 39 // Predefined pool for the address space 40 predefined []netip.Prefix 41 predefinedStartIndex int 42 43 sync.Mutex 44 } 45 46 // String returns the string form of the SubnetKey object 47 func (s *PoolID) String() string { 48 k := fmt.Sprintf("%s/%s", s.AddressSpace, s.Subnet) 49 if s.ChildSubnet != (netip.Prefix{}) { 50 k = fmt.Sprintf("%s/%s", k, s.ChildSubnet) 51 } 52 return k 53 } 54 55 // FromString populates the SubnetKey object reading it from string 56 func (s *PoolID) FromString(str string) error { 57 if str == "" || !strings.Contains(str, "/") { 58 return types.BadRequestErrorf("invalid string form for subnetkey: %s", str) 59 } 60 61 p := strings.Split(str, "/") 62 if len(p) != 3 && len(p) != 5 { 63 return types.BadRequestErrorf("invalid string form for subnetkey: %s", str) 64 } 65 sub, err := netip.ParsePrefix(p[1] + "/" + p[2]) 66 if err != nil { 67 return types.BadRequestErrorf("%v", err) 68 } 69 var child netip.Prefix 70 if len(p) == 5 { 71 child, err = netip.ParsePrefix(p[3] + "/" + p[4]) 72 if err != nil { 73 return types.BadRequestErrorf("%v", err) 74 } 75 } 76 77 *s = PoolID{ 78 AddressSpace: p[0], 79 SubnetKey: SubnetKey{ 80 Subnet: sub, 81 ChildSubnet: child, 82 }, 83 } 84 return nil 85 } 86 87 // String returns the string form of the PoolData object 88 func (p *PoolData) String() string { 89 return fmt.Sprintf("PoolData[Children: %d]", len(p.children)) 90 } 91 92 // allocateSubnet adds the subnet k to the address space. 93 func (aSpace *addrSpace) allocateSubnet(nw, sub netip.Prefix) error { 94 aSpace.Lock() 95 defer aSpace.Unlock() 96 97 // Check if already allocated 98 if pool, ok := aSpace.subnets[nw]; ok { 99 var childExists bool 100 if sub != (netip.Prefix{}) { 101 _, childExists = pool.children[sub] 102 } 103 if sub == (netip.Prefix{}) || childExists { 104 // This means the same pool is already allocated. allocateSubnet is called when there 105 // is request for a pool/subpool. It should ensure there is no overlap with existing pools 106 return ipamapi.ErrPoolOverlap 107 } 108 } 109 110 return aSpace.allocateSubnetL(nw, sub) 111 } 112 113 func (aSpace *addrSpace) allocateSubnetL(nw, sub netip.Prefix) error { 114 // If master pool, check for overlap 115 if sub == (netip.Prefix{}) { 116 if aSpace.contains(nw) { 117 return ipamapi.ErrPoolOverlap 118 } 119 // This is a new master pool, add it along with corresponding bitmask 120 aSpace.subnets[nw] = newPoolData(nw) 121 return nil 122 } 123 124 // This is a new non-master pool (subPool) 125 if nw.Addr().BitLen() != sub.Addr().BitLen() { 126 return fmt.Errorf("pool and subpool are of incompatible address families") 127 } 128 129 // Look for parent pool 130 pp, ok := aSpace.subnets[nw] 131 if !ok { 132 // Parent pool does not exist, add it along with corresponding bitmask 133 pp = newPoolData(nw) 134 pp.autoRelease = true 135 aSpace.subnets[nw] = pp 136 } 137 pp.children[sub] = struct{}{} 138 return nil 139 } 140 141 func (aSpace *addrSpace) releaseSubnet(nw, sub netip.Prefix) error { 142 aSpace.Lock() 143 defer aSpace.Unlock() 144 145 p, ok := aSpace.subnets[nw] 146 if !ok { 147 return ipamapi.ErrBadPool 148 } 149 150 if sub != (netip.Prefix{}) { 151 if _, ok := p.children[sub]; !ok { 152 return ipamapi.ErrBadPool 153 } 154 delete(p.children, sub) 155 } else { 156 p.autoRelease = true 157 } 158 159 if len(p.children) == 0 && p.autoRelease { 160 delete(aSpace.subnets, nw) 161 } 162 163 return nil 164 } 165 166 // contains checks whether nw is a superset or subset of any of the existing subnets in this address space. 167 func (aSpace *addrSpace) contains(nw netip.Prefix) bool { 168 for pool := range aSpace.subnets { 169 if nw.Contains(pool.Addr()) || pool.Contains(nw.Addr()) { 170 return true 171 } 172 } 173 return false 174 }