Skip to content

Commit 5ccdd87

Browse files
committed
ipam: Wait for ENI netlink iface before configuring ingress routes
In ENI IPAM mode the operator creates ENIs asynchronously, so at agent startup the datapath can query netlink for the ifindex of the interface owning a given MAC before that ENI's netlink interface has materialized. Commit 60faea1 added waitForENI() precisely to defeat that race, but it was only wired into the router path (reallocateRouterIPs). The ingress path (allocateIngressIPs) calls RoutingInfo.Configure() with no such guard, so when the ingress IP lives on a secondary ENI that has not shown up yet, retrieveIfIndexFromMAC fails with "interface with MAC <mac> not found". Unlike the router path, the ingress path only warns and swallows the error, and there is no reconciler to retry it, so the missed route is never reinstalled and the stray warning turns check-log-errors red. Mirror the router guard into the ingress path: thread ctx into allocateIngressIPs and, in the IPv4 ENI branch immediately before Configure(), poll waitForENI on the ENI's PrimaryMAC. This is not masking. If the ENI genuinely never appears, waitForENI returns after the same bounded backoff, Configure() still fails, and the warning still fires. Only the transient sub-8s async-creation window is absorbed, which is exactly the window 60faea1 was written to close. The Configure() call also runs in AlibabaCloud ENI mode, and waitForENI just polls netlink for the MAC, so gate the wait on ENI or AlibabaCloud rather than ENI alone, and do the same on the router path so the two stay consistent. Raise the "interface not found" message from warn to error on both paths, since it precedes a route configuration that is about to fail. AIL:3 Signed-off-by: André Martins <andre@cilium.io>
1 parent cb6b7d4 commit 5ccdd87

1 file changed

Lines changed: 15 additions & 7 deletions

File tree

daemon/infraendpoints/infra_ip_allocation.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,11 @@ func (r *infraIPAllocator) reallocateRouterIPs(ctx context.Context, family node.
292292
return nil, fmt.Errorf("failed to create router info: %w", err)
293293
}
294294

295-
// wait for ENI to be up and running before configuring routes and rules.
296-
// This avoids spurious errors where netlink is not able to find
297-
// the ifindex by its MAC because the ENI is not showing up yet.
298-
if r.daemonConfig.IPAM == ipamOption.IPAMENI {
295+
// Wait for the ENI to show up before configuring routes and rules, to
296+
// avoid netlink failing to find the ifindex by its MAC.
297+
if r.daemonConfig.IPAM == ipamOption.IPAMENI || r.daemonConfig.IPAM == ipamOption.IPAMAlibabaCloud {
299298
if err := r.waitForENI(ctx, result.PrimaryMAC); err != nil {
300-
r.logger.Warn("unable to find ENI netlink interface, this will likely lead to an error in configuring the router routes and rules",
299+
r.logger.Error("Unable to find ENI netlink interface, this will likely lead to an error in configuring the router routes and rules",
301300
logfields.MACAddr, result.PrimaryMAC,
302301
)
303302
}
@@ -425,7 +424,7 @@ func (r *infraIPAllocator) allocateHealthIPs(oldV4HealthIP netip.Addr, oldV6Heal
425424
return nil
426425
}
427426

428-
func (r *infraIPAllocator) allocateIngressIPs(oldV4IngressIP net.IP, oldV6IngressIP net.IP) error {
427+
func (r *infraIPAllocator) allocateIngressIPs(ctx context.Context, oldV4IngressIP net.IP, oldV6IngressIP net.IP) error {
429428
if !r.daemonConfig.EnableEnvoyConfig {
430429
return nil
431430
}
@@ -475,6 +474,15 @@ func (r *infraIPAllocator) allocateIngressIPs(oldV4IngressIP net.IP, oldV6Ingres
475474
if ingressRouting, err := r.parseRoutingInfo(result); err != nil {
476475
r.logger.Warn("Unable to allocate ingress information for ENI", logfields.Error, err)
477476
} else {
477+
// The ingress IP may sit on a different ENI than the router IP, so
478+
// wait for its ENI to show up before configuring routes and rules,
479+
// to avoid netlink failing to find the ifindex by its MAC.
480+
if err := r.waitForENI(ctx, result.PrimaryMAC); err != nil {
481+
r.logger.Error("Unable to find ENI netlink interface, this will likely lead to an error in configuring the ingress routes and rules",
482+
logfields.MACAddr, result.PrimaryMAC,
483+
)
484+
}
485+
478486
if err := ingressRouting.Configure(
479487
result.IP,
480488
r.mtuManager.GetDeviceMTU(),
@@ -553,7 +561,7 @@ func (r *infraIPAllocator) AllocateIPs(ctx context.Context) error {
553561
return fmt.Errorf("failed to allocate service loopback IPs: %w", err)
554562
}
555563

556-
if err := r.allocateIngressIPs(localNode.IPv4IngressIP, localNode.IPv6IngressIP); err != nil {
564+
if err := r.allocateIngressIPs(ctx, localNode.IPv4IngressIP, localNode.IPv6IngressIP); err != nil {
557565
return fmt.Errorf("failed to allocate ingress IPs: %w", err)
558566
}
559567

0 commit comments

Comments
 (0)