Browse Source

Merge pull request #612 from aboch/bip

Retire ipallocator
Jana Radhakrishnan 9 years ago
parent
commit
f14bf27c25

+ 0 - 12
libnetwork/drivers/bridge/bridge.go

@@ -16,7 +16,6 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/driverapi"
-	"github.com/docker/libnetwork/ipallocator"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/netutils"
@@ -42,10 +41,6 @@ const (
 	DefaultGatewayV6AuxKey = "DefaultGatewayIPv6"
 	DefaultGatewayV6AuxKey = "DefaultGatewayIPv6"
 )
 )
 
 
-var (
-	ipAllocator *ipallocator.IPAllocator
-)
-
 // configuration info for the "bridge" driver.
 // configuration info for the "bridge" driver.
 type configuration struct {
 type configuration struct {
 	EnableIPForwarding  bool
 	EnableIPForwarding  bool
@@ -118,7 +113,6 @@ type driver struct {
 
 
 // New constructs a new bridge driver
 // New constructs a new bridge driver
 func newDriver() *driver {
 func newDriver() *driver {
-	ipAllocator = ipallocator.New()
 	return &driver{networks: map[string]*bridgeNetwork{}, config: &configuration{}}
 	return &driver{networks: map[string]*bridgeNetwork{}, config: &configuration{}}
 }
 }
 
 
@@ -1069,12 +1063,6 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 	// Remove port mappings. Do not stop endpoint delete on unmap failure
 	// Remove port mappings. Do not stop endpoint delete on unmap failure
 	n.releasePorts(ep)
 	n.releasePorts(ep)
 
 
-	// Release the v4 address allocated to this endpoint's sandbox interface
-	err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.addr.IP)
-	if err != nil {
-		return err
-	}
-
 	// Try removal of link. Discard error: link pair might have
 	// Try removal of link. Discard error: link pair might have
 	// already been deleted by sandbox delete. Make sure defer
 	// already been deleted by sandbox delete. Make sure defer
 	// does not see this error either.
 	// does not see this error either.

+ 0 - 175
libnetwork/ipallocator/allocator.go

@@ -1,175 +0,0 @@
-// Package ipallocator defines the default IP allocator. It will move out of libnetwork as an external IPAM plugin.
-// This has been imported unchanged from Docker, besides additon of registration logic
-package ipallocator
-
-import (
-	"errors"
-	"math/big"
-	"net"
-	"sync"
-
-	"github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/netutils"
-)
-
-// allocatedMap is thread-unsafe set of allocated IP
-type allocatedMap struct {
-	p     map[string]struct{}
-	last  *big.Int
-	begin *big.Int
-	end   *big.Int
-}
-
-func newAllocatedMap(network *net.IPNet) *allocatedMap {
-	firstIP, lastIP := netutils.NetworkRange(network)
-	begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
-	end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
-
-	return &allocatedMap{
-		p:     make(map[string]struct{}),
-		begin: begin,
-		end:   end,
-		last:  big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin
-	}
-}
-
-type networkSet map[string]*allocatedMap
-
-var (
-	// ErrNoAvailableIPs preformatted error
-	ErrNoAvailableIPs = errors.New("no available ip addresses on network")
-	// ErrIPAlreadyAllocated preformatted error
-	ErrIPAlreadyAllocated = errors.New("ip already allocated")
-	// ErrIPOutOfRange preformatted error
-	ErrIPOutOfRange = errors.New("requested ip is out of range")
-	// ErrNetworkAlreadyRegistered preformatted error
-	ErrNetworkAlreadyRegistered = errors.New("network already registered")
-	// ErrBadSubnet preformatted error
-	ErrBadSubnet = errors.New("network does not contain specified subnet")
-)
-
-// IPAllocator manages the ipam
-type IPAllocator struct {
-	allocatedIPs networkSet
-	mutex        sync.Mutex
-}
-
-// New returns a new instance of IPAllocator
-func New() *IPAllocator {
-	return &IPAllocator{networkSet{}, sync.Mutex{}}
-}
-
-// RegisterSubnet registers network in global allocator with bounds
-// defined by subnet. If you want to use network range you must call
-// this method before first RequestIP, otherwise full network range will be used
-func (a *IPAllocator) RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
-	a.mutex.Lock()
-	defer a.mutex.Unlock()
-
-	nw := &net.IPNet{IP: network.IP.Mask(network.Mask), Mask: network.Mask}
-	key := nw.String()
-	if _, ok := a.allocatedIPs[key]; ok {
-		return ErrNetworkAlreadyRegistered
-	}
-
-	// Check that subnet is within network
-	beginIP, endIP := netutils.NetworkRange(subnet)
-	if !(network.Contains(beginIP) && network.Contains(endIP)) {
-		return ErrBadSubnet
-	}
-
-	n := newAllocatedMap(subnet)
-	a.allocatedIPs[key] = n
-	return nil
-}
-
-// RequestIP requests an available ip from the given network.  It
-// will return the next available ip if the ip provided is nil.  If the
-// ip provided is not nil it will validate that the provided ip is available
-// for use or return an error
-func (a *IPAllocator) RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
-	a.mutex.Lock()
-	defer a.mutex.Unlock()
-
-	nw := &net.IPNet{IP: network.IP.Mask(network.Mask), Mask: network.Mask}
-	key := nw.String()
-	allocated, ok := a.allocatedIPs[key]
-	if !ok {
-		allocated = newAllocatedMap(nw)
-		a.allocatedIPs[key] = allocated
-	}
-
-	if ip == nil {
-		return allocated.getNextIP()
-	}
-	return allocated.checkIP(ip)
-}
-
-// ReleaseIP adds the provided ip back into the pool of
-// available ips to be returned for use.
-func (a *IPAllocator) ReleaseIP(network *net.IPNet, ip net.IP) error {
-	a.mutex.Lock()
-	defer a.mutex.Unlock()
-
-	nw := &net.IPNet{IP: network.IP.Mask(network.Mask), Mask: network.Mask}
-	if allocated, exists := a.allocatedIPs[nw.String()]; exists {
-		delete(allocated.p, ip.String())
-	}
-	return nil
-}
-
-func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
-	if _, ok := allocated.p[ip.String()]; ok {
-		return nil, ErrIPAlreadyAllocated
-	}
-
-	pos := ipToBigInt(ip)
-	// Verify that the IP address is within our network range.
-	if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 {
-		return nil, ErrIPOutOfRange
-	}
-
-	// Register the IP.
-	allocated.p[ip.String()] = struct{}{}
-
-	return ip, nil
-}
-
-// return an available ip if one is currently available.  If not,
-// return the next available ip for the network
-func (allocated *allocatedMap) getNextIP() (net.IP, error) {
-	pos := big.NewInt(0).Set(allocated.last)
-	allRange := big.NewInt(0).Sub(allocated.end, allocated.begin)
-	for i := big.NewInt(0); i.Cmp(allRange) <= 0; i.Add(i, big.NewInt(1)) {
-		pos.Add(pos, big.NewInt(1))
-		if pos.Cmp(allocated.end) == 1 {
-			pos.Set(allocated.begin)
-		}
-		if _, ok := allocated.p[bigIntToIP(pos).String()]; ok {
-			continue
-		}
-		allocated.p[bigIntToIP(pos).String()] = struct{}{}
-		allocated.last.Set(pos)
-		return bigIntToIP(pos), nil
-	}
-	return nil, ErrNoAvailableIPs
-}
-
-// Converts a 4 bytes IP into a 128 bit integer
-func ipToBigInt(ip net.IP) *big.Int {
-	x := big.NewInt(0)
-	if ip4 := ip.To4(); ip4 != nil {
-		return x.SetBytes(ip4)
-	}
-	if ip6 := ip.To16(); ip6 != nil {
-		return x.SetBytes(ip6)
-	}
-
-	logrus.Errorf("ipToBigInt: Wrong IP length! %s", ip)
-	return nil
-}
-
-// Converts 128 bit integer into a 4 bytes IP address
-func bigIntToIP(v *big.Int) net.IP {
-	return net.IP(v.Bytes())
-}

+ 0 - 692
libnetwork/ipallocator/allocator_test.go

@@ -1,692 +0,0 @@
-package ipallocator
-
-import (
-	"fmt"
-	"math/big"
-	"net"
-	"testing"
-
-	_ "github.com/docker/libnetwork/testutils"
-)
-
-func TestConversion(t *testing.T) {
-	ip := net.ParseIP("127.0.0.1")
-	i := ipToBigInt(ip)
-	if i.Cmp(big.NewInt(0x7f000001)) != 0 {
-		t.Fatal("incorrect conversion")
-	}
-	conv := bigIntToIP(i)
-	if !ip.Equal(conv) {
-		t.Error(conv.String())
-	}
-}
-
-func TestConversionIPv6(t *testing.T) {
-	ip := net.ParseIP("2a00:1450::1")
-	ip2 := net.ParseIP("2a00:1450::2")
-	ip3 := net.ParseIP("2a00:1450::1:1")
-	i := ipToBigInt(ip)
-	val, success := big.NewInt(0).SetString("2a001450000000000000000000000001", 16)
-	if !success {
-		t.Fatal("Hex-String to BigInt conversion failed.")
-	}
-	if i.Cmp(val) != 0 {
-		t.Fatal("incorrent conversion")
-	}
-
-	conv := bigIntToIP(i)
-	conv2 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(1)))
-	conv3 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(0x10000)))
-
-	if !ip.Equal(conv) {
-		t.Error("2a00:1450::1 should be equal to " + conv.String())
-	}
-	if !ip2.Equal(conv2) {
-		t.Error("2a00:1450::2 should be equal to " + conv2.String())
-	}
-	if !ip3.Equal(conv3) {
-		t.Error("2a00:1450::1:1 should be equal to " + conv3.String())
-	}
-}
-
-func TestRequestNewIps(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-
-	var ip net.IP
-	var err error
-
-	for i := 1; i < 10; i++ {
-		ip, err = a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		if expected := fmt.Sprintf("192.168.0.%d", i); ip.String() != expected {
-			t.Fatalf("Expected ip %s got %s", expected, ip.String())
-		}
-	}
-	value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-	ip, err = a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if ip.String() != value {
-		t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
-	}
-}
-
-func TestRequestNewIpV6(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
-		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
-	}
-
-	var ip net.IP
-	var err error
-	for i := 1; i < 10; i++ {
-		ip, err = a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		if expected := fmt.Sprintf("2a00:1450::%d", i); ip.String() != expected {
-			t.Fatalf("Expected ip %s got %s", expected, ip.String())
-		}
-	}
-	value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-	ip, err = a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if ip.String() != value {
-		t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
-	}
-}
-
-func TestReleaseIp(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-
-	ip, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestReleaseIpV6(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
-		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
-	}
-
-	ip, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestGetReleasedIp(t *testing.T) {
-	a := New()
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-
-	ip, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	value := ip.String()
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-
-	for i := 0; i < 253; i++ {
-		_, err = a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		err = a.ReleaseIP(network, ip)
-		if err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	ip, err = a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if ip.String() != value {
-		t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
-	}
-}
-
-func TestGetReleasedIpV6(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
-		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0},
-	}
-
-	ip, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	value := ip.String()
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-
-	for i := 0; i < 253; i++ {
-		_, err = a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		err = a.ReleaseIP(network, ip)
-		if err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	ip, err = a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if ip.String() != value {
-		t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
-	}
-}
-
-func TestRequestSpecificIp(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 224},
-	}
-
-	ip := net.ParseIP("192.168.0.5")
-
-	// Request a "good" IP.
-	if _, err := a.RequestIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-
-	// Request the same IP again.
-	if _, err := a.RequestIP(network, ip); err != ErrIPAlreadyAllocated {
-		t.Fatalf("Got the same IP twice: %#v", err)
-	}
-
-	// Request an out of range IP.
-	if _, err := a.RequestIP(network, net.ParseIP("192.168.0.42")); err != ErrIPOutOfRange {
-		t.Fatalf("Got an out of range IP: %#v", err)
-	}
-}
-
-func TestRequestSpecificIpV6(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
-		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
-	}
-
-	ip := net.ParseIP("2a00:1450::5")
-
-	// Request a "good" IP.
-	if _, err := a.RequestIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-
-	// Request the same IP again.
-	if _, err := a.RequestIP(network, ip); err != ErrIPAlreadyAllocated {
-		t.Fatalf("Got the same IP twice: %#v", err)
-	}
-
-	// Request an out of range IP.
-	if _, err := a.RequestIP(network, net.ParseIP("2a00:1500::1")); err != ErrIPOutOfRange {
-		t.Fatalf("Got an out of range IP: %#v", err)
-	}
-}
-
-func TestIPAllocator(t *testing.T) {
-	a := New()
-
-	expectedIPs := []net.IP{
-		0: net.IPv4(127, 0, 0, 1),
-		1: net.IPv4(127, 0, 0, 2),
-		2: net.IPv4(127, 0, 0, 3),
-		3: net.IPv4(127, 0, 0, 4),
-		4: net.IPv4(127, 0, 0, 5),
-		5: net.IPv4(127, 0, 0, 6),
-	}
-
-	gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
-
-	network := &net.IPNet{IP: gwIP, Mask: n.Mask}
-	// Pool after initialisation (f = free, u = used)
-	// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
-	//  ↑
-
-	// Check that we get 6 IPs, from 127.0.0.1–127.0.0.6, in that
-	// order.
-	for i := 0; i < 6; i++ {
-		ip, err := a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		assertIPEquals(t, expectedIPs[i], ip)
-	}
-	// Before loop begin
-	// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
-	//  ↑
-
-	// After i = 0
-	// 1(u) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
-	//         ↑
-
-	// After i = 1
-	// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(f)
-	//                ↑
-
-	// After i = 2
-	// 1(u) - 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
-	//                       ↑
-
-	// After i = 3
-	// 1(u) - 2(u) - 3(u) - 4(u) - 5(f) - 6(f)
-	//                              ↑
-
-	// After i = 4
-	// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(f)
-	//                                     ↑
-
-	// After i = 5
-	// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
-	//  ↑
-
-	// Check that there are no more IPs
-	ip, err := a.RequestIP(network, nil)
-	if err == nil {
-		t.Fatalf("There shouldn't be any IP addresses at this point, got %s\n", ip)
-	}
-
-	// Release some IPs in non-sequential order
-	if err := a.ReleaseIP(network, expectedIPs[3]); err != nil {
-		t.Fatal(err)
-	}
-	// 1(u) - 2(u) - 3(u) - 4(f) - 5(u) - 6(u)
-	//                       ↑
-
-	if err := a.ReleaseIP(network, expectedIPs[2]); err != nil {
-		t.Fatal(err)
-	}
-	// 1(u) - 2(u) - 3(f) - 4(f) - 5(u) - 6(u)
-	//                ↑
-
-	if err := a.ReleaseIP(network, expectedIPs[4]); err != nil {
-		t.Fatal(err)
-	}
-	// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(u)
-	//                              ↑
-
-	// Make sure that IPs are reused in sequential order, starting
-	// with the first released IP
-	newIPs := make([]net.IP, 3)
-	for i := 0; i < 3; i++ {
-		ip, err := a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		newIPs[i] = ip
-	}
-	assertIPEquals(t, expectedIPs[2], newIPs[0])
-	assertIPEquals(t, expectedIPs[3], newIPs[1])
-	assertIPEquals(t, expectedIPs[4], newIPs[2])
-
-	_, err = a.RequestIP(network, nil)
-	if err == nil {
-		t.Fatal("There shouldn't be any IP addresses at this point")
-	}
-}
-
-func TestAllocateFirstIP(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 0},
-		Mask: []byte{255, 255, 255, 0},
-	}
-
-	firstIP := network.IP.To4().Mask(network.Mask)
-	first := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
-
-	ip, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	allocated := ipToBigInt(ip)
-
-	if allocated == first {
-		t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
-	}
-}
-
-func TestAllocateAllIps(t *testing.T) {
-	a := New()
-
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-
-	var (
-		current, first net.IP
-		err            error
-		isFirst        = true
-	)
-
-	for err == nil {
-		current, err = a.RequestIP(network, nil)
-		if isFirst {
-			first = current
-			isFirst = false
-		}
-	}
-
-	if err != ErrNoAvailableIPs {
-		t.Fatal(err)
-	}
-
-	if _, err := a.RequestIP(network, nil); err != ErrNoAvailableIPs {
-		t.Fatal(err)
-	}
-
-	if err := a.ReleaseIP(network, first); err != nil {
-		t.Fatal(err)
-	}
-
-	again, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assertIPEquals(t, first, again)
-
-	// ensure that alloc.last == alloc.begin won't result in dead loop
-	if _, err := a.RequestIP(network, nil); err != ErrNoAvailableIPs {
-		t.Fatal(err)
-	}
-
-	// Test by making alloc.last the only free ip and ensure we get it back
-	// #1. first of the range, (alloc.last == ipToInt(first) already)
-	if err := a.ReleaseIP(network, first); err != nil {
-		t.Fatal(err)
-	}
-
-	ret, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assertIPEquals(t, first, ret)
-
-	// #2. last of the range, note that current is the last one
-	last := net.IPv4(192, 168, 0, 254)
-	setLastTo(t, a, network, last)
-
-	ret, err = a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assertIPEquals(t, last, ret)
-
-	// #3. middle of the range
-	mid := net.IPv4(192, 168, 0, 7)
-	setLastTo(t, a, network, mid)
-
-	ret, err = a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assertIPEquals(t, mid, ret)
-}
-
-// make sure the pool is full when calling setLastTo.
-// we don't cheat here
-func setLastTo(t *testing.T, a *IPAllocator, network *net.IPNet, ip net.IP) {
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-
-	ret, err := a.RequestIP(network, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assertIPEquals(t, ip, ret)
-
-	if err := a.ReleaseIP(network, ip); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestAllocateDifferentSubnets(t *testing.T) {
-	a := New()
-	network1 := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-	network2 := &net.IPNet{
-		IP:   []byte{127, 0, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-	network3 := &net.IPNet{
-		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
-		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
-	}
-	network4 := &net.IPNet{
-		IP:   []byte{0x2a, 0x00, 0x16, 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
-		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
-	}
-	expectedIPs := []net.IP{
-		0: net.IPv4(192, 168, 0, 1),
-		1: net.IPv4(192, 168, 0, 2),
-		2: net.IPv4(127, 0, 0, 1),
-		3: net.IPv4(127, 0, 0, 2),
-		4: net.ParseIP("2a00:1450::1"),
-		5: net.ParseIP("2a00:1450::2"),
-		6: net.ParseIP("2a00:1450::3"),
-		7: net.ParseIP("2a00:1632::1"),
-		8: net.ParseIP("2a00:1632::2"),
-	}
-
-	ip11, err := a.RequestIP(network1, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip12, err := a.RequestIP(network1, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip21, err := a.RequestIP(network2, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip22, err := a.RequestIP(network2, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip31, err := a.RequestIP(network3, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip32, err := a.RequestIP(network3, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip33, err := a.RequestIP(network3, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip41, err := a.RequestIP(network4, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	ip42, err := a.RequestIP(network4, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	assertIPEquals(t, expectedIPs[0], ip11)
-	assertIPEquals(t, expectedIPs[1], ip12)
-	assertIPEquals(t, expectedIPs[2], ip21)
-	assertIPEquals(t, expectedIPs[3], ip22)
-	assertIPEquals(t, expectedIPs[4], ip31)
-	assertIPEquals(t, expectedIPs[5], ip32)
-	assertIPEquals(t, expectedIPs[6], ip33)
-	assertIPEquals(t, expectedIPs[7], ip41)
-	assertIPEquals(t, expectedIPs[8], ip42)
-}
-
-func TestRegisterBadTwice(t *testing.T) {
-	a := New()
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 1, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-	subnet := &net.IPNet{
-		IP:   []byte{192, 168, 1, 8},
-		Mask: []byte{255, 255, 255, 248},
-	}
-
-	if err := a.RegisterSubnet(network, subnet); err != nil {
-		t.Fatal(err)
-	}
-	subnet = &net.IPNet{
-		IP:   []byte{192, 168, 1, 16},
-		Mask: []byte{255, 255, 255, 248},
-	}
-	if err := a.RegisterSubnet(network, subnet); err != ErrNetworkAlreadyRegistered {
-		t.Fatalf("Expecteded ErrNetworkAlreadyRegistered error, got %v", err)
-	}
-}
-
-func TestRegisterBadRange(t *testing.T) {
-	a := New()
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 1, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-	subnet := &net.IPNet{
-		IP:   []byte{192, 168, 1, 1},
-		Mask: []byte{255, 255, 0, 0},
-	}
-	if err := a.RegisterSubnet(network, subnet); err != ErrBadSubnet {
-		t.Fatalf("Expected ErrBadSubnet error, got %v", err)
-	}
-}
-
-func TestAllocateFromRange(t *testing.T) {
-	a := New()
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-	// 192.168.1.9 - 192.168.1.14
-	subnet := &net.IPNet{
-		IP:   []byte{192, 168, 0, 8},
-		Mask: []byte{255, 255, 255, 248},
-	}
-
-	if err := a.RegisterSubnet(network, subnet); err != nil {
-		t.Fatal(err)
-	}
-	expectedIPs := []net.IP{
-		0: net.IPv4(192, 168, 0, 9),
-		1: net.IPv4(192, 168, 0, 10),
-		2: net.IPv4(192, 168, 0, 11),
-		3: net.IPv4(192, 168, 0, 12),
-		4: net.IPv4(192, 168, 0, 13),
-		5: net.IPv4(192, 168, 0, 14),
-	}
-	for _, ip := range expectedIPs {
-		rip, err := a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		assertIPEquals(t, ip, rip)
-	}
-
-	if _, err := a.RequestIP(network, nil); err != ErrNoAvailableIPs {
-		t.Fatalf("Expected ErrNoAvailableIPs error, got %v", err)
-	}
-	for _, ip := range expectedIPs {
-		a.ReleaseIP(network, ip)
-		rip, err := a.RequestIP(network, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		assertIPEquals(t, ip, rip)
-	}
-}
-
-func assertIPEquals(t *testing.T, ip1, ip2 net.IP) {
-	if !ip1.Equal(ip2) {
-		t.Fatalf("Expected IP %s, got %s", ip1, ip2)
-	}
-}
-
-func BenchmarkRequestIP(b *testing.B) {
-	network := &net.IPNet{
-		IP:   []byte{192, 168, 0, 1},
-		Mask: []byte{255, 255, 255, 0},
-	}
-	b.ResetTimer()
-
-	for i := 0; i < b.N; i++ {
-		a := New()
-
-		for j := 0; j < 253; j++ {
-			_, err := a.RequestIP(network, nil)
-			if err != nil {
-				b.Fatal(err)
-			}
-		}
-	}
-}