github.com/erriapo/docker@v1.6.0-rc2/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 var ( 45 lock = sync.Mutex{} 46 allocatedIPs = networkSet{} 47 ) 48 49 // RegisterSubnet registers network in global allocator with bounds 50 // defined by subnet. If you want to use network range you must call 51 // this method before first RequestIP, otherwise full network range will be used 52 func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error { 53 lock.Lock() 54 defer lock.Unlock() 55 key := network.String() 56 if _, ok := allocatedIPs[key]; ok { 57 return ErrNetworkAlreadyRegistered 58 } 59 n := newAllocatedMap(network) 60 beginIP, endIP := networkdriver.NetworkRange(subnet) 61 begin := big.NewInt(0).Add(ipToBigInt(beginIP), big.NewInt(1)) 62 end := big.NewInt(0).Sub(ipToBigInt(endIP), big.NewInt(1)) 63 64 // Check that subnet is within network 65 if !(begin.Cmp(n.begin) >= 0 && end.Cmp(n.end) <= 0 && begin.Cmp(end) == -1) { 66 return ErrBadSubnet 67 } 68 n.begin.Set(begin) 69 n.end.Set(end) 70 n.last.Sub(begin, big.NewInt(1)) 71 allocatedIPs[key] = n 72 return nil 73 } 74 75 // RequestIP requests an available ip from the given network. It 76 // will return the next available ip if the ip provided is nil. If the 77 // ip provided is not nil it will validate that the provided ip is available 78 // for use or return an error 79 func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) { 80 lock.Lock() 81 defer lock.Unlock() 82 key := network.String() 83 allocated, ok := allocatedIPs[key] 84 if !ok { 85 allocated = newAllocatedMap(network) 86 allocatedIPs[key] = allocated 87 } 88 89 if ip == nil { 90 return allocated.getNextIP() 91 } 92 return allocated.checkIP(ip) 93 } 94 95 // ReleaseIP adds the provided ip back into the pool of 96 // available ips to be returned for use. 97 func ReleaseIP(network *net.IPNet, ip net.IP) error { 98 lock.Lock() 99 defer lock.Unlock() 100 if allocated, exists := allocatedIPs[network.String()]; exists { 101 delete(allocated.p, ip.String()) 102 } 103 return nil 104 } 105 106 func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) { 107 if _, ok := allocated.p[ip.String()]; ok { 108 return nil, ErrIPAlreadyAllocated 109 } 110 111 pos := ipToBigInt(ip) 112 // Verify that the IP address is within our network range. 113 if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 { 114 return nil, ErrIPOutOfRange 115 } 116 117 // Register the IP. 118 allocated.p[ip.String()] = struct{}{} 119 120 return ip, nil 121 } 122 123 // return an available ip if one is currently available. If not, 124 // return the next available ip for the nextwork 125 func (allocated *allocatedMap) getNextIP() (net.IP, error) { 126 pos := big.NewInt(0).Set(allocated.last) 127 allRange := big.NewInt(0).Sub(allocated.end, allocated.begin) 128 for i := big.NewInt(0); i.Cmp(allRange) <= 0; i.Add(i, big.NewInt(1)) { 129 pos.Add(pos, big.NewInt(1)) 130 if pos.Cmp(allocated.end) == 1 { 131 pos.Set(allocated.begin) 132 } 133 if _, ok := allocated.p[bigIntToIP(pos).String()]; ok { 134 continue 135 } 136 allocated.p[bigIntToIP(pos).String()] = struct{}{} 137 allocated.last.Set(pos) 138 return bigIntToIP(pos), nil 139 } 140 return nil, ErrNoAvailableIPs 141 } 142 143 // Converts a 4 bytes IP into a 128 bit integer 144 func ipToBigInt(ip net.IP) *big.Int { 145 x := big.NewInt(0) 146 if ip4 := ip.To4(); ip4 != nil { 147 return x.SetBytes(ip4) 148 } 149 if ip6 := ip.To16(); ip6 != nil { 150 return x.SetBytes(ip6) 151 } 152 153 log.Errorf("ipToBigInt: Wrong IP length! %s", ip) 154 return nil 155 } 156 157 // Converts 128 bit integer into a 4 bytes IP address 158 func bigIntToIP(v *big.Int) net.IP { 159 return net.IP(v.Bytes()) 160 }