Subject: [quicwg/base-drafts] What to ack in an ACK frame (#764)

From: janaiyengar <[email-masked]>
Date: Wed, 06 Sep 2017 21:53:22 +0000 (UTC)

@martinduke pointed out that it's not clear what exactly an ACK frame include. Specifically, what packets should be acked and what timestamps should be included. We should be more explicit about this in the spec.

-- 
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/issues/764

---

From: martinduke <[email-masked]>
Date: Wed, 06 Sep 2017 22:01:13 +0000 (UTC)

Yes, it is clear that we should not include Ack blocks that have already been acked, and that we SHOULD include timestamps exactly once per packet. There is no stated recommendation on in-flight acks. Possibilities:
    (i) Do not repeat them in subsequent acks
    (ii) Repeat them only if they do not require additional ack blocks
    (iii) Repeat them only if they require neither additional ack blocks nor longer block lengths.
    (iv) Always repeat them until acked

These have significant pros and cons. The benefits of not adding more ACK overhead are obvious. The benefits of repeating acks are obvious. However,

(A) Repeating in-flight acks may increase largest_acked so that we cannot include certain unsent timestamps.
(B) _not_ repeating in-flight acks may create packet number gaps too large to send subsequent ack blocks.

These are subtle issues, and the algorithms to optimize the outcomes are not simple at all. Some sort of implementation guidance, or even narrowing of what is allowed in the frame, would be helpful.

-- 
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/issues/764#issuecomment-327619265

---

From: janaiyengar <[email-masked]>
Date: Tue, 12 Sep 2017 23:57:13 +0000 (UTC)

Just a quick comment on (A): That implies that you have generated timestamps and queued them for sending. I think you'd be better off generating timestamps on the fly, when you're generating the ack.

In general, I would very much argue in favor of repeating until unnecessary (ack of ack is received). From a loss recovery perspective, it's really helpful to ensure this. There's not a tremendous amount of cost in the common case to doing this anyways.

-- 
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/issues/764#issuecomment-329017624

---

From: martinduke <[email-masked]>
Date: Tue, 19 Sep 2017 20:18:49 +0000 (UTC)

If we're actively trying to send a timestamp for a received packet, that implies we're storing the received time somewhere. Once we give up on timestamps we can throw that information; indeed, there is no necessary per-packet receipt record except for the timestamp.

I concur that there is a decent case for sending all unacked ack block at all times; however, this bit profligacy sits uncomfortably with other complexity designed to save a bit or two here and there.

-- 
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/issues/764#issuecomment-330661131

---

From: ianswett <[email-masked]>
Date: Tue, 19 Sep 2017 20:24:42 +0000 (UTC)

If the loss rates are low, then it commonly costs zero extra bytes to keep acking packets that have been included in an ack frame before.  If loss rates are high, then it's likely a good idea to repeat ack info since previous acks may have been lost.  This seems like a good tradeoff to me.

-- 
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/issues/764#issuecomment-330662623

---

From: martinduke <[email-masked]>
Date: Tue, 19 Sep 2017 13:55:32 -0700

@janaiyengar I must not have expressed myself clearly on case (A). Here is an example.
Acks for packets 1001-1200 and 1210-1300 are inflight.
Then I receive (much delayed) packet 1000.

The timestamp information would be quite useful, I imagine, as this will spike the rttvar. If I include all ack blocks, then largest_acked is 1300 and I have no way to express a timestamp 300 packet numbers below largest_acked.

A corner case, yes. It's possible to write some intricate code to handle this case. It's much simpler to not send higher ack blocks as a matter of course. This is how I ended up on option (ii) above.

Anyway, my intent is not to necessarily argue for what I did. It would be useful to get a sense of what people are doing and include an implementation note (or a SHOULD) if there's rough consensus.

@ianswett In the zero-loss case there is no difference between (ii) and (iv).

Comparing (ii) and (iv), each packet loss or burst loss in a window will cost me from 2 to 9 bytes of overhead in each packet. From a wire efficiency perspective, this is much worse than just sending it when the ack is lost, which when using case (ii) may require the loss of multiple acks and is generally quite improbable. OTOH, delivering the ack in < 2RTT with very high probability is good for avoiding spurious retransmissions and congestion backoff. 

This tradeoff doesn't seem obvious to me, but again I think the important thing is to capture the consensus.

-- 
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/issues/764#issuecomment-330670706