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