Removed the IPv6 prefix size limit for cluster-cidr

Signed-off-by: André Martins <aanm90@gmail.com>
This commit is contained in:
André Martins 2017-09-06 20:01:06 +02:00
parent 23eedbb7aa
commit 326754eea4
2 changed files with 154 additions and 22 deletions

View File

@ -43,8 +43,8 @@ const (
// TODO: https://github.com/kubernetes/kubernetes/issues/44918 // TODO: https://github.com/kubernetes/kubernetes/issues/44918
// clusterSubnetMaxDiff limited to 16 due to the uncompressed bitmap // clusterSubnetMaxDiff limited to 16 due to the uncompressed bitmap
clusterSubnetMaxDiff = 16 clusterSubnetMaxDiff = 16
// maximum 64 bits of prefix // halfIPv6Len is the half of the IPv6 length
maxPrefixLength = 64 halfIPv6Len = net.IPv6len / 2
) )
var ( var (
@ -60,7 +60,7 @@ func NewCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) *CidrSet {
clusterMaskSize, _ := clusterMask.Size() clusterMaskSize, _ := clusterMask.Size()
var maxCIDRs int var maxCIDRs int
if ((clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff)) || (subNetMaskSize > maxPrefixLength) { if (clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff) {
maxCIDRs = 0 maxCIDRs = 0
} else { } else {
maxCIDRs = 1 << uint32(subNetMaskSize-clusterMaskSize) maxCIDRs = 1 << uint32(subNetMaskSize-clusterMaskSize)
@ -74,6 +74,48 @@ func NewCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) *CidrSet {
} }
} }
// TODO: Remove this function when upgrading to go 1.9
var len8tab = [256]uint8{
0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
}
// TODO: Remove this function when upgrading to go 1.9
// len64 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
func len64(x uint64) (n int) {
if x >= 1<<32 {
x >>= 32
n = 32
}
if x >= 1<<16 {
x >>= 16
n += 16
}
if x >= 1<<8 {
x >>= 8
n += 8
}
return n + int(len8tab[x])
}
// TODO: Remove this function when upgrading to go 1.9
// leadingZeros64 returns the number of leading zero bits in x; the result is 64 for x == 0.
func leadingZeros64(x uint64) int { return 64 - len64(x) }
func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet { func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet {
var ip []byte var ip []byte
var mask int var mask int
@ -89,10 +131,36 @@ func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet {
} }
case s.clusterIP.To16() != nil: case s.clusterIP.To16() != nil:
{ {
j := uint64(index) << uint64(64-s.subNetMaskSize) // leftClusterIP | rightClusterIP
ipInt := (binary.BigEndian.Uint64(s.clusterIP)) | j // 2001:0DB8:1234:0000:0000:0000:0000:0000
ip = make([]byte, 16) const v6NBits = 128
binary.BigEndian.PutUint64(ip, ipInt) const halfV6NBits = v6NBits / 2
leftClusterIP := binary.BigEndian.Uint64(s.clusterIP[:halfIPv6Len])
rightClusterIP := binary.BigEndian.Uint64(s.clusterIP[halfIPv6Len:])
leftIP, rightIP := make([]byte, halfIPv6Len), make([]byte, halfIPv6Len)
if s.subNetMaskSize <= halfV6NBits {
// We only care about left side IP
leftClusterIP |= uint64(index) << uint(halfV6NBits-s.subNetMaskSize)
} else {
if s.clusterMaskSize < halfV6NBits {
// see how many bits are needed to reach the left side
btl := uint(s.subNetMaskSize - halfV6NBits)
// TODO: Replace this with math/bits.LeadingZeros64 when upgrading to go 1.9
indexMaxBit := uint(64 - leadingZeros64(uint64(index)))
if indexMaxBit > btl {
leftClusterIP |= uint64(index) >> btl
}
}
// the right side will be calculated the same way either the
// subNetMaskSize affects both left and right sides
rightClusterIP |= uint64(index) << uint(v6NBits-s.subNetMaskSize)
}
binary.BigEndian.PutUint64(leftIP, leftClusterIP)
binary.BigEndian.PutUint64(rightIP, rightClusterIP)
ip = append(leftIP, rightIP...)
mask = 128 mask = 128
} }
} }
@ -159,8 +227,12 @@ func (s *CidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err
ipInt := binary.BigEndian.Uint32(cidr.IP) | (^binary.BigEndian.Uint32(cidr.Mask)) ipInt := binary.BigEndian.Uint32(cidr.IP) | (^binary.BigEndian.Uint32(cidr.Mask))
binary.BigEndian.PutUint32(ip, ipInt) binary.BigEndian.PutUint32(ip, ipInt)
} else { } else {
ipInt := binary.BigEndian.Uint64(cidr.IP) | (^binary.BigEndian.Uint64(cidr.Mask)) // ipIntLeft | ipIntRight
binary.BigEndian.PutUint64(ip, ipInt) // 2001:0DB8:1234:0000:0000:0000:0000:0000
ipIntLeft := binary.BigEndian.Uint64(cidr.IP[:net.IPv6len/2]) | (^binary.BigEndian.Uint64(cidr.Mask[:net.IPv6len/2]))
ipIntRight := binary.BigEndian.Uint64(cidr.IP[net.IPv6len/2:]) | (^binary.BigEndian.Uint64(cidr.Mask[net.IPv6len/2:]))
binary.BigEndian.PutUint64(ip[:net.IPv6len/2], ipIntLeft)
binary.BigEndian.PutUint64(ip[net.IPv6len/2:], ipIntRight)
} }
end, err = s.getIndexForCIDR(&net.IPNet{ end, err = s.getIndexForCIDR(&net.IPNet{
IP: net.IP(ip).Mask(subNetMask), IP: net.IP(ip).Mask(subNetMask),
@ -217,7 +289,10 @@ func (s *CidrSet) getIndexForIP(ip net.IP) (int, error) {
return int(cidrIndex), nil return int(cidrIndex), nil
} }
if ip.To16() != nil { if ip.To16() != nil {
cidrIndex := (binary.BigEndian.Uint64(s.clusterIP) ^ binary.BigEndian.Uint64(ip.To16())) >> uint64(64-s.subNetMaskSize) bigIP := big.NewInt(0).SetBytes(s.clusterIP)
bigIP = bigIP.Xor(bigIP, big.NewInt(0).SetBytes(ip))
cidrIndexBig := bigIP.Rsh(bigIP, uint(net.IPv6len*8-s.subNetMaskSize))
cidrIndex := cidrIndexBig.Uint64()
if cidrIndex >= uint64(s.maxCIDRs) { if cidrIndex >= uint64(s.maxCIDRs) {
return 0, fmt.Errorf("CIDR: %v/%v is out of the range of CIDR allocator", ip, s.subNetMaskSize) return 0, fmt.Errorf("CIDR: %v/%v is out of the range of CIDR allocator", ip, s.subNetMaskSize)
} }

View File

@ -93,42 +93,105 @@ func TestIndexToCIDRBlock(t *testing.T) {
subnetMaskSize: 24, subnetMaskSize: 24,
index: 0, index: 0,
CIDRBlock: "127.123.0.0/24", CIDRBlock: "127.123.0.0/24",
description: "Index with IPv4", description: "1st IP address indexed with IPv4",
}, },
{ {
clusterCIDRStr: "127.123.0.0/16", clusterCIDRStr: "127.123.0.0/16",
subnetMaskSize: 24, subnetMaskSize: 24,
index: 15, index: 15,
CIDRBlock: "127.123.15.0/24", CIDRBlock: "127.123.15.0/24",
description: "Index with IPv4", description: "16th IP address indexed with IPv4",
}, },
{ {
clusterCIDRStr: "192.168.5.219/28", clusterCIDRStr: "192.168.5.219/28",
subnetMaskSize: 32, subnetMaskSize: 32,
index: 5, index: 5,
CIDRBlock: "192.168.5.213/32", CIDRBlock: "192.168.5.213/32",
description: "Index with IPv4", description: "5th IP address indexed with IPv4",
}, },
{ {
clusterCIDRStr: "2001:0db8:1234:3::/48", clusterCIDRStr: "2001:0db8:1234:3::/48",
subnetMaskSize: 64, subnetMaskSize: 64,
index: 0, index: 0,
CIDRBlock: "2001:db8:1234::/64", CIDRBlock: "2001:db8:1234::/64",
description: "Index with IPv6", description: "1st IP address indexed with IPv6 /64",
}, },
{ {
clusterCIDRStr: "2001:0db8:1234::/48", clusterCIDRStr: "2001:0db8:1234::/48",
subnetMaskSize: 64, subnetMaskSize: 64,
index: 15, index: 15,
CIDRBlock: "2001:db8:1234:f::/64", CIDRBlock: "2001:db8:1234:f::/64",
description: "Index with IPv6", description: "16th IP address indexed with IPv6 /64",
}, },
{ {
clusterCIDRStr: "2001:0db8:85a3::8a2e:0370:7334/50", clusterCIDRStr: "2001:0db8:85a3::8a2e:0370:7334/50",
subnetMaskSize: 63, subnetMaskSize: 63,
index: 6425, index: 6425,
CIDRBlock: "2001:db8:85a3:3232::/63", CIDRBlock: "2001:db8:85a3:3232::/63",
description: "Index with IPv6", description: "6426th IP address indexed with IPv6 /63",
},
{
clusterCIDRStr: "2001:0db8::/32",
subnetMaskSize: 48,
index: 0,
CIDRBlock: "2001:db8::/48",
description: "1st IP address indexed with IPv6 /48",
},
{
clusterCIDRStr: "2001:0db8::/32",
subnetMaskSize: 48,
index: 15,
CIDRBlock: "2001:db8:f::/48",
description: "16th IP address indexed with IPv6 /48",
},
{
clusterCIDRStr: "2001:0db8:85a3::8a2e:0370:7334/32",
subnetMaskSize: 48,
index: 6425,
CIDRBlock: "2001:db8:1919::/48",
description: "6426th IP address indexed with IPv6 /48",
},
{
clusterCIDRStr: "2001:0db8:1234:ff00::/56",
subnetMaskSize: 72,
index: 0,
CIDRBlock: "2001:db8:1234:ff00::/72",
description: "1st IP address indexed with IPv6 /72",
},
{
clusterCIDRStr: "2001:0db8:1234:ff00::/56",
subnetMaskSize: 72,
index: 15,
CIDRBlock: "2001:db8:1234:ff00:f00::/72",
description: "16th IP address indexed with IPv6 /72",
},
{
clusterCIDRStr: "2001:0db8:1234:ff00::0370:7334/56",
subnetMaskSize: 72,
index: 6425,
CIDRBlock: "2001:db8:1234:ff19:1900::/72",
description: "6426th IP address indexed with IPv6 /72",
},
{
clusterCIDRStr: "2001:0db8:1234:0:1234::/80",
subnetMaskSize: 96,
index: 0,
CIDRBlock: "2001:db8:1234:0:1234::/96",
description: "1st IP address indexed with IPv6 /96",
},
{
clusterCIDRStr: "2001:0db8:1234:0:1234::/80",
subnetMaskSize: 96,
index: 15,
CIDRBlock: "2001:db8:1234:0:1234:f::/96",
description: "16th IP address indexed with IPv6 /96",
},
{
clusterCIDRStr: "2001:0db8:1234:ff00::0370:7334/80",
subnetMaskSize: 96,
index: 6425,
CIDRBlock: "2001:db8:1234:ff00:0:1919::/96",
description: "6426th IP address indexed with IPv6 /96",
}, },
} }
for _, tc := range cases { for _, tc := range cases {
@ -612,12 +675,6 @@ func TestCIDRSetv6(t *testing.T) {
expectErr: true, expectErr: true,
description: "Max cluster subnet size with IPv6", description: "Max cluster subnet size with IPv6",
}, },
{
clusterCIDRStr: "beef:1234::/60",
subNetMaskSize: 65,
expectErr: true,
description: "Max prefix length with IPv6",
},
{ {
clusterCIDRStr: "2001:beef:1234:369b::/60", clusterCIDRStr: "2001:beef:1234:369b::/60",
subNetMaskSize: 64, subNetMaskSize: 64,