gfe-relnote: In QUIC, do not close connection if received an in-order ACK with decreased largest_acked. Protected by gfe2_reloadable_flag_quic_tolerate_reneging. By dremel, this connection close occurs rarely in prod: https://screenshot.googleplex.com/jZpfvdY4nzk Largest_acked can decrease currently in IETF QUIC, though that may change: https://github.com/quicwg/base-drafts/issues/2205 PiperOrigin-RevId: 238228491 Change-Id: If7586fb8da192dea4436a5572c76bb7aeb1a3227
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index f4f15cb..0d7ede9 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -975,7 +975,8 @@ if (!sent_packet_manager_.GetLargestObserved().IsInitialized() || largest_acked > sent_packet_manager_.GetLargestObserved()) { visitor_->OnForwardProgressConfirmed(); - } else if (largest_acked < sent_packet_manager_.GetLargestObserved()) { + } else if (!sent_packet_manager_.tolerate_reneging() && + largest_acked < sent_packet_manager_.GetLargestObserved()) { QUIC_LOG(INFO) << ENDPOINT << "Peer's largest_observed packet decreased:" << largest_acked << " vs " << sent_packet_manager_.GetLargestObserved()
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index acb76de..93ad4eb 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -2488,10 +2488,14 @@ QuicAckFrame frame2 = InitAckFrame(2); ProcessAckPacket(&frame2); - // Now change it to 1, and it should cause a connection error. - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _, - ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(visitor_, OnCanWrite()).Times(0); + if (GetQuicReloadableFlag(quic_tolerate_reneging)) { + EXPECT_CALL(visitor_, OnCanWrite()); + } else { + // Now change it to 1, and it should cause a connection error. + EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _, + ConnectionCloseSource::FROM_SELF)); + EXPECT_CALL(visitor_, OnCanWrite()).Times(0); + } ProcessAckPacket(&frame1); }
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index 93909b7..e078f5f 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -111,7 +111,11 @@ delayed_ack_time_( QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)), rtt_updated_(false), - acked_packets_iter_(last_ack_frame_.packets.rbegin()) { + acked_packets_iter_(last_ack_frame_.packets.rbegin()), + tolerate_reneging_(GetQuicReloadableFlag(quic_tolerate_reneging)) { + if (tolerate_reneging_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_tolerate_reneging); + } SetSendAlgorithm(congestion_control_type); } @@ -1063,7 +1067,8 @@ rtt_updated_ = MaybeUpdateRTT(largest_acked, ack_delay_time, ack_receive_time); DCHECK(!unacked_packets_.largest_acked().IsInitialized() || - largest_acked >= unacked_packets_.largest_acked()); + largest_acked >= unacked_packets_.largest_acked() || + tolerate_reneging_); last_ack_frame_.ack_delay_time = ack_delay_time; acked_packets_iter_ = last_ack_frame_.packets.rbegin(); }
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h index a50d83c..23f3a9f 100644 --- a/quic/core/quic_sent_packet_manager.h +++ b/quic/core/quic_sent_packet_manager.h
@@ -351,6 +351,8 @@ // Setting the send algorithm once the connection is underway is dangerous. void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm); + bool tolerate_reneging() const { return tolerate_reneging_; } + private: friend class test::QuicConnectionPeer; friend class test::QuicSentPacketManagerPeer; @@ -580,6 +582,9 @@ // A reverse iterator of last_ack_frame_.packets. This is reset in // OnAckRangeStart, and gradually moves in OnAckRange.. PacketNumberQueue::const_reverse_iterator acked_packets_iter_; + + // Latched value of quic_tolerate_reneging. + const bool tolerate_reneging_; }; } // namespace quic
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc index eb3c6a8..024b4c7 100644 --- a/quic/core/quic_sent_packet_manager_test.cc +++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -2433,6 +2433,38 @@ EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } +TEST_P(QuicSentPacketManagerTest, TolerateReneging) { + if (!manager_.tolerate_reneging()) { + return; + } + // Send packets 1 - 20. + for (size_t i = 1; i <= 20; ++i) { + SendDataPacket(i); + } + // Ack [5, 7), [10, 12), [15, 17). + uint64_t acked1[] = {5, 6, 10, 11, 15, 16}; + uint64_t lost1[] = {1, 2, 3, 4, 7, 8, 9, 12, 13}; + ExpectAcksAndLosses(true, acked1, QUIC_ARRAYSIZE(acked1), lost1, + QUIC_ARRAYSIZE(lost1)); + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(AnyNumber()); + manager_.OnAckFrameStart(QuicPacketNumber(16), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(15), QuicPacketNumber(17)); + manager_.OnAckRange(QuicPacketNumber(10), QuicPacketNumber(12)); + manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(7)); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); + + // Making sure reneged ACK does not harm. Ack [4, 8), [9, 13). + uint64_t acked2[] = {4, 7, 9, 12}; + ExpectAcksAndLosses(true, acked2, QUIC_ARRAYSIZE(acked2), nullptr, 0); + manager_.OnAckFrameStart(QuicPacketNumber(12), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(9), QuicPacketNumber(13)); + manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(8)); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); + EXPECT_EQ(QuicPacketNumber(16), manager_.GetLargestObserved()); +} + } // namespace } // namespace test } // namespace quic