forked from quic-go/quic-go
make Path MTU Discovery resilient to random packet loss (#4545)
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/rand"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
@@ -25,6 +27,7 @@ var _ = Describe("MTU Discoverer", func() {
|
||||
now time.Time
|
||||
discoveredMTU protocol.ByteCount
|
||||
)
|
||||
r := rand.New(rand.NewSource(uint64(GinkgoRandomSeed())))
|
||||
|
||||
BeforeEach(func() {
|
||||
rttStats = &utils.RTTStats{}
|
||||
@@ -76,6 +79,7 @@ var _ = Describe("MTU Discoverer", func() {
|
||||
t := now.Add(5 * rtt)
|
||||
for d.ShouldSendProbe(t) {
|
||||
ping, size := d.GetPing()
|
||||
fmt.Println("sending", size)
|
||||
ping.Handler.OnAcked(ping.Frame)
|
||||
sizes = append(sizes, size)
|
||||
t = t.Add(5 * rtt)
|
||||
@@ -91,53 +95,107 @@ var _ = Describe("MTU Discoverer", func() {
|
||||
}
|
||||
})
|
||||
|
||||
It("finds the MTU", func() {
|
||||
const rep = 3000
|
||||
var maxDiff protocol.ByteCount
|
||||
for i := 0; i < rep; i++ {
|
||||
maxMTU := protocol.ByteCount(rand.Intn(int(3000-startMTU))) + startMTU + 1
|
||||
currentMTU := startMTU
|
||||
var tracedMTU protocol.ByteCount
|
||||
var tracerDone bool
|
||||
d := newMTUDiscoverer(
|
||||
rttStats,
|
||||
startMTU,
|
||||
maxMTU,
|
||||
func(s protocol.ByteCount) { currentMTU = s },
|
||||
&logging.ConnectionTracer{
|
||||
UpdatedMTU: func(mtu logging.ByteCount, done bool) {
|
||||
tracedMTU = mtu
|
||||
tracerDone = done
|
||||
},
|
||||
It("finds the MTU", MustPassRepeatedly(300), func() {
|
||||
maxMTU := protocol.ByteCount(r.Intn(int(3000-startMTU))) + startMTU + 1
|
||||
currentMTU := startMTU
|
||||
var tracedMTU protocol.ByteCount
|
||||
var tracerDone bool
|
||||
d := newMTUDiscoverer(
|
||||
rttStats,
|
||||
startMTU,
|
||||
maxMTU,
|
||||
func(s protocol.ByteCount) { currentMTU = s },
|
||||
&logging.ConnectionTracer{
|
||||
UpdatedMTU: func(mtu logging.ByteCount, done bool) {
|
||||
tracedMTU = mtu
|
||||
tracerDone = done
|
||||
},
|
||||
)
|
||||
d.Start()
|
||||
now := time.Now()
|
||||
realMTU := protocol.ByteCount(rand.Intn(int(maxMTU-startMTU))) + startMTU
|
||||
t := now.Add(mtuProbeDelay * rtt)
|
||||
var count int
|
||||
for d.ShouldSendProbe(t) {
|
||||
if count > 25 {
|
||||
Fail("too many iterations")
|
||||
}
|
||||
count++
|
||||
|
||||
ping, size := d.GetPing()
|
||||
if size <= realMTU {
|
||||
ping.Handler.OnAcked(ping.Frame)
|
||||
} else {
|
||||
ping.Handler.OnLost(ping.Frame)
|
||||
}
|
||||
t = t.Add(mtuProbeDelay * rtt)
|
||||
},
|
||||
)
|
||||
d.Start()
|
||||
now := time.Now()
|
||||
realMTU := protocol.ByteCount(r.Intn(int(maxMTU-startMTU))) + startMTU
|
||||
fmt.Fprintf(GinkgoWriter, "MTU: %d, max: %d\n", realMTU, maxMTU)
|
||||
t := now.Add(mtuProbeDelay * rtt)
|
||||
var probes []protocol.ByteCount
|
||||
for d.ShouldSendProbe(t) {
|
||||
if len(probes) > 24 {
|
||||
Fail(fmt.Sprintf("too many iterations: %v", probes))
|
||||
}
|
||||
diff := realMTU - currentMTU
|
||||
Expect(diff).To(BeNumerically(">=", 0))
|
||||
maxDiff = max(maxDiff, diff)
|
||||
if maxMTU > currentMTU+maxMTU {
|
||||
Expect(tracedMTU).To(Equal(currentMTU))
|
||||
Expect(tracerDone).To(BeTrue())
|
||||
ping, size := d.GetPing()
|
||||
probes = append(probes, size)
|
||||
if size <= realMTU {
|
||||
ping.Handler.OnAcked(ping.Frame)
|
||||
} else {
|
||||
ping.Handler.OnLost(ping.Frame)
|
||||
}
|
||||
t = t.Add(mtuProbeDelay * rtt)
|
||||
}
|
||||
Expect(maxDiff).To(BeEquivalentTo(maxMTUDiff))
|
||||
diff := realMTU - currentMTU
|
||||
Expect(diff).To(BeNumerically(">=", 0))
|
||||
if maxMTU > currentMTU+maxMTU {
|
||||
Expect(tracedMTU).To(Equal(currentMTU))
|
||||
Expect(tracerDone).To(BeTrue())
|
||||
}
|
||||
fmt.Fprintf(GinkgoWriter, "MTU discovered: %d (diff: %d)\n", currentMTU, diff)
|
||||
fmt.Fprintf(GinkgoWriter, "probes sent (%d): %v\n", len(probes), probes)
|
||||
Expect(diff).To(BeNumerically("<=", maxMTUDiff))
|
||||
})
|
||||
|
||||
const maxRandomLoss = maxLostMTUProbes - 1
|
||||
It(fmt.Sprintf("finds the MTU, with up to %d packets lost", maxRandomLoss), MustPassRepeatedly(500), func() {
|
||||
maxMTU := protocol.ByteCount(r.Intn(int(3000-startMTU))) + startMTU + 1
|
||||
currentMTU := startMTU
|
||||
var tracedMTU protocol.ByteCount
|
||||
var tracerDone bool
|
||||
d := newMTUDiscoverer(
|
||||
rttStats,
|
||||
startMTU,
|
||||
maxMTU,
|
||||
func(s protocol.ByteCount) { currentMTU = s },
|
||||
&logging.ConnectionTracer{
|
||||
UpdatedMTU: func(mtu logging.ByteCount, done bool) {
|
||||
tracedMTU = mtu
|
||||
tracerDone = done
|
||||
},
|
||||
},
|
||||
)
|
||||
d.Start()
|
||||
now := time.Now()
|
||||
realMTU := protocol.ByteCount(r.Intn(int(maxMTU-startMTU))) + startMTU
|
||||
fmt.Fprintf(GinkgoWriter, "MTU: %d, max: %d\n", realMTU, maxMTU)
|
||||
t := now.Add(mtuProbeDelay * rtt)
|
||||
var probes, randomLosses []protocol.ByteCount
|
||||
for d.ShouldSendProbe(t) {
|
||||
if len(probes) > 32 {
|
||||
Fail(fmt.Sprintf("too many iterations: %v", probes))
|
||||
}
|
||||
ping, size := d.GetPing()
|
||||
probes = append(probes, size)
|
||||
packetFits := size <= realMTU
|
||||
var acked bool
|
||||
if packetFits {
|
||||
randomLoss := r.Intn(maxLostMTUProbes) == 0 && len(randomLosses) < maxRandomLoss
|
||||
if randomLoss {
|
||||
randomLosses = append(randomLosses, size)
|
||||
} else {
|
||||
ping.Handler.OnAcked(ping.Frame)
|
||||
acked = true
|
||||
}
|
||||
}
|
||||
if !acked {
|
||||
ping.Handler.OnLost(ping.Frame)
|
||||
}
|
||||
t = t.Add(mtuProbeDelay * rtt)
|
||||
}
|
||||
diff := realMTU - currentMTU
|
||||
Expect(diff).To(BeNumerically(">=", 0))
|
||||
if maxMTU > currentMTU+maxMTU {
|
||||
Expect(tracedMTU).To(Equal(currentMTU))
|
||||
Expect(tracerDone).To(BeTrue())
|
||||
}
|
||||
fmt.Fprintf(GinkgoWriter, "MTU discovered with random losses %v: %d (diff: %d)\n", randomLosses, currentMTU, diff)
|
||||
fmt.Fprintf(GinkgoWriter, "probes sent (%d): %v\n", len(probes), probes)
|
||||
Expect(diff).To(BeNumerically("<=", maxMTUDiff))
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user