{"record":{"id":"c443d79e01e8a961","repo":"cilium/cilium","slug":"updating-tcx-program-w","errorCode":null,"errorMessage":"updating tcx program: %w","messagePattern":"updating tcx program: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/datapath/loader/tcx.go","lineNumber":44,"sourceCode":"\tcase netlink.HANDLE_MIN_INGRESS:\n\t\treturn ebpf.AttachTCXIngress\n\tcase netlink.HANDLE_MIN_EGRESS:\n\t\treturn ebpf.AttachTCXEgress\n\t}\n\tpanic(fmt.Sprintf(\"invalid tc direction: %d\", parent))\n}\n\n// upsertTCXProgram updates or creates a new tcx attachment for prog to device.\n// Returns [link.ErrNotSupported] if tcx is not supported on the node.\nfunc upsertTCXProgram(logger *slog.Logger, device netlink.Link, prog *ebpf.Program, progName, bpffsDir string, parent uint32) error {\n\terr := updateTCX(logger, prog, progName, bpffsDir)\n\tif err == nil {\n\t\t// Link was updated, nothing left to do.\n\t\treturn nil\n\t}\n\tif !errors.Is(err, os.ErrNotExist) {\n\t\t// Unrecoverable error, surface to the caller.\n\t\treturn fmt.Errorf(\"updating tcx program: %w\", err)\n\t}\n\n\treturn attachTCX(logger, device, prog, progName, bpffsDir, parentToAttachType(parent))\n}\n\n// attachTCX creates a new tcx attachment for prog to device at the given attach\n// type. It pins the resulting link object to progName in bpffsDir.\n//\n// progName is typically the Program's key in CollectionSpec.Programs.\nfunc attachTCX(logger *slog.Logger, device netlink.Link, prog *ebpf.Program, progName, bpffsDir string, attach ebpf.AttachType) error {\n\tif err := bpf.MkdirBPF(bpffsDir); err != nil {\n\t\treturn fmt.Errorf(\"creating bpffs link dir for tcx attachment to device %s: %w\", device.Attrs().Name, err)\n\t}\n\n\tl, err := link.AttachTCX(link.TCXOptions{\n\t\tProgram:   prog,\n\t\tAttach:    attach,\n\t\tInterface: device.Attrs().Index,","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/datapath/loader/tcx.go#L26-L62","documentation":"upsertTCXProgram wraps errors from updateTCX that are neither successful updates nor os.ErrNotExist (missing/defunct pin). Such an error means an existing pinned tcx link could not be inspected or updated, so the upsert aborts instead of attaching a new link.","triggerScenarios":"attachSKBProgram with tcxEnabled calls upsertTCXProgram; bpf.UpdateLink on bpffsDir/progName fails with something other than ENOLINK or ErrNotExist — e.g. pin path is a corrupt file, bpffs I/O error, or permission denied opening the pinned link.","commonSituations":"Corrupted bpffs state after node crash, bpffs mount mismatch between restarts, permission/capability loss, wrong pin path due to config change of the bpffs directory.","solutions":["Inspect the pin: bpftool link show pinned <bpffsDir>/<progName>; remove a corrupt pin and restart the agent.","Verify bpffs is mounted correctly and writable, and the agent holds CAP_SYS_ADMIN.","If the pin path changed (config/env), align the bpffs directory configuration with what is on disk.","As a fallback, disable tcx (run with legacy tc) if the kernel cannot support tcx links."],"exampleFix":"// before: corrupt pin breaks update\n$ bpftool link show pinned /sys/fs/bpf/cilium/tcx_from_netdev\nError: can't get link info\n// after\n$ rm /sys/fs/bpf/cilium/tcx_from_netdev && cilium-agent restart","handlingStrategy":"try-catch","validationCode":"// Probe the pin before upsert\nif _, err := os.Stat(filepath.Join(bpffsDir, progName)); err == nil {\n    if _, err := link.LoadPinnedLink(filepath.Join(bpffsDir, progName), nil); err != nil {\n        os.Remove(filepath.Join(bpffsDir, progName)) // corrupt pin\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := upsertTCXProgram(logger, device, prog, progName, bpffsDir, parent); err != nil {\n    if !errors.Is(err, link.ErrNotSupported) && !errors.Is(err, os.ErrNotExist) {\n        logger.Error(\"tcx update failed\", \"pin\", filepath.Join(bpffsDir, progName), \"err\", err)\n        os.Remove(filepath.Join(bpffsDir, progName)) // drop corrupt pin and retry\n    }\n    return err\n}","preventionTips":["Validate bpffs integrity at agent startup.","Keep the bpffs directory config consistent across restarts.","Ensure CAP_SYS_ADMIN for link operations.","Clean pins left by previous Cilium versions."],"tags":["ebpf","bpffs","tcx","cilium"],"backgroundTag":"tcx-link-update-failed","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}