Wire in the ack exponent trransport config for IETF QUIC gfe-relnote: N/A, for IETF QUIC Only, protected by V99 flag. PiperOrigin-RevId: 260736433 Change-Id: I5468bc4f052d78d2bf6890cdf0734cece5b107c0
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index fdd4fd1..12afbd1 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -219,6 +219,8 @@ const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout const QuicTag kMIBS = TAG('M', 'I', 'D', 'S'); // Max incoming bidi streams const QuicTag kMIUS = TAG('M', 'I', 'U', 'S'); // Max incoming unidi streams +const QuicTag kADE = TAG('A', 'D', 'E', 0); // Ack Delay Exponent (IETF + // QUIC ACK Frame Only). const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us. const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name // indication
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index c78fab4..10455e8 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -634,6 +634,39 @@ } } +// Simple transaction, but set a non-default ack exponent at the client +// and ensure it gets to the server. +TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) { + const uint32_t kClientAckDelayExponent = kDefaultAckDelayExponent + 100u; + // Force the ACK exponent to be something other than the default. + // Note that it is sent only if doing IETF QUIC. + client_config_.SetAckDelayExponentToSend(kClientAckDelayExponent); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + int expected_num_client_hellos = 2; + if (ServerSendsVersionNegotiation()) { + ++expected_num_client_hellos; + } + + EXPECT_EQ(expected_num_client_hellos, + client_->client()->GetNumSentClientHellos()); + if (VersionHasIetfQuicFrames( + GetParam().negotiated_version.transport_version)) { + // Should be only for IETF QUIC. + EXPECT_EQ(kClientAckDelayExponent, + GetServerConnection()->framer().peer_ack_delay_exponent()); + } else { + // No change for Google QUIC. + EXPECT_EQ(kDefaultAckDelayExponent, + GetServerConnection()->framer().peer_ack_delay_exponent()); + } + // No change, regardless of version. + EXPECT_EQ(kDefaultAckDelayExponent, + GetServerConnection()->framer().local_ack_delay_exponent()); +} + TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) { client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation());
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc index 661b5f3..22aef80 100644 --- a/quic/core/quic_config.cc +++ b/quic/core/quic_config.cc
@@ -414,7 +414,8 @@ support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL), stateless_reset_token_(kSRST, PRESENCE_OPTIONAL), max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL), - max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL) { + max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL), + ack_delay_exponent_(kADE, PRESENCE_OPTIONAL) { SetDefaults(); } @@ -557,6 +558,22 @@ return max_ack_delay_ms_.GetReceivedValue(); } +void QuicConfig::SetAckDelayExponentToSend(uint32_t exponent) { + ack_delay_exponent_.SetSendValue(exponent); +} + +uint32_t QuicConfig::GetAckDelayExponentToSend() { + return ack_delay_exponent_.GetSendValue(); +} + +bool QuicConfig::HasReceivedAckDelayExponent() const { + return ack_delay_exponent_.HasReceivedValue(); +} + +uint32_t QuicConfig::ReceivedAckDelayExponent() const { + return ack_delay_exponent_.GetReceivedValue(); +} + bool QuicConfig::HasSetBytesForConnectionIdToSend() const { return bytes_for_connection_id_.HasSendValue(); } @@ -711,6 +728,7 @@ SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow); SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs); SetSupportMaxHeaderListSize(); + SetAckDelayExponentToSend(kDefaultAckDelayExponent); } void QuicConfig::ToHandshakeMessage( @@ -724,6 +742,7 @@ max_incoming_bidirectional_streams_.ToHandshakeMessage(out); if (VersionHasIetfQuicFrames(transport_version)) { max_incoming_unidirectional_streams_.ToHandshakeMessage(out); + ack_delay_exponent_.ToHandshakeMessage(out); } if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 1, 4); @@ -806,6 +825,10 @@ error = max_ack_delay_ms_.ProcessPeerHello(peer_hello, hello_type, error_details); } + if (error == QUIC_NO_ERROR) { + error = ack_delay_exponent_.ProcessPeerHello(peer_hello, hello_type, + error_details); + } return error; } @@ -838,6 +861,7 @@ QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 3, 4); params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs); } + params->ack_delay_exponent.set_value(ack_delay_exponent_.GetSendValue()); params->disable_migration = connection_migration_disabled_.HasSendValue() && connection_migration_disabled_.GetSendValue() != 0; @@ -924,6 +948,9 @@ max_ack_delay_ms_.SetReceivedValue(std::min<uint32_t>( params.max_ack_delay.value(), std::numeric_limits<uint32_t>::max())); } + if (params.ack_delay_exponent.IsValid()) { + ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value()); + } connection_migration_disabled_.SetReceivedValue( params.disable_migration ? 1u : 0u);
diff --git a/quic/core/quic_config.h b/quic/core/quic_config.h index 3c82a68..b4a4ca9 100644 --- a/quic/core/quic_config.h +++ b/quic/core/quic_config.h
@@ -424,6 +424,11 @@ bool HasReceivedMaxAckDelayMs() const; uint32_t ReceivedMaxAckDelayMs() const; + void SetAckDelayExponentToSend(uint32_t exponent); + uint32_t GetAckDelayExponentToSend(); + bool HasReceivedAckDelayExponent() const; + uint32_t ReceivedAckDelayExponent() const; + bool negotiated() const; void SetCreateSessionTagIndicators(QuicTagVector tags); @@ -516,6 +521,13 @@ // The received value is the value received from the peer and used by // the peer. QuicFixedUint32 max_ack_delay_ms_; + + // ack_delay_exponent parameter negotiated in IETF QUIC transport + // parameter negotiation. The sent exponent is the exponent that this + // node uses when serializing an ACK frame (and the peer should use when + // deserializing the frame); the received exponent is the value the peer uses + // to serialize frames and this node uses to deserialize them. + QuicFixedUint32 ack_delay_exponent_; }; } // namespace quic
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index a13c506..e65492f 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -425,6 +425,9 @@ stateless_reset_token_received_ = true; received_stateless_reset_token_ = config.ReceivedStatelessResetToken(); } + if (config.HasReceivedAckDelayExponent()) { + framer_.set_peer_ack_delay_exponent(config.ReceivedAckDelayExponent()); + } if (GetQuicReloadableFlag(quic_send_timestamps) && config.HasClientSentConnectionOption(kSTMP, perspective_)) { QUIC_RELOADABLE_FLAG_COUNT(quic_send_timestamps);
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h index 1ba32d8..cdee0f9 100644 --- a/quic/core/quic_constants.h +++ b/quic/core/quic_constants.h
@@ -113,6 +113,9 @@ // in low-bandwidth (< ~384 kbps), where an ack is sent per packet. const int64_t kDefaultDelayedAckTimeMs = 25; +// Default shift of the ACK delay in the IETF QUIC ACK frame. +const uint32_t kDefaultAckDelayExponent = 3; + // Minimum tail loss probe time in ms. static const int64_t kMinTailLossProbeTimeoutMs = 10;
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc index e9d6fa9..59edc79 100644 --- a/quic/core/quic_framer.cc +++ b/quic/core/quic_framer.cc
@@ -50,11 +50,6 @@ #define ENDPOINT \ (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") -// How much to shift the timestamp in the IETF Ack frame. -// TODO(fkastenholz) when we get real IETF QUIC, need to get -// the currect shift from the transport parameters. -const int kIetfAckTimestampShift = 3; - // Number of bits the packet number length bits are shifted from the right // edge of the header. const uint8_t kPublicHeaderSequenceNumberShift = 4; @@ -482,7 +477,9 @@ expected_server_connection_id_length), expected_client_connection_id_length_(0), supports_multiple_packet_number_spaces_(false), - last_written_packet_number_length_(0) { + last_written_packet_number_length_(0), + peer_ack_delay_exponent_(kDefaultAckDelayExponent), + local_ack_delay_exponent_(kDefaultAckDelayExponent) { DCHECK(!supported_versions.empty()); version_ = supported_versions_[0]; decrypter_[ENCRYPTION_INITIAL] = QuicMakeUnique<NullDecrypter>(perspective); @@ -3753,12 +3750,10 @@ return false; } - // TODO(fkastenholz) when we get real IETF QUIC, need to get - // the currect shift from the transport parameters. if (ack_delay_time_in_us == kVarInt62MaxValue) { ack_frame->ack_delay_time = QuicTime::Delta::Infinite(); } else { - ack_delay_time_in_us = (ack_delay_time_in_us << kIetfAckTimestampShift); + ack_delay_time_in_us = (ack_delay_time_in_us << peer_ack_delay_exponent_); ack_frame->ack_delay_time = QuicTime::Delta::FromMicroseconds(ack_delay_time_in_us); } @@ -4566,7 +4561,7 @@ ack_frame_size += QuicDataWriter::GetVarInt62Len(largest_acked.ToUint64()); uint64_t ack_delay_time_us; ack_delay_time_us = frame.ack_delay_time.ToMicroseconds(); - ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift; + ack_delay_time_us = ack_delay_time_us >> local_ack_delay_exponent_; ack_frame_size += QuicDataWriter::GetVarInt62Len(ack_delay_time_us); // If |ecn_counters_populated| is true and any of the ecn counters is non-0 @@ -5423,8 +5418,7 @@ if (!frame.ack_delay_time.IsInfinite()) { DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds()); ack_delay_time_us = frame.ack_delay_time.ToMicroseconds(); - // TODO(fkastenholz): Use the shift from TLS transport parameters. - ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift; + ack_delay_time_us = ack_delay_time_us >> local_ack_delay_exponent_; } if (!writer->WriteVarInt62(ack_delay_time_us)) {
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h index 2349a77..0143abe 100644 --- a/quic/core/quic_framer.h +++ b/quic/core/quic_framer.h
@@ -611,6 +611,18 @@ uint8_t* source_connection_id_length_out, std::string* detailed_error); + void set_local_ack_delay_exponent(uint32_t exponent) { + local_ack_delay_exponent_ = exponent; + } + uint32_t local_ack_delay_exponent() const { + return local_ack_delay_exponent_; + } + + void set_peer_ack_delay_exponent(uint32_t exponent) { + peer_ack_delay_exponent_ = exponent; + } + uint32_t peer_ack_delay_exponent() const { return peer_ack_delay_exponent_; } + private: friend class test::QuicFramerPeer; @@ -1020,6 +1032,15 @@ // The length in bytes of the last packet number written to an IETF-framed // packet. size_t last_written_packet_number_length_; + + // The amount to shift the ack timestamp in ACK frames. The default is 3. + // Local_ is the amount this node shifts timestamps in ACK frames it + // generates. it is sent to the peer in a transport parameter negotiation. + // Peer_ is the amount the peer shifts timestamps when it sends ACK frames to + // this node. This node "unshifts" by this amount. The value is received from + // the peer in the transport parameter negotiation. IETF QUIC only. + uint32_t peer_ack_delay_exponent_; + uint32_t local_ack_delay_exponent_; }; } // namespace quic