Skip to content

Commit 3b3e283

Browse files
committed
routing: ensure desired routes are in the route table
There is a brief period where the IPv6 CIDR is not yet associated with the subnets. Thus, CAPA initially creates a route table without a route to eigw. This change ensures that later reconcilation will add that missing route. Note: Route to eigw for destination "::/0" to eigw is required for EC2 instance time sync on start-up.
1 parent 1f6e295 commit 3b3e283

File tree

1 file changed

+55
-13
lines changed

1 file changed

+55
-13
lines changed

pkg/cloud/services/network/routetables.go

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ func (s *Service) reconcileRouteTables() error {
8484
}
8585
}
8686

87+
// Make sure desired routes are created in the route table.
88+
if err := s.fixMissingRoutes(routes, rt.Routes, rt); err != nil {
89+
return err
90+
}
91+
8792
// Make sure tags are up-to-date.
8893
if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
8994
buildParams := s.getRouteTableTagParams(aws.ToString(rt.RouteTableId), sn.IsPublic, sn.AvailabilityZone)
@@ -145,7 +150,8 @@ func (s *Service) fixMismatchedRouting(specRoute *ec2.CreateRouteInput, currentR
145150
if (currentRoute.DestinationIpv6CidrBlock != nil &&
146151
aws.ToString(currentRoute.DestinationIpv6CidrBlock) == aws.ToString(specRoute.DestinationIpv6CidrBlock)) &&
147152
((currentRoute.GatewayId != nil && aws.ToString(currentRoute.GatewayId) != aws.ToString(specRoute.GatewayId)) ||
148-
(currentRoute.NatGatewayId != nil && aws.ToString(currentRoute.NatGatewayId) != aws.ToString(specRoute.NatGatewayId))) {
153+
(currentRoute.NatGatewayId != nil && aws.ToString(currentRoute.NatGatewayId) != aws.ToString(specRoute.NatGatewayId)) ||
154+
(currentRoute.EgressOnlyInternetGatewayId != nil && aws.ToString(currentRoute.EgressOnlyInternetGatewayId) != aws.ToString(specRoute.EgressOnlyInternetGatewayId))) {
149155
input = &ec2.ReplaceRouteInput{
150156
RouteTableId: rt.RouteTableId,
151157
DestinationIpv6CidrBlock: specRoute.DestinationIpv6CidrBlock,
@@ -170,6 +176,36 @@ func (s *Service) fixMismatchedRouting(specRoute *ec2.CreateRouteInput, currentR
170176
return nil
171177
}
172178

179+
func (s *Service) fixMissingRoutes(specRoutes []*ec2.CreateRouteInput, currentRoutes []types.Route, rt types.RouteTable) error {
180+
// Routes destination cidr blocks must be unique within a routing table.
181+
// Each route can define either an IPv4 or IPv6 CIDR, but not both.
182+
currRouteMap := make(map[string]types.Route)
183+
for _, route := range currentRoutes {
184+
if route.DestinationCidrBlock != nil {
185+
currRouteMap[aws.ToString(route.DestinationCidrBlock)] = route
186+
}
187+
if route.DestinationIpv6CidrBlock != nil {
188+
currRouteMap[aws.ToString(route.DestinationIpv6CidrBlock)] = route
189+
}
190+
}
191+
192+
routesToAdd := make([]*ec2.CreateRouteInput, 0)
193+
for _, route := range specRoutes {
194+
var dest string
195+
if route.DestinationCidrBlock != nil {
196+
dest = aws.ToString(route.DestinationCidrBlock)
197+
}
198+
if route.DestinationIpv6CidrBlock != nil {
199+
dest = aws.ToString(route.DestinationIpv6CidrBlock)
200+
}
201+
if _, ok := currRouteMap[dest]; !ok {
202+
routesToAdd = append(routesToAdd, route)
203+
}
204+
}
205+
206+
return s.createRoutesForRouteTable(routesToAdd, rt.RouteTableId)
207+
}
208+
173209
func (s *Service) describeVpcRouteTablesBySubnet() (map[string]types.RouteTable, error) {
174210
rts, err := s.describeVpcRouteTables()
175211
if err != nil {
@@ -274,28 +310,34 @@ func (s *Service) createRouteTableWithRoutes(routes []*ec2.CreateRouteInput, isP
274310
record.Eventf(s.scope.InfraCluster(), "SuccessfulCreateRouteTable", "Created managed RouteTable %q", aws.ToString(out.RouteTable.RouteTableId))
275311
s.scope.Info("Created route table", "route-table-id", *out.RouteTable.RouteTableId)
276312

313+
if err := s.createRoutesForRouteTable(routes, out.RouteTable.RouteTableId); err != nil {
314+
if cleanupErr := s.deleteRouteTable(*out.RouteTable); cleanupErr != nil {
315+
record.Warnf(s.scope.InfraCluster(), "FailedDeleteRouteTable", "Failed to delete managed RouteTable %q: %v", aws.ToString(out.RouteTable.RouteTableId), cleanupErr)
316+
}
317+
return nil, err
318+
}
319+
320+
return &infrav1.RouteTable{
321+
ID: *out.RouteTable.RouteTableId,
322+
}, nil
323+
}
324+
325+
func (s *Service) createRoutesForRouteTable(routes []*ec2.CreateRouteInput, routeTableID *string) error {
277326
for i := range routes {
278327
route := routes[i]
279328
if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
280-
route.RouteTableId = out.RouteTable.RouteTableId
329+
route.RouteTableId = routeTableID
281330
if _, err := s.EC2Client.CreateRoute(context.TODO(), route); err != nil {
282331
return false, err
283332
}
284333
return true, nil
285334
}, awserrors.RouteTableNotFound, awserrors.NATGatewayNotFound, awserrors.GatewayNotFound); err != nil {
286-
record.Warnf(s.scope.InfraCluster(), "FailedCreateRoute", "Failed to create route %s for RouteTable %q: %v", route, aws.ToString(out.RouteTable.RouteTableId), err)
287-
errDel := s.deleteRouteTable(*out.RouteTable)
288-
if errDel != nil {
289-
record.Warnf(s.scope.InfraCluster(), "FailedDeleteRouteTable", "Failed to delete managed RouteTable %q: %v", aws.ToString(out.RouteTable.RouteTableId), errDel)
290-
}
291-
return nil, errors.Wrapf(err, "failed to create route in route table %q: %v", aws.ToString(out.RouteTable.RouteTableId), route)
335+
record.Warnf(s.scope.InfraCluster(), "FailedCreateRoute", "Failed to create route %s for RouteTable %q: %v", route, aws.ToString(routeTableID), err)
336+
return errors.Wrapf(err, "failed to create route in route table %q: %v", aws.ToString(routeTableID), route)
292337
}
293-
record.Eventf(s.scope.InfraCluster(), "SuccessfulCreateRoute", "Created route %s for RouteTable %q", route, aws.ToString(out.RouteTable.RouteTableId))
338+
record.Eventf(s.scope.InfraCluster(), "SuccessfulCreateRoute", "Created route %s for RouteTable %q", route, aws.ToString(routeTableID))
294339
}
295-
296-
return &infrav1.RouteTable{
297-
ID: *out.RouteTable.RouteTableId,
298-
}, nil
340+
return nil
299341
}
300342

301343
func (s *Service) associateRouteTable(rt *infrav1.RouteTable, subnetID string) error {

0 commit comments

Comments
 (0)