allocator.go 3.6 KB

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