{"record":{"id":"507d238aa97f8e76","repo":"cilium/cilium","slug":"interface-s-egress-w-507d23","errorCode":null,"errorMessage":"interface %s egress: %w","messagePattern":"interface (.+?) egress: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/datapath/loader/host.go","lineNumber":137,"sourceCode":"\t\treturn err\n\t}\n\tdefer cleanup()\n\tdefer hostObj.Close()\n\n\t// Insert host endpoint policy program.\n\tif err := hostObj.PolicyMap.Update(uint32(ep.GetID()), hostObj.PolicyProg, ebpf.UpdateAny); err != nil {\n\t\treturn fmt.Errorf(\"inserting host endpoint policy program: %w\", err)\n\t}\n\n\t// Attach cil_to_host to cilium_host ingress.\n\tif err := attachSKBProgram(logger, host, hostObj.ToHost, symbolToHostEp,\n\t\tbpffsDeviceLinksDir(bpf.CiliumPath(), host), netlink.HANDLE_MIN_INGRESS, option.Config.EnableTCX); err != nil {\n\t\treturn fmt.Errorf(\"interface %s ingress: %w\", ep.InterfaceName(), err)\n\t}\n\t// Attach cil_from_host to cilium_host egress.\n\tif err := attachSKBProgram(logger, host, hostObj.FromHost, symbolFromHostEp,\n\t\tbpffsDeviceLinksDir(bpf.CiliumPath(), host), netlink.HANDLE_MIN_EGRESS, option.Config.EnableTCX); err != nil {\n\t\treturn fmt.Errorf(\"interface %s egress: %w\", ep.InterfaceName(), err)\n\t}\n\n\tif err := commit(); err != nil {\n\t\treturn fmt.Errorf(\"committing bpf pins: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// ciliumNetConfigs holds functions that yield a BPF configuration object for\n// cilium_net.\nvar ciliumNetConfigs funcRegistry[func(endpoint.Config, *config.Config, netlink.Link) any]\n\n// ciliumNetRenames holds functions that yield BPF map renames for cilium_net.\nvar ciliumNetRenames funcRegistry[func(endpoint.Config, *config.Config, netlink.Link) map[string]string]\n\n// ciliumNetConfiguration returns a slice of BPF configuration objects yielded\n// by all registered config providers of [ciliumNetConfigs].","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/datapath/loader/host.go#L119-L155","documentation":"Same family as the ingress failure but for the egress direction: attachSKBProgram failed attaching cil_from_host to cilium_host egress (HANDLE_MIN_EGRESS), wrapped as 'interface %s egress'. It indicates outbound-from-host traffic will not traverse the Cilium BPF programs, breaking host-originated traffic handling. Inner causes mirror the ingress case (qdisc, tcx, pinning, program load).","triggerScenarios":"attachCiliumHost's second attachSKBProgram call (hostObj.FromHost, symbolFromHostEp, netlink.HANDLE_MIN_EGRESS, option.Config.EnableTCX) errors after ingress succeeded: egress hook unsupported, tcx egress link creation fails, bpffs pin conflict for the egress link path, or EPERM on qdisc operation.","commonSituations":"Half-attached state after a partial failure (ingress OK, egress fails) leaving stale ingress links to clean; kernel without egress tc support combined with --enable-tcx; pinned egress links left from a previous agent version under /sys/fs/bpf/cilium; netlink qdisc churn during node network reconfiguration.","solutions":["Check `tc filter show dev cilium_host egress` for stale or conflicting filters; `tc qdisc del dev cilium_host clsact` and let the agent recreate it.","Verify kernel support for the chosen attach mode; disable --enable-tcx on kernels < 6.6.","Clear stale egress link pins under the device's bpffs links dir and restart the agent for a clean attach.","Confirm CAP_NET_ADMIN/CAP_BPF privileges for egress qdisc and link operations.","Inspect errors.Is/Unwrap on the wrapped error to distinguish EEXIST (stale pin) from EPERM (permissions) before cleanup."],"exampleFix":"// before: reload leaves half-attached device after egress failure\n// agent logs: attaching cilium_host: interface cilium_host egress: ...\n\n// after: clean device hooks before retrying reload\nexec.Command(\"tc\", \"qdisc\", \"del\", \"dev\", \"cilium_host\", \"clsact\").Run()\nos.RemoveAll(bpffsDeviceLinksDir(\"/sys/fs/bpf/cilium\", host))\n// then restart cilium-agent to re-run reloadHostEndpoint","handlingStrategy":"retry","validationCode":"// Pre-check both hooks before reload to avoid half-attached state\nfunc canAttachBothDirections(dev string, enableTCX bool) error {\n    if enableTCX && !kernelHasTCX() {\n        return errors.New(\"tcx egress unsupported on this kernel\")\n    }\n    filters, err := safenetlink.FilterList(nil, netlink.MakeHandle(0xffff, 0))\n    if err != nil {\n        return fmt.Errorf(\"cannot inspect egress filters: %w\", err)\n    }\n    _ = filters\n    return nil\n}","typeGuard":"func isEgressAttachError(err error) bool {\n    return strings.Contains(err.Error(), \"egress\") &&\n        (errors.Is(err, unix.EEXIST) || errors.Is(err, unix.EPERM) ||\n         errors.Is(err, unix.ENOSYS))\n}","tryCatchPattern":"if err := reload(); err != nil {\n    if isEgressAttachError(err) {\n        // clean egress hook and retry with backoff\n        detachEgress(\"cilium_host\")\n        err = retryWithBackoff(reload, 3)\n    }\n    if err != nil {\n        // last resort: full datapath resync\n        triggerFullDatapathResync()\n    }\n}","preventionTips":["Retry with backoff — egress attach can fail transiently during qdisc churn.","After a failed reload, clean both ingress and egress hooks to avoid half-attached devices.","Keep kernel and --enable-tcx setting aligned (6.6+ for TCX).","Remove stale egress link pins before agent restarts after crashes.","Monitor 'interface %s egress' errors as indicators of node network reconfiguration conflicts."],"tags":["ebpf","tc","tcx","cilium","qdisc","network"],"backgroundTag":"tc-program-attach-failed","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}