github.com/lxpollitt/docker@v1.5.0/daemon/networkdriver/ipallocator/allocator.go (about)

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