allocator.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. package ipallocator
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "github.com/dotcloud/docker/pkg/netlink"
  6. "net"
  7. "sync"
  8. )
  9. type networkSet map[iPNet]iPSet
  10. type iPSet map[string]struct{}
  11. type iPNet struct {
  12. IP string
  13. Mask string
  14. }
  15. var (
  16. ErrNetworkAlreadyAllocated = errors.New("requested network overlaps with existing network")
  17. ErrNetworkAlreadyRegisterd = errors.New("requested network is already registered")
  18. lock = sync.Mutex{}
  19. allocatedIPs = networkSet{}
  20. availableIPS = networkSet{}
  21. )
  22. func RegisterNetwork(network *net.IPNet) error {
  23. lock.Lock()
  24. defer lock.Unlock()
  25. routes, err := netlink.NetworkGetRoutes()
  26. if err != nil {
  27. return err
  28. }
  29. if err := checkRouteOverlaps(routes, network); err != nil {
  30. return err
  31. }
  32. if err := checkExistingNetworkOverlaps(network); err != nil {
  33. return err
  34. }
  35. allocatedIPs[newIPNet(network)] = iPSet{}
  36. return nil
  37. }
  38. func RequestIP(ip *net.IPAddr) (*net.IPAddr, error) {
  39. lock.Lock()
  40. defer lock.Unlock()
  41. if ip == nil {
  42. next, err := getNextIp()
  43. if err != nil {
  44. return nil, err
  45. }
  46. return next, nil
  47. }
  48. if err := validateIP(ip); err != nil {
  49. return nil, err
  50. }
  51. return ip, nil
  52. }
  53. func ReleaseIP(ip *net.IPAddr) error {
  54. lock.Lock()
  55. defer lock.Unlock()
  56. }
  57. func getNextIp(network iPNet) (net.IPAddr, error) {
  58. if available, exists := availableIPS[network]; exists {
  59. }
  60. var (
  61. netNetwork = newNetIPNet(network)
  62. firstIP, _ = networkRange(netNetwork)
  63. ipNum = ipToInt(firstIP)
  64. ownIP = ipToInt(netNetwork.IP)
  65. size = networkSize(netNetwork.Mask)
  66. pos = int32(1)
  67. max = size - 2 // -1 for the broadcast address, -1 for the gateway address
  68. )
  69. for {
  70. var (
  71. newNum int32
  72. inUse bool
  73. )
  74. // Find first unused IP, give up after one whole round
  75. for attempt := int32(0); attempt < max; attempt++ {
  76. newNum = ipNum + pos
  77. pos = pos%max + 1
  78. // The network's IP is never okay to use
  79. if newNum == ownIP {
  80. continue
  81. }
  82. if _, inUse = alloc.inUse[newNum]; !inUse {
  83. // We found an unused IP
  84. break
  85. }
  86. }
  87. ip := allocatedIP{ip: intToIP(newNum)}
  88. if inUse {
  89. ip.err = errors.New("No unallocated IP available")
  90. }
  91. select {
  92. case quit := <-alloc.quit:
  93. if quit {
  94. return
  95. }
  96. case alloc.queueAlloc <- ip:
  97. alloc.inUse[newNum] = struct{}{}
  98. case released := <-alloc.queueReleased:
  99. r := ipToInt(released)
  100. delete(alloc.inUse, r)
  101. if inUse {
  102. // If we couldn't allocate a new IP, the released one
  103. // will be the only free one now, so instantly use it
  104. // next time
  105. pos = r - ipNum
  106. } else {
  107. // Use same IP as last time
  108. if pos == 1 {
  109. pos = max
  110. } else {
  111. pos--
  112. }
  113. }
  114. }
  115. }
  116. }
  117. func validateIP(ip *net.IPAddr) error {
  118. }
  119. func checkRouteOverlaps(networks []netlink.Route, toCheck *net.IPNet) error {
  120. for _, network := range networks {
  121. if network.IPNet != nil && networkOverlaps(toCheck, network.IPNet) {
  122. return ErrNetworkAlreadyAllocated
  123. }
  124. }
  125. return nil
  126. }
  127. // Detects overlap between one IPNet and another
  128. func networkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
  129. if firstIP, _ := networkRange(netX); netY.Contains(firstIP) {
  130. return true
  131. }
  132. if firstIP, _ := networkRange(netY); netX.Contains(firstIP) {
  133. return true
  134. }
  135. return false
  136. }
  137. func checkExistingNetworkOverlaps(network *net.IPNet) error {
  138. for existing := range allocatedIPs {
  139. if newIPNet(network) == existing {
  140. return ErrNetworkAlreadyRegisterd
  141. }
  142. if networkOverlaps(network, existing) {
  143. return ErrNetworkAlreadyAllocated
  144. }
  145. }
  146. return nil
  147. }
  148. // Calculates the first and last IP addresses in an IPNet
  149. func networkRange(network *net.IPNet) (net.IP, net.IP) {
  150. var (
  151. netIP = network.IP.To4()
  152. firstIP = netIP.Mask(network.Mask)
  153. lastIP = net.IPv4(0, 0, 0, 0).To4()
  154. )
  155. for i := 0; i < len(lastIP); i++ {
  156. lastIP[i] = netIP[i] | ^network.Mask[i]
  157. }
  158. return firstIP, lastIP
  159. }
  160. func newIPNet(network *net.IPNet) iPNet {
  161. return iPNet{
  162. IP: string(network.IP),
  163. Mask: string(network.Mask),
  164. }
  165. }
  166. func newNetIPNet(network iPNet) *net.IPNet {
  167. return &net.IPNet{
  168. IP: []byte(network.IP),
  169. Mask: []byte(network.Mask),
  170. }
  171. }
  172. // Converts a 4 bytes IP into a 32 bit integer
  173. func ipToInt(ip net.IP) int32 {
  174. return int32(binary.BigEndian.Uint32(ip.To4()))
  175. }
  176. // Converts 32 bit integer into a 4 bytes IP address
  177. func intToIP(n int32) net.IP {
  178. b := make([]byte, 4)
  179. binary.BigEndian.PutUint32(b, uint32(n))
  180. return net.IP(b)
  181. }
  182. // Given a netmask, calculates the number of available hosts
  183. func networkSize(mask net.IPMask) int32 {
  184. m := net.IPv4Mask(0, 0, 0, 0)
  185. for i := 0; i < net.IPv4len; i++ {
  186. m[i] = ^mask[i]
  187. }
  188. return int32(binary.BigEndian.Uint32(m)) + 1
  189. }