{"record":{"id":"08802c064e5de44e","repo":"tailscale/tailscale","slug":"couldn-t-check-system-s-udp-gro-forwarding-configu","errorCode":null,"errorMessage":"couldn't check system's UDP GRO forwarding configuration, failed to init ethtool: %v","messagePattern":"couldn't check system's UDP GRO forwarding configuration, failed to init ethtool: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"net/netkernelconf/netkernelconf_linux.go","lineNumber":33,"sourceCode":"\trxWantFeature      = \"rx-udp-gro-forwarding\"\n\trxDoNotWantFeature = \"rx-gro-list\"\n\ttxFeature          = \"tx-udp-segmentation\"\n)\n\n// CheckUDPGROForwarding checks if the machine is optimally configured to\n// forward UDP packets between the default route and Tailscale TUN interfaces.\n// It returns a non-nil warn in the case that the configuration is suboptimal.\n// It returns a non-nil err in the case that an error is encountered while\n// performing the check.\nfunc CheckUDPGROForwarding(tunInterface, defaultRouteInterface string) (warn, err error) {\n\tconst kbLink = \"\\nSee https://tailscale.com/s/ethtool-config-udp-gro\"\n\terrWithPrefix := func(format string, a ...any) error {\n\t\tconst errPrefix = \"couldn't check system's UDP GRO forwarding configuration, \"\n\t\treturn fmt.Errorf(errPrefix+format, a...)\n\t}\n\te, err := ethtool.NewEthtool()\n\tif err != nil {\n\t\treturn nil, errWithPrefix(\"failed to init ethtool: %v\", err)\n\t}\n\tdefer e.Close()\n\ttunFeatures, err := e.Features(tunInterface)\n\tif err != nil {\n\t\treturn nil, errWithPrefix(\"failed to retrieve TUN device features: %v\", err)\n\t}\n\tif !tunFeatures[txFeature] {\n\t\t// if txFeature is disabled/nonexistent on the TUN then UDP GRO\n\t\t// forwarding doesn't matter, we won't be taking advantage of it.\n\t\treturn nil, nil\n\t}\n\tdefaultFeatures, err := e.Features(defaultRouteInterface)\n\tif err != nil {\n\t\treturn nil, errWithPrefix(\"failed to retrieve default route interface features: %v\", err)\n\t}\n\tdefaultHasRxWant, ok := defaultFeatures[rxWantFeature]\n\tif !ok {\n\t\t// unlikely the feature is nonexistent with txFeature in the TUN driver","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/net/netkernelconf/netkernelconf_linux.go#L15-L51","documentation":"CheckUDPGROForwarding probes NIC offload features through the safchain/ethtool netlink library. Its first step opens an ethtool handle; if that fails, the kernel or sandbox does not expose the ethtool generic-netlink family and the check cannot run at all. Tailscale surfaces this on Linux subnet routers/exit nodes as a health warning.","triggerScenarios":"Running tailscaled (or calling this function) under gVisor/runsc, a container whose seccomp profile blocks AF_NETLINK sockets, very old kernels without ethtool netlink support, or stripped-down VMs.","commonSituations":"Kubernetes pods with custom seccomp/apparmor profiles, GKE sandboxed pods, minimal appliance kernels.","solutions":["Allow AF_NETLINK sockets in the container's seccomp policy or run with CAP_NET_ADMIN on a host kernel","Run the check on the host network namespace instead of a restricted sandbox","Upgrade to a kernel with ethtool netlink support","If the environment cannot support it, accept the warning and baseline UDP throughput"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Feature-detect ethtool availability before relying on the check\nif _, err := net.InterfaceByName(tunInterface); err != nil {\n return fmt.Errorf(\"interface %s missing; skip GRO check\", tunInterface)\n}\nwarn, err := netkernelconf.CheckUDPGROForwarding(tunInterface, defaultIf)","typeGuard":null,"tryCatchPattern":"warn, err := netkernelconf.CheckUDPGROForwarding(tun, def)\nif err != nil {\n if strings.Contains(err.Error(), \"failed to init ethtool\") {\n // environment limitation (sandbox/kernel): log once, not fatal\n log.Printf(\"GRO check unavailable in this environment: %v\", err)\n } else {\n return err\n }\n}\nif warn != nil { log.Printf(\"%v\", warn) }","preventionTips":["Run subnet routers on host kernels with AF_NETLINK permitted rather than in gVisor/strict sandboxes","Log CheckUDPGROForwarding errors as health warnings, never as startup failures","Document the seccomp/CAP_NET_ADMIN requirements for containerized tailscaled"],"tags":["linux","ethtool","udp-gro","containers","subnet-router"],"backgroundTag":"ethtool-init-failed","analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}