tailscale/tailscale · error
couldn't check system's UDP GRO forwarding configuration, fa
Error message
couldn't check system's UDP GRO forwarding configuration, failed to init ethtool: %v
What it means
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.
Source
Thrown at net/netkernelconf/netkernelconf_linux.go:33
rxWantFeature = "rx-udp-gro-forwarding"
rxDoNotWantFeature = "rx-gro-list"
txFeature = "tx-udp-segmentation"
)
// CheckUDPGROForwarding checks if the machine is optimally configured to
// forward UDP packets between the default route and Tailscale TUN interfaces.
// It returns a non-nil warn in the case that the configuration is suboptimal.
// It returns a non-nil err in the case that an error is encountered while
// performing the check.
func CheckUDPGROForwarding(tunInterface, defaultRouteInterface string) (warn, err error) {
const kbLink = "\nSee https://tailscale.com/s/ethtool-config-udp-gro"
errWithPrefix := func(format string, a ...any) error {
const errPrefix = "couldn't check system's UDP GRO forwarding configuration, "
return fmt.Errorf(errPrefix+format, a...)
}
e, err := ethtool.NewEthtool()
if err != nil {
return nil, errWithPrefix("failed to init ethtool: %v", err)
}
defer e.Close()
tunFeatures, err := e.Features(tunInterface)
if err != nil {
return nil, errWithPrefix("failed to retrieve TUN device features: %v", err)
}
if !tunFeatures[txFeature] {
// if txFeature is disabled/nonexistent on the TUN then UDP GRO
// forwarding doesn't matter, we won't be taking advantage of it.
return nil, nil
}
defaultFeatures, err := e.Features(defaultRouteInterface)
if err != nil {
return nil, errWithPrefix("failed to retrieve default route interface features: %v", err)
}
defaultHasRxWant, ok := defaultFeatures[rxWantFeature]
if !ok {
// unlikely the feature is nonexistent with txFeature in the TUN driverView on GitHub (pinned to 6e0912f979)
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
Defensive patterns
Strategy: try-catch
Validate before calling
// Feature-detect ethtool availability before relying on the check
if _, err := net.InterfaceByName(tunInterface); err != nil {
return fmt.Errorf("interface %s missing; skip GRO check", tunInterface)
}
warn, err := netkernelconf.CheckUDPGROForwarding(tunInterface, defaultIf) Try / catch
warn, err := netkernelconf.CheckUDPGROForwarding(tun, def)
if err != nil {
if strings.Contains(err.Error(), "failed to init ethtool") {
// environment limitation (sandbox/kernel): log once, not fatal
log.Printf("GRO check unavailable in this environment: %v", err)
} else {
return err
}
}
if warn != nil { log.Printf("%v", warn) } Prevention
- 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
When it happens
Trigger: 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.
Common situations: Kubernetes pods with custom seccomp/apparmor profiles, GKE sandboxed pods, minimal appliance kernels.
Related errors
- UDP GRO forwarding is suboptimally configured on %s, UDP for
- failed to init ethtool: %w
- couldn't check system's UDP GRO forwarding configuration, fa
- couldn't check system's UDP GRO forwarding configuration, fa
- failed to retrieve TUN device features: %w
AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18).
Data as JSON: /api/errors/08802c064e5de44e.
Report an issue: GitHub.