package quicimport ()type mtuDiscoverer interface {// Start starts the MTU discovery process. // It's unnecessary to call ShouldSendProbe before that. Start(now monotime.Time) ShouldSendProbe(now monotime.Time) bool CurrentSize() protocol.ByteCount GetPing(now monotime.Time) (ping ackhandler.Frame, datagramSize protocol.ByteCount) Reset(now monotime.Time, start, max protocol.ByteCount)}const (// At some point, we have to stop searching for a higher MTU. // We're happy to send a packet that's 10 bytes smaller than the actual MTU. maxMTUDiff protocol.ByteCount = 20// send a probe packet every mtuProbeDelay RTTs mtuProbeDelay = 5// Once maxLostMTUProbes MTU probe packets larger than a certain size are lost, // MTU discovery won't probe for larger MTUs than this size. // The algorithm used here is resilient to packet loss of (maxLostMTUProbes - 1) packets. maxLostMTUProbes = 3)// The Path MTU is found by sending a larger packet every now and then.// If the packet is acknowledged, we conclude that the path supports this larger packet size.// If the packet is lost, this can mean one of two things:// 1. The path doesn't support this larger packet size, or// 2. The packet was lost due to packet loss, independent of its size.// The algorithm used here is resilient to packet loss of (maxLostMTUProbes - 1) packets.// For simplicty, the following example use maxLostMTUProbes = 2.//// Initialization:// |------------------------------------------------------------------------------|// min max//// The first MTU probe packet will have size (min+max)/2.// Assume that this packet is acknowledged. We can now move the min marker,// and continue the search in the resulting interval.//// If 1st probe packet acknowledged:// |---------------------------------------|--------------------------------------|// min max//// If 1st probe packet lost:// |---------------------------------------|--------------------------------------|// min lost[0] max//// We can't conclude that the path doesn't support this packet size, since the loss of the probe// packet could have been unrelated to the packet size. A larger probe packet will be sent later on.// After a loss, the next probe packet has size (min+lost[0])/2.// Now assume this probe packet is acknowledged://// 2nd probe packet acknowledged:// |------------------|--------------------|--------------------------------------|// min lost[0] max//// First of all, we conclude that the path supports at least this MTU. That's progress!// Second, we probe a bit more aggressively with the next probe packet:// After an acknowledgement, the next probe packet has size (min+max)/2.// This means we'll send a packet larger than the first probe packet (which was lost).//// If 3rd probe packet acknowledged:// |-------------------------------------------------|----------------------------|// min max//// We can conclude that the loss of the 1st probe packet was not due to its size, and// continue searching in a much smaller interval now.//// If 3rd probe packet lost:// |------------------|--------------------|---------|----------------------------|// min lost[0] max//// Since in our example numPTOProbes = 2, and we lost 2 packets smaller than max, we// conclude that this packet size is not supported on the path, and reduce the maximum// value of the search interval.//// MTU discovery concludes once the interval min and max has been narrowed down to maxMTUDiff.type mtuFinder struct { lastProbeTime monotime.Time rttStats *utils.RTTStats inFlight protocol.ByteCount// the size of the probe packet currently in flight. InvalidByteCount if none is in flight min protocol.ByteCount// on initialization, we treat the maximum size as the first "lost" packet lost [maxLostMTUProbes]protocol.ByteCount lastProbeWasLost bool// The generation is used to ignore ACKs / losses for probe packets sent before a reset. // Resets happen when the connection is migrated to a new path. // We're therefore not concerned about overflows of this counter. generation uint8 qlogger qlogwriter.Recorder}var _ mtuDiscoverer = &mtuFinder{}func newMTUDiscoverer( *utils.RTTStats, , protocol.ByteCount,qlogwriter.Recorder,) *mtuFinder { := &mtuFinder{inFlight: protocol.InvalidByteCount,rttStats: ,qlogger: , } .init(, )return}func ( *mtuFinder) (, protocol.ByteCount) { .min = for := range .lost {if == 0 { .lost[] = continue } .lost[] = protocol.InvalidByteCount }}func ( *mtuFinder) () bool {return .max()-.min <= maxMTUDiff+1}func ( *mtuFinder) () protocol.ByteCount {for , := range .lost {if == protocol.InvalidByteCount {return .lost[-1] } }return .lost[len(.lost)-1]}func ( *mtuFinder) ( monotime.Time) { .lastProbeTime = // makes sure the first probe packet is not sent immediately}func ( *mtuFinder) ( monotime.Time) bool {if .lastProbeTime.IsZero() {returnfalse }if .inFlight != protocol.InvalidByteCount || .done() {returnfalse }return !.Before(.lastProbeTime.Add(mtuProbeDelay * .rttStats.SmoothedRTT()))}func ( *mtuFinder) ( monotime.Time) (ackhandler.Frame, protocol.ByteCount) {varprotocol.ByteCountif .lastProbeWasLost { = (.min + .lost[0]) / 2 } else { = (.min + .max()) / 2 } .lastProbeTime = .inFlight = returnackhandler.Frame{Frame: &wire.PingFrame{},Handler: &mtuFinderAckHandler{mtuFinder: , generation: .generation}, }, }func ( *mtuFinder) () protocol.ByteCount {return .min}func ( *mtuFinder) ( monotime.Time, , protocol.ByteCount) { .generation++ .lastProbeTime = .lastProbeWasLost = false .inFlight = protocol.InvalidByteCount .init(, )}type mtuFinderAckHandler struct { *mtuFinder generation uint8}var _ ackhandler.FrameHandler = &mtuFinderAckHandler{}func ( *mtuFinderAckHandler) (wire.Frame) {if .generation != .mtuFinder.generation {// ACK for probe sent before resetreturn } := .inFlightif == protocol.InvalidByteCount {panic("OnAcked callback called although there's no MTU probe packet in flight") } .inFlight = protocol.InvalidByteCount .min = .lastProbeWasLost = false// remove all values smaller than size from the lost arrayvarintfor , := range .lost {if < { = break } }if > 0 {for := 0; < len(.lost); ++ {if + < len(.lost) { .lost[] = .lost[+] } else { .lost[] = protocol.InvalidByteCount } } }if .qlogger != nil { .qlogger.RecordEvent(qlog.MTUUpdated{Value: int(),Done: .done(), }) }}func ( *mtuFinderAckHandler) (wire.Frame) {if .generation != .mtuFinder.generation {// probe sent before reset receivedreturn } := .inFlightif == protocol.InvalidByteCount {panic("OnLost callback called although there's no MTU probe packet in flight") } .lastProbeWasLost = true .inFlight = protocol.InvalidByteCountfor , := range .lost {if < {copy(.lost[+1:], .lost[:]) .lost[] = break } }}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.