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