-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Renumber packet types and invert Connection ID Flag #956
Conversation
This commit makes the following changes: - Renumber long header packet types to count from 0x7f downwards, rather than from 0x01 upwards - Renumber short header packet types to count from 0x1f downward, rather than from 0x01 upward - Invert the sense of the Connection ID Flag in the short header packets, to become an Omit COnnection ID Flag The purpose of the changes is to make it possible to easily demultiplex QUIC and STUN packets running on a single UDP port, to enable peer to peer use of QUIC. They also enable demultiplexing of WebRTC packets and QUIC packets on a single UDP port. Discussed in QUIC and AVTCORE working groups at IETF 100.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Colin. As you say, this is a fairly modest change, but I'd like to double check that this doesn't cause issues for people who are already deploying versions of QUIC that might be hard to run concurrent with these new codepoints.
That includes @janaiyengar and @dtikhonov at a minimum.
I recently implemented the header parsing logic for quic-go, such that it can handle both gQUIC and IETF QUIC. You might find my summary of the different formats for the type byte useful: https://docs.google.com/document/d/162BtfR84c6xTvAG6AaPK0dXSQXKahMrtJOXxNnpcwDw/edit?usp=sharing. The current packet header format has the nice property that it is possible to decide if the packet is a gQUIC or an IETF QUIC packet by just looking at the type byte. This is possible due to the following properties: for packets sent by the serverFor packets sent by the server the client already knows the QUIC version needed for parsing the packet, as soon as version negotiation is completed. Therefore, the only requirement here is that the type byte used for the Version Negotiation Packet in IETF QUIC is not used in gQUIC, and the type byte used for the gQUIC VNP is not used in IETF QUIC. for packets sent by the clientAll gQUIC packets have bits 0x80 and 0x40 unset, and currently IETF QUIC packets either have 0x80 set (for long headers) or 0x40 set (for short headers, if connection ID omission is not allowed, which I assume is what server implementations will do). |
I haven't looked at gQUIC, but does it matter that the "server wouldn't be able to distinguish between gQUIC and short header packets"? Can it tell from the initial long header packets if the flow is gQUIC or IETF QUIC? |
In order to do that, you would have to associate the packet with a flow, which would mean that the server would have to extract the connection ID from the header first. This might or might not be possible, depending on how we shift around the location of the connection ID. |
First, assume that you require a connection ID at the server. The general case for packets sent by clients in gQUIC is 0b00pp1000. The change to short headers in this PR makes the typical IETF QUIC type byte 0b00k111pp, though obviously we don't make any promises about those 1 octets (and we will probably want to grease them). One possible strategy we could pursue here is to disable greasing until we wean people off gQUIC. Or - perhaps better - negotiate greasing. Actually, I like that second idea, because it suits Colin's use case very nicely. |
@martinthomson: Right, I missed that part. Relying on bit 0x4 might be the solution here. In general, I don't think greasing should be negotiated (we should always grease as much as possible), but if that's the only way to make a transition possible, this wouldn't be a bad option. |
I wouldn't have suggested negotiation if not for this realtime case. There, they probably want us to avoid using certain values (blame RFC 7983). Negotiation would be a solution to that problem, and as long as the overwhelming majority of QUIC traffic greased, then it would all work out. Of course, they negotiate sessions and could limit greasing to a narrower range of values. |
Right – we likely want to grease by default, but have the ability to disable/limit greasing for certain flows where we know the greasing will conflict with other uses of the port. |
I did a write-up about this some time ago. I think this change will make it easier to differentiate between gQUIC and QUIC. Types 0x1F, 0x1E, and 0x1D would give us the following gQUIC interpretations, in order:
gQUIC public resets do not have two-byte packet numbers. Likewise, gQUIC version negotiation packets are unlikely to have two-byte packet numbers. |
I think this change doesn't change how difficult it is to support GQUIC and IETF QUIC at once. The fact we're not moving the connection ID really helps, since we can always lookup by connection ID first, and then if nothing is found, try to parse it as a handshake packet that creates a new connection. On the client side, the main issue would be version negotiation, since for every other packet, the client knows the version in use. This VN codepoint is not used in GQUIC, so we should be all set. But to pop the stack, I'm trying to walk through why the heuristics approach outlined in the draft isn't sufficient in practice. The negatives like not being able to run DTLS and QUIC at the same time on the same 5-tuple seem like non-issues. Can someone outline what the issues are that motivate this change? The issue of greasing is real. Unfortunately, I think we may need a way to communicate codepoints not to grease for WebRTC, GQUIC, and other future use cases. If a server is running GQUIC and IETF QUIC at once, then it is actually using all the codepoints, just for two different protocols, so the space is effectively being greased. |
It's possible that we can still grease even for cases where multiplexing with RTP is desired, we just might multiplex less. Would it help if I wrote up what I am considering specifying for greasing? |
@ianswett writes:
Could you please elaborate why you think that? And (emphasis added):
This is quite expensive compared to simply examining the packet header! One can also imagine a situation where a demultiplexer forwards packets to two separate (processes or machines) QUIC implementations: gQUIC and IETF QUIC. The demux would not have the associated state. The fallback to looking up a connection for each packet to determine which QUIC version it is should be used as last resort. I hope we can avoid it. |
I'm surprised this was merged already. The problem of stateless packet handling wasn't solved, since relying on bit 0x4 will not work as soon as we start greasing (or change anything else for the short headers). |
Agreed on this merging sooner than I expected. I realize we want to nail down the type byte, but I'm still not sure why we're doing this? @dtikhonov You seemed to think it made supporting both at once easier than before? Is that because all the new code points are either undefined or in practice unused in GQUIC? @martinthomson Yes, I think it would help to have a specific greasing proposal written up that deals with both coexistence of GQUIC and IETF QUIC, as well as IETF QUIC and WebRTC. |
When multiplexing, don’t grease the ranges being used by the protocols that you’re multiplexing with. You’re already exercising the ability to send packets using those bits.
Likely, yes |
@ianswett: The reason I think this change makes it easier is that some of the potential ambiguities no longer exist. The heuristics to tell one version from another using the new packet type numbering scheme based are described in my original post above. You state that you do not think this change make it easier to differentiate between packet types; I'd like to know why. |
Our server always requires connection id to be present on packets it receives, so the ambiguity you mention in your original post is not a problem. With the previous numbering scheme, on the server side, we can just look at the first two bits. If either is 1, then it's IETF QUIC, and if both are 0, it's GQUIC. In the new scheme, I can still check the first bit for the long header, and then I can check the nonce bit, and if it's that's 1, it must be IETF QUIC because the client never sends a diversification nonce. But I believe the nonce bit is the bit that would end up being the spin bit, which could start making things pretty tricky. It's probably worth thinking through what happens if two bits are reserved for measurement. |
I see. If one can assume that 0x40 (multipath) bit is never set in GQUIC, then this is indeed very easy. I did not make this assumption in my analyses to err on the conservative side.
Are you saying that the packet type in the short header would be narrower and occupy fewer than the currently-allocated low five bits? (I apologize for not being on top of this development.) |
That would be really unpleasant. What is the reason for inverting the Connection ID flag? |
Yes, the 0x40 bit is always 0, because we never deployed multipath. There's been quite a bit of discussion about the spin bit, including a new draft sent out today: The current proposal makes the type shorter, but the nonce bit would still always be 1 in the above proposal, so as long as no other bits are used for anything, we should still be able to use the plan of looking at the first bit or the nonce bit to detect IETF QUIC? But as Marten says, this PR definitely makes things more complex than I originally thought, particularly in light of other potential header changes. |
I'm surprised to see this PR merged -- I don't think we had agreed on STUN types being necessary to multiplex with. In addition to concerns about GQUIC vs QUIC, there remains the high-level question of what do we need to multiplex QUIC with on the same port. This was a conversation that made good progress in Singapore, and I was expecting to continue it and finalize on list. |
Let's have discussions on issues and not PRs. Let's please continue this on #426. |
My understanding from the meeting was that there is no need to multiplex short header with stun so the change of the type values for the short header is a surprise and I did not see any discussion on the QUIC mailing list about this change. It is not mentioned also in the Singapore meeting notes. The change that was agreed as far as I remember was to flip the value of the connection ID flag since it will be on for the peer to peer case. |
We certainly need to demux QUIC short header packets with STUN, to maintain bindings. Changing the packet type values doesn't prevent the spin bit, although it might change which bit is used as the spin bit. |
Note also that #989 would give us more degrees of freedom in the short header first octet. |
Un-does most of the changes in PR #956, to give time for rough consensus to be reached before changing the type byte.
Colin is right here. You have to multiplex short headers with STUN b/c of consent checks, as well as candidates you learn about late |
Can we please continue this discussion on #426? This is a merged PR, and as such, effectively dead space. |
This commit makes the following changes:
This is a purely syntactic change, with no semantic impact on QUIC.
The purpose of the changes is to make it possible to easily demultiplex QUIC and STUN packets running on a single UDP port, to enable peer to peer use of QUIC. It also enables demultiplexing of WebRTC packets and QUIC packets on a single UDP port.
Discussed in QUIC and AVTCORE working groups at IETF 100 (draft-aboba-avtcore-quic-multiplexing-01) and on QUIC mailing list.
Addresses issue #426