summaryrefslogtreecommitdiffhomepage
path: root/net/tstun
diff options
context:
space:
mode:
Diffstat (limited to 'net/tstun')
-rw-r--r--net/tstun/mtu.go65
-rw-r--r--net/tstun/mtu_test.go14
-rw-r--r--net/tstun/tun.go2
3 files changed, 66 insertions, 15 deletions
diff --git a/net/tstun/mtu.go b/net/tstun/mtu.go
index 2307d47f9..43bbc28ec 100644
--- a/net/tstun/mtu.go
+++ b/net/tstun/mtu.go
@@ -4,15 +4,66 @@ package tstun
import "tailscale.com/envknob"
+// There are several kinds of MTU.
+//
+// On-the-wire MTU: This what the network device advertises as the
+// maximum packet size available above the physical link layer. This
+// includes IP headers and everything at a higher level. For Ethernet,
+// this is typically 1500 bytes but can be larger or smaller.
+//
+// Tailscale interface MTU: This is what we advertise to userspace as
+// the largest possible packet it can send through the tailscale
+// interface. This is 80 bytes lower than the largest interface we
+// have available to send things on, which is the size of the headers
+// Wireguard adds (80 for IPv6, 60 for IPv4, but we don't know which
+// it will be so we always subtract 80). E.g. if the largest interface
+// MTU is 1500, we set the tailscale interface MTU to 1420.
+//
+// Peer MTU: The MTU that we have probed for the path to a specific
+// peer's various endpoints. If this is smaller than the advertised
+// tailscale interface, and the packet is larger than the peer MTU,
+// then we generate ICMP Packet Too Big (IPv6) or Fragmentation Needed
+// (IPv4) packets inside tailscale and drop the packet.
+//
+// Historically, we set the tailscale interface MTU to 1280. This
+// means we treated the "on the wire" MTU as 1360. This is now the
+// "Safe" value we use when we do not know what the path MTU is.
+//
+// Internally, we store the peer MTU as the MTU advertised to the user.
+//
+// We have to call these by different names or it is way way too confusing.
+//
+// Wire MTU
+// User MTU
+// Peer MTU
+//
+// What should happen when we set TS_DEBUG_MTU? It should set the
+// interface to that, but we should not assume that the path MTU is
+// this. So distinguish between what we set the interface MTU to and
+// what we assume the path MTU is in the absence of probe information.
+
const (
- maxMTU uint32 = 65536
- defaultMTU uint32 = 1280
+ maxMTU uint32 = 65536
+ wireguardOverhead = 80
+ DefaultUserMTU uint32 = 1280
+ DefaultWireMTU uint32 = 1280 + wireguardOverhead
)
-// DefaultMTU returns either the constant default MTU of 1280, or the value set
-// in TS_DEBUG_MTU clamped to a maximum of 65536.
-func DefaultMTU() uint32 {
- // DefaultMTU is the Tailscale default MTU for now.
+func userMTUToWireMTU(userMTU uint32) uint32 {
+ return userMTU + wireguardOverhead
+}
+
+func wireMTUToUserMTU(wireMTU uint32) uint32 {
+ if wireMTU < wireguardOverhead {
+ return 0
+ }
+ return wireMTU - wireguardOverhead
+}
+
+// TunMTU returns either the constant default user MTU of 1280, or the
+// value set in TS_DEBUG_MTU clamped to a maximum of 65536.
+func TunMTU() uint32 {
+ // TunMTU is the Tailscale default MTU for now.
//
// wireguard-go defaults to 1420 bytes, which only works if the
// "outer" MTU is 1500 bytes. This breaks on DSL connections
@@ -21,7 +72,7 @@ func DefaultMTU() uint32 {
// 1280 is the smallest MTU allowed for IPv6, which is a sensible
// "probably works everywhere" setting until we develop proper PMTU
// discovery.
- tunMTU := defaultMTU
+ tunMTU := DefaultUserMTU
if mtu, ok := envknob.LookupUintSized("TS_DEBUG_MTU", 10, 32); ok {
mtu := uint32(mtu)
if mtu > maxMTU {
diff --git a/net/tstun/mtu_test.go b/net/tstun/mtu_test.go
index f3aea4697..1e01c5b12 100644
--- a/net/tstun/mtu_test.go
+++ b/net/tstun/mtu_test.go
@@ -7,22 +7,22 @@ import (
"testing"
)
-func TestDefaultMTU(t *testing.T) {
+func TestTunMTU(t *testing.T) {
orig := os.Getenv("TS_DEBUG_MTU")
defer os.Setenv("TS_DEBUG_MTU", orig)
os.Setenv("TS_DEBUG_MTU", "")
- if DefaultMTU() != 1280 {
- t.Errorf("DefaultMTU() = %d, want 1280", DefaultMTU())
+ if TunMTU() != 1280 {
+ t.Errorf("TunMTU() = %d, want 1280", TunMTU())
}
os.Setenv("TS_DEBUG_MTU", "9000")
- if DefaultMTU() != 9000 {
- t.Errorf("DefaultMTU() = %d, want 9000", DefaultMTU())
+ if TunMTU() != 9000 {
+ t.Errorf("TunMTU() = %d, want 9000", TunMTU())
}
os.Setenv("TS_DEBUG_MTU", "123456789")
- if DefaultMTU() != maxMTU {
- t.Errorf("DefaultMTU() = %d, want %d", DefaultMTU(), maxMTU)
+ if TunMTU() != maxMTU {
+ t.Errorf("TunMTU() = %d, want %d", TunMTU(), maxMTU)
}
}
diff --git a/net/tstun/tun.go b/net/tstun/tun.go
index b31ffa7ca..0373c7400 100644
--- a/net/tstun/tun.go
+++ b/net/tstun/tun.go
@@ -44,7 +44,7 @@ func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
}
dev, err = createTAP(tapName, bridgeName)
} else {
- dev, err = tun.CreateTUN(tunName, int(DefaultMTU()))
+ dev, err = tun.CreateTUN(tunName, int(TunMTU()))
}
if err != nil {
return nil, "", err