blob: b4baa2f3b4a63cf5623f31ca6ebb237dfda06980 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// BBR (Bottleneck Bandwidth and RTT) congestion control algorithm.
6
7#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_BBR_SENDER_H_
8#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_BBR_SENDER_H_
9
10#include <cstdint>
11#include <ostream>
vasilvv872e7a32019-03-12 16:42:44 -070012#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050013
QUICHE teama6ef0a62019-03-07 20:34:33 -050014#include "net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h"
15#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
16#include "net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h"
17#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
18#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
19#include "net/third_party/quiche/src/quic/core/quic_packets.h"
20#include "net/third_party/quiche/src/quic/core/quic_time.h"
21#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h"
22#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050023
24namespace quic {
25
26class RttStats;
27
QUICHE teama6ef0a62019-03-07 20:34:33 -050028// BbrSender implements BBR congestion control algorithm. BBR aims to estimate
29// the current available Bottleneck Bandwidth and RTT (hence the name), and
30// regulates the pacing rate and the size of the congestion window based on
31// those signals.
32//
33// BBR relies on pacing in order to function properly. Do not use BBR when
34// pacing is disabled.
35//
36// TODO(vasilvv): implement traffic policer (long-term sampling) mode.
37class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
38 public:
39 enum Mode {
40 // Startup phase of the connection.
41 STARTUP,
42 // After achieving the highest possible bandwidth during the startup, lower
43 // the pacing rate in order to drain the queue.
44 DRAIN,
45 // Cruising mode.
46 PROBE_BW,
47 // Temporarily slow down sending in order to empty the buffer and measure
48 // the real minimum RTT.
49 PROBE_RTT,
50 };
51
52 // Indicates how the congestion control limits the amount of bytes in flight.
53 enum RecoveryState {
54 // Do not limit.
55 NOT_IN_RECOVERY,
56 // Allow an extra outstanding byte for each byte acknowledged.
57 CONSERVATION,
58 // Allow two extra outstanding bytes for each byte acknowledged (slow
59 // start).
60 GROWTH
61 };
62
63 // Debug state can be exported in order to troubleshoot potential congestion
64 // control issues.
dschinazif25169a2019-10-23 08:12:18 -070065 struct QUIC_EXPORT_PRIVATE DebugState {
QUICHE teama6ef0a62019-03-07 20:34:33 -050066 explicit DebugState(const BbrSender& sender);
67 DebugState(const DebugState& state);
68
69 Mode mode;
70 QuicBandwidth max_bandwidth;
71 QuicRoundTripCount round_trip_count;
72 int gain_cycle_index;
73 QuicByteCount congestion_window;
74
75 bool is_at_full_bandwidth;
76 QuicBandwidth bandwidth_at_last_round;
77 QuicRoundTripCount rounds_without_bandwidth_gain;
78
79 QuicTime::Delta min_rtt;
80 QuicTime min_rtt_timestamp;
81
82 RecoveryState recovery_state;
83 QuicByteCount recovery_window;
84
85 bool last_sample_is_app_limited;
86 QuicPacketNumber end_of_app_limited_phase;
87 };
88
wub967ba572019-04-01 09:27:52 -070089 BbrSender(QuicTime now,
90 const RttStats* rtt_stats,
QUICHE teama6ef0a62019-03-07 20:34:33 -050091 const QuicUnackedPacketMap* unacked_packets,
92 QuicPacketCount initial_tcp_congestion_window,
93 QuicPacketCount max_tcp_congestion_window,
wub967ba572019-04-01 09:27:52 -070094 QuicRandom* random,
95 QuicConnectionStats* stats);
QUICHE teama6ef0a62019-03-07 20:34:33 -050096 BbrSender(const BbrSender&) = delete;
97 BbrSender& operator=(const BbrSender&) = delete;
98 ~BbrSender() override;
99
100 // Start implementation of SendAlgorithmInterface.
101 bool InSlowStart() const override;
102 bool InRecovery() const override;
103 bool ShouldSendProbingPacket() const override;
104
105 void SetFromConfig(const QuicConfig& config,
106 Perspective perspective) override;
107
108 void AdjustNetworkParameters(QuicBandwidth bandwidth,
fayangf1b99dc2019-05-14 06:29:18 -0700109 QuicTime::Delta rtt,
110 bool allow_cwnd_to_decrease) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 void SetInitialCongestionWindowInPackets(
112 QuicPacketCount congestion_window) override;
113 void OnCongestionEvent(bool rtt_updated,
114 QuicByteCount prior_in_flight,
115 QuicTime event_time,
116 const AckedPacketVector& acked_packets,
117 const LostPacketVector& lost_packets) override;
118 void OnPacketSent(QuicTime sent_time,
119 QuicByteCount bytes_in_flight,
120 QuicPacketNumber packet_number,
121 QuicByteCount bytes,
122 HasRetransmittableData is_retransmittable) override;
dschinazi17d42422019-06-18 16:35:07 -0700123 void OnRetransmissionTimeout(bool /*packets_retransmitted*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500124 void OnConnectionMigration() override {}
125 bool CanSend(QuicByteCount bytes_in_flight) override;
126 QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override;
127 QuicBandwidth BandwidthEstimate() const override;
128 QuicByteCount GetCongestionWindow() const override;
129 QuicByteCount GetSlowStartThreshold() const override;
130 CongestionControlType GetCongestionControlType() const override;
vasilvvc48c8712019-03-11 13:38:16 -0700131 std::string GetDebugState() const override;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500132 void OnApplicationLimited(QuicByteCount bytes_in_flight) override;
133 // End implementation of SendAlgorithmInterface.
134
135 // Gets the number of RTTs BBR remains in STARTUP phase.
136 QuicRoundTripCount num_startup_rtts() const { return num_startup_rtts_; }
137 bool has_non_app_limited_sample() const {
138 return has_non_app_limited_sample_;
139 }
140
141 // Sets the pacing gain used in STARTUP. Must be greater than 1.
142 void set_high_gain(float high_gain) {
143 DCHECK_LT(1.0f, high_gain);
144 high_gain_ = high_gain;
145 if (mode_ == STARTUP) {
146 pacing_gain_ = high_gain;
147 }
148 }
149
150 // Sets the CWND gain used in STARTUP. Must be greater than 1.
151 void set_high_cwnd_gain(float high_cwnd_gain) {
152 DCHECK_LT(1.0f, high_cwnd_gain);
153 high_cwnd_gain_ = high_cwnd_gain;
154 if (mode_ == STARTUP) {
155 congestion_window_gain_ = high_cwnd_gain;
156 }
157 }
158
159 // Sets the gain used in DRAIN. Must be less than 1.
160 void set_drain_gain(float drain_gain) {
161 DCHECK_GT(1.0f, drain_gain);
162 drain_gain_ = drain_gain;
163 }
164
wub5b352f12019-05-07 11:45:26 -0700165 // Returns the current estimate of the RTT of the connection. Outside of the
166 // edge cases, this is minimum RTT.
167 QuicTime::Delta GetMinRtt() const;
168
QUICHE teama6ef0a62019-03-07 20:34:33 -0500169 DebugState ExportDebugState() const;
170
171 private:
172 typedef WindowedFilter<QuicBandwidth,
173 MaxFilter<QuicBandwidth>,
174 QuicRoundTripCount,
175 QuicRoundTripCount>
176 MaxBandwidthFilter;
177
178 typedef WindowedFilter<QuicByteCount,
179 MaxFilter<QuicByteCount>,
180 QuicRoundTripCount,
181 QuicRoundTripCount>
182 MaxAckHeightFilter;
183
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 // Returns whether the connection has achieved full bandwidth required to exit
185 // the slow start.
186 bool IsAtFullBandwidth() const;
187 // Computes the target congestion window using the specified gain.
188 QuicByteCount GetTargetCongestionWindow(float gain) const;
189 // The target congestion window during PROBE_RTT.
190 QuicByteCount ProbeRttCongestionWindow() const;
191 // Returns true if the current min_rtt should be kept and we should not enter
192 // PROBE_RTT immediately.
193 bool ShouldExtendMinRttExpiry() const;
194
195 // Enters the STARTUP mode.
wub967ba572019-04-01 09:27:52 -0700196 void EnterStartupMode(QuicTime now);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500197 // Enters the PROBE_BW mode.
198 void EnterProbeBandwidthMode(QuicTime now);
199
200 // Discards the lost packets from BandwidthSampler state.
201 void DiscardLostPackets(const LostPacketVector& lost_packets);
202 // Updates the round-trip counter if a round-trip has passed. Returns true if
203 // the counter has been advanced.
204 bool UpdateRoundTripCounter(QuicPacketNumber last_acked_packet);
205 // Updates the current bandwidth and min_rtt estimate based on the samples for
206 // the received acknowledgements. Returns true if min_rtt has expired.
207 bool UpdateBandwidthAndMinRtt(QuicTime now,
208 const AckedPacketVector& acked_packets);
209 // Updates the current gain used in PROBE_BW mode.
210 void UpdateGainCyclePhase(QuicTime now,
211 QuicByteCount prior_in_flight,
212 bool has_losses);
213 // Tracks for how many round-trips the bandwidth has not increased
214 // significantly.
215 void CheckIfFullBandwidthReached();
216 // Transitions from STARTUP to DRAIN and from DRAIN to PROBE_BW if
217 // appropriate.
218 void MaybeExitStartupOrDrain(QuicTime now);
219 // Decides whether to enter or exit PROBE_RTT.
220 void MaybeEnterOrExitProbeRtt(QuicTime now,
221 bool is_round_start,
222 bool min_rtt_expired);
223 // Determines whether BBR needs to enter, exit or advance state of the
224 // recovery.
225 void UpdateRecoveryState(QuicPacketNumber last_acked_packet,
226 bool has_losses,
227 bool is_round_start);
228
229 // Updates the ack aggregation max filter in bytes.
230 // Returns the most recent addition to the filter, or |newly_acked_bytes| if
231 // nothing was fed in to the filter.
232 QuicByteCount UpdateAckAggregationBytes(QuicTime ack_time,
233 QuicByteCount newly_acked_bytes);
234
235 // Determines the appropriate pacing rate for the connection.
236 void CalculatePacingRate();
237 // Determines the appropriate congestion window for the connection.
238 void CalculateCongestionWindow(QuicByteCount bytes_acked,
239 QuicByteCount excess_acked);
wub967ba572019-04-01 09:27:52 -0700240 // Determines the appropriate window that constrains the in-flight during
QUICHE teama6ef0a62019-03-07 20:34:33 -0500241 // recovery.
242 void CalculateRecoveryWindow(QuicByteCount bytes_acked,
243 QuicByteCount bytes_lost);
244
245 // Returns true if there are enough bytes in flight to ensure more bandwidth
246 // will be observed if present.
247 bool IsPipeSufficientlyFull() const;
248
wub967ba572019-04-01 09:27:52 -0700249 // Called right before exiting STARTUP.
250 void OnExitStartup(QuicTime now);
251
QUICHE teama6ef0a62019-03-07 20:34:33 -0500252 const RttStats* rtt_stats_;
253 const QuicUnackedPacketMap* unacked_packets_;
254 QuicRandom* random_;
wub967ba572019-04-01 09:27:52 -0700255 QuicConnectionStats* stats_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500256
257 Mode mode_;
258
259 // Bandwidth sampler provides BBR with the bandwidth measurements at
260 // individual points.
261 BandwidthSampler sampler_;
262
263 // The number of the round trips that have occurred during the connection.
264 QuicRoundTripCount round_trip_count_;
265
266 // The packet number of the most recently sent packet.
267 QuicPacketNumber last_sent_packet_;
268 // Acknowledgement of any packet after |current_round_trip_end_| will cause
269 // the round trip counter to advance.
270 QuicPacketNumber current_round_trip_end_;
271
272 // The filter that tracks the maximum bandwidth over the multiple recent
273 // round-trips.
274 MaxBandwidthFilter max_bandwidth_;
275
QUICHE teama6ef0a62019-03-07 20:34:33 -0500276 // Minimum RTT estimate. Automatically expires within 10 seconds (and
277 // triggers PROBE_RTT mode) if no new value is sampled during that period.
278 QuicTime::Delta min_rtt_;
279 // The time at which the current value of |min_rtt_| was assigned.
280 QuicTime min_rtt_timestamp_;
281
282 // The maximum allowed number of bytes in flight.
283 QuicByteCount congestion_window_;
284
285 // The initial value of the |congestion_window_|.
286 QuicByteCount initial_congestion_window_;
287
288 // The largest value the |congestion_window_| can achieve.
289 QuicByteCount max_congestion_window_;
290
291 // The smallest value the |congestion_window_| can achieve.
292 QuicByteCount min_congestion_window_;
293
294 // The pacing gain applied during the STARTUP phase.
295 float high_gain_;
296
297 // The CWND gain applied during the STARTUP phase.
298 float high_cwnd_gain_;
299
300 // The pacing gain applied during the DRAIN phase.
301 float drain_gain_;
302
303 // The current pacing rate of the connection.
304 QuicBandwidth pacing_rate_;
305
306 // The gain currently applied to the pacing rate.
307 float pacing_gain_;
308 // The gain currently applied to the congestion window.
309 float congestion_window_gain_;
310
311 // The gain used for the congestion window during PROBE_BW. Latched from
312 // quic_bbr_cwnd_gain flag.
313 const float congestion_window_gain_constant_;
314 // The number of RTTs to stay in STARTUP mode. Defaults to 3.
315 QuicRoundTripCount num_startup_rtts_;
316 // If true, exit startup if 1RTT has passed with no bandwidth increase and
317 // the connection is in recovery.
318 bool exit_startup_on_loss_;
319
320 // Number of round-trips in PROBE_BW mode, used for determining the current
321 // pacing gain cycle.
322 int cycle_current_offset_;
323 // The time at which the last pacing gain cycle was started.
324 QuicTime last_cycle_start_;
325
326 // Indicates whether the connection has reached the full bandwidth mode.
327 bool is_at_full_bandwidth_;
328 // Number of rounds during which there was no significant bandwidth increase.
329 QuicRoundTripCount rounds_without_bandwidth_gain_;
330 // The bandwidth compared to which the increase is measured.
331 QuicBandwidth bandwidth_at_last_round_;
332
333 // Set to true upon exiting quiescence.
334 bool exiting_quiescence_;
335
336 // Time at which PROBE_RTT has to be exited. Setting it to zero indicates
337 // that the time is yet unknown as the number of packets in flight has not
338 // reached the required value.
339 QuicTime exit_probe_rtt_at_;
340 // Indicates whether a round-trip has passed since PROBE_RTT became active.
341 bool probe_rtt_round_passed_;
342
343 // Indicates whether the most recent bandwidth sample was marked as
344 // app-limited.
345 bool last_sample_is_app_limited_;
346 // Indicates whether any non app-limited samples have been recorded.
347 bool has_non_app_limited_sample_;
348 // Indicates app-limited calls should be ignored as long as there's
349 // enough data inflight to see more bandwidth when necessary.
350 bool flexible_app_limited_;
351
352 // Current state of recovery.
353 RecoveryState recovery_state_;
354 // Receiving acknowledgement of a packet after |end_recovery_at_| will cause
355 // BBR to exit the recovery mode. A value above zero indicates at least one
356 // loss has been detected, so it must not be set back to zero.
357 QuicPacketNumber end_recovery_at_;
358 // A window used to limit the number of bytes in flight during loss recovery.
359 QuicByteCount recovery_window_;
360 // If true, consider all samples in recovery app-limited.
361 bool is_app_limited_recovery_;
362
363 // When true, pace at 1.5x and disable packet conservation in STARTUP.
364 bool slower_startup_;
365 // When true, disables packet conservation in STARTUP.
366 bool rate_based_startup_;
367 // When non-zero, decreases the rate in STARTUP by the total number of bytes
368 // lost in STARTUP divided by CWND.
369 uint8_t startup_rate_reduction_multiplier_;
370 // Sum of bytes lost in STARTUP.
371 QuicByteCount startup_bytes_lost_;
372
373 // When true, add the most recent ack aggregation measurement during STARTUP.
374 bool enable_ack_aggregation_during_startup_;
375 // When true, expire the windowed ack aggregation values in STARTUP when
376 // bandwidth increases more than 25%.
377 bool expire_ack_aggregation_in_startup_;
378
379 // If true, will not exit low gain mode until bytes_in_flight drops below BDP
380 // or it's time for high gain mode.
381 bool drain_to_target_;
382
383 // If true, use a CWND of 0.75*BDP during probe_rtt instead of 4 packets.
384 bool probe_rtt_based_on_bdp_;
385 // If true, skip probe_rtt and update the timestamp of the existing min_rtt to
386 // now if min_rtt over the last cycle is within 12.5% of the current min_rtt.
387 // Even if the min_rtt is 12.5% too low, the 25% gain cycling and 2x CWND gain
388 // should overcome an overly small min_rtt.
389 bool probe_rtt_skipped_if_similar_rtt_;
390 // If true, disable PROBE_RTT entirely as long as the connection was recently
391 // app limited.
392 bool probe_rtt_disabled_if_app_limited_;
393 bool app_limited_since_last_probe_rtt_;
394 QuicTime::Delta min_rtt_since_last_probe_rtt_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500395};
396
397QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
398 const BbrSender::Mode& mode);
399QUIC_EXPORT_PRIVATE std::ostream& operator<<(
400 std::ostream& os,
401 const BbrSender::DebugState& state);
402
403} // namespace quic
404
405#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_BBR_SENDER_H_