| ... | ... |
@@ -3,6 +3,7 @@ package docker |
| 3 | 3 |
import ( |
| 4 | 4 |
"bytes" |
| 5 | 5 |
"encoding/binary" |
| 6 |
+ "errors" |
|
| 6 | 7 |
"fmt" |
| 7 | 8 |
"math/rand" |
| 8 | 9 |
"net" |
| ... | ... |
@@ -118,3 +119,65 @@ func allocateNetwork() (*NetworkInterface, error) {
|
| 118 | 118 |
} |
| 119 | 119 |
return iface, nil |
| 120 | 120 |
} |
| 121 |
+ |
|
| 122 |
+type NetworkAllocator struct {
|
|
| 123 |
+ iface string |
|
| 124 |
+ queue chan (net.IP) |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+func (alloc *NetworkAllocator) Acquire() (net.IP, error) {
|
|
| 128 |
+ select {
|
|
| 129 |
+ case ip := <-alloc.queue: |
|
| 130 |
+ return ip, nil |
|
| 131 |
+ default: |
|
| 132 |
+ return net.IP{}, errors.New("No more IP addresses available")
|
|
| 133 |
+ } |
|
| 134 |
+ return net.IP{}, nil
|
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+func (alloc *NetworkAllocator) Release(ip net.IP) error {
|
|
| 138 |
+ select {
|
|
| 139 |
+ case alloc.queue <- ip: |
|
| 140 |
+ return nil |
|
| 141 |
+ default: |
|
| 142 |
+ return errors.New("Too many IP addresses have been released")
|
|
| 143 |
+ } |
|
| 144 |
+ return nil |
|
| 145 |
+} |
|
| 146 |
+ |
|
| 147 |
+func (alloc *NetworkAllocator) PopulateFromNetwork(network *net.IPNet) error {
|
|
| 148 |
+ firstIP, _ := networkRange(network) |
|
| 149 |
+ size, err := networkSize(network.Mask) |
|
| 150 |
+ if err != nil {
|
|
| 151 |
+ return err |
|
| 152 |
+ } |
|
| 153 |
+ // The queue size should be the network size - 3 |
|
| 154 |
+ // -1 for the network address, -1 for the broadcast address and |
|
| 155 |
+ // -1 for the gateway address |
|
| 156 |
+ alloc.queue = make(chan net.IP, size-3) |
|
| 157 |
+ for i := int32(1); i < size-1; i++ {
|
|
| 158 |
+ ipNum, err := ipToInt(firstIP) |
|
| 159 |
+ if err != nil {
|
|
| 160 |
+ return err |
|
| 161 |
+ } |
|
| 162 |
+ ip, err := intToIp(ipNum + int32(i)) |
|
| 163 |
+ if err != nil {
|
|
| 164 |
+ return err |
|
| 165 |
+ } |
|
| 166 |
+ // Discard the network IP (that's the host IP address) |
|
| 167 |
+ if ip.Equal(network.IP) {
|
|
| 168 |
+ continue |
|
| 169 |
+ } |
|
| 170 |
+ alloc.Release(ip) |
|
| 171 |
+ } |
|
| 172 |
+ return nil |
|
| 173 |
+} |
|
| 174 |
+ |
|
| 175 |
+func (alloc *NetworkAllocator) PopulateFromInterface(iface string) error {
|
|
| 176 |
+ addr, err := getBridgeAddr(iface) |
|
| 177 |
+ if err != nil {
|
|
| 178 |
+ return err |
|
| 179 |
+ } |
|
| 180 |
+ network := addr.(*net.IPNet) |
|
| 181 |
+ return alloc.PopulateFromNetwork(network) |
|
| 182 |
+} |
| ... | ... |
@@ -99,3 +99,30 @@ func TestConversion(t *testing.T) {
|
| 99 | 99 |
t.Error(conv.String()) |
| 100 | 100 |
} |
| 101 | 101 |
} |
| 102 |
+ |
|
| 103 |
+func TestNetworkAllocator(t *testing.T) {
|
|
| 104 |
+ alloc := NetworkAllocator{}
|
|
| 105 |
+ _, n, _ := net.ParseCIDR("127.0.0.1/29")
|
|
| 106 |
+ alloc.PopulateFromNetwork(n) |
|
| 107 |
+ var lastIP net.IP |
|
| 108 |
+ for i := 0; i < 5; i++ {
|
|
| 109 |
+ ip, err := alloc.Acquire() |
|
| 110 |
+ if err != nil {
|
|
| 111 |
+ t.Fatal(err) |
|
| 112 |
+ } |
|
| 113 |
+ lastIP = ip |
|
| 114 |
+ } |
|
| 115 |
+ ip, err := alloc.Acquire() |
|
| 116 |
+ if err == nil {
|
|
| 117 |
+ t.Fatal("There shouldn't be any IP addresses at this point")
|
|
| 118 |
+ } |
|
| 119 |
+ // Release 1 IP |
|
| 120 |
+ alloc.Release(lastIP) |
|
| 121 |
+ ip, err = alloc.Acquire() |
|
| 122 |
+ if err != nil {
|
|
| 123 |
+ t.Fatal(err) |
|
| 124 |
+ } |
|
| 125 |
+ if !ip.Equal(lastIP) {
|
|
| 126 |
+ t.Fatal(ip.String()) |
|
| 127 |
+ } |
|
| 128 |
+} |