1 // Copyright 2019 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 #include "quiche/quic/core/congestion_control/uber_loss_algorithm.h"
6
7 #include <algorithm>
8
9 #include "quiche/quic/core/crypto/crypto_protocol.h"
10 #include "quiche/quic/platform/api/quic_bug_tracker.h"
11
12 namespace quic {
13
UberLossAlgorithm()14 UberLossAlgorithm::UberLossAlgorithm() {
15 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
16 general_loss_algorithms_[i].Initialize(static_cast<PacketNumberSpace>(i),
17 this);
18 }
19 }
20
SetFromConfig(const QuicConfig & config,Perspective perspective)21 void UberLossAlgorithm::SetFromConfig(const QuicConfig& config,
22 Perspective perspective) {
23 if (config.HasClientRequestedIndependentOption(kELDT, perspective) &&
24 tuner_ != nullptr) {
25 tuning_configured_ = true;
26 MaybeStartTuning();
27 }
28 }
29
DetectLosses(const QuicUnackedPacketMap & unacked_packets,QuicTime time,const RttStats & rtt_stats,QuicPacketNumber,const AckedPacketVector & packets_acked,LostPacketVector * packets_lost)30 LossDetectionInterface::DetectionStats UberLossAlgorithm::DetectLosses(
31 const QuicUnackedPacketMap& unacked_packets, QuicTime time,
32 const RttStats& rtt_stats, QuicPacketNumber /*largest_newly_acked*/,
33 const AckedPacketVector& packets_acked, LostPacketVector* packets_lost) {
34 DetectionStats overall_stats;
35
36 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
37 const QuicPacketNumber largest_acked =
38 unacked_packets.GetLargestAckedOfPacketNumberSpace(
39 static_cast<PacketNumberSpace>(i));
40 if (!largest_acked.IsInitialized() ||
41 unacked_packets.GetLeastUnacked() > largest_acked) {
42 // Skip detecting losses if no packet has been received for this packet
43 // number space or the least_unacked is greater than largest_acked.
44 continue;
45 }
46
47 DetectionStats stats = general_loss_algorithms_[i].DetectLosses(
48 unacked_packets, time, rtt_stats, largest_acked, packets_acked,
49 packets_lost);
50
51 overall_stats.sent_packets_max_sequence_reordering =
52 std::max(overall_stats.sent_packets_max_sequence_reordering,
53 stats.sent_packets_max_sequence_reordering);
54 overall_stats.sent_packets_num_borderline_time_reorderings +=
55 stats.sent_packets_num_borderline_time_reorderings;
56 overall_stats.total_loss_detection_response_time +=
57 stats.total_loss_detection_response_time;
58 }
59
60 return overall_stats;
61 }
62
GetLossTimeout() const63 QuicTime UberLossAlgorithm::GetLossTimeout() const {
64 QuicTime loss_timeout = QuicTime::Zero();
65 // Returns the earliest non-zero loss timeout.
66 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
67 const QuicTime timeout = general_loss_algorithms_[i].GetLossTimeout();
68 if (!loss_timeout.IsInitialized()) {
69 loss_timeout = timeout;
70 continue;
71 }
72 if (timeout.IsInitialized()) {
73 loss_timeout = std::min(loss_timeout, timeout);
74 }
75 }
76 return loss_timeout;
77 }
78
SpuriousLossDetected(const QuicUnackedPacketMap & unacked_packets,const RttStats & rtt_stats,QuicTime ack_receive_time,QuicPacketNumber packet_number,QuicPacketNumber previous_largest_acked)79 void UberLossAlgorithm::SpuriousLossDetected(
80 const QuicUnackedPacketMap& unacked_packets, const RttStats& rtt_stats,
81 QuicTime ack_receive_time, QuicPacketNumber packet_number,
82 QuicPacketNumber previous_largest_acked) {
83 general_loss_algorithms_[unacked_packets.GetPacketNumberSpace(packet_number)]
84 .SpuriousLossDetected(unacked_packets, rtt_stats, ack_receive_time,
85 packet_number, previous_largest_acked);
86 }
87
SetLossDetectionTuner(std::unique_ptr<LossDetectionTunerInterface> tuner)88 void UberLossAlgorithm::SetLossDetectionTuner(
89 std::unique_ptr<LossDetectionTunerInterface> tuner) {
90 if (tuner_ != nullptr) {
91 QUIC_BUG(quic_bug_10469_1)
92 << "LossDetectionTuner can only be set once when session begins.";
93 return;
94 }
95 tuner_ = std::move(tuner);
96 }
97
MaybeStartTuning()98 void UberLossAlgorithm::MaybeStartTuning() {
99 if (tuner_started_ || !tuning_configured_ || !min_rtt_available_ ||
100 !user_agent_known_ || !reorder_happened_) {
101 return;
102 }
103
104 tuner_started_ = tuner_->Start(&tuned_parameters_);
105 if (!tuner_started_) {
106 return;
107 }
108
109 if (tuned_parameters_.reordering_shift.has_value() &&
110 tuned_parameters_.reordering_threshold.has_value()) {
111 QUIC_DLOG(INFO) << "Setting reordering shift to "
112 << *tuned_parameters_.reordering_shift
113 << ", and reordering threshold to "
114 << *tuned_parameters_.reordering_threshold;
115 SetReorderingShift(*tuned_parameters_.reordering_shift);
116 SetReorderingThreshold(*tuned_parameters_.reordering_threshold);
117 } else {
118 QUIC_BUG(quic_bug_10469_2)
119 << "Tuner started but some parameters are missing";
120 }
121 }
122
OnConfigNegotiated()123 void UberLossAlgorithm::OnConfigNegotiated() {}
124
OnMinRttAvailable()125 void UberLossAlgorithm::OnMinRttAvailable() {
126 min_rtt_available_ = true;
127 MaybeStartTuning();
128 }
129
OnUserAgentIdKnown()130 void UberLossAlgorithm::OnUserAgentIdKnown() {
131 user_agent_known_ = true;
132 MaybeStartTuning();
133 }
134
OnConnectionClosed()135 void UberLossAlgorithm::OnConnectionClosed() {
136 if (tuner_ != nullptr && tuner_started_) {
137 tuner_->Finish(tuned_parameters_);
138 }
139 }
140
OnReorderingDetected()141 void UberLossAlgorithm::OnReorderingDetected() {
142 const bool tuner_started_before = tuner_started_;
143 const bool reorder_happened_before = reorder_happened_;
144
145 reorder_happened_ = true;
146 MaybeStartTuning();
147
148 if (!tuner_started_before && tuner_started_) {
149 if (reorder_happened_before) {
150 QUIC_CODE_COUNT(quic_loss_tuner_started_after_first_reorder);
151 } else {
152 QUIC_CODE_COUNT(quic_loss_tuner_started_on_first_reorder);
153 }
154 }
155 }
156
SetReorderingShift(int reordering_shift)157 void UberLossAlgorithm::SetReorderingShift(int reordering_shift) {
158 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
159 general_loss_algorithms_[i].set_reordering_shift(reordering_shift);
160 }
161 }
162
SetReorderingThreshold(QuicPacketCount reordering_threshold)163 void UberLossAlgorithm::SetReorderingThreshold(
164 QuicPacketCount reordering_threshold) {
165 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
166 general_loss_algorithms_[i].set_reordering_threshold(reordering_threshold);
167 }
168 }
169
EnableAdaptiveReorderingThreshold()170 void UberLossAlgorithm::EnableAdaptiveReorderingThreshold() {
171 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
172 general_loss_algorithms_[i].set_use_adaptive_reordering_threshold(true);
173 }
174 }
175
DisableAdaptiveReorderingThreshold()176 void UberLossAlgorithm::DisableAdaptiveReorderingThreshold() {
177 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
178 general_loss_algorithms_[i].set_use_adaptive_reordering_threshold(false);
179 }
180 }
181
EnableAdaptiveTimeThreshold()182 void UberLossAlgorithm::EnableAdaptiveTimeThreshold() {
183 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
184 general_loss_algorithms_[i].enable_adaptive_time_threshold();
185 }
186 }
187
GetPacketReorderingThreshold() const188 QuicPacketCount UberLossAlgorithm::GetPacketReorderingThreshold() const {
189 return general_loss_algorithms_[APPLICATION_DATA].reordering_threshold();
190 }
191
GetPacketReorderingShift() const192 int UberLossAlgorithm::GetPacketReorderingShift() const {
193 return general_loss_algorithms_[APPLICATION_DATA].reordering_shift();
194 }
195
DisablePacketThresholdForRuntPackets()196 void UberLossAlgorithm::DisablePacketThresholdForRuntPackets() {
197 for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
198 general_loss_algorithms_[i].disable_packet_threshold_for_runt_packets();
199 }
200 }
201
ResetLossDetection(PacketNumberSpace space)202 void UberLossAlgorithm::ResetLossDetection(PacketNumberSpace space) {
203 if (space >= NUM_PACKET_NUMBER_SPACES) {
204 QUIC_BUG(quic_bug_10469_3) << "Invalid packet number space: " << space;
205 return;
206 }
207 general_loss_algorithms_[space].Reset();
208 }
209
210 } // namespace quic
211