gfe-relnote: Stop removing handshake packets from flight when the handshake timer causes them to be retransmitted. Protected by gfe2_reloadable_flag_quic_loss_removes_from_inflight.
PiperOrigin-RevId: 244887395
Change-Id: I355da0f1a78e596e4d4bd2a2721c37d1cedc5806
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 5a9cbb0..ad5f297 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -111,10 +111,15 @@
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
rtt_updated_(false),
acked_packets_iter_(last_ack_frame_.packets.rbegin()),
- tolerate_reneging_(GetQuicReloadableFlag(quic_tolerate_reneging)) {
+ tolerate_reneging_(GetQuicReloadableFlag(quic_tolerate_reneging)),
+ loss_removes_from_inflight_(
+ GetQuicReloadableFlag(quic_loss_removes_from_inflight)) {
if (tolerate_reneging_) {
QUIC_RELOADABLE_FLAG_COUNT(quic_tolerate_reneging);
}
+ if (loss_removes_from_inflight_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_loss_removes_from_inflight);
+ }
SetSendAlgorithm(congestion_control_type);
}
@@ -357,14 +362,25 @@
DCHECK(retransmission_type == ALL_UNACKED_RETRANSMISSION ||
retransmission_type == ALL_INITIAL_RETRANSMISSION);
QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin();
it != unacked_packets_.end(); ++it, ++packet_number) {
if ((retransmission_type == ALL_UNACKED_RETRANSMISSION ||
- it->encryption_level == ENCRYPTION_ZERO_RTT) &&
- unacked_packets_.HasRetransmittableFrames(*it)) {
- MarkForRetransmission(packet_number, retransmission_type);
+ it->encryption_level == ENCRYPTION_ZERO_RTT)) {
+ if (loss_removes_from_inflight_ && it->in_flight) {
+ // Remove 0-RTT packets and packets of the wrong version from flight,
+ // because neither can be processed by the peer.
+ unacked_packets_.RemoveFromInFlight(&*it);
+ }
+ if (unacked_packets_.HasRetransmittableFrames(*it)) {
+ MarkForRetransmission(packet_number, retransmission_type);
+ }
}
}
+ if (retransmission_type == ALL_UNACKED_RETRANSMISSION &&
+ unacked_packets_.bytes_in_flight() > 0) {
+ QUIC_BUG << "RetransmitUnackedPackets should remove all packets from flight"
+ << ", bytes_in_flight:" << unacked_packets_.bytes_in_flight();
+ }
}
void QuicSentPacketManager::NeuterUnencryptedPackets() {
@@ -384,15 +400,17 @@
}
for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
it != unacked_packets_.end(); ++it, ++packet_number) {
- if (it->encryption_level == ENCRYPTION_INITIAL &&
- unacked_packets_.HasRetransmittableFrames(*it)) {
- // Once you're forward secure, no unencrypted packets will be sent, crypto
- // or otherwise. Unencrypted packets are neutered and abandoned, to ensure
- // they are not retransmitted or considered lost from a congestion control
- // perspective.
- pending_retransmissions_.erase(packet_number);
- unacked_packets_.RemoveFromInFlight(packet_number);
- unacked_packets_.RemoveRetransmittability(packet_number);
+ if (it->encryption_level == ENCRYPTION_INITIAL) {
+ if (loss_removes_from_inflight_ ||
+ unacked_packets_.HasRetransmittableFrames(*it)) {
+ // Once you're forward secure, no unencrypted packets will be sent,
+ // crypto or otherwise. Unencrypted packets are neutered and abandoned,
+ // to ensure they are not retransmitted or considered lost from a
+ // congestion control perspective.
+ pending_retransmissions_.erase(packet_number);
+ unacked_packets_.RemoveFromInFlight(packet_number);
+ unacked_packets_.RemoveRetransmittability(packet_number);
+ }
}
}
}
@@ -437,7 +455,8 @@
// Handshake packets should never be sent as probing retransmissions.
DCHECK(!transmission_info->has_crypto_handshake ||
transmission_type != PROBING_RETRANSMISSION);
- if (!RetransmissionLeavesBytesInFlight(transmission_type)) {
+ if (!loss_removes_from_inflight_ &&
+ !RetransmissionLeavesBytesInFlight(transmission_type)) {
unacked_packets_.RemoveFromInFlight(transmission_info);
}
@@ -854,6 +873,9 @@
time);
}
+ if (loss_removes_from_inflight_) {
+ unacked_packets_.RemoveFromInFlight(packet.packet_number);
+ }
MarkForRetransmission(packet.packet_number, LOSS_RETRANSMISSION);
}
}
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index f7f3c12..f2524a1 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -629,6 +629,9 @@
// Latched value of quic_tolerate_reneging.
const bool tolerate_reneging_;
+
+ // Latched value of quic_loss_removes_from_inflight.
+ const bool loss_removes_from_inflight_;
};
} // namespace quic
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 6448419..ec8de8b 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -1036,6 +1036,7 @@
SendDataPacket(kNumSentCryptoPackets + i);
}
EXPECT_TRUE(manager_.HasUnackedCryptoPackets());
+ EXPECT_EQ(5 * kDefaultLength, manager_.GetBytesInFlight());
// The first retransmits 2 packets.
if (manager_.session_decides_what_to_write()) {
@@ -1051,6 +1052,10 @@
RetransmitNextPacket(7);
EXPECT_FALSE(manager_.HasPendingRetransmissions());
}
+ // Expect all 4 handshake packets to be in flight and 3 data packets.
+ if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) {
+ EXPECT_EQ(7 * kDefaultLength, manager_.GetBytesInFlight());
+ }
EXPECT_TRUE(manager_.HasUnackedCryptoPackets());
// The second retransmits 2 packets.
@@ -1067,12 +1072,26 @@
RetransmitNextPacket(9);
EXPECT_FALSE(manager_.HasPendingRetransmissions());
}
+ if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) {
+ EXPECT_EQ(9 * kDefaultLength, manager_.GetBytesInFlight());
+ }
EXPECT_TRUE(manager_.HasUnackedCryptoPackets());
// Now ack the two crypto packets and the speculatively encrypted request,
// and ensure the first four crypto packets get abandoned, but not lost.
- uint64_t acked[] = {3, 4, 5, 8, 9};
- ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
+ if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) {
+ // Crypto packets remain in flight, so any that aren't acked will be lost.
+ uint64_t acked[] = {3, 4, 5, 8, 9};
+ uint64_t lost[] = {1, 2, 6};
+ ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), lost,
+ QUIC_ARRAYSIZE(lost));
+ if (manager_.session_decides_what_to_write()) {
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(3);
+ }
+ } else {
+ uint64_t acked[] = {3, 4, 5, 8, 9};
+ ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
+ }
if (manager_.session_decides_what_to_write()) {
EXPECT_CALL(notifier_, HasUnackedCryptoData())
.WillRepeatedly(Return(false));
@@ -1203,8 +1222,13 @@
manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_FALSE(manager_.HasUnackedCryptoPackets());
- uint64_t unacked[] = {3};
- VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
+ if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) {
+ uint64_t unacked[] = {1, 3};
+ VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
+ } else {
+ uint64_t unacked[] = {3};
+ VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
+ }
}
TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) {