Browse code

Implement get next ip

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

Michael Crosby authored on 2014/01/23 09:13:22
Showing 1 changed files
... ...
@@ -19,6 +19,7 @@ type iPNet struct {
19 19
 var (
20 20
 	ErrNetworkAlreadyAllocated = errors.New("requested network overlaps with existing network")
21 21
 	ErrNetworkAlreadyRegisterd = errors.New("requested network is already registered")
22
+	ErrNoAvailableIps          = errors.New("no available ips on network")
22 23
 	lock                       = sync.Mutex{}
23 24
 	allocatedIPs               = networkSet{}
24 25
 	availableIPS               = networkSet{}
... ...
@@ -40,109 +41,87 @@ func RegisterNetwork(network *net.IPNet) error {
40 40
 	if err := checkExistingNetworkOverlaps(network); err != nil {
41 41
 		return err
42 42
 	}
43
-
44 43
 	allocatedIPs[newIPNet(network)] = iPSet{}
45 44
 
46 45
 	return nil
47 46
 }
48 47
 
49
-func RequestIP(ip *net.IPAddr) (*net.IPAddr, error) {
48
+func RequestIP(network *net.IPNet, ip *net.IPAddr) (*net.IPAddr, error) {
50 49
 	lock.Lock()
51 50
 	defer lock.Unlock()
52 51
 
53 52
 	if ip == nil {
54
-		next, err := getNextIp()
53
+		next, err := getNextIp(network)
55 54
 		if err != nil {
56 55
 			return nil, err
57 56
 		}
58 57
 		return next, nil
59 58
 	}
60 59
 
61
-	if err := validateIP(ip); err != nil {
60
+	if err := validateIP(network, ip); err != nil {
62 61
 		return nil, err
63 62
 	}
64 63
 	return ip, nil
65 64
 }
66 65
 
67
-func ReleaseIP(ip *net.IPAddr) error {
66
+func ReleaseIP(network *net.IPNet, ip *net.IPAddr) error {
68 67
 	lock.Lock()
69 68
 	defer lock.Unlock()
70 69
 
70
+	n := newIPNet(network)
71
+	existing := allocatedIPs[n]
72
+
73
+	delete(existing, ip.String())
74
+	availableIPS[n][ip.String()] = struct{}{}
75
+
76
+	return nil
71 77
 }
72 78
 
73
-func getNextIp(network iPNet) (net.IPAddr, error) {
79
+func getNextIp(network *net.IPNet) (net.IPAddr, error) {
74 80
 	if available, exists := availableIPS[network]; exists {
81
+		return nil, nil
75 82
 	}
76 83
 
77 84
 	var (
78
-		netNetwork = newNetIPNet(network)
79
-		firstIP, _ = networkRange(netNetwork)
85
+		firstIP, _ = networkRange(network)
80 86
 		ipNum      = ipToInt(firstIP)
81
-		ownIP      = ipToInt(netNetwork.IP)
82
-		size       = networkSize(netNetwork.Mask)
83
-
84
-		pos = int32(1)
85
-		max = size - 2 // -1 for the broadcast address, -1 for the gateway address
87
+		ownIP      = ipToInt(network.IP)
88
+		size       = networkSize(network.Mask)
89
+		n          = newIPNet(network)
90
+		allocated  = allocatedIPs[n]
91
+
92
+		pos    = int32(1)
93
+		max    = size - 2 // -1 for the broadcast address, -1 for the gateway address
94
+		ip     *net.IP
95
+		newNum int32
96
+		inUse  bool
86 97
 	)
87 98
 
88
-	for {
89
-		var (
90
-			newNum int32
91
-			inUse  bool
92
-		)
93
-
94
-		// Find first unused IP, give up after one whole round
95
-		for attempt := int32(0); attempt < max; attempt++ {
96
-			newNum = ipNum + pos
97
-
98
-			pos = pos%max + 1
99
-
100
-			// The network's IP is never okay to use
101
-			if newNum == ownIP {
102
-				continue
103
-			}
104
-
105
-			if _, inUse = alloc.inUse[newNum]; !inUse {
106
-				// We found an unused IP
107
-				break
108
-			}
99
+	// Find first unused IP, give up after one whole round
100
+	for attempt := int32(0); attempt < max; attempt++ {
101
+		newNum = ipNum + pos
102
+		pos = pos%max + 1
103
+		// The network's IP is never okay to use
104
+		if newNum == ownIP {
105
+			continue
109 106
 		}
110 107
 
111
-		ip := allocatedIP{ip: intToIP(newNum)}
112
-		if inUse {
113
-			ip.err = errors.New("No unallocated IP available")
108
+		ip = intToIP(newNum)
109
+		if _, inUse = allocated[ip.String()]; !inUse {
110
+			// We found an unused IP
111
+			break
114 112
 		}
113
+	}
115 114
 
116
-		select {
117
-		case quit := <-alloc.quit:
118
-			if quit {
119
-				return
120
-			}
121
-		case alloc.queueAlloc <- ip:
122
-			alloc.inUse[newNum] = struct{}{}
123
-		case released := <-alloc.queueReleased:
124
-			r := ipToInt(released)
125
-			delete(alloc.inUse, r)
126
-
127
-			if inUse {
128
-				// If we couldn't allocate a new IP, the released one
129
-				// will be the only free one now, so instantly use it
130
-				// next time
131
-				pos = r - ipNum
132
-			} else {
133
-				// Use same IP as last time
134
-				if pos == 1 {
135
-					pos = max
136
-				} else {
137
-					pos--
138
-				}
139
-			}
140
-		}
115
+	if ip == nil {
116
+		return nil, ErrNoAvailableIps
141 117
 	}
118
+	allocated[ip.String()] = struct{}{}
142 119
 
120
+	return ip, nil
143 121
 }
144 122
 
145
-func validateIP(ip *net.IPAddr) error {
123
+func validateIP(network *net.IPNet, ip *net.IPAddr) error {
146 124
 
147 125
 }
148 126