1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Change subnet key schema in ipam

- to addrSpace/subnet/childSubnet

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2015-06-15 17:13:49 -07:00
parent c395cf2eb6
commit 390a9702d2
2 changed files with 80 additions and 22 deletions

View file

@ -3,6 +3,7 @@ package ipam
import ( import (
"fmt" "fmt"
"net" "net"
"strings"
"sync" "sync"
"github.com/docker/libnetwork/bitseq" "github.com/docker/libnetwork/bitseq"
@ -24,7 +25,7 @@ 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]*SubnetInfo subnets map[subnetKey]*SubnetInfo
// Allocated addresses in each address space's internal subnet // Allocated addresses in each address space's internal subnet
addresses map[subnetKey]*bitmask addresses map[subnetKey]*bitmask
// Datastore // Datastore
@ -35,7 +36,7 @@ type Allocator struct {
// NewAllocator returns an instance of libnetwork ipam // NewAllocator returns an instance of libnetwork ipam
func NewAllocator(ds datastore.DataStore) *Allocator { func NewAllocator(ds datastore.DataStore) *Allocator {
a := &Allocator{} a := &Allocator{}
a.subnetsInfo = make(map[subnetKey]*SubnetInfo) a.subnets = make(map[subnetKey]*SubnetInfo)
a.addresses = make(map[subnetKey]*bitmask) a.addresses = make(map[subnetKey]*bitmask)
a.internalHostSize = defaultInternalHostSize a.internalHostSize = defaultInternalHostSize
a.store = ds a.store = ds
@ -46,10 +47,33 @@ func NewAllocator(ds datastore.DataStore) *Allocator {
type subnetKey struct { type subnetKey struct {
addressSpace AddressSpace addressSpace AddressSpace
subnet string subnet string
childSubnet string
} }
func (s *subnetKey) String() string { func (s *subnetKey) String() string {
return fmt.Sprintf("%s/%s", s.addressSpace, s.subnet) k := fmt.Sprintf("%s/%s", s.addressSpace, s.subnet)
if s.childSubnet != "" {
k = fmt.Sprintf("%s/%s", k, s.childSubnet)
}
return k
}
func (s *subnetKey) FromString(str string) error {
if str == "" || !strings.Contains(str, "/") {
return fmt.Errorf("invalid string form for subnetkey: %s", str)
}
p := strings.Split(str, "/")
if len(p) != 3 && len(p) != 5 {
return fmt.Errorf("invalid string form for subnetkey: %s", str)
}
s.addressSpace = AddressSpace(p[0])
s.subnet = fmt.Sprintf("%s/%s", p[1], p[2])
if len(p) == 5 {
s.childSubnet = fmt.Sprintf("%s/%s", p[1], p[2])
}
return nil
} }
// The structs containing the address allocation bitmask for the internal subnet. // The structs containing the address allocation bitmask for the internal subnet.
@ -91,16 +115,16 @@ func (a *Allocator) AddSubnet(addrSpace AddressSpace, subnetInfo *SubnetInfo) er
} }
// Store the configured subnet information // Store the configured subnet information
key := subnetKey{addrSpace, subnetInfo.Subnet.String()} key := subnetKey{addrSpace, subnetInfo.Subnet.String(), ""}
a.Lock() a.Lock()
a.subnetsInfo[key] = subnetInfo a.subnets[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 _, 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()} smallKey := subnetKey{addrSpace, key.subnet, sub.String()}
// Add the new address masks // Add the new address masks
a.Lock() a.Lock()
@ -139,7 +163,7 @@ func adjustAndCheckSubnetSize(subnet *net.IPNet) (*net.IPNet, error) {
func (a *Allocator) contains(space AddressSpace, subInfo *SubnetInfo) bool { func (a *Allocator) contains(space AddressSpace, subInfo *SubnetInfo) bool {
a.Lock() a.Lock()
defer a.Unlock() defer a.Unlock()
for k, v := range a.subnetsInfo { for k, v := range a.subnets {
if space == k.addressSpace { if space == k.addressSpace {
if subInfo.Subnet.Contains(v.Subnet.IP) || if subInfo.Subnet.Contains(v.Subnet.IP) ||
v.Subnet.Contains(subInfo.Subnet.IP) { v.Subnet.Contains(subInfo.Subnet.IP) {
@ -201,9 +225,9 @@ 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() a.Lock()
_, ok := a.subnetsInfo[subKey] _, ok := a.subnets[subKey]
a.Unlock() a.Unlock()
if !ok { if !ok {
return ErrSubnetNotFound return ErrSubnetNotFound
@ -217,12 +241,12 @@ func (a *Allocator) RemoveSubnet(addrSpace AddressSpace, subnet *net.IPNet) erro
for _, s := range subnetList { for _, s := range subnetList {
a.Lock() a.Lock()
delete(a.addresses, subnetKey{addrSpace, s.String()}) delete(a.addresses, subnetKey{addrSpace, subKey.subnet, s.String()})
a.Unlock() a.Unlock()
} }
a.Lock() a.Lock()
delete(a.subnetsInfo, subKey) delete(a.subnets, subKey)
a.Unlock() a.Unlock()
return nil return nil
@ -274,7 +298,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()}] response.Subnet = *a.subnets[subnetKey{addrSpace, req.Subnet.String(), ""}]
a.Unlock() a.Unlock()
} }
@ -291,11 +315,13 @@ 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 a.Lock()
space := a.addresses[subKey]
a.Unlock()
sub := space.subnet
if sub.Contains(address) { if sub.Contains(address) {
// Retrieve correspondent ordinal in the subnet // Retrieve correspondent ordinal in the subnet
space := a.addresses[subnetKey{addrSpace, sub.String()}] ordinal := ipToInt(getHostPortionIP(address, sub))
ordinal := ipToInt(getHostPortionIP(address, space.subnet))
// Release it // Release it
space.addressMask.PushReservation(ordinal/8, ordinal%8, true) space.addressMask.PushReservation(ordinal/8, ordinal%8, true)
space.freeAddresses++ space.freeAddresses++
@ -315,7 +341,7 @@ func (a *Allocator) reserveAddress(addrSpace AddressSpace, subnet *net.IPNet, pr
return nil, nil, err return nil, nil, err
} }
for _, s := range subnetList { for _, s := range subnetList {
keyList = append(keyList, subnetKey{addrSpace, s.String()}) keyList = append(keyList, subnetKey{addrSpace, subnet.String(), s.String()})
} }
} else { } else {
a.Lock() a.Lock()
@ -396,11 +422,11 @@ again:
func (a *Allocator) DumpDatabase() { func (a *Allocator) DumpDatabase() {
a.Lock() a.Lock()
defer a.Unlock() defer a.Unlock()
for k, config := range a.subnetsInfo { for k, config := range a.subnets {
fmt.Printf("\n\n%s:", config.Subnet.String()) fmt.Printf("\n\n%s:", config.Subnet.String())
subnetList, _ := getInternalSubnets(config.Subnet, a.internalHostSize) subnetList, _ := getInternalSubnets(config.Subnet, a.internalHostSize)
for _, s := range subnetList { for _, s := range subnetList {
internKey := subnetKey{k.addressSpace, s.String()} internKey := subnetKey{k.addressSpace, config.Subnet.String(), s.String()}
bm := a.addresses[internKey] 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)
} }

View file

@ -57,6 +57,38 @@ func TestGetAddressVersion(t *testing.T) {
} }
} }
func TestKeyString(t *testing.T) {
k := &subnetKey{addressSpace: "default", subnet: "172.27.0.0/16"}
expected := "default/172.27.0.0/16"
if expected != k.String() {
t.Fatalf("Unexpected key string: %s", k.String())
}
k2 := &subnetKey{}
err := k2.FromString(expected)
if err != nil {
t.Fatal(err)
}
if k2.addressSpace != k.addressSpace || k2.subnet != k.subnet {
t.Fatalf("subnetKey.FromString() failed. Expected %v. Got %v", k, k2)
}
expected = fmt.Sprintf("%s/%s", expected, "172.27.3.0/24")
k.childSubnet = "172.27.3.0/24"
if expected != k.String() {
t.Fatalf("Unexpected key string: %s", k.String())
}
err = k2.FromString(expected)
if err != nil {
t.Fatal(err)
}
if k2.addressSpace != k.addressSpace || k2.subnet != k.subnet {
t.Fatalf("subnetKey.FromString() failed. Expected %v. Got %v", k, k2)
}
}
func TestAddSubnets(t *testing.T) { func TestAddSubnets(t *testing.T) {
a := NewAllocator(nil) a := NewAllocator(nil)
@ -162,7 +194,7 @@ func TestRemoveSubnet(t *testing.T) {
_, sub, _ := net.ParseCIDR("172.17.0.0/16") _, sub, _ := net.ParseCIDR("172.17.0.0/16")
a.RemoveSubnet("default", sub) a.RemoveSubnet("default", sub)
if len(a.subnetsInfo) != 7 { if len(a.subnets) != 7 {
t.Fatalf("Failed to remove subnet info") t.Fatalf("Failed to remove subnet info")
} }
list := a.getSubnetList("default", v4) list := a.getSubnetList("default", v4)
@ -172,7 +204,7 @@ func TestRemoveSubnet(t *testing.T) {
_, sub, _ = net.ParseCIDR("2002:1:2:3:4:5:ffff::/112") _, sub, _ = net.ParseCIDR("2002:1:2:3:4:5:ffff::/112")
a.RemoveSubnet("default", sub) a.RemoveSubnet("default", sub)
if len(a.subnetsInfo) != 6 { if len(a.subnets) != 6 {
t.Fatalf("Failed to remove subnet info") t.Fatalf("Failed to remove subnet info")
} }
list = a.getSubnetList("default", v6) list = a.getSubnetList("default", v6)
@ -182,7 +214,7 @@ func TestRemoveSubnet(t *testing.T) {
_, sub, _ = net.ParseCIDR("2002:1:2:3:4:5:6::/112") _, sub, _ = net.ParseCIDR("2002:1:2:3:4:5:6::/112")
a.RemoveSubnet("splane", sub) a.RemoveSubnet("splane", sub)
if len(a.subnetsInfo) != 5 { if len(a.subnets) != 5 {
t.Fatalf("Failed to remove subnet info") t.Fatalf("Failed to remove subnet info")
} }
list = a.getSubnetList("splane", v6) list = a.getSubnetList("splane", v6)
@ -367,7 +399,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[subnetKey{"default", subnet}] bm := a.addresses[subnetKey{"default", subnet, subnet}]
// Allocate all addresses // Allocate all addresses
for err != ErrNoAvailableIPs { for err != ErrNoAvailableIPs {