allocator.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package ipallocator
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "github.com/dotcloud/docker/daemon/networkdriver"
  6. "github.com/dotcloud/docker/pkg/collections"
  7. "net"
  8. "sync"
  9. "sync/atomic"
  10. )
  11. type allocatedMap struct {
  12. *collections.OrderedIntSet
  13. last int32
  14. }
  15. func newAllocatedMap() *allocatedMap {
  16. return &allocatedMap{OrderedIntSet: collections.NewOrderedIntSet()}
  17. }
  18. type networkSet map[string]*allocatedMap
  19. var (
  20. ErrNoAvailableIPs = errors.New("no available ip addresses on network")
  21. ErrIPAlreadyAllocated = errors.New("ip already allocated")
  22. )
  23. var (
  24. lock = sync.Mutex{}
  25. allocatedIPs = networkSet{}
  26. )
  27. // RequestIP requests an available ip from the given network. It
  28. // will return the next available ip if the ip provided is nil. If the
  29. // ip provided is not nil it will validate that the provided ip is available
  30. // for use or return an error
  31. func RequestIP(address *net.IPNet, ip *net.IP) (*net.IP, error) {
  32. lock.Lock()
  33. defer lock.Unlock()
  34. checkAddress(address)
  35. if ip == nil {
  36. next, err := getNextIp(address)
  37. if err != nil {
  38. return nil, err
  39. }
  40. return next, nil
  41. }
  42. if err := registerIP(address, ip); err != nil {
  43. return nil, err
  44. }
  45. return ip, nil
  46. }
  47. // ReleaseIP adds the provided ip back into the pool of
  48. // available ips to be returned for use.
  49. func ReleaseIP(address *net.IPNet, ip *net.IP) error {
  50. lock.Lock()
  51. defer lock.Unlock()
  52. checkAddress(address)
  53. var (
  54. allocated = allocatedIPs[address.String()]
  55. pos = getPosition(address, ip)
  56. )
  57. allocated.Remove(int(pos))
  58. return nil
  59. }
  60. // convert the ip into the position in the subnet. Only
  61. // position are saved in the set
  62. func getPosition(address *net.IPNet, ip *net.IP) int32 {
  63. var (
  64. first, _ = networkdriver.NetworkRange(address)
  65. base = ipToInt(&first)
  66. i = ipToInt(ip)
  67. )
  68. return i - base
  69. }
  70. // return an available ip if one is currently available. If not,
  71. // return the next available ip for the nextwork
  72. func getNextIp(address *net.IPNet) (*net.IP, error) {
  73. var (
  74. ownIP = ipToInt(&address.IP)
  75. allocated = allocatedIPs[address.String()]
  76. first, _ = networkdriver.NetworkRange(address)
  77. base = ipToInt(&first)
  78. size = int(networkdriver.NetworkSize(address.Mask))
  79. max = int32(size - 2) // size -1 for the broadcast address, -1 for the gateway address
  80. pos = atomic.LoadInt32(&allocated.last)
  81. )
  82. var (
  83. firstNetIP = address.IP.To4().Mask(address.Mask)
  84. firstAsInt = ipToInt(&firstNetIP) + 1
  85. )
  86. for i := int32(0); i < max; i++ {
  87. pos = pos%max + 1
  88. next := int32(base + pos)
  89. if next == ownIP || next == firstAsInt {
  90. continue
  91. }
  92. if !allocated.Exists(int(pos)) {
  93. ip := intToIP(next)
  94. allocated.Push(int(pos))
  95. atomic.StoreInt32(&allocated.last, pos)
  96. return ip, nil
  97. }
  98. }
  99. return nil, ErrNoAvailableIPs
  100. }
  101. func registerIP(address *net.IPNet, ip *net.IP) error {
  102. var (
  103. allocated = allocatedIPs[address.String()]
  104. pos = getPosition(address, ip)
  105. )
  106. if allocated.Exists(int(pos)) {
  107. return ErrIPAlreadyAllocated
  108. }
  109. atomic.StoreInt32(&allocated.last, pos)
  110. return nil
  111. }
  112. // Converts a 4 bytes IP into a 32 bit integer
  113. func ipToInt(ip *net.IP) int32 {
  114. return int32(binary.BigEndian.Uint32(ip.To4()))
  115. }
  116. // Converts 32 bit integer into a 4 bytes IP address
  117. func intToIP(n int32) *net.IP {
  118. b := make([]byte, 4)
  119. binary.BigEndian.PutUint32(b, uint32(n))
  120. ip := net.IP(b)
  121. return &ip
  122. }
  123. func checkAddress(address *net.IPNet) {
  124. key := address.String()
  125. if _, exists := allocatedIPs[key]; !exists {
  126. allocatedIPs[key] = newAllocatedMap()
  127. }
  128. }