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