introduce a OptimizeConn function to manually enable UDP optimizations

This commit is contained in:
Marten Seemann
2023-05-05 12:53:55 +03:00
parent 7ea6dc991f
commit 727f9e5654
4 changed files with 33 additions and 11 deletions

View File

@@ -15,13 +15,30 @@ import (
type OOBCapablePacketConn interface {
net.PacketConn
SyscallConn() (syscall.RawConn, error)
SetReadBuffer(int) error
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
}
var _ OOBCapablePacketConn = &net.UDPConn{}
func wrapConn(pc net.PacketConn) (rawConn, error) {
// OptimizeConn takes a net.PacketConn and attempts to enable various optimizations that will improve QUIC performance:
// 1. It enables the Don't Fragment (DF) bit on the IP header.
// This allows us to do DPLPMTUD (Path MTU Discovery).
// 2. It enables reading of the ECN bits from the IP header.
// This allows the remote node to speed up its loss detection and recovery.
// 3. It uses batched syscalls (recvmmsg) to more efficiently receive packets from the socket.
//
// For this to work, the connection needs to implement the OOBCapablePacketConn interface (as a *net.UDPConn does).
func OptimizeConn(c net.PacketConn) (net.PacketConn, error) {
return wrapConn(c)
}
func wrapConn(pc net.PacketConn) (interface {
net.PacketConn
rawConn
}, error,
) {
conn, ok := pc.(interface {
SyscallConn() (syscall.RawConn, error)
})

View File

@@ -4,7 +4,7 @@ package quic
import "net"
func newConn(c net.PacketConn, supportsDF bool) (rawConn, error) {
func newConn(c net.PacketConn, supportsDF bool) (*basicConn, error) {
return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
}

View File

@@ -8,7 +8,7 @@ import (
"golang.org/x/sys/windows"
)
func newConn(c OOBCapablePacketConn, supportsDF bool) (rawConn, error) {
func newConn(c OOBCapablePacketConn, supportsDF bool) (*basicConn, error) {
return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
}

View File

@@ -30,10 +30,8 @@ type Transport struct {
// A single net.PacketConn can only be handled by one Transport.
// Bad things will happen if passed to multiple Transports.
//
// If the connection satisfies the OOBCapablePacketConn interface
// (as a net.UDPConn does), ECN and packet info support will be enabled.
// In this case, optimized syscalls might be used, skipping the
// ReadFrom and WriteTo calls to read / write packets.
// If not done by the user, the connection is passed through OptimizeConn to enable a number of optimizations.
// After passing the connection to the Transport, its invalid to call ReadFrom and WriteTo.
Conn net.PacketConn
// The length of the connection ID in bytes.
@@ -180,11 +178,18 @@ func (t *Transport) init(isServer bool) error {
t.initOnce.Do(func() {
getMultiplexer().AddConn(t.Conn)
conn, err := wrapConn(t.Conn)
if err != nil {
t.initErr = err
return
var conn rawConn
if c, ok := t.Conn.(rawConn); ok {
conn = c
} else {
var err error
conn, err = wrapConn(t.Conn)
if err != nil {
t.initErr = err
return
}
}
t.conn = conn
t.logger = utils.DefaultLogger // TODO: make this configurable
t.conn = conn