Quic recovery
include quic_loss_recovery
function kInitialWindow : stream_pos
function kMinimumWindow : stream_pos
function kLossReductionFactor: stream_pos
function kPersistentCongestionThreshold : stream_pos
function max_datagram_size : stream_pos
function ecn_ce_counters(E:quic_packet_type) : stream_pos
function bytes_in_flight : stream_pos
function congestion_window : stream_pos
function congestion_recovery_start_time : microseconds
function ssthresh : stream_pos
after init {
max_datagram_size := 1200;
kLossReductionFactor := 2; # 1.5
kPersistentCongestionThreshold := 3;
kInitialWindow := 10 * max_datagram_size;
ssthresh := 0xFFFFFF; # TODO: set to infinity
congestion_window := kInitialWindow;
ecn_ce_counters(E) := 0;
}
action on_congestion_event(sent_time_of_last_loss:microseconds) = {
if ~ (sent_time_of_last_loss <= congestion_recovery_start_time) {
congestion_recovery_start_time := time_api.c_timer.now_micros;
ssthresh := congestion_window / kLossReductionFactor;
congestion_window := ssthresh;
if congestion_window < kMinimumWindow {
congestion_window := kMinimumWindow;
}
}
}
This is invoked from loss detection's OnAckReceived and is supplied with the newly acked_packets from sent_packets.In congestion avoidance, implementers that use an integer representation for congestion_window should be careful with division and can use the alternative approach suggested in Section 2.1 of [RFC3465].
action on_packets_acked(pn_space:quic_packet_type) = {
var idx : stream_pos := 0;
while idx < newly_acked_packets_end(pn_space) {
call on_packet_acked(newly_acked_packets(pn_space,idx));
idx := idx + 1;
}
}
action on_packet_acked(acked_packet:quic_packet) = {
if sent_packets_in_flight(acked_packet.ptype,acked_packet.seq_num) {
bytes_in_flight := bytes_in_flight - sent_packets_sent_bytes(acked_packet.ptype,acked_packet.seq_num);
Do not increase congestion window in recovery period.
if ~(sent_packets_time_sent(acked_packet.ptype,acked_packet.seq_num) <= congestion_recovery_start_time) {
if congestion_window < ssthresh {
congestion_window := congestion_window + sent_packets_sent_bytes(acked_packet.ptype,acked_packet.seq_num);
} else {
congestion_window := congestion_window + max_datagram_size * sent_packets_sent_bytes(acked_packet.ptype,acked_packet.seq_num) / congestion_window;
}
}
}
}
action on_packets_lost(pn_space:quic_packet_type) = {
var sent_time_of_last_loss : microseconds := 0;
var idx :stream_pos := 0;
while idx < lost_packets_end(pn_space) {
packets_to_retransmit(pn_space, packets_to_retransmit_end(pn_space)) := lost_packets(pn_space,idx).payload;
packets_to_retransmit_end(pn_space) := packets_to_retransmit_end(pn_space) + 1;
if sent_packets_in_flight(lost_packets(pn_space,idx).ptype,lost_packets(pn_space,idx).seq_num) {
bytes_in_flight := bytes_in_flight - sent_packets_sent_bytes(lost_packets(pn_space,idx).ptype,lost_packets(pn_space,idx).seq_num);
if sent_time_of_last_loss < sent_packets_time_sent(lost_packets(pn_space,idx).ptype,lost_packets(pn_space,idx).seq_num) {
sent_time_of_last_loss := sent_packets_time_sent(lost_packets(pn_space,idx).ptype,lost_packets(pn_space,idx).seq_num);
}
}
idx := idx + 1;
}
if sent_time_of_last_loss ~= 0 {
call on_congestion_event(sent_time_of_last_loss);
}
if first_rtt_sample ~= 0 { # call show_is_sleep_fake_timeout(is_not_sleeping);
pc_lost_end(pn_space) := 0;
idx : stream_pos := 0;
while idx < lost_packets_end(pn_space) {
if sent_packets_time_sent(lost_packets(pn_space,idx).ptype,lost_packets(pn_space,idx).seq_num) > first_rtt_sample {
pc_lost_end(pn_space) := pc_lost_end(pn_space) + 1;
}
idx := idx + 1;
}
if pc_lost_end(pn_space) >= kPersistentCongestionThreshold {
congestion_window := kMinimumWindow;
congestion_recovery_start_time := 0;
}
};
}
action remove_from_bytes_in_flight(pn_space:quic_packet_type) = {
var idx :stream_pos := 0;
while idx < sent_packets_end(pn_space) {
if sent_packets_in_flight(sent_packets(pn_space, idx).ptype, sent_packets(pn_space, idx).seq_num) {
bytes_in_flight := bytes_in_flight - sent_packets_sent_bytes(sent_packets(pn_space, idx).ptype, sent_packets(pn_space, idx).seq_num);
}
idx := idx + 1;
}
}