Replace CanPMTUD() with ShouldPMTUD() to check if peer path MTU discovery should be enabled, in preparation for adding support for enabling/disabling peer MTU dynamically. Updated #311 Signed-off-by: Val <valerie@tailscale.com>main
parent
a5ae21a832
commit
95635857dc
@ -0,0 +1,99 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build (darwin && !ios) || (linux && !android)
|
||||
|
||||
package magicsock |
||||
|
||||
// Peer path MTU routines shared by platforms that implement it.
|
||||
|
||||
// DontFragSetting returns true if at least one of the underlying sockets of
|
||||
// this connection is a UDP socket with the don't fragment bit set, otherwise it
|
||||
// returns false. It also returns an error if either connection returned an error
|
||||
// other than errUnsupportedConnType.
|
||||
func (c *Conn) DontFragSetting() (bool, error) { |
||||
df4, err4 := c.getDontFragment("udp4") |
||||
df6, err6 := c.getDontFragment("udp6") |
||||
df := df4 || df6 |
||||
err := err4 |
||||
if err4 != nil && err4 != errUnsupportedConnType { |
||||
err = err6 |
||||
} |
||||
if err == errUnsupportedConnType { |
||||
err = nil |
||||
} |
||||
return df, err |
||||
} |
||||
|
||||
// ShouldPMTUD returns true if this client should try to enable peer MTU
|
||||
// discovery, false otherwise.
|
||||
func (c *Conn) ShouldPMTUD() bool { |
||||
if v, ok := debugEnablePMTUD().Get(); ok { |
||||
if debugPMTUD() { |
||||
c.logf("magicsock: peermtu: peer path MTU discovery set via envknob to %v", v) |
||||
} |
||||
return v |
||||
} |
||||
if debugPMTUD() { |
||||
c.logf("magicsock: peermtu: peer path MTU discovery set by default to false") |
||||
} |
||||
return false // Until we feel confident PMTUD is solid.
|
||||
} |
||||
|
||||
// PeerMTUEnabled returns true if this Conn is has peer path MTU discovery enabled.
|
||||
func (c *Conn) PeerMTUEnabled() bool { |
||||
return c.peerMTUEnabled.Load() |
||||
} |
||||
|
||||
// UpdatePMTUD configures underlying sockets of this Conn to enable or disable
|
||||
// peer path MTU discovery according to the current configuration.
|
||||
//
|
||||
// Enabling or disabling peer path MTU discovery requires setting the don't
|
||||
// fragment bit on its two underlying pconns. There are three distinct results
|
||||
// for this operation on each pconn:
|
||||
//
|
||||
// 1. Success
|
||||
// 2. Failure (not supported on this platform, or supported but failed)
|
||||
// 3. Not a UDP socket (most likely one of IPv4 or IPv6 couldn't be used)
|
||||
//
|
||||
// To simplify the fast path for the most common case, we set the PMTUD status
|
||||
// of the overall Conn according to the results of setting the sockopt on pconn
|
||||
// as follows:
|
||||
//
|
||||
// 1. Both setsockopts succeed: PMTUD status update succeeds
|
||||
// 2. One succeeds, one returns not a UDP socket: PMTUD status update succeeds
|
||||
// 4. Neither setsockopt succeeds: PMTUD disabled
|
||||
// 3. Either setsockopt fails: PMTUD disabled
|
||||
//
|
||||
// If the PMTUD settings changed, it resets the endpoint state so that it will
|
||||
// re-probe path MTUs to this peer.
|
||||
func (c *Conn) UpdatePMTUD() { |
||||
if debugPMTUD() { |
||||
df4, err4 := c.getDontFragment("udp4") |
||||
df6, err6 := c.getDontFragment("udp6") |
||||
c.logf("magicsock: peermtu: peer MTU status %v DF bit status: v4: %v (%v) v6: %v (%v)", c.peerMTUEnabled.Load(), df4, err4, df6, err6) |
||||
} |
||||
|
||||
enable := c.ShouldPMTUD() |
||||
if c.peerMTUEnabled.Load() == enable { |
||||
c.logf("magicsock: peermtu: peer MTU status is %v", enable) |
||||
return |
||||
} |
||||
|
||||
newStatus := enable |
||||
err4 := c.setDontFragment("udp4", enable) |
||||
err6 := c.setDontFragment("udp6", enable) |
||||
anySuccess := err4 == nil || err6 == nil |
||||
noFailures := (err4 == nil || err4 == errUnsupportedConnType) && (err6 == nil || err6 == errUnsupportedConnType) |
||||
|
||||
if anySuccess && noFailures { |
||||
c.logf("magicsock: peermtu: peer MTU status updated to %v", newStatus) |
||||
} else { |
||||
c.logf("[unexpected] magicsock: peermtu: updating peer MTU status to %v failed (v4: %v, v6: %v), disabling", enable, err4, err6) |
||||
_ = c.setDontFragment("udp4", false) |
||||
_ = c.setDontFragment("udp6", false) |
||||
newStatus = false |
||||
} |
||||
c.peerMTUEnabled.Store(newStatus) |
||||
c.resetEndpointStates() |
||||
} |
||||
Loading…
Reference in new issue