gfe-relnote: In QUIC, check nonretransmittable_frames, instead of packet length, to determine if a serialized packet is a MTU probe or not. Protected by --gfe2_reloadable_flag_quic_better_mtu_packet_check. PiperOrigin-RevId: 292604133 Change-Id: I14e54f30af8d8a42c205809f5424a9c76a9eeccb
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 9d9f1fc..9ad0190 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -339,7 +339,9 @@ check_handshake_timeout_before_idle_timeout_(GetQuicReloadableFlag( quic_check_handshake_timeout_before_idle_timeout)), batch_writer_flush_after_mtu_probe_( - GetQuicReloadableFlag(quic_batch_writer_flush_after_mtu_probe)) { + GetQuicReloadableFlag(quic_batch_writer_flush_after_mtu_probe)), + better_mtu_packet_check_( + GetQuicReloadableFlag(quic_better_mtu_packet_check)) { QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID " << server_connection_id << " and version: " << ParsedQuicVersionToString(version()); @@ -358,6 +360,10 @@ quic_check_handshake_timeout_before_idle_timeout); } + if (better_mtu_packet_check_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_better_mtu_packet_check); + } + framer_.set_visitor(this); stats_.connection_creation_time = clock_->ApproximateNow(); // TODO(ianswett): Supply the NetworkChangeVisitor as a constructor argument @@ -2196,7 +2202,14 @@ } const bool looks_like_mtu_probe = packet->retransmittable_frames.empty() && packet->encrypted_length > long_term_mtu_; - SerializedPacketFate fate = DeterminePacketFate(looks_like_mtu_probe); + const bool is_mtu_discovery = + better_mtu_packet_check_ + ? QuicUtils::ContainsFrameType(packet->nonretransmittable_frames, + MTU_DISCOVERY_FRAME) + : looks_like_mtu_probe; + DCHECK_EQ(looks_like_mtu_probe, is_mtu_discovery); + + SerializedPacketFate fate = DeterminePacketFate(is_mtu_discovery); // Termination packets are encrypted and saved, so don't exit early. const bool is_termination_packet = IsTerminationPacket(*packet); QuicPacketNumber packet_number = packet->packet_number; @@ -2215,7 +2228,7 @@ } DCHECK_LE(encrypted_length, kMaxOutgoingPacketSize); - if (!looks_like_mtu_probe) { + if (!is_mtu_discovery) { DCHECK_LE(encrypted_length, packet_creator_.max_packet_length()); } QUIC_DVLOG(1) << ENDPOINT << "Sending packet " << packet_number << " : " @@ -2293,7 +2306,7 @@ // be closed. By manually flush the writer here, the MTU probe is sent in // a normal(non-GSO) packet, so the kernel can return EMSGSIZE and we will // not close the connection. - if (batch_writer_flush_after_mtu_probe_ && looks_like_mtu_probe && + if (batch_writer_flush_after_mtu_probe_ && is_mtu_discovery && writer_->IsBatchMode()) { QUIC_RELOADABLE_FLAG_COUNT(quic_batch_writer_flush_after_mtu_probe); result = writer_->Flush(); @@ -2332,7 +2345,7 @@ // In some cases, an MTU probe can cause EMSGSIZE. This indicates that the // MTU discovery is permanently unsuccessful. - if (IsMsgTooBig(result) && looks_like_mtu_probe) { + if (IsMsgTooBig(result) && is_mtu_discovery) { // When MSG_TOO_BIG is returned, the system typically knows what the // actual MTU is, so there is no need to probe further. // TODO(wub): Reduce max packet size to a safe default, or the actual MTU.
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 12a899f..6a4d007 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -1523,6 +1523,9 @@ // Latched value of quic_batch_writer_flush_after_mtu_probe. const bool batch_writer_flush_after_mtu_probe_; + + // Latched value of quic_better_mtu_packet_check. + const bool better_mtu_packet_check_; }; } // namespace quic
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc index 733ee39..f5eecd7 100644 --- a/quic/core/quic_utils.cc +++ b/quic/core/quic_utils.cc
@@ -321,6 +321,17 @@ } // static +bool QuicUtils::ContainsFrameType(const QuicFrames& frames, + QuicFrameType type) { + for (const QuicFrame& frame : frames) { + if (frame.type == type) { + return true; + } + } + return false; +} + +// static SentPacketState QuicUtils::RetransmissionTypeToPacketState( TransmissionType retransmission_type) { switch (retransmission_type) {
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h index 04858f0..c143154 100644 --- a/quic/core/quic_utils.h +++ b/quic/core/quic_utils.h
@@ -101,6 +101,9 @@ static bool IsHandshakeFrame(const QuicFrame& frame, QuicTransportVersion transport_version); + // Return true if any frame in |frames| is of |type|. + static bool ContainsFrameType(const QuicFrames& frames, QuicFrameType type); + // Returns packet state corresponding to |retransmission_type|. static SentPacketState RetransmissionTypeToPacketState( TransmissionType retransmission_type);