Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automated cherry pick of #52033 #53972

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
95 changes: 85 additions & 10 deletions pkg/controller/node/ipam/cidrset/cidr_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ const (
// TODO: https://github.com/kubernetes/kubernetes/issues/44918
// clusterSubnetMaxDiff limited to 16 due to the uncompressed bitmap
clusterSubnetMaxDiff = 16
// maximum 64 bits of prefix
maxPrefixLength = 64
// halfIPv6Len is the half of the IPv6 length
halfIPv6Len = net.IPv6len / 2
)

var (
Expand All @@ -60,7 +60,7 @@ func NewCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) *CidrSet {
clusterMaskSize, _ := clusterMask.Size()

var maxCIDRs int
if ((clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff)) || (subNetMaskSize > maxPrefixLength) {
if (clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff) {
maxCIDRs = 0
} else {
maxCIDRs = 1 << uint32(subNetMaskSize-clusterMaskSize)
Expand All @@ -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 {
var ip []byte
var mask int
Expand All @@ -89,10 +131,36 @@ func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet {
}
case s.clusterIP.To16() != nil:
{
j := uint64(index) << uint64(64-s.subNetMaskSize)
ipInt := (binary.BigEndian.Uint64(s.clusterIP)) | j
ip = make([]byte, 16)
binary.BigEndian.PutUint64(ip, ipInt)
// leftClusterIP | rightClusterIP
// 2001:0DB8:1234:0000:0000:0000:0000:0000
const v6NBits = 128
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
}
}
Expand Down Expand Up @@ -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))
binary.BigEndian.PutUint32(ip, ipInt)
} else {
ipInt := binary.BigEndian.Uint64(cidr.IP) | (^binary.BigEndian.Uint64(cidr.Mask))
binary.BigEndian.PutUint64(ip, ipInt)
// ipIntLeft | ipIntRight
// 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{
IP: net.IP(ip).Mask(subNetMask),
Expand Down Expand Up @@ -217,7 +289,10 @@ func (s *CidrSet) getIndexForIP(ip net.IP) (int, error) {
return int(cidrIndex), 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) {
return 0, fmt.Errorf("CIDR: %v/%v is out of the range of CIDR allocator", ip, s.subNetMaskSize)
}
Expand Down
81 changes: 69 additions & 12 deletions pkg/controller/node/ipam/cidrset/cidr_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,42 +93,105 @@ func TestIndexToCIDRBlock(t *testing.T) {
subnetMaskSize: 24,
index: 0,
CIDRBlock: "127.123.0.0/24",
description: "Index with IPv4",
description: "1st IP address indexed with IPv4",
},
{
clusterCIDRStr: "127.123.0.0/16",
subnetMaskSize: 24,
index: 15,
CIDRBlock: "127.123.15.0/24",
description: "Index with IPv4",
description: "16th IP address indexed with IPv4",
},
{
clusterCIDRStr: "192.168.5.219/28",
subnetMaskSize: 32,
index: 5,
CIDRBlock: "192.168.5.213/32",
description: "Index with IPv4",
description: "5th IP address indexed with IPv4",
},
{
clusterCIDRStr: "2001:0db8:1234:3::/48",
subnetMaskSize: 64,
index: 0,
CIDRBlock: "2001:db8:1234::/64",
description: "Index with IPv6",
description: "1st IP address indexed with IPv6 /64",
},
{
clusterCIDRStr: "2001:0db8:1234::/48",
subnetMaskSize: 64,
index: 15,
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",
subnetMaskSize: 63,
index: 6425,
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 {
Expand Down Expand Up @@ -612,12 +675,6 @@ func TestCIDRSetv6(t *testing.T) {
expectErr: true,
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",
subNetMaskSize: 64,
Expand Down