allocator.go 5.0 KB

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