github.com/jjyr/docker@v1.5.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 // 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 }