Browse Source

Add locking to libnetwork ipam

Signed-off-by: Alessandro Boch <aboch@docker.com>
Alessandro Boch 10 years ago
parent
commit
a0e0d07250
1 changed files with 26 additions and 0 deletions
  1. 26 0
      libnetwork/ipam/allocator.go

+ 26 - 0
libnetwork/ipam/allocator.go

@@ -3,6 +3,7 @@ package ipam
 import (
 import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
+	"sync"
 
 
 	"github.com/docker/libnetwork/bitseq"
 	"github.com/docker/libnetwork/bitseq"
 )
 )
@@ -25,6 +26,7 @@ type Allocator struct {
 	subnetsInfo map[subnetKey]*subnetData
 	subnetsInfo map[subnetKey]*subnetData
 	// Allocated addresses in each address space's internal subnet
 	// Allocated addresses in each address space's internal subnet
 	addresses map[isKey]*bitmask
 	addresses map[isKey]*bitmask
+	sync.Mutex
 }
 }
 
 
 // NewAllocator returns an instance of libnetwork ipam
 // NewAllocator returns an instance of libnetwork ipam
@@ -99,7 +101,9 @@ func (a *Allocator) AddSubnet(addrSpace AddressSpace, subnetInfo *SubnetInfo) er
 	// Store the configured subnet information
 	// Store the configured subnet information
 	subnetKey := subnetKey{addrSpace, subnetInfo.Subnet.String()}
 	subnetKey := subnetKey{addrSpace, subnetInfo.Subnet.String()}
 	info := &subnetData{info: subnetInfo, intSubKeyes: make([]*isKey, len(subnetList))}
 	info := &subnetData{info: subnetInfo, intSubKeyes: make([]*isKey, len(subnetList))}
+	a.Lock()
 	a.subnetsInfo[subnetKey] = info
 	a.subnetsInfo[subnetKey] = info
+	a.Unlock()
 
 
 	// Create and insert the internal subnet(s) addresses masks into the address database
 	// Create and insert the internal subnet(s) addresses masks into the address database
 	for i, sub := range subnetList {
 	for i, sub := range subnetList {
@@ -111,11 +115,13 @@ func (a *Allocator) AddSubnet(addrSpace AddressSpace, subnetInfo *SubnetInfo) er
 		info.intSubKeyes[i] = smallKey
 		info.intSubKeyes[i] = smallKey
 
 
 		// Add the new address masks
 		// Add the new address masks
+		a.Lock()
 		a.addresses[*smallKey] = &bitmask{
 		a.addresses[*smallKey] = &bitmask{
 			subnet:        sub,
 			subnet:        sub,
 			addressMask:   bitseq.New(uint32(numAddresses)),
 			addressMask:   bitseq.New(uint32(numAddresses)),
 			freeAddresses: numAddresses,
 			freeAddresses: numAddresses,
 		}
 		}
+		a.Unlock()
 	}
 	}
 
 
 	return nil
 	return nil
@@ -143,6 +149,8 @@ func adjustAndCheckSubnetSize(subnet *net.IPNet) (*net.IPNet, error) {
 
 
 // Checks whether the passed subnet is a superset or subset of any of the subset in the db
 // Checks whether the passed subnet is a superset or subset of any of the subset in the db
 func (a *Allocator) contains(space AddressSpace, subInfo *SubnetInfo) bool {
 func (a *Allocator) contains(space AddressSpace, subInfo *SubnetInfo) bool {
+	a.Lock()
+	defer a.Unlock()
 	for k, v := range a.subnetsInfo {
 	for k, v := range a.subnetsInfo {
 		if space == k.addressSpace {
 		if space == k.addressSpace {
 			if subInfo.Subnet.Contains(v.info.Subnet.IP) ||
 			if subInfo.Subnet.Contains(v.info.Subnet.IP) ||
@@ -200,16 +208,22 @@ func (a *Allocator) RemoveSubnet(addrSpace AddressSpace, subnet *net.IPNet) erro
 	// Look for the respective subnet configuration data
 	// Look for the respective subnet configuration data
 	// Remove it along with the internal subnets
 	// Remove it along with the internal subnets
 	subKey := subnetKey{addrSpace, subnet.String()}
 	subKey := subnetKey{addrSpace, subnet.String()}
+	a.Lock()
 	subData, ok := a.subnetsInfo[subKey]
 	subData, ok := a.subnetsInfo[subKey]
+	a.Unlock()
 	if !ok {
 	if !ok {
 		return ErrSubnetNotFound
 		return ErrSubnetNotFound
 	}
 	}
 
 
 	for _, key := range subData.intSubKeyes {
 	for _, key := range subData.intSubKeyes {
+		a.Lock()
 		delete(a.addresses, *key)
 		delete(a.addresses, *key)
+		a.Unlock()
 	}
 	}
 
 
+	a.Lock()
 	delete(a.subnetsInfo, subKey)
 	delete(a.subnetsInfo, subKey)
+	a.Unlock()
 
 
 	return nil
 	return nil
 
 
@@ -259,7 +273,9 @@ func (a *Allocator) request(addrSpace AddressSpace, req *AddressRequest, version
 	if err == nil {
 	if err == nil {
 		// Populate response
 		// Populate response
 		response.Address = ip
 		response.Address = ip
+		a.Lock()
 		response.Subnet = *a.subnetsInfo[subnetKey{addrSpace, req.Subnet.String()}].info
 		response.Subnet = *a.subnetsInfo[subnetKey{addrSpace, req.Subnet.String()}].info
+		a.Unlock()
 	}
 	}
 
 
 	return response, err
 	return response, err
@@ -293,16 +309,22 @@ func (a *Allocator) reserveAddress(addrSpace AddressSpace, subnet *net.IPNet, pr
 
 
 	// Get the list of pointers to the internal subnets
 	// Get the list of pointers to the internal subnets
 	if subnet != nil {
 	if subnet != nil {
+		a.Lock()
 		keyList = a.subnetsInfo[subnetKey{addrSpace, subnet.String()}].intSubKeyes
 		keyList = a.subnetsInfo[subnetKey{addrSpace, subnet.String()}].intSubKeyes
+		a.Unlock()
 	} else {
 	} else {
+		a.Lock()
 		keyList = a.getSubnetList(addrSpace, ver)
 		keyList = a.getSubnetList(addrSpace, ver)
+		a.Unlock()
 	}
 	}
 	if len(keyList) == 0 {
 	if len(keyList) == 0 {
 		return nil, nil, ErrNoAvailableSubnet
 		return nil, nil, ErrNoAvailableSubnet
 	}
 	}
 
 
 	for _, key := range keyList {
 	for _, key := range keyList {
+		a.Lock()
 		smallSubnet := a.addresses[*key]
 		smallSubnet := a.addresses[*key]
+		a.Unlock()
 		address, err := a.getAddress(smallSubnet, prefAddress, ver)
 		address, err := a.getAddress(smallSubnet, prefAddress, ver)
 		if err == nil {
 		if err == nil {
 			return address, subnet, nil
 			return address, subnet, nil
@@ -316,6 +338,7 @@ func (a *Allocator) reserveAddress(addrSpace AddressSpace, subnet *net.IPNet, pr
 func (a *Allocator) getSubnetList(addrSpace AddressSpace, ver ipVersion) []*isKey {
 func (a *Allocator) getSubnetList(addrSpace AddressSpace, ver ipVersion) []*isKey {
 	var list [1024]*isKey
 	var list [1024]*isKey
 	ind := 0
 	ind := 0
+	a.Lock()
 	for subKey := range a.addresses {
 	for subKey := range a.addresses {
 		_, s, _ := net.ParseCIDR(subKey.subnet)
 		_, s, _ := net.ParseCIDR(subKey.subnet)
 		subVer := getAddressVersion(s.IP)
 		subVer := getAddressVersion(s.IP)
@@ -324,6 +347,7 @@ func (a *Allocator) getSubnetList(addrSpace AddressSpace, ver ipVersion) []*isKe
 			ind++
 			ind++
 		}
 		}
 	}
 	}
+	a.Unlock()
 	return list[0:ind]
 	return list[0:ind]
 }
 }
 
 
@@ -364,6 +388,8 @@ again:
 
 
 // DumpDatabase dumps the internal info
 // DumpDatabase dumps the internal info
 func (a *Allocator) DumpDatabase() {
 func (a *Allocator) DumpDatabase() {
+	a.Lock()
+	defer a.Unlock()
 	for _, config := range a.subnetsInfo {
 	for _, config := range a.subnetsInfo {
 		fmt.Printf("\n\n%s:", config.info.Subnet.String())
 		fmt.Printf("\n\n%s:", config.info.Subnet.String())
 		for _, internKey := range config.intSubKeyes {
 		for _, internKey := range config.intSubKeyes {