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
Use PTO to declare in-flight packets lost #1965
Conversation
QUIC, unlike TCP, allows the connection to get into a situation where there could be packets in flight, and a connection could even be CWND limited, but there may not be any outstanding data to retransmit. The suggested solution is to send a retransmittable frame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the concept, though I have some problems with the explanatory text.
One zoom-out question about TLP in QUIC: If there's a tail loss, you'll have to wait for an entire delayed-ack timeout to send, wait at worst for another DAT to get the ack, then a reordering timeout to declare the intervening packets lost. How does that compare to a plain old RTO?
draft-ietf-quic-recovery.md
Outdated
@@ -418,6 +418,12 @@ used to send a probe into the network prior to establishing any packet loss, | |||
prior unacknowledged packets SHOULD NOT be marked as lost when a TLP timer | |||
expires. | |||
|
|||
If no new data or unacknowledged data is available to send, a retransmittable | |||
frame SHOULD be sent. Sending a retransmittable frame ensures that any in | |||
flight packets are acknowledged or declared lost in a timely manner, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think TLP accelerates acknowledgment of in-flight pkts unless you happen to hit what the maximum number of delayed-acked pkts are.
So I would delete "acknowledged or"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, if you TLP, then you haven't received an ACK that contained any information about the in flight packets, because otherwise you'd fast or early retransmit them. So you have some number of in flight packets, and you don't know what their status is. It's possible the ACK was just lost, etc. So in that sense, it accelerates receiving an acknowledgement for them if they were in fact not lost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, ack losses. You're right
draft-ietf-quic-recovery.md
Outdated
If no new data or unacknowledged data is available to send, a retransmittable | ||
frame SHOULD be sent. Sending a retransmittable frame ensures that any in | ||
flight packets are acknowledged or declared lost in a timely manner, | ||
potentially preventing a deadlock if all in flight packets contain no data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete everything after "deadlock."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I update the text right as you were reviewing, PTAL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New data also prevents a deadlock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
D'oh! comments passed in flight.
draft-ietf-quic-recovery.md
Outdated
@@ -418,6 +418,12 @@ used to send a probe into the network prior to establishing any packet loss, | |||
prior unacknowledged packets SHOULD NOT be marked as lost when a TLP timer | |||
expires. | |||
|
|||
If no new data or unacknowledged data is available to send, a retransmittable | |||
frame SHOULD be sent. Sending a retransmittable frame ensures that any in | |||
flight packets are acknowledged or declared lost in a timely manner. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"acknowledged or" remains problematic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
howso?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mind, see above.
draft-ietf-quic-recovery.md
Outdated
frame SHOULD be sent. Sending a retransmittable frame ensures that any in | ||
flight packets are acknowledged or declared lost in a timely manner. | ||
Otherwise, a deadlock results if there is no available congestion window and | ||
all in flight packets contain no data that can be retransmitted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hyphenate "in-flight" when used before the noun this way.
I feel like maybe I don't understand this. It's titled "deadlock" but it looks to me like it's really just RTO. Am I misunderstanding? |
Good question, @ekr It's definitely a detail point, but I think the above approach is likely the ideal fix. But here's what I expect to happen now. If the implementation stores some state saying "the tlp alarm fired, but I couldn't send anything, and I'll remember that in case there is some data I can send in the near future." then when there's new data, everything should be fixed, though you'll also only be able to send a single packet. And if that packet or the corresponding ACK is lost, it'll be another TLP before you can send a packet. Alternately, an implementation could fire the alarm, realize it can't send anything, then not re-arm the alarm(since if it was re-armed, it would just fire immediately and you'd spin). The second approach is a deadlock. The first one is just going to be very slow recovery. Both seem somewhat suboptimal. There's another solution to this, which is to declare all in-flight packets lost. But that goes against the approach we use throughout QUIC loss recovery where we don't declare packets lost until a larger packet is acknowledged. OT: @martinduke pointed out that this should be fixed for RTO as well, since it's possible between TLP and RTO(or between two RTOs) in-flight data is cancelled, so now there's nothing to retransmit. |
draft-ietf-quic-recovery.md
Outdated
@@ -142,7 +142,7 @@ of frames contained in a packet affect recovery and congestion control logic: | |||
|
|||
* Packets that contain only ACK frames do not count toward congestion control | |||
limits and are not considered in-flight. Note that this means PADDING frames | |||
cause packets to contribute toward bytes in flight without directly causing an | |||
cause packets to contribute toward bytes in-flight without directly causing an | |||
acknowledgment to be sent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was agreed to spell this "bytes in flight" but I could be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If in-flight
is used, I think other text needs to be updated also. The motivation for not using hyphen was the confusion with bytes_in_flight
as a variable name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"in-flight" when used as a compound modifier (in-flight packets, for example) should usually have a hyphen before the noun. Here, it's after the noun, so this wouldn't get one. See here, for example.
Rather than adding a new paragraph to patch the hole, I'd update the description of what a "probe" packet is. Currently it's "a packet which is not subject to CC and which contains unsent data (if possible) or sent data (otherwise)." I'd update this sentence and move it somewhere to apply to both TLP and RTO probes. |
@ianswett do you have an example of a case where you have packets in flight but no outstanding data to retransmit? I was trying to come up with one but couldn't. In the case of a stream getting cancelled, you'd still have the RST_STREAM frame that needs to be sent. |
@nibanks couldn't RST happen async separate from the pipeline of schedule transmissions. More generally, data might exist, but not (yet) in the low level tranmissions system that deals with retransmission. |
@mikkelfj that's really an implementation detail. For me, resetting a stream, queuing the RST_STREAM frame for delivery and removing the actual stream data for retransmission is an atomic operation. |
@nibanks I agree, but because it is an implementation detail, the protocol cannot make general assumptions on how implementations work. Forcing an implemtation to operate atomically is not ideal. EDIT: can->cannot in the above |
@mikkelfj I totally agree. I was just trying to understand if there were any non-implementation specific scenarios where this could happen (in other words, does this apply to my implementation or can I ignore this bit of text). |
Given if there is something to be sent, I don't think this is a deadlock, I'm inclined to close this PR, both because it's old and I'm not convinced it's a practical issue. |
@nibanks The simplest way for this to happen is that the first TLP timeout resends some data, and then the original is acked. Thus we have an in-flight packet (the retransmission) but the actual application data is already gone from the send buffer. The TLP timer will fire again, and there's nothing to send. @ianswett There are still some problems with the new text. The main practical impact is that we will delay declaring the last packet lost, meaning we won't free up the flightsize or execute a congestion response as quickly. I'm having a little trouble reasoning about the full implications of this for new data. |
I updated this to clarify it's not really a deadlock, but suggest what should be done on PTO in this case: either send an ack-eliciting packet or declare the packets lost. |
For the record, I believe this was a potential deadlock: |
Previously, Jana said you should store that the PTO had fired and there was nothing to send, so when data does arrive to send, you can immediately send it. But that wasn't explicitly documented anywhere to my knowledge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @martinduke is right that we should handle this particular case, and I'm fine with the resolution in this PR. A few comments (and the text is in teh wrong place)
draft-ietf-quic-recovery.md
Outdated
|
||
A sender may not know that a packet being sent is a tail packet. Consequently, | ||
a sender may have to arm or adjust the TLP timer on every sent retransmittable | ||
packet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect this para is leftover and should be removed.
draft-ietf-quic-recovery.md
Outdated
@@ -421,6 +421,15 @@ control and loss recovery state, including resetting any pending timers. Either | |||
packet indicates that the Initial was received but not processed. Neither | |||
packet can be treated as an acknowledgment for the Initial. | |||
|
|||
If no new data or unacknowledged data is available to send, an ack-eliciting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new text should be further below in the #pto section.
Co-Authored-By: ianswett <ianswett@users.noreply.github.com>
A proposal: I think I prefer to mark things as lost instead of suggesting that a sender SHOULD send something when there's really nothing to be sent. I was starting to rephrase your PR to say "SHOULD send ack-eliciting packet, but MAY mark as lost", and I needed to explain how a sender makes this choice. I realized that if it's been long enough (PTO is long enough) and there's nothing left to send, then maybe it is sensible to mark anything pending as lost. So, I changed my suggestion to that, which is this PR (against your PR).
Hm. I started to think about how to rephrase a bit, which ended up leading to #2212. Take a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@martinduke : See if this resolves your concerns.
@martinduke Jana and I replaced my text with a version of his PR. We believe this solves the issue you point out as well. |
I like this language a lot. Ship it! |
QUIC, unlike TCP, allows the connection to get into a situation where there could be packets in flight, and a connection could even be CWND limited, but there may not be any outstanding data to retransmit.
The suggested solution is to send a retransmittable frame.