//{Name: "multipartfiles", Package: "mime/multipart"},
{Name: "multipartmaxheaders", Package: "mime/multipart"},
{Name: "multipartmaxparts", Package: "mime/multipart"},
+ {Name: "multipathtcp", Package: "net"},
{Name: "netdns", Package: "net", Opaque: true},
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
{Name: "randautoseed", Package: "math/rand"},
import (
"context"
+ "internal/godebug"
"internal/nettrace"
"syscall"
"time"
defaultMPTCPEnabled = false
)
+var multipathtcp = godebug.New("multipathtcp")
+
// mptcpStatus is a tristate for Multipath TCP, see go.dev/issue/56539
type mptcpStatus uint8
return false
}
+ // If MPTCP is forced via GODEBUG=multipathtcp=1
+ if multipathtcp.Value() == "1" {
+ multipathtcp.IncNonDefault()
+
+ return true
+ }
+
return defaultMPTCPEnabled
}
// SetMultipathTCP directs the Dial methods to use, or not use, MPTCP,
// if supported by the operating system. This method overrides the
-// system default.
+// system default and the GODEBUG=multipathtcp=... setting if any.
//
// If MPTCP is not available on the host or not supported by the server,
// the Dial methods will fall back to TCP.
// SetMultipathTCP directs the Listen method to use, or not use, MPTCP,
// if supported by the operating system. This method overrides the
-// system default.
+// system default and the GODEBUG=multipathtcp=... setting if any.
//
// If MPTCP is not available on the host or not supported by the client,
// the Listen method will fall back to TCP.
"testing"
)
-func newLocalListenerMPTCP(t *testing.T) Listener {
+func newLocalListenerMPTCP(t *testing.T, envVar bool) Listener {
lc := &ListenConfig{}
- if lc.MultipathTCP() {
- t.Error("MultipathTCP should be off by default")
- }
- lc.SetMultipathTCP(true)
- if !lc.MultipathTCP() {
- t.Fatal("MultipathTCP is not on after having been forced to on")
+ if envVar {
+ if !lc.MultipathTCP() {
+ t.Fatal("MultipathTCP Listen is not on despite GODEBUG=multipathtcp=1")
+ }
+ } else {
+ if lc.MultipathTCP() {
+ t.Error("MultipathTCP should be off by default")
+ }
+
+ lc.SetMultipathTCP(true)
+ if !lc.MultipathTCP() {
+ t.Fatal("MultipathTCP is not on after having been forced to on")
+ }
}
ln, err := lc.Listen(context.Background(), "tcp", "127.0.0.1:0")
}
}
-func dialerMPTCP(t *testing.T, addr string) {
+func dialerMPTCP(t *testing.T, addr string, envVar bool) {
d := &Dialer{}
- if d.MultipathTCP() {
- t.Error("MultipathTCP should be off by default")
- }
- d.SetMultipathTCP(true)
- if !d.MultipathTCP() {
- t.Fatal("MultipathTCP is not on after having been forced to on")
+ if envVar {
+ if !d.MultipathTCP() {
+ t.Fatal("MultipathTCP Dialer is not on despite GODEBUG=multipathtcp=1")
+ }
+ } else {
+ if d.MultipathTCP() {
+ t.Error("MultipathTCP should be off by default")
+ }
+
+ d.SetMultipathTCP(true)
+ if !d.MultipathTCP() {
+ t.Fatal("MultipathTCP is not on after having been forced to on")
+ }
}
c, err := d.Dial("tcp", addr)
return true
}
-func TestMultiPathTCP(t *testing.T) {
- if !canCreateMPTCPSocket() {
- t.Skip("Cannot create MPTCP sockets")
+func testMultiPathTCP(t *testing.T, envVar bool) {
+ if envVar {
+ t.Log("Test with GODEBUG=multipathtcp=1")
+ t.Setenv("GODEBUG", "multipathtcp=1")
+ } else {
+ t.Log("Test with GODEBUG=multipathtcp=0")
+ t.Setenv("GODEBUG", "multipathtcp=0")
}
- ln := newLocalListenerMPTCP(t)
+ ln := newLocalListenerMPTCP(t, envVar)
// similar to tcpsock_test:TestIPv6LinkLocalUnicastTCP
ls := (&streamListener{Listener: ln}).newLocalServer()
t.Fatal(err)
}
- dialerMPTCP(t, ln.Addr().String())
+ dialerMPTCP(t, ln.Addr().String(), envVar)
if err := <-genericCh; err != nil {
t.Error(err)
t.Error(err)
}
}
+
+func TestMultiPathTCP(t *testing.T) {
+ if !canCreateMPTCPSocket() {
+ t.Skip("Cannot create MPTCP sockets")
+ }
+
+ for _, envVar := range []bool{false, true} {
+ testMultiPathTCP(t, envVar)
+ }
+}