Add locking to libnetwork ipam

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2015-06-12 15:36:28 -07:00
parent 75443aaf72
commit a0e0d07250
1 changed files with 26 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package ipam
import (
"fmt"
"net"
"sync"
"github.com/docker/libnetwork/bitseq"
)
@ -25,6 +26,7 @@ type Allocator struct {
subnetsInfo map[subnetKey]*subnetData
// Allocated addresses in each address space's internal subnet
addresses map[isKey]*bitmask
sync.Mutex
}
// 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
subnetKey := subnetKey{addrSpace, subnetInfo.Subnet.String()}
info := &subnetData{info: subnetInfo, intSubKeyes: make([]*isKey, len(subnetList))}
a.Lock()
a.subnetsInfo[subnetKey] = info
a.Unlock()
// Create and insert the internal subnet(s) addresses masks into the address database
for i, sub := range subnetList {
@ -111,11 +115,13 @@ func (a *Allocator) AddSubnet(addrSpace AddressSpace, subnetInfo *SubnetInfo) er
info.intSubKeyes[i] = smallKey
// Add the new address masks
a.Lock()
a.addresses[*smallKey] = &bitmask{
subnet: sub,
addressMask: bitseq.New(uint32(numAddresses)),
freeAddresses: numAddresses,
}
a.Unlock()
}
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
func (a *Allocator) contains(space AddressSpace, subInfo *SubnetInfo) bool {
a.Lock()
defer a.Unlock()
for k, v := range a.subnetsInfo {
if space == k.addressSpace {
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
// Remove it along with the internal subnets
subKey := subnetKey{addrSpace, subnet.String()}
a.Lock()
subData, ok := a.subnetsInfo[subKey]
a.Unlock()
if !ok {
return ErrSubnetNotFound
}
for _, key := range subData.intSubKeyes {
a.Lock()
delete(a.addresses, *key)
a.Unlock()
}
a.Lock()
delete(a.subnetsInfo, subKey)
a.Unlock()
return nil
@ -259,7 +273,9 @@ func (a *Allocator) request(addrSpace AddressSpace, req *AddressRequest, version
if err == nil {
// Populate response
response.Address = ip
a.Lock()
response.Subnet = *a.subnetsInfo[subnetKey{addrSpace, req.Subnet.String()}].info
a.Unlock()
}
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
if subnet != nil {
a.Lock()
keyList = a.subnetsInfo[subnetKey{addrSpace, subnet.String()}].intSubKeyes
a.Unlock()
} else {
a.Lock()
keyList = a.getSubnetList(addrSpace, ver)
a.Unlock()
}
if len(keyList) == 0 {
return nil, nil, ErrNoAvailableSubnet
}
for _, key := range keyList {
a.Lock()
smallSubnet := a.addresses[*key]
a.Unlock()
address, err := a.getAddress(smallSubnet, prefAddress, ver)
if err == 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 {
var list [1024]*isKey
ind := 0
a.Lock()
for subKey := range a.addresses {
_, s, _ := net.ParseCIDR(subKey.subnet)
subVer := getAddressVersion(s.IP)
@ -324,6 +347,7 @@ func (a *Allocator) getSubnetList(addrSpace AddressSpace, ver ipVersion) []*isKe
ind++
}
}
a.Unlock()
return list[0:ind]
}
@ -364,6 +388,8 @@ again:
// DumpDatabase dumps the internal info
func (a *Allocator) DumpDatabase() {
a.Lock()
defer a.Unlock()
for _, config := range a.subnetsInfo {
fmt.Printf("\n\n%s:", config.info.Subnet.String())
for _, internKey := range config.intSubKeyes {