{"record":{"id":"7119cc7ed70a4cee","repo":"tailscale/tailscale","slug":"couldn-t-check-system-s-udp-gro-forwarding-configu-7119cc","errorCode":null,"errorMessage":"couldn't check system's UDP GRO forwarding configuration, failed to retrieve TUN device features: %v","messagePattern":"couldn't check system's UDP GRO forwarding configuration, failed to retrieve TUN device features: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"net/netkernelconf/netkernelconf_linux.go","lineNumber":38,"sourceCode":"// 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\n\t\t// being added to the kernel later than rxWantFeature, but let's be sure\n\t\treturn nil, nil\n\t}\n\tif !defaultHasRxWant || defaultFeatures[rxDoNotWantFeature] {\n\t\treturn fmt.Errorf(\"UDP GRO forwarding is suboptimally configured on %s, UDP forwarding throughput capability will increase with a configuration change.%s\", defaultRouteInterface, kbLink), nil","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/net/netkernelconf/netkernelconf_linux.go#L20-L56","documentation":"The GRO check reads the offload feature bitmap of the Tailscale TUN interface via ethtool.Features and this call failed: the interface name is wrong or absent, the TUN lives in another network namespace, or the TUN driver does not implement ethtool feature reporting.","triggerScenarios":"Passing a TUN interface name that does not exist (check runs before tailscale0 is created), a non-TUN interface name, containerized setups where the TUN device belongs to a different netns, or TUN drivers without ethtool ops.","commonSituations":"Health checks racing with tailscaled startup, custom TUN names (--tun=...), Dockerized tailscaled with mismatched namespaces, swapped argument order.","solutions":["Verify the interface exists first: ip link show <tunInterface>","Run the check after the TUN is up, or pass the actual interface name","Run in the same network namespace as the TUN device"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if _, err := net.InterfaceByName(tunInterface); err != nil {\n return fmt.Errorf(\"TUN interface %q not present: %w\", tunInterface, err)\n}\nwarn, err := netkernelconf.CheckUDPGROForwarding(tunInterface, defaultRouteInterface)","typeGuard":null,"tryCatchPattern":"warn, err := netkernelconf.CheckUDPGROForwarding(tun, def)\nif err != nil && strings.Contains(err.Error(), \"failed to retrieve TUN device features\") {\n // wrong interface name or netns: verify with `ip link` and retry after TUN creation\n log.Printf(\"TUN feature query failed; retry after tailscaled is up: %v\", err)\n}","preventionTips":["Call NIC checks only after the TUN interface is confirmed to exist","Pass interface names obtained from link monitor events, not hardcoded guesses","Run the check in the network namespace that owns the TUN device"],"tags":["linux","ethtool","tun","udp-gro"],"backgroundTag":"ethtool-feature-query-failed","analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}