Skip to content

Commit 7a6aaa1

Browse files
axel7bornhebelsan
andauthored
Allow creation or more that one IPv6 shoot in one VPC (gardener#1403)
* If subnet creation fails due to a conflicting IPv6 range, try the next /64 range. * Address review comments. * Add ensureSubnetIPv6 * Add comment * Update pkg/controller/infrastructure/infraflow/reconcile.go Co-authored-by: Alexander Hebel <alexander.hebel@sap.com> --------- Co-authored-by: Alexander Hebel <alexander.hebel@sap.com>
1 parent 51a9be9 commit 7a6aaa1

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

pkg/controller/infrastructure/infraflow/reconcile.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,11 @@ func (c *FlowContext) addSubnetReconcileTasks(g *flow.Graph, desired, current *a
866866
return nil, err
867867
}
868868
suffix := fmt.Sprintf("%s-%s", zoneName, subnetKey)
869+
if ptr.Deref(desired.AssignIpv6AddressOnCreation, true) {
870+
return c.AddTask(g, "ensure IPv6 subnet "+suffix,
871+
c.ensureSubnetIPv6(subnetKey, desired, current),
872+
Timeout(defaultTimeout)), nil
873+
}
869874
return c.AddTask(g, "ensure subnet "+suffix,
870875
c.ensureSubnet(subnetKey, desired, current),
871876
Timeout(defaultTimeout)), nil
@@ -976,6 +981,55 @@ func (c *FlowContext) ensureSubnet(subnetKey string, desired, current *awsclient
976981
}
977982
}
978983

984+
func (c *FlowContext) ensureSubnetIPv6(subnetKey string, desired, current *awsclient.Subnet) flow.TaskFn {
985+
zoneChild := c.getSubnetZoneChildByItem(desired)
986+
if current == nil {
987+
return func(ctx context.Context) error {
988+
log := LogFromContext(ctx)
989+
log.Info("creating...")
990+
var lastErr error
991+
for attempts := 0; attempts < 256; attempts++ {
992+
created, err := c.client.CreateSubnet(ctx, desired, defaultTimeout)
993+
if err == nil {
994+
zoneChild.Set(subnetKey, created.SubnetId)
995+
return nil
996+
}
997+
// Check for InvalidSubnet.Conflict error
998+
apiErrCode := awsclient.GetAWSAPIErrorCode(err)
999+
if apiErrCode == "InvalidSubnet.Conflict" {
1000+
log.Info("CIDR conflict, trying next CIDR block")
1001+
newCIDRs, nextErr := calcNextIPv6CidrBlock(desired.Ipv6CidrBlocks[0])
1002+
if nextErr != nil {
1003+
return nextErr
1004+
}
1005+
desired.Ipv6CidrBlocks = []string{newCIDRs}
1006+
lastErr = err
1007+
continue
1008+
}
1009+
// Any other error, return immediately
1010+
return err
1011+
}
1012+
// If we exhausted all attempts, return the last error
1013+
if lastErr != nil {
1014+
return lastErr
1015+
}
1016+
return fmt.Errorf("failed to create subnet after multiple attempts")
1017+
}
1018+
}
1019+
return func(ctx context.Context) error {
1020+
zoneChild.Set(subnetKey, current.SubnetId)
1021+
modified, err := c.updater.UpdateSubnet(ctx, desired, current)
1022+
if err != nil {
1023+
return err
1024+
}
1025+
if modified {
1026+
log := LogFromContext(ctx)
1027+
log.Info("updated")
1028+
}
1029+
return nil
1030+
}
1031+
}
1032+
9791033
func (c *FlowContext) ensureSubnetCidrReservation(ctx context.Context) error {
9801034
if !isIPv6(c.getIpFamilies()) {
9811035
return nil
@@ -1964,3 +2018,30 @@ func cidrSubnet(baseCIDR string, newPrefixLength int, index int) (string, error)
19642018
subnetIP := net.IP(big.NewInt(0).Add(big.NewInt(0).SetBytes(baseIP), offset).Bytes())
19652019
return fmt.Sprintf("%s/%d", subnetIP.String(), newPrefixLength), nil
19662020
}
2021+
2022+
// calcNextIPv6CidrBlock returns the next IPv6 /64 subnet CIDR block within the same /56 VPC range.
2023+
// It increments the 8th byte of the IP address (index 7) to generate the next subnet.
2024+
// This is used to avoid subnet conflicts when creating IPv6 subnets.
2025+
// Returns an error if the maximum index (255) is reached or the input CIDR is invalid.
2026+
func calcNextIPv6CidrBlock(currentSubnetCIDR string) (string, error) {
2027+
ip, _, err := net.ParseCIDR(currentSubnetCIDR)
2028+
if err != nil {
2029+
return "", fmt.Errorf("failed to parse CIDR: %v", err)
2030+
}
2031+
2032+
currentIndex := int(ip[7])
2033+
2034+
if currentIndex >= 255 {
2035+
return "", fmt.Errorf("already at maximum index (255) within /56 range")
2036+
}
2037+
2038+
nextIndex := currentIndex + 1
2039+
2040+
nextIP := make(net.IP, 16)
2041+
copy(nextIP, ip)
2042+
nextIP[7] = byte(nextIndex)
2043+
2044+
nextCIDR := fmt.Sprintf("%s/64", nextIP.String())
2045+
2046+
return nextCIDR, nil
2047+
}

0 commit comments

Comments
 (0)