Skip to content

Commit 6cc5b27

Browse files
committed
Revert "wgengine,net,ipn,disco: split up and define different types of MTU"
This reverts commit 059051c. Signed-off-by: Val <[email protected]>
1 parent 059051c commit 6cc5b27

File tree

7 files changed

+52
-250
lines changed

7 files changed

+52
-250
lines changed

ipn/localapi/localapi.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"tailscale.com/net/netmon"
3737
"tailscale.com/net/netutil"
3838
"tailscale.com/net/portmapper"
39+
"tailscale.com/net/tstun"
3940
"tailscale.com/tailcfg"
4041
"tailscale.com/tka"
4142
"tailscale.com/tstime"
@@ -50,7 +51,6 @@ import (
5051
"tailscale.com/util/osdiag"
5152
"tailscale.com/util/rands"
5253
"tailscale.com/version"
53-
"tailscale.com/wgengine/magicsock"
5454
)
5555

5656
type localAPIHandler func(*Handler, http.ResponseWriter, *http.Request)
@@ -1380,8 +1380,8 @@ func (h *Handler) servePing(w http.ResponseWriter, r *http.Request) {
13801380
http.Error(w, "'size' parameter is only supported with disco pings", 400)
13811381
return
13821382
}
1383-
if size > magicsock.MaxDiscoPingSize {
1384-
http.Error(w, fmt.Sprintf("maximum value for 'size' is %v", magicsock.MaxDiscoPingSize), 400)
1383+
if size > int(tstun.DefaultMTU()) {
1384+
http.Error(w, fmt.Sprintf("maximum value for 'size' is %v", tstun.DefaultMTU()), 400)
13851385
return
13861386
}
13871387
}

net/tstun/mtu.go

Lines changed: 23 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,33 @@
11
// Copyright (c) Tailscale Inc & AUTHORS
22
// SPDX-License-Identifier: BSD-3-Clause
3-
43
package tstun
54

6-
import (
7-
"tailscale.com/envknob"
8-
)
9-
10-
// The MTU (Maximum Transmission Unit) of a network interface is the largest
11-
// packet that can be sent or received through that interface, including all
12-
// headers above the link layer (e.g. IP headers, UDP headers, Wireguard
13-
// headers, etc.). We have to think about several different values of MTU:
14-
//
15-
// Wire MTU: The MTU of an interface underneath the tailscale TUN, e.g. an
16-
// Ethernet network card will default to a 1500 byte MTU. The user may change
17-
// this MTU at any time.
18-
//
19-
// TUN MTU: The current MTU of the tailscale TUN. This MTU is adjusted downward
20-
// to make room for the wireguard/tailscale headers. For example, if the
21-
// underlying network interface's MTU is 1500 bytes, the maximum size of a
22-
// packet entering the tailscale TUN is 1420 bytes. The user may change this MTU
23-
// at any time via the OS's tools (ifconfig, ip, etc.).
24-
//
25-
// User configured initial MTU: The MTU the tailscale TUN should be created
26-
// with, set by the user via TS_DEBUG_MTU. It should be adjusted down from the
27-
// underlying interface MTU by 80 bytes to make room for the wireguard
28-
// headers. This envknob is mostly for debugging. This value is used once at TUN
29-
// creation and ignored thereafter.
30-
//
31-
// User configured current MTU: The MTU set via the OS's tools (ifconfig, ip,
32-
// etc.). This MTU can change at any time. Setting the MTU this way goes through
33-
// the MTU() method of tailscale's TUN wrapper.
34-
//
35-
// Maximum probed MTU: This is the largest MTU size that we send probe packets
36-
// for.
37-
//
38-
// Safe MTU: If the tailscale TUN MTU is set to this value, almost all packets
39-
// will get to their destination. Tailscale defaults to this MTU in the absence
40-
// of path MTU probe information or user MTU configuration. We may occasionally
41-
// find a path that needs a smaller MTU but it is very rare.
42-
//
43-
// Peer MTU: This is the path MTU to a peer's current best endpoint. It defaults
44-
// to the Safe MTU unless we have path MTU probe results that tell us otherwise.
45-
//
46-
// Initial MTU: This is the MTU tailscaled creates the TUN with. In order of
47-
// priority, it is:
48-
//
49-
// 1. If set, the value of TS_DEBUG_MTU clamped to a maximum of 65536
50-
// 2. If TS_DEBUG_ENABLE_PMTUD is set, the maximum size MTU we probe, minus wg
51-
// overhead
52-
// 3. If TS_DEBUG_ENABLE_PMTUD is not set, the Safe MTU
53-
//
54-
// Current MTU: This the MTU of the tailscale TUN at any given moment
55-
// after TUN creation. In order of priority, it is:
56-
//
57-
// 1. The MTU set by the user via the OS, if it has ever been set
58-
// 2. If TS_DEBUG_ENABLE_PMTUD is set, the maximum size MTU we probe, minus wg
59-
// overhead
60-
// 4. If TS_DEBUG_ENABLE_PMTUD is not set, the Safe MTU
61-
62-
// TUNMTU is the MTU for the tailscale TUN.
63-
type TUNMTU uint32
64-
65-
// WireMTU is the MTU for the underlying network devices.
66-
type WireMTU uint32
5+
import "tailscale.com/envknob"
676

687
const (
69-
// maxTUNMTU is the largest MTU we will consider for the Tailscale
70-
// TUN. This is inherited from wireguard-go and can be surprisingly
71-
// small; on Windows it is currently 2048 - 32 bytes and iOS it is 1700
72-
// - 32 bytes.
73-
// TODO(val,raggi): On Windows this seems to derive from RIO driver
74-
// constraints in Wireguard but we don't use RIO so could probably make
75-
// this bigger.
76-
maxTUNMTU TUNMTU = TUNMTU(MaxPacketSize)
77-
// safeTUNMTU is the default "safe" MTU for the Tailscale TUN that we
78-
// use in the absence of other information such as path MTU probes.
79-
safeTUNMTU TUNMTU = 1280
8+
maxMTU uint32 = 65536
9+
defaultMTU uint32 = 1280
8010
)
8111

82-
// MaxProbedWireMTU is the largest MTU we will test for path MTU
83-
// discovery.
84-
var MaxProbedWireMTU WireMTU = 9000
85-
86-
func init() {
87-
if MaxProbedWireMTU > WireMTU(maxTUNMTU) {
88-
MaxProbedWireMTU = WireMTU(maxTUNMTU)
89-
}
90-
}
91-
92-
// wgHeaderLen is the length of all the headers Wireguard adds to a packet
93-
// in the worst case (IPv6). This constant is for use when we can't or
94-
// shouldn't use information about the IP version of a specific packet
95-
// (e.g., calculating the MTU for the Tailscale interface.
96-
//
97-
// A Wireguard header includes:
98-
//
99-
// - 20-byte IPv4 header or 40-byte IPv6 header
100-
// - 8-byte UDP header
101-
// - 4-byte type
102-
// - 4-byte key index
103-
// - 8-byte nonce
104-
// - 16-byte authentication tag
105-
const wgHeaderLen = 40 + 8 + 4 + 4 + 8 + 16
106-
107-
// TUNToWireMTU takes the MTU that the Tailscale TUN presents to the user and
108-
// returns the on-the-wire MTU necessary to transmit the largest packet that
109-
// will fit through the TUN, given that we have to add wireguard headers.
110-
func TUNToWireMTU(t TUNMTU) WireMTU {
111-
return WireMTU(t + wgHeaderLen)
112-
}
113-
114-
// WireToTUNMTU takes the MTU of an underlying network device and returns the
115-
// largest possible MTU for a Tailscale TUN operating on top of that device,
116-
// given that we have to add wireguard headers.
117-
func WireToTUNMTU(w WireMTU) TUNMTU {
118-
if w < wgHeaderLen {
119-
return 0
120-
}
121-
return TUNMTU(w - wgHeaderLen)
122-
}
123-
124-
// DefaultTUNMTU returns the MTU we use to set the Tailscale TUN
125-
// MTU. It is also the path MTU that we default to if we have no
126-
// information about the path to a peer.
127-
//
128-
// 1. If set, the value of TS_DEBUG_MTU clamped to a maximum of MaxTunMTU
129-
// 2. If TS_DEBUG_ENABLE_PMTUD is set, the maximum size MTU we probe, minus wg overhead
130-
// 3. If TS_DEBUG_ENABLE_PMTUD is not set, the Safe MTU
131-
func DefaultTUNMTU() TUNMTU {
132-
if m, ok := envknob.LookupUintSized("TS_DEBUG_MTU", 10, 32); ok {
133-
return min(TUNMTU(m), maxTUNMTU)
134-
}
135-
136-
debugPMTUD, _ := envknob.LookupBool("TS_DEBUG_ENABLE_PMTUD")
137-
if debugPMTUD {
138-
return WireToTUNMTU(MaxProbedWireMTU)
139-
}
140-
141-
return safeTUNMTU
142-
}
143-
144-
// Temporary workaround for code on corp that uses this function name.
145-
// TODO(val): Remove as soon as corp OSS is updated.
12+
// DefaultMTU returns either the constant default MTU of 1280, or the value set
13+
// in TS_DEBUG_MTU clamped to a maximum of 65536.
14614
func DefaultMTU() uint32 {
147-
return uint32(DefaultTUNMTU())
148-
}
149-
150-
// DefaultWireMTU returns the default TUN MTU, adjusted for wireguard
151-
// overhead.
152-
func DefaultWireMTU() WireMTU {
153-
return TUNToWireMTU(DefaultTUNMTU())
15+
// DefaultMTU is the Tailscale default MTU for now.
16+
//
17+
// wireguard-go defaults to 1420 bytes, which only works if the
18+
// "outer" MTU is 1500 bytes. This breaks on DSL connections
19+
// (typically 1492 MTU) and on GCE (1460 MTU?!).
20+
//
21+
// 1280 is the smallest MTU allowed for IPv6, which is a sensible
22+
// "probably works everywhere" setting until we develop proper PMTU
23+
// discovery.
24+
tunMTU := defaultMTU
25+
if mtu, ok := envknob.LookupUintSized("TS_DEBUG_MTU", 10, 32); ok {
26+
mtu := uint32(mtu)
27+
if mtu > maxMTU {
28+
mtu = maxMTU
29+
}
30+
tunMTU = mtu
31+
}
32+
return tunMTU
15433
}

net/tstun/mtu_test.go

Lines changed: 11 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -4,93 +4,25 @@ package tstun
44

55
import (
66
"os"
7-
"strconv"
87
"testing"
98
)
109

11-
// Test the default MTU in the presence of various envknobs.
12-
func TestDefaultTunMTU(t *testing.T) {
13-
// Save and restore the envknobs we will be changing.
10+
func TestDefaultMTU(t *testing.T) {
11+
orig := os.Getenv("TS_DEBUG_MTU")
12+
defer os.Setenv("TS_DEBUG_MTU", orig)
1413

15-
// TS_DEBUG_MTU sets the MTU to a specific value.
16-
defer os.Setenv("TS_DEBUG_MTU", os.Getenv("TS_DEBUG_MTU"))
1714
os.Setenv("TS_DEBUG_MTU", "")
18-
19-
// TS_DEBUG_ENABLE_PMTUD enables path MTU discovery.
20-
defer os.Setenv("TS_DEBUG_ENABLE_PMTUD", os.Getenv("TS_DEBUG_ENABLE_PMTUD"))
21-
os.Setenv("TS_DEBUG_ENABLE_PMTUD", "")
22-
23-
// With no MTU envknobs set, we should get the conservative MTU.
24-
if DefaultTUNMTU() != safeTUNMTU {
25-
t.Errorf("default TUN MTU = %d, want %d", DefaultTUNMTU(), safeTUNMTU)
26-
}
27-
28-
// If set, TS_DEBUG_MTU should set the MTU.
29-
mtu := maxTUNMTU - 1
30-
os.Setenv("TS_DEBUG_MTU", strconv.Itoa(int(mtu)))
31-
if DefaultTUNMTU() != mtu {
32-
t.Errorf("default TUN MTU = %d, want %d, TS_DEBUG_MTU ignored", DefaultTUNMTU(), mtu)
33-
}
34-
35-
// MTU should be clamped to maxTunMTU.
36-
mtu = maxTUNMTU + 1
37-
os.Setenv("TS_DEBUG_MTU", strconv.Itoa(int(mtu)))
38-
if DefaultTUNMTU() != maxTUNMTU {
39-
t.Errorf("default TUN MTU = %d, want %d, clamping failed", DefaultTUNMTU(), maxTUNMTU)
40-
}
41-
42-
// If PMTUD is enabled, the MTU should default to the largest probed
43-
// MTU, but only if the user hasn't requested a specific MTU.
44-
os.Setenv("TS_DEBUG_MTU", "")
45-
os.Setenv("TS_DEBUG_ENABLE_PMTUD", "true")
46-
if DefaultTUNMTU() != WireToTUNMTU(MaxProbedWireMTU) {
47-
t.Errorf("default TUN MTU = %d, want %d", DefaultTUNMTU(), WireToTUNMTU(MaxProbedWireMTU))
48-
}
49-
// TS_DEBUG_MTU should take precedence over TS_DEBUG_ENABLE_PMTUD.
50-
mtu = WireToTUNMTU(MaxProbedWireMTU - 1)
51-
os.Setenv("TS_DEBUG_MTU", strconv.Itoa(int(mtu)))
52-
if DefaultTUNMTU() != mtu {
53-
t.Errorf("default TUN MTU = %d, want %d", DefaultTUNMTU(), mtu)
54-
}
55-
}
56-
57-
// Test the conversion of wire MTU to/from Tailscale TUN MTU corner cases.
58-
func TestMTUConversion(t *testing.T) {
59-
tests := []struct {
60-
w WireMTU
61-
t TUNMTU
62-
}{
63-
{w: 0, t: 0},
64-
{w: wgHeaderLen - 1, t: 0},
65-
{w: wgHeaderLen, t: 0},
66-
{w: wgHeaderLen + 1, t: 1},
67-
{w: 1360, t: 1280},
68-
{w: 1500, t: 1420},
69-
{w: 9000, t: 8920},
70-
}
71-
72-
for _, tt := range tests {
73-
m := WireToTUNMTU(tt.w)
74-
if m != tt.t {
75-
t.Errorf("conversion of wire MTU %v to TUN MTU = %v, want %v", tt.w, m, tt.t)
76-
}
15+
if DefaultMTU() != 1280 {
16+
t.Errorf("DefaultMTU() = %d, want 1280", DefaultMTU())
7717
}
7818

79-
tests2 := []struct {
80-
t TUNMTU
81-
w WireMTU
82-
}{
83-
{t: 0, w: wgHeaderLen},
84-
{t: 1, w: wgHeaderLen + 1},
85-
{t: 1280, w: 1360},
86-
{t: 1420, w: 1500},
87-
{t: 8920, w: 9000},
19+
os.Setenv("TS_DEBUG_MTU", "9000")
20+
if DefaultMTU() != 9000 {
21+
t.Errorf("DefaultMTU() = %d, want 9000", DefaultMTU())
8822
}
8923

90-
for _, tt := range tests2 {
91-
m := TUNToWireMTU(tt.t)
92-
if m != tt.w {
93-
t.Errorf("conversion of TUN MTU %v to wire MTU = %v, want %v", tt.t, m, tt.w)
94-
}
24+
os.Setenv("TS_DEBUG_MTU", "123456789")
25+
if DefaultMTU() != maxMTU {
26+
t.Errorf("DefaultMTU() = %d, want %d", DefaultMTU(), maxMTU)
9527
}
9628
}

net/tstun/tun.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
4444
}
4545
dev, err = createTAP(tapName, bridgeName)
4646
} else {
47-
dev, err = tun.CreateTUN(tunName, int(DefaultTUNMTU()))
47+
dev, err = tun.CreateTUN(tunName, int(DefaultMTU()))
4848
}
4949
if err != nil {
5050
return nil, "", err

wgengine/magicsock/endpoint.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -422,10 +422,6 @@ func (de *endpoint) noteActiveLocked() {
422422
}
423423
}
424424

425-
// MaxDiscoPingSize is the largest useful ping message size that we
426-
// can send - the maximum packet size minus the IPv4 and UDP headers.
427-
var MaxDiscoPingSize = tstun.MaxPacketSize - 20 - 8
428-
429425
// cliPing starts a ping for the "tailscale ping" command. res is value to call cb with,
430426
// already partially filled.
431427
func (de *endpoint) cliPing(res *ipnstate.PingResult, size int, cb func(*ipnstate.PingResult)) {
@@ -437,11 +433,6 @@ func (de *endpoint) cliPing(res *ipnstate.PingResult, size int, cb func(*ipnstat
437433
cb(res)
438434
return
439435
}
440-
if size > MaxDiscoPingSize {
441-
res.Err = errPingTooBig.Error()
442-
cb(res)
443-
return
444-
}
445436

446437
now := mono.Now()
447438
udpAddr, derpAddr, _ := de.addrForSendLocked(now)
@@ -466,7 +457,6 @@ func (de *endpoint) cliPing(res *ipnstate.PingResult, size int, cb func(*ipnstat
466457
var (
467458
errExpired = errors.New("peer's node key has expired")
468459
errNoUDPOrDERP = errors.New("no UDP or DERP addr")
469-
errPingTooBig = errors.New("ping size too big")
470460
)
471461

472462
func (de *endpoint) send(buffs [][]byte) error {
@@ -574,9 +564,13 @@ const discoPingSize = len(disco.Magic) + key.DiscoPublicRawLen + disco.NonceLen
574564
// The caller should use de.discoKey as the discoKey argument.
575565
// It is passed in so that sendDiscoPing doesn't need to lock de.mu.
576566
func (de *endpoint) sendDiscoPing(ep netip.AddrPort, discoKey key.DiscoPublic, txid stun.TxID, size int, logLevel discoLogLevel) {
577-
size = min(size, MaxDiscoPingSize)
578-
padding := max(size-discoPingSize, 0)
579-
567+
padding := 0
568+
if size > int(tstun.DefaultMTU()) {
569+
size = int(tstun.DefaultMTU())
570+
}
571+
if size-discoPingSize > 0 {
572+
padding = size - discoPingSize
573+
}
580574
sent, _ := de.c.sendDiscoMessage(ep, de.publicKey, discoKey, &disco.Ping{
581575
TxID: [12]byte(txid),
582576
NodeKey: de.c.publicKeyAtomic.Load(),

0 commit comments

Comments
 (0)