All packets sent after receiving and processing transport parameters might be affected, including Initial, Handshake, and Retry packets. <del> A client MAY also clear the QUIC Bit in packets that are sent prior to receiving transport parameters from the server.  However, a client MUST NOT clear the QUIC Bit unless the Initial packets it sends include a token provided by the server in a NEW_TOKEN frame (Section 19.7 of QUIC) received less than 604800 seconds (7 days) prior on a connection where the server also included the grease_quic_bit transport parameter. </del>  This 7 day limit allows for changes in server configuration.  If server configuration changes and a client does not set the QUIC

URL Has there been any analysis done for the 7 day rule? or is this just an agreed value. It would be nice to provide some reasoning behind the 7 day rule.
This matches the recommendations in TLS for session tickets, which prohibit the use of tickets after 7 days. But I don't think we should hide from the fact that this is completely and unapologetically arbitrary. Arbitrary is OK; justification only papers over that.
If this is completely arbitrary then we should not need to recommend this, this is not an experimental specification. In that case it makes sense to even drop it. But I see this is not really that much arbitrary, and reflects the practice for TLS session token. I think we can just say that. in this case we can go from SHOULD to MAY, making it optional. by the way I also think, the security consideration falls short on this topic. If we are recommending something then we it is better to say what happens when it is not followed.
It is arbitrary, but it does need a specified maximum. What happens when it is not followed is that packets can't be processed.
yes, if we say something then it will be best to specify a maximum. so the question now from my side is - do we need a strong recommendation (SHOULD) or can we make is optional (MAY)? if we don't have enough experience of actual deployment of it them perhaps it is best that we make it optional. But I am interested to hear why this should be a "SHOULD". when you say "packets can't be processed" do you mean at server? can we write this down?
The text already says why:
now that we have explicitly added handshake and 0-RTT packet in this clause, the to me call for a attention from the WG to review. Otherwise looks good to me. Latest text LGTMThanks for addressing my nits

All packets sent after receiving and processing transport parameters might be affected, including Initial, Handshake, and Retry packets.  <ins> A client MAY also clear the QUIC Bit in Initial, Handshake, or 0-RTT packets that are sent prior to receiving transport parameters from the server.  However, a client MUST NOT clear the QUIC Bit unless the Initial packets it sends include a token provided by the server in a NEW_TOKEN frame (Section 19.7 of QUIC), received less than 604800 seconds (7 days) prior on a connection where the server also included the grease_quic_bit transport parameter. </ins> This 7 day limit allows for changes in server configuration.  If server configuration changes and a client does not set the QUIC


The grease_quic_bit transport parameter (0x2ab2) can be sent by both client and server.  The transport parameter is sent with an empty value; an endpoint that understands this transport parameter MUST <del> treat receipt of a non-empty value as a connection error of type TRANSPORT_PARAMETER_ERROR. </del>  An endpoint that advertises the grease_quic_bit transport parameter MUST accept packets with the QUIC Bit set to a value of 0.  The QUIC

Broken into separate changes; see the commentary on each. This won't rebase nicely with , but I can manage that later.

The grease_quic_bit transport parameter (0x2ab2) can be sent by both client and server.  The transport parameter is sent with an empty value; an endpoint that understands this transport parameter MUST  <ins> treat receipt of a non-empty value of the transport parameter as a connection error of type TRANSPORT_PARAMETER_ERROR. </ins> An endpoint that advertises the grease_quic_bit transport parameter MUST accept packets with the QUIC Bit set to a value of 0.  The QUIC


The second-to-most significant bit of the first byte in every QUIC packet is defined as having a fixed value in QUIC version 1 QUIC. <del> The purpose of having a fixed value is to allow QUIC to be efficiently distinguished from other protocols; see DEMUX for a </del>  description of a system that might use this property.  As this bit can identify a packet as QUIC, it is sometimes referred to as the "QUIC Bit". change makes the task of identifying QUIC more difficult without cooperation of endpoints.  This sometimes works counter to the security goals of network operators who rely on network <del> classification to identify threats. </del>  5.

LGTM.
Actually, looking at a bit closer, perhaps consider: "... endpoint and cooperating intermediaries to efficiently ..." and perhaps make the Manageability reference explicitly to section 3.1 that covers identifying QUIC traffic.
Note that this is the second paragraph of the document. I'd prefer not to pile too many unrelated concepts in at this point. I think that it is OK to consider "cooperating intermediaries" to be implicit when we say "endpoint" when operating at this level of abstraction. Toward the end, where manageability is cited, is a better place for that sort of detail. I narrowed the citation to point to Section 3.1 as you suggested.
I think this update addresses NAME 's point in the telechat review.

The second-to-most significant bit of the first byte in every QUIC packet is defined as having a fixed value in QUIC version 1 QUIC.  <ins> The purpose of having a fixed value is to allow endpoints to efficiently distinguish QUIC from other protocols; see DEMUX for a </ins> description of a system that might use this property.  As this bit can identify a packet as QUIC, it is sometimes referred to as the "QUIC Bit". change makes the task of identifying QUIC more difficult without cooperation of endpoints.  This sometimes works counter to the security goals of network operators who rely on network  <ins> classification to identify threats; see Section 3.1 of MANAGEABILITY for a more comprehensive treatment of this topic. </ins> 5.


This one says something like what Lucas said, with the caveat that the whole thing about per-connection ID is specific to spin bits, so I dropped that.
LGTM


Greasing the QUIC Bit <del> draft-ietf-quic-bit-grease-latest </del> Abstract This document describes a method for negotiating the ability to send <del> an arbitrary value for the second-to-most significant bit in QUIC </del>  packets. 1. <del> QUIC QUIC intentionally describes a very narrow set of fields that are visible to entities other than endpoints.  Beyond those characteristics that are defined as invariant QUIC-INVARIANTS, very little about the "wire image" RFC8546 of QUIC is visible. </del>  <del> The second-to-most significant bit of the first byte in every QUIC </del>  packet is defined as having a fixed value in QUIC version 1 QUIC. The purpose of having a fixed value is to allow endpoints to efficiently distinguish QUIC from other protocols; see DEMUX for a Where endpoints and the intermediaries that support them do not depend on the QUIC Bit having a fixed value, sending the same value <del> in every packet is more of liability than an asset.  If systems come to depend on a fixed value, then it might become infeasible to define a version of QUIC that attributes semantics to this bit. </del>  In order to safeguard future use of this bit, this document defines a QUIC transport parameter that indicates that an endpoint is willing 3. <del> The grease_quic_bit transport parameter (0x2ab2) can be sent by both client and server.  The transport parameter is sent with an empty value; an endpoint that understands this transport parameter MUST treat receipt of a non-empty value of the transport parameter as a connection error of type TRANSPORT_PARAMETER_ERROR. </del>  An endpoint that advertises the grease_quic_bit transport parameter MUST accept packets with the QUIC Bit set to a value of 0.  The QUIC <del> Bit is defined as the second-to-most significant bit of the first byte of QUIC packets (that is, the value 0x40). </del>  3.1. than 604800 seconds (7 days) prior on a connection where the server also included the grease_quic_bit transport parameter. <del> This 7 day limit allows for changes in server configuration.  If </del>  server configuration changes and a client does not set the QUIC Bit, then it is possible that a server will drop packets, resulting in connection failures. <del> A server MUST set the QUIC bit to 0 only after processing transport </del>  parameters from a client.  A server MUST NOT remember that a client negotiated the extension in a previous connection and set the QUIC Bit to 0 based on that information. according to rules defined by the extension, they might also be randomized as specified in this document. <del> Receiving a transport parameter for an extension that uses the QUIC Bit could be used to confirm that a peer supports the semantic </del>  defined in the extension.  To avoid acting on a randomized signal, the extension can require that endpoints set the QUIC Bit according <del> to the rules of the extension, but defer acting on the information </del>  conveyed until the transport parameter for the extension is received. Extensions that define semantics for the QUIC Bit can be negotiated Permanent <del> This document. Date of registration. </del>  <del> QUIC Working Group (quic@ietf.org) </del>  IETF (iesg@ietf.org)  (none)

These are all the changes I found from the text diff, plus some extra changes about versions.
I have reviewed the changes, and I agree that they are editorial in nature.

Greasing the QUIC Bit  Abstract This document describes a method for negotiating the ability to send  <ins> an arbitrary value for the second-most significant bit in QUIC </ins> packets. 1.  <ins> The version-independent definition of QUIC QUIC-INVARIANTS intentionally describes a very narrow set of fields that are visible to entities other than endpoints.  Beyond those characteristics that are invariant, very little about the "wire image" RFC8546 of QUIC is visible. </ins>  <ins> The second-most significant bit of the first byte in every QUIC </ins> packet is defined as having a fixed value in QUIC version 1 QUIC. The purpose of having a fixed value is to allow endpoints to efficiently distinguish QUIC from other protocols; see DEMUX for a Where endpoints and the intermediaries that support them do not depend on the QUIC Bit having a fixed value, sending the same value  <ins> in every packet is more of a liability than an asset.  If systems come to depend on a fixed value, then it might become infeasible to define a version of QUIC that attributes semantics to this bit. </ins> In order to safeguard future use of this bit, this document defines a QUIC transport parameter that indicates that an endpoint is willing 3.  <ins> The grease_quic_bit transport parameter (0x2ab2) is defined for QUIC version 1 QUIC.  This transport parameter can be sent by both client and server.  The transport parameter is sent with an empty value; an endpoint that understands this transport parameter MUST treat receipt of a non-empty value of the transport parameter as a connection error of type TRANSPORT_PARAMETER_ERROR. </ins> An endpoint that advertises the grease_quic_bit transport parameter MUST accept packets with the QUIC Bit set to a value of 0.  The QUIC  <ins> Bit is defined as the second-most significant bit of the first byte of QUIC packets (that is, the value 0x40). </ins> 3.1. than 604800 seconds (7 days) prior on a connection where the server also included the grease_quic_bit transport parameter.  <ins> This 7-day limit allows for changes in server configuration.  If </ins> server configuration changes and a client does not set the QUIC Bit, then it is possible that a server will drop packets, resulting in connection failures.  <ins> A server MUST set the QUIC Bit to 0 only after processing transport </ins> parameters from a client.  A server MUST NOT remember that a client negotiated the extension in a previous connection and set the QUIC Bit to 0 based on that information. according to rules defined by the extension, they might also be randomized as specified in this document.  <ins> The receipt of a transport parameter for an extension that uses the QUIC Bit could be used to confirm that a peer supports the semantic </ins> defined in the extension.  To avoid acting on a randomized signal, the extension can require that endpoints set the QUIC Bit according  <ins> to the rules of the extension but defer acting on the information </ins> conveyed until the transport parameter for the extension is received. Extensions that define semantics for the QUIC Bit can be negotiated Permanent  <ins> RFC 9287 </ins>  <ins> 2022-07-13 </ins> IETF (iesg@ietf.org) <ins> QUIC Working Group (quic@ietf.org) </ins> (none)


version with version 1.  Therefore, v2-capable servers MUST use compatible version negotiation unless they do not support version 1. <del> As version 1 support is more likely than version 2 support, a client SHOULD use QUIC version 1 for its original version unless it has out- of-band knowledge that the server supports version 2. </del>  5.

and I could be persuaded that some of the choices made here are not the best.
Oops, I posted , which is almost exactly the same. My bad. The 0-RTT thing is one I might contest here. It is possible to accept 0-RTT if you have a compatible upgrade, but I'm not sure that you ever need it. The situations in which you can use 0-RTT without knowing what version is in use are few. All the client has to do is remember the negotiated version from last time and use that version.
I take it we've reached rough consensus that 0RTT has value, though no one will force MT to accept those packets. I'm going to merge this, and in a separate PR (taking text from )
It is necessary to specify how retry works when a compatible upgrade is used. The easiest way to specify this is to say that Retry can be sent in version 1, but the validation is performed as though a version 2 retry was sent. That's what I've seen implemented thus far.
Here's the relevant text in your PR (numbers mine) (1) A server SHOULD produce a Retry packet in the same version as the Initial packet that the Retry packet responds to. (2) Validation of the Retry exchange uses the logic of the final negotiated version, treating the Retry as if it were sent in that version. (3) This means that the version used for Retry is not authenticated, only that it occurred and the connection ID that was used. (1) I made it a MUST in the recent merge, to make it a bit easier for clients. (2) I'm not really sure what this means in the context of v1/v2 -- the logic is identical in both cases. Maybe this is something for the v1->vn text (pending) in the VN doc? But yeah, anything in the client hello, including the retry TPs, are processed syntactically as v1 but the content is used for v2 purposes. Do I understand the takeaway correctly? (3) This is a fair point to make, I guess: the Retry logic only ever measured that the CIDs matched. But, meh? The client changing the version between connection attempts would be strange, but legal and not obviously dangerous. If you think this sentence is valuable, I can add it.
Fine. Yeah, this was just a wording choice of mine. I do think that the validation is an important point to be clear on, lest people decide to skip it. I don't think that this can be part of the VN document at least as it stands as the Retry mechanism is version-specific and so any handling of it also needs to be. This is really just noting the limitations of the validation. I don't think that it has security consequences, particularly if the client enforces the requirement that Retry use the original version (which, presumably they are permitted to... by dropping the packet).
URL is going to introduce some considerations specific to v1. Nevertheless, I'm happy to write something down here.
We now have some implementation experience, and got interop between 2 implementations. That's great, but the process was difficult because the transition is somehow under specified. There was a lot of discussion as issues with the compatible version negotiation draft: These issues cannot be fully addressed in the compatible version negotiation draft, which has to be version independent. Instead, they need to be addressed in specific drafts. The V2 draft, for example, should specify exactly what happens during the version negotiation. My understanding is that when version negotiation succeeds, we will see something like: Client sends a first flight composed of Version 1 initial packets Server may send Version 1 initial packets containing acknowledgement, e.g., to manage losses of Initial packets At some point, the server will have received and parsed the transport parameters, and decided to upgrade to V2 After that point, server will send version 2 packets (Initial, Handshake, 1RTT) Client will receive version 2 packets and should be ready to process them before the negotiation completes The transport parameters will arrive in V2 handshake packets, after which the negotiation is done. There are quite a few potential issues that need resolution: 1) As explained above, in case of successful negotiation, the client expects the server to start sending V2 packets asap. Shall it ignore V1 packets as soon as it received V2 packets? Should in check version numbers in Initial packets, in a process similar to key updates? 2) If the client receives transport parameters on a version 2 packet, what shall it do if the chosen version is V1? 3) And vice versa? 4) If the server receives V2 handshake packets from the client, shall it conclude that the negotiation is successful? 5) In case of session resumption, does the client resume using V1 or V2? I think the answer to that question depends on the content of the "supported versions" list provided by the server. If it includes V2, then the server is ready to receive V2 packets. If the server is part of a server farm with partial deployment of V2, it should not say that V2 is ready. The answer may also depend on local conditions at the client. 6) If the client resumes using V1, it will send 0-RTT packets using V1. The server will receive these packets after the client's initial packets, and thus after receiving the transport parameters and completing the version upgrade. Should the server drop these packets? Or should it continue accept them until the handshake completes? 7) On the client side, there will be a delay between completing the negotiation and finalizing the handshake. The client may want to send 0-RTT packets during that interval. Shall it send those using V1 or V2?
The most literal answer to your question is, "of course all v1 can be interchanged with v2, since they're identical". But I'm going to answer the more interesting question of what precise questions a new version has to answer. AFAICT, in the v1->v2 case, (assuming all the support is present) there are four possible responses from the server: 1) a v2 Initial with ACK and/or ServerHello 2) a v1 Initial with ACK, followed by a v2 Initial with ServerHello 3) a v1 Retry (a v2 Retry would also be correct, but silly for the server to do things that way) 4) a v1 Initial with ACK, followed by nothing (because some of the client hello was lost) I believe this generalizes to all transitions v1->vn. So clearly the client can't draw any conclusions about the ultimate version until it sees the server hello, or a v2 packet of any kind. It can't fully authenticate the handshake until we get 1-RTT keys. So to answer your questions: (1) yes, ignore v1 once you get v2 -- you don't need the Initial ACK anyway (2) and (3) if the chosen version in the TP doesn't match the QUIC header, this is a VN violation, no? Shouldn't this be handled in the VN draft? (4) I would think that any client packet with v2 and the correct keys would do the trick. (5) The two elements of this are the NEWTOKEN token and the TLS session ticket. The hard part here is that the contents of this are not in any version spec; if QUIC and TLS implementations put version specific things in there, then it won't work. IIUC in general the session ticket wouldn't include anything derived from the version-dependent HKDF labels, so it ought to work. (6) and (7) I believe the server has to handle v1 0RTT till the handshake is over, as it can't guarantee that 0RTT arriving after the 2nd flight was sent after that flight. The client could switch its 0RTT to v2 once negotiated -- I have no strong opinion if that complexity is worthwhile. I don't think putting these responses in a PR is the right move -- I'd like to clarify what properly should go in the VN draft and what should rest here.
Minor fix. In NAME example, ACK in V1 from the server is received by the client before any V2 packets. So, the client can handle it anyway.
This is probably a good idea. We can say that 0RTT belongs to the previous connection of V1. NAME If you agree, let's implement this and do interop.
We need to prohibit v2 Retry since a v1-only client cannot retry if v2 Retry is received.
When a client see V2 in a long header, it switches to V2 keys. This switch is allowed only once. After handshake is completed, the client checks if the version for keys and Chosen Version is the same.
OK, I will test the 0-RTT part internally first. There are timing issues in the server code, depending on whether the 0-RTT key is produced before the negotiation or after it.
NAME The idea for 0-RTT works perfectly on my local tests. I will brush up the code tomorrow and set up a public server.
Thank you for this work. Can quic v2 server accept a v1 0-RTT packet via Compatible Version Negotiation? If I understand correctly, The says that "future versions will determine how to handle it." Even if the server accepts v1 packets as is, I would think the handling needs to be described in v2.
Developers are actually puzzled. See URL
Moving the discussion here, I think that 0-RTT is not as clear-cut as it seems. When doing a compatible upgrade from v1 to v2, a server makes the switch when it processes the ClientHello (that is, all Initial packets from the client to a first approximation). It is relatively easy for the server to make the switch cleanly at that point because it doesn't need to read any more Initial packets and all other packets will be v2 from then on. A client makes the switch based on seeing a v2 packet. It might receive some v1 Initial packets, but the one containing a ServerHello will be v2. If the client is sending 0-RTT packets, it might need to send them until it receives all of the Handshake packets from the server. That is, it might be some time. For a client in that state, it doesn't really make sense to switch to sending v2 0-RTT packets, but if it doesn't it will be intermixing transmission of v1 0-RTT packets and v2 Handshake packets. This is awkward because there is no clean cut-over. In my implementation, I also have to deal with stack integration issues that make installing the right 0-RTT keys difficult. I ultimately opted to just reject 0-RTT if there was a version change. The number of cases in which you might want to use 0-RTT and you don't already know what version the server wants to use are very limited. Basically, this only happens if you are doing 0-RTT across an upgrade of the server. Losing 0-RTT in that case seems tolerable.
The text reflects the consensus so far. I have to update my implementation to ensure that it follows these rules exactly, in particular for 0RTT, might add comments when that implementation is tested.

version with version 1.  Therefore, v2-capable servers MUST use compatible version negotiation unless they do not support version 1.  <ins> 4.1. Compatible version negotiation between versions 1 and 2 follow the same requirements in either direction.  This section uses the terms "original version" and "negotiated version" from QUIC-VN. If the server elects to send a Retry packet, it MUST do so using the original version. The server SHOULD start sending its Initial packets using the negotiated version as soon as it decides to change.  Note that the server might send some Initial packets using the original version. Once the client has processed a packet using the negotiated version, it SHOULD send subsequent Initial packets using that version.  The server MUST NOT discard its original version Initial receive keys until it successfully processes a packet with the negotiated version. Both endpoints MUST send Handshake or 1-RTT packets using the negotiated version.  An endpoint MUST drop packets using any other version.  Endpoints have no need to generate the keying material that would allow them to decrypt or authenticate these packets. If the server's version_information transport parameter does not contain a Chosen Version field equivalent to the version in the server's Handshake packet headers, the client MUST terminate the connection with a VERSION_NEGOTIATION_ERROR. The client MUST NOT send 0-RTT packets using the negotiated version, even after processing a packet of that version from the server. Servers can apply original version 0-RTT packets to a connection without additional considerations. </ins> 5.


same requirements in either direction.  This section uses the terms "original version" and "negotiated version" from QUIC-VN. <del> If the server elects to send a Retry packet, it MUST do so using the original version. </del>  The server SHOULD start sending its Initial packets using the negotiated version as soon as it decides to change.  Before the

NAME fixed up IAW with your comments. PTAL
It is necessary to specify how retry works when a compatible upgrade is used. The easiest way to specify this is to say that Retry can be sent in version 1, but the validation is performed as though a version 2 retry was sent. That's what I've seen implemented thus far.
Here's the relevant text in your PR (numbers mine) (1) A server SHOULD produce a Retry packet in the same version as the Initial packet that the Retry packet responds to. (2) Validation of the Retry exchange uses the logic of the final negotiated version, treating the Retry as if it were sent in that version. (3) This means that the version used for Retry is not authenticated, only that it occurred and the connection ID that was used. (1) I made it a MUST in the recent merge, to make it a bit easier for clients. (2) I'm not really sure what this means in the context of v1/v2 -- the logic is identical in both cases. Maybe this is something for the v1->vn text (pending) in the VN doc? But yeah, anything in the client hello, including the retry TPs, are processed syntactically as v1 but the content is used for v2 purposes. Do I understand the takeaway correctly? (3) This is a fair point to make, I guess: the Retry logic only ever measured that the CIDs matched. But, meh? The client changing the version between connection attempts would be strange, but legal and not obviously dangerous. If you think this sentence is valuable, I can add it.
Fine. Yeah, this was just a wording choice of mine. I do think that the validation is an important point to be clear on, lest people decide to skip it. I don't think that this can be part of the VN document at least as it stands as the Retry mechanism is version-specific and so any handling of it also needs to be. This is really just noting the limitations of the validation. I don't think that it has security consequences, particularly if the client enforces the requirement that Retry use the original version (which, presumably they are permitted to... by dropping the packet).
URL is going to introduce some considerations specific to v1. Nevertheless, I'm happy to write something down here.

same requirements in either direction.  This section uses the terms "original version" and "negotiated version" from QUIC-VN.  <ins> If the server sends a Retry packet, it MUST use the original version. The client ignores Retry packets using other versions.  The client MUST NOT use a different version in the subsequent Initial that contains the Retry token.  The server MAY encode the QUIC version in its Retry token to validate that the client did not switch versions, and drop the packet if it switched. QUIC version 2 uses the same transport parameters to authenticate the Retry as QUIC version 1.  After switching to a negotiated version after a Retry, the server MUST include the relevant transport parameters to validate that the server sent the Retry and the connection IDs used in the exchange, as described in Section 7.3 of QUIC.  Note that the version of the first Initial and the subsequent Retry are not authenticated by transport parameters. </ins> The server SHOULD start sending its Initial packets using the negotiated version as soon as it decides to change.  Before the


specification as described in QUIC, QUIC-TLS, and RFC9002, with the following changes: <del> The version field of long headers is TBD.  Note: Unless this document is published as an RFC, implementations should use the provisional value 0xff020000, which might change with each edition of this document. </del>  The salt used to derive Initial keys in Section 5.2 of QUIC-TLS changes to: This document requests that IANA add the following entry to the QUIC version registry: <del> Value: TBD </del>  <del> Status: permanent </del>  Specification: This Document

Get one from IANA
I'll ask for 0x70 9a 50 c4 .
Feedback from NAME was that you should do that after publishing a revision with that number in it. I second that.

specification as described in QUIC, QUIC-TLS, and RFC9002, with the following changes:  <ins> The version field of long headers is 0x709a50c4. </ins> The salt used to derive Initial keys in Section 5.2 of QUIC-TLS changes to: This document requests that IANA add the following entry to the QUIC version registry:  <ins> Value: 0x709a50c4 </ins>  <ins> Status: provisional </ins> Specification: This Document


4. QUIC version 2 endpoints SHOULD also support QUIC version 1.  Any <del> QUIC endpoint that supports multiple versions MUST fully implement QUIC-VN to prevent version downgrade attacks. </del>  Note that version 2 meets that document's definition of a compatible version with version 1.  Therefore, v2-capable servers MUST use

The draft currently states: I think we should weaken this to only require the downgrade prevention aspect of QUIC-VN. Chrome doesn't currently support incompatible version negotiation and we don't plan to change that when we add support for v2.
I agree that 'fully support' is too onerous. However, it is not really clear to me what the minimum set of VN support is. The VN draft doesn't really envision partial support. If a client includes the version information TP, it MUST support compatible negotiation. A server that sends VN packets (as they all should!) MUST support incompatible negotiation. So for clients, AFAICT there are three levels of support: 1) No support: do not the send the TP. If you get a VN packet, switch to TCP 2) Compatible only - send the TP, be prepared to accept an upgrade 3) Full: respond to VN packets with incompatible negotiation. For servers, it would be 1) Send the TP and support incompatible negotiation 2) Support compatible negotiation
I don't think that's right. The client can just always send Therefore, for clients, the options are: No support: do not the send nor parse the TP. If you get a VN packet, fail the QUIC connection Downgrade prevention only: send the TP with only one other version, also parse and validate the TP. If you get a VN packet, fail the QUIC connection Compatible only: downgrade prevention and be prepared to accept an upgrade Incompatible only: downgrade prevention and retry with new version when receiving VN Full: downgrade prevention, compatible VN and incompatible VN I agree with what you said about servers.
I don't understand 2. If only one version is advertised, what downgrade are we preventing? Also, I don't see how (4) works if the server decides to do a compatible VN. Is the idea that the client only advertises support for one version in its TP?
Let's say the client tries version B and the server supports both versions A and B. An active network attacker can intercept the client's version B packets and rewrite them as version A before forwarding them to the server - then you would end up with a connection where the client thinks it's speaking version B and the server thinks it's speaking version A. If version A is vulnerable to an attack that B isn't, the attacker managed to downgrade the security from version B to version A. In practice this attack doesn't work with v1 and v2 because we changed the HKDF labels, but the attack could work on other versions. This entire class of problem goes away if you add the Chosen Version to the TLS transcript, so there's some value in the downgrade-prevention-only mode. That's right.
(2) Offline, David clarified that the attack doesn't work in v1/v2 because the handshake packets authenticate the version field. but this is not generalizable to all QUIC versions. as for (4), thanks, makes sense.
I filed URL I think the right language for this draft is something to the effect of "Endpoints that support multiple versions MUST meet the minimum requirements described in {{QUIC-VN}}."
It's not entirely clear what minimal support is, but we have an issue for that :-)

4. QUIC version 2 endpoints SHOULD also support QUIC version 1.  Any  <ins> QUIC endpoint that supports multiple versions MUST meet the minimum requirements described in QUIC-VN to prevent version downgrade attacks. </ins> Note that version 2 meets that document's definition of a compatible version with version 1.  Therefore, v2-capable servers MUST use


4. <del> QUIC version 2 endpoints SHOULD also support QUIC version 1.  Any QUIC endpoint that supports multiple versions MUST meet the minimum requirements described in QUIC-VN to prevent version downgrade attacks. </del>  Note that version 2 meets that document's definition of a compatible <del> version with version 1.  Therefore, v2-capable servers MUST use compatible version negotiation unless they do not support version 1. </del>  4.1. 5.  QUIC version 2 provides protection against some forms of ossification.  Devices that assume that all long headers will contain encode version 1, or that the version 1 Initial key derivation server supports it, or are willing to suffer a round-trip penalty if they are incorrect. <del> 6. </del>  This version of QUIC provides no change from QUIC version 1 relating to the capabilities available to applications.  Therefore, all All QUIC extensions defined to work with version 1 also work with version 2. <del> 7. </del>  QUIC version 2 introduces no changes to the security or privacy properties of QUIC version 1. attacks, but downgrades have no security implications, as the version properties are identical. <del> 8. </del>  This document requests that IANA add the following entry to the QUIC version registry:

Incorporated all suggestions. My only concern about server MUST is that it involves mucking with TLS implementations again to encode version in the ticket. Would this be a real obstacle]?
NAME for any implementation that uses BoringSSL (and I suspect the OpenSSL API is the same way), adding the version to the ticket will not require modifying the TLS implementation at all because the TLS implementation already accepts an opaque blob of data from QUIC (and that's currently used for transport parameters and h3 settings, adding the QUIC version would be transparent to TLS).
I am a bit concerned that we are departing from the common pattern used in QUIC specification: "Clients MUST NOT do this particular vile thing; server MAY terminate the connection if they catch the client doing it." The purpose of the MUST NOT is to prevent the client from creating problems at the server. The purpose of the MAY is to encourage servers to do some enforcement, so bad client implementations have a good chance of being detected and do not become some entrenched practice. Telling the servers that they MUST enforce forces servers to dedicate resource to explicit detection, which may not be the right tradeoff for classes of servers, such as for example embedded servers with resource constraints.
NAME that is true, however TLS has a common pattern which is to require servers to validate their tickets thoroughly. I guess we have to pick which common pattern we care about most. I still think having the MUST on both clients and servers will lead to better interoperability
NAME maybe. The way I deal with that in the picoquic demo server is simple: the default transport parameters are set when the process start, and by default the STEK key is also set at process start. I suppose that embedded servers could just follow that tradeoff, i.e., forget tickets issued before the last reboot in exchange for code simplicity. But the simple server only verifies that the version is "one of the supported versions", does not check the ticket for that. So this is extra code. Not a ton of extra code, so I am not going to fight that too long. But still extra code.
I changed the MUST to a SHOULD. "Servers gonna do", so what we write here doesn't matter much, but I see no reason to create RFC violations where they're not really needed, and on the off chance that some servers have a serious obstacle to doing this.
During the discussion of URL, we came to the conclusion that it was simplest and safest to ban TLS resumption across QUIC versions. The version negotiation draft will mention this, but without normative text because TLS is not a QUIC invariant. The QUICv2 draft should add normative text to explicitly ban resuming TLS across versions.
Does this consensus apply to compatible VN? If the client initiates with v1 and a v1 resumption ticket, can the server upgrade it to v2 and still respect the 0RTT, etc? IIUC, this means that if the client connects with v1 and learns that the server does v2, but there's no upgrade, if the client decides to connect next time with v2 it can't use 0RTT because there will have been a v1 resumption ticket? Whereas an upgraded connection would have a v2 resumption ticket?
What does this mean? How does the client "learn" that the server speaks v2 if the server didn't perform compatible VN from v1 to v2?
If the server does not upgrade, but it learns about available versions via the TP.
The server's Other Versions field exists to prevent downgrades in incompatible VN. There's no text suggesting that clients remember that information for use outside of the current connection.
That may not have been your intent, but why wouldn't a client do this?
This issue is hopelessly intertwined with other issues, like how we handle ALPN. I am not equipped to evaluate the claim that cross-version use of tags will cause a security problem, although as I understand it this sentiment is a concern rather than an established threat. However: the use case I am concerned about involves a client learning about an incompatible version via the supported_versions TP, and choosing to connect to that version. If the resumption tags aren't reusable, then it has to lose an RTT by not doing 0RTT. Relying on incompatible VN would be two RTTs before data arrives. Granted, v1 and v2 are not incompatible. But if it's not actually unsafe, I'd rather set a precedent that works for future, incompatible versions.
Outcome of offline discussion with NAME and NAME 1) Clients MUST NOT use a resumption ticket from a QUIC connection and apply it to another version. 2) Servers SHOULD validate that resumption tickets are not being used across QUIC versions and refuse to honor the ticket (or terminate the connection?) if they are. 3) Make it clear that the resumption ticket from a connection that did compatible VN maps to the negotiated version, not the original one.
Wow, that was a fast shift back to "SHOULD". I missed that. I did a little digging and it seems like there is a different determination for 0-RTT and resumption in our code. Accepting 0-RTT is something that needs to be controlled, but resumption has no similar controls. In that, we're in a similar position to NAME We can't really stop resumption without first performing a little surgery on the TLS stack. With that in mind, I'm conditionally OK with this resolution. That's a purely pragmatic decision on my part on the basis that "compatible" in this case means not really changing anything about TLS.
I'm not 100% firm on the server "MUST", but I really think we should consider it.

4.  <ins> QUIC version 2 is not intended to deprecate version 1.  Endpoints that support version 2 might continue support for version 1 to maximize compatibility with clients.  In particular, HTTP clients often use Alt-Svc RFC7838 to discover QUIC support.  As this mechanism does not currently distinguish between QUIC versions, HTTP servers that support multiple versions reduce the probability of incompatibility and the cost associated with QUIC version negotiation or TCP fallback.  For example, an origin advertising support for "h3" in Alt-Svc SHOULD support QUIC version 1 as it was the original QUIC version used by HTTP/3 and therefore some clients will only support that version. Any QUIC endpoint that supports multiple versions MUST meet the minimum requirements described in QUIC-VN to prevent version downgrade attacks. </ins> Note that version 2 meets that document's definition of a compatible  <ins> version with version 1.  Therefore, servers can use compatible negotiation to switch a connection between the two versions. Endpoints that support both versions SHOULD support compatible version negotiation to avoid a round trip. </ins> 4.1. 5. <ins> TLS session tickets are specific to the QUIC version of the connection that provided them.  Clients MUST NOT use a session ticket from a QUICv1 connection to initiate a QUICv2 connection, or vice versa. Servers SHOULD validate the originating version of any session ticket and not resume from any ticket issued from a different version.  This results in falling back to a full TLS handshake, without 0-RTT. After compatible version negotiation, any resulting session ticket maps to the negotiated version rather than original one. 6. </ins> QUIC version 2 provides protection against some forms of ossification.  Devices that assume that all long headers will contain encode version 1, or that the version 1 Initial key derivation server supports it, or are willing to suffer a round-trip penalty if they are incorrect.  <ins> 7. </ins> This version of QUIC provides no change from QUIC version 1 relating to the capabilities available to applications.  Therefore, all All QUIC extensions defined to work with version 1 also work with version 2.  <ins> 8. </ins> QUIC version 2 introduces no changes to the security or privacy properties of QUIC version 1. attacks, but downgrades have no security implications, as the version properties are identical.  <ins> 9. </ins> This document requests that IANA add the following entry to the QUIC version registry:


4. <del> QUIC version 2 endpoints SHOULD also support QUIC version 1.  Any QUIC endpoint that supports multiple versions MUST meet the minimum requirements described in QUIC-VN to prevent version downgrade attacks. </del>  Note that version 2 meets that document's definition of a compatible <del> version with version 1.  Therefore, v2-capable servers MUST use compatible version negotiation unless they do not support version 1. </del>  4.1.

The original intent was to recommend compatible VN. But that doesn't make any sense: compatible VN is something that the server initiates between versions that are at least partially supported. The client doesn't really have any control except that it can omit versions from the TP. Incompatible VN cannot happen between mutually supported versions, and the client is in control.
NAME major rewrite that I think addresses your concerns. PTAL
In practice, v2 servers should also support compatible VN, as long as v1 clients are ubiquitous. To do otherwise would result in a performance penalty.
Thanks for the discussion!

4.  <ins> QUIC version 2 is not intended to deprecate version 1.  Endpoints that support version 2 might continue support for version 1 to maximize compatibility with clients.  In particular, HTTP clients often use Alt-Svc RFC7838 to discover QUIC support.  As this mechanism does not currently distinguish between QUIC versions, HTTP servers that support multiple versions reduce the probability of incompatibility and the cost associated with QUIC version negotiation or TCP fallback.  For example, an origin advertising support for "h3" in Alt-Svc SHOULD support QUIC version 1 as it was the original QUIC version used by HTTP/3 and therefore some clients will only support that version. Any QUIC endpoint that supports multiple versions MUST meet the minimum requirements described in QUIC-VN to prevent version downgrade attacks. </ins> Note that version 2 meets that document's definition of a compatible  <ins> version with version 1.  Therefore, servers can use compatible negotiation to switch a connection between the two versions. Endpoints that support both versions SHOULD support compatible version negotiation to avoid a round trip. </ins> 4.1.


version used by HTTP/3 and therefore some clients will only support that version. <del> Any QUIC endpoint that supports multiple versions MUST meet the minimum requirements described in QUIC-VN to prevent version downgrade attacks. </del>  Note that version 2 meets that document's definition of a compatible <del> version with version 1.  Therefore, servers can use compatible negotiation to switch a connection between the two versions. Endpoints that support both versions SHOULD support compatible version negotiation to avoid a round trip. </del>  4.1.

As described in URL, we're going to simply require all not-just-v1 servers to support the version-information transport parameter, even if they're v2-only servers.

version used by HTTP/3 and therefore some clients will only support that version.  <ins> Any QUIC endpoint that supports QUIC version 2 MUST send, process, and validate the version_information transport parameter specified in QUIC-VN to prevent version downgrade attacks. </ins> Note that version 2 meets that document's definition of a compatible  <ins> version with version 1, and version 1 is compatible with version 2. Therefore, servers can use compatible negotiation to switch a connection between the two versions.  Endpoints that support both versions SHOULD support compatible version negotiation to avoid a round trip. </ins> 4.1.


to the capabilities available to applications.  Therefore, all Application Layer Protocol Negotiation (ALPN) (RFC7301) codepoints specified to operate over QUICv1 can also operate over this version <del> of QUIC. </del>  All QUIC extensions defined to work with version 1 also work with version 2.

Now that DoQ is in the RFCEd queue, this draft should specifically state it is compatible with both registered ALPNs.

to the capabilities available to applications.  Therefore, all Application Layer Protocol Negotiation (ALPN) (RFC7301) codepoints specified to operate over QUICv1 can also operate over this version  <ins> of QUIC.  In particular, both the "h3" I-D.ietf-quic-http and "doq" I-D.ietf-dprive-dnsoquic ALPNs can operate over QUICv2. </ins> All QUIC extensions defined to work with version 1 also work with version 2.


5. <del> TLS session tickets are specific to the QUIC version of the connection that provided them.  Clients MUST NOT use a session ticket from a QUICv1 connection to initiate a QUICv2 connection, or vice versa. Servers SHOULD validate the originating version of any session ticket and not resume from any ticket issued from a different version.  This results in falling back to a full TLS handshake, without 0-RTT. </del>  After compatible version negotiation, any resulting session ticket maps to the negotiated version rather than original one.

Are NEW_TOKEN tokens reusable across versions? On current patterns, probably not, but we should write it down.
Agreed, we should mirror here what we did for TLS resumption tickets

5.  <ins> TLS session tickets and NEW_TOKEN tokens are specific to the QUIC version of the connection that provided them.  Clients SHOULD NOT use a session ticket or token from a QUICv1 connection to initiate a QUICv2 connection, or vice versa. Servers MUST validate the originating version of any session ticket or token and not accept one issued from a different version.  A rejected ticket results in falling back to a full TLS handshake, without 0-RTT.  A rejected token results in the client address remaining unverified, which limits the amount of data the server can send. </ins> After compatible version negotiation, any resulting session ticket maps to the negotiated version rather than original one.


Clients interested in combating firewall ossification can initiate a connection using version 2 if they are either reasonably certain the server supports it, or are willing to suffer a round-trip penalty if <del> they are incorrect. </del>  7.

Though no guarantee can be made, a client with a v2 ticket (which cannot be used with v1) might be in a good position to attempt v2 outright. Avoiding saying this creates something of a weird contradiction between sections.
Hmm. Your changes draws attention to the server expressing intent with a session ticket (but maybe not actual support), but that now seems oddly contrasting against the prior sentence that the client acts on reasonable confidence of support. So is the session ticket intent something a client can have reasonable confidence in, or not?
I thought that this was an appropriate amount of hedging on that point. The previous sentence is the "without other information, probably choose v1" side, the added sentence is the "maybe if you get a ticket you could bet the other way". Nothing firm either way, as tickets don't represent a commitment, they only signal intent in a way that alters probabilities.
Got it. On balance that seems right, we can't proscribe too much behaviour here. Looking forward to the research papers that analyse the effects of choice in the wild during 2023+

Clients interested in combating firewall ossification can initiate a connection using version 2 if they are either reasonably certain the server supports it, or are willing to suffer a round-trip penalty if  <ins> they are incorrect.  In particular, a server that issues a session ticket for version 2 indicates an intent to maintain version 2 support while the ticket remains valid, even if support cannot be guaranteed. </ins> 7.


QUIC version 2 is meant to mitigate ossification concerns and exercise the version negotiation mechanisms.  The only change is a <del> tweak to the inputs of some crypto derivation functions to enforce full key separation.  Any endpoint that supports two versions needs to implement version negotiation to protect against downgrade attacks. </del>  2.

Not only because crypto is short for cryptocurrency.
QUICv3, the web3 protocol, uses crypto the right way: the blockchain way.
You're only allowed to call it crypto in QUIC v3

QUIC version 2 is meant to mitigate ossification concerns and exercise the version negotiation mechanisms.  The only change is a  <ins> tweak to key derivation inputs to enforce full key separation.  Any endpoint that supports two versions needs to implement version negotiation to protect against downgrade attacks. </ins> 2.


6.  QUIC version 2 introduces no changes to the security or privacy properties of QUIC version 1. attacks, but downgrades have no security implications, as the version properties are identical. <del> 7. </del>  This document requests that IANA add the following entry to the QUIC version registry:

One way to
I have a feeling you'll need to say that this "updates" HTTP/3.
on slack some are saying we should roll a new h3 ALPN for running over quicv2. I cannot quite follow the argument but this is a better venue for the discussion.
You definitely need a new specification, because a different QUIC version might not be suitable. You either say: h3 can be used with QUICv2, or h3q2 (or whatever new string you like) identifies HTTP/3 when running over QUICv2. There are lots of arguments as to why you might choose to do one or the other.
I'm swayed more toward a new ALP.N at the moment
FWIW we painted ourselves into this corner. We punting on the problem and simply tied H3 to v1. Now we are actively trying to solve VN we might be able to pay back the tech debt. For example, a document that updates H3 to say that it can work over versions compatible with v1. Incompatible versions could still need to defined as a new application mapping,
Whatever we do, I think we need to ensure that servers can give sufficient information to clients via Alt-Svc so that the client can pick a compatible version (if any) and avoid VN. This could, then, be solved via Alt-Svc layer or via ALPN, but I think this is any important property.
Well "avoiding VN" is only important to the extent that we can't do compatible VN.
I think we want to allow the existence of a server that only supports v2 and servers that only support v1.... and clients that only support v2 and clients that only support v1. Given this, there will be client : server pairs which do not support any mutually compatible options. It seems like it would be desirable for clients to be able to deduce this from Alt-Svc without needing to see the QUIC connection to the server fail?
Oh, and this text from the HTTP/3 docs is probably relevant:

6. <ins> This version of QUIC provides no change from QUIC version 1 relating to the capabilities available to applications.  Therefore, all Application Layer Protocol Negotiation (ALPN) (RFC7301) codepoints specified to operate over QUICv1 can also operate over this version of QUIC. 7. </ins> QUIC version 2 introduces no changes to the security or privacy properties of QUIC version 1. attacks, but downgrades have no security implications, as the version properties are identical.  <ins> 8. </ins> This document requests that IANA add the following entry to the QUIC version registry:


Note that "version 2" is an informal name for this proposal that indicates it is the second standards-track QUIC version.  The <del> protocol specified here will receive a version number other than 2 from IANA. Discussion of this work is encouraged to happen on the QUIC IETF mailing list <quic@ietf.org> or on the GitHub repository which contains the draft: <https://github.com/quicwg/quic-v2>. </del>  1. 3. QUIC version 2 endpoints MUST implement the QUIC version 1 <del> specification as described in QUIC, QUIC-TLS, and RFC9002.  However, the following differences apply in version 2. </del>  3.1. The Version field of long headers is 0x709a50c4.  3.2. All version 2 long header packet types are different.  The Type field version.  Endpoints have no need to generate the keying material that would allow them to decrypt or authenticate these packets. <del> If the server's version_information transport parameter does not contain a Chosen Version field equivalent to the version in the server's Handshake packet headers, the client MUST terminate the connection with a VERSION_NEGOTIATION_ERROR. </del> The client MUST NOT send 0-RTT packets using the negotiated version, even after processing a packet of that version from the server. Servers can apply original version 0-RTT packets to a connection

, ,
It would be nice to have the references use a consistent format (e.g. all having a name instead of the RFC number for some)
OK, I've only left document number references where the subject is indicated beforehand, e.g. Alt-Svc {{?RFC7838}}
fixed by
Draft currently states: This repeats the QUIC VN document, should we remove it?
Yes, good catch.
fixed by
The draft currently says: Could we add a note to be removed by the RFC editor that clarifies whether or not we're going to change the version number before publication or not?
fixed by
The abstract currently contains: I'm pretty sure the second one won't be included, but there's no note saying so. I don't know if the first one is meant to stay. Can we add a note to make this explicit? Markdown can do it for you for the second one.
Actually the second note can be removed entirely because it repeats the paragraph that's autogenerated.
Thanks!

Note that "version 2" is an informal name for this proposal that indicates it is the second standards-track QUIC version.  The  <ins> protocol specified here uses a version number other than 2 in the wire image. </ins> 1. 3. QUIC version 2 endpoints MUST implement the QUIC version 1  <ins> specification as described in QUIC, QUIC-TLS, and QUIC-LOSSRECOVERY. However, the following differences apply in version 2. </ins> 3.1. The Version field of long headers is 0x709a50c4. <ins> This version number will not change in subsequent versions of this draft, unless there is a behavior change that breaks compatibility. </ins> 3.2. All version 2 long header packet types are different.  The Type field version.  Endpoints have no need to generate the keying material that would allow them to decrypt or authenticate these packets.  The client MUST NOT send 0-RTT packets using the negotiated version, even after processing a packet of that version from the server. Servers can apply original version 0-RTT packets to a connection


Retry as QUIC version 1.  After switching to a negotiated version after a Retry, the server MUST include the relevant transport parameters to validate that the server sent the Retry and the <del> connection IDs used in the exchange, as described in QUIC.  Note that the version of the first Initial and the subsequent Retry are not authenticated by transport parameters. </del>  The server SHOULD start sending its Initial packets using the negotiated version as soon as it decides to change.  Before the

NAME verbally approved.
Draft currently states: Is this true? The client sends this as its Chosen Version right?
I don't think so? If the client receives a v1 Retry and then chooses to connect via v2 for some reason, that won't break the transcript.
The "for some reason" doesn't make sense to me here. If the client follows the normative language in this document and in QUIC VN, it won't magically switch to v2 after receiving a v1 retry - it will instead send a second v1 initial which will contain the retry token and also . Also, while we're at it, what is the "subsequent Retry" here? Can you write up a packet diagram to explain the flow you have in mind? (on this issue not in the draft)
Ah, I'd forgotten that in 4.1 we validate the version in the Retry token. I'll delete the sentence.

Retry as QUIC version 1.  After switching to a negotiated version after a Retry, the server MUST include the relevant transport parameters to validate that the server sent the Retry and the  <ins> connection IDs used in the exchange, as described in QUIC. </ins> The server SHOULD start sending its Initial packets using the negotiated version as soon as it decides to change.  Before the


parameters to validate that the server sent the Retry and the connection IDs used in the exchange, as described in QUIC. <del> The server SHOULD start sending its Initial packets using the negotiated version as soon as it decides to change.  Before the server is able to process transport parameters from the client, it might need to respond to Initial packets from the client.  For these packets the server uses the original version. Once the client has processed a packet using the negotiated version, it SHOULD send subsequent Initial packets using that version.  The server MUST NOT discard its original version Initial receive keys until it successfully processes a packet with the negotiated version. Both endpoints MUST send Handshake or 1-RTT packets using the </del>  negotiated version.  An endpoint MUST drop packets using any other version.  Endpoints have no need to generate the keying material that would allow them to decrypt or authenticate such packets.

pending the discussion on the list.
Let's assume the current scenario: the client sends and the server decides to do compatible VN v1-to-v2. Then the server send its ServerHello in an INITIAL at v1 (the draft explicitly allows this by making it a SHOULD and not a MUST: ). At this point, there have only been QUICv1 packets exchanged. So the client can install handshake send keys for either version, but it is supposed to meet this requirement: even though the client doesn't yet know what the negotiated version is. We have text in the right direction: but that's not quite enough, we need to explain that the client learns about the version switch form the long headers and then validates it when it receives the server's ChosenVersion
Since we've closed , let me reiterate a test case here that we need to make sure is handled by the resolution of this issue: Client sends an INITIAL(ClientHello) where LongHeaderVersion=v1, ChosenVersion=v1, and OtherVersions=v1,v2 Client receives server INITIAL(ServerHello) where LongHeaderVersion=v1 Client receives server HANDSHAKE(EncryptedExtensions) where LongHeaderVersion=v1, ChosenVersion=v2, and OtherVersions=v1,v2
Shouldn't the server have the LongHeaderVersion=v2 on its HANDSHAKE packets, once it has upgraded the connection to the negotiated version?
Yes the server isn't supposed to do that (sorry I should have made the clear). The question is: what should the client do when it sees the server misbehaving like this?
If we're in agreement the server is misbehaving, then I would suggest the client close the connection.
I'm broadly OK with the shape of this change. David's suggestion might have made sense earlier in the process, but I don't think that it works now. I'm not sure that it worked ever, but I'm less inclined to get precious about that sort of thing than I used to.LGTM but please wait until we've agreed on what to do in the VN draft before mergingWorks for me. Crypto frames sing new VN makes sense.

parameters to validate that the server sent the Retry and the connection IDs used in the exchange, as described in QUIC.  <ins> The server cannot send CRYPTO frames until it has processed the client's transport parameters.  The server MUST send all CRYPTO frames using the negotiated version. The client learns the negotiated version by observing the first long header Version field that differs from the original version.  If the client receives a CRYPTO frame from the server in the original version, that indicates that the negotiated version is equal to the original version. Before the server is able to process transport parameters from the client, it might need to respond to Initial packets from the client. For these packets, the server uses the original version. Once the client has learned the negotiated version, it SHOULD send subsequent Initial packets using that version.  The server MUST NOT discard its original version Initial receive keys until it successfully processes a Handshake packet with the negotiated version. Both endpoints MUST send Handshake and 1-RTT packets using the </ins> negotiated version.  An endpoint MUST drop packets using any other version.  Endpoints have no need to generate the keying material that would allow them to decrypt or authenticate such packets.


13.3. <del> QUIC endpoints use Explicit Congestion Notification (ECN) RFC3168 to detect and respond to network congestion.  ECN allows a network node to indicate congestion in the network by setting a codepoint in the IP header of a packet instead of dropping it.  Endpoints react to </del>  congestion by reducing their sending rate in response, as described in QUIC-RECOVERY. 13.3.1. <del> On receiving a QUIC packet with an ECT or CE codepoint, an endpoint that can access the ECN codepoints from the enclosing IP packet increases the corresponding ECT(0), ECT(1), or CE count, and includes these counts in subsequent ACK frames (see processing-and-ack and frame-ack). </del>  A packet detected by a receiver as a duplicate does not affect the receiver's local ECN codepoint counts; see (security-ecn) for If an endpoint receives a QUIC packet without an ECT or CE codepoint in the IP packet header, it responds per processing-and-ack with an <del> ACK frame without increasing any ECN counts.  Similarly, if an endpoint does not have access to received ECN codepoints, it does not increase ECN counts. </del>  Coalesced packets (see packet-coalesce) mean that several packets can share the same IP header.  The ECN counter for the ECN codepoint Each endpoint independently verifies and enables use of ECN by setting the IP header ECN codepoint to ECN Capable Transport (ECT) <del> for the path from it to the other peer.  Even if ECN is not used on the path to the peer, the endpoint MUST provide feedback about ECN markings received (if accessible). </del>  To verify both that a path supports ECN and the peer can provide ECN <del> feedback, an endpoint MUST set the ECT(0) codepoint in the IP header of all outgoing packets RFC8311. </del>  If an ECT codepoint set in the IP header is not corrupted by a network device, then a received packet contains either the codepoint or more ACK Blocks.  ACK Blocks are ranges of acknowledged packets. If the frame type is 0x03, ACK frames also contain the sum of QUIC packets with associated ECN marks received on the connection up until <del> this point. </del>  QUIC acknowledgements are irrevocable.  Once acknowledged, a packet remains acknowledged, even if it does not appear in a future ACK

Implementations are free to enable sending or not. 2, Implementations MAY read the ECN code points if they can and send ECN ACKs. Implementations MUST accept the 0x03 ACK type and if they are sending ECN SHOULD use the ECN section. I recognize that some people want to have stronger language here, based on this discussion I think this is where we are. I'll defer to the chairs to judge whether more is needed here and can change the PR as required.
I took the discussion to be "MAY" but obviously this is easily changed if the chairs judge consensus otherwise.

13.3.  <ins> QUIC endpoints can use Explicit Congestion Notification (ECN) RFC3168 to detect and respond to network congestion.  ECN allows a network node to indicate congestion in the network by setting a codepoint in the IP header of a packet instead of dropping it.  Endpoints react to </ins> congestion by reducing their sending rate in response, as described in QUIC-RECOVERY. 13.3.1.  <ins> On receiving a QUIC packet with an ECT or CE codepoint, an ECN- enabled endpoint that can access the ECN codepoints from the enclosing IP packet increases the corresponding ECT(0), ECT(1), or CE count, and includes these counts in subsequent ACK frames (see processing-and-ack and frame-ack).  Note that this requires being able to read the ECN codepoints from the enclosing IP packet, which is not possible on all platforms. </ins> A packet detected by a receiver as a duplicate does not affect the receiver's local ECN codepoint counts; see (security-ecn) for If an endpoint receives a QUIC packet without an ECT or CE codepoint in the IP packet header, it responds per processing-and-ack with an  <ins> ACK frame without increasing any ECN counts.  if an endpoint does not implement ECN support or does not have access to received ECN codepoints, it does not increase ECN counts. </ins> Coalesced packets (see packet-coalesce) mean that several packets can share the same IP header.  The ECN counter for the ECN codepoint Each endpoint independently verifies and enables use of ECN by setting the IP header ECN codepoint to ECN Capable Transport (ECT)  <ins> for the path from it to the other peer.  Even if not setting ECN codepoints on packets it transmits, the endpoint SHOULD provide feedback about ECN markings received (if accessible). </ins> To verify both that a path supports ECN and the peer can provide ECN  <ins> feedback, an endpoint sets the ECT(0) codepoint in the IP header of all outgoing packets RFC8311. </ins> If an ECT codepoint set in the IP header is not corrupted by a network device, then a received packet contains either the codepoint or more ACK Blocks.  ACK Blocks are ranges of acknowledged packets. If the frame type is 0x03, ACK frames also contain the sum of QUIC packets with associated ECN marks received on the connection up until  <ins> this point.  QUIC implementations MUST properly handle both types and, if they have enabled ECN for packets they send, they SHOULD use the information in the ECN section to manage their congestion state. </ins> QUIC acknowledgements are irrevocable.  Once acknowledged, a packet remains acknowledged, even if it does not appear in a future ACK


17.6. <del> A Handshake packet uses long headers with a type value of 0x3.  It is </del>  used to carry acknowledgments and cryptographic handshake messages from the server and client.

Handshake and Retry have the same type number in the text; assuming the table is correct, this aligns the text with the table.

17.6.  <ins> A Handshake packet uses long headers with a type value of 0x2.  It is </ins> used to carry acknowledgments and cryptographic handshake messages from the server and client.


7.7. A sender becomes idle if it ceases to send data and has no bytes in <del> flight.  A sender's congestion window MUST not increase while it is </del>  idle. When sending data after becoming idle, a sender MUST reset its

I think "MUST NOT" was the intention of , not "MUST not".
NAME you can just merge these.

7.7. A sender becomes idle if it ceases to send data and has no bytes in  <ins> flight.  A sender's congestion window MUST NOT increase while it is </ins> idle. When sending data after becoming idle, a sender MUST reset its


Network devices that corrupt or apply non-standard ECN markings might result in reduced throughput or other undesirable side-effects.  To reduce this risk, an endpoint uses the following steps to verify the <del> counts it receives in an ACK frame.  Counts MUST NOT be verified if the ACK frame does not increase the largest received packet number at the endpoint. </del>  The total increase in ECT(0), ECT(1), and CE counts MUST be no smaller than the total number of QUIC packets sent with an ECT succeeds, the local reference counts MUST be increased to match the counts in the ACK frame.  Upon successful verification, an endpoint continues to set ECT codepoints in subsequent packets with the expectation that the path is ECN-capable.

There's probably slightly better phrasing for the packet number clause, so feel free to suggest something.
Jana's talked me through this and now I realize that this is broken in a larger sense. As we've previously discussed, any time an acknowledgement is dropped, ECN validation MAY fail.
After more discussion, I agree that this does fix the problem. I think the text could be moved to a better location, but I'm fine with this for now.
"Processed in different order than it was sent" is a bit vague. If there is reordering you don't know which frame is the one that is out of order. There needs to be a clear selection criteria such as not processing a frame in packet with a PN lower than a previously processed.
NAME I've reworded and moved the text. See what you think.
NAME : I've incorporated your comments.
This still LGTM.
Thanks for considering my input.
This is implicitly assumed, and, as NAME points out in , not doing so can cause undesired outcomes. There should be normative text in the transport draft requiring this behavior.
So the situation is that if one so far have ACKed: 1,2,3,6,7. Then if 4,5 shows up at the receiver and it is going to ACK those, it must at least send an ACK that contains 4,5 and 7, thus likely acking 4-7? It should not be allowed to send an ACK saying 4, 5 in the above situation as that doesn't indicate the receiver total progress, i.e. all the way to 7? I think requiring Largest Acknowledge to always indicate highest solves some issues and likely simplifies a lot of implementations. But it may result in larger ACK frames as one will have include the full current state between the largest Acknowledged and so far into the past PNs that you need to go. In severe re-ordering cases that could be a lot. Will this cause cause the ACK to be to large to include? Especially maybe in connections with a large delay bandwidth product going full steam encountering a serious hick up in the network. For example if an ACK is required to ack packet 4000 + 1E9 and you have 500 gaps that has arrived the last RTT/4 and really should be included. Resulting in an ACK frame that is at least 1000 bytes large, possibly bigger.
There are a few things this precludes, and we we should understand those before doing this. 1) A very limited implementation(ie: hardware) can't always send only one ACK block without giving up on reordered packets. I don't have such an implementation, but at some point I remember discussing this idea with people who seemed interested in it. 2) One cannot do multipath with QUIC v1 and it means the multipath design will have to use a PN space per path, as described in Christian's draft: URL I think that's likely the right choice for other reasons, but I'm hesitant to make that decision now. 3) An RTT sample can only be taken based on the largest acked. Therefore, if there is a large amount of reordering(ie: 1RTT), you don't get any RTT samples for an RTT. If we care about this, we can probably solve it a different way in the recovery draft, but that likely means using ack delay sometimes and not others. In regards to Martin's comment, I thought we already had text that said ACKs with lower packet numbers than the largest ACK packet number should be ignored, since they're old?
NAME regarding your question. "In regards to Martin's comment, I thought we already had text that said ACKs with lower packet numbers than the largest ACK packet number should be ignored, since they're old?" At least when it comes to ECN, the editors have been working hard to reformulate which has resulted in that there is nothing that applies this from the PN increasing for the ACKs. So to solve the ECN part, I think (re-)introducing that aspect into the text is the simpliest fix for ECN. But there clearly are other aspects here.
NAME The problem doesn't go away if you ignore acks that are lower than largest_acked. The problem is that the receiver sent the acks in the wrong order because packets were received in the wrong order, but ECN counts are going up. But you raise good points. This is a corner case. I think that with the current spec, under these conditions, ECN gets turned off since validation fails. I think that's a reasonable outcome, and I'm fine with it. NAME
ECN Validation as I currently understand it will not fail if the sender to receiver reordering happens as long as the ACKs from the receiver to sender are not reordered. So to my understanding what is missing is a requirement for the sender to no process verfication for out of order ACKs. It will not fail if the largest acknowledge is not increasing as the comparison is done on number of newly ACKed packets versus counts change. The current sentence in Section 13.3.2 (-17): "Counts MUST NOT be verified if the ACK frame does not increase the largest received packet number at the endpoint." Which I interpret to mean that what PN the ACK reference (sender-receiver direction), rather than the PN of the receiver to sender direction. Can NAME or NAME fix that?
I think is enough to address the original problem, so I'd like to close this issue. I think and are enough. NAME sound ok?
Yes, the ECN related issue is resolved. What I don't know if it is resolved fully is the implementation requirements is that a sender MUST be capable of handling an ACK frame with Largest Acknowledged that is smaller than highest received? From my perspective there are good and valid arguments why this may be required, however I think consensus needs to be established on that.
NAME I am not sure if I'm following the context, but my understanding is that a sender MUST be capable of that, because we allow an endpoint to simply retransmit the payload of a packet that is being deemed lost; see .
Just a stray thought: is this requirement really strictly needed? It would complicate trasnmitters that split work into multiple processing units which might not be fully synced on the latest ACK'ed.
NAME what NAME says. Also, a sender needs to be able to simply deal with reordering on the ack path. Did you mean something else?
My concern was primarily about the clearness of this behavior in the specification text. In transport I find the following which indicates this but are not explicit. : To limit receiver state or the size of ACK frames, a receiver MAY limit the number of ACK Ranges it sends. : Largest Acknowledged: A variable-length integer representing the largest packet number the peer is acknowledging; this is usually the largest packet number that the peer has received prior to generating the ACK frame. I think there are strong hints, with the above "usually the largest" indicating that it is not always. I would have made this explicit in 19.3, but then I prefer being more explicit than not. I think it is possible interop issue point. Anywhere else this is more explicit? (I have read github master version) NAME I think there are strong points for allowing an ACK frame to acknowledge only a part of the range between highest received and confirmed to be have been ACKed. The two main reasons I see. high rate flows suffering an packet loss burst so that the number of ACK ranges becomes to large to fit a single QUIC packet. Low complexity receivers ACKing a single range of received packets and doing this for reordered packets.
NAME As suggested by NAME in , might be the correct place. I am advocating for describing the design principle the PR, but we might (or might not) be interested in expanding how ACK could look like.
So results in certain implications, that an ACK could arrive that addresses older state, thus resulting in acknowledging some PNs that was previously unacknowledged. As 13.2 is about retransmissions, I think there are other desing principle aspects of ACKs that probably should be covered, but then earlier in 13.1.
We're in the process of making our implementation accept smaller largest_acked values, so I'm wonder if we're any closer to consensus(one way or the other) on this issue?
I think this is mostly addressed and what's left is OBE. There's text in the draft now that says: "Processing counts out of order can result in verification failure. An endpoint SHOULD NOT perform this verification if the ACK frame is received in a packet with packet number lower than a previously received ACK frame. Verifying based on ACK frames that arrive out of order can result in disabling ECN unnecessarily." This would be adequate, but there's other text (thanks to ) that says old ACKs can be resent. I think we simply add a note about that in the para above, which should be adequate.
Discussed in London: NAME to prepare a PR for those remaining bits
NAME any progress here?
I think the conclusion here is close with no further action, but it'd be good for NAME to confirm.
I've added , which I believe addresses what's left of this issue.
Note that we agreed that proposal-ready would be used when there were approvals for PRs (or at least apparent agreement, as determined by editors).
NAME : Yeah, my bad.
This gets fixed by , so marking this issue as well.
Fixed by .
I really don't like adding a hard coupling like this to the design. I would be comfortable with a SHOULD NOT, explaining that if you don't do that, you might disable ECN unnecessarily in some rare cases.

Network devices that corrupt or apply non-standard ECN markings might result in reduced throughput or other undesirable side-effects.  To reduce this risk, an endpoint uses the following steps to verify the  <ins> counts it receives in an ACK frame. </ins> The total increase in ECT(0), ECT(1), and CE counts MUST be no smaller than the total number of QUIC packets sent with an ECT succeeds, the local reference counts MUST be increased to match the counts in the ACK frame. <ins> Processing counts out of order can result in verification failure. An endpoint SHOULD NOT perform this verification if the ACK frame is received in a packet with packet number lower than a previously received ACK frame.  Verifying based on ACK frames that arrive out of order can result in disabling ECN unnecessarily. </ins> Upon successful verification, an endpoint continues to set ECT codepoints in subsequent packets with the expectation that the path is ECN-capable.


The key and IV for the packet are computed as described in protection-keys.  The nonce, N, is formed by combining the packet <del> protection IV with the packet number.  The 64 bits of the </del>  reconstructed QUIC packet number in network byte order are left- padded with zeros to the size of the IV.  The exclusive OR of the padded packet number and the IV forms the AEAD nonce. 12.3. <del> The packet number is an integer in the range 0 to 2^62-1.  Where present, packet numbers are encoded as a variable-length integer (see integer-encoding).  This number is used in determining the cryptographic nonce for packet protection.  Each endpoint maintains a separate packet number for sending and receiving. </del>  Version Negotiation (packet-version) and Retry packet-retry packets do not include a packet number. 17.1. <del> Packet numbers in long and short packet headers are encoded in 1 to 4 bytes.  The number of bits required to represent the packet number is reduced by including the least significant bits of the packet number. </del>  The encoded packet number is protected as described in Section 5.4 of QUIC-TLS.

In Section 12.3, the transport specs says: But in both 17.2 (Long Header) and 17.3 (Short Header), Packet Number field in the packet is noted as the following format: which suggest it isn't variable-length integers. Can we get some clarification regarding this? Thank you!
Section 17.2/17.3 is correct -- PNs are not encoded using the varint form in Sec 16.

The key and IV for the packet are computed as described in protection-keys.  The nonce, N, is formed by combining the packet  <ins> protection IV with the packet number.  The 62 bits of the </ins> reconstructed QUIC packet number in network byte order are left- padded with zeros to the size of the IV.  The exclusive OR of the padded packet number and the IV forms the AEAD nonce. 12.3.  <ins> The packet number is an integer in the range 0 to 2^62-1.  This number is used in determining the cryptographic nonce for packet protection.  Each endpoint maintains a separate packet number for sending and receiving. Packet numbers are limited to this range because they need to be representable in whole in the Largest Acknowledged field of an ACK frame (frame-ack).  When present in a long or short header however, packet numbers are reduced and encoded in 1 to 4 bytes, see packet- encoding). </ins> Version Negotiation (packet-version) and Retry packet-retry packets do not include a packet number. 17.1.  <ins> Packet numbers are integers in the range 0 to 2^62-1 (packet- numbers).  When present in long or short packet headers, they are encoded in 1 to 4 bytes.  The number of bits required to represent the packet number is reduced by including the least significant bits of the packet number. </ins> The encoded packet number is protected as described in Section 5.4 of QUIC-TLS.


setting this timer, implementations are cautioned that the new path could have a longer round-trip time than the original.  A value of three times the larger of the current Probe Timeout (PTO) or the <del> initial timeout (that is, kInitialRtt*2) as defined in QUIC-RECOVERY </del>  is RECOMMENDED.  That is: Note that the endpoint might receive packets containing other frames

1789:Retransmittion Timeout (RTO) as defined in {{QUIC-RECOVERY}} is RECOMMENDED. 2182:(RTO) interval as defined in {{QUIC-RECOVERY}}. 2253:draining state before the packets arrive. If a peer could timeout within an RTO
Also, we have to set a minimum for the path validation timout. Suggest initial timeout(kInitiaRtt2)3 = 600ms. That makes this a design issue.
LG, one suggestion.

setting this timer, implementations are cautioned that the new path could have a longer round-trip time than the original.  A value of three times the larger of the current Probe Timeout (PTO) or the  <ins> initial timeout (that is, 2*kInitialRtt) as defined in QUIC-RECOVERY </ins> is RECOMMENDED.  That is: Note that the endpoint might receive packets containing other frames


If the Destination Connection ID is zero length and the packet matches the address/port tuple of a connection where the host did not require connection IDs, QUIC processes the packet as part of that <del> connection.  Endpoints MUST drop packets with zero-length Destination Connection ID fields if they do not correspond to a single connection. </del>  Endpoints can send a Stateless Reset (stateless-reset) for any packets that cannot be attributed to an existing connection.  A

How could this happen? The recipient knows if a given tuple is unique, so it shouldn't issue zero-length DCIDs for that tuple.
Yeah, it is more like recipients MUST not issue 0-length CID's in that case. And MUST drop non-issued CID's.
I remember why was added. If you had one connection on those addresses, time passes and a NAT rebinding moves another connection to that same path, then you get problems. That a nonsensical situation and better addressed as suggested.

If the Destination Connection ID is zero length and the packet matches the address/port tuple of a connection where the host did not require connection IDs, QUIC processes the packet as part of that  <ins> connection.  Endpoints SHOULD either reject connection attempts that use the same addresses as existing connections, or use a non-zero- length Destination Connection ID so that packets can be correctly attributed to connections. </ins> Endpoints can send a Stateless Reset (stateless-reset) for any packets that cannot be attributed to an existing connection.  A


off between resource commitment and overhead when determining how large a limit is advertised. <del> A receiver MAY use an autotuning mechanism to tune the frequency and </del>  amount of advertised additional credit based on a round-trip time estimate and the rate at which the receiving application consumes <del> data, similar to common TCP implementations. </del>  If a sender runs out of flow control credit, it will be unable to send new data and is considered blocked.  It is generally considered

This doesn't need normative text. This adds NAME recommendation about only sending flow control frames when there are other frames to send. Though I added another note about the peer being explicitly blocked, which I think is a useful transition to the next paragraph.
I don't think so. Flow control credits can go out with acknowledgments. The advice is there so that you don't have the MAX_DATA frame go out immediately, with a delayed ACK going out 20ms later. They can both go out together.
Bundling frames definitely makes sense, but I don’t think we need the “or when a peer is blocked” part.
Your assertion being that a blocked peer will already have to live with being blocked for a round trip, so the gain isn't worth documenting?
I’m saying that you shouldn’t let your peer become blocked under normal circumstances. I just noticed that in the corner case where the peer is blocked because the application is consuming data too slowly, it actually makes sense to not bundle the flow control update. So I guess the text is fine as is.
The text just says that sending more packets causes more packets to be sent. That is kind of obvious. Also, sending flow control with other frames isn't working if there isn't anything to ACK or anything to send once the application gets around to drain its buffer and inform transport about more credits.
Looks fine, one suggestion.
In light of the first paragraph which says that I can do whatever I want, what is the purpose of this MAY? It seems like you should either recommend that people do this or just remove the normative language.
I agree the MAY isn't doing anything here. The one thing I think should be encouraged is bundling flow control updates with other data instead of sending them in their own packets, since the frames themselves are very small.
It takes one RTT for the sender to learn that the receiver is blocked and to grant additional flow control credit, so this will lead to frequent stalls of the connection, if one receiver has nothing else to send.

off between resource commitment and overhead when determining how large a limit is advertised.  <ins> A receiver can use an autotuning mechanism to tune the frequency and </ins> amount of advertised additional credit based on a round-trip time estimate and the rate at which the receiving application consumes  <ins> data, similar to common TCP implementations.  As an optimization, sending frames related to flow control only when there are other frames to send or when a peer is blocked ensures that flow control doesn't cause extra packets to be sent. </ins> If a sender runs out of flow control credit, it will be unable to send new data and is considered blocked.  It is generally considered


On receiving a PATH_CHALLENGE frame, an endpoint MUST respond immediately by echoing the data contained in the PATH_CHALLENGE frame <del> in a PATH_RESPONSE frame.  However, because a PATH_CHALLENGE might be sent from a spoofed address, an endpoint MUST limit the rate at which it sends PATH_RESPONSE frames and MAY silently discard PATH_CHALLENGE frames that would cause it to respond at a higher rate. </del>  To ensure that packets can be both sent to and received from the peer, the PATH_RESPONSE MUST be sent on the same path as the

Implementations can do this anyway, so we're not getting much from the recommendation. And we already have good limits on what can be sent (including PATH_RESPONSE) in the migration section.
This can lead to amplification attack if not careful.
NAME how can this lead to amplification?
If an endpoint seeing a challenge uses the opportunity to discover if its preferred MTU is supported by padding the response (as opposed to the challenge) even if the challenge packet is small. Since this might fail, it like will also send a small response after a delay or after a new challenge if it doesn't get an ACK before that. A defence could be to ensure that challenges are no larger than, say twice, response.
An endpoint may also optimistically bundle all kinds of other data in a response. Even with 1200 bytes, this can be much larger than a small challenge packet without considering PMTU discovery at all.
I think I raised this issue quite a while ago this is the reason the limit was introduced, although I didn't formulate the exact counter measure.
The counter measure we have against amplification is the initial congestion window. We won't send more than that. That's higher than the x3 we have during the handshake, but I think that's a reasonable balance, considering that the attacker in this context has to spend a considerable amount of effort. Yes, this is a policy question, but I'm happy with it. (Though we should probably highlight this when asking for review.)
It's pretty hard to understand what the normative force of this is, given that it doesn't explain what the limit is. I think there's actually a simple rule we should propose, which is one PATH_CHALLENGE frame per packet (with others to be ignored). Given that we require duplicate suppression at the packet level, that will have an amplification factor of 1:1, which you can get by a variety of other mechanisms.
The relevant existing guideline is the 3x limit we have on handshake amplification. Given that CHALLENGE/RESPONSE doesn't inherently include any amplification other than what might result from different connection ID lengths on packets, I don't think that we need to do much special. That is, the text in 9.3.1 is fine, even if the limits are different. I'm OK with striking everything from "However" onward here.

On receiving a PATH_CHALLENGE frame, an endpoint MUST respond immediately by echoing the data contained in the PATH_CHALLENGE frame  <ins> in a PATH_RESPONSE frame. </ins> To ensure that packets can be both sent to and received from the peer, the PATH_RESPONSE MUST be sent on the same path as the


acknowledgement is received that establishes loss or delivery of packets. <del> If a threshold number of consecutive PTOs have occurred (pto_count is more than kPersistentCongestionThreshold, see cc-consts-of-interest), the network is considered to be experiencing persistent congestion, and the sender's congestion window MUST be reduced to the minimum congestion window. </del>  7.6. Reduction in congestion window when a new loss event is detected. The RECOMMENDED value is 0.5. <del> Number of consecutive PTOs after which network is considered to be experiencing persistent congestion.  The rationale for this threshold is to enable a sender to use initial PTOs for aggressive probing, similar to Tail Loss Probe (TLP) in TCP TLP RACK.  Once the number of consecutive PTOs reaches this threshold - that is, persistent congestion is established - the sender responds by collapsing its congestion window to kMinimumWindow, similar to a Retransmission Timeout (RTO) in TCP RFC5681.  The RECOMMENDED value for kPersistentCongestionThreshold is 2, which is equivalent to having two TLPs before an RTO in TCP. </del>  7.9.2.

I've reworded and I think the wording is better now. I'll merge, but do comment if you think the wording needs fixing.
Consider the following sequence of packets being sent In our old loss recovery code (before unifying TLP and RTO, ), we used the following logic for determining if an RTO was not spurious, which would then lead to collapse of the congestion window: In the example above would be packet 14. This means that to count as a verified RTO, an ACK must acknowledge 15 or 16, but not any packets smaller or equal than 14. With , we now collapse the congestion window when is larger than 2 and we receive an ACK which leads us to declare any packet lost. In the example above this means any ACK received after sending packet 15 which declares a packet lost would suffice. Even worse, this logic already triggers if we receive the ACK immediately after sending 15, i.e. when the peer didn't even have a chance to receive it. This seems a lot more aggressive than what we had before before. Is this intentional?
This is unintentional. I belIeve Jana is intending to fix this in PR , so please take a look at that.
If I understand correctly, is a fix for and only makes the description of the constant and the pseudo code consistent.
I believe the text is now correct, but the pseudocode is still incorrect in the way you describe. I think we should introduce a largestsentbefore_congestion variable as a replacement, but I'm open to other solutions.
I'm removing design. I consider this a bug fix, but still very important.
See which I believe fixes the text.
I've been using to mark things that will result in changes that affect implementations. This would seem to fit that description. Whether you consider it worth discussing is different. If it isn't worth discussing, maybe it will just be fixed by and everything will be fine without discussion in Tokyo. WIthout the label, this won't make the change log, and that might be a problem.
Fair point, I think fixes the text, but I'll re-label this as design to ensure it's included in the changelogs.
The text says Similar text exists for the description of kPersistentCongestionThreshold. We actually only collapse the congestion window when receiving an ACK for a probe packet, and only if this ACK leads us to declare any packet(s) lost. Specifically, this means that pto_count may grow larger than kPersistentCongestionThreshold, if no acknowledgements are received.
Good point. Sent .

acknowledgement is received that establishes loss or delivery of packets.  <ins> When an ACK frame is received that establishes loss after a threshold number of consecutive PTOs (pto_count is more than kPersistentCongestionThreshold, see cc-consts-of-interest), the network is considered to be experiencing persistent congestion, and the sender's congestion window MUST be reduced to the minimum congestion window (kMinimumWindow).  This response of collapsing the congestion window on persistent congestion is functionally similar to a sender's response on a Retransmission Timeout (RTO) in TCP RFC5681. </ins> 7.6. Reduction in congestion window when a new loss event is detected. The RECOMMENDED value is 0.5.  <ins> Number of consecutive PTOs required for persistent congestion to be established.  The rationale for this threshold is to enable a sender to use initial PTOs for aggressive probing, as TCP does with Tail Loss Probe (TLP) TLP RACK, before establishing persistent congestion, as TCP does with a Retransmission Timeout (RTO) RFC5681.  The RECOMMENDED value for kPersistentCongestionThreshold is 2, which is equivalent to having two TLPs before an RTO in TCP. </ins> 7.9.2.


To limit ACK Blocks to those that have not yet been received by the sender, the receiver SHOULD track which ACK frames have been <del> acknowledged by its peer.  Once an ACK frame has been acknowledged, the packets it acknowledges SHOULD NOT be acknowledged again. </del>  Because ACK frames are not sent in response to ACK-only packets, a receiver that is only sending ACK frames will only receive

Thanks everyone, this is much better.
From NAME I think that the advice here is that ranges are dropped when all ACKs for all packets in that range have been acknowledged. Or something along those lines. Maybe: Though that seems clumsy. Better words would be appreciated.
Maybe "Endpoints SHOULD not acknowledge packets for which it has already received acknowledgement of acknowledgements, except where this would create unnecessary gaps in the encoded ACK frame." Not ideal, I know/
I think this is connected to in an interesting way. The question that arises is if one MUST include all ACK state between highest received, and the lower PN that needs to be ACKed (as it is newly arrived due to reordering). An alternative would be to explicitly allow GAPs for packets that has been received and where the reception's ACKs has been ACKed. But, I guess that results in interesting bookkeeping chores in the implementations.
Agreed the wording is too strong. Take a look at PR

To limit ACK Blocks to those that have not yet been received by the sender, the receiver SHOULD track which ACK frames have been  <ins> acknowledged.  The receiver SHOULD exclude already acknowledged packets from future ACK frames whenever these packets would unnecessarily contribute to the ACK frame size. </ins> Because ACK frames are not sent in response to ACK-only packets, a receiver that is only sending ACK frames will only receive