From 8526309cac0a845600cb84495ee0545f11f4721d Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Thu, 25 Oct 2018 15:00:17 +1100 Subject: [PATCH 1/2] Use octets rather than bytes throughout Also closes #1863. --- draft-ietf-quic-transport.md | 49 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index bcc6265408..9dbf69a4a7 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -195,7 +195,7 @@ Endpoint: Stream: -: A logical unidirectional or bidirectional channel of ordered bytes within a +: A logical unidirectional or bidirectional channel of ordered octets within a QUIC connection. Connection: @@ -753,11 +753,11 @@ MAY send MAX_STREAM_DATA frames in multiple packets in order to make sure that the sender receives an update before running out of flow control credit, even if one of the packets is lost. -Connection flow control is a limit to the total bytes of stream data sent in +Connection flow control is a limit to the total octets of stream data sent in STREAM frames on all streams. A receiver advertises credit for a connection by -sending a MAX_DATA frame. A receiver maintains a cumulative sum of bytes +sending a MAX_DATA frame. A receiver maintains a cumulative sum of octets received on all contributing streams, which are used to check for flow control -violations. A receiver might use a sum of bytes consumed on all streams to +violations. A receiver might use a sum of octets consumed on all streams to determine the maximum data limit to be advertised. A receiver MAY advertise a larger offset at any point by sending MAX_STREAM_DATA @@ -791,18 +791,18 @@ waiting for a MAX_STREAM_DATA or MAX_DATA frame which will never come. On receipt of a RST_STREAM frame, an endpoint will tear down state for the matching stream and ignore further data arriving on that stream. This could result in the endpoints getting out of sync, since the RST_STREAM frame may have -arrived out of order and there may be further bytes in flight. The data sender +arrived out of order and there could be more data in flight. The data sender would have counted the data against its connection level flow control budget, -but a receiver that has not received these bytes would not know to include them -as well. The receiver must learn the number of bytes that were sent on the +but a receiver that has not received these octets would not know to include them +as well. The receiver must learn the number of octets that were sent on the stream to make the same adjustment in its connection flow controller. To ensure that endpoints maintain a consistent connection-level flow control state, the RST_STREAM frame ({{frame-rst-stream}}) includes the largest offset of data sent on the stream. On receiving a RST_STREAM frame, a receiver -definitively knows how many bytes were sent on that stream before the RST_STREAM -frame, and the receiver MUST use the final offset to account for all bytes sent -on the stream in its connection level flow controller. +definitively knows how many octets were sent on that stream before the +RST_STREAM frame, and the receiver MUST use the final offset to account for all +octets sent on the stream in its connection level flow controller. RST_STREAM terminates one direction of a stream abruptly. Whether any action or response can or should be taken on the data already received is application @@ -816,7 +816,7 @@ either side sends CONNECTION_CLOSE or APPLICATION_CLOSE. ## Data Limit Increments {#fc-credit} -This document leaves when and how many bytes to advertise in a MAX_DATA or +This document leaves when and how many octets to advertise in a MAX_DATA or MAX_STREAM_DATA to implementations, but offers a few considerations. These frames contribute to connection overhead. Therefore frequently sending frames with small changes is undesirable. At the same time, larger increments to @@ -1552,9 +1552,10 @@ server has successfully processed a Handshake packet from the client, it can consider the client address to have been validated. Prior to validating the client address, servers MUST NOT send more than three -times as many bytes as the number of bytes they have received. This limits the -magnitude of any amplification attack that can be mounted using spoofed source -addresses. +times as many octets as the number of octets they have received. This limits +the magnitude of any amplification attack that can be mounted using spoofed +source addresses. In determining this limit, servers only count the size of +successfully processed packets. To ensure that the server is not overly constrained by this restriction, clients MUST send UDP datagrams with at least 1200 octets of payload until the server @@ -3026,7 +3027,7 @@ datagram is smaller than 1200 octets. It MUST NOT send any other frame type in response, or otherwise behave as if any part of the offending packet was processed as valid. -The server MUST also limit the number of bytes it sends before validating the +The server MUST also limit the number of octets it sends before validating the address of the client, see {{address-validation}}. @@ -3068,7 +3069,7 @@ connection if an alternative path cannot be found. Traditional ICMP-based path MTU discovery in IPv4 {{!PMTUDv4}} is potentially vulnerable to off-path attacks that successfully guess the IP/port 4-tuple and reduce the MTU to a bandwidth-inefficient value. TCP connections mitigate this -risk by using the (at minimum) 8 bytes of transport header echoed in the ICMP +risk by using the (at minimum) 8 octets of transport header echoed in the ICMP message to validate the TCP sequence number as valid for the current connection. However, as QUIC operates over UDP, in IPv4 the echoed information could consist only of the IP and UDP headers, which usually has insufficient @@ -3567,7 +3568,7 @@ NEW_TOKEN frame: Token Length: -: A variable-length integer specifying the length of the Token field, in bytes. +: A variable-length integer specifying the length of the Token field, in octets. This value is zero if no token is present. Initial packets sent by the server MUST set the Token Length field to zero; clients that receive an Initial packet with a non-zero Token Length field MUST either discard the packet or @@ -4093,10 +4094,10 @@ Frame Type: Reason Phrase Length: -: A variable-length integer specifying the length of the reason phrase in bytes. - Note that a CONNECTION_CLOSE frame cannot be split between packets, so in - practice any limits on packet size will also limit the space available for a - reason phrase. +: A variable-length integer specifying the length of the reason phrase in + octets. Note that a CONNECTION_CLOSE frame cannot be split between packets, + so in practice any limits on packet size will also limit the space available + for a reason phrase. Reason Phrase: @@ -4770,7 +4771,7 @@ The fields of a NEW_TOKEN frame are as follows: Token Length: -: A variable-length integer specifying the length of the token in bytes. +: A variable-length integer specifying the length of the token in octets. Token: @@ -4841,7 +4842,7 @@ Length: Stream Data: -: The bytes from the designated stream to be delivered. +: The octets from the designated stream to be delivered. When a Stream Data field has a length of 0, the offset in the STREAM frame is the offset of the next byte that would be sent. @@ -4855,7 +4856,7 @@ less than 2^62. The CRYPTO frame (type=0x18) is used to transmit cryptographic handshake messages. It can be sent in all packet types. The CRYPTO frame offers the -cryptographic protocol an in-order stream of bytes. CRYPTO frames are +cryptographic protocol an in-order stream of octets. CRYPTO frames are functionally identical to STREAM frames, except that they do not bear a stream identifier; they are not flow controlled; and they do not carry markers for optional offset, optional length, and the end of the stream. From 92c7dcaa0632da455c74aea7b506775440e15220 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Thu, 25 Oct 2018 15:07:43 +1100 Subject: [PATCH 2/2] Use octets for units; size for packet sizes --- draft-ietf-quic-recovery.md | 53 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 0d4b79cd07..8d815cd32d 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -322,12 +322,11 @@ When crypto packets are sent, the sender MUST set a timer for the crypto timeout period. Upon timeout, the sender MUST retransmit all unacknowledged CRYPTO data if possible. -Until the server has validated the client's address on the path, the number of -bytes it can send is limited, as specified in {{QUIC-TRANSPORT}}. -If not all unacknowledged CRYPTO data can be sent, then all unacknowledged -CRYPTO data sent in Initial packets should be retransmitted. If no bytes -can be sent, then no alarm should be armed until bytes have been received from -the client. +Until the server has validated the client's address on the path, the amount of +data it can send is limited, as specified in {{QUIC-TRANSPORT}}. If not all +unacknowledged CRYPTO data can be sent, then all unacknowledged CRYPTO data sent +in Initial packets should be retransmitted. If no data can be sent, then no +alarm should be armed until data has been received from the client. Because the server could be blocked until more packets are received, the client MUST start the crypto retransmission timer even if there is no @@ -443,8 +442,8 @@ sent as a probe into the network prior to establishing any packet loss, prior unacknowledged packets SHOULD NOT be marked as lost. A packet sent on an RTO timer MUST NOT be blocked by the sender's congestion -controller. A sender MUST however count these bytes as additional bytes in -flight, since this packet adds network load without establishing packet loss. +controller. A sender MUST however count these octets as being in flight, since +this packet adds network load without establishing packet loss. ## Generating Acknowledgements @@ -618,8 +617,8 @@ sent_packets: : An association of packet numbers to information about them, including a number field indicating the packet number, a time field indicating the time a packet was sent, a boolean indicating whether the packet is ack-only, a boolean - indicating whether it counts towards bytes in flight, and a bytes - field indicating the packet's size. sent_packets is ordered by packet number, + indicating whether it counts towards bytes in flight, and a size field + that indicates the packet's size. sent_packets is ordered by packet number, and packets remain in sent_packets until acknowledged or lost. A sent_packets data structure is maintained per packet number space, and ACK processing only applies to a single space. @@ -670,7 +669,7 @@ are as follows: handshake. In this version of QUIC, this includes any packet with the long header that includes a CRYPTO frame. -* sent_bytes: The number of bytes sent in the packet, not including UDP or IP +* sent_bytes: The number of octets sent in the packet, not including UDP or IP overhead, but including QUIC framing overhead. Pseudocode for OnPacketSent follows: @@ -688,7 +687,7 @@ Pseudocode for OnPacketSent follows: time_of_last_sent_crypto_packet = now time_of_last_sent_retransmittable_packet = now OnPacketSentCC(sent_bytes) - sent_packets[packet_number].bytes = sent_bytes + sent_packets[packet_number].size = sent_bytes SetLossDetectionTimer() ~~~ @@ -910,7 +909,7 @@ both the median and mean min_rtt typically observed on the public internet. QUIC's congestion control is based on TCP NewReno {{?RFC6582}}. NewReno is a congestion window based congestion control. QUIC specifies the congestion -window in bytes rather than packets due to finer control and the ease of +window in octets rather than packets due to finer control and the ease of appropriate byte counting {{?RFC3465}}. QUIC hosts MUST NOT send packets if they would increase bytes_in_flight @@ -936,7 +935,7 @@ QUIC begins every connection in slow start and exits slow start upon loss or upon increase in the ECN-CE counter. QUIC re-enters slow start anytime the congestion window is less than ssthresh, which typically only occurs after an RTO. While in slow start, QUIC increases the congestion window by the number of -bytes acknowledged when each ack is processed. +octets acknowledged when each acknowledgment is processed. ## Congestion Avoidance @@ -965,8 +964,8 @@ losses or increases in the ECN-CE counter. ## Tail Loss Probe A TLP packet MUST NOT be blocked by the sender's congestion controller. The -sender MUST however count these bytes as additional bytes-in-flight, since a TLP -adds network load without establishing packet loss. +sender MUST however count TLP packets against bytes-in-flight, since a TLP adds +network load without establishing packet loss. Acknowledgement or loss of tail loss probes are treated like any other packet. @@ -1012,15 +1011,15 @@ in order to better suit a variety of environments. kMaxDatagramSize: : The sender's maximum payload size. Does not include UDP or IP overhead. The max packet size is used for calculating initial and minimum congestion - windows. The RECOMMENDED value is 1200 bytes. + windows. The RECOMMENDED value is 1200 octets. kInitialWindow: -: Default limit on the initial amount of outstanding data in bytes. +: Default limit on the initial amount of outstanding data in octets. Taken from {{?RFC6928}}. The RECOMMENDED value is the minimum of 10 * kMaxDatagramSize and max(2* kMaxDatagramSize, 14600)). kMinimumWindow: -: Minimum congestion window in bytes. The RECOMMENDED value is +: Minimum congestion window in octets. The RECOMMENDED value is 2 * kMaxDatagramSize. kLossReductionFactor: @@ -1038,7 +1037,7 @@ ecn_ce_counter: counter. bytes_in_flight: -: The sum of the size in bytes of all sent packets that contain at least +: The sum of the size in octets of all sent packets that contain at least one retransmittable or PADDING frame, and have not been acked or declared lost. The size does not include IP or UDP overhead, but does include the QUIC header and AEAD overhead. @@ -1053,9 +1052,9 @@ end_of_recovery: packet is acknowledged, QUIC exits recovery. ssthresh: -: Slow start threshold in bytes. When the congestion window is below +: Slow start threshold in octets. When the congestion window is below ssthresh, the mode is slow start and the window grows by the number of - bytes acknowledged. + octets acknowledged. ### Initialization @@ -1091,16 +1090,16 @@ acked_packet from sent_packets. OnPacketAckedCC(acked_packet): // Remove from bytes_in_flight. - bytes_in_flight -= acked_packet.bytes + bytes_in_flight -= acked_packet.size if (InRecovery(acked_packet.packet_number)): // Do not increase congestion window in recovery period. return if (congestion_window < ssthresh): // Slow start. - congestion_window += acked_packet.bytes + congestion_window += acked_packet.size else: // Congestion avoidance. - congestion_window += kMaxDatagramSize * acked_packet.bytes + congestion_window += kMaxDatagramSize * acked_packet.size / congestion_window ~~~ @@ -1145,7 +1144,7 @@ are detected lost. OnPacketsLost(lost_packets): // Remove lost packets from bytes_in_flight. for (lost_packet : lost_packets): - bytes_in_flight -= lost_packet.bytes + bytes_in_flight -= lost_packet.size largest_lost_packet = lost_packets.last() // Start a new congestion epoch if the last lost packet @@ -1165,7 +1164,7 @@ sent before the newly acknowledged RTO packet. // Declare all packets prior to packet_number lost. for (sent_packet: sent_packets): if (sent_packet.packet_number < packet_number): - bytes_in_flight -= sent_packet.bytes + bytes_in_flight -= sent_packet.size sent_packets.remove(sent_packet.packet_number) ~~~