Adding IPv6 to cidr_set and cidr_set_test

pull/6/head
Robert Pothier 2017-03-20 16:39:09 -04:00
parent 1284d78c92
commit 5e96523913
2 changed files with 504 additions and 126 deletions

View File

@ -35,19 +35,62 @@ type cidrSet struct {
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 {
clusterMask := clusterCIDR.Mask
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{
clusterCIDR: clusterCIDR,
clusterIP: clusterCIDR.IP.To4(),
clusterIP: clusterCIDR.IP,
clusterMaskSize: clusterMaskSize,
maxCIDRs: maxCIDRs,
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) {
s.Lock()
defer s.Unlock()
@ -67,41 +110,47 @@ func (s *cidrSet) allocateNext() (*net.IPNet, error) {
s.used.SetBit(&s.used, nextUnused, 1)
j := uint32(nextUnused) << uint32(32-s.subNetMaskSize)
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
return s.indexToCIDRBlock(nextUnused), nil
}
func (s *cidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err error) {
begin, end = 0, s.maxCIDRs-1
cidrMask := cidr.Mask
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)) {
return -1, -1, fmt.Errorf("cidr %v is out the range of cluster cidr %v", cidr, s.clusterCIDR)
}
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{
IP: cidr.IP.To4().Mask(subNetMask),
IP: cidr.IP.Mask(subNetMask),
Mask: subNetMask,
})
if err != nil {
return -1, -1, err
}
ip := make([]byte, 4)
ipInt := binary.BigEndian.Uint32(cidr.IP) | (^binary.BigEndian.Uint32(cidr.Mask))
binary.BigEndian.PutUint32(ip, ipInt)
ip := make([]byte, ipSize)
if cidr.IP.To4() != nil {
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)
}
end, err = s.getIndexForCIDR(&net.IPNet{
IP: net.IP(ip).To4().Mask(subNetMask),
IP: net.IP(ip).Mask(subNetMask),
Mask: subNetMask,
})
if err != nil {
@ -140,11 +189,21 @@ func (s *cidrSet) occupy(cidr *net.IPNet) (err 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) {
return 0, fmt.Errorf("CIDR: %v is out of the range of CIDR allocator", cidr)
if cidrIndex64 >= uint64(s.maxCIDRs) {
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
}

View File

@ -26,124 +26,244 @@ import (
)
func TestCIDRSetFullyAllocated(t *testing.T) {
_, clusterCIDR, _ := net.ParseCIDR("127.123.234.0/30")
a := newCIDRSet(clusterCIDR, 30)
cases := []struct {
clusterCIDRStr string
subNetMaskSize int
expectedCIDR string
description string
}{
{
clusterCIDRStr: "127.123.234.0/30",
subNetMaskSize: 30,
expectedCIDR: "127.123.234.0/30",
description: "Fully allocated CIDR with IPv4",
},
{
clusterCIDRStr: "beef:1234::/30",
subNetMaskSize: 30,
expectedCIDR: "beef:1234::/30",
description: "Fully allocated CIDR with IPv6",
},
}
for _, tc := range cases {
_, clusterCIDR, _ := net.ParseCIDR(tc.clusterCIDRStr)
a := newCIDRSet(clusterCIDR, tc.subNetMaskSize)
p, err := a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if p.String() != "127.123.234.0/30" {
t.Fatalf("unexpected allocated cidr: %s", p.String())
}
p, err := a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
if p.String() != tc.expectedCIDR {
t.Fatalf("unexpected allocated cidr: %v, expecting %v for %v",
p.String(), tc.expectedCIDR, tc.description)
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range")
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range for %v", tc.description)
}
a.release(p)
p, err = a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %v", err)
a.release(p)
p, err = a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
if p.String() != tc.expectedCIDR {
t.Fatalf("unexpected allocated cidr: %v, expecting %v for %v",
p.String(), tc.expectedCIDR, tc.description)
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range for %v", tc.description)
}
}
if p.String() != "127.123.234.0/30" {
t.Fatalf("unexpected allocated cidr: %s", p.String())
}
func TestIndexToCIDRBlock(t *testing.T) {
cases := []struct {
clusterCIDRStr string
subnetMaskSize int
index int
CIDRBlock string
description string
}{
{
clusterCIDRStr: "127.123.3.0/16",
subnetMaskSize: 24,
index: 0,
CIDRBlock: "127.123.0.0/24",
description: "Index with IPv4",
},
{
clusterCIDRStr: "127.123.0.0/16",
subnetMaskSize: 24,
index: 15,
CIDRBlock: "127.123.15.0/24",
description: "Index with IPv4",
},
{
clusterCIDRStr: "192.168.5.219/28",
subnetMaskSize: 32,
index: 5,
CIDRBlock: "192.168.5.213/32",
description: "Index with IPv4",
},
{
clusterCIDRStr: "2001:0db8:1234:3::/48",
subnetMaskSize: 64,
index: 0,
CIDRBlock: "2001:db8:1234::/64",
description: "Index with IPv6",
},
{
clusterCIDRStr: "2001:0db8:1234::/48",
subnetMaskSize: 64,
index: 15,
CIDRBlock: "2001:db8:1234:f::/64",
description: "Index with IPv6",
},
{
clusterCIDRStr: "2001:0db8:85a3::8a2e:0370:7334/50",
subnetMaskSize: 63,
index: 6425,
CIDRBlock: "2001:db8:85a3:3232::/63",
description: "Index with IPv6",
},
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range")
for _, tc := range cases {
_, clusterCIDR, _ := net.ParseCIDR(tc.clusterCIDRStr)
a := newCIDRSet(clusterCIDR, tc.subnetMaskSize)
cidr := a.indexToCIDRBlock(tc.index)
if cidr.String() != tc.CIDRBlock {
t.Fatalf("error for %v index %d %s", tc.description, tc.index, cidr.String())
}
}
}
func TestCIDRSet_RandomishAllocation(t *testing.T) {
_, clusterCIDR, _ := net.ParseCIDR("127.123.234.0/16")
a := newCIDRSet(clusterCIDR, 24)
// allocate all the CIDRs
var err error
cidrs := make([]*net.IPNet, 256)
cases := []struct {
clusterCIDRStr string
description string
}{
{
clusterCIDRStr: "127.123.234.0/16",
description: "RandomishAllocation with IPv4",
},
{
clusterCIDRStr: "beef:1234::/16",
description: "RandomishAllocation with IPv6",
},
}
for _, tc := range cases {
_, clusterCIDR, _ := net.ParseCIDR(tc.clusterCIDRStr)
a := newCIDRSet(clusterCIDR, 24)
// allocate all the CIDRs
var cidrs []*net.IPNet
for i := 0; i < 256; i++ {
cidrs[i], err = a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %v", err)
for i := 0; i < 256; i++ {
if c, err := a.allocateNext(); err == nil {
cidrs = append(cidrs, c)
} else {
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
}
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range")
}
// release them all
for i := 0; i < 256; i++ {
a.release(cidrs[i])
}
// allocate the CIDRs again
rcidrs := make([]*net.IPNet, 256)
for i := 0; i < 256; i++ {
rcidrs[i], err = a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %d, %v", i, err)
var err error
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range for %v", tc.description)
}
// release them all
for i := 0; i < len(cidrs); i++ {
a.release(cidrs[i])
}
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range")
}
if !reflect.DeepEqual(cidrs, rcidrs) {
t.Fatalf("expected re-allocated cidrs are the same collection")
// allocate the CIDRs again
var rcidrs []*net.IPNet
for i := 0; i < 256; i++ {
if c, err := a.allocateNext(); err == nil {
rcidrs = append(rcidrs, c)
} else {
t.Fatalf("unexpected error: %d, %v for %v", i, err, tc.description)
}
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range for %v", tc.description)
}
if !reflect.DeepEqual(cidrs, rcidrs) {
t.Fatalf("expected re-allocated cidrs are the same collection for %v", tc.description)
}
}
}
func TestCIDRSet_AllocationOccupied(t *testing.T) {
_, clusterCIDR, _ := net.ParseCIDR("127.123.234.0/16")
a := newCIDRSet(clusterCIDR, 24)
cases := []struct {
clusterCIDRStr string
description string
}{
{
clusterCIDRStr: "127.123.234.0/16",
description: "AllocationOccupied with IPv4",
},
{
clusterCIDRStr: "beef:1234::/16",
description: "AllocationOccupied with IPv6",
},
}
for _, tc := range cases {
_, clusterCIDR, _ := net.ParseCIDR(tc.clusterCIDRStr)
a := newCIDRSet(clusterCIDR, 24)
// allocate all the CIDRs
var err error
cidrs := make([]*net.IPNet, 256)
// allocate all the CIDRs
var cidrs []*net.IPNet
var num_cidrs = 256
for i := 0; i < 256; i++ {
cidrs[i], err = a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %v", err)
for i := 0; i < num_cidrs; i++ {
if c, err := a.allocateNext(); err == nil {
cidrs = append(cidrs, c)
} else {
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
}
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range")
}
// release them all
for i := 0; i < 256; i++ {
a.release(cidrs[i])
}
// occupy the last 128 CIDRs
for i := 128; i < 256; i++ {
a.occupy(cidrs[i])
}
// allocate the first 128 CIDRs again
rcidrs := make([]*net.IPNet, 128)
for i := 0; i < 128; i++ {
rcidrs[i], err = a.allocateNext()
if err != nil {
t.Fatalf("unexpected error: %d, %v", i, err)
var err error
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range for %v", tc.description)
}
// release them all
for i := 0; i < len(cidrs); i++ {
a.release(cidrs[i])
}
// occupy the last 128 CIDRs
for i := num_cidrs / 2; i < num_cidrs; i++ {
a.occupy(cidrs[i])
}
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range")
}
// check Occupy() work properly
for i := 128; i < 256; i++ {
rcidrs = append(rcidrs, cidrs[i])
}
if !reflect.DeepEqual(cidrs, rcidrs) {
t.Fatalf("expected re-allocated cidrs are the same collection")
// allocate the first 128 CIDRs again
var rcidrs []*net.IPNet
for i := 0; i < num_cidrs/2; i++ {
if c, err := a.allocateNext(); err == nil {
rcidrs = append(rcidrs, c)
} else {
t.Fatalf("unexpected error: %d, %v for %v", i, err, tc.description)
}
}
_, err = a.allocateNext()
if err == nil {
t.Fatalf("expected error because of fully-allocated range for %v", tc.description)
}
// check Occupy() work properly
for i := num_cidrs / 2; i < num_cidrs; i++ {
rcidrs = append(rcidrs, cidrs[i])
}
if !reflect.DeepEqual(cidrs, rcidrs) {
t.Fatalf("expected re-allocated cidrs are the same collection for %v", tc.description)
}
}
}
@ -154,6 +274,7 @@ func TestGetBitforCIDR(t *testing.T) {
subNetCIDRStr string
expectedBit int
expectErr bool
description string
}{
{
clusterCIDRStr: "127.0.0.0/8",
@ -161,6 +282,15 @@ func TestGetBitforCIDR(t *testing.T) {
subNetCIDRStr: "127.0.0.0/16",
expectedBit: 0,
expectErr: false,
description: "Get 0 Bit with IPv4",
},
{
clusterCIDRStr: "be00::/8",
subNetMaskSize: 16,
subNetCIDRStr: "be00::/16",
expectedBit: 0,
expectErr: false,
description: "Get 0 Bit with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/8",
@ -168,6 +298,15 @@ func TestGetBitforCIDR(t *testing.T) {
subNetCIDRStr: "127.123.0.0/16",
expectedBit: 123,
expectErr: false,
description: "Get 123rd Bit with IPv4",
},
{
clusterCIDRStr: "be00::/8",
subNetMaskSize: 16,
subNetCIDRStr: "beef::/16",
expectedBit: 0xef,
expectErr: false,
description: "Get xef Bit with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/8",
@ -175,6 +314,15 @@ func TestGetBitforCIDR(t *testing.T) {
subNetCIDRStr: "127.168.0.0/16",
expectedBit: 168,
expectErr: false,
description: "Get 168th Bit with IPv4",
},
{
clusterCIDRStr: "be00::/8",
subNetMaskSize: 16,
subNetCIDRStr: "be68::/16",
expectedBit: 0x68,
expectErr: false,
description: "Get x68th Bit with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/8",
@ -182,6 +330,15 @@ func TestGetBitforCIDR(t *testing.T) {
subNetCIDRStr: "127.224.0.0/16",
expectedBit: 224,
expectErr: false,
description: "Get 224th Bit with IPv4",
},
{
clusterCIDRStr: "be00::/8",
subNetMaskSize: 16,
subNetCIDRStr: "be24::/16",
expectedBit: 0x24,
expectErr: false,
description: "Get x24th Bit with IPv6",
},
{
clusterCIDRStr: "192.168.0.0/16",
@ -189,6 +346,15 @@ func TestGetBitforCIDR(t *testing.T) {
subNetCIDRStr: "192.168.12.0/24",
expectedBit: 12,
expectErr: false,
description: "Get 12th Bit with IPv4",
},
{
clusterCIDRStr: "beef::/16",
subNetMaskSize: 24,
subNetCIDRStr: "beef:1200::/24",
expectedBit: 0x12,
expectErr: false,
description: "Get x12th Bit with IPv6",
},
{
clusterCIDRStr: "192.168.0.0/16",
@ -196,41 +362,58 @@ func TestGetBitforCIDR(t *testing.T) {
subNetCIDRStr: "192.168.151.0/24",
expectedBit: 151,
expectErr: false,
description: "Get 151st Bit with IPv4",
},
{
clusterCIDRStr: "beef::/16",
subNetMaskSize: 24,
subNetCIDRStr: "beef:9700::/24",
expectedBit: 0x97,
expectErr: false,
description: "Get x97st Bit with IPv6",
},
{
clusterCIDRStr: "192.168.0.0/16",
subNetMaskSize: 24,
subNetCIDRStr: "127.168.224.0/24",
expectErr: true,
description: "Get error with IPv4",
},
{
clusterCIDRStr: "beef::/16",
subNetMaskSize: 24,
subNetCIDRStr: "2001:db00::/24",
expectErr: true,
description: "Get error with IPv6",
},
}
for _, tc := range cases {
_, clusterCIDR, err := net.ParseCIDR(tc.clusterCIDRStr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
cs := newCIDRSet(clusterCIDR, tc.subNetMaskSize)
_, subnetCIDR, err := net.ParseCIDR(tc.subNetCIDRStr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
got, err := cs.getIndexForCIDR(subnetCIDR)
if err == nil && tc.expectErr {
glog.Errorf("expected error but got null")
glog.Errorf("expected error but got null for %v", tc.description)
continue
}
if err != nil && !tc.expectErr {
glog.Errorf("unexpected error: %v", err)
glog.Errorf("unexpected error: %v for %v", err, tc.description)
continue
}
if got != tc.expectedBit {
glog.Errorf("expected %v, but got %v", tc.expectedBit, got)
glog.Errorf("expected %v, but got %v for %v", tc.expectedBit, got, tc.description)
}
}
}
@ -243,6 +426,7 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin int
expectedUsedEnd int
expectErr bool
description string
}{
{
clusterCIDRStr: "127.0.0.0/8",
@ -251,6 +435,16 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin: 0,
expectedUsedEnd: 255,
expectErr: false,
description: "Occupy all Bits with IPv4",
},
{
clusterCIDRStr: "2001:beef:1200::/40",
subNetMaskSize: 48,
subNetCIDRStr: "2001:beef:1200::/40",
expectedUsedBegin: 0,
expectedUsedEnd: 255,
expectErr: false,
description: "Occupy all Bits with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/8",
@ -259,6 +453,16 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin: 0,
expectedUsedEnd: 255,
expectErr: false,
description: "Occupy every Bit with IPv4",
},
{
clusterCIDRStr: "2001:beef:1200::/40",
subNetMaskSize: 48,
subNetCIDRStr: "2001:beef:1234::/34",
expectedUsedBegin: 0,
expectedUsedEnd: 255,
expectErr: false,
description: "Occupy every Bit with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/8",
@ -267,6 +471,16 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin: 0,
expectedUsedEnd: 0,
expectErr: false,
description: "Occupy 1st Bit with IPv4",
},
{
clusterCIDRStr: "2001:beef:1200::/40",
subNetMaskSize: 48,
subNetCIDRStr: "2001:beef:1200::/48",
expectedUsedBegin: 0,
expectedUsedEnd: 0,
expectErr: false,
description: "Occupy 1st Bit with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/8",
@ -275,6 +489,16 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin: 0,
expectedUsedEnd: 65535,
expectErr: false,
description: "Occupy 65535 Bits with IPv4",
},
{
clusterCIDRStr: "2001:beef:1200::/48",
subNetMaskSize: 64,
subNetCIDRStr: "2001:beef:1200::/48",
expectedUsedBegin: 0,
expectedUsedEnd: 65535,
expectErr: false,
description: "Occupy 65535 Bits with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/7",
@ -283,6 +507,16 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin: 256,
expectedUsedEnd: 257,
expectErr: false,
description: "Occupy 257th Bit with IPv4",
},
{
clusterCIDRStr: "2001:beef:7f00::/39",
subNetMaskSize: 48,
subNetCIDRStr: "2001:beef:7f00::/47",
expectedUsedBegin: 256,
expectedUsedEnd: 257,
expectErr: false,
description: "Occupy 257th Bit with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/7",
@ -291,6 +525,16 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin: 128,
expectedUsedEnd: 128,
expectErr: false,
description: "Occupy 128th Bit with IPv4",
},
{
clusterCIDRStr: "2001:beef:7f00::/39",
subNetMaskSize: 47,
subNetCIDRStr: "2001:beef:7f00::/47",
expectedUsedBegin: 128,
expectedUsedEnd: 128,
expectErr: false,
description: "Occupy 128th Bit with IPv6",
},
{
clusterCIDRStr: "127.0.0.0/7",
@ -299,29 +543,39 @@ func TestOccupy(t *testing.T) {
expectedUsedBegin: 1024,
expectedUsedEnd: 1031,
expectErr: false,
description: "Occupy 1031st Bit with IPv4",
},
{
clusterCIDRStr: "2001:beef:7f00::/39",
subNetMaskSize: 50,
subNetCIDRStr: "2001:beef:7f00::/47",
expectedUsedBegin: 1024,
expectedUsedEnd: 1031,
expectErr: false,
description: "Occupy 1031st Bit with IPv6",
},
}
for _, tc := range cases {
_, clusterCIDR, err := net.ParseCIDR(tc.clusterCIDRStr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
cs := newCIDRSet(clusterCIDR, tc.subNetMaskSize)
_, subnetCIDR, err := net.ParseCIDR(tc.subNetCIDRStr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("unexpected error: %v for %v", err, tc.description)
}
err = cs.occupy(subnetCIDR)
if err == nil && tc.expectErr {
t.Errorf("expected error but got none")
t.Errorf("expected error but got none for %v", tc.description)
continue
}
if err != nil && !tc.expectErr {
t.Errorf("unexpected error: %v", err)
t.Errorf("unexpected error: %v for %v", err, tc.description)
continue
}
@ -330,7 +584,72 @@ func TestOccupy(t *testing.T) {
expectedUsed.SetBit(&expectedUsed, i, 1)
}
if expectedUsed.Cmp(&cs.used) != 0 {
t.Errorf("error")
t.Errorf("error for %v", tc.description)
}
}
}
func TestCIDRSetv6(t *testing.T) {
cases := []struct {
clusterCIDRStr string
subNetMaskSize int
expectedCIDR string
expectedCIDR2 string
expectErr bool
description string
}{
{
clusterCIDRStr: "127.0.0.0/8",
subNetMaskSize: 32,
expectErr: false,
expectedCIDR: "127.0.0.0/32",
expectedCIDR2: "127.0.0.1/32",
description: "Max cluster subnet size with IPv4",
},
{
clusterCIDRStr: "beef:1234::/32",
subNetMaskSize: 49,
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,
expectedCIDR: "2001:beef:1234:3690::/64",
expectedCIDR2: "2001:beef:1234:3691::/64",
expectErr: false,
description: "Allocate a few IPv6",
},
}
for _, tc := range cases {
_, clusterCIDR, _ := net.ParseCIDR(tc.clusterCIDRStr)
a := newCIDRSet(clusterCIDR, tc.subNetMaskSize)
p, err := a.allocateNext()
if err == nil && tc.expectErr {
t.Errorf("expected error but got none for %v", tc.description)
continue
}
if err != nil && !tc.expectErr {
t.Errorf("unexpected error: %v for %v", err, tc.description)
continue
}
if !tc.expectErr {
if p.String() != tc.expectedCIDR {
t.Fatalf("unexpected allocated cidr: %s for %v", p.String(), tc.description)
}
}
p2, err := a.allocateNext()
if !tc.expectErr {
if p2.String() != tc.expectedCIDR2 {
t.Fatalf("unexpected allocated cidr: %s for %v", p2.String(), tc.description)
}
}
}
}