mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Reorganize libnetwork ipam datastructures
- In order to facilitate usage of datastore - This makes it slower. Efficiency will be revisited later after datastore integration is done. Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
a0e0d07250
commit
3ff75bd42d
2 changed files with 55 additions and 52 deletions
|
@ -23,17 +23,17 @@ type Allocator struct {
|
||||||
// The internal subnets host size
|
// The internal subnets host size
|
||||||
internalHostSize int
|
internalHostSize int
|
||||||
// Static subnet information
|
// Static subnet information
|
||||||
subnetsInfo map[subnetKey]*subnetData
|
subnetsInfo map[subnetKey]*SubnetInfo
|
||||||
// Allocated addresses in each address space's internal subnet
|
// Allocated addresses in each address space's internal subnet
|
||||||
addresses map[isKey]*bitmask
|
addresses map[subnetKey]*bitmask
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAllocator returns an instance of libnetwork ipam
|
// NewAllocator returns an instance of libnetwork ipam
|
||||||
func NewAllocator() *Allocator {
|
func NewAllocator() *Allocator {
|
||||||
a := &Allocator{}
|
a := &Allocator{}
|
||||||
a.subnetsInfo = make(map[subnetKey]*subnetData)
|
a.subnetsInfo = make(map[subnetKey]*SubnetInfo)
|
||||||
a.addresses = make(map[isKey]*bitmask)
|
a.addresses = make(map[subnetKey]*bitmask)
|
||||||
a.internalHostSize = defaultInternalHostSize
|
a.internalHostSize = defaultInternalHostSize
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
@ -44,14 +44,8 @@ type subnetKey struct {
|
||||||
subnet string
|
subnet string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointer to the internal subnets in each address space
|
func (s *subnetKey) String() string {
|
||||||
type isKey subnetKey
|
return fmt.Sprintf("%s/%s", s.addressSpace, s.subnet)
|
||||||
|
|
||||||
// The structs contains the configured subnet information
|
|
||||||
// along with the pointers to the respective internal subnets
|
|
||||||
type subnetData struct {
|
|
||||||
info *SubnetInfo // Configured subnet
|
|
||||||
intSubKeyes []*isKey // Pointers to child internal subnets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The structs containing the address allocation bitmask for the internal subnet.
|
// The structs containing the address allocation bitmask for the internal subnet.
|
||||||
|
@ -86,37 +80,27 @@ func (a *Allocator) AddSubnet(addrSpace AddressSpace, subnetInfo *SubnetInfo) er
|
||||||
return ErrOverlapSubnet
|
return ErrOverlapSubnet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check and size adjustment for v6
|
|
||||||
subnetToSplit, err := adjustAndCheckSubnetSize(subnetInfo.Subnet)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to smaller internal subnets (if needed)
|
// Convert to smaller internal subnets (if needed)
|
||||||
subnetList, err := getInternalSubnets(subnetToSplit, a.internalHostSize)
|
subnetList, err := getInternalSubnets(subnetInfo.Subnet, a.internalHostSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the configured subnet information
|
// Store the configured subnet information
|
||||||
subnetKey := subnetKey{addrSpace, subnetInfo.Subnet.String()}
|
key := subnetKey{addrSpace, subnetInfo.Subnet.String()}
|
||||||
info := &subnetData{info: subnetInfo, intSubKeyes: make([]*isKey, len(subnetList))}
|
|
||||||
a.Lock()
|
a.Lock()
|
||||||
a.subnetsInfo[subnetKey] = info
|
a.subnetsInfo[key] = subnetInfo
|
||||||
a.Unlock()
|
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 _, sub := range subnetList {
|
||||||
ones, bits := sub.Mask.Size()
|
ones, bits := sub.Mask.Size()
|
||||||
numAddresses := 1 << uint(bits-ones)
|
numAddresses := 1 << uint(bits-ones)
|
||||||
|
smallKey := subnetKey{addrSpace, sub.String()}
|
||||||
// Create and store internal subnet key into parent subnet handle
|
|
||||||
smallKey := &isKey{addrSpace, sub.String()}
|
|
||||||
info.intSubKeyes[i] = smallKey
|
|
||||||
|
|
||||||
// Add the new address masks
|
// Add the new address masks
|
||||||
a.Lock()
|
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,
|
||||||
|
@ -153,8 +137,8 @@ func (a *Allocator) contains(space AddressSpace, subInfo *SubnetInfo) bool {
|
||||||
defer a.Unlock()
|
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.Subnet.IP) ||
|
||||||
v.info.Subnet.Contains(subInfo.Subnet.IP) {
|
v.Subnet.Contains(subInfo.Subnet.IP) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,9 +149,15 @@ func (a *Allocator) contains(space AddressSpace, subInfo *SubnetInfo) bool {
|
||||||
// Splits the passed subnet into N internal subnets with host size equal to internalHostSize.
|
// Splits the passed subnet into N internal subnets with host size equal to internalHostSize.
|
||||||
// If the subnet's host size is equal to or smaller than internalHostSize, there won't be any
|
// If the subnet's host size is equal to or smaller than internalHostSize, there won't be any
|
||||||
// split and the return list will contain only the passed subnet.
|
// split and the return list will contain only the passed subnet.
|
||||||
func getInternalSubnets(subnet *net.IPNet, internalHostSize int) ([]*net.IPNet, error) {
|
func getInternalSubnets(inSubnet *net.IPNet, internalHostSize int) ([]*net.IPNet, error) {
|
||||||
var subnetList []*net.IPNet
|
var subnetList []*net.IPNet
|
||||||
|
|
||||||
|
// Sanity check and size adjustment for v6
|
||||||
|
subnet, err := adjustAndCheckSubnetSize(inSubnet)
|
||||||
|
if err != nil {
|
||||||
|
return subnetList, err
|
||||||
|
}
|
||||||
|
|
||||||
// Get network/host subnet information
|
// Get network/host subnet information
|
||||||
netBits, bits := subnet.Mask.Size()
|
netBits, bits := subnet.Mask.Size()
|
||||||
hostBits := bits - netBits
|
hostBits := bits - netBits
|
||||||
|
@ -209,15 +199,21 @@ func (a *Allocator) RemoveSubnet(addrSpace AddressSpace, subnet *net.IPNet) erro
|
||||||
// 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()
|
a.Lock()
|
||||||
subData, ok := a.subnetsInfo[subKey]
|
_, ok := a.subnetsInfo[subKey]
|
||||||
a.Unlock()
|
a.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrSubnetNotFound
|
return ErrSubnetNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, key := range subData.intSubKeyes {
|
// Get the list of smaller internal subnets
|
||||||
|
subnetList, err := getInternalSubnets(subnet, a.internalHostSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range subnetList {
|
||||||
a.Lock()
|
a.Lock()
|
||||||
delete(a.addresses, *key)
|
delete(a.addresses, subnetKey{addrSpace, s.String()})
|
||||||
a.Unlock()
|
a.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +270,7 @@ func (a *Allocator) request(addrSpace AddressSpace, req *AddressRequest, version
|
||||||
// Populate response
|
// Populate response
|
||||||
response.Address = ip
|
response.Address = ip
|
||||||
a.Lock()
|
a.Lock()
|
||||||
response.Subnet = *a.subnetsInfo[subnetKey{addrSpace, req.Subnet.String()}].info
|
response.Subnet = *a.subnetsInfo[subnetKey{addrSpace, req.Subnet.String()}]
|
||||||
a.Unlock()
|
a.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,10 +287,10 @@ func (a *Allocator) Release(addrSpace AddressSpace, address net.IP) {
|
||||||
address = address.To4()
|
address = address.To4()
|
||||||
}
|
}
|
||||||
for _, subKey := range a.getSubnetList(addrSpace, ver) {
|
for _, subKey := range a.getSubnetList(addrSpace, ver) {
|
||||||
sub := a.addresses[*subKey].subnet
|
sub := a.addresses[subKey].subnet
|
||||||
if sub.Contains(address) {
|
if sub.Contains(address) {
|
||||||
// Retrieve correspondent ordinal in the subnet
|
// Retrieve correspondent ordinal in the subnet
|
||||||
space := a.addresses[isKey{addrSpace, sub.String()}]
|
space := a.addresses[subnetKey{addrSpace, sub.String()}]
|
||||||
ordinal := ipToInt(getHostPortionIP(address, space.subnet))
|
ordinal := ipToInt(getHostPortionIP(address, space.subnet))
|
||||||
// Release it
|
// Release it
|
||||||
space.addressMask = bitseq.PushReservation(ordinal/8, ordinal%8, space.addressMask, true)
|
space.addressMask = bitseq.PushReservation(ordinal/8, ordinal%8, space.addressMask, true)
|
||||||
|
@ -305,13 +301,18 @@ func (a *Allocator) Release(addrSpace AddressSpace, address net.IP) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Allocator) reserveAddress(addrSpace AddressSpace, subnet *net.IPNet, prefAddress net.IP, ver ipVersion) (net.IP, *net.IPNet, error) {
|
func (a *Allocator) reserveAddress(addrSpace AddressSpace, subnet *net.IPNet, prefAddress net.IP, ver ipVersion) (net.IP, *net.IPNet, error) {
|
||||||
var keyList []*isKey
|
var keyList []subnetKey
|
||||||
|
|
||||||
// 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()
|
// Get the list of smaller internal subnets
|
||||||
keyList = a.subnetsInfo[subnetKey{addrSpace, subnet.String()}].intSubKeyes
|
subnetList, err := getInternalSubnets(subnet, a.internalHostSize)
|
||||||
a.Unlock()
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
for _, s := range subnetList {
|
||||||
|
keyList = append(keyList, subnetKey{addrSpace, s.String()})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
a.Lock()
|
a.Lock()
|
||||||
keyList = a.getSubnetList(addrSpace, ver)
|
keyList = a.getSubnetList(addrSpace, ver)
|
||||||
|
@ -323,7 +324,7 @@ func (a *Allocator) reserveAddress(addrSpace AddressSpace, subnet *net.IPNet, pr
|
||||||
|
|
||||||
for _, key := range keyList {
|
for _, key := range keyList {
|
||||||
a.Lock()
|
a.Lock()
|
||||||
smallSubnet := a.addresses[*key]
|
smallSubnet := a.addresses[key]
|
||||||
a.Unlock()
|
a.Unlock()
|
||||||
address, err := a.getAddress(smallSubnet, prefAddress, ver)
|
address, err := a.getAddress(smallSubnet, prefAddress, ver)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -335,15 +336,15 @@ func (a *Allocator) reserveAddress(addrSpace AddressSpace, subnet *net.IPNet, pr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the list of available internal subnets for the specified address space and the desired ip version
|
// Get the list of available internal subnets for the specified address space and the desired ip version
|
||||||
func (a *Allocator) getSubnetList(addrSpace AddressSpace, ver ipVersion) []*isKey {
|
func (a *Allocator) getSubnetList(addrSpace AddressSpace, ver ipVersion) []subnetKey {
|
||||||
var list [1024]*isKey
|
var list [1024]subnetKey
|
||||||
ind := 0
|
ind := 0
|
||||||
a.Lock()
|
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)
|
||||||
if subKey.addressSpace == addrSpace && subVer == ver {
|
if subKey.addressSpace == addrSpace && subVer == ver {
|
||||||
list[ind] = &subKey
|
list[ind] = subKey
|
||||||
ind++
|
ind++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,10 +391,12 @@ again:
|
||||||
func (a *Allocator) DumpDatabase() {
|
func (a *Allocator) DumpDatabase() {
|
||||||
a.Lock()
|
a.Lock()
|
||||||
defer a.Unlock()
|
defer a.Unlock()
|
||||||
for _, config := range a.subnetsInfo {
|
for k, config := range a.subnetsInfo {
|
||||||
fmt.Printf("\n\n%s:", config.info.Subnet.String())
|
fmt.Printf("\n\n%s:", config.Subnet.String())
|
||||||
for _, internKey := range config.intSubKeyes {
|
subnetList, _ := getInternalSubnets(config.Subnet, a.internalHostSize)
|
||||||
bm := a.addresses[*internKey]
|
for _, s := range subnetList {
|
||||||
|
internKey := subnetKey{k.addressSpace, s.String()}
|
||||||
|
bm := a.addresses[internKey]
|
||||||
fmt.Printf("\n\t%s: %s\n\t%d", bm.subnet, bm.addressMask, bm.freeAddresses)
|
fmt.Printf("\n\t%s: %s\n\t%d", bm.subnet, bm.addressMask, bm.freeAddresses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,8 +347,8 @@ func TestRequest(t *testing.T) {
|
||||||
{"192.168.240.0/20", 16 * 254, "192.168.255.254"},
|
{"192.168.240.0/20", 16 * 254, "192.168.255.254"},
|
||||||
|
|
||||||
{"192.168.0.0/16", 256 * 254, "192.168.255.254"},
|
{"192.168.0.0/16", 256 * 254, "192.168.255.254"},
|
||||||
{"10.0.0.0/8", 256 * 254, "10.0.255.254"},
|
{"10.0.0.0/8", 2 * 254, "10.0.1.254"},
|
||||||
{"10.0.0.0/8", 257 * 254, "10.1.0.254"},
|
{"10.0.0.0/8", 5 * 254, "10.0.4.254"},
|
||||||
//{"10.0.0.0/8", 100 * 256 * 254, "10.99.255.254"},
|
//{"10.0.0.0/8", 100 * 256 * 254, "10.99.255.254"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ func TestRelease(t *testing.T) {
|
||||||
_, sub, _ := net.ParseCIDR(subnet)
|
_, sub, _ := net.ParseCIDR(subnet)
|
||||||
a := getAllocator(sub)
|
a := getAllocator(sub)
|
||||||
req = &AddressRequest{Subnet: *sub}
|
req = &AddressRequest{Subnet: *sub}
|
||||||
bm := a.addresses[isKey{"default", subnet}]
|
bm := a.addresses[subnetKey{"default", subnet}]
|
||||||
|
|
||||||
// Allocate all addresses
|
// Allocate all addresses
|
||||||
for err != ErrNoAvailableIPs {
|
for err != ErrNoAvailableIPs {
|
||||||
|
|
Loading…
Add table
Reference in a new issue