Browse code

Finish implementation and begin working on tests

Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/01/23 11:05:20
Showing 3 changed files
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"errors"
6 6
 	"github.com/dotcloud/docker/pkg/netlink"
7 7
 	"net"
8
-	"sort"
9 8
 	"sync"
10 9
 )
11 10
 
... ...
@@ -20,9 +19,11 @@ var (
20 20
 	ErrNetworkAlreadyAllocated = errors.New("requested network overlaps with existing network")
21 21
 	ErrNetworkAlreadyRegisterd = errors.New("requested network is already registered")
22 22
 	ErrNoAvailableIps          = errors.New("no available ips on network")
23
-	lock                       = sync.Mutex{}
24
-	allocatedIPs               = networkSet{}
25
-	availableIPS               = networkSet{}
23
+	ErrIPAlreadyAllocated      = errors.New("ip already allocated")
24
+
25
+	lock         = sync.Mutex{}
26
+	allocatedIPs = networkSet{}
27
+	availableIPS = networkSet{}
26 28
 )
27 29
 
28 30
 func RegisterNetwork(network *net.IPNet) error {
... ...
@@ -41,12 +42,15 @@ func RegisterNetwork(network *net.IPNet) error {
41 41
 	if err := checkExistingNetworkOverlaps(network); err != nil {
42 42
 		return err
43 43
 	}
44
-	allocatedIPs[newIPNet(network)] = iPSet{}
44
+	n := newIPNet(network)
45
+
46
+	allocatedIPs[n] = iPSet{}
47
+	availableIPS[n] = iPSet{}
45 48
 
46 49
 	return nil
47 50
 }
48 51
 
49
-func RequestIP(network *net.IPNet, ip *net.IPAddr) (*net.IPAddr, error) {
52
+func RequestIP(network *net.IPNet, ip *net.IP) (*net.IP, error) {
50 53
 	lock.Lock()
51 54
 	defer lock.Unlock()
52 55
 
... ...
@@ -58,71 +62,65 @@ func RequestIP(network *net.IPNet, ip *net.IPAddr) (*net.IPAddr, error) {
58 58
 		return next, nil
59 59
 	}
60 60
 
61
-	if err := validateIP(network, ip); err != nil {
61
+	if err := registerIP(network, ip); err != nil {
62 62
 		return nil, err
63 63
 	}
64 64
 	return ip, nil
65 65
 }
66 66
 
67
-func ReleaseIP(network *net.IPNet, ip *net.IPAddr) error {
67
+func ReleaseIP(network *net.IPNet, ip *net.IP) error {
68 68
 	lock.Lock()
69 69
 	defer lock.Unlock()
70 70
 
71 71
 	n := newIPNet(network)
72 72
 	existing := allocatedIPs[n]
73 73
 
74
-	delete(existing, ip.String())
75
-	availableIPS[n][ip.String()] = struct{}{}
74
+	i := ipToInt(ip)
75
+	existing.Remove(int(i))
76
+	available := availableIPS[n]
77
+	available.Push(int(i))
76 78
 
77 79
 	return nil
78 80
 }
79 81
 
80
-func getNextIp(network *net.IPNet) (net.IPAddr, error) {
81
-	if available, exists := availableIPS[network]; exists {
82
-		return nil, nil
83
-	}
84
-
82
+func getNextIp(network *net.IPNet) (*net.IP, error) {
85 83
 	var (
86
-		firstIP, _ = networkRange(network)
87
-		ipNum      = ipToInt(firstIP)
88
-		ownIP      = ipToInt(network.IP)
89
-		size       = networkSize(network.Mask)
90
-		n          = newIPNet(network)
91
-		allocated  = allocatedIPs[n]
92
-
93
-		pos    = int32(1)
94
-		max    = size - 2 // -1 for the broadcast address, -1 for the gateway address
95
-		ip     *net.IP
96
-		newNum int32
97
-		inUse  bool
84
+		n         = newIPNet(network)
85
+		available = availableIPS[n]
86
+		next      = available.Pop()
87
+		allocated = allocatedIPs[n]
88
+		ownIP     = int(ipToInt(&network.IP))
98 89
 	)
99 90
 
100
-	// Find first unused IP, give up after one whole round
101
-	for attempt := int32(0); attempt < max; attempt++ {
102
-		newNum = ipNum + pos
103
-		pos = pos%max + 1
104
-		// The network's IP is never okay to use
105
-		if newNum == ownIP {
91
+	if next != 0 {
92
+		ip := intToIP(int32(next))
93
+		allocated.Push(int(next))
94
+		return ip, nil
95
+	}
96
+	size := int(networkSize(network.Mask))
97
+	next = allocated.PullBack() + 1
98
+
99
+	// size -1 for the broadcast address, -1 for the gateway address
100
+	for i := 0; i < size-2; i++ {
101
+		if next == ownIP {
102
+			next++
106 103
 			continue
107 104
 		}
108 105
 
109
-		ip = intToIP(newNum)
110
-		if _, inUse = allocated[ip.String()]; !inUse {
111
-			// We found an unused IP
112
-			break
113
-		}
114
-	}
106
+		ip := intToIP(int32(next))
107
+		allocated.Push(next)
115 108
 
116
-	if ip == nil {
117
-		return nil, ErrNoAvailableIps
109
+		return ip, nil
118 110
 	}
119
-	allocated[ip.String()] = struct{}{}
120
-
121
-	return ip, nil
111
+	return nil, ErrNoAvailableIps
122 112
 }
123 113
 
124
-func validateIP(network *net.IPNet, ip *net.IPAddr) error {
125
-
114
+func registerIP(network *net.IPNet, ip *net.IP) error {
115
+	existing := allocatedIPs[newIPNet(network)]
116
+	if existing.Exists(int(ipToInt(ip))) {
117
+		return ErrIPAlreadyAllocated
118
+	}
119
+	return nil
126 120
 }
127 121
 
128 122
 func checkRouteOverlaps(networks []netlink.Route, toCheck *net.IPNet) error {
... ...
@@ -150,7 +148,9 @@ func checkExistingNetworkOverlaps(network *net.IPNet) error {
150 150
 		if newIPNet(network) == existing {
151 151
 			return ErrNetworkAlreadyRegisterd
152 152
 		}
153
-		if networkOverlaps(network, existing) {
153
+
154
+		ex := newNetIPNet(existing)
155
+		if networkOverlaps(network, ex) {
154 156
 			return ErrNetworkAlreadyAllocated
155 157
 		}
156 158
 	}
... ...
@@ -186,15 +186,16 @@ func newNetIPNet(network iPNet) *net.IPNet {
186 186
 }
187 187
 
188 188
 // Converts a 4 bytes IP into a 32 bit integer
189
-func ipToInt(ip net.IP) int32 {
189
+func ipToInt(ip *net.IP) int32 {
190 190
 	return int32(binary.BigEndian.Uint32(ip.To4()))
191 191
 }
192 192
 
193 193
 // Converts 32 bit integer into a 4 bytes IP address
194
-func intToIP(n int32) net.IP {
194
+func intToIP(n int32) *net.IP {
195 195
 	b := make([]byte, 4)
196 196
 	binary.BigEndian.PutUint32(b, uint32(n))
197
-	return net.IP(b)
197
+	ip := net.IP(b)
198
+	return &ip
198 199
 }
199 200
 
200 201
 // Given a netmask, calculates the number of available hosts
201 202
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+package ipallocator
1
+
2
+import (
3
+	"net"
4
+	"testing"
5
+)
6
+
7
+func TestRegisterNetwork(t *testing.T) {
8
+	network := &net.IPNet{
9
+		IP:   []byte{192, 168, 0, 1},
10
+		Mask: []byte{255, 255, 255, 0},
11
+	}
12
+
13
+	if err := RegisterNetwork(network); err != nil {
14
+		t.Fatal(err)
15
+	}
16
+
17
+	n := newIPNet(network)
18
+	if _, exists := allocatedIPs[n]; !exists {
19
+		t.Fatal("IPNet should exist in allocated IPs")
20
+	}
21
+
22
+	if _, exists := availableIPS[n]; !exists {
23
+		t.Fatal("IPNet should exist in available IPs")
24
+	}
25
+}
... ...
@@ -8,13 +8,13 @@ import (
8 8
 // iPSet is a thread-safe sorted set and a stack.
9 9
 type iPSet struct {
10 10
 	sync.RWMutex
11
-	set []int32
11
+	set []int
12 12
 }
13 13
 
14 14
 // Push takes a string and adds it to the set. If the elem aready exists, it has no effect.
15
-func (s *iPSet) Push(elem int32) {
15
+func (s *iPSet) Push(elem int) {
16 16
 	s.RLock()
17
-	for i, e := range s.set {
17
+	for _, e := range s.set {
18 18
 		if e == elem {
19 19
 			s.RUnlock()
20 20
 			return
... ...
@@ -30,13 +30,13 @@ func (s *iPSet) Push(elem int32) {
30 30
 }
31 31
 
32 32
 // Pop is an alias to PopFront()
33
-func (s *iPSet) Pop() int32 {
33
+func (s *iPSet) Pop() int {
34 34
 	return s.PopFront()
35 35
 }
36 36
 
37 37
 // Pop returns the first elemen from the list and removes it.
38 38
 // If the list is empty, it returns 0
39
-func (s *iPSet) PopFront() int32 {
39
+func (s *iPSet) PopFront() int {
40 40
 	s.RLock()
41 41
 
42 42
 	for i, e := range s.set {
... ...
@@ -45,24 +45,25 @@ func (s *iPSet) PopFront() int32 {
45 45
 		s.Lock()
46 46
 		s.set = append(s.set[:i], s.set[i+1:]...)
47 47
 		s.Unlock()
48
-		return e
48
+		return ret
49 49
 	}
50 50
 	s.RUnlock()
51
-	return ""
51
+
52
+	return 0
52 53
 }
53 54
 
54 55
 // PullBack retrieve the last element of the list.
55 56
 // The element is not removed.
56 57
 // If the list is empty, an empty element is returned.
57
-func (s *iPSet) PullBack() int32 {
58
+func (s *iPSet) PullBack() int {
58 59
 	if len(s.set) == 0 {
59
-		return ""
60
+		return 0
60 61
 	}
61 62
 	return s.set[len(s.set)-1]
62 63
 }
63 64
 
64 65
 // Exists checks if the given element present in the list.
65
-func (s *iPSet) Exists(elem int32) bool {
66
+func (s *iPSet) Exists(elem int) bool {
66 67
 	for _, e := range s.set {
67 68
 		if e == elem {
68 69
 			return true
... ...
@@ -73,7 +74,7 @@ func (s *iPSet) Exists(elem int32) bool {
73 73
 
74 74
 // Remove removes an element from the list.
75 75
 // If the element is not found, it has no effect.
76
-func (s *iPSet) Remove(elem int32) {
76
+func (s *iPSet) Remove(elem int) {
77 77
 	for i, e := range s.set {
78 78
 		if e == elem {
79 79
 			s.set = append(s.set[:i], s.set[i+1:]...)