Subject: [quicwg/base-drafts] Include ack_delay when deciding with PN space to arm PTO for (#3666)

From: ianswett <[email-masked]>
Date: Mon, 18 May 2020 04:05:57 -0700

Updates the pseudocode to match the text.

Fixes #3564
You can view, comment on, or merge this pull request online at:

  https://github.com/quicwg/base-drafts/pull/3666

-- Commit Summary --

  * Include ack_delay when deciding with PN space to arm PTO for

-- File Changes --

    M draft-ietf-quic-recovery.md (31)

-- Patch Links --

https://github.com/quicwg/base-drafts/pull/3666.patch
https://github.com/quicwg/base-drafts/pull/3666.diff

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666

---

From: ianswett <[email-masked]>
Date: Mon, 18 May 2020 05:18:24 -0700

@ianswett pushed 1 commit.

5e8f35e65344718137dd5c85776cfd95baffdb69  Update draft-ietf-quic-recovery.md

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666/files/f2d81814258d21f2d3e8936a9d3bc8aabcc3430b..5e8f35e65344718137dd5c85776cfd95baffdb69

---

From: martinduke <[email-masked]>
Date: Mon, 18 May 2020 10:01:54 -0700

@martinduke requested changes on this pull request.

> -  space = Initial
-  for pn_space in [ Handshake, ApplicationData ]:
-    if (times[pn_space] != 0 &&
-        (time == 0 || times[pn_space] < time) &&
-        # Skip ApplicationData until handshake completion.
-        (pn_space != ApplicationData ||
-          IsHandshakeComplete()):
-      time = times[pn_space];
-      space = pn_space
+GetEarliestTimeAndSpace(times, ack_delay):
+  time, space = times[Initial], Initial
+  if (times[Handshake] != 0 &&
+      (time == 0 || times[Handshake] < time)):
+    time, space = times[Handshake], Handshake
+  # Skip ApplicationData until handshake completion.
+  if (pn_space == ApplicationData &&

I think we need to delete this line.

> @@ -1270,7 +1273,7 @@ PeerCompletedAddressValidation():
        has received HANDSHAKE_DONE
 
 SetLossDetectionTimer():
-  earliest_loss_time, _ = GetEarliestTimeAndSpace(loss_time)
+  earliest_loss_time, _ = GetEarliestTimeAndSpace(loss_time, 0)
   if (earliest_loss_time != 0):
     // Time threshold loss detection.

I confess to not really understanding this bit of code at all. If any packet has been sent in any PN space, we don't actually  go through the motions of setting the timer? Before we check for anti-amplification limit, etc?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#pullrequestreview-413750535

---

From: ianswett <[email-masked]>
Date: Mon, 18 May 2020 10:40:00 -0700

@ianswett commented on this pull request.

Done.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#discussion_r426791030

---

From: ianswett <[email-masked]>
Date: Mon, 18 May 2020 10:40:41 -0700

0c3f6fcf1867ac2d9740ba07f029e3fe47427419  Update draft-ietf-quic-recovery.md

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666/files/5e8f35e65344718137dd5c85776cfd95baffdb69..0c3f6fcf1867ac2d9740ba07f029e3fe47427419

---

From: ianswett <[email-masked]>
Date: Mon, 18 May 2020 10:45:08 -0700

SetLossDetectionTimer():

loss_time tracks packets which may need to be declared lost.   The GetEarliestTimeAndSpace method operates on loss_times and time_of_last_sent_ack_eliciting_packet.  There were two methods, but they were doing the same thing.  This Issue/PR makes them sharing a method a bit more awkward, but it seems ok overall.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#discussion_r426793692

---

From: martinduke <[email-masked]>
Date: Mon, 18 May 2020 11:26:03 -0700

@martinduke commented on this pull request.

 SetLossDetectionTimer():

Ah, I managed to miss that the argument is loss_time. My mistake.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#discussion_r426815304

---

From: martinduke <[email-masked]>
Date: Mon, 18 May 2020 11:31:52 -0700

@martinduke approved this pull request.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#pullrequestreview-413839964

---

From: Martin Thomson <[email-masked]>
Date: Mon, 18 May 2020 17:45:00 -0700

@martinthomson commented on this pull request.

One large comment.  Bottom line is that I don't think that this pseudocode is doing a great job of communicating here.  Also, this is a functional change to the outcome in more ways that the subject of the PR implies.

> +  // Calculate PTO duration, sent_time includes max_ack_delay.
+  timeout = smoothed_rtt + max(4 * rttvar, kGranularity)

Not that it was great before, but I think that this change obfuscates things.

I think that the inclusion of the max_ack_delay argument overloads GetEarliestTimeAndSpace in a way that just highlights how the dual purpose to which the function is applied is not appropriate.

We use this function for working out two things:
* when to declare something lost
* when the PTO timer should start 

The former is not affected by max_ack_delay.   The PTO calculation is, but this change adds max_ack_delay to the baseline rather than the PTO calculation itself.

For one, that's a fundamental change in logic for one (because PTO number 2 used to include 2*max_ack_delay and now it doesn't. Maybe that was a bug that this fixes, but that needs to be clear.

However, the main problem is the way that this code now communicates its intent.  If the intent is to start with a baseline (t_sent) and to add a PTO (RTT + 4*rttvar) that is then doubled each time, and only then compensate for ACK delay, you want to show your work, not hide it:

```
pto_timer = smoothed_rtt + max(4 * rttvar, kGranularity)
pto_timer *= 1 << pto_count
loss_detection_timer.update(sent_time + pto_timer + ?max_ack_delay)
```
Or is it, with maybe a fix for the packet number space issue...
```
pto_timer = smoothed_rtt + max(4 * rttvar, kGranularity) + ?max_ack_delay
pto_timer *= 1 << pto_count
loss_detection_timer.update(sent_time + pto_timer)
```

The trick is that the code that triggers SendOneOrTwoAckElicitingPackets() needs to follow the same logic.  But that too is too clever.  Basing that on the reference time (the time you sent the last packet) rather than the time that the timer is expected to pop is obtuse (even if it is correct as you currently formulate it).

Why not provide a CalculatePtoTime() function and use that?  This code doesn't need to be optimized, so you can calculate everything always.

```python
pto_time = { Initial: 0, Handshake: 0, ApplicationData: 0 };
for space in time_of_last_sent_ack_eliciting_packet:
    if time_of_last_sent_ack_eliciting_packet[space] == 0:
        continue;
    t = smoothed_rtt + max(4 * rttvar, kGranularity)
    t = t * (2 ^ pto_count)
    if space == ApplicationData: # or move this up as you need
        t += max_ack_delay
    pto_time[space] = time_of_last_sent_ack_eliciting_packet[space] + t
pto_time, pn_space = GetEarliestTimeAndSpace(pto_time)
```

This needs tweaking for the case where sent_time == 0, but that is just a case of factoring out the PTO interval calculation.  Note that you aren't adding max_ack_delay in that case, which is another difference.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#pullrequestreview-414027013

---

From: ianswett <[email-masked]>
Date: Wed, 20 May 2020 09:11:55 -0700

Thanks for your comments, I created #3681 to fix #3564 and another one(#3674) I noticed while looking more closely at the PTO code.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#issuecomment-631574438

---

From: ianswett <[email-masked]>
Date: Wed, 20 May 2020 09:12:01 -0700

Closed #3666.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3666#event-3357219334