magicsock: set the don't fragment sockopt (#8715)

This sets the Don't Fragment flag, for now behind the
TS_DEBUG_ENABLE_PMTUD envknob.

Updates #311.

Signed-off-by: Val <valerie@tailscale.com>
Signed-off-by: salman <salman@tailscale.com>
pull/8851/head
salman aljammaz 1 year ago committed by GitHub
parent 16bc9350e3
commit 99e06d3544
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -47,6 +47,8 @@ var (
// debugRingBufferMaxSizeBytes overrides the default size of the endpoint // debugRingBufferMaxSizeBytes overrides the default size of the endpoint
// history ringbuffer. // history ringbuffer.
debugRingBufferMaxSizeBytes = envknob.RegisterInt("TS_DEBUG_MAGICSOCK_RING_BUFFER_MAX_SIZE_BYTES") debugRingBufferMaxSizeBytes = envknob.RegisterInt("TS_DEBUG_MAGICSOCK_RING_BUFFER_MAX_SIZE_BYTES")
// debugPMTUD enables path MTU discovery. Currently only sets the Don't Fragment sockopt.
debugPMTUD = envknob.RegisterBool("TS_DEBUG_ENABLE_PMTUD")
// Hey you! Adding a new debugknob? Make sure to stub it out in the debugknob_stubs.go // Hey you! Adding a new debugknob? Make sure to stub it out in the debugknob_stubs.go
// file too. // file too.
) )

@ -20,6 +20,7 @@ func debugAlwaysDERP() bool { return false }
func debugUseDERPHTTP() bool { return false } func debugUseDERPHTTP() bool { return false }
func debugEnableSilentDisco() bool { return false } func debugEnableSilentDisco() bool { return false }
func debugSendCallMeUnknownPeer() bool { return false } func debugSendCallMeUnknownPeer() bool { return false }
func debugPMTUD() bool { return false }
func debugUseDERPAddr() string { return "" } func debugUseDERPAddr() string { return "" }
func debugUseDerpRouteEnv() string { return "" } func debugUseDerpRouteEnv() string { return "" }
func debugUseDerpRoute() opt.Bool { return "" } func debugUseDerpRoute() opt.Bool { return "" }

@ -0,0 +1,35 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build darwin && !ios
package magicsock
import (
"net"
"syscall"
"golang.org/x/sys/unix"
"tailscale.com/types/nettype"
)
func setDontFragment(pconn nettype.PacketConn, network string) (err error) {
if c, ok := pconn.(*net.UDPConn); ok {
rc, err := c.SyscallConn()
if err == nil {
rc.Control(func(fd uintptr) {
if network == "udp4" {
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, unix.IP_DONTFRAG, 1)
}
if network == "udp6" {
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, unix.IPV6_DONTFRAG, 1)
}
})
}
}
return err
}
func CanPMTUD() bool {
return debugPMTUD() // only if the envknob is for now.
}

@ -0,0 +1,24 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build (!linux && !darwin) || android || ios
package magicsock
import (
"errors"
"tailscale.com/types/nettype"
)
// setDontFragment sets the dontfragment sockopt on pconn on the platforms that support it,
// for both IPv4 and IPv6.
// (C.f. https://datatracker.ietf.org/doc/html/rfc3542#section-11.2 for IPv6 fragmentation)
func setDontFragment(pconn nettype.PacketConn, network string) (err error) {
return errors.New("setting don't fragment bit not supported on this OS")
}
// CanPMTUD returns whether this platform supports performing peet path MTU discovery.
func CanPMTUD() bool {
return false
}

@ -0,0 +1,34 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build linux && !android
package magicsock
import (
"net"
"syscall"
"tailscale.com/types/nettype"
)
func setDontFragment(pconn nettype.PacketConn, network string) (err error) {
if c, ok := pconn.(*net.UDPConn); ok {
rc, err := c.SyscallConn()
if err == nil {
rc.Control(func(fd uintptr) {
if network == "udp4" {
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DO)
}
if network == "udp6" {
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DO)
}
})
}
}
return err
}
func CanPMTUD() bool {
return debugPMTUD() // only if the envknob is enabled, for now.
}

@ -2233,6 +2233,16 @@ func (c *Conn) bindSocket(ruc *RebindingUDPConn, network string, curPortFate cur
continue continue
} }
trySetSocketBuffer(pconn, c.logf) trySetSocketBuffer(pconn, c.logf)
if CanPMTUD() {
err = setDontFragment(pconn, network)
if err != nil {
c.logf("magicsock: set dontfragment failed for %v port %d: %v", network, port, err)
// TODO disable PMTUD in this case. We don't expect the setsockopt to fail on
// supported platforms, but we might as well be paranoid.
}
}
// Success. // Success.
if debugBindSocket() { if debugBindSocket() {
c.logf("magicsock: bindSocket: successfully listened %v port %d", network, port) c.logf("magicsock: bindSocket: successfully listened %v port %d", network, port)

Loading…
Cancel
Save