...

Source file src/golang.org/x/net/internal/quic/loss.go

Documentation: golang.org/x/net/internal/quic

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package quic
     8  
     9  import (
    10  	"math"
    11  	"time"
    12  )
    13  
    14  type lossState struct {
    15  	side connSide
    16  
    17  	// True when the handshake is confirmed.
    18  	// https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2
    19  	handshakeConfirmed bool
    20  
    21  	// Peer's max_ack_delay transport parameter.
    22  	// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.28.1
    23  	maxAckDelay time.Duration
    24  
    25  	// Time of the next event: PTO expiration (if ptoTimerArmed is true),
    26  	// or loss detection.
    27  	// The connection must call lossState.advance when the timer expires.
    28  	timer time.Time
    29  
    30  	// True when the PTO timer is set.
    31  	ptoTimerArmed bool
    32  
    33  	// True when the PTO timer has expired and a probe packet has not yet been sent.
    34  	ptoExpired bool
    35  
    36  	// Count of PTO expirations since the lack received acknowledgement.
    37  	// https://www.rfc-editor.org/rfc/rfc9002#section-6.2.1-9
    38  	ptoBackoffCount int
    39  
    40  	// Anti-amplification limit: Three times the amount of data received from
    41  	// the peer, less the amount of data sent.
    42  	//
    43  	// Set to antiAmplificationUnlimited (MaxInt) to disable the limit.
    44  	// The limit is always disabled for clients, and for servers after the
    45  	// peer's address is validated.
    46  	//
    47  	// Anti-amplification is per-address; this will need to change if/when we
    48  	// support address migration.
    49  	//
    50  	// https://www.rfc-editor.org/rfc/rfc9000#section-8-2
    51  	antiAmplificationLimit int
    52  
    53  	// Count of non-ack-eliciting packets (ACKs) sent since the last ack-eliciting one.
    54  	consecutiveNonAckElicitingPackets int
    55  
    56  	rtt   rttState
    57  	pacer pacerState
    58  	cc    *ccReno
    59  
    60  	// Per-space loss detection state.
    61  	spaces [numberSpaceCount]struct {
    62  		sentPacketList
    63  		maxAcked         packetNumber
    64  		lastAckEliciting packetNumber
    65  	}
    66  
    67  	// Temporary state used when processing an ACK frame.
    68  	ackFrameRTT                  time.Duration // RTT from latest packet in frame
    69  	ackFrameContainsAckEliciting bool          // newly acks an ack-eliciting packet?
    70  }
    71  
    72  const antiAmplificationUnlimited = math.MaxInt
    73  
    74  func (c *lossState) init(side connSide, maxDatagramSize int, now time.Time) {
    75  	c.side = side
    76  	if side == clientSide {
    77  		// Clients don't have an anti-amplification limit.
    78  		c.antiAmplificationLimit = antiAmplificationUnlimited
    79  	}
    80  	c.rtt.init()
    81  	c.cc = newReno(maxDatagramSize)
    82  	c.pacer.init(now, c.cc.congestionWindow, timerGranularity)
    83  
    84  	// Peer's assumed max_ack_delay, prior to receiving transport parameters.
    85  	// https://www.rfc-editor.org/rfc/rfc9000#section-18.2
    86  	c.maxAckDelay = 25 * time.Millisecond
    87  
    88  	for space := range c.spaces {
    89  		c.spaces[space].maxAcked = -1
    90  		c.spaces[space].lastAckEliciting = -1
    91  	}
    92  }
    93  
    94  // setMaxAckDelay sets the max_ack_delay transport parameter received from the peer.
    95  func (c *lossState) setMaxAckDelay(d time.Duration) {
    96  	if d >= (1<<14)*time.Millisecond {
    97  		// Values of 2^14 or greater are invalid.
    98  		// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.28.1
    99  		return
   100  	}
   101  	c.maxAckDelay = d
   102  }
   103  
   104  // confirmHandshake indicates the handshake has been confirmed.
   105  func (c *lossState) confirmHandshake() {
   106  	c.handshakeConfirmed = true
   107  }
   108  
   109  // validateClientAddress disables the anti-amplification limit after
   110  // a server validates a client's address.
   111  func (c *lossState) validateClientAddress() {
   112  	c.antiAmplificationLimit = antiAmplificationUnlimited
   113  }
   114  
   115  // minDatagramSize is the minimum datagram size permitted by
   116  // anti-amplification protection.
   117  //
   118  // Defining a minimum size avoids the case where, say, anti-amplification
   119  // technically allows us to send a 1-byte datagram, but no such datagram
   120  // can be constructed.
   121  const minPacketSize = 128
   122  
   123  type ccLimit int
   124  
   125  const (
   126  	ccOK      = ccLimit(iota) // OK to send
   127  	ccBlocked                 // sending blocked by anti-amplification
   128  	ccLimited                 // sending blocked by congestion control
   129  	ccPaced                   // sending allowed by congestion, but delayed by pacer
   130  )
   131  
   132  // sendLimit reports whether sending is possible at this time.
   133  // When sending is pacing limited, it returns the next time a packet may be sent.
   134  func (c *lossState) sendLimit(now time.Time) (limit ccLimit, next time.Time) {
   135  	if c.antiAmplificationLimit < minPacketSize {
   136  		// When at the anti-amplification limit, we may not send anything.
   137  		return ccBlocked, time.Time{}
   138  	}
   139  	if c.ptoExpired {
   140  		// On PTO expiry, send a probe.
   141  		return ccOK, time.Time{}
   142  	}
   143  	if !c.cc.canSend() {
   144  		// Congestion control blocks sending.
   145  		return ccLimited, time.Time{}
   146  	}
   147  	if c.cc.bytesInFlight == 0 {
   148  		// If no bytes are in flight, send packet unpaced.
   149  		return ccOK, time.Time{}
   150  	}
   151  	canSend, next := c.pacer.canSend(now)
   152  	if !canSend {
   153  		// Pacer blocks sending.
   154  		return ccPaced, next
   155  	}
   156  	return ccOK, time.Time{}
   157  }
   158  
   159  // maxSendSize reports the maximum datagram size that may be sent.
   160  func (c *lossState) maxSendSize() int {
   161  	return min(c.antiAmplificationLimit, c.cc.maxDatagramSize)
   162  }
   163  
   164  // advance is called when time passes.
   165  // The lossf function is called for each packet newly detected as lost.
   166  func (c *lossState) advance(now time.Time, lossf func(numberSpace, *sentPacket, packetFate)) {
   167  	c.pacer.advance(now, c.cc.congestionWindow, c.rtt.smoothedRTT)
   168  	if c.ptoTimerArmed && !c.timer.IsZero() && !c.timer.After(now) {
   169  		c.ptoExpired = true
   170  		c.timer = time.Time{}
   171  		c.ptoBackoffCount++
   172  	}
   173  	c.detectLoss(now, lossf)
   174  }
   175  
   176  // nextNumber returns the next packet number to use in a space.
   177  func (c *lossState) nextNumber(space numberSpace) packetNumber {
   178  	return c.spaces[space].nextNum
   179  }
   180  
   181  // packetSent records a sent packet.
   182  func (c *lossState) packetSent(now time.Time, space numberSpace, sent *sentPacket) {
   183  	sent.time = now
   184  	c.spaces[space].add(sent)
   185  	size := sent.size
   186  	if c.antiAmplificationLimit != antiAmplificationUnlimited {
   187  		c.antiAmplificationLimit = max(0, c.antiAmplificationLimit-size)
   188  	}
   189  	if sent.inFlight {
   190  		c.cc.packetSent(now, space, sent)
   191  		c.pacer.packetSent(now, size, c.cc.congestionWindow, c.rtt.smoothedRTT)
   192  		if sent.ackEliciting {
   193  			c.spaces[space].lastAckEliciting = sent.num
   194  			c.ptoExpired = false // reset expired PTO timer after sending probe
   195  		}
   196  		c.scheduleTimer(now)
   197  	}
   198  	if sent.ackEliciting {
   199  		c.consecutiveNonAckElicitingPackets = 0
   200  	} else {
   201  		c.consecutiveNonAckElicitingPackets++
   202  	}
   203  }
   204  
   205  // datagramReceived records a datagram (not packet!) received from the peer.
   206  func (c *lossState) datagramReceived(now time.Time, size int) {
   207  	if c.antiAmplificationLimit != antiAmplificationUnlimited {
   208  		c.antiAmplificationLimit += 3 * size
   209  		// Reset the PTO timer, possibly to a point in the past, in which
   210  		// case the caller should execute it immediately.
   211  		// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-2
   212  		c.scheduleTimer(now)
   213  		if c.ptoTimerArmed && !c.timer.IsZero() && !c.timer.After(now) {
   214  			c.ptoExpired = true
   215  			c.timer = time.Time{}
   216  		}
   217  	}
   218  }
   219  
   220  // receiveAckStart starts processing an ACK frame.
   221  // Call receiveAckRange for each range in the frame.
   222  // Call receiveAckFrameEnd after all ranges are processed.
   223  func (c *lossState) receiveAckStart() {
   224  	c.ackFrameContainsAckEliciting = false
   225  	c.ackFrameRTT = -1
   226  }
   227  
   228  // receiveAckRange processes a range within an ACK frame.
   229  // The ackf function is called for each newly-acknowledged packet.
   230  func (c *lossState) receiveAckRange(now time.Time, space numberSpace, rangeIndex int, start, end packetNumber, ackf func(numberSpace, *sentPacket, packetFate)) {
   231  	// Limit our range to the intersection of the ACK range and
   232  	// the in-flight packets we have state for.
   233  	if s := c.spaces[space].start(); start < s {
   234  		start = s
   235  	}
   236  	if e := c.spaces[space].end(); end > e {
   237  		end = e
   238  	}
   239  	if start >= end {
   240  		return
   241  	}
   242  	if rangeIndex == 0 {
   243  		// If the latest packet in the ACK frame is newly-acked,
   244  		// record the RTT in c.ackFrameRTT.
   245  		sent := c.spaces[space].num(end - 1)
   246  		if !sent.acked {
   247  			c.ackFrameRTT = max(0, now.Sub(sent.time))
   248  		}
   249  	}
   250  	for pnum := start; pnum < end; pnum++ {
   251  		sent := c.spaces[space].num(pnum)
   252  		if sent.acked || sent.lost {
   253  			continue
   254  		}
   255  		// This is a newly-acknowledged packet.
   256  		if pnum > c.spaces[space].maxAcked {
   257  			c.spaces[space].maxAcked = pnum
   258  		}
   259  		sent.acked = true
   260  		c.cc.packetAcked(now, sent)
   261  		ackf(space, sent, packetAcked)
   262  		if sent.ackEliciting {
   263  			c.ackFrameContainsAckEliciting = true
   264  		}
   265  	}
   266  }
   267  
   268  // receiveAckEnd finishes processing an ack frame.
   269  // The lossf function is called for each packet newly detected as lost.
   270  func (c *lossState) receiveAckEnd(now time.Time, space numberSpace, ackDelay time.Duration, lossf func(numberSpace, *sentPacket, packetFate)) {
   271  	c.spaces[space].sentPacketList.clean()
   272  	// Update the RTT sample when the largest acknowledged packet in the ACK frame
   273  	// is newly acknowledged, and at least one newly acknowledged packet is ack-eliciting.
   274  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.1-2.2
   275  	if c.ackFrameRTT >= 0 && c.ackFrameContainsAckEliciting {
   276  		c.rtt.updateSample(now, c.handshakeConfirmed, space, c.ackFrameRTT, ackDelay, c.maxAckDelay)
   277  	}
   278  	// Reset the PTO backoff.
   279  	// Exception: A client does not reset the backoff on acks for Initial packets.
   280  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-9
   281  	if !(c.side == clientSide && space == initialSpace) {
   282  		c.ptoBackoffCount = 0
   283  	}
   284  	// If the client has set a PTO timer with no packets in flight
   285  	// we want to restart that timer now. Clearing c.timer does this.
   286  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-3
   287  	c.timer = time.Time{}
   288  	c.detectLoss(now, lossf)
   289  	c.cc.packetBatchEnd(now, space, &c.rtt, c.maxAckDelay)
   290  }
   291  
   292  // discardPackets declares that packets within a number space will not be delivered
   293  // and that data contained in them should be resent.
   294  // For example, after receiving a Retry packet we discard already-sent Initial packets.
   295  func (c *lossState) discardPackets(space numberSpace, lossf func(numberSpace, *sentPacket, packetFate)) {
   296  	for i := 0; i < c.spaces[space].size; i++ {
   297  		sent := c.spaces[space].nth(i)
   298  		sent.lost = true
   299  		c.cc.packetDiscarded(sent)
   300  		lossf(numberSpace(space), sent, packetLost)
   301  	}
   302  	c.spaces[space].clean()
   303  }
   304  
   305  // discardKeys is called when dropping packet protection keys for a number space.
   306  func (c *lossState) discardKeys(now time.Time, space numberSpace) {
   307  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.4
   308  	for i := 0; i < c.spaces[space].size; i++ {
   309  		sent := c.spaces[space].nth(i)
   310  		c.cc.packetDiscarded(sent)
   311  	}
   312  	c.spaces[space].discard()
   313  	c.spaces[space].maxAcked = -1
   314  	c.spaces[space].lastAckEliciting = -1
   315  	c.scheduleTimer(now)
   316  }
   317  
   318  func (c *lossState) lossDuration() time.Duration {
   319  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
   320  	return max((9*max(c.rtt.smoothedRTT, c.rtt.latestRTT))/8, timerGranularity)
   321  }
   322  
   323  func (c *lossState) detectLoss(now time.Time, lossf func(numberSpace, *sentPacket, packetFate)) {
   324  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.1-1
   325  	const lossThreshold = 3
   326  
   327  	lossTime := now.Add(-c.lossDuration())
   328  	for space := numberSpace(0); space < numberSpaceCount; space++ {
   329  		for i := 0; i < c.spaces[space].size; i++ {
   330  			sent := c.spaces[space].nth(i)
   331  			if sent.lost || sent.acked {
   332  				continue
   333  			}
   334  			// RFC 9002 Section 6.1 states that a packet is only declared lost if it
   335  			// is "in flight", which excludes packets that contain only ACK frames.
   336  			// However, we need some way to determine when to drop state for ACK-only
   337  			// packets, and the loss algorithm in Appendix A handles loss detection of
   338  			// not-in-flight packets identically to all others, so we do the same here.
   339  			switch {
   340  			case c.spaces[space].maxAcked-sent.num >= lossThreshold:
   341  				// Packet threshold
   342  				// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.1
   343  				fallthrough
   344  			case sent.num <= c.spaces[space].maxAcked && !sent.time.After(lossTime):
   345  				// Time threshold
   346  				// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
   347  				sent.lost = true
   348  				lossf(space, sent, packetLost)
   349  				if sent.inFlight {
   350  					c.cc.packetLost(now, space, sent, &c.rtt)
   351  				}
   352  			}
   353  			if !sent.lost {
   354  				break
   355  			}
   356  		}
   357  		c.spaces[space].clean()
   358  	}
   359  	c.scheduleTimer(now)
   360  }
   361  
   362  // scheduleTimer sets the loss or PTO timer.
   363  //
   364  // The connection is responsible for arranging for advance to be called after
   365  // the timer expires.
   366  //
   367  // The timer may be set to a point in the past, in which advance should be called
   368  // immediately. We don't do this here, because executing the timer can cause
   369  // packet loss events, and it's simpler for the connection if loss events only
   370  // occur when advancing time.
   371  func (c *lossState) scheduleTimer(now time.Time) {
   372  	c.ptoTimerArmed = false
   373  
   374  	// Loss timer for sent packets.
   375  	// The loss timer is only started once a later packet has been acknowledged,
   376  	// and takes precedence over the PTO timer.
   377  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
   378  	var oldestPotentiallyLost time.Time
   379  	for space := numberSpace(0); space < numberSpaceCount; space++ {
   380  		if c.spaces[space].size > 0 && c.spaces[space].start() <= c.spaces[space].maxAcked {
   381  			firstTime := c.spaces[space].nth(0).time
   382  			if oldestPotentiallyLost.IsZero() || firstTime.Before(oldestPotentiallyLost) {
   383  				oldestPotentiallyLost = firstTime
   384  			}
   385  		}
   386  	}
   387  	if !oldestPotentiallyLost.IsZero() {
   388  		c.timer = oldestPotentiallyLost.Add(c.lossDuration())
   389  		return
   390  	}
   391  
   392  	// PTO timer.
   393  	if c.ptoExpired {
   394  		// PTO timer has expired, don't restart it until we send a probe.
   395  		c.timer = time.Time{}
   396  		return
   397  	}
   398  	if c.antiAmplificationLimit >= 0 && c.antiAmplificationLimit < minPacketSize {
   399  		// Server is at its anti-amplification limit and can't send any more data.
   400  		// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-1
   401  		c.timer = time.Time{}
   402  		return
   403  	}
   404  	// Timer starts at the most recently sent ack-eliciting packet.
   405  	// Prior to confirming the handshake, we consider the Initial and Handshake
   406  	// number spaces; after, we consider only Application Data.
   407  	var last time.Time
   408  	if !c.handshakeConfirmed {
   409  		for space := initialSpace; space <= handshakeSpace; space++ {
   410  			sent := c.spaces[space].num(c.spaces[space].lastAckEliciting)
   411  			if sent == nil {
   412  				continue
   413  			}
   414  			if last.IsZero() || last.After(sent.time) {
   415  				last = sent.time
   416  			}
   417  		}
   418  	} else {
   419  		sent := c.spaces[appDataSpace].num(c.spaces[appDataSpace].lastAckEliciting)
   420  		if sent != nil {
   421  			last = sent.time
   422  		}
   423  	}
   424  	if last.IsZero() &&
   425  		c.side == clientSide &&
   426  		c.spaces[handshakeSpace].maxAcked < 0 &&
   427  		!c.handshakeConfirmed {
   428  		// The client must always set a PTO timer prior to receiving an ack for a
   429  		// handshake packet or the handshake being confirmed.
   430  		// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1
   431  		if !c.timer.IsZero() {
   432  			// If c.timer is non-zero here, we've already set the PTO timer and
   433  			// should leave it as-is rather than moving it forward.
   434  			c.ptoTimerArmed = true
   435  			return
   436  		}
   437  		last = now
   438  	} else if last.IsZero() {
   439  		c.timer = time.Time{}
   440  		return
   441  	}
   442  	c.timer = last.Add(c.ptoPeriod())
   443  	c.ptoTimerArmed = true
   444  }
   445  
   446  func (c *lossState) ptoPeriod() time.Duration {
   447  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1
   448  	return c.ptoBasePeriod() << c.ptoBackoffCount
   449  }
   450  
   451  func (c *lossState) ptoBasePeriod() time.Duration {
   452  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1
   453  	pto := c.rtt.smoothedRTT + max(4*c.rtt.rttvar, timerGranularity)
   454  	if c.handshakeConfirmed {
   455  		// The max_ack_delay is the maximum amount of time the peer might delay sending
   456  		// an ack to us. We only take it into account for the Application Data space.
   457  		// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-4
   458  		pto += c.maxAckDelay
   459  	}
   460  	return pto
   461  }
   462  

View as plain text