瀏覽代碼

Implement get next ip

Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
Michael Crosby 11 年之前
父節點
當前提交
d32777f6b1
共有 1 個文件被更改,包括 42 次插入63 次删除
  1. 42 63
      networkdriver/portallocator/allocator.go

+ 42 - 63
networkdriver/portallocator/allocator.go

@@ -19,6 +19,7 @@ type iPNet struct {
 var (
 	ErrNetworkAlreadyAllocated = errors.New("requested network overlaps with existing network")
 	ErrNetworkAlreadyRegisterd = errors.New("requested network is already registered")
+	ErrNoAvailableIps          = errors.New("no available ips on network")
 	lock                       = sync.Mutex{}
 	allocatedIPs               = networkSet{}
 	availableIPS               = networkSet{}
@@ -40,109 +41,87 @@ func RegisterNetwork(network *net.IPNet) error {
 	if err := checkExistingNetworkOverlaps(network); err != nil {
 		return err
 	}
-
 	allocatedIPs[newIPNet(network)] = iPSet{}
 
 	return nil
 }
 
-func RequestIP(ip *net.IPAddr) (*net.IPAddr, error) {
+func RequestIP(network *net.IPNet, ip *net.IPAddr) (*net.IPAddr, error) {
 	lock.Lock()
 	defer lock.Unlock()
 
 	if ip == nil {
-		next, err := getNextIp()
+		next, err := getNextIp(network)
 		if err != nil {
 			return nil, err
 		}
 		return next, nil
 	}
 
-	if err := validateIP(ip); err != nil {
+	if err := validateIP(network, ip); err != nil {
 		return nil, err
 	}
 	return ip, nil
 }
 
-func ReleaseIP(ip *net.IPAddr) error {
+func ReleaseIP(network *net.IPNet, ip *net.IPAddr) error {
 	lock.Lock()
 	defer lock.Unlock()
 
+	n := newIPNet(network)
+	existing := allocatedIPs[n]
+
+	delete(existing, ip.String())
+	availableIPS[n][ip.String()] = struct{}{}
+
+	return nil
 }
 
-func getNextIp(network iPNet) (net.IPAddr, error) {
+func getNextIp(network *net.IPNet) (net.IPAddr, error) {
 	if available, exists := availableIPS[network]; exists {
+		return nil, nil
 	}
 
 	var (
-		netNetwork = newNetIPNet(network)
-		firstIP, _ = networkRange(netNetwork)
+		firstIP, _ = networkRange(network)
 		ipNum      = ipToInt(firstIP)
-		ownIP      = ipToInt(netNetwork.IP)
-		size       = networkSize(netNetwork.Mask)
-
-		pos = int32(1)
-		max = size - 2 // -1 for the broadcast address, -1 for the gateway address
+		ownIP      = ipToInt(network.IP)
+		size       = networkSize(network.Mask)
+		n          = newIPNet(network)
+		allocated  = allocatedIPs[n]
+
+		pos    = int32(1)
+		max    = size - 2 // -1 for the broadcast address, -1 for the gateway address
+		ip     *net.IP
+		newNum int32
+		inUse  bool
 	)
 
-	for {
-		var (
-			newNum int32
-			inUse  bool
-		)
-
-		// Find first unused IP, give up after one whole round
-		for attempt := int32(0); attempt < max; attempt++ {
-			newNum = ipNum + pos
-
-			pos = pos%max + 1
-
-			// The network's IP is never okay to use
-			if newNum == ownIP {
-				continue
-			}
-
-			if _, inUse = alloc.inUse[newNum]; !inUse {
-				// We found an unused IP
-				break
-			}
+	// Find first unused IP, give up after one whole round
+	for attempt := int32(0); attempt < max; attempt++ {
+		newNum = ipNum + pos
+		pos = pos%max + 1
+		// The network's IP is never okay to use
+		if newNum == ownIP {
+			continue
 		}
 
-		ip := allocatedIP{ip: intToIP(newNum)}
-		if inUse {
-			ip.err = errors.New("No unallocated IP available")
+		ip = intToIP(newNum)
+		if _, inUse = allocated[ip.String()]; !inUse {
+			// We found an unused IP
+			break
 		}
+	}
 
-		select {
-		case quit := <-alloc.quit:
-			if quit {
-				return
-			}
-		case alloc.queueAlloc <- ip:
-			alloc.inUse[newNum] = struct{}{}
-		case released := <-alloc.queueReleased:
-			r := ipToInt(released)
-			delete(alloc.inUse, r)
-
-			if inUse {
-				// If we couldn't allocate a new IP, the released one
-				// will be the only free one now, so instantly use it
-				// next time
-				pos = r - ipNum
-			} else {
-				// Use same IP as last time
-				if pos == 1 {
-					pos = max
-				} else {
-					pos--
-				}
-			}
-		}
+	if ip == nil {
+		return nil, ErrNoAvailableIps
 	}
+	allocated[ip.String()] = struct{}{}
 
+	return ip, nil
 }
 
-func validateIP(ip *net.IPAddr) error {
+func validateIP(network *net.IPNet, ip *net.IPAddr) error {
 
 }