|
|
@@ -6,12 +6,15 @@ package wgengine
|
|
|
import (
|
|
|
"fmt"
|
|
|
"net/netip"
|
|
|
+ "os"
|
|
|
"reflect"
|
|
|
+ "runtime"
|
|
|
"testing"
|
|
|
|
|
|
"go4.org/mem"
|
|
|
"tailscale.com/cmd/testwrapper/flakytest"
|
|
|
"tailscale.com/control/controlknobs"
|
|
|
+ "tailscale.com/envknob"
|
|
|
"tailscale.com/net/dns"
|
|
|
"tailscale.com/net/netaddr"
|
|
|
"tailscale.com/net/tstun"
|
|
|
@@ -20,6 +23,7 @@ import (
|
|
|
"tailscale.com/tstime/mono"
|
|
|
"tailscale.com/types/key"
|
|
|
"tailscale.com/types/netmap"
|
|
|
+ "tailscale.com/types/opt"
|
|
|
"tailscale.com/wgengine/router"
|
|
|
"tailscale.com/wgengine/wgcfg"
|
|
|
)
|
|
|
@@ -227,6 +231,86 @@ func TestUserspaceEnginePortReconfig(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// Test that enabling and disabling peer path MTU discovery works correctly.
|
|
|
+func TestUserspaceEnginePeerMTUReconfig(t *testing.T) {
|
|
|
+ if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
|
|
|
+ t.Skipf("skipping on %q; peer MTU not supported", runtime.GOOS)
|
|
|
+ }
|
|
|
+
|
|
|
+ defer os.Setenv("TS_DEBUG_ENABLE_PMTUD", os.Getenv("TS_DEBUG_ENABLE_PMTUD"))
|
|
|
+ envknob.Setenv("TS_DEBUG_ENABLE_PMTUD", "")
|
|
|
+ // Turn on debugging to help diagnose problems.
|
|
|
+ defer os.Setenv("TS_DEBUG_PMTUD", os.Getenv("TS_DEBUG_PMTUD"))
|
|
|
+ envknob.Setenv("TS_DEBUG_PMTUD", "true")
|
|
|
+
|
|
|
+ var knobs controlknobs.Knobs
|
|
|
+
|
|
|
+ e, err := NewFakeUserspaceEngine(t.Logf, 0, &knobs)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ t.Cleanup(e.Close)
|
|
|
+ ue := e.(*userspaceEngine)
|
|
|
+
|
|
|
+ if ue.magicConn.PeerMTUEnabled() != false {
|
|
|
+ t.Error("peer MTU enabled by default, should not be")
|
|
|
+ }
|
|
|
+ osDefaultDF, err := ue.magicConn.DontFragSetting()
|
|
|
+ if err != nil {
|
|
|
+ t.Errorf("get don't fragment bit failed: %v", err)
|
|
|
+ }
|
|
|
+ t.Logf("Info: OS default don't fragment bit(s) setting: %v", osDefaultDF)
|
|
|
+
|
|
|
+ // Build a set of configs to use as we change the peer MTU settings.
|
|
|
+ nodeKey, err := key.ParseNodePublicUntyped(mem.S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ cfg := &wgcfg.Config{
|
|
|
+ Peers: []wgcfg.Peer{
|
|
|
+ {
|
|
|
+ PublicKey: nodeKey,
|
|
|
+ AllowedIPs: []netip.Prefix{
|
|
|
+ netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+ routerCfg := &router.Config{}
|
|
|
+
|
|
|
+ tests := []struct {
|
|
|
+ desc string // test description
|
|
|
+ wantP bool // desired value of PMTUD setting
|
|
|
+ wantDF bool // desired value of don't fragment bits
|
|
|
+ shouldP opt.Bool // if set, force peer MTU to this value
|
|
|
+ }{
|
|
|
+ {desc: "after_first_reconfig", wantP: false, wantDF: osDefaultDF, shouldP: ""},
|
|
|
+ {desc: "enabling_PMTUD_first_time", wantP: true, wantDF: true, shouldP: "true"},
|
|
|
+ {desc: "disabling_PMTUD", wantP: false, wantDF: false, shouldP: "false"},
|
|
|
+ {desc: "enabling_PMTUD_second_time", wantP: true, wantDF: true, shouldP: "true"},
|
|
|
+ {desc: "returning_to_default_PMTUD", wantP: false, wantDF: false, shouldP: ""},
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.desc, func(t *testing.T) {
|
|
|
+ if v, ok := tt.shouldP.Get(); ok {
|
|
|
+ knobs.PeerMTUEnable.Store(v)
|
|
|
+ } else {
|
|
|
+ knobs.PeerMTUEnable.Store(false)
|
|
|
+ }
|
|
|
+ if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if v := ue.magicConn.PeerMTUEnabled(); v != tt.wantP {
|
|
|
+ t.Errorf("peer MTU set to %v, want %v", v, tt.wantP)
|
|
|
+ }
|
|
|
+ if v, err := ue.magicConn.DontFragSetting(); v != tt.wantDF || err != nil {
|
|
|
+ t.Errorf("don't fragment bit set to %v, want %v, err %v", v, tt.wantP, err)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
func nkFromHex(hex string) key.NodePublic {
|
|
|
if len(hex) != 64 {
|
|
|
panic(fmt.Sprintf("%q is len %d; want 64", hex, len(hex)))
|