diff --git a/cli/support.go b/cli/support.go index f66bcda13b..5dfe7a45a1 100644 --- a/cli/support.go +++ b/cli/support.go @@ -254,6 +254,7 @@ func writeBundle(src *support.Bundle, dest *zip.Writer) error { "deployment/health.json": src.Deployment.HealthReport, "network/connection_info.json": src.Network.ConnectionInfo, "network/netcheck.json": src.Network.Netcheck, + "network/interfaces.json": src.Network.Interfaces, "workspace/template.json": src.Workspace.Template, "workspace/template_version.json": src.Workspace.TemplateVersion, "workspace/parameters.json": src.Workspace.Parameters, diff --git a/cli/support_test.go b/cli/support_test.go index d9bee0fb2f..d53aac66c8 100644 --- a/cli/support_test.go +++ b/cli/support_test.go @@ -197,6 +197,10 @@ func assertBundleContents(t *testing.T, path string, wantWorkspace bool, wantAge var v derphealth.Report decodeJSONFromZip(t, f, &v) require.NotEmpty(t, v, "netcheck should not be empty") + case "network/interfaces.json": + var v healthsdk.InterfacesReport + decodeJSONFromZip(t, f, &v) + require.NotEmpty(t, v, "interfaces should not be empty") case "workspace/workspace.json": var v codersdk.Workspace decodeJSONFromZip(t, f, &v) diff --git a/codersdk/healthsdk/interfaces.go b/codersdk/healthsdk/interfaces.go index 380a6a71ff..6f4365aaee 100644 --- a/codersdk/healthsdk/interfaces.go +++ b/codersdk/healthsdk/interfaces.go @@ -8,6 +8,13 @@ import ( "github.com/coder/coder/v2/coderd/healthcheck/health" ) +// gVisor is nominally permitted to send packets up to 1280. +// Wireguard adds 30 bytes (1310) +// UDP adds 8 bytes (1318) +// IP adds 20-60 bytes (1338-1378) +// So, it really needs to be 1378 to be totally safe +const safeMTU = 1378 + // @typescript-ignore InterfacesReport type InterfacesReport struct { BaseReport @@ -61,11 +68,11 @@ func generateInterfacesReport(st *interfaces.State) (report InterfacesReport) { continue } report.Interfaces = append(report.Interfaces, healthIface) - if iface.MTU < 1378 { + if iface.MTU < safeMTU { report.Severity = health.SeverityWarning report.Warnings = append(report.Warnings, health.Messagef(health.CodeInterfaceSmallMTU, - "network interface %s has MTU %d (less than 1378), which may cause problems with direct connections", iface.Name, iface.MTU), + "network interface %s has MTU %d (less than %d), which may cause problems with direct connections", iface.Name, iface.MTU, safeMTU), ) } } diff --git a/support/support.go b/support/support.go index af3ad21200..5ae48ddb37 100644 --- a/support/support.go +++ b/support/support.go @@ -47,9 +47,10 @@ type Deployment struct { type Network struct { ConnectionInfo workspacesdk.AgentConnectionInfo - CoordinatorDebug string `json:"coordinator_debug"` - Netcheck *derphealth.Report `json:"netcheck"` - TailnetDebug string `json:"tailnet_debug"` + CoordinatorDebug string `json:"coordinator_debug"` + Netcheck *derphealth.Report `json:"netcheck"` + TailnetDebug string `json:"tailnet_debug"` + Interfaces healthsdk.InterfacesReport `json:"interfaces"` } type Netcheck struct { @@ -194,6 +195,15 @@ func NetworkInfo(ctx context.Context, client *codersdk.Client, log slog.Logger) return nil }) + eg.Go(func() error { + rpt, err := healthsdk.RunInterfacesReport() + if err != nil { + return xerrors.Errorf("run interfaces report: %w", err) + } + n.Interfaces = rpt + return nil + }) + if err := eg.Wait(); err != nil { log.Error(ctx, "fetch network information", slog.Error(err)) } diff --git a/support/support_test.go b/support/support_test.go index 55eb6a1f23..cdd62ceeb8 100644 --- a/support/support_test.go +++ b/support/support_test.go @@ -66,6 +66,7 @@ func TestRun(t *testing.T) { assertNotNilNotEmpty(t, bun.Network.CoordinatorDebug, "network coordinator debug should be present") assertNotNilNotEmpty(t, bun.Network.Netcheck, "network netcheck should be present") assertNotNilNotEmpty(t, bun.Network.TailnetDebug, "network tailnet debug should be present") + assertNotNilNotEmpty(t, bun.Network.Interfaces, "network interfaces health should be present") assertNotNilNotEmpty(t, bun.Workspace.Workspace, "workspace should be present") assertSanitizedWorkspace(t, bun.Workspace.Workspace) assertNotNilNotEmpty(t, bun.Workspace.BuildLogs, "workspace build logs should be present") @@ -114,6 +115,7 @@ func TestRun(t *testing.T) { assertNotNilNotEmpty(t, bun.Network.CoordinatorDebug, "network coordinator debug should be present") assertNotNilNotEmpty(t, bun.Network.Netcheck, "network netcheck should be present") assertNotNilNotEmpty(t, bun.Network.TailnetDebug, "network tailnet debug should be present") + assertNotNilNotEmpty(t, bun.Network.Interfaces, "network interfaces health should be present") assert.Empty(t, bun.Workspace.Workspace, "did not expect workspace to be present") assert.Empty(t, bun.Agent, "did not expect agent to be present") assertNotNilNotEmpty(t, bun.Logs, "bundle logs should be present")