TUN-7575: Add option to disable PTMU discovery over QUIC

This commit implements the option to disable PTMU discovery for QUIC
connections.
QUIC finds the PMTU during startup by increasing Ping packet frames
until Ping responses are not received anymore, and it seems to stick
with that PMTU forever.

This is no problem if the PTMU doesn't change over time, but if it does
it may case packet drops.
We add this hidden flag for debugging purposes in such situations as a
quick way to validate if problems that are being seen can be solved by
reducing the packet size to the edge.

Note however, that this option may impact UDP proxying since we expect
being able to send UDP packets of 1280 bytes over QUIC.
So, this option should not be used when tunnel is being used for UDP
proxying.
This commit is contained in:
João Oliveirinha 2023-07-12 10:37:19 +01:00
parent fdab68aa08
commit 0c8bc56930
3 changed files with 24 additions and 8 deletions

View File

@ -82,6 +82,11 @@ const (
// udpUnregisterSessionTimeout is how long we wait before we stop trying to unregister a UDP session from the edge // udpUnregisterSessionTimeout is how long we wait before we stop trying to unregister a UDP session from the edge
udpUnregisterSessionTimeoutFlag = "udp-unregister-session-timeout" udpUnregisterSessionTimeoutFlag = "udp-unregister-session-timeout"
// quicDisablePathMTUDiscovery sets if QUIC should not perform PTMU discovery and use a smaller (safe) packet size.
// Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
// Note that this may result in packet drops for UDP proxying, since we expect being able to send at least 1280 bytes of inner packets.
quicDisablePathMTUDiscovery = "quic-disable-pmtu-discovery"
// uiFlag is to enable launching cloudflared in interactive UI mode // uiFlag is to enable launching cloudflared in interactive UI mode
uiFlag = "ui" uiFlag = "ui"
@ -692,6 +697,13 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
Value: 5 * time.Second, Value: 5 * time.Second,
Hidden: true, Hidden: true,
}), }),
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: quicDisablePathMTUDiscovery,
EnvVars: []string{"TUNNEL_DISABLE_QUIC_PMTU"},
Usage: "Use this option to disable PTMU discovery for QUIC connections. This will result in lower packet sizes. Not however, that this may cause instability for UDP proxying.",
Value: false,
Hidden: true,
}),
altsrc.NewStringFlag(&cli.StringFlag{ altsrc.NewStringFlag(&cli.StringFlag{
Name: connectorLabelFlag, Name: connectorLabelFlag,
Usage: "Use this option to give a meaningful label to a specific connector. When a tunnel starts up, a connector id unique to the tunnel is generated. This is a uuid. To make it easier to identify a connector, we will use the hostname of the machine the tunnel is running on along with the connector ID. This option exists if one wants to have more control over what their individual connectors are called.", Usage: "Use this option to give a meaningful label to a specific connector. When a tunnel starts up, a connector id unique to the tunnel is generated. This is a uuid. To make it easier to identify a connector, we will use the hostname of the machine the tunnel is running on along with the connector ID. This option exists if one wants to have more control over what their individual connectors are called.",

View File

@ -240,6 +240,7 @@ func prepareTunnelConfig(
PQKexIdx: pqKexIdx, PQKexIdx: pqKexIdx,
MaxEdgeAddrRetries: uint8(c.Int("max-edge-addr-retries")), MaxEdgeAddrRetries: uint8(c.Int("max-edge-addr-retries")),
UDPUnregisterSessionTimeout: c.Duration(udpUnregisterSessionTimeoutFlag), UDPUnregisterSessionTimeout: c.Duration(udpUnregisterSessionTimeoutFlag),
DisableQUICPathMTUDiscovery: c.Bool(quicDisablePathMTUDiscovery),
} }
packetConfig, err := newPacketConfig(c, log) packetConfig, err := newPacketConfig(c, log)
if err != nil { if err != nil {

View File

@ -70,6 +70,8 @@ type TunnelConfig struct {
PacketConfig *ingress.GlobalRouterConfig PacketConfig *ingress.GlobalRouterConfig
UDPUnregisterSessionTimeout time.Duration UDPUnregisterSessionTimeout time.Duration
DisableQUICPathMTUDiscovery bool
} }
func (c *TunnelConfig) registrationOptions(connectionID uint8, OriginLocalIP string, uuid uuid.UUID) *tunnelpogs.RegistrationOptions { func (c *TunnelConfig) registrationOptions(connectionID uint8, OriginLocalIP string, uuid uuid.UUID) *tunnelpogs.RegistrationOptions {
@ -596,14 +598,15 @@ func (e *EdgeTunnelServer) serveQUIC(
} }
quicConfig := &quic.Config{ quicConfig := &quic.Config{
HandshakeIdleTimeout: quicpogs.HandshakeIdleTimeout, HandshakeIdleTimeout: quicpogs.HandshakeIdleTimeout,
MaxIdleTimeout: quicpogs.MaxIdleTimeout, MaxIdleTimeout: quicpogs.MaxIdleTimeout,
KeepAlivePeriod: quicpogs.MaxIdlePingPeriod, KeepAlivePeriod: quicpogs.MaxIdlePingPeriod,
MaxIncomingStreams: quicpogs.MaxIncomingStreams, MaxIncomingStreams: quicpogs.MaxIncomingStreams,
MaxIncomingUniStreams: quicpogs.MaxIncomingStreams, MaxIncomingUniStreams: quicpogs.MaxIncomingStreams,
EnableDatagrams: true, EnableDatagrams: true,
MaxDatagramFrameSize: quicpogs.MaxDatagramFrameSize, MaxDatagramFrameSize: quicpogs.MaxDatagramFrameSize,
Tracer: quicpogs.NewClientTracer(connLogger.Logger(), connIndex), Tracer: quicpogs.NewClientTracer(connLogger.Logger(), connIndex),
DisablePathMTUDiscovery: e.config.DisableQUICPathMTUDiscovery,
} }
quicConn, err := connection.NewQUICConnection( quicConn, err := connection.NewQUICConnection(