Commit 063fc6a7 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #43586 from rpothier/cidr_set_ipv6

Automatic merge from submit-queue (batch tested with PRs 50103, 49677, 49449, 43586, 48969) Adding IPv6 to cidr_set and cidr_set_test **What this PR does / why we need it**: This allows IPv6 in cidr_set Currently cidr_set only supports IPv4. This adds IPv6 compatibility and adds IPv6 unit tests. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #43588 **Special notes for your reviewer**: The IPv6 code here makes some assumptions. The subnets should be at least /64. (maximum 64 bits of prefix) The subnet mask size cannot be greater than 30 more than the cluster mask size. **Release note**: ```release-note ```
parents 6843ca57 5e965239
...@@ -35,19 +35,62 @@ type cidrSet struct { ...@@ -35,19 +35,62 @@ type cidrSet struct {
subNetMaskSize int subNetMaskSize int
} }
const (
// The subnet mask size cannot be greater than 16 more than the cluster mask size
// 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
)
func newCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) *cidrSet { func newCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) *cidrSet {
clusterMask := clusterCIDR.Mask clusterMask := clusterCIDR.Mask
clusterMaskSize, _ := clusterMask.Size() clusterMaskSize, _ := clusterMask.Size()
maxCIDRs := 1 << uint32(subNetMaskSize-clusterMaskSize)
var maxCIDRs int
if ((clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff)) || (subNetMaskSize > maxPrefixLength) {
maxCIDRs = 0
} else {
maxCIDRs = 1 << uint32(subNetMaskSize-clusterMaskSize)
}
return &cidrSet{ return &cidrSet{
clusterCIDR: clusterCIDR, clusterCIDR: clusterCIDR,
clusterIP: clusterCIDR.IP.To4(), clusterIP: clusterCIDR.IP,
clusterMaskSize: clusterMaskSize, clusterMaskSize: clusterMaskSize,
maxCIDRs: maxCIDRs, maxCIDRs: maxCIDRs,
subNetMaskSize: subNetMaskSize, subNetMaskSize: subNetMaskSize,
} }
} }
func (s *cidrSet) indexToCIDRBlock(index int) *net.IPNet {
var ip []byte
var mask int
switch /*v4 or v6*/ {
case s.clusterIP.To4() != nil:
{
j := uint32(index) << uint32(32-s.subNetMaskSize)
ipInt := (binary.BigEndian.Uint32(s.clusterIP)) | j
ip = make([]byte, 4)
binary.BigEndian.PutUint32(ip, ipInt)
mask = 32
}
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)
mask = 128
}
}
return &net.IPNet{
IP: ip,
Mask: net.CIDRMask(s.subNetMaskSize, mask),
}
}
func (s *cidrSet) allocateNext() (*net.IPNet, error) { func (s *cidrSet) allocateNext() (*net.IPNet, error) {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
...@@ -67,41 +110,47 @@ func (s *cidrSet) allocateNext() (*net.IPNet, error) { ...@@ -67,41 +110,47 @@ func (s *cidrSet) allocateNext() (*net.IPNet, error) {
s.used.SetBit(&s.used, nextUnused, 1) s.used.SetBit(&s.used, nextUnused, 1)
j := uint32(nextUnused) << uint32(32-s.subNetMaskSize) return s.indexToCIDRBlock(nextUnused), nil
ipInt := (binary.BigEndian.Uint32(s.clusterIP)) | j
ip := make([]byte, 4)
binary.BigEndian.PutUint32(ip, ipInt)
return &net.IPNet{
IP: ip,
Mask: net.CIDRMask(s.subNetMaskSize, 32),
}, nil
} }
func (s *cidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err error) { func (s *cidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err error) {
begin, end = 0, s.maxCIDRs-1 begin, end = 0, s.maxCIDRs-1
cidrMask := cidr.Mask cidrMask := cidr.Mask
maskSize, _ := cidrMask.Size() maskSize, _ := cidrMask.Size()
var ipSize int
if cidr == nil {
return -1, -1, fmt.Errorf("Error getting indices for cluster cidr %v, cidr is nil", s.clusterCIDR)
}
if !s.clusterCIDR.Contains(cidr.IP.Mask(s.clusterCIDR.Mask)) && !cidr.Contains(s.clusterCIDR.IP.Mask(cidr.Mask)) { if !s.clusterCIDR.Contains(cidr.IP.Mask(s.clusterCIDR.Mask)) && !cidr.Contains(s.clusterCIDR.IP.Mask(cidr.Mask)) {
return -1, -1, fmt.Errorf("cidr %v is out the range of cluster cidr %v", cidr, s.clusterCIDR) return -1, -1, fmt.Errorf("cidr %v is out the range of cluster cidr %v", cidr, s.clusterCIDR)
} }
if s.clusterMaskSize < maskSize { if s.clusterMaskSize < maskSize {
subNetMask := net.CIDRMask(s.subNetMaskSize, 32)
ipSize = net.IPv4len
if cidr.IP.To4() == nil {
ipSize = net.IPv6len
}
subNetMask := net.CIDRMask(s.subNetMaskSize, ipSize*8)
begin, err = s.getIndexForCIDR(&net.IPNet{ begin, err = s.getIndexForCIDR(&net.IPNet{
IP: cidr.IP.To4().Mask(subNetMask), IP: cidr.IP.Mask(subNetMask),
Mask: subNetMask, Mask: subNetMask,
}) })
if err != nil { if err != nil {
return -1, -1, err return -1, -1, err
} }
ip := make([]byte, ipSize)
ip := make([]byte, 4) if cidr.IP.To4() != nil {
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 {
ipInt := binary.BigEndian.Uint64(cidr.IP) | (^binary.BigEndian.Uint64(cidr.Mask))
binary.BigEndian.PutUint64(ip, ipInt)
}
end, err = s.getIndexForCIDR(&net.IPNet{ end, err = s.getIndexForCIDR(&net.IPNet{
IP: net.IP(ip).To4().Mask(subNetMask), IP: net.IP(ip).Mask(subNetMask),
Mask: subNetMask, Mask: subNetMask,
}) })
if err != nil { if err != nil {
...@@ -140,11 +189,21 @@ func (s *cidrSet) occupy(cidr *net.IPNet) (err error) { ...@@ -140,11 +189,21 @@ func (s *cidrSet) occupy(cidr *net.IPNet) (err error) {
} }
func (s *cidrSet) getIndexForCIDR(cidr *net.IPNet) (int, error) { func (s *cidrSet) getIndexForCIDR(cidr *net.IPNet) (int, error) {
cidrIndex := (binary.BigEndian.Uint32(s.clusterIP) ^ binary.BigEndian.Uint32(cidr.IP.To4())) >> uint32(32-s.subNetMaskSize) var cidrIndex uint32
if cidr.IP.To4() != nil {
cidrIndex = (binary.BigEndian.Uint32(s.clusterIP) ^ binary.BigEndian.Uint32(cidr.IP.To4())) >> uint32(32-s.subNetMaskSize)
if cidrIndex >= uint32(s.maxCIDRs) {
return 0, fmt.Errorf("CIDR: %v is out of the range of CIDR allocator", cidr)
}
} else if cidr.IP.To16() != nil {
cidrIndex64 := (binary.BigEndian.Uint64(s.clusterIP) ^ binary.BigEndian.Uint64(cidr.IP.To16())) >> uint64(64-s.subNetMaskSize)
if cidrIndex >= uint32(s.maxCIDRs) { if cidrIndex64 >= uint64(s.maxCIDRs) {
return 0, fmt.Errorf("CIDR: %v is out of the range of CIDR allocator", cidr) return 0, fmt.Errorf("CIDR: %v is out of the range of CIDR allocator", cidr)
}
cidrIndex = uint32(cidrIndex64)
} else {
return 0, fmt.Errorf("invalid CIDR block: %v", cidr)
} }
return int(cidrIndex), nil return int(cidrIndex), nil
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment