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);