github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/ipam/structures.go (about) 1 package ipam 2 3 import ( 4 "fmt" 5 "net/netip" 6 "strings" 7 "sync" 8 9 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/bitmap" 10 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/ipamapi" 11 "github.com/Prakhar-Agarwal-byte/moby/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 // PoolIDFromString creates a new PoolID and populates the SubnetKey object 47 // reading it from the given string. 48 func PoolIDFromString(str string) (pID PoolID, err error) { 49 if str == "" { 50 return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str) 51 } 52 53 p := strings.Split(str, "/") 54 if len(p) != 3 && len(p) != 5 { 55 return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str) 56 } 57 pID.AddressSpace = p[0] 58 pID.Subnet, err = netip.ParsePrefix(p[1] + "/" + p[2]) 59 if err != nil { 60 return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str) 61 } 62 if len(p) == 5 { 63 pID.ChildSubnet, err = netip.ParsePrefix(p[3] + "/" + p[4]) 64 if err != nil { 65 return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str) 66 } 67 } 68 69 return pID, nil 70 } 71 72 // String returns the string form of the SubnetKey object 73 func (s *PoolID) String() string { 74 if s.ChildSubnet == (netip.Prefix{}) { 75 return s.AddressSpace + "/" + s.Subnet.String() 76 } else { 77 return s.AddressSpace + "/" + s.Subnet.String() + "/" + s.ChildSubnet.String() 78 } 79 } 80 81 // String returns the string form of the PoolData object 82 func (p *PoolData) String() string { 83 return fmt.Sprintf("PoolData[Children: %d]", len(p.children)) 84 } 85 86 // allocateSubnet adds the subnet k to the address space. 87 func (aSpace *addrSpace) allocateSubnet(nw, sub netip.Prefix) error { 88 aSpace.Lock() 89 defer aSpace.Unlock() 90 91 // Check if already allocated 92 if pool, ok := aSpace.subnets[nw]; ok { 93 var childExists bool 94 if sub != (netip.Prefix{}) { 95 _, childExists = pool.children[sub] 96 } 97 if sub == (netip.Prefix{}) || childExists { 98 // This means the same pool is already allocated. allocateSubnet is called when there 99 // is request for a pool/subpool. It should ensure there is no overlap with existing pools 100 return ipamapi.ErrPoolOverlap 101 } 102 } 103 104 return aSpace.allocateSubnetL(nw, sub) 105 } 106 107 func (aSpace *addrSpace) allocateSubnetL(nw, sub netip.Prefix) error { 108 // If master pool, check for overlap 109 if sub == (netip.Prefix{}) { 110 if aSpace.contains(nw) { 111 return ipamapi.ErrPoolOverlap 112 } 113 // This is a new master pool, add it along with corresponding bitmask 114 aSpace.subnets[nw] = newPoolData(nw) 115 return nil 116 } 117 118 // This is a new non-master pool (subPool) 119 if nw.Addr().BitLen() != sub.Addr().BitLen() { 120 return fmt.Errorf("pool and subpool are of incompatible address families") 121 } 122 123 // Look for parent pool 124 pp, ok := aSpace.subnets[nw] 125 if !ok { 126 // Parent pool does not exist, add it along with corresponding bitmask 127 pp = newPoolData(nw) 128 pp.autoRelease = true 129 aSpace.subnets[nw] = pp 130 } 131 pp.children[sub] = struct{}{} 132 return nil 133 } 134 135 func (aSpace *addrSpace) releaseSubnet(nw, sub netip.Prefix) error { 136 aSpace.Lock() 137 defer aSpace.Unlock() 138 139 p, ok := aSpace.subnets[nw] 140 if !ok { 141 return ipamapi.ErrBadPool 142 } 143 144 if sub != (netip.Prefix{}) { 145 if _, ok := p.children[sub]; !ok { 146 return ipamapi.ErrBadPool 147 } 148 delete(p.children, sub) 149 } else { 150 p.autoRelease = true 151 } 152 153 if len(p.children) == 0 && p.autoRelease { 154 delete(aSpace.subnets, nw) 155 } 156 157 return nil 158 } 159 160 // contains checks whether nw is a superset or subset of any of the existing subnets in this address space. 161 func (aSpace *addrSpace) contains(nw netip.Prefix) bool { 162 for pool := range aSpace.subnets { 163 if nw.Contains(pool.Addr()) || pool.Contains(nw.Addr()) { 164 return true 165 } 166 } 167 return false 168 }