disco,net/tstun,wgengine/magicsock: probe peer MTU
Automatically probe the path MTU to a peer when peer MTU is enabled, but do not use the MTU information for anything yet. Updates #311 Signed-off-by: Val <valerie@tailscale.com>
This commit is contained in:
@ -35,6 +35,16 @@ import (
|
||||
"tailscale.com/util/ringbuffer"
|
||||
)
|
||||
|
||||
var mtuProbePingSizesV4 []int
|
||||
var mtuProbePingSizesV6 []int
|
||||
|
||||
func init() {
|
||||
for _, m := range tstun.WireMTUsToProbe {
|
||||
mtuProbePingSizesV4 = append(mtuProbePingSizesV4, pktLenToPingSize(m, false))
|
||||
mtuProbePingSizesV6 = append(mtuProbePingSizesV6, pktLenToPingSize(m, true))
|
||||
}
|
||||
}
|
||||
|
||||
// endpoint is a wireguard/conn.Endpoint. In wireguard-go and kernel WireGuard
|
||||
// there is only one endpoint for a peer, but in Tailscale we distribute a
|
||||
// number of possible endpoints for a peer which would include the all the
|
||||
@ -374,7 +384,7 @@ func (de *endpoint) addrForPingSizeLocked(now mono.Time, size int) (udpAddr, der
|
||||
|
||||
udpAddr = de.bestAddr.AddrPort
|
||||
pathMTU := de.bestAddr.wireMTU
|
||||
requestedMTU := pingSizeToPktLen(size, udpAddr.Addr())
|
||||
requestedMTU := pingSizeToPktLen(size, udpAddr.Addr().Is6())
|
||||
mtuOk := requestedMTU <= pathMTU
|
||||
|
||||
if udpAddr.IsValid() && mtuOk {
|
||||
@ -666,21 +676,41 @@ func (de *endpoint) startDiscoPingLocked(ep netip.AddrPort, now mono.Time, purpo
|
||||
st.lastPing = now
|
||||
}
|
||||
|
||||
txid := stun.NewTxID()
|
||||
de.sentPing[txid] = sentPing{
|
||||
to: ep,
|
||||
at: now,
|
||||
timer: time.AfterFunc(pingTimeoutDuration, func() { de.discoPingTimeout(txid) }),
|
||||
purpose: purpose,
|
||||
res: res,
|
||||
cb: cb,
|
||||
// If we are doing a discovery ping or a CLI ping with no specified size
|
||||
// to a non DERP address, then probe the MTU. Otherwise just send the
|
||||
// one specified ping.
|
||||
|
||||
// Default to sending a single ping of the specified size
|
||||
sizes := []int{size}
|
||||
if de.c.PeerMTUEnabled() {
|
||||
isDerp := ep.Addr() == tailcfg.DerpMagicIPAddr
|
||||
if !isDerp && ((purpose == pingDiscovery) || (purpose == pingCLI && size == 0)) {
|
||||
de.c.dlogf("[v1] magicsock: starting MTU probe")
|
||||
sizes = mtuProbePingSizesV4
|
||||
if ep.Addr().Is6() {
|
||||
sizes = mtuProbePingSizesV6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logLevel := discoLog
|
||||
if purpose == pingHeartbeat {
|
||||
logLevel = discoVerboseLog
|
||||
}
|
||||
go de.sendDiscoPing(ep, epDisco.key, txid, size, logLevel)
|
||||
for _, s := range sizes {
|
||||
txid := stun.NewTxID()
|
||||
de.sentPing[txid] = sentPing{
|
||||
to: ep,
|
||||
at: now,
|
||||
timer: time.AfterFunc(pingTimeoutDuration, func() { de.discoPingTimeout(txid) }),
|
||||
purpose: purpose,
|
||||
res: res,
|
||||
cb: cb,
|
||||
size: s,
|
||||
}
|
||||
go de.sendDiscoPing(ep, epDisco.key, txid, s, logLevel)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// sendDiscoPingsLocked starts pinging all of ep's endpoints.
|
||||
@ -982,13 +1012,13 @@ func (de *endpoint) noteConnectivityChange() {
|
||||
// pingSizeToPktLen calculates the minimum path MTU that would permit
|
||||
// a disco ping message of length size to reach its target at
|
||||
// addr. size is the length of the entire disco message including
|
||||
// disco headers. If size is zero, assume it is the default MTU.
|
||||
func pingSizeToPktLen(size int, addr netip.Addr) tstun.WireMTU {
|
||||
// disco headers. If size is zero, assume it is the safe wire MTU.
|
||||
func pingSizeToPktLen(size int, is6 bool) tstun.WireMTU {
|
||||
if size == 0 {
|
||||
return tstun.DefaultWireMTU()
|
||||
return tstun.SafeWireMTU()
|
||||
}
|
||||
headerLen := ipv4.HeaderLen
|
||||
if addr.Is6() {
|
||||
if is6 {
|
||||
headerLen = ipv6.HeaderLen
|
||||
}
|
||||
headerLen += 8 // UDP header length
|
||||
@ -999,12 +1029,12 @@ func pingSizeToPktLen(size int, addr netip.Addr) tstun.WireMTU {
|
||||
// create a disco ping message whose on-the-wire length is exactly mtu
|
||||
// bytes long. If mtu is zero or less than the minimum ping size, then
|
||||
// no MTU probe is desired and return zero for an unpadded ping.
|
||||
func pktLenToPingSize(mtu tstun.WireMTU, addr netip.Addr) int {
|
||||
func pktLenToPingSize(mtu tstun.WireMTU, is6 bool) int {
|
||||
if mtu == 0 {
|
||||
return 0
|
||||
}
|
||||
headerLen := ipv4.HeaderLen
|
||||
if addr.Is6() {
|
||||
if is6 {
|
||||
headerLen = ipv6.HeaderLen
|
||||
}
|
||||
headerLen += 8 // UDP header length
|
||||
@ -1053,7 +1083,7 @@ func (de *endpoint) handlePongConnLocked(m *disco.Pong, di *discoInfo, src netip
|
||||
}
|
||||
|
||||
if sp.purpose != pingHeartbeat {
|
||||
de.c.dlogf("[v1] magicsock: disco: %v<-%v (%v, %v) got pong tx=%x latency=%v pktlen=%v pong.src=%v%v", de.c.discoShort, de.discoShort(), de.publicKey.ShortString(), src, m.TxID[:6], latency.Round(time.Millisecond), pingSizeToPktLen(sp.size, sp.to.Addr()), m.Src, logger.ArgWriter(func(bw *bufio.Writer) {
|
||||
de.c.dlogf("[v1] magicsock: disco: %v<-%v (%v, %v) got pong tx=%x latency=%v pktlen=%v pong.src=%v%v", de.c.discoShort, de.discoShort(), de.publicKey.ShortString(), src, m.TxID[:6], latency.Round(time.Millisecond), pingSizeToPktLen(sp.size, sp.to.Addr().Is6()), m.Src, logger.ArgWriter(func(bw *bufio.Writer) {
|
||||
if sp.to != src {
|
||||
fmt.Fprintf(bw, " ping.to=%v", sp.to)
|
||||
}
|
||||
@ -1071,9 +1101,9 @@ func (de *endpoint) handlePongConnLocked(m *disco.Pong, di *discoInfo, src netip
|
||||
// Promote this pong response to our current best address if it's lower latency.
|
||||
// TODO(bradfitz): decide how latency vs. preference order affects decision
|
||||
if !isDerp {
|
||||
thisPong := addrQuality{sp.to, latency, pingSizeToPktLen(sp.size, sp.to.Addr())}
|
||||
thisPong := addrQuality{sp.to, latency, tstun.WireMTU(pingSizeToPktLen(sp.size, sp.to.Addr().Is6()))}
|
||||
if betterAddr(thisPong, de.bestAddr) {
|
||||
de.c.logf("magicsock: disco: node %v %v now using %v mtu %v", de.publicKey.ShortString(), de.discoShort(), sp.to, thisPong.wireMTU)
|
||||
de.c.logf("magicsock: disco: node %v %v now using %v mtu=%v tx=%x", de.publicKey.ShortString(), de.discoShort(), sp.to, thisPong.wireMTU, m.TxID[:6])
|
||||
de.debugUpdates.Add(EndpointChange{
|
||||
When: time.Now(),
|
||||
What: "handlePingLocked-bestAddr-update",
|
||||
|
Reference in New Issue
Block a user