mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 12:47:36 +03:00
reduce the number of skipped packet numbers for long connections
This commit is contained in:
parent
416d88990b
commit
431dff2172
4 changed files with 53 additions and 45 deletions
|
@ -6,6 +6,7 @@ import (
|
||||||
mrand "math/rand"
|
mrand "math/rand"
|
||||||
|
|
||||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||||
|
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type packetNumberGenerator interface {
|
type packetNumberGenerator interface {
|
||||||
|
@ -37,8 +38,9 @@ func (p *sequentialPacketNumberGenerator) Pop() protocol.PacketNumber {
|
||||||
// it randomly skips a packet number every averagePeriod packets (on average).
|
// it randomly skips a packet number every averagePeriod packets (on average).
|
||||||
// It is guaranteed to never skip two consecutive packet numbers.
|
// It is guaranteed to never skip two consecutive packet numbers.
|
||||||
type skippingPacketNumberGenerator struct {
|
type skippingPacketNumberGenerator struct {
|
||||||
rand *mrand.Rand
|
rand *mrand.Rand
|
||||||
averagePeriod protocol.PacketNumber
|
period protocol.PacketNumber
|
||||||
|
maxPeriod protocol.PacketNumber
|
||||||
|
|
||||||
next protocol.PacketNumber
|
next protocol.PacketNumber
|
||||||
nextToSkip protocol.PacketNumber
|
nextToSkip protocol.PacketNumber
|
||||||
|
@ -46,13 +48,14 @@ type skippingPacketNumberGenerator struct {
|
||||||
|
|
||||||
var _ packetNumberGenerator = &skippingPacketNumberGenerator{}
|
var _ packetNumberGenerator = &skippingPacketNumberGenerator{}
|
||||||
|
|
||||||
func newSkippingPacketNumberGenerator(initial, averagePeriod protocol.PacketNumber) packetNumberGenerator {
|
func newSkippingPacketNumberGenerator(initial, initialPeriod, maxPeriod protocol.PacketNumber) packetNumberGenerator {
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
rand.Read(b) // it's not the end of the world if we don't get perfect random here
|
rand.Read(b) // it's not the end of the world if we don't get perfect random here
|
||||||
g := &skippingPacketNumberGenerator{
|
g := &skippingPacketNumberGenerator{
|
||||||
rand: mrand.New(mrand.NewSource(int64(binary.LittleEndian.Uint64(b)))),
|
rand: mrand.New(mrand.NewSource(int64(binary.LittleEndian.Uint64(b)))),
|
||||||
next: initial,
|
next: initial,
|
||||||
averagePeriod: averagePeriod,
|
period: initialPeriod,
|
||||||
|
maxPeriod: maxPeriod,
|
||||||
}
|
}
|
||||||
g.generateNewSkip()
|
g.generateNewSkip()
|
||||||
return g
|
return g
|
||||||
|
@ -74,5 +77,6 @@ func (p *skippingPacketNumberGenerator) Pop() protocol.PacketNumber {
|
||||||
|
|
||||||
func (p *skippingPacketNumberGenerator) generateNewSkip() {
|
func (p *skippingPacketNumberGenerator) generateNewSkip() {
|
||||||
// make sure that there are never two consecutive packet numbers that are skipped
|
// make sure that there are never two consecutive packet numbers that are skipped
|
||||||
p.nextToSkip = p.next + 2 + protocol.PacketNumber(p.rand.Int31n(int32(2*p.averagePeriod)))
|
p.nextToSkip = p.next + 2 + protocol.PacketNumber(p.rand.Int63n(int64(2*p.period)))
|
||||||
|
p.period = utils.MinPacketNumber(2*p.period, p.maxPeriod)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package ackhandler
|
package ackhandler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
@ -20,24 +23,17 @@ var _ = Describe("Sequential Packet Number Generator", func() {
|
||||||
})
|
})
|
||||||
|
|
||||||
var _ = Describe("Skipping Packet Number Generator", func() {
|
var _ = Describe("Skipping Packet Number Generator", func() {
|
||||||
var png *skippingPacketNumberGenerator
|
|
||||||
const initialPN protocol.PacketNumber = 8
|
const initialPN protocol.PacketNumber = 8
|
||||||
|
const initialPeriod protocol.PacketNumber = 25
|
||||||
BeforeEach(func() {
|
const maxPeriod protocol.PacketNumber = 300
|
||||||
png = newSkippingPacketNumberGenerator(initialPN, 100).(*skippingPacketNumberGenerator)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("can be initialized to return any first packet number", func() {
|
It("can be initialized to return any first packet number", func() {
|
||||||
png = newSkippingPacketNumberGenerator(12345, 100).(*skippingPacketNumberGenerator)
|
png := newSkippingPacketNumberGenerator(12345, initialPeriod, maxPeriod)
|
||||||
Expect(png.Pop()).To(Equal(protocol.PacketNumber(12345)))
|
Expect(png.Pop()).To(Equal(protocol.PacketNumber(12345)))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("gets the first packet number", func() {
|
|
||||||
num := png.Pop()
|
|
||||||
Expect(num).To(Equal(initialPN))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("allows peeking", func() {
|
It("allows peeking", func() {
|
||||||
|
png := newSkippingPacketNumberGenerator(initialPN, initialPeriod, maxPeriod).(*skippingPacketNumberGenerator)
|
||||||
png.nextToSkip = 1000
|
png.nextToSkip = 1000
|
||||||
Expect(png.Peek()).To(Equal(initialPN))
|
Expect(png.Peek()).To(Equal(initialPN))
|
||||||
Expect(png.Peek()).To(Equal(initialPN))
|
Expect(png.Peek()).To(Equal(initialPN))
|
||||||
|
@ -47,6 +43,7 @@ var _ = Describe("Skipping Packet Number Generator", func() {
|
||||||
})
|
})
|
||||||
|
|
||||||
It("skips a packet number", func() {
|
It("skips a packet number", func() {
|
||||||
|
png := newSkippingPacketNumberGenerator(initialPN, initialPeriod, maxPeriod)
|
||||||
var last protocol.PacketNumber
|
var last protocol.PacketNumber
|
||||||
var skipped bool
|
var skipped bool
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
|
@ -60,35 +57,38 @@ var _ = Describe("Skipping Packet Number Generator", func() {
|
||||||
Expect(skipped).To(BeTrue())
|
Expect(skipped).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("skips a specific packet number", func() {
|
|
||||||
png.nextToSkip = initialPN + 1
|
|
||||||
Expect(png.Pop()).To(Equal(initialPN))
|
|
||||||
Expect(png.Peek()).To(Equal(initialPN + 2))
|
|
||||||
Expect(png.Pop()).To(Equal(initialPN + 2))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("generates a new packet number to skip", func() {
|
It("generates a new packet number to skip", func() {
|
||||||
const averagePeriod = 25
|
const rep = 500
|
||||||
png.averagePeriod = averagePeriod
|
periods := make([][]protocol.PacketNumber, rep)
|
||||||
|
expectedPeriods := []protocol.PacketNumber{25, 50, 100, 200, 300, 300, 300}
|
||||||
|
|
||||||
periods := make([]protocol.PacketNumber, 0, 500)
|
for i := 0; i < rep; i++ {
|
||||||
last := initialPN
|
png := newSkippingPacketNumberGenerator(initialPN, initialPeriod, maxPeriod)
|
||||||
var lastSkip protocol.PacketNumber
|
last := initialPN
|
||||||
for len(periods) < cap(periods) {
|
lastSkip := initialPN
|
||||||
next := png.Pop()
|
for len(periods[i]) < len(expectedPeriods) {
|
||||||
if next > last+1 {
|
next := png.Pop()
|
||||||
skipped := next - 1
|
if next > last+1 {
|
||||||
Expect(skipped).To(BeNumerically(">", lastSkip+1))
|
skipped := next - 1
|
||||||
periods = append(periods, skipped-lastSkip-1)
|
Expect(skipped).To(BeNumerically(">", lastSkip+1))
|
||||||
lastSkip = skipped
|
periods[i] = append(periods[i], skipped-lastSkip-1)
|
||||||
|
lastSkip = skipped
|
||||||
|
}
|
||||||
|
last = next
|
||||||
}
|
}
|
||||||
last = next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var average float64
|
for j := 0; j < len(expectedPeriods); j++ {
|
||||||
for _, p := range periods {
|
var average float64
|
||||||
average += float64(p) / float64(len(periods))
|
for i := 0; i < rep; i++ {
|
||||||
|
average += float64(periods[i][j]) / float64(len(periods))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(GinkgoWriter, "Period %d: %.2f (expected %d)\n", j, average, expectedPeriods[j])
|
||||||
|
tolerance := protocol.PacketNumber(5)
|
||||||
|
if t := expectedPeriods[j] / 10; t > tolerance {
|
||||||
|
tolerance = t
|
||||||
|
}
|
||||||
|
Expect(average).To(BeNumerically("~", expectedPeriods[j]+1 /* we never skip two packet numbers at the same time */, tolerance))
|
||||||
}
|
}
|
||||||
Expect(average).To(BeNumerically("~", averagePeriod+1 /* we never skip two packet numbers at the same time */, 5))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -37,7 +37,7 @@ type packetNumberSpace struct {
|
||||||
func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStats *utils.RTTStats) *packetNumberSpace {
|
func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStats *utils.RTTStats) *packetNumberSpace {
|
||||||
var pns packetNumberGenerator
|
var pns packetNumberGenerator
|
||||||
if skipPNs {
|
if skipPNs {
|
||||||
pns = newSkippingPacketNumberGenerator(initialPN, protocol.SkipPacketAveragePeriodLength)
|
pns = newSkippingPacketNumberGenerator(initialPN, protocol.SkipPacketInitialPeriod, protocol.SkipPacketMaxPeriod)
|
||||||
} else {
|
} else {
|
||||||
pns = newSequentialPacketNumberGenerator(initialPN)
|
pns = newSequentialPacketNumberGenerator(initialPN)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,12 @@ const MaxServerUnprocessedPackets = 1024
|
||||||
// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed.
|
// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed.
|
||||||
const MaxSessionUnprocessedPackets = 256
|
const MaxSessionUnprocessedPackets = 256
|
||||||
|
|
||||||
// SkipPacketAveragePeriodLength is the average period length in which one packet number is skipped to prevent an Optimistic ACK attack
|
// SkipPacketInitialPeriod is the initial period length used for packet number skipping to prevent an Optimistic ACK attack.
|
||||||
const SkipPacketAveragePeriodLength PacketNumber = 500
|
// Every time a packet number is skipped, the period is doubled, up to SkipPacketMaxPeriod.
|
||||||
|
const SkipPacketInitialPeriod PacketNumber = 256
|
||||||
|
|
||||||
|
// SkipPacketMaxPeriod is the maximum period length used for packet number skipping.
|
||||||
|
const SkipPacketMaxPeriod PacketNumber = 128 * 1024
|
||||||
|
|
||||||
// MaxAcceptQueueSize is the maximum number of sessions that the server queues for accepting.
|
// MaxAcceptQueueSize is the maximum number of sessions that the server queues for accepting.
|
||||||
// If the queue is full, new connection attempts will be rejected.
|
// If the queue is full, new connection attempts will be rejected.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue