allocator.go 3.9 KB

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