Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify MaxAckDelay for TLP and RTO #991

Merged
merged 13 commits into from
Dec 5, 2017
73 changes: 41 additions & 32 deletions draft-ietf-quic-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,30 +300,24 @@ receiver.
The alarm duration, or Probe Timeout (PTO), is set based on the following
conditions:

* If there is exactly one unacknowledged packet, PTO SHOULD be scheduled for
max(2*SRTT, 1.5*SRTT+kDelayedAckTimeout)

* If there are more than one unacknowledged packets, PTO SHOULD be scheduled for
max(2*SRTT, 10ms).
* PTO SHOULD be scheduled for max(1.5*SRTT+MaxAckDelay, 10ms)

* If RTO ({{rto}}) is earlier, schedule a TLP alarm in its place. That is,
PTO SHOULD be scheduled for min(RTO, PTO).

kDelayedAckTimeout is the expected delayed ACK timer. When there is exactly one
unacknowledged packet, the alarm duration includes time for a delayed
acknowledgment to be received by including kDelayedAckTimeout.

The RECOMMENDED value for kDelayedAckTimeout is 25ms.

(TODO: Add negotiability of delayed ack timeout.)
MaxAckDelay is the maximum ack delay supplied in an incoming ACK frame.
MaxAckDelay excludes ack delays that aren't included in an RTT sample because
they're too large and excludes those which reference an ack-only packet.

A PTO value of at least 2*SRTT ensures that the ACK is overdue. Using a PTO of
exactly 1*SRTT may generate spurious probes, and 2*SRTT is simply the next
integral value of RTT.
QUIC diverges from TCP by calculating MaxAckDelay dynamically, instead of
assuming a constant delayed ack timeout for all connections. QUIC includes
this in all probe timeouts, because it assume the ack delay may come into play,
regardless of the number of packets outstanding. TCP's TLP assumes if at least
2 packets are outstanding, acks will not be delayed.

The values of 2 and 1.5 are based on
{{?LOSS-PROBE=I-D.dukkipati-tcpm-tcp-loss-probe}}, but implementations MAY
experiment with other constants.
A PTO value of at least 1.5*SRTT ensures that the ACK is overdue. The 1.5
is based on {{?LOSS-PROBE=I-D.dukkipati-tcpm-tcp-loss-probe}}, but
implementations MAY experiment with other constants.

To reduce latency, it is RECOMMENDED that the sender set and allow the TLP alarm
to fire twice before setting an RTO alarm. In other words, when the TLP alarm
Expand Down Expand Up @@ -360,7 +354,7 @@ Similar to TCP {{!RFC6298}}, the RTO period is set based on the following
conditions:

* When the final TLP packet is sent, the RTO period is set to max(SRTT +
4*RTTVAR, minRTO)
4*RTTVAR + MaxAckDelay, minRTO)

* When an RTO alarm fires, the RTO period is doubled.

Expand All @@ -372,9 +366,16 @@ one significantly increases resilience to packet drop in both directions, thus
reducing the probability of consecutive RTO events.

QUIC's RTO algorithm differs from TCP in that the firing of an RTO alarm is not
considered a strong enough signal of packet loss. An RTO alarm fires only when
there's a prolonged period of network silence, which could be caused by a change
in the underlying network RTT.
considered a strong enough signal of packet loss, so does not result in an
immediate change to congestion window or recovery state. An RTO alarm fires only
when there's a prolonged period of network silence, which could be caused by a
change in the underlying network RTT.

QUIC also diverges from TCP by including MaxAckDelay in the RTO period. QUIC is
able to explicitly model delay at the receiver via the ack delay field in the
ACK frame. Since QUIC corrects for this delay in its SRTT and RTTVAR
computations, it is necessary to add this delay explicitly in the TLP and RTO
computation.

When an acknowledgment is received for a packet sent on an RTO event, any
unacknowledged packets with lower packet numbers than those acknowledged MUST be
Expand Down Expand Up @@ -486,7 +487,7 @@ largest_sent_packet:
: The packet number of the most recently sent packet.

largest_acked_packet:
: The largest packet number acknowledged in an ack frame.
: The largest packet number acknowledged in an ACK frame.

latest_rtt:
: The most recent RTT measurement made when receiving an ack for
Expand All @@ -502,6 +503,11 @@ rttvar:
min_rtt:
: The minimum RTT seen in the connection, ignoring ack delay.

max_ack_delay:
: The maximum ack delay in an incoming ACK frame for this connection.
Excludes ack delays for ack only packets and those that create an
RTT sample less than min_rtt.

reordering_threshold:
: The largest delta between the largest acked
retransmittable packet and a packet containing retransmittable frames before
Expand All @@ -517,9 +523,9 @@ transmit or exceeding the reordering window in time.
sent_packets:
: An association of packet numbers to information about them, including a number
field indicating the packet number, a time field indicating the time a packet
was sent, and a bytes field indicating the packet's size. sent_packets is
ordered by packet number, and packets remain in sent_packets until
acknowledged or lost.
was sent, a boolean indicating whether the packet is ack only, and a bytes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ack only/ackable. I think this constraint needs to be more than just ack only packets.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, in a future PR.

field indicating the packet's size. sent_packets is ordered by packet
number, and packets remain in sent_packets until acknowledged or lost.

### Initialization

Expand All @@ -541,6 +547,7 @@ follows:
smoothed_rtt = 0
rttvar = 0
min_rtt = 0
max_ack_delay = 0
largest_sent_before_rto = 0
time_of_last_sent_packet = 0
largest_sent_packet = 0
Expand Down Expand Up @@ -569,6 +576,7 @@ Pseudocode for OnPacketSent follows:
largest_sent_packet = packet_number
sent_packets[packet_number].packet_number = packet_number
sent_packets[packet_number].time = now
sent_packets[packet_number].ack_only = is_ack_only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is_ackable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

if !is_ack_only:
OnPacketSentCC(sent_bytes)
sent_packets[packet_number].bytes = sent_bytes
Expand Down Expand Up @@ -602,6 +610,10 @@ Pseudocode for OnAckReceived and UpdateRtt follow:
// Adjust for ack delay if it's plausible.
if (latest_rtt - min_rtt > ack_delay):
latest_rtt -= ack_delay
// Only save into max ack delay if it's used
// for rtt calculation and is not ack only.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

if (!sent_packets[ack.largest_acked].ack_only)
max_ack_delay = max(max_ack_delay, ack_delay)
// Based on {{?RFC6298}}.
if (smoothed_rtt == 0):
smoothed_rtt = latest_rtt
Expand Down Expand Up @@ -702,11 +714,8 @@ Pseudocode for SetLossDetectionAlarm follows:
alarm_duration = loss_time - time_of_last_sent_packet
else if (tlp_count < kMaxTLPs):
// Tail Loss Probe
if (num_retransmittable_packets_outstanding == 1):
alarm_duration = 1.5 * smoothed_rtt + kDelayedAckTimeout
else:
alarm_duration = kMinTLPTimeout
alarm_duration = max(alarm_duration, 2 * smoothed_rtt)
alarm_duration = max(1.5 * smoothed_rtt + max_ack_delay,
kMinTLPTimeout)
else:
// RTO alarm
alarm_duration = smoothed_rtt + 4 * rttvar
Expand Down Expand Up @@ -906,7 +915,7 @@ bytes_in_flight:
: The sum of the size in bytes of all sent packets that contain at least
one retransmittable or PADDING frame, and have not been acked or
declared lost. The size does not include IP or UDP overhead.
Packets only containing ack frames do not count towards byte_in_flight
Packets only containing ACK frames do not count towards byte_in_flight
to ensure congestion control does not impede congestion feedback.

congestion_window:
Expand Down