cidr_set.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. clusterSubnetMaxDiff = 16
  40. // halfIPv6Len is the half of the IPv6 length
  41. halfIPv6Len = net.IPv6len / 2
  42. )
  43. var (
  44. // ErrCIDRRangeNoCIDRsRemaining occurs when there is no more space
  45. // to allocate CIDR ranges.
  46. ErrCIDRRangeNoCIDRsRemaining = errors.New(
  47. "CIDR allocation failed; there are no remaining CIDRs left to allocate in the accepted range")
  48. // ErrCIDRSetSubNetTooBig occurs when the subnet mask size is too
  49. // big compared to the CIDR mask size.
  50. ErrCIDRSetSubNetTooBig = errors.New(
  51. "New CIDR set failed; the node CIDR size is too big")
  52. )
  53. // NewCIDRSet creates a new CidrSet.
  54. func NewCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) (*CidrSet, error) {
  55. clusterMask := clusterCIDR.Mask
  56. clusterMaskSize, _ := clusterMask.Size()
  57. var maxCIDRs int
  58. if (clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff) {
  59. return nil, ErrCIDRSetSubNetTooBig
  60. }
  61. maxCIDRs = 1 << uint32(subNetMaskSize-clusterMaskSize)
  62. return &CidrSet{
  63. clusterCIDR: clusterCIDR,
  64. clusterIP: clusterCIDR.IP,
  65. clusterMaskSize: clusterMaskSize,
  66. maxCIDRs: maxCIDRs,
  67. subNetMaskSize: subNetMaskSize,
  68. }, nil
  69. }
  70. func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet {
  71. var ip []byte
  72. var mask int
  73. switch /*v4 or v6*/ {
  74. case s.clusterIP.To4() != nil:
  75. {
  76. j := uint32(index) << uint32(32-s.subNetMaskSize)
  77. ipInt := (binary.BigEndian.Uint32(s.clusterIP)) | j
  78. ip = make([]byte, 4)
  79. binary.BigEndian.PutUint32(ip, ipInt)
  80. mask = 32
  81. }
  82. case s.clusterIP.To16() != nil:
  83. {
  84. // leftClusterIP | rightClusterIP
  85. // 2001:0DB8:1234:0000:0000:0000:0000:0000
  86. const v6NBits = 128
  87. const halfV6NBits = v6NBits / 2
  88. leftClusterIP := binary.BigEndian.Uint64(s.clusterIP[:halfIPv6Len])
  89. rightClusterIP := binary.BigEndian.Uint64(s.clusterIP[halfIPv6Len:])
  90. leftIP, rightIP := make([]byte, halfIPv6Len), make([]byte, halfIPv6Len)
  91. if s.subNetMaskSize <= halfV6NBits {
  92. // We only care about left side IP
  93. leftClusterIP |= uint64(index) << uint(halfV6NBits-s.subNetMaskSize)
  94. } else {
  95. if s.clusterMaskSize < halfV6NBits {
  96. // see how many bits are needed to reach the left side
  97. btl := uint(s.subNetMaskSize - halfV6NBits)
  98. indexMaxBit := uint(64 - bits.LeadingZeros64(uint64(index)))
  99. if indexMaxBit > btl {
  100. leftClusterIP |= uint64(index) >> btl
  101. }
  102. }
  103. // the right side will be calculated the same way either the
  104. // subNetMaskSize affects both left and right sides
  105. rightClusterIP |= uint64(index) << uint(v6NBits-s.subNetMaskSize)
  106. }
  107. binary.BigEndian.PutUint64(leftIP, leftClusterIP)
  108. binary.BigEndian.PutUint64(rightIP, rightClusterIP)
  109. ip = append(leftIP, rightIP...)
  110. mask = 128
  111. }
  112. }
  113. return &net.IPNet{
  114. IP: ip,
  115. Mask: net.CIDRMask(s.subNetMaskSize, mask),
  116. }
  117. }
  118. // AllocateNext allocates the next free CIDR range. This will set the range
  119. // as occupied and return the allocated range.
  120. func (s *CidrSet) AllocateNext() (*net.IPNet, error) {
  121. s.Lock()
  122. defer s.Unlock()
  123. nextUnused := -1
  124. for i := 0; i < s.maxCIDRs; i++ {
  125. candidate := (i + s.nextCandidate) % s.maxCIDRs
  126. if s.used.Bit(candidate) == 0 {
  127. nextUnused = candidate
  128. break
  129. }
  130. }
  131. if nextUnused == -1 {
  132. return nil, ErrCIDRRangeNoCIDRsRemaining
  133. }
  134. s.nextCandidate = (nextUnused + 1) % s.maxCIDRs
  135. s.used.SetBit(&s.used, nextUnused, 1)
  136. return s.indexToCIDRBlock(nextUnused), nil
  137. }
  138. func (s *CidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err error) {
  139. begin, end = 0, s.maxCIDRs-1
  140. cidrMask := cidr.Mask
  141. maskSize, _ := cidrMask.Size()
  142. var ipSize int
  143. if cidr == nil {
  144. return -1, -1, fmt.Errorf("Error getting indices for cluster cidr %v, cidr is nil", s.clusterCIDR)
  145. }
  146. if !s.clusterCIDR.Contains(cidr.IP.Mask(s.clusterCIDR.Mask)) && !cidr.Contains(s.clusterCIDR.IP.Mask(cidr.Mask)) {
  147. return -1, -1, fmt.Errorf("cidr %v is out the range of cluster cidr %v", cidr, s.clusterCIDR)
  148. }
  149. if s.clusterMaskSize < maskSize {
  150. ipSize = net.IPv4len
  151. if cidr.IP.To4() == nil {
  152. ipSize = net.IPv6len
  153. }
  154. subNetMask := net.CIDRMask(s.subNetMaskSize, ipSize*8)
  155. begin, err = s.getIndexForCIDR(&net.IPNet{
  156. IP: cidr.IP.Mask(subNetMask),
  157. Mask: subNetMask,
  158. })
  159. if err != nil {
  160. return -1, -1, err
  161. }
  162. ip := make([]byte, ipSize)
  163. if cidr.IP.To4() != nil {
  164. ipInt := binary.BigEndian.Uint32(cidr.IP) | (^binary.BigEndian.Uint32(cidr.Mask))
  165. binary.BigEndian.PutUint32(ip, ipInt)
  166. } else {
  167. // ipIntLeft | ipIntRight
  168. // 2001:0DB8:1234:0000:0000:0000:0000:0000
  169. ipIntLeft := binary.BigEndian.Uint64(cidr.IP[:net.IPv6len/2]) | (^binary.BigEndian.Uint64(cidr.Mask[:net.IPv6len/2]))
  170. ipIntRight := binary.BigEndian.Uint64(cidr.IP[net.IPv6len/2:]) | (^binary.BigEndian.Uint64(cidr.Mask[net.IPv6len/2:]))
  171. binary.BigEndian.PutUint64(ip[:net.IPv6len/2], ipIntLeft)
  172. binary.BigEndian.PutUint64(ip[net.IPv6len/2:], ipIntRight)
  173. }
  174. end, err = s.getIndexForCIDR(&net.IPNet{
  175. IP: net.IP(ip).Mask(subNetMask),
  176. Mask: subNetMask,
  177. })
  178. if err != nil {
  179. return -1, -1, err
  180. }
  181. }
  182. return begin, end, nil
  183. }
  184. // Release releases the given CIDR range.
  185. func (s *CidrSet) Release(cidr *net.IPNet) error {
  186. begin, end, err := s.getBeginingAndEndIndices(cidr)
  187. if err != nil {
  188. return err
  189. }
  190. s.Lock()
  191. defer s.Unlock()
  192. for i := begin; i <= end; i++ {
  193. s.used.SetBit(&s.used, i, 0)
  194. }
  195. return nil
  196. }
  197. // Occupy marks the given CIDR range as used. Occupy does not check if the CIDR
  198. // range was previously used.
  199. func (s *CidrSet) Occupy(cidr *net.IPNet) (err error) {
  200. begin, end, err := s.getBeginingAndEndIndices(cidr)
  201. if err != nil {
  202. return err
  203. }
  204. s.Lock()
  205. defer s.Unlock()
  206. for i := begin; i <= end; i++ {
  207. s.used.SetBit(&s.used, i, 1)
  208. }
  209. return nil
  210. }
  211. func (s *CidrSet) getIndexForCIDR(cidr *net.IPNet) (int, error) {
  212. return s.getIndexForIP(cidr.IP)
  213. }
  214. func (s *CidrSet) getIndexForIP(ip net.IP) (int, error) {
  215. if ip.To4() != nil {
  216. cidrIndex := (binary.BigEndian.Uint32(s.clusterIP) ^ binary.BigEndian.Uint32(ip.To4())) >> uint32(32-s.subNetMaskSize)
  217. if cidrIndex >= uint32(s.maxCIDRs) {
  218. return 0, fmt.Errorf("CIDR: %v/%v is out of the range of CIDR allocator", ip, s.subNetMaskSize)
  219. }
  220. return int(cidrIndex), nil
  221. }
  222. if ip.To16() != nil {
  223. bigIP := big.NewInt(0).SetBytes(s.clusterIP)
  224. bigIP = bigIP.Xor(bigIP, big.NewInt(0).SetBytes(ip))
  225. cidrIndexBig := bigIP.Rsh(bigIP, uint(net.IPv6len*8-s.subNetMaskSize))
  226. cidrIndex := cidrIndexBig.Uint64()
  227. if cidrIndex >= uint64(s.maxCIDRs) {
  228. return 0, fmt.Errorf("CIDR: %v/%v is out of the range of CIDR allocator", ip, s.subNetMaskSize)
  229. }
  230. return int(cidrIndex), nil
  231. }
  232. return 0, fmt.Errorf("invalid IP: %v", ip)
  233. }