Refactor: Extract DebugState from Bbr2Sender and Bbr3Sender to a common header.

This change moves the DebugState struct from being nested within Bbr2Sender and Bbr3Sender to a standalone Bbr2DebugState struct in bbr2_misc.h. This allows both Bbr2Sender and Bbr3Sender to share the same debug state representation.

Adds the Bbrv3 enum value, but no production code instantiates a Bbr3Sender yet.

PiperOrigin-RevId: 902643234
diff --git a/quiche/quic/core/congestion_control/bbr2_drain.cc b/quiche/quic/core/congestion_control/bbr2_drain.cc
index 3d5d137..06fe48e 100644
--- a/quiche/quic/core/congestion_control/bbr2_drain.cc
+++ b/quiche/quic/core/congestion_control/bbr2_drain.cc
@@ -45,18 +45,12 @@
   return std::max<QuicByteCount>(bdp, sender_->GetMinimumCongestionWindow());
 }
 
-Bbr2DrainMode::DebugState Bbr2DrainMode::ExportDebugState() const {
-  DebugState s;
+Bbr2DebugState::Drain Bbr2DrainMode::ExportDebugState() const {
+  Bbr2DebugState::Drain s;
   s.drain_target = DrainTarget();
   return s;
 }
 
-std::ostream& operator<<(std::ostream& os,
-                         const Bbr2DrainMode::DebugState& state) {
-  os << "[DRAIN] drain_target: " << state.drain_target << "\n";
-  return os;
-}
-
 const Bbr2Params& Bbr2DrainMode::Params() const { return sender_->Params(); }
 
 }  // namespace quic
diff --git a/quiche/quic/core/congestion_control/bbr2_drain.h b/quiche/quic/core/congestion_control/bbr2_drain.h
index 7741f53..70d7654 100644
--- a/quiche/quic/core/congestion_control/bbr2_drain.h
+++ b/quiche/quic/core/congestion_control/bbr2_drain.h
@@ -39,11 +39,7 @@
     return Bbr2Mode::DRAIN;
   }
 
-  struct QUICHE_EXPORT DebugState {
-    QuicByteCount drain_target;
-  };
-
-  DebugState ExportDebugState() const;
+  Bbr2DebugState::Drain ExportDebugState() const;
 
  private:
   const Bbr2Params& Params() const;
@@ -51,8 +47,6 @@
   QuicByteCount DrainTarget() const;
 };
 
-QUICHE_EXPORT std::ostream& operator<<(std::ostream& os,
-                                       const Bbr2DrainMode::DebugState& state);
 
 }  // namespace quic
 
diff --git a/quiche/quic/core/congestion_control/bbr2_misc.cc b/quiche/quic/core/congestion_control/bbr2_misc.cc
index 43c6f8c..123dd1d 100644
--- a/quiche/quic/core/congestion_control/bbr2_misc.cc
+++ b/quiche/quic/core/congestion_control/bbr2_misc.cc
@@ -495,4 +495,29 @@
   }
 }
 
+std::ostream& operator<<(std::ostream& os, const Bbr2DebugState& s) {
+  os << "mode: " << s.mode << "\n";
+  os << "round_trip_count: " << s.round_trip_count << "\n";
+  os << "bandwidth_hi ~ lo ~ est: " << s.bandwidth_hi << " ~ " << s.bandwidth_lo
+     << " ~ " << s.bandwidth_est << "\n";
+  os << "min_rtt: " << s.min_rtt << "\n";
+  os << "min_rtt_timestamp: " << s.min_rtt_timestamp << "\n";
+  os << "congestion_window: " << s.congestion_window << "\n";
+  os << "pacing_rate: " << s.pacing_rate << "\n";
+  os << "last_sample_is_app_limited: " << s.last_sample_is_app_limited << "\n";
+
+  os << "startup: {full_bw_reached: " << s.startup.full_bandwidth_reached
+     << ", full_bw_baseline: " << s.startup.full_bandwidth_baseline
+     << ", rounds_without_growth: "
+     << s.startup.round_trips_without_bandwidth_growth << "}\n";
+  os << "drain: {drain_target: " << s.drain.drain_target << "}\n";
+  os << "probe_bw: {phase: " << ProbePhaseToString(s.probe_bw.phase)
+     << ", cycle_start_time: " << s.probe_bw.cycle_start_time
+     << ", phase_start_time: " << s.probe_bw.phase_start_time << "}\n";
+  os << "probe_rtt: {inflight_target: " << s.probe_rtt.inflight_target
+     << ", exit_time: " << s.probe_rtt.exit_time << "}\n";
+
+  return os;
+}
+
 }  // namespace quic
diff --git a/quiche/quic/core/congestion_control/bbr2_misc.h b/quiche/quic/core/congestion_control/bbr2_misc.h
index d57b6be..a702e90 100644
--- a/quiche/quic/core/congestion_control/bbr2_misc.h
+++ b/quiche/quic/core/congestion_control/bbr2_misc.h
@@ -707,6 +707,51 @@
          send_state.total_bytes_lost;
 }
 
+// Bbr2DebugState contains most of the internal state of a Bbr2/Bbr3 sender.
+struct QUICHE_EXPORT Bbr2DebugState {
+  Bbr2Mode mode;
+
+  // Shared states.
+  QuicRoundTripCount round_trip_count;
+  QuicBandwidth bandwidth_hi = QuicBandwidth::Zero();
+  QuicBandwidth bandwidth_lo = QuicBandwidth::Zero();
+  QuicBandwidth bandwidth_est = QuicBandwidth::Zero();
+  QuicByteCount inflight_hi;
+  QuicByteCount inflight_lo;
+  QuicByteCount max_ack_height;
+  QuicTime::Delta min_rtt = QuicTime::Delta::Zero();
+  QuicTime min_rtt_timestamp = QuicTime::Zero();
+  QuicByteCount congestion_window;
+  QuicBandwidth pacing_rate = QuicBandwidth::Zero();
+  bool last_sample_is_app_limited;
+  QuicPacketNumber end_of_app_limited_phase;
+
+  // Mode-specific states.
+  struct QUICHE_EXPORT Startup {
+    bool full_bandwidth_reached = false;
+    QuicBandwidth full_bandwidth_baseline = QuicBandwidth::Zero();
+    QuicRoundTripCount round_trips_without_bandwidth_growth = 0;
+  } startup;
+
+  struct QUICHE_EXPORT Drain {
+    QuicByteCount drain_target = 0;
+  } drain;
+
+  struct QUICHE_EXPORT ProbeBw {
+    ProbePhase phase = ProbePhase::PROBE_NOT_STARTED;
+    QuicTime cycle_start_time = QuicTime::Zero();
+    QuicTime phase_start_time = QuicTime::Zero();
+  } probe_bw;
+
+  struct QUICHE_EXPORT ProbeRtt {
+    QuicByteCount inflight_target = 0;
+    QuicTime exit_time = QuicTime::Zero();
+  } probe_rtt;
+};
+
+QUICHE_EXPORT std::ostream& operator<<(std::ostream& os,
+                                       const Bbr2DebugState& state);
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_CONGESTION_CONTROL_BBR2_MISC_H_
diff --git a/quiche/quic/core/congestion_control/bbr2_probe_bw.cc b/quiche/quic/core/congestion_control/bbr2_probe_bw.cc
index d15617b..3588f0f 100644
--- a/quiche/quic/core/congestion_control/bbr2_probe_bw.cc
+++ b/quiche/quic/core/congestion_control/bbr2_probe_bw.cc
@@ -600,24 +600,14 @@
   }
 }
 
-
-
-Bbr2ProbeBwMode::DebugState Bbr2ProbeBwMode::ExportDebugState() const {
-  DebugState s;
+Bbr2DebugState::ProbeBw Bbr2ProbeBwMode::ExportDebugState() const {
+  Bbr2DebugState::ProbeBw s;
   s.phase = cycle_.phase;
   s.cycle_start_time = cycle_.cycle_start_time;
   s.phase_start_time = cycle_.phase_start_time;
   return s;
 }
 
-std::ostream& operator<<(std::ostream& os,
-                         const Bbr2ProbeBwMode::DebugState& state) {
-  os << "[PROBE_BW] phase: " << state.phase << "\n";
-  os << "[PROBE_BW] cycle_start_time: " << state.cycle_start_time << "\n";
-  os << "[PROBE_BW] phase_start_time: " << state.phase_start_time << "\n";
-  return os;
-}
-
 const Bbr2Params& Bbr2ProbeBwMode::Params() const { return sender_->Params(); }
 
 float Bbr2ProbeBwMode::PacingGainForPhase(ProbePhase phase) const {
diff --git a/quiche/quic/core/congestion_control/bbr2_probe_bw.h b/quiche/quic/core/congestion_control/bbr2_probe_bw.h
index 83c5764..306ef9b 100644
--- a/quiche/quic/core/congestion_control/bbr2_probe_bw.h
+++ b/quiche/quic/core/congestion_control/bbr2_probe_bw.h
@@ -38,14 +38,7 @@
   Bbr2Mode OnExitQuiescence(QuicTime now,
                             QuicTime quiescence_start_time) override;
 
-
-  struct QUICHE_EXPORT DebugState {
-    ProbePhase phase;
-    QuicTime cycle_start_time = QuicTime::Zero();
-    QuicTime phase_start_time = QuicTime::Zero();
-  };
-
-  DebugState ExportDebugState() const;
+  Bbr2DebugState::ProbeBw ExportDebugState() const;
 
  private:
   const Bbr2Params& Params() const;
@@ -118,8 +111,6 @@
   bool last_cycle_stopped_risky_probe_;
 };
 
-QUICHE_EXPORT std::ostream& operator<<(
-    std::ostream& os, const Bbr2ProbeBwMode::DebugState& state);
 
 }  // namespace quic
 
diff --git a/quiche/quic/core/congestion_control/bbr2_probe_rtt.cc b/quiche/quic/core/congestion_control/bbr2_probe_rtt.cc
index f7ce351..880b98f 100644
--- a/quiche/quic/core/congestion_control/bbr2_probe_rtt.cc
+++ b/quiche/quic/core/congestion_control/bbr2_probe_rtt.cc
@@ -63,20 +63,13 @@
   return Bbr2Mode::PROBE_RTT;
 }
 
-Bbr2ProbeRttMode::DebugState Bbr2ProbeRttMode::ExportDebugState() const {
-  DebugState s;
+Bbr2DebugState::ProbeRtt Bbr2ProbeRttMode::ExportDebugState() const {
+  Bbr2DebugState::ProbeRtt s;
   s.inflight_target = InflightTarget();
   s.exit_time = exit_time_;
   return s;
 }
 
-std::ostream& operator<<(std::ostream& os,
-                         const Bbr2ProbeRttMode::DebugState& state) {
-  os << "[PROBE_RTT] inflight_target: " << state.inflight_target << "\n";
-  os << "[PROBE_RTT] exit_time: " << state.exit_time << "\n";
-  return os;
-}
-
 const Bbr2Params& Bbr2ProbeRttMode::Params() const { return sender_->Params(); }
 
 }  // namespace quic
diff --git a/quiche/quic/core/congestion_control/bbr2_probe_rtt.h b/quiche/quic/core/congestion_control/bbr2_probe_rtt.h
index f832476..974035e 100644
--- a/quiche/quic/core/congestion_control/bbr2_probe_rtt.h
+++ b/quiche/quic/core/congestion_control/bbr2_probe_rtt.h
@@ -35,12 +35,7 @@
   Bbr2Mode OnExitQuiescence(QuicTime now,
                             QuicTime quiescence_start_time) override;
 
-  struct QUICHE_EXPORT DebugState {
-    QuicByteCount inflight_target;
-    QuicTime exit_time = QuicTime::Zero();
-  };
-
-  DebugState ExportDebugState() const;
+  Bbr2DebugState::ProbeRtt ExportDebugState() const;
 
  private:
   const Bbr2Params& Params() const;
@@ -50,8 +45,6 @@
   QuicTime exit_time_ = QuicTime::Zero();
 };
 
-QUICHE_EXPORT std::ostream& operator<<(
-    std::ostream& os, const Bbr2ProbeRttMode::DebugState& state);
 
 }  // namespace quic
 
diff --git a/quiche/quic/core/congestion_control/bbr2_sender.cc b/quiche/quic/core/congestion_control/bbr2_sender.cc
index 0beda68..c5bb0cb 100644
--- a/quiche/quic/core/congestion_control/bbr2_sender.cc
+++ b/quiche/quic/core/congestion_control/bbr2_sender.cc
@@ -522,8 +522,8 @@
   return stream.str();
 }
 
-Bbr2Sender::DebugState Bbr2Sender::ExportDebugState() const {
-  DebugState s;
+Bbr2DebugState Bbr2Sender::ExportDebugState() const {
+  Bbr2DebugState s;
   s.mode = mode_;
   s.round_trip_count = model_.RoundTripCount();
   s.bandwidth_hi = model_.MaxBandwidth();
@@ -547,34 +547,4 @@
   return s;
 }
 
-std::ostream& operator<<(std::ostream& os, const Bbr2Sender::DebugState& s) {
-  os << "mode: " << s.mode << "\n";
-  os << "round_trip_count: " << s.round_trip_count << "\n";
-  os << "bandwidth_hi ~ lo ~ est: " << s.bandwidth_hi << " ~ " << s.bandwidth_lo
-     << " ~ " << s.bandwidth_est << "\n";
-  os << "min_rtt: " << s.min_rtt << "\n";
-  os << "min_rtt_timestamp: " << s.min_rtt_timestamp << "\n";
-  os << "congestion_window: " << s.congestion_window << "\n";
-  os << "pacing_rate: " << s.pacing_rate << "\n";
-  os << "last_sample_is_app_limited: " << s.last_sample_is_app_limited << "\n";
-
-  if (s.mode == Bbr2Mode::STARTUP) {
-    os << s.startup;
-  }
-
-  if (s.mode == Bbr2Mode::DRAIN) {
-    os << s.drain;
-  }
-
-  if (s.mode == Bbr2Mode::PROBE_BW) {
-    os << s.probe_bw;
-  }
-
-  if (s.mode == Bbr2Mode::PROBE_RTT) {
-    os << s.probe_rtt;
-  }
-
-  return os;
-}
-
 }  // namespace quic
diff --git a/quiche/quic/core/congestion_control/bbr2_sender.h b/quiche/quic/core/congestion_control/bbr2_sender.h
index 21ed5e8..f625919 100644
--- a/quiche/quic/core/congestion_control/bbr2_sender.h
+++ b/quiche/quic/core/congestion_control/bbr2_sender.h
@@ -116,32 +116,7 @@
     return model_.IsBandwidthOverestimateAvoidanceEnabled();
   }
 
-  struct QUICHE_EXPORT DebugState {
-    Bbr2Mode mode;
-
-    // Shared states.
-    QuicRoundTripCount round_trip_count;
-    QuicBandwidth bandwidth_hi = QuicBandwidth::Zero();
-    QuicBandwidth bandwidth_lo = QuicBandwidth::Zero();
-    QuicBandwidth bandwidth_est = QuicBandwidth::Zero();
-    QuicByteCount inflight_hi;
-    QuicByteCount inflight_lo;
-    QuicByteCount max_ack_height;
-    QuicTime::Delta min_rtt = QuicTime::Delta::Zero();
-    QuicTime min_rtt_timestamp = QuicTime::Zero();
-    QuicByteCount congestion_window;
-    QuicBandwidth pacing_rate = QuicBandwidth::Zero();
-    bool last_sample_is_app_limited;
-    QuicPacketNumber end_of_app_limited_phase;
-
-    // Mode-specific debug states.
-    Bbr2StartupMode::DebugState startup;
-    Bbr2DrainMode::DebugState drain;
-    Bbr2ProbeBwMode::DebugState probe_bw;
-    Bbr2ProbeRttMode::DebugState probe_rtt;
-  };
-
-  DebugState ExportDebugState() const;
+  Bbr2DebugState ExportDebugState() const;
 
   const Bbr2NetworkModel& GetNetworkModel() const { return model_; }
 
@@ -216,8 +191,6 @@
   friend class Bbr2ProbeRttMode;
 };
 
-QUICHE_EXPORT std::ostream& operator<<(std::ostream& os,
-                                       const Bbr2Sender::DebugState& state);
 
 }  // namespace quic
 
diff --git a/quiche/quic/core/congestion_control/bbr2_simulator_test.cc b/quiche/quic/core/congestion_control/bbr2_simulator_test.cc
index 6214aff..46edc86 100644
--- a/quiche/quic/core/congestion_control/bbr2_simulator_test.cc
+++ b/quiche/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -176,7 +176,7 @@
   ~Bbr2DefaultTopologyTest() {
     const auto* test_info =
         ::testing::UnitTest::GetInstance()->current_test_info();
-    const Bbr2Sender::DebugState& debug_state = sender_->ExportDebugState();
+    const Bbr2DebugState& debug_state = sender_->ExportDebugState();
     QUIC_LOG(INFO) << "Bbr2DefaultTopologyTest." << test_info->name()
                    << " completed at simulated time: "
                    << SimulatedNow().ToDebuggingValue() / 1e6
@@ -333,7 +333,7 @@
 
   QuicConnection* sender_connection() { return sender_endpoint_.connection(); }
 
-  Bbr2Sender::DebugState sender_debug_state() const {
+  Bbr2DebugState sender_debug_state() const {
     return sender_->ExportDebugState();
   }
 
diff --git a/quiche/quic/core/congestion_control/bbr2_startup.cc b/quiche/quic/core/congestion_control/bbr2_startup.cc
index a7d327f..0bf04dc 100644
--- a/quiche/quic/core/congestion_control/bbr2_startup.cc
+++ b/quiche/quic/core/congestion_control/bbr2_startup.cc
@@ -132,8 +132,8 @@
   }
 }
 
-Bbr2StartupMode::DebugState Bbr2StartupMode::ExportDebugState() const {
-  DebugState s;
+Bbr2DebugState::Startup Bbr2StartupMode::ExportDebugState() const {
+  Bbr2DebugState::Startup s;
   s.full_bandwidth_reached = model_->full_bandwidth_reached();
   s.full_bandwidth_baseline = model_->full_bandwidth_baseline();
   s.round_trips_without_bandwidth_growth =
@@ -141,17 +141,6 @@
   return s;
 }
 
-std::ostream& operator<<(std::ostream& os,
-                         const Bbr2StartupMode::DebugState& state) {
-  os << "[STARTUP] full_bandwidth_reached: " << state.full_bandwidth_reached
-     << "\n";
-  os << "[STARTUP] full_bandwidth_baseline: " << state.full_bandwidth_baseline
-     << "\n";
-  os << "[STARTUP] round_trips_without_bandwidth_growth: "
-     << state.round_trips_without_bandwidth_growth << "\n";
-  return os;
-}
-
 const Bbr2Params& Bbr2StartupMode::Params() const { return sender_->Params(); }
 
 }  // namespace quic
diff --git a/quiche/quic/core/congestion_control/bbr2_startup.h b/quiche/quic/core/congestion_control/bbr2_startup.h
index 64fa5b0..fa5303c 100644
--- a/quiche/quic/core/congestion_control/bbr2_startup.h
+++ b/quiche/quic/core/congestion_control/bbr2_startup.h
@@ -44,13 +44,7 @@
     return Bbr2Mode::STARTUP;
   }
 
-  struct QUICHE_EXPORT DebugState {
-    bool full_bandwidth_reached;
-    QuicBandwidth full_bandwidth_baseline = QuicBandwidth::Zero();
-    QuicRoundTripCount round_trips_without_bandwidth_growth;
-  };
-
-  DebugState ExportDebugState() const;
+  Bbr2DebugState::Startup ExportDebugState() const;
 
  private:
   const Bbr2Params& Params() const;
@@ -60,8 +54,6 @@
   QuicBandwidth max_bw_at_round_beginning_ = QuicBandwidth::Zero();
 };
 
-QUICHE_EXPORT std::ostream& operator<<(
-    std::ostream& os, const Bbr2StartupMode::DebugState& state);
 
 }  // namespace quic
 
diff --git a/quiche/quic/core/congestion_control/bbr3_sender.cc b/quiche/quic/core/congestion_control/bbr3_sender.cc
index dbfad1d..176dfce 100644
--- a/quiche/quic/core/congestion_control/bbr3_sender.cc
+++ b/quiche/quic/core/congestion_control/bbr3_sender.cc
@@ -588,8 +588,8 @@
   return stream.str();
 }
 
-Bbr3Sender::DebugState Bbr3Sender::ExportDebugState() const {
-  DebugState s;
+Bbr2DebugState Bbr3Sender::ExportDebugState() const {
+  Bbr2DebugState s;
   s.mode = mode_;
   s.round_trip_count = model_.RoundTripCount();
   s.bandwidth_hi = model_.MaxBandwidth();
@@ -622,31 +622,6 @@
   return s;
 }
 
-std::ostream& operator<<(std::ostream& os, const Bbr3Sender::DebugState& s) {
-  os << "mode: " << s.mode << "\n";
-  os << "round_trip_count: " << s.round_trip_count << "\n";
-  os << "bandwidth_hi ~ lo ~ est: " << s.bandwidth_hi << " ~ " << s.bandwidth_lo
-     << " ~ " << s.bandwidth_est << "\n";
-  os << "min_rtt: " << s.min_rtt << "\n";
-  os << "min_rtt_timestamp: " << s.min_rtt_timestamp << "\n";
-  os << "congestion_window: " << s.congestion_window << "\n";
-  os << "pacing_rate: " << s.pacing_rate << "\n";
-  os << "last_sample_is_app_limited: " << s.last_sample_is_app_limited << "\n";
-
-  os << "startup: {full_bw_reached: " << s.startup.full_bandwidth_reached
-     << ", full_bw_baseline: " << s.startup.full_bandwidth_baseline
-     << ", rounds_without_growth: "
-     << s.startup.round_trips_without_bandwidth_growth << "}\n";
-  os << "drain: {drain_target: " << s.drain.drain_target << "}\n";
-  os << "probe_bw: {phase: " << ProbePhaseToString(s.probe_bw.phase)
-     << ", cycle_start_time: " << s.probe_bw.cycle_start_time
-     << ", phase_start_time: " << s.probe_bw.phase_start_time << "}\n";
-  os << "probe_rtt: {inflight_target: " << s.probe_rtt.inflight_target
-     << ", exit_time: " << s.probe_rtt.exit_time << "}\n";
-
-  return os;
-}
-
 Bbr2Mode Bbr3Sender::OnCongestionEventStartup(
     const Bbr2CongestionEvent& congestion_event) {
   if (model_.full_bandwidth_reached()) {
diff --git a/quiche/quic/core/congestion_control/bbr3_sender.h b/quiche/quic/core/congestion_control/bbr3_sender.h
index 722df9b..1b4666f 100644
--- a/quiche/quic/core/congestion_control/bbr3_sender.h
+++ b/quiche/quic/core/congestion_control/bbr3_sender.h
@@ -85,7 +85,7 @@
   QuicByteCount GetSlowStartThreshold() const override { return 0; }
 
   CongestionControlType GetCongestionControlType() const override {
-    return kBBRv2;
+    return kBBRv3;
   }
 
   std::string GetDebugState() const override;
@@ -112,48 +112,7 @@
     return model_.IsBandwidthOverestimateAvoidanceEnabled();
   }
 
-  struct QUICHE_EXPORT DebugState {
-    Bbr2Mode mode;
-
-    // Shared states.
-    QuicRoundTripCount round_trip_count;
-    QuicBandwidth bandwidth_hi = QuicBandwidth::Zero();
-    QuicBandwidth bandwidth_lo = QuicBandwidth::Zero();
-    QuicBandwidth bandwidth_est = QuicBandwidth::Zero();
-    QuicByteCount inflight_hi;
-    QuicByteCount inflight_lo;
-    QuicByteCount max_ack_height;
-    QuicTime::Delta min_rtt = QuicTime::Delta::Zero();
-    QuicTime min_rtt_timestamp = QuicTime::Zero();
-    QuicByteCount congestion_window;
-    QuicBandwidth pacing_rate = QuicBandwidth::Zero();
-    bool last_sample_is_app_limited;
-    QuicPacketNumber end_of_app_limited_phase;
-
-    // Mode-specific states.
-    struct QUICHE_EXPORT Startup {
-      bool full_bandwidth_reached = false;
-      QuicBandwidth full_bandwidth_baseline = QuicBandwidth::Zero();
-      QuicRoundTripCount round_trips_without_bandwidth_growth = 0;
-    } startup;
-
-    struct QUICHE_EXPORT Drain {
-      QuicByteCount drain_target = 0;
-    } drain;
-
-    struct QUICHE_EXPORT ProbeBw {
-      ProbePhase phase = ProbePhase::PROBE_NOT_STARTED;
-      QuicTime cycle_start_time = QuicTime::Zero();
-      QuicTime phase_start_time = QuicTime::Zero();
-    } probe_bw;
-
-    struct QUICHE_EXPORT ProbeRtt {
-      QuicByteCount inflight_target = 0;
-      QuicTime exit_time = QuicTime::Zero();
-    } probe_rtt;
-  };
-
-  DebugState ExportDebugState() const;
+  Bbr2DebugState ExportDebugState() const;
 
   const Bbr2NetworkModel& GetNetworkModel() const { return model_; }
 
@@ -288,8 +247,6 @@
   bool last_sample_is_app_limited_;
 };
 
-QUICHE_EXPORT std::ostream& operator<<(std::ostream& os,
-                                       const Bbr3Sender::DebugState& state);
 
 }  // namespace quic
 
diff --git a/quiche/quic/core/congestion_control/bbr3_simulator_test.cc b/quiche/quic/core/congestion_control/bbr3_simulator_test.cc
index 0adb9d1..5984c31 100644
--- a/quiche/quic/core/congestion_control/bbr3_simulator_test.cc
+++ b/quiche/quic/core/congestion_control/bbr3_simulator_test.cc
@@ -175,7 +175,7 @@
   ~Bbr3DefaultTopologyTest() {
     const auto* test_info =
         ::testing::UnitTest::GetInstance()->current_test_info();
-    const Bbr3Sender::DebugState& debug_state = sender_->ExportDebugState();
+    const Bbr2DebugState& debug_state = sender_->ExportDebugState();
     QUIC_LOG(INFO) << "Bbr3DefaultTopologyTest." << test_info->name()
                    << " completed at simulated time: "
                    << SimulatedNow().ToDebuggingValue() / 1e6
@@ -332,7 +332,7 @@
 
   QuicConnection* sender_connection() { return sender_endpoint_.connection(); }
 
-  Bbr3Sender::DebugState sender_debug_state() const {
+  Bbr2DebugState sender_debug_state() const {
     return sender_->ExportDebugState();
   }
 
diff --git a/quiche/quic/core/congestion_control/send_algorithm_interface.cc b/quiche/quic/core/congestion_control/send_algorithm_interface.cc
index cd1cff1..53c9929 100644
--- a/quiche/quic/core/congestion_control/send_algorithm_interface.cc
+++ b/quiche/quic/core/congestion_control/send_algorithm_interface.cc
@@ -6,6 +6,7 @@
 
 #include "absl/base/attributes.h"
 #include "quiche/quic/core/congestion_control/bbr2_sender.h"
+#include "quiche/quic/core/congestion_control/bbr3_sender.h"
 #include "quiche/quic/core/congestion_control/bbr_sender.h"
 #include "quiche/quic/core/congestion_control/prague_sender.h"
 #include "quiche/quic/core/congestion_control/tcp_cubic_sender_bytes.h"
@@ -35,6 +36,14 @@
       return new BbrSender(clock->ApproximateNow(), rtt_stats, unacked_packets,
                            initial_congestion_window, max_congestion_window,
                            random, stats);
+    case kBBRv3:
+      return new Bbr3Sender(
+          clock->ApproximateNow(), rtt_stats, unacked_packets,
+          initial_congestion_window, max_congestion_window, random, stats,
+          old_send_algorithm &&
+                  old_send_algorithm->GetCongestionControlType() == kBBR
+              ? static_cast<BbrSender*>(old_send_algorithm)
+              : nullptr);
     case kBBRv2:
       return new Bbr2Sender(
           clock->ApproximateNow(), rtt_stats, unacked_packets,
diff --git a/quiche/quic/core/quic_sent_packet_manager.cc b/quiche/quic/core/quic_sent_packet_manager.cc
index c9485a1..6b731f0 100644
--- a/quiche/quic/core/quic_sent_packet_manager.cc
+++ b/quiche/quic/core/quic_sent_packet_manager.cc
@@ -1219,7 +1219,8 @@
 
 QuicTime::Delta QuicSentPacketManager::GetSlowStartDuration() const {
   if (send_algorithm_->GetCongestionControlType() == kBBR ||
-      send_algorithm_->GetCongestionControlType() == kBBRv2) {
+      send_algorithm_->GetCongestionControlType() == kBBRv2 ||
+      send_algorithm_->GetCongestionControlType() == kBBRv3) {
     return stats_->slowstart_duration.GetTotalElapsedTime(
         clock_->ApproximateNow());
   }
diff --git a/quiche/quic/core/quic_types.cc b/quiche/quic/core/quic_types.cc
index e4988dd..28a28b3 100644
--- a/quiche/quic/core/quic_types.cc
+++ b/quiche/quic/core/quic_types.cc
@@ -324,6 +324,8 @@
       return "BBR";
     case kBBRv2:
       return "BBRv2";
+    case kBBRv3:
+      return "BBRv3";
     case kPCC:
       return "PCC";
     case kGoogCC:
diff --git a/quiche/quic/core/quic_types.h b/quiche/quic/core/quic_types.h
index 5be2c05..065e93d 100644
--- a/quiche/quic/core/quic_types.h
+++ b/quiche/quic/core/quic_types.h
@@ -456,8 +456,8 @@
   kBBR,
   kPCC,
   kGoogCC,
-  kBBRv2,  // TODO(rch): This is effectively BBRv3. We should finish the
-           // implementation and rename this enum.
+  kBBRv2,  // This has some changes from BBRv3 as well.
+  kBBRv3,
   kPragueCubic,
 };