github.com/jaegerpicker/docker@v0.7.7-0.20150325003727-22dba32b4dab/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 return &allocatedMap{ 27 p: make(map[string]struct{}), 28 begin: begin, 29 end: end, 30 last: big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin 31 } 32 } 33 34 type networkSet map[string]*allocatedMap 35 36 var ( 37 ErrNoAvailableIPs = errors.New("no available ip addresses on network") 38 ErrIPAlreadyAllocated = errors.New("ip already allocated") 39 ErrIPOutOfRange = errors.New("requested ip is out of range") 40 ErrNetworkAlreadyRegistered = errors.New("network already registered") 41 ErrBadSubnet = errors.New("network does not contain specified subnet") 42 ) 43 44 type IPAllocator struct { 45 allocatedIPs networkSet 46 mutex sync.Mutex 47 } 48 49 func New() *IPAllocator { 50 return &IPAllocator{networkSet{}, sync.Mutex{}} 51 } 52 53 // RegisterSubnet registers network in global allocator with bounds 54 // defined by subnet. If you want to use network range you must call 55 // this method before first RequestIP, otherwise full network range will be used 56 func (a *IPAllocator) RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error { 57 a.mutex.Lock() 58 defer a.mutex.Unlock() 59 60 key := network.String() 61 if _, ok := a.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 a.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 (a *IPAllocator) RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) { 85 a.mutex.Lock() 86 defer a.mutex.Unlock() 87 88 key := network.String() 89 allocated, ok := a.allocatedIPs[key] 90 if !ok { 91 allocated = newAllocatedMap(network) 92 a.allocatedIPs[key] = allocated 93 } 94 95 if ip == nil { 96 return allocated.getNextIP() 97 } 98 return allocated.checkIP(ip) 99 } 100 101 // ReleaseIP adds the provided ip back into the pool of 102 // available ips to be returned for use. 103 func (a *IPAllocator) ReleaseIP(network *net.IPNet, ip net.IP) error { 104 a.mutex.Lock() 105 defer a.mutex.Unlock() 106 107 if allocated, exists := a.allocatedIPs[network.String()]; exists { 108 delete(allocated.p, ip.String()) 109 } 110 return nil 111 } 112 113 func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) { 114 if _, ok := allocated.p[ip.String()]; ok { 115 return nil, ErrIPAlreadyAllocated 116 } 117 118 pos := ipToBigInt(ip) 119 // Verify that the IP address is within our network range. 120 if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 { 121 return nil, ErrIPOutOfRange 122 } 123 124 // Register the IP. 125 allocated.p[ip.String()] = struct{}{} 126 127 return ip, nil 128 } 129 130 // return an available ip if one is currently available. If not, 131 // return the next available ip for the nextwork 132 func (allocated *allocatedMap) getNextIP() (net.IP, error) { 133 pos := big.NewInt(0).Set(allocated.last) 134 allRange := big.NewInt(0).Sub(allocated.end, allocated.begin) 135 for i := big.NewInt(0); i.Cmp(allRange) <= 0; i.Add(i, big.NewInt(1)) { 136 pos.Add(pos, big.NewInt(1)) 137 if pos.Cmp(allocated.end) == 1 { 138 pos.Set(allocated.begin) 139 } 140 if _, ok := allocated.p[bigIntToIP(pos).String()]; ok { 141 continue 142 } 143 allocated.p[bigIntToIP(pos).String()] = struct{}{} 144 allocated.last.Set(pos) 145 return bigIntToIP(pos), nil 146 } 147 return nil, ErrNoAvailableIPs 148 } 149 150 // Converts a 4 bytes IP into a 128 bit integer 151 func ipToBigInt(ip net.IP) *big.Int { 152 x := big.NewInt(0) 153 if ip4 := ip.To4(); ip4 != nil { 154 return x.SetBytes(ip4) 155 } 156 if ip6 := ip.To16(); ip6 != nil { 157 return x.SetBytes(ip6) 158 } 159 160 log.Errorf("ipToBigInt: Wrong IP length! %s", ip) 161 return nil 162 } 163 164 // Converts 128 bit integer into a 4 bytes IP address 165 func bigIntToIP(v *big.Int) net.IP { 166 return net.IP(v.Bytes()) 167 }