cidr_set.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cidrset
  14. import (
  15. "encoding/binary"
  16. "errors"
  17. "fmt"
  18. "math/big"
  19. "math/bits"
  20. "net"
  21. "sync"
  22. )
  23. // CidrSet manages a set of CIDR ranges from which blocks of IPs can
  24. // be allocated from.
  25. type CidrSet struct {
  26. sync.Mutex
  27. clusterCIDR *net.IPNet
  28. clusterIP net.IP
  29. clusterMaskSize int
  30. maxCIDRs int
  31. nextCandidate int
  32. used big.Int
  33. subNetMaskSize int
  34. }
  35. const (
  36. // The subnet mask size cannot be greater than 16 more than the cluster mask size
  37. // TODO: https://github.com/kubernetes/kubernetes/issues/44918
  38. // clusterSubnetMaxDiff limited to 16 due to the uncompressed bitmap
  39. // Due to this limitation the subnet mask for IPv6 cluster cidr needs to be >= 48
  40. // as default mask size for IPv6 is 64.
  41. clusterSubnetMaxDiff = 16
  42. // halfIPv6Len is the half of the IPv6 length
  43. halfIPv6Len = net.IPv6len / 2
  44. )
  45. var (
  46. // ErrCIDRRangeNoCIDRsRemaining occurs when there is no more space
  47. // to allocate CIDR ranges.
  48. ErrCIDRRangeNoCIDRsRemaining = errors.New(
  49. "CIDR allocation failed; there are no remaining CIDRs left to allocate in the accepted range")
  50. // ErrCIDRSetSubNetTooBig occurs when the subnet mask size is too
  51. // big compared to the CIDR mask size.
  52. ErrCIDRSetSubNetTooBig = errors.New(
  53. "New CIDR set failed; the node CIDR size is too big")
  54. )
  55. // NewCIDRSet creates a new CidrSet.
  56. func NewCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) (*CidrSet, error) {
  57. clusterMask := clusterCIDR.Mask
  58. clusterMaskSize, _ := clusterMask.Size()
  59. var maxCIDRs int
  60. if (clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff) {
  61. return nil, ErrCIDRSetSubNetTooBig
  62. }
  63. maxCIDRs = 1 << uint32(subNetMaskSize-clusterMaskSize)
  64. return &CidrSet{
  65. clusterCIDR: clusterCIDR,
  66. clusterIP: clusterCIDR.IP,
  67. clusterMaskSize: clusterMaskSize,
  68. maxCIDRs: maxCIDRs,
  69. subNetMaskSize: subNetMaskSize,
  70. }, nil
  71. }
  72. func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet {
  73. var ip []byte
  74. var mask int
  75. switch /*v4 or v6*/ {
  76. case s.clusterIP.To4() != nil:
  77. {
  78. j := uint32(index) << uint32(32-s.subNetMaskSize)
  79. ipInt := (binary.BigEndian.Uint32(s.clusterIP)) | j
  80. ip = make([]byte, 4)
  81. binary.BigEndian.PutUint32(ip, ipInt)
  82. mask = 32
  83. }
  84. case s.clusterIP.To16() != nil:
  85. {
  86. // leftClusterIP | rightClusterIP
  87. // 2001:0DB8:1234:0000:0000:0000:0000:0000
  88. const v6NBits = 128
  89. const halfV6NBits = v6NBits / 2
  90. leftClusterIP := binary.BigEndian.Uint64(s.clusterIP[:halfIPv6Len])
  91. rightClusterIP := binary.BigEndian.Uint64(s.clusterIP[halfIPv6Len:])
  92. leftIP, rightIP := make([]byte, halfIPv6Len), make([]byte, halfIPv6Len)
  93. if s.subNetMaskSize <= halfV6NBits {
  94. // We only care about left side IP
  95. leftClusterIP |= uint64(index) << uint(halfV6NBits-s.subNetMaskSize)
  96. } else {
  97. if s.clusterMaskSize < halfV6NBits {
  98. // see how many bits are needed to reach the left side
  99. btl := uint(s.subNetMaskSize - halfV6NBits)
  100. indexMaxBit := uint(64 - bits.LeadingZeros64(uint64(index)))
  101. if indexMaxBit > btl {
  102. leftClusterIP |= uint64(index) >> btl
  103. }
  104. }
  105. // the right side will be calculated the same way either the
  106. // subNetMaskSize affects both left and right sides
  107. rightClusterIP |= uint64(index) << uint(v6NBits-s.subNetMaskSize)
  108. }
  109. binary.BigEndian.PutUint64(leftIP, leftClusterIP)
  110. binary.BigEndian.PutUint64(rightIP, rightClusterIP)
  111. ip = append(leftIP, rightIP...)
  112. mask = 128
  113. }
  114. }
  115. return &net.IPNet{
  116. IP: ip,
  117. Mask: net.CIDRMask(s.subNetMaskSize, mask),
  118. }
  119. }
  120. // AllocateNext allocates the next free CIDR range. This will set the range
  121. // as occupied and return the allocated range.
  122. func (s *CidrSet) AllocateNext() (*net.IPNet, error) {
  123. s.Lock()
  124. defer s.Unlock()
  125. nextUnused := -1
  126. for i := 0; i < s.maxCIDRs; i++ {
  127. candidate := (i + s.nextCandidate) % s.maxCIDRs
  128. if s.used.Bit(candidate) == 0 {
  129. nextUnused = candidate
  130. break
  131. }
  132. }
  133. if nextUnused == -1 {
  134. return nil, ErrCIDRRangeNoCIDRsRemaining
  135. }
  136. s.nextCandidate = (nextUnused + 1) % s.maxCIDRs
  137. s.used.SetBit(&s.used, nextUnused, 1)
  138. return s.indexToCIDRBlock(nextUnused), nil
  139. }
  140. func (s *CidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err error) {
  141. begin, end = 0, s.maxCIDRs-1
  142. cidrMask := cidr.Mask
  143. maskSize, _ := cidrMask.Size()
  144. var ipSize int
  145. if cidr == nil {
  146. return -1, -1, fmt.Errorf("error getting indices for cluster cidr %v, cidr is nil", s.clusterCIDR)
  147. }
  148. if !s.clusterCIDR.Contains(cidr.IP.Mask(s.clusterCIDR.Mask)) && !cidr.Contains(s.clusterCIDR.IP.Mask(cidr.Mask)) {
  149. return -1, -1, fmt.Errorf("cidr %v is out the range of cluster cidr %v", cidr, s.clusterCIDR)
  150. }
  151. if s.clusterMaskSize < maskSize {
  152. ipSize = net.IPv4len
  153. if cidr.IP.To4() == nil {
  154. ipSize = net.IPv6len
  155. }
  156. subNetMask := net.CIDRMask(s.subNetMaskSize, ipSize*8)
  157. begin, err = s.getIndexForCIDR(&net.IPNet{
  158. IP: cidr.IP.Mask(subNetMask),
  159. Mask: subNetMask,
  160. })
  161. if err != nil {
  162. return -1, -1, err
  163. }
  164. ip := make([]byte, ipSize)
  165. if cidr.IP.To4() != nil {
  166. ipInt := binary.BigEndian.Uint32(cidr.IP) | (^binary.BigEndian.Uint32(cidr.Mask))
  167. binary.BigEndian.PutUint32(ip, ipInt)
  168. } else {
  169. // ipIntLeft | ipIntRight
  170. // 2001:0DB8:1234:0000:0000:0000:0000:0000
  171. ipIntLeft := binary.BigEndian.Uint64(cidr.IP[:net.IPv6len/2]) | (^binary.BigEndian.Uint64(cidr.Mask[:net.IPv6len/2]))
  172. ipIntRight := binary.BigEndian.Uint64(cidr.IP[net.IPv6len/2:]) | (^binary.BigEndian.Uint64(cidr.Mask[net.IPv6len/2:]))
  173. binary.BigEndian.PutUint64(ip[:net.IPv6len/2], ipIntLeft)
  174. binary.BigEndian.PutUint64(ip[net.IPv6len/2:], ipIntRight)
  175. }
  176. end, err = s.getIndexForCIDR(&net.IPNet{
  177. IP: net.IP(ip).Mask(subNetMask),
  178. Mask: subNetMask,
  179. })
  180. if err != nil {
  181. return -1, -1, err
  182. }
  183. }
  184. return begin, end, nil
  185. }
  186. // Release releases the given CIDR range.
  187. func (s *CidrSet) Release(cidr *net.IPNet) error {
  188. begin, end, err := s.getBeginingAndEndIndices(cidr)
  189. if err != nil {
  190. return err
  191. }
  192. s.Lock()
  193. defer s.Unlock()
  194. for i := begin; i <= end; i++ {
  195. s.used.SetBit(&s.used, i, 0)
  196. }
  197. return nil
  198. }
  199. // Occupy marks the given CIDR range as used. Occupy does not check if the CIDR
  200. // range was previously used.
  201. func (s *CidrSet) Occupy(cidr *net.IPNet) (err error) {
  202. begin, end, err := s.getBeginingAndEndIndices(cidr)
  203. if err != nil {
  204. return err
  205. }
  206. s.Lock()
  207. defer s.Unlock()
  208. for i := begin; i <= end; i++ {
  209. s.used.SetBit(&s.used, i, 1)
  210. }
  211. return nil
  212. }
  213. func (s *CidrSet) getIndexForCIDR(cidr *net.IPNet) (int, error) {
  214. return s.getIndexForIP(cidr.IP)
  215. }
  216. func (s *CidrSet) getIndexForIP(ip net.IP) (int, error) {
  217. if ip.To4() != nil {
  218. cidrIndex := (binary.BigEndian.Uint32(s.clusterIP) ^ binary.BigEndian.Uint32(ip.To4())) >> uint32(32-s.subNetMaskSize)
  219. if cidrIndex >= uint32(s.maxCIDRs) {
  220. return 0, fmt.Errorf("CIDR: %v/%v is out of the range of CIDR allocator", ip, s.subNetMaskSize)
  221. }
  222. return int(cidrIndex), nil
  223. }
  224. if ip.To16() != nil {
  225. bigIP := big.NewInt(0).SetBytes(s.clusterIP)
  226. bigIP = bigIP.Xor(bigIP, big.NewInt(0).SetBytes(ip))
  227. cidrIndexBig := bigIP.Rsh(bigIP, uint(net.IPv6len*8-s.subNetMaskSize))
  228. cidrIndex := cidrIndexBig.Uint64()
  229. if cidrIndex >= uint64(s.maxCIDRs) {
  230. return 0, fmt.Errorf("CIDR: %v/%v is out of the range of CIDR allocator", ip, s.subNetMaskSize)
  231. }
  232. return int(cidrIndex), nil
  233. }
  234. return 0, fmt.Errorf("invalid IP: %v", ip)
  235. }