1 /** @file
2 *
3 * A brief file description
4 *
5 * @section license License
6 *
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements. See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership. The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License. You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24 #include "QUICLossDetector.h"
25
26 #include "tscore/ink_assert.h"
27
28 #include "QUICConfig.h"
29 #include "QUICEvents.h"
30 #include "QUICDebugNames.h"
31 #include "QUICFrameGenerator.h"
32 #include "QUICPinger.h"
33 #include "QUICPadder.h"
34 #include "QUICPacketProtectionKeyInfo.h"
35
36 #define QUICLDDebug(fmt, ...) \
37 Debug("quic_loss_detector", "[%s] " fmt, this->_context.connection_info()->cids().data(), ##__VA_ARGS__)
38 #define QUICLDVDebug(fmt, ...) \
39 Debug("v_quic_loss_detector", "[%s] " fmt, this->_context.connection_info()->cids().data(), ##__VA_ARGS__)
40
QUICLossDetector(QUICContext & context,QUICCongestionController * cc,QUICRTTMeasure * rtt_measure,QUICPinger * pinger,QUICPadder * padder)41 QUICLossDetector::QUICLossDetector(QUICContext &context, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure,
42 QUICPinger *pinger, QUICPadder *padder)
43 : _rtt_measure(rtt_measure), _pinger(pinger), _padder(padder), _cc(cc), _context(context)
44 {
45 auto &ld_config = _context.ld_config();
46 this->mutex = new_ProxyMutex();
47 this->_loss_detection_mutex = new_ProxyMutex();
48
49 this->_k_packet_threshold = ld_config.packet_threshold();
50 this->_k_time_threshold = ld_config.time_threshold();
51
52 this->reset();
53
54 SET_HANDLER(&QUICLossDetector::event_handler);
55 }
56
~QUICLossDetector()57 QUICLossDetector::~QUICLossDetector()
58 {
59 if (this->_loss_detection_timer) {
60 this->_loss_detection_timer->cancel();
61 this->_loss_detection_timer = nullptr;
62 }
63
64 for (auto i = 0; i < QUIC_N_PACKET_SPACES; i++) {
65 this->_sent_packets[i].clear();
66 }
67 }
68
69 int
event_handler(int event,Event * edata)70 QUICLossDetector::event_handler(int event, Event *edata)
71 {
72 switch (event) {
73 case EVENT_INTERVAL: {
74 if (this->_loss_detection_alarm_at <= Thread::get_hrtime()) {
75 this->_loss_detection_alarm_at = 0;
76 this->_on_loss_detection_timeout();
77 }
78 break;
79 }
80 case QUIC_EVENT_LD_SHUTDOWN: {
81 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
82 QUICLDDebug("Shutdown");
83
84 if (this->_loss_detection_timer) {
85 this->_loss_detection_timer->cancel();
86 this->_loss_detection_timer = nullptr;
87 }
88 break;
89 }
90 default:
91 break;
92 }
93 return EVENT_CONT;
94 }
95
96 std::vector<QUICFrameType>
interests()97 QUICLossDetector::interests()
98 {
99 return {QUICFrameType::ACK};
100 }
101
102 QUICConnectionErrorUPtr
handle_frame(QUICEncryptionLevel level,const QUICFrame & frame)103 QUICLossDetector::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame)
104 {
105 QUICConnectionErrorUPtr error = nullptr;
106
107 switch (frame.type()) {
108 case QUICFrameType::ACK:
109 this->_on_ack_received(static_cast<const QUICAckFrame &>(frame), QUICTypeUtil::pn_space(level));
110 break;
111 default:
112 QUICLDDebug("Unexpected frame type: %02x", static_cast<unsigned int>(frame.type()));
113 ink_assert(false);
114 break;
115 }
116
117 return error;
118 }
119
120 QUICPacketNumber
largest_acked_packet_number(QUICPacketNumberSpace pn_space) const121 QUICLossDetector::largest_acked_packet_number(QUICPacketNumberSpace pn_space) const
122 {
123 int index = static_cast<int>(pn_space);
124 return this->_largest_acked_packet[index];
125 }
126
127 void
on_packet_sent(QUICSentPacketInfoUPtr packet_info,bool in_flight)128 QUICLossDetector::on_packet_sent(QUICSentPacketInfoUPtr packet_info, bool in_flight)
129 {
130 // ADDITIONAL CODE
131 if (packet_info->type == QUICPacketType::VERSION_NEGOTIATION) {
132 return;
133 }
134 // END OF ADDITIONAL CODE
135
136 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
137
138 QUICPacketNumber packet_number = packet_info->packet_number;
139 bool ack_eliciting = packet_info->ack_eliciting;
140 ink_hrtime now = packet_info->time_sent;
141 size_t sent_bytes = packet_info->sent_bytes;
142 QUICPacketNumberSpace pn_space = packet_info->pn_space;
143
144 QUICLDVDebug("%s packet sent : %" PRIu64 " bytes: %lu ack_eliciting: %d", QUICDebugNames::pn_space(packet_info->pn_space),
145 packet_number, sent_bytes, ack_eliciting);
146
147 this->_add_to_sent_packet_list(packet_number, std::move(packet_info));
148
149 if (in_flight) {
150 if (ack_eliciting) {
151 this->_time_of_last_ack_eliciting_packet[static_cast<int>(pn_space)] = now;
152 }
153 this->_cc->on_packet_sent(sent_bytes);
154 this->_set_loss_detection_timer();
155 }
156 }
157
158 void
on_datagram_received()159 QUICLossDetector::on_datagram_received()
160 {
161 if (this->_context.connection_info()->is_at_anti_amplification_limit()) {
162 this->_set_loss_detection_timer();
163 }
164 }
165
166 void
on_packet_number_space_discarded(QUICPacketNumberSpace pn_space)167 QUICLossDetector::on_packet_number_space_discarded(QUICPacketNumberSpace pn_space)
168 {
169 ink_assert(pn_space != QUICPacketNumberSpace::APPLICATION_DATA);
170 size_t bytes_in_flight = 0;
171 for (auto it = this->_sent_packets[static_cast<int>(pn_space)].begin();
172 it != this->_sent_packets[static_cast<int>(pn_space)].end();) {
173 auto ret = this->_remove_from_sent_packet_list(it, pn_space);
174 auto &pi = ret.first;
175 if (pi->in_flight) {
176 bytes_in_flight += pi->sent_bytes;
177 }
178 it = ret.second;
179 }
180 this->_cc->on_packet_number_space_discarded(bytes_in_flight);
181 // Reset the loss detection and PTO timer
182 this->_time_of_last_ack_eliciting_packet[static_cast<int>(pn_space)] = 0;
183 this->_loss_time[static_cast<int>(pn_space)] = 0;
184 this->_rtt_measure->set_pto_count(0);
185 this->_set_loss_detection_timer();
186 QUICLDDebug("[%s] Packets have been discarded because keys for the space are discarded", QUICDebugNames::pn_space(pn_space));
187 }
188
189 void
reset()190 QUICLossDetector::reset()
191 {
192 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
193
194 // A.4. Initialization
195 if (this->_loss_detection_timer) {
196 this->_loss_detection_timer->cancel();
197 this->_loss_detection_timer = nullptr;
198 }
199 this->_rtt_measure->reset();
200 for (auto i = 0; i < QUIC_N_PACKET_SPACES; i++) {
201 this->_largest_acked_packet[i] = UINT64_MAX;
202 this->_time_of_last_ack_eliciting_packet[i] = 0;
203 this->_loss_time[i] = 0;
204 this->_sent_packets[i].clear();
205 // ADDITIONAL CODE
206 this->_num_packets_in_flight[i] = 0;
207 // END OF ADDITIONAL CODE
208 }
209
210 // ADDITIONAL CODE
211 this->_ack_eliciting_outstanding = 0;
212 // END OF ADDITIONAL CODE
213 }
214
215 void
update_ack_delay_exponent(uint8_t ack_delay_exponent)216 QUICLossDetector::update_ack_delay_exponent(uint8_t ack_delay_exponent)
217 {
218 this->_ack_delay_exponent = ack_delay_exponent;
219 }
220
221 bool
_include_ack_eliciting(const std::vector<QUICSentPacketInfoUPtr> & acked_packets) const222 QUICLossDetector::_include_ack_eliciting(const std::vector<QUICSentPacketInfoUPtr> &acked_packets) const
223 {
224 // Find out ack_elicting packet.
225 // FIXME: this loop is the same as _on_ack_received's loop it would better
226 // to combine it.
227 for (const auto &packet : acked_packets) {
228 if (packet->ack_eliciting) {
229 return true;
230 }
231 }
232
233 return false;
234 }
235
236 void
_on_ack_received(const QUICAckFrame & ack_frame,QUICPacketNumberSpace pn_space)237 QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space)
238 {
239 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
240
241 int index = static_cast<int>(pn_space);
242 if (this->_largest_acked_packet[index] == UINT64_MAX) {
243 this->_largest_acked_packet[index] = ack_frame.largest_acknowledged();
244 } else {
245 this->_largest_acked_packet[index] = std::max(this->_largest_acked_packet[index], ack_frame.largest_acknowledged());
246 }
247
248 auto newly_acked_packets = this->_detect_and_remove_acked_packets(ack_frame, pn_space);
249 if (newly_acked_packets.empty()) {
250 return;
251 }
252
253 // If the largest acknowledged is newly acked and
254 // ack-eliciting, update the RTT.
255 const auto &largest_acked = newly_acked_packets[0];
256 if (largest_acked->packet_number == ack_frame.largest_acknowledged() && this->_include_ack_eliciting(newly_acked_packets)) {
257 ink_hrtime latest_rtt = Thread::get_hrtime() - largest_acked->time_sent;
258 // _latest_rtt is nanosecond but ack_frame.ack_delay is microsecond and scaled
259 ink_hrtime ack_delay = 0;
260 if (pn_space == QUICPacketNumberSpace::APPLICATION_DATA) {
261 ack_delay = HRTIME_USECONDS(ack_frame.ack_delay() << this->_ack_delay_exponent);
262 }
263 this->_rtt_measure->update_rtt(latest_rtt, ack_delay);
264 }
265
266 // if (ACK frame contains ECN information):
267 // ProcessECN(ack)
268 if (ack_frame.ecn_section() != nullptr) {
269 this->_cc->process_ecn(ack_frame, pn_space, largest_acked->time_sent);
270 }
271
272 // ADDITIONAL CODE
273 // Find all newly acked packets.
274 for (const auto &info : newly_acked_packets) {
275 this->_on_packet_acked(*info);
276 }
277 // END OF ADDITIONAL CODE
278
279 auto lost_packets = this->_detect_and_remove_lost_packets(pn_space);
280 if (!lost_packets.empty()) {
281 this->_cc->on_packets_lost(lost_packets);
282 }
283 this->_cc->on_packets_acked(newly_acked_packets);
284
285 QUICLDVDebug("[%s] Newly acked:%lu Lost:%lu Unacked packets:%lu (%u ack eliciting)", QUICDebugNames::pn_space(pn_space),
286 newly_acked_packets.size(), lost_packets.size(), this->_sent_packets[index].size(),
287 this->_ack_eliciting_outstanding.load());
288
289 if (this->_peer_completed_address_validation()) {
290 this->_rtt_measure->set_pto_count(0);
291 }
292 this->_set_loss_detection_timer();
293 }
294
295 void
_on_packet_acked(const QUICSentPacketInfo & acked_packet)296 QUICLossDetector::_on_packet_acked(const QUICSentPacketInfo &acked_packet)
297 {
298 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
299 QUICLDVDebug("[%s] Packet number %" PRIu64 " has been acked", QUICDebugNames::pn_space(acked_packet.pn_space),
300 acked_packet.packet_number);
301
302 for (const QUICSentPacketInfo::FrameInfo &frame_info : acked_packet.frames) {
303 auto reactor = frame_info.generated_by();
304 if (reactor == nullptr) {
305 continue;
306 }
307
308 reactor->on_frame_acked(frame_info.id());
309 }
310 }
311
312 ink_hrtime
_get_loss_time_and_space(QUICPacketNumberSpace & pn_space)313 QUICLossDetector::_get_loss_time_and_space(QUICPacketNumberSpace &pn_space)
314 {
315 ink_hrtime time = this->_loss_time[static_cast<int>(QUICPacketNumberSpace::INITIAL)];
316 pn_space = QUICPacketNumberSpace::INITIAL;
317 for (auto i = 1; i < QUIC_N_PACKET_SPACES; i++) {
318 if (time == 0 || this->_loss_time[i] < time) {
319 time = this->_loss_time[i];
320 pn_space = static_cast<QUICPacketNumberSpace>(i);
321 }
322 }
323
324 return time;
325 }
326
327 ink_hrtime
_get_pto_time_and_space(QUICPacketNumberSpace & space)328 QUICLossDetector::_get_pto_time_and_space(QUICPacketNumberSpace &space)
329 {
330 ink_hrtime duration =
331 (this->_rtt_measure->smoothed_rtt() + std::max(4 * this->_rtt_measure->rttvar(), this->_rtt_measure->k_granularity())) *
332 (1 << this->_rtt_measure->pto_count());
333
334 // Arm PTO from now when there are no inflight packets.
335 if (this->_num_packets_in_flight[static_cast<int>(QUICPacketNumberSpace::INITIAL)].load() == 0 &&
336 this->_num_packets_in_flight[static_cast<int>(QUICPacketNumberSpace::HANDSHAKE)].load() == 0 &&
337 this->_num_packets_in_flight[static_cast<int>(QUICPacketNumberSpace::APPLICATION_DATA)].load() == 0) {
338 ink_assert(!this->_peer_completed_address_validation());
339 if (this->_context.connection_info()->has_keys_for(QUICPacketNumberSpace::HANDSHAKE)) {
340 space = QUICPacketNumberSpace::HANDSHAKE;
341 return Thread::get_hrtime() + duration;
342 } else {
343 space = QUICPacketNumberSpace::INITIAL;
344 return Thread::get_hrtime() + duration;
345 }
346 }
347 ink_hrtime pto_timeout = INT64_MAX;
348 QUICPacketNumberSpace pto_space = QUICPacketNumberSpace::INITIAL;
349 for (int i = 0; i < QUIC_N_PACKET_SPACES; ++i) {
350 if (this->_num_packets_in_flight[i].load() == 0) {
351 continue;
352 }
353 if (i == static_cast<int>(QUICPacketNumberSpace::APPLICATION_DATA)) {
354 // Skip ApplicationData until handshake complete.
355 if (!this->_context.connection_info()->is_address_validation_completed()) {
356 space = pto_space;
357 return pto_timeout;
358 }
359 // Include max_ack_delay and backoff for ApplicationData.
360 // FIXME should be set by transport parameters
361 duration += this->_rtt_measure->max_ack_delay() * (1 << this->_rtt_measure->pto_count());
362 }
363
364 ink_hrtime t = this->_time_of_last_ack_eliciting_packet[i] + duration;
365 if (t < pto_timeout) {
366 pto_timeout = t;
367 pto_space = QUICPacketNumberSpace(i);
368 }
369 }
370 space = pto_space;
371 return pto_timeout;
372 }
373
374 bool
_peer_completed_address_validation() const375 QUICLossDetector::_peer_completed_address_validation() const
376 {
377 return this->_context.connection_info()->is_address_validation_completed();
378 }
379
380 void
_set_loss_detection_timer()381 QUICLossDetector::_set_loss_detection_timer()
382 {
383 std::function<void(ink_hrtime)> update_timer = [this](ink_hrtime time) {
384 this->_loss_detection_alarm_at = time;
385 if (!this->_loss_detection_timer) {
386 this->_loss_detection_timer = eventProcessor.schedule_every(this, HRTIME_MSECONDS(25));
387 }
388 };
389
390 std::function<void(void)> cancel_timer = [this]() {
391 this->_loss_detection_alarm_at = 0;
392 this->_loss_detection_timer->cancel();
393 this->_loss_detection_timer = nullptr;
394 };
395
396 QUICPacketNumberSpace pn_space;
397 ink_hrtime earliest_loss_time = this->_get_loss_time_and_space(pn_space);
398 if (earliest_loss_time != 0) {
399 update_timer(earliest_loss_time);
400 QUICLDDebug("[%s] time threshold loss detection timer: %" PRId64 "ms", QUICDebugNames::pn_space(pn_space),
401 (this->_loss_detection_alarm_at - Thread::get_hrtime()) / HRTIME_MSECOND);
402 return;
403 }
404
405 if (this->_context.connection_info()->is_at_anti_amplification_limit()) {
406 if (this->_loss_detection_timer) {
407 cancel_timer();
408 QUICLDDebug("Loss detection alarm has been unset because of anti-amplification limit");
409 return;
410 }
411 }
412
413 // Don't arm the alarm if there are no packets with retransmittable data in flight.
414 if (this->_ack_eliciting_outstanding == 0 && this->_peer_completed_address_validation()) {
415 if (this->_loss_detection_timer) {
416 cancel_timer();
417 QUICLDDebug("Loss detection alarm has been unset because of no ack eliciting packets outstanding");
418 }
419 return;
420 }
421
422 // PTO Duration
423 ink_hrtime timeout = this->_get_pto_time_and_space(pn_space);
424 update_timer(timeout);
425 QUICLDVDebug("[%s] PTO timeout has been set: %" PRId64 "ms", QUICDebugNames::pn_space(pn_space),
426 (timeout - this->_time_of_last_ack_eliciting_packet[static_cast<int>(pn_space)]) / HRTIME_MSECOND);
427 }
428
429 void
_on_loss_detection_timeout()430 QUICLossDetector::_on_loss_detection_timeout()
431 {
432 QUICPacketNumberSpace pn_space;
433 ink_hrtime earliest_loss_time = this->_get_loss_time_and_space(pn_space);
434 if (earliest_loss_time != 0) {
435 // Time threshold loss Detection
436 auto lost_packets = this->_detect_and_remove_lost_packets(pn_space);
437 ink_assert(!lost_packets.empty());
438 this->_cc->on_packets_lost(lost_packets);
439 this->_set_loss_detection_timer();
440 return;
441 }
442
443 if (this->_cc->bytes_in_flight() > 0) {
444 // PTO. Send new data if available, else retransmit old data.
445 // If neither is available, send a single PING frame.
446 QUICPacketNumberSpace pns;
447 this->_get_pto_time_and_space(pns);
448 this->_send_one_or_two_ack_eliciting_packet(pns);
449 } else {
450 // This assertion is on draft-29 but not correct
451 // Keep it as a comment for now to not add it back
452 // ink_assert(this->_is_client_without_one_rtt_key());
453
454 // Client sends an anti-deadlock packet: Initial is padded
455 // to earn more anti-amplification credit,
456 // a Handshake packet proves address ownership.
457 if (this->_context.key_info()->is_encryption_key_available(QUICKeyPhase::HANDSHAKE)) {
458 this->_send_one_ack_eliciting_handshake_packet();
459 } else {
460 this->_send_one_ack_eliciting_padded_initial_packet();
461 }
462 }
463
464 this->_rtt_measure->set_pto_count(this->_rtt_measure->pto_count() + 1);
465 this->_set_loss_detection_timer();
466
467 QUICLDDebug("[%s] Unacked packets %lu (ack_eliciting %u)", QUICDebugNames::pn_space(pn_space),
468 this->_sent_packets[static_cast<int>(pn_space)].size(), this->_ack_eliciting_outstanding.load());
469
470 if (is_debug_tag_set("v_quic_loss_detector")) {
471 for (auto i = 0; i < 3; i++) {
472 for (auto &unacked : this->_sent_packets[i]) {
473 QUICLDVDebug("[%s] #%" PRIu64 " ack_eliciting=%i size=%zu %u",
474 QUICDebugNames::pn_space(static_cast<QUICPacketNumberSpace>(i)), unacked.first, unacked.second->ack_eliciting,
475 unacked.second->sent_bytes, this->_ack_eliciting_outstanding.load());
476 }
477 }
478 }
479 }
480
481 std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>
_detect_and_remove_lost_packets(QUICPacketNumberSpace pn_space)482 QUICLossDetector::_detect_and_remove_lost_packets(QUICPacketNumberSpace pn_space)
483 {
484 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
485 ink_assert(this->_largest_acked_packet[static_cast<int>(pn_space)] != UINT64_MAX);
486
487 this->_loss_time[static_cast<int>(pn_space)] = 0;
488 std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> lost_packets;
489 ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_rtt_measure->latest_rtt(), this->_rtt_measure->smoothed_rtt());
490
491 // Minimum time of kGranularity before packets are deemed lost.
492 loss_delay = std::max(loss_delay, this->_rtt_measure->k_granularity());
493
494 // Packets sent before this time are deemed lost.
495 ink_hrtime lost_send_time = Thread::get_hrtime() - loss_delay;
496
497 // Packets with packet numbers before this are deemed lost.
498 // QUICPacketNumber lost_pn = this->_largest_acked_packet[static_cast<int>(pn_space)] - this->_k_packet_threshold;
499
500 for (auto it = this->_sent_packets[static_cast<int>(pn_space)].begin();
501 it != this->_sent_packets[static_cast<int>(pn_space)].end();) {
502 if (it->first > this->_largest_acked_packet[static_cast<int>(pn_space)]) {
503 // the spec uses continue but we can break here because the _sent_packets is sorted by packet_number.
504 break;
505 }
506
507 auto &unacked = it->second;
508
509 // Mark packet as lost, or set time when it should be marked.
510 if (unacked->time_sent <= lost_send_time ||
511 this->_largest_acked_packet[static_cast<int>(pn_space)] >= unacked->packet_number + this->_k_packet_threshold) {
512 if (unacked->time_sent <= lost_send_time) {
513 QUICLDDebug("[%s] Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%" PRId64
514 ", fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")",
515 QUICDebugNames::pn_space(pn_space), it->first, unacked->time_sent, lost_send_time, this->_k_time_threshold,
516 this->_rtt_measure->latest_rtt(), this->_rtt_measure->smoothed_rtt());
517 } else {
518 QUICLDDebug("[%s] Lost: packet delta is too large (#%" PRId64 " largest=%" PRId64 " threshold=%" PRId32 ")",
519 QUICDebugNames::pn_space(pn_space), it->first, this->_largest_acked_packet[static_cast<int>(pn_space)],
520 this->_k_packet_threshold);
521 }
522
523 auto ret = this->_remove_from_sent_packet_list(it, pn_space);
524 auto pi = std::move(ret.first);
525 it = ret.second;
526 if (pi->in_flight) {
527 this->_context.trigger(QUICContext::CallbackEvent::PACKET_LOST, *pi);
528 lost_packets.emplace(pi->packet_number, std::move(pi));
529 }
530
531 } else {
532 if (this->_loss_time[static_cast<int>(pn_space)] == 0) {
533 this->_loss_time[static_cast<int>(pn_space)] = unacked->time_sent + loss_delay;
534 } else {
535 this->_loss_time[static_cast<int>(pn_space)] =
536 std::min(this->_loss_time[static_cast<int>(pn_space)], unacked->time_sent + loss_delay);
537 }
538 ++it;
539 }
540 }
541
542 // -- ADDITIONAL CODE --
543 // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send
544 // them somewhere.
545 // I couldn't find the place so just send them here for now.
546 if (!lost_packets.empty()) {
547 for (const auto &lost_packet : lost_packets) {
548 this->_retransmit_lost_packet(*lost_packet.second);
549 }
550 }
551 // -- END OF ADDITIONAL CODE --
552
553 return lost_packets;
554 }
555
556 // ===== Functions below are used on the spec but there're no pseudo code =====
557
558 void
_send_packet(QUICEncryptionLevel level,bool padded)559 QUICLossDetector::_send_packet(QUICEncryptionLevel level, bool padded)
560 {
561 if (padded) {
562 this->_padder->request(level);
563 } else {
564 this->_pinger->request(level);
565 }
566 this->_cc->add_extra_credit();
567 }
568
569 void
_send_one_or_two_ack_eliciting_packet(QUICPacketNumberSpace pn_space)570 QUICLossDetector::_send_one_or_two_ack_eliciting_packet(QUICPacketNumberSpace pn_space)
571 {
572 this->_send_packet(QUICEncryptionLevel::ONE_RTT);
573 this->_send_packet(QUICEncryptionLevel::ONE_RTT);
574 ink_assert(this->_pinger->count(QUICEncryptionLevel::ONE_RTT) >= 2);
575 QUICLDDebug("[%s] send ping frame %" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::ONE_RTT),
576 this->_pinger->count(QUICEncryptionLevel::ONE_RTT));
577 }
578
579 void
_send_one_ack_eliciting_handshake_packet()580 QUICLossDetector::_send_one_ack_eliciting_handshake_packet()
581 {
582 this->_send_packet(QUICEncryptionLevel::HANDSHAKE);
583 QUICLDDebug("[%s] send handshake packet: ping count=%" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::HANDSHAKE),
584 this->_pinger->count(QUICEncryptionLevel::HANDSHAKE));
585 }
586
587 void
_send_one_ack_eliciting_padded_initial_packet()588 QUICLossDetector::_send_one_ack_eliciting_padded_initial_packet()
589 {
590 this->_send_packet(QUICEncryptionLevel::INITIAL, true);
591 QUICLDDebug("[%s] send PADDING frame: ping count=%" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::INITIAL),
592 this->_pinger->count(QUICEncryptionLevel::INITIAL));
593 }
594
595 // ===== Functions below are helper functions =====
596
597 void
_retransmit_lost_packet(const QUICSentPacketInfo & packet_info)598 QUICLossDetector::_retransmit_lost_packet(const QUICSentPacketInfo &packet_info)
599 {
600 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
601
602 QUICLDDebug("Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet_info.type), packet_info.packet_number);
603 for (const QUICSentPacketInfo::FrameInfo &frame_info : packet_info.frames) {
604 auto reactor = frame_info.generated_by();
605 if (reactor == nullptr) {
606 continue;
607 }
608
609 reactor->on_frame_lost(frame_info.id());
610 }
611 }
612
613 std::vector<QUICSentPacketInfoUPtr>
_detect_and_remove_acked_packets(const QUICAckFrame & ack_frame,QUICPacketNumberSpace pn_space)614 QUICLossDetector::_detect_and_remove_acked_packets(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space)
615 {
616 std::vector<QUICSentPacketInfoUPtr> packets;
617 std::set<QUICAckFrame::PacketNumberRange> numbers;
618 int index = static_cast<int>(pn_space);
619
620 QUICPacketNumber x = ack_frame.largest_acknowledged();
621 numbers.insert({x, static_cast<uint64_t>(x) - ack_frame.ack_block_section()->first_ack_block()});
622 x -= ack_frame.ack_block_section()->first_ack_block() + 1;
623 for (auto &&block : *(ack_frame.ack_block_section())) {
624 x -= block.gap() + 1;
625 numbers.insert({x, static_cast<uint64_t>(x) - block.length()});
626 x -= block.length() + 1;
627 }
628
629 for (auto &&range : numbers) {
630 for (auto ite = this->_sent_packets[index].begin(); ite != this->_sent_packets[index].end();) {
631 if (range.contains(ite->first)) {
632 auto ret = this->_remove_from_sent_packet_list(ite, pn_space);
633 packets.push_back(std::move(ret.first));
634 ite = ret.second;
635 } else {
636 ++ite;
637 }
638 }
639 }
640
641 return packets;
642 }
643
644 void
_add_to_sent_packet_list(QUICPacketNumber packet_number,QUICSentPacketInfoUPtr packet_info)645 QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, QUICSentPacketInfoUPtr packet_info)
646 {
647 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
648
649 // Add to the list
650 int index = static_cast<int>(packet_info->pn_space);
651 this->_sent_packets[index].insert(std::pair<QUICPacketNumber, QUICSentPacketInfoUPtr>(packet_number, std::move(packet_info)));
652
653 // Increment counters
654 auto ite = this->_sent_packets[index].find(packet_number);
655 if (ite != this->_sent_packets[index].end()) {
656 if (ite->second->ack_eliciting) {
657 ++this->_ack_eliciting_outstanding;
658 ink_assert(this->_ack_eliciting_outstanding.load() > 0);
659 }
660 if (ite->second->in_flight) {
661 ++this->_num_packets_in_flight[index];
662 }
663 }
664 }
665
666 std::pair<QUICSentPacketInfoUPtr, std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator>
_remove_from_sent_packet_list(std::map<QUICPacketNumber,QUICSentPacketInfoUPtr>::iterator it,QUICPacketNumberSpace pn_space)667 QUICLossDetector::_remove_from_sent_packet_list(std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator it,
668 QUICPacketNumberSpace pn_space)
669 {
670 SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
671
672 this->_decrement_counters(it, pn_space);
673 auto pi = std::move(it->second);
674 return {std::move(pi), this->_sent_packets[static_cast<int>(pn_space)].erase(it)};
675 }
676
677 void
_decrement_counters(std::map<QUICPacketNumber,QUICSentPacketInfoUPtr>::iterator it,QUICPacketNumberSpace pn_space)678 QUICLossDetector::_decrement_counters(std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator it,
679 QUICPacketNumberSpace pn_space)
680 {
681 if (it != this->_sent_packets[static_cast<int>(pn_space)].end()) {
682 if (it->second->ack_eliciting) {
683 ink_assert(this->_ack_eliciting_outstanding.load() > 0);
684 --this->_ack_eliciting_outstanding;
685 }
686 --this->_num_packets_in_flight[static_cast<int>(pn_space)];
687 }
688 }
689
690 bool
_is_client_without_one_rtt_key() const691 QUICLossDetector::_is_client_without_one_rtt_key() const
692 {
693 return this->_context.connection_info()->direction() == NET_VCONNECTION_OUT &&
694 !((this->_context.key_info()->is_encryption_key_available(QUICKeyPhase::PHASE_1) &&
695 this->_context.key_info()->is_decryption_key_available(QUICKeyPhase::PHASE_1)) ||
696 (this->_context.key_info()->is_encryption_key_available(QUICKeyPhase::PHASE_0) &&
697 this->_context.key_info()->is_decryption_key_available(QUICKeyPhase::PHASE_0)));
698 }
699
700 //
701 // QUICRTTMeasure
702 //
QUICRTTMeasure(const QUICLDConfig & ld_config)703 QUICRTTMeasure::QUICRTTMeasure(const QUICLDConfig &ld_config)
704 : _k_granularity(ld_config.granularity()), _k_initial_rtt(ld_config.initial_rtt())
705 {
706 }
707
708 void
init(const QUICLDConfig & ld_config)709 QUICRTTMeasure::init(const QUICLDConfig &ld_config)
710 {
711 this->_k_granularity = ld_config.granularity();
712 this->_k_initial_rtt = ld_config.initial_rtt();
713 }
714
715 ink_hrtime
smoothed_rtt() const716 QUICRTTMeasure::smoothed_rtt() const
717 {
718 return this->_smoothed_rtt;
719 }
720
721 void
update_rtt(ink_hrtime latest_rtt,ink_hrtime ack_delay)722 QUICRTTMeasure::update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay)
723 {
724 this->_latest_rtt = latest_rtt;
725
726 if (this->_is_first_sample) {
727 this->_min_rtt = this->_latest_rtt;
728 this->_smoothed_rtt = this->_latest_rtt;
729 this->_rttvar = this->_latest_rtt / 2;
730 this->_is_first_sample = false;
731 return;
732 }
733
734 // min_rtt ignores ack delay.
735 this->_min_rtt = std::min(this->_min_rtt, latest_rtt);
736 // Limit ack_delay by max_ack_delay
737 ack_delay = std::min(ack_delay, this->_max_ack_delay);
738 // Adjust for ack delay if it's plausible.
739 auto adjusted_rtt = this->_latest_rtt;
740 if (adjusted_rtt > this->_min_rtt + ack_delay) {
741 adjusted_rtt -= ack_delay;
742 }
743
744 // Based on {{RFC6298}}.
745 this->_rttvar = 3.0 / 4.0 * this->_rttvar + 1.0 / 4.0 * ABS(this->_smoothed_rtt - adjusted_rtt);
746 this->_smoothed_rtt = 7.0 / 8.0 * this->_smoothed_rtt + 1.0 / 8.0 * adjusted_rtt;
747 }
748
749 ink_hrtime
current_pto_period() const750 QUICRTTMeasure::current_pto_period() const
751 {
752 // PTO timeout
753 ink_hrtime alarm_duration;
754 alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay;
755 alarm_duration = std::max(alarm_duration, this->_k_granularity);
756 alarm_duration = alarm_duration * (1 << this->_pto_count);
757 return alarm_duration;
758 }
759
760 ink_hrtime
congestion_period(uint32_t threshold) const761 QUICRTTMeasure::congestion_period(uint32_t threshold) const
762 {
763 ink_hrtime pto = this->_smoothed_rtt + std::max(this->_rttvar * 4, this->_k_granularity);
764 return pto * threshold;
765 }
766
767 void
set_pto_count(uint32_t count)768 QUICRTTMeasure::set_pto_count(uint32_t count)
769 {
770 this->_pto_count = count;
771 }
772
773 void
set_max_ack_delay(ink_hrtime max_ack_delay)774 QUICRTTMeasure::set_max_ack_delay(ink_hrtime max_ack_delay)
775 {
776 this->_max_ack_delay = max_ack_delay;
777 }
778
779 ink_hrtime
rttvar() const780 QUICRTTMeasure::rttvar() const
781 {
782 return this->_rttvar;
783 }
784
785 ink_hrtime
latest_rtt() const786 QUICRTTMeasure::latest_rtt() const
787 {
788 return this->_latest_rtt;
789 }
790
791 uint32_t
pto_count() const792 QUICRTTMeasure::pto_count() const
793 {
794 return this->_pto_count;
795 }
796
797 ink_hrtime
max_ack_delay() const798 QUICRTTMeasure::max_ack_delay() const
799 {
800 return this->_max_ack_delay;
801 }
802
803 ink_hrtime
k_granularity() const804 QUICRTTMeasure::k_granularity() const
805 {
806 return this->_k_granularity;
807 }
808
809 void
reset()810 QUICRTTMeasure::reset()
811 {
812 // A.4. Initialization
813 this->_pto_count = 0;
814 this->_latest_rtt = 0;
815 this->_smoothed_rtt = this->_k_initial_rtt;
816 this->_rttvar = this->_k_initial_rtt / 2.0;
817 this->_min_rtt = 0;
818 }
819