This is an automated email from the ASF dual-hosted git repository. masaori pushed a commit to branch quic-latest in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit f7473556c7cf541fff398d1b13197531fb65e715 Author: Masaori Koshiba <masa...@apache.org> AuthorDate: Wed Jun 20 14:50:50 2018 +0900 [draft-11] Follow pseudocode updates of draft-ietf-quic-recovery --- iocore/net/quic/QUICCongestionController.cc | 10 +- iocore/net/quic/QUICLossDetector.cc | 143 ++++++++++++++++++---------- iocore/net/quic/QUICLossDetector.h | 10 +- 3 files changed, 102 insertions(+), 61 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 70510a8..606449c 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -62,21 +62,21 @@ QUICCongestionController::_in_recovery(QUICPacketNumber packet_number) } void -QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) +QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) { // Remove from bytes_in_flight. - this->_bytes_in_flight -= acked_packet_size; - if (this->_in_recovery(acked_packet_number)) { + this->_bytes_in_flight -= acked_packet.bytes; + if (this->_in_recovery(acked_packet.packet_number)) { // Do not increase congestion window in recovery period. return; } if (this->_congestion_window < this->_ssthresh) { // Slow start. - this->_congestion_window += acked_packet_size; + this->_congestion_window += acked_packet.bytes; QUICCCDebug("slow start window chaged"); } else { // Congestion avoidance. - this->_congestion_window += this->_k_default_mss * acked_packet_size / this->_congestion_window; + this->_congestion_window += this->_k_default_mss * acked_packet.bytes / this->_congestion_window; QUICCCDebug("Congestion avoidance window changed"); } } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 327b253..d82dbe8 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -29,6 +29,7 @@ #include "QUICEvents.h" #define QUICLDDebug(fmt, ...) Debug("quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) +#define QUICLDVDebug(fmt, ...) Debug("v_quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc) @@ -175,17 +176,22 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_on this->_largest_sent_packet = packet_number; // FIXME Should we really keep actual packet object? - std::unique_ptr<PacketInfo> packet_info( - new PacketInfo({packet_number, now, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); - this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); - if (!is_ack_only) { + PacketInfoUPtr packet_info(new PacketInfo({packet_number, now, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); + if (is_handshake) { this->_time_of_last_sent_handshake_packet = now; } this->_time_of_last_sent_retransmittable_packet = now; this->_cc->on_packet_sent(sent_bytes); this->_set_loss_detection_alarm(); + } else { + // -- ADDITIONAL CODE -- + // To simplify code - setting sent_bytes only if the packet is not ack_only. + PacketInfoUPtr packet_info(new PacketInfo({packet_number, now, is_ack_only, is_handshake, 0, std::move(packet)})); + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); + // -- END OF ADDITIONAL CODE -- } } @@ -216,7 +222,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr<const QUICAckFrame> &ac auto tmp_ite = ite; tmp_ite++; if (range.contains(ite->first)) { - this->_on_packet_acked(ite->first, ite->second->bytes); + this->_on_packet_acked(*(ite->second)); } ite = tmp_ite; } @@ -259,21 +265,25 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICP } void -QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) +QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); - this->_cc->on_packet_acked(acked_packet_number, acked_packet_size); + + if (!acked_packet.ack_only) { + this->_cc->on_packet_acked(acked_packet); + } + // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. - if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { + if (this->_rto_count > 0 && acked_packet.packet_number > this->_largest_sent_before_rto) { this->_cc->on_retransmission_timeout_verified(); } this->_handshake_count = 0; this->_tlp_count = 0; this->_rto_count = 0; - this->_remove_from_sent_packet_list(acked_packet_number); + this->_remove_from_sent_packet_list(acked_packet.packet_number); } void @@ -282,14 +292,17 @@ QUICLossDetector::_set_loss_detection_alarm() ink_hrtime alarm_duration; // Don't arm the alarm if there are no packets with // retransmittable data in flight. - if (this->_retransmittable_outstanding == 0 && this->_loss_detection_alarm) { + if (this->_cc->bytes_in_flight() == 0 && this->_loss_detection_alarm) { this->_loss_detection_alarm_at = 0; this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; QUICLDDebug("Loss detection alarm has been unset"); return; + } else { + QUICLDDebug("bytes_in_flight=%" PRIu32, this->_cc->bytes_in_flight()); } + if (this->_handshake_outstanding) { // Handshake retransmission alarm. if (this->_smoothed_rtt == 0) { @@ -302,35 +315,41 @@ QUICLossDetector::_set_loss_detection_alarm() this->_loss_detection_alarm_at = this->_time_of_last_sent_handshake_packet + alarm_duration; QUICLDDebug("Handshake retransmission alarm will be set"); - } else if (this->_loss_time != 0) { - // Early retransmit timer or time loss detection. - alarm_duration = this->_loss_time - this->_time_of_last_sent_retransmittable_packet; - QUICLDDebug("Early retransmit timer or time loss detection will be set"); - } else if (this->_tlp_count < this->_k_max_tlps) { - // Tail Loss Probe - alarm_duration = std::max(static_cast<ink_hrtime>(1.5 * this->_smoothed_rtt + this->_max_ack_delay), this->_k_min_tlp_timeout); - QUICLDDebug("TLP alarm will be set"); + // -- ADDITIONAL CODE -- + // In psudocode returning here, but we don't do for scheduling _loss_detection_alarm event. + // -- END OF ADDITIONAL CODE -- } else { - // RTO alarm - alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; - alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); - alarm_duration = alarm_duration * (1 << this->_rto_count); - QUICLDDebug("RTO alarm will be set"); - } + if (this->_loss_time != 0) { + // Early retransmit timer or time loss detection. + alarm_duration = this->_loss_time - this->_time_of_last_sent_retransmittable_packet; + QUICLDDebug("Early retransmit timer or time loss detection will be set"); - // ADDITIONAL CODE - // alarm_curation can be negative value because _loss_time is updated in _detect_lost_packets() - // In that case, perhaps we should trigger the alarm immediately. - if (alarm_duration < 0) { - alarm_duration = 1; - } - // END OF ADDITONAL CODE + } else { + // RTO or TLP alarm + alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; + alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); + alarm_duration = alarm_duration * (1 << this->_rto_count); + + if (this->_tlp_count < this->_k_max_tlps) { + // Tail Loss Probe + ink_hrtime tlp_alarm_duration = + std::max(static_cast<ink_hrtime>(1.5 * this->_smoothed_rtt + this->_max_ack_delay), this->_k_min_tlp_timeout); + alarm_duration = std::min(tlp_alarm_duration, alarm_duration); + } + QUICLDDebug("RTO or TLP alarm will be set"); + } + + // -- ADDITIONAL CODE -- + // alarm_curation can be negative value because _loss_time is updated in _detect_lost_packets() + // In that case, perhaps we should trigger the alarm immediately. + if (alarm_duration < 0) { + alarm_duration = 1; + } + // -- END OF ADDITONAL CODE -- - if (this->_loss_detection_alarm_at) { - this->_loss_detection_alarm_at = std::min(this->_loss_detection_alarm_at, Thread::get_hrtime() + alarm_duration); - } else { this->_loss_detection_alarm_at = this->_time_of_last_sent_retransmittable_packet + alarm_duration; } + QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", alarm_duration / HRTIME_MSECOND); if (!this->_loss_detection_alarm) { @@ -343,7 +362,7 @@ QUICLossDetector::_on_loss_detection_alarm() { if (this->_handshake_outstanding) { // Handshake retransmission alarm. - this->_retransmit_handshake_packets(); + this->_retransmit_all_unacked_handshake_data(); this->_handshake_count++; } else if (this->_loss_time != 0) { // Early retransmit or Time Loss Detection @@ -363,8 +382,16 @@ QUICLossDetector::_on_loss_detection_alarm() this->_send_two_packets(); this->_rto_count++; } + QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + + if (is_debug_tag_set("v_quic_loss_detector")) { + for (auto &unacked : this->_sent_packets) { + QUICLDVDebug("#%" PRIu64 " is_handshake=%i is_ack_only=%i size=%zu", unacked.first, unacked.second->handshake, unacked.second->ack_only, unacked.second->bytes); + } + } + this->_set_loss_detection_alarm(); } @@ -389,17 +416,27 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num break; } ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; - uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; - if (time_since_sent > delay_until_lost) { - QUICLDDebug("Lost: time since sent is too long (PN=%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 - ", srtt=%" PRId64 ")", - unacked.first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, - this->_smoothed_rtt); - lost_packets.insert({unacked.first, unacked.second.get()}); - } else if (packet_delta > this->_reordering_threshold) { - QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", - unacked.first, largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); - lost_packets.insert({unacked.first, unacked.second.get()}); + uint64_t delta = largest_acked_packet_number - unacked.second->packet_number; + if (time_since_sent > delay_until_lost || delta > this->_reordering_threshold) { + if (time_since_sent > delay_until_lost) { + QUICLDDebug("Lost: time since sent is too long (PN=%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 + ", srtt=%" PRId64 ")", + unacked.first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, + this->_smoothed_rtt); + } else { + QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", + unacked.first, largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); + } + + if (!unacked.second->ack_only) { + lost_packets.insert({unacked.first, unacked.second.get()}); + } else { + // -- ADDITIONAL CODE -- + // We remove only "ack-only" packets for life time management of packets. + // Packets in lost_packets will be removed from sent_packet later. + this->_remove_from_sent_packet_list(unacked.first); + // -- END OF ADDITIONAL CODE -- + } } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; } @@ -409,14 +446,16 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // lets it decide whether to retransmit immediately. if (!lost_packets.empty()) { this->_cc->on_packets_lost(lost_packets); - for (auto lost_packet : lost_packets) { - // ADDITIONAL CODE + for (auto &lost_packet : lost_packets) { + // -- ADDITIONAL CODE -- // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send // them somewhere. // I couldn't find the place so just send them here for now. this->_retransmit_lost_packet(*lost_packet.second->packet); - // END OF ADDITIONAL CODE + // -- END OF ADDITIONAL CODE -- + // -- ADDITIONAL CODE -- this->_remove_from_sent_packet_list(lost_packet.first); + // -- END OF ADDITIONAL CODE -- } } } @@ -424,7 +463,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // ===== Functions below are used on the spec but there're no pseudo code ===== void -QUICLossDetector::_retransmit_handshake_packets() +QUICLossDetector::_retransmit_all_unacked_handshake_data() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); @@ -500,12 +539,12 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) } void -QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr<PacketInfo> packet_info) +QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, PacketInfoUPtr packet_info) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // Add to the list - this->_sent_packets.insert(std::pair<QUICPacketNumber, std::unique_ptr<PacketInfo>>(packet_number, std::move(packet_info))); + this->_sent_packets.insert(std::pair<QUICPacketNumber, PacketInfoUPtr>(packet_number, std::move(packet_info))); // Increment counters auto ite = this->_sent_packets.find(packet_number); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 023d135..3b2d7a1 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -49,6 +49,8 @@ struct PacketInfo { QUICPacketUPtr packet; }; +using PacketInfoUPtr = std::unique_ptr<PacketInfo>; + class QUICRTTProvider { public: @@ -61,7 +63,7 @@ public: QUICCongestionController(QUICConnectionInfoProvider *info); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); - void on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); + void on_packet_acked(const PacketInfo &acked_packet); virtual void on_packets_lost(std::map<QUICPacketNumber, PacketInfo *> &packets); void on_retransmission_timeout_verified(); bool check_credit() const; @@ -142,7 +144,7 @@ private: uint32_t _reordering_threshold = 0; double _time_reordering_fraction = 0.0; ink_hrtime _loss_time = 0; - std::map<QUICPacketNumber, std::unique_ptr<PacketInfo>> _sent_packets; + std::map<QUICPacketNumber, PacketInfoUPtr> _sent_packets; // These are not defined on the spec but expected to be count // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions. @@ -160,7 +162,7 @@ private: void _on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet); void _on_ack_received(const std::shared_ptr<const QUICAckFrame> &ack_frame); - void _on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); + void _on_packet_acked(const PacketInfo &acked_packet); void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked); void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); @@ -169,7 +171,7 @@ private: std::set<QUICAckFrame::PacketNumberRange> _determine_newly_acked_packets(const QUICAckFrame &ack_frame); - void _retransmit_handshake_packets(); + void _retransmit_all_unacked_handshake_data(); void _send_one_packet(); void _send_two_packets();