1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Use a structure to keep the allocated ips pool.

Fixes #11624.

Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2015-03-23 20:20:10 -07:00
parent bcb369af11
commit 7e95b13460
3 changed files with 128 additions and 111 deletions

View file

@ -80,6 +80,7 @@ var (
defaultBindingIP = net.ParseIP("0.0.0.0")
currentInterfaces = ifaces{c: make(map[string]*networkInterface)}
ipAllocator = ipallocator.New()
)
func InitDriver(job *engine.Job) engine.Status {
@ -244,7 +245,7 @@ func InitDriver(job *engine.Job) engine.Status {
return job.Error(err)
}
log.Debugf("Subnet: %v", subnet)
if err := ipallocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil {
if err := ipAllocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil {
return job.Error(err)
}
}
@ -255,14 +256,14 @@ func InitDriver(job *engine.Job) engine.Status {
return job.Error(err)
}
log.Debugf("Subnet: %v", subnet)
if err := ipallocator.RegisterSubnet(subnet, subnet); err != nil {
if err := ipAllocator.RegisterSubnet(subnet, subnet); err != nil {
return job.Error(err)
}
globalIPv6Network = subnet
}
// Block BridgeIP in IP allocator
ipallocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP)
ipAllocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP)
// https://github.com/docker/docker/issues/2768
job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP)
@ -509,7 +510,7 @@ func Allocate(job *engine.Job) engine.Status {
globalIPv6 net.IP
)
ip, err = ipallocator.RequestIP(bridgeIPv4Network, requestedIP)
ip, err = ipAllocator.RequestIP(bridgeIPv4Network, requestedIP)
if err != nil {
return job.Error(err)
}
@ -530,7 +531,7 @@ func Allocate(job *engine.Job) engine.Status {
}
}
globalIPv6, err = ipallocator.RequestIP(globalIPv6Network, requestedIPv6)
globalIPv6, err = ipAllocator.RequestIP(globalIPv6Network, requestedIPv6)
if err != nil {
log.Errorf("Allocator: RequestIP v6: %v", err)
return job.Error(err)
@ -591,11 +592,11 @@ func Release(job *engine.Job) engine.Status {
}
}
if err := ipallocator.ReleaseIP(bridgeIPv4Network, containerInterface.IP); err != nil {
if err := ipAllocator.ReleaseIP(bridgeIPv4Network, containerInterface.IP); err != nil {
log.Infof("Unable to release IPv4 %s", err)
}
if globalIPv6Network != nil {
if err := ipallocator.ReleaseIP(globalIPv6Network, containerInterface.IPv6); err != nil {
if err := ipAllocator.ReleaseIP(globalIPv6Network, containerInterface.IPv6); err != nil {
log.Infof("Unable to release IPv6 %s", err)
}
}

View file

@ -41,19 +41,24 @@ var (
ErrBadSubnet = errors.New("network does not contain specified subnet")
)
var (
lock = sync.Mutex{}
allocatedIPs = networkSet{}
)
type IPAllocator struct {
allocatedIPs networkSet
mutex sync.Mutex
}
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 RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
lock.Lock()
defer lock.Unlock()
func (a *IPAllocator) RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
a.mutex.Lock()
defer a.mutex.Unlock()
key := network.String()
if _, ok := allocatedIPs[key]; ok {
if _, ok := a.allocatedIPs[key]; ok {
return ErrNetworkAlreadyRegistered
}
n := newAllocatedMap(network)
@ -68,7 +73,7 @@ func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
n.begin.Set(begin)
n.end.Set(end)
n.last.Sub(begin, big.NewInt(1))
allocatedIPs[key] = n
a.allocatedIPs[key] = n
return nil
}
@ -76,14 +81,15 @@ func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
// 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 RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
lock.Lock()
defer lock.Unlock()
func (a *IPAllocator) RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
a.mutex.Lock()
defer a.mutex.Unlock()
key := network.String()
allocated, ok := allocatedIPs[key]
allocated, ok := a.allocatedIPs[key]
if !ok {
allocated = newAllocatedMap(network)
allocatedIPs[key] = allocated
a.allocatedIPs[key] = allocated
}
if ip == nil {
@ -94,10 +100,11 @@ func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
// ReleaseIP adds the provided ip back into the pool of
// available ips to be returned for use.
func ReleaseIP(network *net.IPNet, ip net.IP) error {
lock.Lock()
defer lock.Unlock()
if allocated, exists := allocatedIPs[network.String()]; exists {
func (a *IPAllocator) ReleaseIP(network *net.IPNet, ip net.IP) error {
a.mutex.Lock()
defer a.mutex.Unlock()
if allocated, exists := a.allocatedIPs[network.String()]; exists {
delete(allocated.p, ip.String())
}
return nil

View file

@ -7,10 +7,6 @@ import (
"testing"
)
func reset() {
allocatedIPs = networkSet{}
}
func TestConversion(t *testing.T) {
ip := net.ParseIP("127.0.0.1")
i := ipToBigInt(ip)
@ -52,7 +48,8 @@ func TestConversionIPv6(t *testing.T) {
}
func TestRequestNewIps(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 0, 1},
Mask: []byte{255, 255, 255, 0},
@ -62,7 +59,7 @@ func TestRequestNewIps(t *testing.T) {
var err error
for i := 1; i < 10; i++ {
ip, err = RequestIP(network, nil)
ip, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -72,10 +69,10 @@ func TestRequestNewIps(t *testing.T) {
}
}
value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
if err := ReleaseIP(network, ip); err != nil {
if err := a.ReleaseIP(network, ip); err != nil {
t.Fatal(err)
}
ip, err = RequestIP(network, nil)
ip, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -85,7 +82,8 @@ func TestRequestNewIps(t *testing.T) {
}
func TestRequestNewIpV6(t *testing.T) {
defer reset()
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
@ -94,7 +92,7 @@ func TestRequestNewIpV6(t *testing.T) {
var ip net.IP
var err error
for i := 1; i < 10; i++ {
ip, err = RequestIP(network, nil)
ip, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -104,10 +102,10 @@ func TestRequestNewIpV6(t *testing.T) {
}
}
value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
if err := ReleaseIP(network, ip); err != nil {
if err := a.ReleaseIP(network, ip); err != nil {
t.Fatal(err)
}
ip, err = RequestIP(network, nil)
ip, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -117,68 +115,70 @@ func TestRequestNewIpV6(t *testing.T) {
}
func TestReleaseIp(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 0, 1},
Mask: []byte{255, 255, 255, 0},
}
ip, err := RequestIP(network, nil)
ip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
if err := ReleaseIP(network, ip); err != nil {
if err := a.ReleaseIP(network, ip); err != nil {
t.Fatal(err)
}
}
func TestReleaseIpV6(t *testing.T) {
defer reset()
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 := RequestIP(network, nil)
ip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
if err := ReleaseIP(network, ip); err != nil {
if err := a.ReleaseIP(network, ip); err != nil {
t.Fatal(err)
}
}
func TestGetReleasedIp(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 0, 1},
Mask: []byte{255, 255, 255, 0},
}
ip, err := RequestIP(network, nil)
ip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
value := ip.String()
if err := ReleaseIP(network, ip); err != nil {
if err := a.ReleaseIP(network, ip); err != nil {
t.Fatal(err)
}
for i := 0; i < 253; i++ {
_, err = RequestIP(network, nil)
_, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
err = ReleaseIP(network, ip)
err = a.ReleaseIP(network, ip)
if err != nil {
t.Fatal(err)
}
}
ip, err = RequestIP(network, nil)
ip, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -189,34 +189,35 @@ func TestGetReleasedIp(t *testing.T) {
}
func TestGetReleasedIpV6(t *testing.T) {
defer reset()
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 := RequestIP(network, nil)
ip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
value := ip.String()
if err := ReleaseIP(network, ip); err != nil {
if err := a.ReleaseIP(network, ip); err != nil {
t.Fatal(err)
}
for i := 0; i < 253; i++ {
_, err = RequestIP(network, nil)
_, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
err = ReleaseIP(network, ip)
err = a.ReleaseIP(network, ip)
if err != nil {
t.Fatal(err)
}
}
ip, err = RequestIP(network, nil)
ip, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -227,7 +228,8 @@ func TestGetReleasedIpV6(t *testing.T) {
}
func TestRequestSpecificIp(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 0, 1},
Mask: []byte{255, 255, 255, 224},
@ -236,23 +238,24 @@ func TestRequestSpecificIp(t *testing.T) {
ip := net.ParseIP("192.168.0.5")
// Request a "good" IP.
if _, err := RequestIP(network, ip); err != nil {
if _, err := a.RequestIP(network, ip); err != nil {
t.Fatal(err)
}
// Request the same IP again.
if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
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 := RequestIP(network, net.ParseIP("192.168.0.42")); err != ErrIPOutOfRange {
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) {
defer reset()
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
@ -261,22 +264,24 @@ func TestRequestSpecificIpV6(t *testing.T) {
ip := net.ParseIP("2a00:1450::5")
// Request a "good" IP.
if _, err := RequestIP(network, ip); err != nil {
if _, err := a.RequestIP(network, ip); err != nil {
t.Fatal(err)
}
// Request the same IP again.
if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
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 := RequestIP(network, net.ParseIP("2a00:1500::1")); err != ErrIPOutOfRange {
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),
@ -296,7 +301,7 @@ func TestIPAllocator(t *testing.T) {
// Check that we get 6 IPs, from 127.0.0.1127.0.0.6, in that
// order.
for i := 0; i < 6; i++ {
ip, err := RequestIP(network, nil)
ip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -332,25 +337,25 @@ func TestIPAllocator(t *testing.T) {
// ↑
// Check that there are no more IPs
ip, err := RequestIP(network, nil)
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 := ReleaseIP(network, expectedIPs[3]); err != nil {
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 := ReleaseIP(network, expectedIPs[2]); err != nil {
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 := ReleaseIP(network, expectedIPs[4]); err != nil {
if err := a.ReleaseIP(network, expectedIPs[4]); err != nil {
t.Fatal(err)
}
// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(u)
@ -360,7 +365,7 @@ func TestIPAllocator(t *testing.T) {
// with the first released IP
newIPs := make([]net.IP, 3)
for i := 0; i < 3; i++ {
ip, err := RequestIP(network, nil)
ip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -371,14 +376,15 @@ func TestIPAllocator(t *testing.T) {
assertIPEquals(t, expectedIPs[3], newIPs[1])
assertIPEquals(t, expectedIPs[4], newIPs[2])
_, err = RequestIP(network, nil)
_, 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) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 0, 0},
Mask: []byte{255, 255, 255, 0},
@ -387,7 +393,7 @@ func TestAllocateFirstIP(t *testing.T) {
firstIP := network.IP.To4().Mask(network.Mask)
first := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
ip, err := RequestIP(network, nil)
ip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -399,7 +405,8 @@ func TestAllocateFirstIP(t *testing.T) {
}
func TestAllocateAllIps(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 0, 1},
Mask: []byte{255, 255, 255, 0},
@ -412,7 +419,7 @@ func TestAllocateAllIps(t *testing.T) {
)
for err == nil {
current, err = RequestIP(network, nil)
current, err = a.RequestIP(network, nil)
if isFirst {
first = current
isFirst = false
@ -423,15 +430,15 @@ func TestAllocateAllIps(t *testing.T) {
t.Fatal(err)
}
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
if _, err := a.RequestIP(network, nil); err != ErrNoAvailableIPs {
t.Fatal(err)
}
if err := ReleaseIP(network, first); err != nil {
if err := a.ReleaseIP(network, first); err != nil {
t.Fatal(err)
}
again, err := RequestIP(network, nil)
again, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -439,17 +446,17 @@ func TestAllocateAllIps(t *testing.T) {
assertIPEquals(t, first, again)
// ensure that alloc.last == alloc.begin won't result in dead loop
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
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 := ReleaseIP(network, first); err != nil {
if err := a.ReleaseIP(network, first); err != nil {
t.Fatal(err)
}
ret, err := RequestIP(network, nil)
ret, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -458,9 +465,9 @@ func TestAllocateAllIps(t *testing.T) {
// #2. last of the range, note that current is the last one
last := net.IPv4(192, 168, 0, 254)
setLastTo(t, network, last)
setLastTo(t, a, network, last)
ret, err = RequestIP(network, nil)
ret, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -469,9 +476,9 @@ func TestAllocateAllIps(t *testing.T) {
// #3. middle of the range
mid := net.IPv4(192, 168, 0, 7)
setLastTo(t, network, mid)
setLastTo(t, a, network, mid)
ret, err = RequestIP(network, nil)
ret, err = a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -481,25 +488,25 @@ func TestAllocateAllIps(t *testing.T) {
// make sure the pool is full when calling setLastTo.
// we don't cheat here
func setLastTo(t *testing.T, network *net.IPNet, ip net.IP) {
if err := ReleaseIP(network, ip); err != nil {
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 := RequestIP(network, nil)
ret, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
assertIPEquals(t, ip, ret)
if err := ReleaseIP(network, ip); err != nil {
if err := a.ReleaseIP(network, ip); err != nil {
t.Fatal(err)
}
}
func TestAllocateDifferentSubnets(t *testing.T) {
defer reset()
a := New()
network1 := &net.IPNet{
IP: []byte{192, 168, 0, 1},
Mask: []byte{255, 255, 255, 0},
@ -528,39 +535,39 @@ func TestAllocateDifferentSubnets(t *testing.T) {
8: net.ParseIP("2a00:1632::2"),
}
ip11, err := RequestIP(network1, nil)
ip11, err := a.RequestIP(network1, nil)
if err != nil {
t.Fatal(err)
}
ip12, err := RequestIP(network1, nil)
ip12, err := a.RequestIP(network1, nil)
if err != nil {
t.Fatal(err)
}
ip21, err := RequestIP(network2, nil)
ip21, err := a.RequestIP(network2, nil)
if err != nil {
t.Fatal(err)
}
ip22, err := RequestIP(network2, nil)
ip22, err := a.RequestIP(network2, nil)
if err != nil {
t.Fatal(err)
}
ip31, err := RequestIP(network3, nil)
ip31, err := a.RequestIP(network3, nil)
if err != nil {
t.Fatal(err)
}
ip32, err := RequestIP(network3, nil)
ip32, err := a.RequestIP(network3, nil)
if err != nil {
t.Fatal(err)
}
ip33, err := RequestIP(network3, nil)
ip33, err := a.RequestIP(network3, nil)
if err != nil {
t.Fatal(err)
}
ip41, err := RequestIP(network4, nil)
ip41, err := a.RequestIP(network4, nil)
if err != nil {
t.Fatal(err)
}
ip42, err := RequestIP(network4, nil)
ip42, err := a.RequestIP(network4, nil)
if err != nil {
t.Fatal(err)
}
@ -576,7 +583,7 @@ func TestAllocateDifferentSubnets(t *testing.T) {
}
func TestRegisterBadTwice(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 1, 1},
Mask: []byte{255, 255, 255, 0},
@ -586,20 +593,20 @@ func TestRegisterBadTwice(t *testing.T) {
Mask: []byte{255, 255, 255, 248},
}
if err := RegisterSubnet(network, subnet); err != nil {
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 := RegisterSubnet(network, subnet); err != ErrNetworkAlreadyRegistered {
if err := a.RegisterSubnet(network, subnet); err != ErrNetworkAlreadyRegistered {
t.Fatalf("Expecteded ErrNetworkAlreadyRegistered error, got %v", err)
}
}
func TestRegisterBadRange(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 1, 1},
Mask: []byte{255, 255, 255, 0},
@ -608,13 +615,13 @@ func TestRegisterBadRange(t *testing.T) {
IP: []byte{192, 168, 1, 1},
Mask: []byte{255, 255, 0, 0},
}
if err := RegisterSubnet(network, subnet); err != ErrBadSubnet {
if err := a.RegisterSubnet(network, subnet); err != ErrBadSubnet {
t.Fatalf("Expected ErrBadSubnet error, got %v", err)
}
}
func TestAllocateFromRange(t *testing.T) {
defer reset()
a := New()
network := &net.IPNet{
IP: []byte{192, 168, 0, 1},
Mask: []byte{255, 255, 255, 0},
@ -625,7 +632,7 @@ func TestAllocateFromRange(t *testing.T) {
Mask: []byte{255, 255, 255, 248},
}
if err := RegisterSubnet(network, subnet); err != nil {
if err := a.RegisterSubnet(network, subnet); err != nil {
t.Fatal(err)
}
expectedIPs := []net.IP{
@ -637,19 +644,19 @@ func TestAllocateFromRange(t *testing.T) {
5: net.IPv4(192, 168, 0, 14),
}
for _, ip := range expectedIPs {
rip, err := RequestIP(network, nil)
rip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
assertIPEquals(t, ip, rip)
}
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
if _, err := a.RequestIP(network, nil); err != ErrNoAvailableIPs {
t.Fatalf("Expected ErrNoAvailableIPs error, got %v", err)
}
for _, ip := range expectedIPs {
ReleaseIP(network, ip)
rip, err := RequestIP(network, nil)
a.ReleaseIP(network, ip)
rip, err := a.RequestIP(network, nil)
if err != nil {
t.Fatal(err)
}
@ -669,13 +676,15 @@ func BenchmarkRequestIP(b *testing.B) {
Mask: []byte{255, 255, 255, 0},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
a := New()
for j := 0; j < 253; j++ {
_, err := RequestIP(network, nil)
_, err := a.RequestIP(network, nil)
if err != nil {
b.Fatal(err)
}
}
reset()
}
}