gfe-relnote: In QUIC, enable IETF style loss detection. Protected by
gfe2_reloadable_flag_quic_enable_ietf_loss_detection.

PiperOrigin-RevId: 268674408
Change-Id: Idb598126b44838732b3b3a3f679b3aff80bc5beb
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc
index 805ee83..3502031 100644
--- a/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -19,10 +19,9 @@
 // triggers when a nack has been receieved for the packet.
 static const size_t kMinLossDelayMs = 5;
 
-// Default fraction of an RTT the algorithm waits before determining a packet is
-// lost due to early retransmission by time based loss detection.
-static const int kDefaultLossDelayShift = 2;
-// Default fraction of an RTT when doing adaptive loss detection.
+// Default fraction (1/8) of an RTT when doing IETF loss detection.
+static const int kDefaultIetfLossDelayShift = 3;
+// Default fraction (1/16) of an RTT when doing adaptive loss detection.
 static const int kDefaultAdaptiveLossDelayShift = 4;
 
 }  // namespace
@@ -42,9 +41,13 @@
   loss_detection_timeout_ = QuicTime::Zero();
   largest_sent_on_spurious_retransmit_.Clear();
   loss_type_ = loss_type;
-  reordering_shift_ = loss_type == kAdaptiveTime
-                          ? kDefaultAdaptiveLossDelayShift
-                          : kDefaultLossDelayShift;
+  if (loss_type == kAdaptiveTime) {
+    reordering_shift_ = kDefaultAdaptiveLossDelayShift;
+  } else if (loss_type == kIetfLossDetection) {
+    reordering_shift_ = kDefaultIetfLossDelayShift;
+  } else {
+    reordering_shift_ = kDefaultLossDelayShift;
+  }
   largest_previously_acked_.Clear();
 }
 
@@ -83,9 +86,14 @@
   }
   QuicTime::Delta max_rtt =
       std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
-  QuicTime::Delta loss_delay =
-      std::max(QuicTime::Delta::FromMilliseconds(kMinLossDelayMs),
-               max_rtt + (max_rtt >> reordering_shift_));
+  if (loss_type_ == kIetfLossDetection) {
+    max_rtt = std::max(QuicTime::Delta::FromMilliseconds(1), max_rtt);
+  }
+  QuicTime::Delta loss_delay = max_rtt + (max_rtt >> reordering_shift_);
+  if (loss_type_ != kIetfLossDetection) {
+    loss_delay = std::max(QuicTime::Delta::FromMilliseconds(kMinLossDelayMs),
+                          loss_delay);
+  }
   QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
   auto it = unacked_packets.begin();
   if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) {
@@ -113,8 +121,8 @@
       continue;
     }
 
-    if (loss_type_ == kNack) {
-      // FACK based loss detection.
+    if (loss_type_ == kNack || loss_type_ == kIetfLossDetection) {
+      // Packet threshold loss detection.
       if (largest_newly_acked - packet_number >= reordering_threshold_) {
         packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
         continue;
@@ -132,17 +140,14 @@
       }
     }
 
-    // Only early retransmit(RFC5827) when the last packet gets acked and
-    // there are retransmittable packets in flight.
-    // This also implements a timer-protected variant of FACK.
-    QuicPacketNumber largest_sent_retransmittable_packet;
-    // Use largest_sent_retransmittable_packet of corresponding packet number
-    // space for timer based loss detection.
-    largest_sent_retransmittable_packet =
+    // Time threshold loss detection. Also implements early retransmit(RFC5827)
+    // when time threshold is not used and the last packet gets acked.
+    QuicPacketNumber largest_sent_retransmittable_packet =
         unacked_packets.GetLargestSentRetransmittableOfPacketNumberSpace(
             packet_number_space_);
     if (largest_sent_retransmittable_packet <= largest_newly_acked ||
-        loss_type_ == kTime || loss_type_ == kAdaptiveTime) {
+        loss_type_ == kTime || loss_type_ == kAdaptiveTime ||
+        loss_type_ == kIetfLossDetection) {
       QuicTime when_lost = it->sent_time + loss_delay;
       if (time < when_lost) {
         loss_detection_timeout_ = when_lost;
@@ -157,8 +162,10 @@
     }
 
     // NACK-based loss detection allows for a max reordering window of 1 RTT.
-    if (it->sent_time + rtt_stats.smoothed_rtt() <
-        unacked_packets.GetTransmissionInfo(largest_newly_acked).sent_time) {
+    if (loss_type_ != kIetfLossDetection &&
+        it->sent_time + rtt_stats.smoothed_rtt() <
+            unacked_packets.GetTransmissionInfo(largest_newly_acked)
+                .sent_time) {
       packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
       continue;
     }
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h
index 3bde91b..c9da837 100644
--- a/quic/core/congestion_control/general_loss_algorithm.h
+++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -65,6 +65,14 @@
 
   int reordering_shift() const { return reordering_shift_; }
 
+  void set_reordering_shift(int reordering_shift) {
+    reordering_shift_ = reordering_shift;
+  }
+
+  bool use_adaptive_reordering_threshold() const {
+    return use_adaptive_reordering_threshold_;
+  }
+
   void enable_adaptive_reordering_threshold() {
     use_adaptive_reordering_threshold_ = true;
   }
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index 8c200cc..dba6d5b 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -595,6 +595,71 @@
   packets_acked.clear();
 }
 
+TEST_F(GeneralLossAlgorithmTest, DefaultIetfLossDetection) {
+  loss_algorithm_.SetLossDetectionType(kIetfLossDetection);
+  for (size_t i = 1; i <= 6; ++i) {
+    SendDataPacket(i);
+  }
+  // Packet threshold loss detection.
+  AckedPacketVector packets_acked;
+  // No loss on one ack.
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(AckedPacket(
+      QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
+  packets_acked.clear();
+  // No loss on two acks.
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(AckedPacket(
+      QuicPacketNumber(3), kMaxOutgoingPacketSize, QuicTime::Zero()));
+  VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
+  packets_acked.clear();
+  // Loss on three acks.
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(AckedPacket(
+      QuicPacketNumber(4), kMaxOutgoingPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, {1});
+  EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+  packets_acked.clear();
+
+  SendDataPacket(7);
+
+  // Time threshold loss detection.
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(6));
+  packets_acked.push_back(AckedPacket(
+      QuicPacketNumber(6), kMaxOutgoingPacketSize, QuicTime::Zero()));
+  VerifyLosses(6, packets_acked, std::vector<uint64_t>{});
+  packets_acked.clear();
+  EXPECT_EQ(clock_.Now() + rtt_stats_.smoothed_rtt() +
+                (rtt_stats_.smoothed_rtt() >> 3),
+            loss_algorithm_.GetLossTimeout());
+  clock_.AdvanceTime(rtt_stats_.smoothed_rtt() +
+                     (rtt_stats_.smoothed_rtt() >> 3));
+  VerifyLosses(6, packets_acked, {5});
+  EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, IetfLossDetectionWithOneFourthRttDelay) {
+  loss_algorithm_.SetLossDetectionType(kIetfLossDetection);
+  loss_algorithm_.set_reordering_shift(2);
+  SendDataPacket(1);
+  SendDataPacket(2);
+
+  AckedPacketVector packets_acked;
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(AckedPacket(
+      QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
+  packets_acked.clear();
+  EXPECT_EQ(clock_.Now() + rtt_stats_.smoothed_rtt() +
+                (rtt_stats_.smoothed_rtt() >> 2),
+            loss_algorithm_.GetLossTimeout());
+  clock_.AdvanceTime(rtt_stats_.smoothed_rtt() +
+                     (rtt_stats_.smoothed_rtt() >> 2));
+  VerifyLosses(2, packets_acked, {1});
+  EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/congestion_control/uber_loss_algorithm.cc b/quic/core/congestion_control/uber_loss_algorithm.cc
index e3b526a..3b669e2 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -92,4 +92,16 @@
                             packet_number, previous_largest_acked);
 }
 
+void UberLossAlgorithm::SetReorderingShift(int reordering_shift) {
+  for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
+    general_loss_algorithms_[i].set_reordering_shift(reordering_shift);
+  }
+}
+
+void UberLossAlgorithm::EnableAdaptiveReorderingThreshold() {
+  for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
+    general_loss_algorithms_[i].enable_adaptive_reordering_threshold();
+  }
+}
+
 }  // namespace quic
diff --git a/quic/core/congestion_control/uber_loss_algorithm.h b/quic/core/congestion_control/uber_loss_algorithm.h
index 558aaea..0d2b788 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.h
+++ b/quic/core/congestion_control/uber_loss_algorithm.h
@@ -9,6 +9,12 @@
 
 namespace quic {
 
+namespace test {
+
+class QuicSentPacketManagerPeer;
+
+}  // namespace test
+
 // This class comprises multiple loss algorithms, each per packet number space.
 class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
  public:
@@ -49,7 +55,15 @@
                             QuicPacketNumber packet_number,
                             QuicPacketNumber previous_largest_acked) override;
 
+  // Sets reordering_shift for all packet number spaces.
+  void SetReorderingShift(int reordering_shift);
+
+  // Enable adaptive reordering threshold of all packet number spaces.
+  void EnableAdaptiveReorderingThreshold();
+
  private:
+  friend class test::QuicSentPacketManagerPeer;
+
   LossDetectionType loss_type_;
   // One loss algorithm per packet number space.
   GeneralLossAlgorithm general_loss_algorithms_[NUM_PACKET_NUMBER_SPACES];
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 812aae0..9b3559d 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -163,6 +163,19 @@
 const QuicTag kLFAK = TAG('L', 'F', 'A', 'K');   // Don't invoke FACK on the
                                                  // first ack.
 const QuicTag kSTMP = TAG('S', 'T', 'M', 'P');   // Send and process timestamps
+
+const QuicTag kILD0 = TAG('I', 'L', 'D', '0');   // IETF style loss detection
+                                                 // (default with 1/8 RTT time
+                                                 // threshold)
+const QuicTag kILD1 = TAG('I', 'L', 'D', '1');   // IETF style loss detection
+                                                 // with 1/4 RTT time threshold
+const QuicTag kILD2 = TAG('I', 'L', 'D', '2');   // IETF style loss detection
+                                                 // with adaptive packet
+                                                 // threshold
+const QuicTag kILD3 = TAG('I', 'L', 'D', '3');   // IETF style loss detection
+                                                 // with 1/4 RTT time threshold
+                                                 // and adaptive packet
+                                                 // threshold
 // TODO(fayang): Remove this connection option when QUIC_VERSION_35, is removed
 // Since MAX_HEADER_LIST_SIZE settings frame is supported instead.
 const QuicTag kSMHL = TAG('S', 'M', 'H', 'L');   // Support MAX_HEADER_LIST_SIZE
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 439d04e..1033b26 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -368,6 +368,9 @@
     if (GetQuicReloadableFlag(quic_enable_pto)) {
       copt.push_back(k2PTO);
     }
+    if (VersionHasIetfQuicFrames(negotiated_version_.transport_version)) {
+      copt.push_back(kILD0);
+    }
     client_config_.SetConnectionOptionsToSend(copt);
 
     // Start the server first, because CreateQuicClient() attempts
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index cdee0f9..3dc462c 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -241,6 +241,10 @@
 // Default initial rtt used before any samples are received.
 const int kInitialRttMs = 100;
 
+// Default fraction (1/4) of an RTT the algorithm waits before determining a
+// packet is lost due to early retransmission by time based loss detection.
+static const int kDefaultLossDelayShift = 2;
+
 // Packet number of first sending packet of a connection. Please note, this
 // cannot be used as first received packet because peer can choose its starting
 // packet number.
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 7a413d0..ee7bb34 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -249,6 +249,30 @@
   if (config.HasClientRequestedIndependentOption(kLFAK, perspective)) {
     uber_loss_algorithm_.SetLossDetectionType(kLazyFack);
   }
+  if (GetQuicReloadableFlag(quic_enable_ietf_loss_detection)) {
+    if (config.HasClientRequestedIndependentOption(kILD0, perspective)) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 1, 4);
+      uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection);
+    }
+    if (config.HasClientRequestedIndependentOption(kILD1, perspective)) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 2, 4);
+      uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection);
+      uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift);
+    }
+    if (GetQuicReloadableFlag(quic_detect_spurious_loss)) {
+      if (config.HasClientRequestedIndependentOption(kILD2, perspective)) {
+        QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 3, 4);
+        uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection);
+        uber_loss_algorithm_.EnableAdaptiveReorderingThreshold();
+      }
+      if (config.HasClientRequestedIndependentOption(kILD3, perspective)) {
+        QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 4, 4);
+        uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection);
+        uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift);
+        uber_loss_algorithm_.EnableAdaptiveReorderingThreshold();
+      }
+    }
+  }
   if (config.HasClientSentConnectionOption(kCONH, perspective)) {
     conservative_handshake_retransmits_ = true;
   }
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index b0806e5..e787715 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -2159,6 +2159,101 @@
                        ->GetLossDetectionType());
 }
 
+TEST_P(QuicSentPacketManagerTest, NegotiateIetfLossDetectionFromOptions) {
+  SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true);
+  EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                       ->GetLossDetectionType());
+
+  QuicConfig config;
+  QuicTagVector options;
+  options.push_back(kILD0);
+  QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  manager_.SetFromConfig(config);
+
+  EXPECT_EQ(kIetfLossDetection,
+            QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                ->GetLossDetectionType());
+  EXPECT_EQ(3, QuicSentPacketManagerPeer::GetReorderingShift(&manager_));
+  EXPECT_FALSE(
+      QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest,
+       NegotiateIetfLossDetectionOneFourthRttFromOptions) {
+  SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true);
+  EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                       ->GetLossDetectionType());
+
+  QuicConfig config;
+  QuicTagVector options;
+  options.push_back(kILD1);
+  QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  manager_.SetFromConfig(config);
+
+  EXPECT_EQ(kIetfLossDetection,
+            QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                ->GetLossDetectionType());
+  EXPECT_EQ(kDefaultLossDelayShift,
+            QuicSentPacketManagerPeer::GetReorderingShift(&manager_));
+  EXPECT_FALSE(
+      QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest,
+       NegotiateIetfLossDetectionAdaptiveReorderingThreshold) {
+  SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true);
+  SetQuicReloadableFlag(quic_detect_spurious_loss, true);
+  EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                       ->GetLossDetectionType());
+  EXPECT_FALSE(
+      QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_));
+
+  QuicConfig config;
+  QuicTagVector options;
+  options.push_back(kILD2);
+  QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  manager_.SetFromConfig(config);
+
+  EXPECT_EQ(kIetfLossDetection,
+            QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                ->GetLossDetectionType());
+  EXPECT_EQ(3, QuicSentPacketManagerPeer::GetReorderingShift(&manager_));
+  EXPECT_TRUE(
+      QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest,
+       NegotiateIetfLossDetectionAdaptiveReorderingThreshold2) {
+  SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true);
+  SetQuicReloadableFlag(quic_detect_spurious_loss, true);
+  EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                       ->GetLossDetectionType());
+  EXPECT_FALSE(
+      QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_));
+
+  QuicConfig config;
+  QuicTagVector options;
+  options.push_back(kILD3);
+  QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  manager_.SetFromConfig(config);
+
+  EXPECT_EQ(kIetfLossDetection,
+            QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+                ->GetLossDetectionType());
+  EXPECT_EQ(kDefaultLossDelayShift,
+            QuicSentPacketManagerPeer::GetReorderingShift(&manager_));
+  EXPECT_TRUE(
+      QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_));
+}
+
 TEST_P(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) {
   QuicConfig config;
   QuicTagVector options;
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h
index 814b63c..bd7ff55 100644
--- a/quic/core/quic_types.h
+++ b/quic/core/quic_types.h
@@ -383,10 +383,11 @@
 };
 
 enum LossDetectionType : uint8_t {
-  kNack,          // Used to mimic TCP's loss detection.
-  kTime,          // Time based loss detection.
-  kAdaptiveTime,  // Adaptive time based loss detection.
-  kLazyFack,      // Nack based but with FACK disabled for the first ack.
+  kNack,               // Used to mimic TCP's loss detection.
+  kTime,               // Time based loss detection.
+  kAdaptiveTime,       // Adaptive time based loss detection.
+  kLazyFack,           // Nack based but with FACK disabled for the first ack.
+  kIetfLossDetection,  // IETF style loss detection.
 };
 
 // EncryptionLevel enumerates the stages of encryption that a QUIC connection
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.cc b/quic/test_tools/quic_sent_packet_manager_peer.cc
index c48c090..b680f66 100644
--- a/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -209,5 +209,19 @@
   sent_packet_manager->pacing_sender_.ideal_next_packet_send_time_ = time;
 }
 
+// static
+int QuicSentPacketManagerPeer::GetReorderingShift(
+    QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->uber_loss_algorithm_.general_loss_algorithms_[0]
+      .reordering_shift();
+}
+
+// static
+bool QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(
+    QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->uber_loss_algorithm_.general_loss_algorithms_[0]
+      .use_adaptive_reordering_threshold();
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.h b/quic/test_tools/quic_sent_packet_manager_peer.h
index 6dcce0c..6be8b46 100644
--- a/quic/test_tools/quic_sent_packet_manager_peer.h
+++ b/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -93,6 +93,11 @@
 
   static void SetNextPacedPacketTime(QuicSentPacketManager* sent_packet_manager,
                                      QuicTime time);
+
+  static int GetReorderingShift(QuicSentPacketManager* sent_packet_manager);
+
+  static bool AdaptiveReorderingThresholdEnabled(
+      QuicSentPacketManager* sent_packet_manager);
 };
 
 }  // namespace test