diff --git a/network.go b/network.go index 1e9a2edd5d..977db53c90 100644 --- a/network.go +++ b/network.go @@ -3,6 +3,7 @@ package docker import ( "bytes" "encoding/binary" + "errors" "fmt" "math/rand" "net" @@ -118,3 +119,65 @@ func allocateNetwork() (*NetworkInterface, error) { } return iface, nil } + +type NetworkAllocator struct { + iface string + queue chan (net.IP) +} + +func (alloc *NetworkAllocator) Acquire() (net.IP, error) { + select { + case ip := <-alloc.queue: + return ip, nil + default: + return net.IP{}, errors.New("No more IP addresses available") + } + return net.IP{}, nil +} + +func (alloc *NetworkAllocator) Release(ip net.IP) error { + select { + case alloc.queue <- ip: + return nil + default: + return errors.New("Too many IP addresses have been released") + } + return nil +} + +func (alloc *NetworkAllocator) PopulateFromNetwork(network *net.IPNet) error { + firstIP, _ := networkRange(network) + size, err := networkSize(network.Mask) + if err != nil { + return err + } + // The queue size should be the network size - 3 + // -1 for the network address, -1 for the broadcast address and + // -1 for the gateway address + alloc.queue = make(chan net.IP, size-3) + for i := int32(1); i < size-1; i++ { + ipNum, err := ipToInt(firstIP) + if err != nil { + return err + } + ip, err := intToIp(ipNum + int32(i)) + if err != nil { + return err + } + // Discard the network IP (that's the host IP address) + if ip.Equal(network.IP) { + continue + } + alloc.Release(ip) + } + return nil +} + +func (alloc *NetworkAllocator) PopulateFromInterface(iface string) error { + addr, err := getBridgeAddr(iface) + if err != nil { + return err + } + network := addr.(*net.IPNet) + return alloc.PopulateFromNetwork(network) +} diff --git a/network_test.go b/network_test.go index c1ea382783..c3de398681 100644 --- a/network_test.go +++ b/network_test.go @@ -99,3 +99,30 @@ func TestConversion(t *testing.T) { t.Error(conv.String()) } } + +func TestNetworkAllocator(t *testing.T) { + alloc := NetworkAllocator{} + _, n, _ := net.ParseCIDR("127.0.0.1/29") + alloc.PopulateFromNetwork(n) + var lastIP net.IP + for i := 0; i < 5; i++ { + ip, err := alloc.Acquire() + if err != nil { + t.Fatal(err) + } + lastIP = ip + } + ip, err := alloc.Acquire() + if err == nil { + t.Fatal("There shouldn't be any IP addresses at this point") + } + // Release 1 IP + alloc.Release(lastIP) + ip, err = alloc.Acquire() + if err != nil { + t.Fatal(err) + } + if !ip.Equal(lastIP) { + t.Fatal(ip.String()) + } +}