diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 600ff743fe..bbf2cd2fd6 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -16,7 +16,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/driverapi" - "github.com/docker/libnetwork/ipallocator" "github.com/docker/libnetwork/iptables" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netutils" @@ -42,10 +41,6 @@ const ( DefaultGatewayV6AuxKey = "DefaultGatewayIPv6" ) -var ( - ipAllocator *ipallocator.IPAllocator -) - // configuration info for the "bridge" driver. type configuration struct { EnableIPForwarding bool @@ -118,7 +113,6 @@ type driver struct { // New constructs a new bridge driver func newDriver() *driver { - ipAllocator = ipallocator.New() 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 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 // already been deleted by sandbox delete. Make sure defer // does not see this error either. diff --git a/libnetwork/ipallocator/allocator.go b/libnetwork/ipallocator/allocator.go deleted file mode 100644 index 06bc051c55..0000000000 --- a/libnetwork/ipallocator/allocator.go +++ /dev/null @@ -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()) -} diff --git a/libnetwork/ipallocator/allocator_test.go b/libnetwork/ipallocator/allocator_test.go deleted file mode 100644 index 26a551fdcd..0000000000 --- a/libnetwork/ipallocator/allocator_test.go +++ /dev/null @@ -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) - } - } - } -}