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:
parent
c395cf2eb6
commit
390a9702d2
2 changed files with 80 additions and 22 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue