Split network CIDR into even bigger subnets

This commit is contained in:
Ciprian Hacman 2023-08-20 17:52:26 +03:00
parent fc30975eba
commit 879bb604b9
3 changed files with 49 additions and 37 deletions

View File

@ -45,6 +45,11 @@ func BelongsTo(parent *net.IPNet, child *net.IPNet) bool {
return childMasked.Equal(parentMasked) return childMasked.Equal(parentMasked)
} }
// SplitInto1 splits the parent IPNet into 1 subnet
func SplitInto1(parent *net.IPNet) ([]*net.IPNet, error) {
return SplitInto(0, parent)
}
// SplitInto2 splits the parent IPNet into 2 subnets // SplitInto2 splits the parent IPNet into 2 subnets
func SplitInto2(parent *net.IPNet) ([]*net.IPNet, error) { func SplitInto2(parent *net.IPNet) ([]*net.IPNet, error) {
return SplitInto(1, parent) return SplitInto(1, parent)
@ -61,13 +66,9 @@ func SplitInto8(parent *net.IPNet) ([]*net.IPNet, error) {
} }
// SplitInto splits the parent IPNet into subnets with the specified number of additional bits in the prefix. // SplitInto splits the parent IPNet into subnets with the specified number of additional bits in the prefix.
func SplitInto(additionalBits int, parent *net.IPNet) ([]*net.IPNet, error) { func SplitInto(additionalBits uint, parent *net.IPNet) ([]*net.IPNet, error) {
if additionalBits < 1 || additionalBits > 3 {
return nil, fmt.Errorf("additionalBits value must be between 1 and 3, not %d", additionalBits)
}
networkLength, _ := parent.Mask.Size() networkLength, _ := parent.Mask.Size()
networkLength += additionalBits networkLength += int(additionalBits)
var subnets []*net.IPNet var subnets []*net.IPNet
for i := 0; i < 1<<additionalBits; i++ { for i := 0; i < 1<<additionalBits; i++ {

View File

@ -131,10 +131,21 @@ func assignCIDRsToSubnets(c *kops.Cluster, cloud fi.Cloud) error {
} }
} }
// Assign a consistent order
sort.Sort(ByZone(bigSubnets))
sort.Sort(ByZone(littleSubnets))
// Check how many subnet slices are needed
cidrCount := len(bigSubnets)
if len(littleSubnets) > 0 {
cidrCount += 1
}
var bigCIDRs []*net.IPNet var bigCIDRs []*net.IPNet
if len(bigSubnets)+1 <= 2 { if cidrCount <= 1 {
bigCIDRs, err = subnet.SplitInto1(cidr)
} else if cidrCount <= 2 {
bigCIDRs, err = subnet.SplitInto2(cidr) bigCIDRs, err = subnet.SplitInto2(cidr)
} else if len(bigSubnets)+1 <= 4 { } else if cidrCount <= 4 {
bigCIDRs, err = subnet.SplitInto4(cidr) bigCIDRs, err = subnet.SplitInto4(cidr)
} else { } else {
bigCIDRs, err = subnet.SplitInto8(cidr) bigCIDRs, err = subnet.SplitInto8(cidr)
@ -164,16 +175,30 @@ func assignCIDRsToSubnets(c *kops.Cluster, cloud fi.Cloud) error {
return fmt.Errorf("could not find any non-overlapping CIDRs in parent NetworkCIDR; cannot automatically assign CIDR to subnet") return fmt.Errorf("could not find any non-overlapping CIDRs in parent NetworkCIDR; cannot automatically assign CIDR to subnet")
} }
littleCIDRs, err := subnet.SplitInto8(bigCIDRs[0]) // Assign CIDRs to little subnets
if err != nil { if len(littleSubnets) > 0 {
return err littleCIDRs, err := subnet.SplitInto8(bigCIDRs[0])
if err != nil {
return err
}
bigCIDRs = bigCIDRs[1:]
for _, subnet := range littleSubnets {
if subnet.CIDR != "" {
continue
}
if len(littleCIDRs) == 0 {
return fmt.Errorf("insufficient (little) CIDRs remaining for automatic CIDR allocation to subnet %q", subnet.Name)
}
subnet.CIDR = littleCIDRs[0].String()
klog.Infof("Assigned CIDR %s to subnet %s", subnet.CIDR, subnet.Name)
littleCIDRs = littleCIDRs[1:]
}
} }
bigCIDRs = bigCIDRs[1:]
// Assign a consistent order
sort.Sort(ByZone(bigSubnets))
sort.Sort(ByZone(littleSubnets))
// Assign CIDRs to big subnets
for _, subnet := range bigSubnets { for _, subnet := range bigSubnets {
if subnet.CIDR != "" { if subnet.CIDR != "" {
continue continue
@ -191,20 +216,6 @@ func assignCIDRsToSubnets(c *kops.Cluster, cloud fi.Cloud) error {
bigCIDRs = bigCIDRs[1:] bigCIDRs = bigCIDRs[1:]
} }
for _, subnet := range littleSubnets {
if subnet.CIDR != "" {
continue
}
if len(littleCIDRs) == 0 {
return fmt.Errorf("insufficient (little) CIDRs remaining for automatic CIDR allocation to subnet %q", subnet.Name)
}
subnet.CIDR = littleCIDRs[0].String()
klog.Infof("Assigned CIDR %s to subnet %s", subnet.CIDR, subnet.Name)
littleCIDRs = littleCIDRs[1:]
}
return nil return nil
} }

View File

@ -39,35 +39,35 @@ func Test_AssignSubnets(t *testing.T) {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
{Name: "a", Zone: "a", CIDR: "", Type: kops.SubnetTypePublic}, {Name: "a", Zone: "a", CIDR: "", Type: kops.SubnetTypePublic},
}, },
expected: []string{"10.128.0.0/9"}, expected: []string{"10.0.0.0/8"},
}, },
{ {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
{Name: "a", Zone: "a", CIDR: "", Type: kops.SubnetTypePublic}, {Name: "a", Zone: "a", CIDR: "", Type: kops.SubnetTypePublic},
{Name: "b", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic}, {Name: "b", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic},
}, },
expected: []string{"10.64.0.0/10", "10.128.0.0/10"}, expected: []string{"10.0.0.0/9", "10.128.0.0/9"},
}, },
{ {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
{Name: "a", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic}, {Name: "a", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic},
{Name: "b", Zone: "a", CIDR: "", Type: kops.SubnetTypePublic}, {Name: "b", Zone: "a", CIDR: "", Type: kops.SubnetTypePublic},
}, },
expected: []string{"10.128.0.0/10", "10.64.0.0/10"}, expected: []string{"10.128.0.0/9", "10.0.0.0/9"},
}, },
{ {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
{Name: "a", Zone: "a", CIDR: "10.64.0.0/11", Type: kops.SubnetTypePublic}, {Name: "a", Zone: "a", CIDR: "10.64.0.0/11", Type: kops.SubnetTypePublic},
{Name: "b", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic}, {Name: "b", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic},
}, },
expected: []string{"10.64.0.0/11", "10.128.0.0/10"}, expected: []string{"10.64.0.0/11", "10.128.0.0/9"},
}, },
{ {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
{Name: "a", Zone: "a", CIDR: "10.0.0.0/9", Type: kops.SubnetTypePublic}, {Name: "a", Zone: "a", CIDR: "10.0.0.0/9", Type: kops.SubnetTypePublic},
{Name: "b", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic}, {Name: "b", Zone: "b", CIDR: "", Type: kops.SubnetTypePublic},
}, },
expected: []string{"10.0.0.0/9", "10.192.0.0/10"}, expected: []string{"10.0.0.0/9", "10.128.0.0/9"},
}, },
{ {
@ -94,7 +94,7 @@ func Test_AssignSubnets(t *testing.T) {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
{Name: "a", Zone: "a", CIDR: "", Type: kops.SubnetTypePrivate}, {Name: "a", Zone: "a", CIDR: "", Type: kops.SubnetTypePrivate},
}, },
expected: []string{"10.128.0.0/9"}, expected: []string{"10.0.0.0/8"},
}, },
{ {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
@ -106,7 +106,7 @@ func Test_AssignSubnets(t *testing.T) {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{
{Name: "a", Zone: "a", CIDR: "", IPv6CIDR: "/64#0", Type: kops.SubnetTypeDualStack}, {Name: "a", Zone: "a", CIDR: "", IPv6CIDR: "/64#0", Type: kops.SubnetTypeDualStack},
}, },
expected: []string{"10.128.0.0/9"}, expected: []string{"10.0.0.0/8"},
}, },
{ {
subnets: []kops.ClusterSubnetSpec{ subnets: []kops.ClusterSubnetSpec{