cilium/cilium · error

unable to lookup link %d: %w

Error message

unable to lookup link %d: %w

What it means

After the netns section succeeds, the plugin (now back in the host netns) resolves the host-side veth by the peer index captured inside the container: netlink.LinkByIndex(peerIndex). If the link cannot be found, this error wraps it. It means the container-side veth's peer is no longer visible from the host, so the plugin cannot learn the host veth name/MAC/index required for the Cilium EndpointChangeRequest.

Source

Thrown at plugins/cilium-cni/chaining/generic-veth/generic-veth.go:180

				if rt.MTU != int(pluginCtx.CiliumConf.RouteMTU) {
					rt.MTU = int(pluginCtx.CiliumConf.RouteMTU)
					err = netlink.RouteReplace(&rt)
					if err != nil {
						err = fmt.Errorf("unable to replace the mtu %d for the route %s: %s", rt.MTU, rt.String(), err.Error())
						return err
					}
				}
			}
		}

		return nil
	}); err != nil {
		return
	}

	peer, err = netlink.LinkByIndex(peerIndex)
	if err != nil {
		err = fmt.Errorf("unable to lookup link %d: %w", peerIndex, err)
		return
	}

	hostMac, _ = mac.FromHardwareAddr(peer.Attrs().HardwareAddr)
	vethHostName = peer.Attrs().Name
	vethHostIdx = peer.Attrs().Index

	switch {
	case vethHostName == "":
		err = errors.New("unable to determine name of veth pair on the host side")
		return
	case !hostMac.IsValid():
		err = errors.New("unable to determine MAC address of veth pair on the host side")
		return
	case !vethLXCMac.IsValid():
		err = errors.New("unable to determine MAC address of veth pair on the container side")
		return
	case vethIP == "" && vethIPv6 == "":

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Retry pod creation — a teardown race resolves itself; check whether the pod's sandbox was being stopped at the same time.
  2. Verify the peer ifindex still exists on the host: ip link | grep <ifindex> and compare with the error's %d value.
  3. Check node memory/netlink health (dmesg for rtnetlink errors); reboot if persistent rtnetlink corruption is seen.
  4. Ensure the runtime isn't concurrently modifying the veth pair (check containerd/CRI logs for the same container ID).
Defensive patterns

Strategy: retry

Try / catch

peer, err := netlink.LinkByIndex(peerIndex)
if err != nil {
    if errors.Is(err, syscall.ENODEV) {
        // host-side peer gone: sandbox teardown race, kubelet will retry
    }
    return fmt.Errorf("unable to lookup link %d: %w", peerIndex, err)
}

Prevention

When it happens

Trigger: netlink.LinkByIndex(peerIndex) in Add() (host netns) returns an error: the peer veth was deleted between VethPeerIndex() inside the container and this lookup (pod teardown race), a stale/incorrect peerIndex, or a netlink dump failure on the host.

Common situations: Kubelet deleting the sandbox while CNI ADD is in flight; move-to-netns operations that destroyed the peer; kernel/netlink bugs after long uptime; running the plugin in an environment where host netlink is restricted (某些 hardened runtimes).

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/8f95634403120b89. Report an issue: GitHub.