disable Path MTU Discovery on Windows

This commit is contained in:
Marten Seemann
2021-09-14 18:39:23 +02:00
parent 3b46d7402c
commit d410b590e9
8 changed files with 56 additions and 34 deletions

View File

@@ -5,6 +5,8 @@ package quic
import "net" import "net"
const disablePathMTUDiscovery = false
func newConn(c net.PacketConn) (connection, error) { func newConn(c net.PacketConn) (connection, error) {
return &basicConn{PacketConn: c}, nil return &basicConn{PacketConn: c}, nil
} }

View File

@@ -5,7 +5,10 @@ package quic
import "golang.org/x/sys/unix" import "golang.org/x/sys/unix"
const msgTypeIPTOS = unix.IP_RECVTOS const (
msgTypeIPTOS = unix.IP_RECVTOS
disablePathMTUDiscovery = false
)
const ( const (
ipv4RECVPKTINFO = unix.IP_RECVPKTINFO ipv4RECVPKTINFO = unix.IP_RECVPKTINFO

View File

@@ -5,7 +5,10 @@ package quic
import "golang.org/x/sys/unix" import "golang.org/x/sys/unix"
const msgTypeIPTOS = unix.IP_RECVTOS const (
msgTypeIPTOS = unix.IP_RECVTOS
disablePathMTUDiscovery = false
)
const ( const (
ipv4RECVPKTINFO = 0x7 ipv4RECVPKTINFO = 0x7

View File

@@ -5,7 +5,10 @@ package quic
import "golang.org/x/sys/unix" import "golang.org/x/sys/unix"
const msgTypeIPTOS = unix.IP_TOS const (
msgTypeIPTOS = unix.IP_TOS
disablePathMTUDiscovery = false
)
const ( const (
ipv4RECVPKTINFO = unix.IP_PKTINFO ipv4RECVPKTINFO = unix.IP_PKTINFO

View File

@@ -12,7 +12,10 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
const IP_DONTFRAGMENT = 14 const (
disablePathMTUDiscovery = true
IP_DONTFRAGMENT = 14
)
func newConn(c OOBCapablePacketConn) (connection, error) { func newConn(c OOBCapablePacketConn) (connection, error) {
rawConn, err := c.SyscallConn() rawConn, err := c.SyscallConn()

View File

@@ -283,6 +283,7 @@ type Config struct {
KeepAlive bool KeepAlive bool
// DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899). // DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899).
// Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size. // Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
// Note that Path MTU discovery is always disabled on Windows, see https://github.com/lucas-clemente/quic-go/issues/3273.
DisablePathMTUDiscovery bool DisablePathMTUDiscovery bool
// DisableVersionNegotiationPackets disables the sending of Version Negotiation packets. // DisableVersionNegotiationPackets disables the sending of Version Negotiation packets.
// This can be useful if version information is exchanged out-of-band. // This can be useful if version information is exchanged out-of-band.

View File

@@ -130,6 +130,10 @@ func (e *errCloseForRecreating) Error() string {
var sessionTracingID uint64 // to be accessed atomically var sessionTracingID uint64 // to be accessed atomically
func nextSessionTracingID() uint64 { return atomic.AddUint64(&sessionTracingID, 1) } func nextSessionTracingID() uint64 { return atomic.AddUint64(&sessionTracingID, 1) }
func pathMTUDiscoveryEnabled(config *Config) bool {
return !disablePathMTUDiscovery && !config.DisablePathMTUDiscovery
}
// A Session is a QUIC session // A Session is a QUIC session
type session struct { type session struct {
// Destination connection ID used during the handshake. // Destination connection ID used during the handshake.
@@ -743,7 +747,7 @@ func (s *session) maybeResetTimer() {
deadline = s.idleTimeoutStartTime().Add(s.idleTimeout) deadline = s.idleTimeoutStartTime().Add(s.idleTimeout)
} }
} }
if s.handshakeConfirmed && !s.config.DisablePathMTUDiscovery { if s.handshakeConfirmed && pathMTUDiscoveryEnabled(s.config) {
if probeTime := s.mtuDiscoverer.NextProbeTime(); !probeTime.IsZero() { if probeTime := s.mtuDiscoverer.NextProbeTime(); !probeTime.IsZero() {
deadline = utils.MinTime(deadline, probeTime) deadline = utils.MinTime(deadline, probeTime)
} }
@@ -807,7 +811,7 @@ func (s *session) handleHandshakeConfirmed() {
s.sentPacketHandler.SetHandshakeConfirmed() s.sentPacketHandler.SetHandshakeConfirmed()
s.cryptoStreamHandler.SetHandshakeConfirmed() s.cryptoStreamHandler.SetHandshakeConfirmed()
if !s.config.DisablePathMTUDiscovery { if pathMTUDiscoveryEnabled(s.config) {
maxPacketSize := s.peerParams.MaxUDPPayloadSize maxPacketSize := s.peerParams.MaxUDPPayloadSize
if maxPacketSize == 0 { if maxPacketSize == 0 {
maxPacketSize = protocol.MaxByteCount maxPacketSize = protocol.MaxByteCount
@@ -1768,7 +1772,7 @@ func (s *session) sendPacket() (bool, error) {
s.sendQueue.Send(packet.buffer) s.sendQueue.Send(packet.buffer)
return true, nil return true, nil
} }
if !s.config.DisablePathMTUDiscovery && s.mtuDiscoverer.ShouldSendProbe(now) { if pathMTUDiscoveryEnabled(s.config) && s.mtuDiscoverer.ShouldSendProbe(now) {
packet, err := s.packer.PackMTUProbePacket(s.mtuDiscoverer.GetPing()) packet, err := s.packer.PackMTUProbePacket(s.mtuDiscoverer.GetPing())
if err != nil { if err != nil {
return false, err return false, err

View File

@@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"runtime"
"runtime/pprof" "runtime/pprof"
"strings" "strings"
"time" "time"
@@ -1681,33 +1682,35 @@ var _ = Describe("Session", func() {
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
}) })
It("sends a Path MTU probe packet", func() { if runtime.GOOS != "windows" { // Path MTU Discovery is disabled on Windows
mtuDiscoverer := NewMockMtuDiscoverer(mockCtrl) It("sends a Path MTU probe packet", func() {
sess.mtuDiscoverer = mtuDiscoverer mtuDiscoverer := NewMockMtuDiscoverer(mockCtrl)
sess.config.DisablePathMTUDiscovery = false sess.mtuDiscoverer = mtuDiscoverer
sph.EXPECT().SentPacket(gomock.Any()) sess.config.DisablePathMTUDiscovery = false
sph.EXPECT().HasPacingBudget().Return(true).AnyTimes() sph.EXPECT().SentPacket(gomock.Any())
sph.EXPECT().SendMode().Return(ackhandler.SendAny) sph.EXPECT().HasPacingBudget().Return(true).AnyTimes()
sph.EXPECT().SendMode().Return(ackhandler.SendNone) sph.EXPECT().SendMode().Return(ackhandler.SendAny)
written := make(chan struct{}, 1) sph.EXPECT().SendMode().Return(ackhandler.SendNone)
sender.EXPECT().WouldBlock().AnyTimes() written := make(chan struct{}, 1)
sender.EXPECT().Send(gomock.Any()).DoAndReturn(func(p *packetBuffer) { written <- struct{}{} }) sender.EXPECT().WouldBlock().AnyTimes()
gomock.InOrder( sender.EXPECT().Send(gomock.Any()).DoAndReturn(func(p *packetBuffer) { written <- struct{}{} })
mtuDiscoverer.EXPECT().NextProbeTime(), gomock.InOrder(
mtuDiscoverer.EXPECT().ShouldSendProbe(gomock.Any()).Return(true), mtuDiscoverer.EXPECT().NextProbeTime(),
mtuDiscoverer.EXPECT().NextProbeTime(), mtuDiscoverer.EXPECT().ShouldSendProbe(gomock.Any()).Return(true),
) mtuDiscoverer.EXPECT().NextProbeTime(),
ping := ackhandler.Frame{Frame: &wire.PingFrame{}} )
mtuDiscoverer.EXPECT().GetPing().Return(ping, protocol.ByteCount(1234)) ping := ackhandler.Frame{Frame: &wire.PingFrame{}}
packer.EXPECT().PackMTUProbePacket(ping, protocol.ByteCount(1234)).Return(getPacket(1), nil) mtuDiscoverer.EXPECT().GetPing().Return(ping, protocol.ByteCount(1234))
go func() { packer.EXPECT().PackMTUProbePacket(ping, protocol.ByteCount(1234)).Return(getPacket(1), nil)
defer GinkgoRecover() go func() {
cryptoSetup.EXPECT().RunHandshake().MaxTimes(1) defer GinkgoRecover()
sess.run() cryptoSetup.EXPECT().RunHandshake().MaxTimes(1)
}() sess.run()
sess.scheduleSending() }()
Eventually(written).Should(Receive()) sess.scheduleSending()
}) Eventually(written).Should(Receive())
})
}
}) })
Context("scheduling sending", func() { Context("scheduling sending", func() {