No public description

PiperOrigin-RevId: 675563943
diff --git a/quiche/quic/core/congestion_control/bbr2_misc.cc b/quiche/quic/core/congestion_control/bbr2_misc.cc
index 1584d02..00879b9 100644
--- a/quiche/quic/core/congestion_control/bbr2_misc.cc
+++ b/quiche/quic/core/congestion_control/bbr2_misc.cc
@@ -226,6 +226,16 @@
           std::max(bandwidth_latest_, bandwidth_lo_ * (1.0 - Params().beta));
       QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_
                     << ", bandwidth_latest_ is " << bandwidth_latest_;
+      if (enable_app_driven_pacing_) {
+        // In this mode, we forcibly cap bandwidth_lo_ at the application driven
+        // pacing rate when congestion_event.bytes_lost > 0. The idea is to
+        // avoid going over what the application needs at the earliest signs of
+        // network congestion.
+        bandwidth_lo_ = std::min(application_bandwidth_target_, bandwidth_lo_);
+        QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_
+                      << "after applying application_driven_pacing at "
+                      << application_bandwidth_target_;
+      }
 
       if (Params().ignore_inflight_lo) {
         return;
diff --git a/quiche/quic/core/congestion_control/bbr2_misc.h b/quiche/quic/core/congestion_control/bbr2_misc.h
index 6dbe904..09654ad 100644
--- a/quiche/quic/core/congestion_control/bbr2_misc.h
+++ b/quiche/quic/core/congestion_control/bbr2_misc.h
@@ -438,6 +438,14 @@
 
   bool MaybeExpireMinRtt(const Bbr2CongestionEvent& congestion_event);
 
+  void SetEnableAppDrivenPacing(bool value) {
+    enable_app_driven_pacing_ = value;
+  }
+
+  void SetApplicationBandwidthTarget(QuicBandwidth bandwidth) {
+    application_bandwidth_target_ = bandwidth;
+  }
+
   QuicBandwidth BandwidthEstimate() const {
     return std::min(MaxBandwidth(), bandwidth_lo_);
   }
@@ -576,6 +584,9 @@
   QuicBandwidth bandwidth_latest_ = QuicBandwidth::Zero();
   // Max bandwidth of recent rounds. Updated once per round.
   QuicBandwidth bandwidth_lo_ = bandwidth_lo_default();
+  // Target bandwidth from applications for app-driven pacing. Only used when
+  // enable_app_driven_pacing_ is true.
+  QuicBandwidth application_bandwidth_target_ = QuicBandwidth::Infinite();
   // bandwidth_lo_ at the beginning of a round with loss. Only used when the
   // bw_lo_mode is non-default.
   QuicBandwidth prior_bandwidth_lo_ = QuicBandwidth::Zero();
@@ -593,6 +604,9 @@
   // epoch.
   bool cwnd_limited_before_aggregation_epoch_ = false;
 
+  // Enable application-driven pacing.
+  bool enable_app_driven_pacing_ = false;
+
   // STARTUP-centric fields which experimentally used by PROBE_UP.
   bool full_bandwidth_reached_ = false;
   QuicBandwidth full_bandwidth_baseline_ = QuicBandwidth::Zero();
diff --git a/quiche/quic/core/congestion_control/bbr2_sender.cc b/quiche/quic/core/congestion_control/bbr2_sender.cc
index 3e4ecb3..6118546 100644
--- a/quiche/quic/core/congestion_control/bbr2_sender.cc
+++ b/quiche/quic/core/congestion_control/bbr2_sender.cc
@@ -194,6 +194,9 @@
   if (ContainsQuicTag(connection_options, kBBRB)) {
     model_.SetLimitMaxAckHeightTrackerBySendRate(true);
   }
+  if (ContainsQuicTag(connection_options, kADP0)) {
+    model_.SetEnableAppDrivenPacing(true);
+  }
   if (ContainsQuicTag(connection_options, kB206)) {
     params_.startup_full_loss_count = params_.probe_bw_full_loss_count;
   }
@@ -273,6 +276,11 @@
   }
 }
 
+void Bbr2Sender::SetApplicationDrivenPacingRate(
+    QuicBandwidth application_bandwidth_target) {
+  model_.SetApplicationBandwidthTarget(application_bandwidth_target);
+}
+
 void Bbr2Sender::OnCongestionEvent(bool /*rtt_updated*/,
                                    QuicByteCount prior_in_flight,
                                    QuicTime event_time,
diff --git a/quiche/quic/core/congestion_control/bbr2_sender.h b/quiche/quic/core/congestion_control/bbr2_sender.h
index 636d340..9338414 100644
--- a/quiche/quic/core/congestion_control/bbr2_sender.h
+++ b/quiche/quic/core/congestion_control/bbr2_sender.h
@@ -52,6 +52,9 @@
   void SetInitialCongestionWindowInPackets(
       QuicPacketCount congestion_window) override;
 
+  void SetApplicationDrivenPacingRate(
+      QuicBandwidth application_bandwidth_target) override;
+
   void OnCongestionEvent(bool rtt_updated, QuicByteCount prior_in_flight,
                          QuicTime event_time,
                          const AckedPacketVector& acked_packets,
diff --git a/quiche/quic/core/congestion_control/bbr_sender.h b/quiche/quic/core/congestion_control/bbr_sender.h
index 625394a..132908f 100644
--- a/quiche/quic/core/congestion_control/bbr_sender.h
+++ b/quiche/quic/core/congestion_control/bbr_sender.h
@@ -108,6 +108,8 @@
   void AdjustNetworkParameters(const NetworkParams& params) override;
   void SetInitialCongestionWindowInPackets(
       QuicPacketCount congestion_window) override;
+  void SetApplicationDrivenPacingRate(
+      QuicBandwidth /*application_bandwidth_target*/) override {}
   void OnCongestionEvent(bool rtt_updated, QuicByteCount prior_in_flight,
                          QuicTime event_time,
                          const AckedPacketVector& acked_packets,
diff --git a/quiche/quic/core/congestion_control/send_algorithm_interface.h b/quiche/quic/core/congestion_control/send_algorithm_interface.h
index 95cd8f0..e5f5588 100644
--- a/quiche/quic/core/congestion_control/send_algorithm_interface.h
+++ b/quiche/quic/core/congestion_control/send_algorithm_interface.h
@@ -74,6 +74,11 @@
   // if called after the initial congestion window is no longer relevant.
   virtual void SetInitialCongestionWindowInPackets(QuicPacketCount packets) = 0;
 
+  // [Experimental] Sets the application driven pacing rate. This is only used
+  // by an experimental feature for bbr2_sender.
+  virtual void SetApplicationDrivenPacingRate(
+      QuicBandwidth application_bandwidth_target) = 0;
+
   // Indicates an update to the congestion state, caused either by an incoming
   // ack or loss event timeout.  |rtt_updated| indicates whether a new
   // latest_rtt sample has been taken, |prior_in_flight| the bytes in flight
diff --git a/quiche/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/quiche/quic/core/congestion_control/tcp_cubic_sender_bytes.h
index de003f7..b62a808 100644
--- a/quiche/quic/core/congestion_control/tcp_cubic_sender_bytes.h
+++ b/quiche/quic/core/congestion_control/tcp_cubic_sender_bytes.h
@@ -50,6 +50,8 @@
   void SetNumEmulatedConnections(int num_connections);
   void SetInitialCongestionWindowInPackets(
       QuicPacketCount congestion_window) override;
+  void SetApplicationDrivenPacingRate(
+      QuicBandwidth /*application_bandwidth_target*/) override {}
   void OnConnectionMigration() override;
   void OnCongestionEvent(bool rtt_updated, QuicByteCount prior_in_flight,
                          QuicTime event_time,
diff --git a/quiche/quic/core/crypto/crypto_protocol.h b/quiche/quic/core/crypto/crypto_protocol.h
index e05f869..118de64 100644
--- a/quiche/quic/core/crypto/crypto_protocol.h
+++ b/quiche/quic/core/crypto/crypto_protocol.h
@@ -364,6 +364,9 @@
 const QuicTag kNSLC = TAG('N', 'S', 'L', 'C');  // Always send connection close
                                                 // for idle timeout.
 
+// Enable application-driven pacing experiment.
+const QuicTag kADP0 = TAG('A', 'D', 'P', '0');  // Enable App-Driven Pacing.
+
 // Proof types (i.e. certificate types)
 // NOTE: although it would be silly to do so, specifying both kX509 and kX59R
 // is allowed and is equivalent to specifying only kX509.
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h
index ada2cbc..df9fd66 100644
--- a/quiche/quic/test_tools/quic_test_utils.h
+++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -1216,6 +1216,8 @@
               (const QuicTagVector& connection_options), (override));
   MOCK_METHOD(void, SetInitialCongestionWindowInPackets,
               (QuicPacketCount packets), (override));
+  MOCK_METHOD(void, SetApplicationDrivenPacingRate,
+              (QuicBandwidth application_bandwidth_target), (override));
   MOCK_METHOD(void, OnCongestionEvent,
               (bool rtt_updated, QuicByteCount bytes_in_flight,
                QuicTime event_time, const AckedPacketVector& acked_packets,