diff --git a/cli/support.go b/cli/support.go index f66bcda13ba6f..5dfe7a45a151b 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 d9bee0fb2fb20..d53aac66c820c 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 380a6a71ff1ca..6f4365aaeefac 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 af3ad21200d02..5ae48ddb37cba 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 55eb6a1f23bd9..cdd62ceeb8f9b 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")