Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit94b740d

Browse files
committed
feat: add interface report to coder netcheck
1 parenta11f8b0 commit94b740d

File tree

7 files changed

+297
-5
lines changed

7 files changed

+297
-5
lines changed

‎cli/netcheck.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"fmt"
77
"time"
88

9+
"github.com/coder/coder/v2/codersdk/healthsdk"
10+
911
"golang.org/x/xerrors"
1012

1113
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
@@ -34,11 +36,21 @@ func (r *RootCmd) netcheck() *serpent.Command {
3436

3537
_,_=fmt.Fprint(inv.Stderr,"Gathering a network report. This may take a few seconds...\n\n")
3638

37-
varreport derphealth.Report
38-
report.Run(ctx,&derphealth.ReportOptions{
39+
varderpReport derphealth.Report
40+
derpReport.Run(ctx,&derphealth.ReportOptions{
3941
DERPMap:connInfo.DERPMap,
4042
})
4143

44+
ifReport,err:=healthsdk.RunInterfacesReport()
45+
iferr!=nil {
46+
returnxerrors.Errorf("failed to run interfaces report: %w",err)
47+
}
48+
49+
report:= healthsdk.ClientNetcheckReport{
50+
DERP:healthsdk.DERPHealthReport(derpReport),
51+
Interfaces:ifReport,
52+
}
53+
4254
raw,err:=json.MarshalIndent(report,""," ")
4355
iferr!=nil {
4456
returnerr

‎cli/netcheck_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ func TestNetcheck(t *testing.T) {
2626

2727
b:=out.Bytes()
2828
t.Log(string(b))
29-
varreport healthsdk.DERPHealthReport
29+
varreport healthsdk.ClientNetcheckReport
3030
require.NoError(t,json.Unmarshal(b,&report))
3131

3232
// We do not assert that the report is healthy, just that
3333
// it has the expected number of reports per region.
34-
require.Len(t,report.Regions,1+1)// 1 built-in region + 1 test-managed STUN region
35-
for_,v:=rangereport.Regions {
34+
require.Len(t,report.DERP.Regions,1+1)// 1 built-in region + 1 test-managed STUN region
35+
for_,v:=rangereport.DERP.Regions {
3636
require.Len(t,v.NodeReports,len(v.Region.Nodes))
3737
}
3838
}

‎coderd/healthcheck/health/model.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const (
4343
CodeProvisionerDaemonsNoProvisionerDaemonsCode=`EPD01`
4444
CodeProvisionerDaemonVersionMismatchCode=`EPD02`
4545
CodeProvisionerDaemonAPIMajorVersionDeprecatedCode=`EPD03`
46+
47+
CodeInterfaceSmallMTU=`EIF01`
4648
)
4749

4850
// Default docs URL

‎codersdk/healthsdk/healthsdk.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,8 @@ type WorkspaceProxyReport struct {
269269
BaseReport
270270
WorkspaceProxies codersdk.RegionsResponse[codersdk.WorkspaceProxy]`json:"workspace_proxies"`
271271
}
272+
273+
typeClientNetcheckReportstruct {
274+
DERPDERPHealthReport`json:"derp"`
275+
InterfacesInterfacesReport`json:"interfaces"`
276+
}

‎codersdk/healthsdk/interfaces.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package healthsdk
2+
3+
import (
4+
"net"
5+
6+
"tailscale.com/net/interfaces"
7+
8+
"github.com/coder/coder/v2/coderd/healthcheck/health"
9+
)
10+
11+
typeInterfacesReportstruct {
12+
BaseReport
13+
Interfaces []Interface`json:"interfaces"`
14+
}
15+
16+
typeInterfacestruct {
17+
Namestring`json:"name"`
18+
MTUint`json:"mtu"`
19+
Addresses []string`json:"addresses"`
20+
}
21+
22+
funcRunInterfacesReport() (InterfacesReport,error) {
23+
st,err:=interfaces.GetState()
24+
iferr!=nil {
25+
returnInterfacesReport{},err
26+
}
27+
returngenerateInterfacesReport(st),nil
28+
}
29+
30+
funcgenerateInterfacesReport(st*interfaces.State) (reportInterfacesReport) {
31+
report.Severity=health.SeverityOK
32+
forname,iface:=rangest.Interface {
33+
// macOS has a ton of random interfaces, so to keep things helpful, let's filter out any
34+
// that:
35+
//
36+
// - are not enabled
37+
// - don't have any addresses
38+
// - have only link-local addresses (e.g. fe80:...)
39+
if (iface.Flags&net.FlagUp)==0 {
40+
continue
41+
}
42+
addrs:=st.InterfaceIPs[name]
43+
iflen(addrs)==0 {
44+
continue
45+
}
46+
varrbool
47+
healthIface:=Interface{
48+
Name:iface.Name,
49+
MTU:iface.MTU,
50+
}
51+
for_,addr:=rangeaddrs {
52+
healthIface.Addresses=append(healthIface.Addresses,addr.String())
53+
ifaddr.Addr().IsLinkLocalUnicast()||addr.Addr().IsLinkLocalMulticast() {
54+
continue
55+
}
56+
r=true
57+
}
58+
if!r {
59+
continue
60+
}
61+
report.Interfaces=append(report.Interfaces,healthIface)
62+
ififace.MTU<1378 {
63+
report.Severity=health.SeverityWarning
64+
report.Warnings=append(report.Warnings,
65+
health.Messagef(health.CodeInterfaceSmallMTU,
66+
"network interface %s has MTU %d (less than 1378), which may cause problems with direct connections",iface.Name,iface.MTU),
67+
)
68+
}
69+
}
70+
returnreport
71+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package healthsdk
2+
3+
import (
4+
"net"
5+
"net/netip"
6+
"strings"
7+
"testing"
8+
9+
"github.com/stretchr/testify/require"
10+
"golang.org/x/exp/slices"
11+
"tailscale.com/net/interfaces"
12+
13+
"github.com/coder/coder/v2/coderd/healthcheck/health"
14+
)
15+
16+
funcTest_generateInterfacesReport(t*testing.T) {
17+
t.Parallel()
18+
testCases:= []struct {
19+
namestring
20+
state interfaces.State
21+
severity health.Severity
22+
expectedInterfaces []string
23+
expectedWarnings []string
24+
}{
25+
{
26+
name:"Empty",
27+
state: interfaces.State{},
28+
severity:health.SeverityOK,
29+
expectedInterfaces: []string{},
30+
},
31+
{
32+
name:"Normal",
33+
state: interfaces.State{
34+
Interface:map[string]interfaces.Interface{
35+
"en0": {Interface:&net.Interface{
36+
MTU:1500,
37+
Name:"en0",
38+
Flags:net.FlagUp,
39+
}},
40+
"lo0": {Interface:&net.Interface{
41+
MTU:65535,
42+
Name:"lo0",
43+
Flags:net.FlagUp,
44+
}},
45+
},
46+
InterfaceIPs:map[string][]netip.Prefix{
47+
"en0": {
48+
netip.MustParsePrefix("192.168.100.1/24"),
49+
netip.MustParsePrefix("fe80::c13:1a92:3fa5:dd7e/64"),
50+
},
51+
"lo0": {
52+
netip.MustParsePrefix("127.0.0.1/8"),
53+
netip.MustParsePrefix("::1/128"),
54+
netip.MustParsePrefix("fe80::1/64"),
55+
},
56+
},
57+
},
58+
severity:health.SeverityOK,
59+
expectedInterfaces: []string{"en0","lo0"},
60+
},
61+
{
62+
name:"IgnoreDisabled",
63+
state: interfaces.State{
64+
Interface:map[string]interfaces.Interface{
65+
"en0": {Interface:&net.Interface{
66+
MTU:1300,
67+
Name:"en0",
68+
Flags:0,
69+
}},
70+
"lo0": {Interface:&net.Interface{
71+
MTU:65535,
72+
Name:"lo0",
73+
Flags:net.FlagUp,
74+
}},
75+
},
76+
InterfaceIPs:map[string][]netip.Prefix{
77+
"en0": {netip.MustParsePrefix("192.168.100.1/24")},
78+
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
79+
},
80+
},
81+
severity:health.SeverityOK,
82+
expectedInterfaces: []string{"lo0"},
83+
},
84+
{
85+
name:"IgnoreLinkLocalOnly",
86+
state: interfaces.State{
87+
Interface:map[string]interfaces.Interface{
88+
"en0": {Interface:&net.Interface{
89+
MTU:1300,
90+
Name:"en0",
91+
Flags:net.FlagUp,
92+
}},
93+
"lo0": {Interface:&net.Interface{
94+
MTU:65535,
95+
Name:"lo0",
96+
Flags:net.FlagUp,
97+
}},
98+
},
99+
InterfaceIPs:map[string][]netip.Prefix{
100+
"en0": {netip.MustParsePrefix("fe80::1:1/64")},
101+
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
102+
},
103+
},
104+
severity:health.SeverityOK,
105+
expectedInterfaces: []string{"lo0"},
106+
},
107+
{
108+
name:"IgnoreNoAddress",
109+
state: interfaces.State{
110+
Interface:map[string]interfaces.Interface{
111+
"en0": {Interface:&net.Interface{
112+
MTU:1300,
113+
Name:"en0",
114+
Flags:net.FlagUp,
115+
}},
116+
"lo0": {Interface:&net.Interface{
117+
MTU:65535,
118+
Name:"lo0",
119+
Flags:net.FlagUp,
120+
}},
121+
},
122+
InterfaceIPs:map[string][]netip.Prefix{
123+
"en0": {},
124+
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
125+
},
126+
},
127+
severity:health.SeverityOK,
128+
expectedInterfaces: []string{"lo0"},
129+
},
130+
{
131+
name:"SmallMTUTunnel",
132+
state: interfaces.State{
133+
Interface:map[string]interfaces.Interface{
134+
"en0": {Interface:&net.Interface{
135+
MTU:1500,
136+
Name:"en0",
137+
Flags:net.FlagUp,
138+
}},
139+
"lo0": {Interface:&net.Interface{
140+
MTU:65535,
141+
Name:"lo0",
142+
Flags:net.FlagUp,
143+
}},
144+
"tun0": {Interface:&net.Interface{
145+
MTU:1280,
146+
Name:"tun0",
147+
Flags:net.FlagUp,
148+
}},
149+
},
150+
InterfaceIPs:map[string][]netip.Prefix{
151+
"en0": {netip.MustParsePrefix("192.168.100.1/24")},
152+
"tun0": {netip.MustParsePrefix("10.3.55.9/8")},
153+
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
154+
},
155+
},
156+
severity:health.SeverityWarning,
157+
expectedInterfaces: []string{"en0","lo0","tun0"},
158+
expectedWarnings: []string{"tun0"},
159+
},
160+
}
161+
162+
for_,tc:=rangetestCases {
163+
tc:=tc
164+
t.Run(tc.name,func(t*testing.T) {
165+
t.Parallel()
166+
r:=generateInterfacesReport(&tc.state)
167+
require.Equal(t,tc.severity,r.Severity)
168+
gotInterfaces:= []string{}
169+
for_,i:=ranger.Interfaces {
170+
gotInterfaces=append(gotInterfaces,i.Name)
171+
}
172+
slices.Sort(gotInterfaces)
173+
slices.Sort(tc.expectedInterfaces)
174+
require.Equal(t,tc.expectedInterfaces,gotInterfaces)
175+
176+
require.Len(t,r.Warnings,len(tc.expectedWarnings),
177+
"expected %d warnings, got %d",len(tc.expectedWarnings),len(r.Warnings))
178+
for_,name:=rangetc.expectedWarnings {
179+
found:=false
180+
for_,w:=ranger.Warnings {
181+
ifstrings.Contains(w.String(),name) {
182+
found=true
183+
break
184+
}
185+
}
186+
if!found {
187+
t.Errorf("missing warning for %s",name)
188+
}
189+
}
190+
})
191+
}
192+
}

‎docs/admin/healthcheck.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,16 @@ version of Coder.
328328
>Note: This may be a transient issue if you are currently in the process of
329329
>updating your deployment.
330330
331+
###EIF01
332+
333+
_Interface with Small MTU_
334+
335+
**Problem:** One or more local interfaces have MTU smaller than 1378, which is the minimum MTU for
336+
Coder to establish direct connections without fragmentation.
337+
338+
**Solution:** Since IP fragmentation can be a source of performance problems, we recommend you
339+
disable the interface when using Coder or[disable direct connections](./cli#--disable-direct-connections)
340+
331341
##EUNKNOWN
332342

333343
_Unknown Error_

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp