From 52f16b5d1035c1c3fa2c374eb0fbeac1c14c21f6 Mon Sep 17 00:00:00 2001 From: Andrew Dunham Date: Wed, 14 Feb 2024 19:19:59 -0500 Subject: [PATCH] doctor/ethtool, ipn/ipnlocal: add ethtool bugreport check Updates #11137 Signed-off-by: Andrew Dunham Change-Id: Idbe862d80e428adb044249c47d9096b87f29d5d8 --- cmd/tailscaled/depaware.txt | 3 +- doctor/ethtool/ethtool.go | 23 ++++++++++ doctor/ethtool/ethtool_linux.go | 78 +++++++++++++++++++++++++++++++++ doctor/ethtool/ethtool_other.go | 17 +++++++ ipn/ipnlocal/local.go | 2 + 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 doctor/ethtool/ethtool.go create mode 100644 doctor/ethtool/ethtool_linux.go create mode 100644 doctor/ethtool/ethtool_other.go diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index c354b03c9..87adf447c 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -138,7 +138,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de L github.com/pierrec/lz4/v4/internal/xxh32 from github.com/pierrec/lz4/v4/internal/lz4stream LD github.com/pkg/sftp from tailscale.com/ssh/tailssh LD github.com/pkg/sftp/internal/encoding/ssh/filexfer from github.com/pkg/sftp - L 💣 github.com/safchain/ethtool from tailscale.com/net/netkernelconf + L 💣 github.com/safchain/ethtool from tailscale.com/net/netkernelconf+ W 💣 github.com/tailscale/certstore from tailscale.com/control/controlclient W 💣 github.com/tailscale/go-winio from tailscale.com/safesocket W 💣 github.com/tailscale/go-winio/internal/fs from github.com/tailscale/go-winio @@ -247,6 +247,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/derp/derphttp from tailscale.com/cmd/tailscaled+ tailscale.com/disco from tailscale.com/derp+ tailscale.com/doctor from tailscale.com/ipn/ipnlocal + tailscale.com/doctor/ethtool from tailscale.com/ipn/ipnlocal 💣 tailscale.com/doctor/permissions from tailscale.com/ipn/ipnlocal tailscale.com/doctor/routetable from tailscale.com/ipn/ipnlocal tailscale.com/envknob from tailscale.com/client/tailscale+ diff --git a/doctor/ethtool/ethtool.go b/doctor/ethtool/ethtool.go new file mode 100644 index 000000000..f80b00a51 --- /dev/null +++ b/doctor/ethtool/ethtool.go @@ -0,0 +1,23 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Package ethtool provides a doctor.Check that prints diagnostic information +// obtained from the 'ethtool' utility on the current system. +package ethtool + +import ( + "context" + + "tailscale.com/types/logger" +) + +// Check implements the doctor.Check interface. +type Check struct{} + +func (Check) Name() string { + return "ethtool" +} + +func (Check) Run(_ context.Context, logf logger.Logf) error { + return ethtoolImpl(logf) +} diff --git a/doctor/ethtool/ethtool_linux.go b/doctor/ethtool/ethtool_linux.go new file mode 100644 index 000000000..07a7dd9cc --- /dev/null +++ b/doctor/ethtool/ethtool_linux.go @@ -0,0 +1,78 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package ethtool + +import ( + "net/netip" + "sort" + + "github.com/safchain/ethtool" + "tailscale.com/net/interfaces" + "tailscale.com/types/logger" + "tailscale.com/util/set" +) + +func ethtoolImpl(logf logger.Logf) error { + et, err := ethtool.NewEthtool() + if err != nil { + logf("could not create ethtool: %v", err) + return nil + } + defer et.Close() + + interfaces.ForeachInterface(func(iface interfaces.Interface, _ []netip.Prefix) { + ilogf := logger.WithPrefix(logf, iface.Name+": ") + features, err := et.Features(iface.Name) + if err == nil { + enabled := []string{} + for feature, value := range features { + if value { + enabled = append(enabled, feature) + } + } + sort.Strings(enabled) + ilogf("features: %v", enabled) + } else { + ilogf("features: error: %v", err) + } + + stats, err := et.Stats(iface.Name) + if err == nil { + printStats(ilogf, stats) + } else { + ilogf("stats: error: %v", err) + } + }) + + return nil +} + +// Stats that should be printed if non-zero +var nonzeroStats = set.SetOf([]string{ + // AWS ENA driver statistics; see: + // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-network-performance-ena.html + "bw_in_allowance_exceeded", + "bw_out_allowance_exceeded", + "conntrack_allowance_exceeded", + "linklocal_allowance_exceeded", + "pps_allowance_exceeded", +}) + +// Stats that should be printed if zero +var zeroStats = set.SetOf([]string{ + // AWS ENA driver statistics; see: + // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-network-performance-ena.html + "conntrack_allowance_available", +}) + +func printStats(logf logger.Logf, stats map[string]uint64) { + for name, value := range stats { + if value != 0 && nonzeroStats.Contains(name) { + logf("stats: warning: %s = %d > 0", name, value) + } + if value == 0 && zeroStats.Contains(name) { + logf("stats: warning: %s = %d == 0", name, value) + } + } +} diff --git a/doctor/ethtool/ethtool_other.go b/doctor/ethtool/ethtool_other.go new file mode 100644 index 000000000..9aaa9dda8 --- /dev/null +++ b/doctor/ethtool/ethtool_other.go @@ -0,0 +1,17 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +//go:build !linux + +package ethtool + +import ( + "runtime" + + "tailscale.com/types/logger" +) + +func ethtoolImpl(logf logger.Logf) error { + logf("unsupported on %s/%s", runtime.GOOS, runtime.GOARCH) + return nil +} diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 1f11fa1a1..b8aa769a1 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -39,6 +39,7 @@ import ( "tailscale.com/control/controlclient" "tailscale.com/control/controlknobs" "tailscale.com/doctor" + "tailscale.com/doctor/ethtool" "tailscale.com/doctor/permissions" "tailscale.com/doctor/routetable" "tailscale.com/envknob" @@ -5511,6 +5512,7 @@ func (b *LocalBackend) Doctor(ctx context.Context, logf logger.Logf) { checks = append(checks, permissions.Check{}, routetable.Check{}, + ethtool.Check{}, ) // Print a log message if any of the global DNS resolvers are Tailscale