structures.go 4.3 KB

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