introduce an invalid packet number to simplify ackhandler and congestion

This commit is contained in:
Marten Seemann 2019-05-13 14:49:32 +02:00
parent dca57baef6
commit e06961266c
5 changed files with 33 additions and 43 deletions

View file

@ -29,8 +29,10 @@ type packetNumberSpace struct {
func newPacketNumberSpace(initialPN protocol.PacketNumber) *packetNumberSpace {
return &packetNumberSpace{
history: newSentPacketHistory(),
pns: newPacketNumberGenerator(initialPN, protocol.SkipPacketAveragePeriodLength),
history: newSentPacketHistory(),
pns: newPacketNumberGenerator(initialPN, protocol.SkipPacketAveragePeriodLength),
largestSent: protocol.InvalidPacketNumber,
largestAcked: protocol.InvalidPacketNumber,
}
}
@ -161,14 +163,15 @@ func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLev
func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* is ack-eliciting */ {
pnSpace := h.getPacketNumberSpace(packet.EncryptionLevel)
if h.logger.Debug() && pnSpace.largestSent != 0 {
for p := pnSpace.largestSent + 1; p < packet.PacketNumber; p++ {
if h.logger.Debug() {
for p := utils.MaxPacketNumber(0, pnSpace.largestSent+1); p < packet.PacketNumber; p++ {
h.logger.Debugf("Skipping packet number %#x", p)
}
}
pnSpace.largestSent = packet.PacketNumber
packet.largestAcked = protocol.InvalidPacketNumber
if packet.Ack != nil {
packet.largestAcked = packet.Ack.LargestAcked()
}
@ -232,10 +235,7 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumbe
priorInFlight := h.bytesInFlight
for _, p := range ackedPackets {
// largestAcked == 0 either means that the packet didn't contain an ACK, or it just acked packet 0
// It is safe to ignore the corner case of packets that just acked packet 0, because
// the lowestPacketNotConfirmedAcked is only used to limit the number of ACK ranges we will send.
if p.largestAcked != 0 && encLevel == protocol.Encryption1RTT {
if p.largestAcked != protocol.InvalidPacketNumber && encLevel == protocol.Encryption1RTT {
h.lowestNotConfirmedAcked = utils.MaxPacketNumber(h.lowestNotConfirmedAcked, p.largestAcked+1)
}
if err := h.onPacketAcked(p, rcvTime); err != nil {

View file

@ -68,6 +68,9 @@ var _ SendAlgorithm = &cubicSender{}
func NewCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestionWindow, initialMaxCongestionWindow protocol.ByteCount) *cubicSender {
return &cubicSender{
rttStats: rttStats,
largestSentPacketNumber: protocol.InvalidPacketNumber,
largestAckedPacketNumber: protocol.InvalidPacketNumber,
largestSentAtLastCutback: protocol.InvalidPacketNumber,
initialCongestionWindow: initialCongestionWindow,
initialMaxCongestionWindow: initialMaxCongestionWindow,
congestionWindow: initialCongestionWindow,
@ -110,7 +113,7 @@ func (c *cubicSender) OnPacketSent(
}
func (c *cubicSender) InRecovery() bool {
return c.largestAckedPacketNumber <= c.largestSentAtLastCutback && c.largestAckedPacketNumber != 0
return c.largestAckedPacketNumber != protocol.InvalidPacketNumber && c.largestAckedPacketNumber <= c.largestSentAtLastCutback
}
func (c *cubicSender) InSlowStart() bool {
@ -282,7 +285,7 @@ func (c *cubicSender) SetNumEmulatedConnections(n int) {
// OnRetransmissionTimeout is called on an retransmission timeout
func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
c.largestSentAtLastCutback = 0
c.largestSentAtLastCutback = protocol.InvalidPacketNumber
if !packetsRetransmitted {
return
}
@ -296,9 +299,9 @@ func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
func (c *cubicSender) OnConnectionMigration() {
c.hybridSlowStart.Restart()
c.prr = PrrSender{}
c.largestSentPacketNumber = 0
c.largestAckedPacketNumber = 0
c.largestSentAtLastCutback = 0
c.largestSentPacketNumber = protocol.InvalidPacketNumber
c.largestAckedPacketNumber = protocol.InvalidPacketNumber
c.largestSentAtLastCutback = protocol.InvalidPacketNumber
c.lastCutbackExitedSlowstart = false
c.cubic.Reset()
c.numAckedPackets = 0

View file

@ -1,5 +1,12 @@
package protocol
// A PacketNumber in QUIC
type PacketNumber int64
// InvalidPacketNumber is a packet number that is never sent.
// In QUIC, 0 is a valid packet number.
const InvalidPacketNumber = -1
// PacketNumberLen is the length of the packet number in bytes
type PacketNumberLen uint8
@ -34,7 +41,10 @@ func DecodePacketNumber(
epochDelta = PacketNumber(1) << 32
}
epoch := lastPacketNumber & ^(epochDelta - 1)
prevEpochBegin := epoch - epochDelta
var prevEpochBegin PacketNumber
if epoch > epochDelta {
prevEpochBegin = epoch - epochDelta
}
nextEpochBegin := epoch + epochDelta
return closestTo(
lastPacketNumber+1,

View file

@ -2,7 +2,6 @@ package protocol
import (
"fmt"
"math"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@ -10,6 +9,10 @@ import (
// Tests taken and extended from chrome
var _ = Describe("packet number calculation", func() {
It("InvalidPacketNumber is smaller than all valid packet numbers", func() {
Expect(InvalidPacketNumber).To(BeNumerically("<", 0))
})
It("works with the example from the draft", func() {
Expect(DecodePacketNumber(PacketNumberLen2, 0xa82f30ea, 0x9b32)).To(Equal(PacketNumber(0xa82f9b32)))
})
@ -25,10 +28,10 @@ var _ = Describe("packet number calculation", func() {
epoch := getEpoch(length)
epochMask := epoch - 1
wirePacketNumber := expected & epochMask
Expect(DecodePacketNumber(length, PacketNumber(last), PacketNumber(wirePacketNumber))).To(Equal(PacketNumber(expected)))
ExpectWithOffset(1, DecodePacketNumber(length, PacketNumber(last), PacketNumber(wirePacketNumber))).To(Equal(PacketNumber(expected)))
}
for _, l := range []PacketNumberLen{PacketNumberLen1, PacketNumberLen2, PacketNumberLen4} {
for _, l := range []PacketNumberLen{PacketNumberLen1, PacketNumberLen2, PacketNumberLen3, PacketNumberLen4} {
length := l
Context(fmt.Sprintf("with %d bytes", length), func() {
@ -113,29 +116,6 @@ var _ = Describe("packet number calculation", func() {
}
})
It("works near next max", func() {
maxNumber := uint64(math.MaxUint64)
maxEpoch := maxNumber & ^epochMask
// Cases where the last number was close to the end of the range
for i := uint64(0); i < 10; i++ {
// Subtract 1, because the expected next packet number is 1 more than the
// last packet number.
last := maxNumber - i - 1
// Small numbers should not wrap, because they have nowhere to go.
for j := uint64(0); j < 10; j++ {
check(length, maxEpoch+j, last)
}
// Large numbers should not wrap either.
for j := uint64(0); j < 10; j++ {
num := epoch - 1 - j
check(length, maxEpoch+num, last)
}
}
})
Context("shortening a packet number for the header", func() {
Context("shortening", func() {
It("sends out low packet numbers as 2 byte", func() {

View file

@ -5,9 +5,6 @@ import (
"time"
)
// A PacketNumber in QUIC
type PacketNumber uint64
// The PacketType is the Long Header Type
type PacketType uint8