Add connection options to experiment client path degrading alarms with PTOs.

Protected by client options PDP2, PDP3, PDP4, PDP5.

PiperOrigin-RevId: 343346768
Change-Id: Ieda8c4e96ab5824fe35dbe9c6fd913d7331e1543
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 5372f3f..96c1be1 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -377,6 +377,18 @@
 const QuicTag kQLVE = TAG('Q', 'L', 'V', 'E');   // Legacy Version
                                                  // Encapsulation.
 
+const QuicTag kPDP2 = TAG('P', 'D', 'P', '2');   // Path degrading triggered
+                                                 // at 2PTO.
+
+const QuicTag kPDP3 = TAG('P', 'D', 'P', '3');   // Path degrading triggered
+                                                 // at 3PTO.
+
+const QuicTag kPDP4 = TAG('P', 'D', 'P', '4');   // Path degrading triggered
+                                                 // at 4PTO.
+
+const QuicTag kPDP5 = TAG('P', 'D', 'P', '5');   // Path degrading triggered
+                                                 // at 5PTO.
+
 const QuicTag kQNZ2 = TAG('Q', 'N', 'Z', '2');   // Turn off QUIC crypto 0-RTT.
 
 const QuicTag kQNSP = TAG('Q', 'N', 'S', 'P');   // Turn off server push in
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 592faa1..c823582 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -115,7 +115,8 @@
       one_rtt_packet_sent_(false),
       first_pto_srtt_multiplier_(0),
       use_standard_deviation_for_pto_(false),
-      pto_multiplier_without_rtt_samples_(3) {
+      pto_multiplier_without_rtt_samples_(3),
+      num_ptos_for_path_degrading_(0) {
   SetSendAlgorithm(congestion_control_type);
   if (pto_enabled_) {
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_on_pto, 1, 2);
@@ -219,6 +220,18 @@
       use_standard_deviation_for_pto_ = true;
       rtt_stats_.EnableStandardDeviationCalculation();
     }
+    if (config.HasClientRequestedIndependentOption(kPDP2, perspective)) {
+      num_ptos_for_path_degrading_ = 2;
+    }
+    if (config.HasClientRequestedIndependentOption(kPDP3, perspective)) {
+      num_ptos_for_path_degrading_ = 3;
+    }
+    if (config.HasClientRequestedIndependentOption(kPDP4, perspective)) {
+      num_ptos_for_path_degrading_ = 4;
+    }
+    if (config.HasClientRequestedIndependentOption(kPDP5, perspective)) {
+      num_ptos_for_path_degrading_ = 5;
+    }
   }
 
   // Configure congestion control.
@@ -1393,6 +1406,9 @@
 }
 
 const QuicTime::Delta QuicSentPacketManager::GetPathDegradingDelay() const {
+  if (num_ptos_for_path_degrading_ > 0) {
+    return num_ptos_for_path_degrading_ * GetPtoDelay();
+  }
   return GetNConsecutiveRetransmissionTimeoutDelay(
       max_tail_loss_probes_ + kNumRetransmissionDelaysForPathDegradingDelay);
 }
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index df18f2a..7dad0b0 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -737,6 +737,10 @@
   // available.
   float pto_multiplier_without_rtt_samples_;
 
+  // The number of PTOs needed for path degrading alarm. If equals to 0, the
+  // traditional path degrading mechanism will be used.
+  int num_ptos_for_path_degrading_;
+
   const bool give_sent_packet_to_debug_visitor_after_sent_ =
       GetQuicReloadableFlag(quic_give_sent_packet_to_debug_visitor_after_sent);
 };
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 3975809..4ef1664 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -3865,6 +3865,23 @@
   EXPECT_EQ(expected_delay, manager_.GetPathDegradingDelay());
 }
 
+TEST_F(QuicSentPacketManagerTest, GetPathDegradingDelayUsingPTO) {
+  QuicConfig client_config;
+  QuicTagVector options;
+  options.push_back(k1PTO);
+  QuicTagVector client_options;
+  client_options.push_back(kPDP2);
+  QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+  client_config.SetConnectionOptionsToSend(options);
+  client_config.SetClientConnectionOptions(client_options);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  manager_.SetFromConfig(client_config);
+  EXPECT_TRUE(manager_.pto_enabled());
+  QuicTime::Delta expected_delay = 2 * manager_.GetPtoDelay();
+  EXPECT_EQ(expected_delay, manager_.GetPathDegradingDelay());
+}
+
 // Regression test for b/154050235.
 TEST_F(QuicSentPacketManagerTest, ExponentialBackoffWithNoRttMeasurement) {
   QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);