allocator.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package ipallocator
  2. import (
  3. "errors"
  4. "math/big"
  5. "net"
  6. "sync"
  7. "github.com/docker/docker/daemon/networkdriver"
  8. "github.com/docker/docker/pkg/log"
  9. )
  10. // allocatedMap is thread-unsafe set of allocated IP
  11. type allocatedMap struct {
  12. p map[string]struct{}
  13. last *big.Int
  14. begin *big.Int
  15. end *big.Int
  16. }
  17. func newAllocatedMap(network *net.IPNet) *allocatedMap {
  18. firstIP, lastIP := networkdriver.NetworkRange(network)
  19. begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
  20. end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
  21. // if IPv4 network, then allocation range starts at begin + 1 because begin is bridge IP
  22. if len(firstIP) == 4 {
  23. begin = begin.Add(begin, big.NewInt(1))
  24. }
  25. return &allocatedMap{
  26. p: make(map[string]struct{}),
  27. begin: begin,
  28. end: end,
  29. last: big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin
  30. }
  31. }
  32. type networkSet map[string]*allocatedMap
  33. var (
  34. ErrNoAvailableIPs = errors.New("no available ip addresses on network")
  35. ErrIPAlreadyAllocated = errors.New("ip already allocated")
  36. ErrIPOutOfRange = errors.New("requested ip is out of range")
  37. ErrNetworkAlreadyRegistered = errors.New("network already registered")
  38. ErrBadSubnet = errors.New("network does not contain specified subnet")
  39. )
  40. var (
  41. lock = sync.Mutex{}
  42. allocatedIPs = networkSet{}
  43. )
  44. // RegisterSubnet registers network in global allocator with bounds
  45. // defined by subnet. If you want to use network range you must call
  46. // this method before first RequestIP, otherwise full network range will be used
  47. func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
  48. lock.Lock()
  49. defer lock.Unlock()
  50. key := network.String()
  51. if _, ok := allocatedIPs[key]; ok {
  52. return ErrNetworkAlreadyRegistered
  53. }
  54. n := newAllocatedMap(network)
  55. beginIP, endIP := networkdriver.NetworkRange(subnet)
  56. begin := big.NewInt(0).Add(ipToBigInt(beginIP), big.NewInt(1))
  57. end := big.NewInt(0).Sub(ipToBigInt(endIP), big.NewInt(1))
  58. // Check that subnet is within network
  59. if !(begin.Cmp(n.begin) >= 0 && end.Cmp(n.end) <= 0 && begin.Cmp(end) == -1) {
  60. return ErrBadSubnet
  61. }
  62. n.begin.Set(begin)
  63. n.end.Set(end)
  64. n.last.Sub(begin, big.NewInt(1))
  65. allocatedIPs[key] = n
  66. return nil
  67. }
  68. // RequestIP requests an available ip from the given network. It
  69. // will return the next available ip if the ip provided is nil. If the
  70. // ip provided is not nil it will validate that the provided ip is available
  71. // for use or return an error
  72. func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
  73. lock.Lock()
  74. defer lock.Unlock()
  75. key := network.String()
  76. allocated, ok := allocatedIPs[key]
  77. if !ok {
  78. allocated = newAllocatedMap(network)
  79. allocatedIPs[key] = allocated
  80. }
  81. if ip == nil {
  82. return allocated.getNextIP()
  83. }
  84. return allocated.checkIP(ip)
  85. }
  86. // ReleaseIP adds the provided ip back into the pool of
  87. // available ips to be returned for use.
  88. func ReleaseIP(network *net.IPNet, ip net.IP) error {
  89. lock.Lock()
  90. defer lock.Unlock()
  91. if allocated, exists := allocatedIPs[network.String()]; exists {
  92. delete(allocated.p, ip.String())
  93. }
  94. return nil
  95. }
  96. func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
  97. if _, ok := allocated.p[ip.String()]; ok {
  98. return nil, ErrIPAlreadyAllocated
  99. }
  100. pos := ipToBigInt(ip)
  101. // Verify that the IP address is within our network range.
  102. if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 {
  103. return nil, ErrIPOutOfRange
  104. }
  105. // Register the IP.
  106. allocated.p[ip.String()] = struct{}{}
  107. allocated.last.Set(pos)
  108. return ip, nil
  109. }
  110. // return an available ip if one is currently available. If not,
  111. // return the next available ip for the nextwork
  112. func (allocated *allocatedMap) getNextIP() (net.IP, error) {
  113. for pos := big.NewInt(0).Add(allocated.last, big.NewInt(1)); pos.Cmp(allocated.last) != 0; pos.Add(pos, big.NewInt(1)) {
  114. if pos.Cmp(allocated.end) == 1 {
  115. pos.Set(allocated.begin)
  116. }
  117. if _, ok := allocated.p[bigIntToIP(pos).String()]; ok {
  118. continue
  119. }
  120. allocated.p[bigIntToIP(pos).String()] = struct{}{}
  121. allocated.last.Set(pos)
  122. return bigIntToIP(pos), nil
  123. }
  124. return nil, ErrNoAvailableIPs
  125. }
  126. // Converts a 4 bytes IP into a 128 bit integer
  127. func ipToBigInt(ip net.IP) *big.Int {
  128. x := big.NewInt(0)
  129. if ip4 := ip.To4(); ip4 != nil {
  130. return x.SetBytes(ip4)
  131. }
  132. if ip6 := ip.To16(); ip6 != nil {
  133. return x.SetBytes(ip6)
  134. }
  135. log.Errorf("ipToBigInt: Wrong IP length! %s", ip)
  136. return nil
  137. }
  138. // Converts 128 bit integer into a 4 bytes IP address
  139. func bigIntToIP(v *big.Int) net.IP {
  140. return net.IP(v.Bytes())
  141. }