Change protection scheme for code that marks outgoing ECT.

The code that marks outgoing packets ECT(0) or ECT(1) was originally written to support tests of the code that receives and reports those marks, although we knew it would eventually be used to send them in production as well. The plan was to eventually experiment with sending ECT(1) from GFE, so most of the code was protected with quic_support_ect1.

The plan has changed. For multiple reasons, initial send-side experiments will occur in Chrome instead. As such, a GFE feature flag is a cumbersome means to manage a rollout.

Instead, sending ECT marks will only be enabled when QUIC loads a congestion controller that supports it. There is no code path in Quiche or GFE that will do this. Any addition in this space can be flag-protected in case of unexpected bad effects.

The various QuicPacketWriter derived classes now simply report 'true' for ECN support since they are no longer dependent on the flag. This is necessary but not sufficient to send ECT marks, because the congestion controller also needs to return true for 'EnableECT1' or 'EnableECT0'.

Also, fix inconsistent checking of the ECN setting before calling set_ecn_bits().

This CL dramatically reduces the footprint of the feature flag. Most new code is trivial when the connection is not sending ECT. There are two exceptions:

1) Feature flag quic_preserve_dscp_with_ecn protects the code that reads the DSCP bits currently set from a socket and ORs them with whatever ECN setting it is propagating. This code is a bit more complex and therefore higher-risk. It is not used in Chrome, and I strongly suspect it is not used in other Quiche codepaths. (Only QuicDefaultPacketWriter sets the ECN info bit, and that class is only used or extended in fringy places).

2) QuicSentPacketManager has some complex ECN validation code in its ACK processing. This is protected by a new boolean member ecn_queried_ so that it only executes if the QuicConnection has turned on ECN markings.

Protected by FLAGS_quic_restart_flag_quic_preserve_dscp_with_ecn.

PiperOrigin-RevId: 695874210
diff --git a/quiche/common/quiche_feature_flags_list.h b/quiche/common/quiche_feature_flags_list.h
index dbdcb4b..6bbc38d 100755
--- a/quiche/common/quiche_feature_flags_list.h
+++ b/quiche/common/quiche_feature_flags_list.h
@@ -56,7 +56,7 @@
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_update_transmission_info_on_frame_acked, false, true, "If true, QuicUnackedPacketMap will update transmission info after session_notifier_->OnFrameAcked.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_use_alarm_multiplexer, false, false, "Manages all of the connection alarms via QuicAlarmMultiplexer.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_use_received_client_addresses_cache, true, true, "If true, use a LRU cache to record client addresses of packets received on server's original address.")
-QUICHE_FLAG(bool, quiche_restart_flag_quic_support_ect1, false, false, "When true, allows sending of QUIC packets marked ECT(1). A different flag (TBD) will actually utilize this capability to send ECT(1).")
+QUICHE_FLAG(bool, quiche_restart_flag_quic_preserve_dscp_with_ecn, false, false, "When true, preserves the existing DSCP setting when setting ECN.")
 QUICHE_FLAG(bool, quiche_restart_flag_quic_support_flow_label2, false, false, "If true, QUIC will support reading and writing IPv6 flow labels.")
 QUICHE_FLAG(bool, quiche_restart_flag_quic_support_release_time_for_gso, false, false, "If true, QuicGsoBatchWriter will support release time if it is available and the process has the permission to do so.")
 QUICHE_FLAG(bool, quiche_restart_flag_quic_testonly_default_false, false, false, "A testonly restart flag that will always default to false.")
diff --git a/quiche/quic/core/batch_writer/quic_gso_batch_writer.cc b/quiche/quic/core/batch_writer/quic_gso_batch_writer.cc
index 3009d1d..1d5a80f 100644
--- a/quiche/quic/core/batch_writer/quic_gso_batch_writer.cc
+++ b/quiche/quic/core/batch_writer/quic_gso_batch_writer.cc
@@ -150,8 +150,7 @@
   if (release_time != 0) {
     *hdr->GetNextCmsgData<uint64_t>(SOL_SOCKET, SO_TXTIME) = release_time;
   }
-  if (ecn_codepoint != ECN_NOT_ECT && GetQuicRestartFlag(quic_support_ect1)) {
-    QUIC_RESTART_FLAG_COUNT_N(quic_support_ect1, 8, 9);
+  if (ecn_codepoint != ECN_NOT_ECT) {
     if (self_address.IsIPv4()) {
       *hdr->GetNextCmsgData<int>(IPPROTO_IP, IP_TOS) =
           static_cast<int>(ecn_codepoint);
diff --git a/quiche/quic/core/batch_writer/quic_gso_batch_writer.h b/quiche/quic/core/batch_writer/quic_gso_batch_writer.h
index 96a46ec..5e82952 100644
--- a/quiche/quic/core/batch_writer/quic_gso_batch_writer.h
+++ b/quiche/quic/core/batch_writer/quic_gso_batch_writer.h
@@ -25,9 +25,7 @@
 
   bool SupportsReleaseTime() const final { return supports_release_time_; }
 
-  bool SupportsEcn() const override {
-    return GetQuicRestartFlag(quic_support_ect1);
-  }
+  bool SupportsEcn() const override { return true; }
 
   CanBatchResult CanBatch(const char* buffer, size_t buf_len,
                           const QuicIpAddress& self_address,
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc
index 4f3bfd6..b6321d2 100644
--- a/quiche/quic/core/http/end_to_end_test.cc
+++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -7773,7 +7773,6 @@
 
 TEST_P(EndToEndTest, ServerReportsNotEct) {
   // Client connects using not-ECT.
-  SetQuicRestartFlag(quic_support_ect1, true);
   ASSERT_TRUE(Initialize());
   QuicConnection* client_connection = GetClientConnection();
   QuicConnectionPeer::DisableEcnCodepointValidation(client_connection);
@@ -7793,7 +7792,6 @@
 
 TEST_P(EndToEndTest, ServerReportsEct0) {
   // Client connects using not-ECT.
-  SetQuicRestartFlag(quic_support_ect1, true);
   ASSERT_TRUE(Initialize());
   QuicConnection* client_connection = GetClientConnection();
   QuicConnectionPeer::DisableEcnCodepointValidation(client_connection);
@@ -7817,7 +7815,6 @@
 
 TEST_P(EndToEndTest, ServerReportsEct1) {
   // Client connects using not-ECT.
-  SetQuicRestartFlag(quic_support_ect1, true);
   ASSERT_TRUE(Initialize());
   QuicConnection* client_connection = GetClientConnection();
   QuicConnectionPeer::DisableEcnCodepointValidation(client_connection);
@@ -7841,7 +7838,6 @@
 
 TEST_P(EndToEndTest, ServerReportsCe) {
   // Client connects using not-ECT.
-  SetQuicRestartFlag(quic_support_ect1, true);
   ASSERT_TRUE(Initialize());
   QuicConnection* client_connection = GetClientConnection();
   QuicConnectionPeer::DisableEcnCodepointValidation(client_connection);
@@ -7864,7 +7860,6 @@
 }
 
 TEST_P(EndToEndTest, ClientReportsEct1) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   ASSERT_TRUE(Initialize());
   // Wait for handshake to complete, so that we can manipulate the server
   // connection without race conditions.
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 7df6663..92a9e51 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -442,7 +442,21 @@
     active_migration_disabled_ = true;
   }
 
+  // Note that SetFromConfig() can be called twice: once at initialization and
+  // once after handshake completion. This can cause ECN to be set again after
+  // failing validation during the handshake. It is legal per RFC9000 to
+  // periodically try to validate ECN after failure, and post-handshakes is as
+  // good a time as any.
   sent_packet_manager_.SetFromConfig(config);
+  // TODO(martinduke): set_ecn_codepoint() itself calls EnableECT1() and
+  // EnableECT0(). Once set_ecn_codepoint() has proven to be safe, this can
+  // just call set_ecn_codepoint(ECT0) and (ECT1) without any conditional.
+  if (sent_packet_manager_.EnableECT1()) {
+    set_ecn_codepoint(ECN_ECT1);
+  } else if (sent_packet_manager_.EnableECT0()) {
+    set_ecn_codepoint(ECN_ECT0);
+  }
+
   if (perspective_ == Perspective::IS_SERVER &&
       config.HasClientSentConnectionOption(kAFF2, perspective_)) {
     send_ack_frequency_on_handshake_completion_ = true;
@@ -3966,19 +3980,14 @@
 }
 
 void QuicConnection::OnInFlightEcnPacketAcked() {
-  QUIC_BUG_IF(quic_bug_518619343_01, !GetQuicRestartFlag(quic_support_ect1))
-      << "Unexpected call to OnInFlightEcnPacketAcked()";
   // Only packets on the default path are in-flight.
   if (!default_path_.ecn_marked_packet_acked) {
     QUIC_DVLOG(1) << ENDPOINT << "First ECT packet acked on active path.";
-    QUIC_RESTART_FLAG_COUNT_N(quic_support_ect1, 2, 9);
     default_path_.ecn_marked_packet_acked = true;
   }
 }
 
 void QuicConnection::OnInvalidEcnFeedback() {
-  QUIC_BUG_IF(quic_bug_518619343_02, !GetQuicRestartFlag(quic_support_ect1))
-      << "Unexpected call to OnInvalidEcnFeedback().";
   if (disable_ecn_codepoint_validation_) {
     // In some tests, senders may send ECN marks in patterns that are not
     // in accordance with the spec, and should not fail validation as a result.
@@ -7467,10 +7476,6 @@
 }
 
 bool QuicConnection::set_ecn_codepoint(QuicEcnCodepoint ecn_codepoint) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return false;
-  }
-  QUIC_RESTART_FLAG_COUNT_N(quic_support_ect1, 3, 9);
   if (disable_ecn_codepoint_validation_ || ecn_codepoint == ECN_NOT_ECT) {
     packet_writer_params_.ecn_codepoint = ecn_codepoint;
     return true;
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 007f422..68f8594 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -417,6 +417,8 @@
       connection_options.push_back(kMTUH);
       config.SetInitialReceivedConnectionOptions(connection_options);
       EXPECT_CALL(*send_algorithm, SetFromConfig(_, _));
+      EXPECT_CALL(*send_algorithm, EnableECT1()).WillOnce(Return(false));
+      EXPECT_CALL(*send_algorithm, EnableECT0()).WillOnce(Return(false));
       SetFromConfig(config);
     }
 
@@ -1491,6 +1493,8 @@
     EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
     QuicConfig config;
     EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+    EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+    EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
     connection_.SetFromConfig(config);
     connection_.set_expected_server_preferred_address(kServerPreferredAddress);
   }
@@ -1523,6 +1527,8 @@
     QuicConfigPeer::SetPreferredAddressConnectionIdAndToken(
         &config, connection_id, reset_token);
     EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+    EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+    EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
     connection_.SetFromConfig(config);
 
     ASSERT_TRUE(
@@ -1871,6 +1877,8 @@
   QuicConfigPeer::SetReceivedInitialSourceConnectionId(&config,
                                                        QuicConnectionId());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   // Clear direct_peer_address.
@@ -3182,6 +3190,8 @@
   QuicConfigPeer::SetPreferredAddressConnectionIdAndToken(
       &config, connection_id, reset_token);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -3207,6 +3217,8 @@
 
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   constexpr uint32_t kTestMaxPacketSize = 1233u;
   QuicConfig config;
   QuicConfigPeer::SetReceivedMaxPacketSize(&config, kTestMaxPacketSize);
@@ -3220,6 +3232,8 @@
 
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   constexpr uint32_t kTestMaxPacketSize = 1450u;
   QuicConfig config;
   QuicConfigPeer::SetReceivedMaxPacketSize(&config, kTestMaxPacketSize);
@@ -3679,6 +3693,8 @@
 
 TEST_P(QuicConnectionTest, AckNeedsRetransmittableFramesAfterPto) {
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicTagVector connection_options;
   connection_options.push_back(kEACK);
@@ -4865,6 +4881,8 @@
   }
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -4904,6 +4922,8 @@
   }
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.set_max_undecryptable_packets(100);
   connection_.SetFromConfig(config);
@@ -4975,6 +4995,8 @@
 
   // SetFromConfig sets the initial timeouts before negotiation.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
   // Subtract a second from the idle timeout on the client side.
@@ -5007,6 +5029,8 @@
   EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
   EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
@@ -5058,6 +5082,8 @@
   EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
   EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
@@ -5868,6 +5894,8 @@
 TEST_P(QuicConnectionTest, TimeoutAfterSendDuringHandshake) {
   EXPECT_TRUE(connection_.connected());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
 
@@ -5920,6 +5948,8 @@
   // connection close packets.
   EXPECT_TRUE(connection_.connected());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
 
   // Create a handshake message that also enables silent close.
@@ -5999,6 +6029,8 @@
   // to be sent.
   EXPECT_TRUE(connection_.connected());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
 
   // Create a handshake message that also enables silent close.
@@ -6061,6 +6093,8 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_TRUE(connection_.connected());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
 
@@ -6110,6 +6144,8 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_TRUE(connection_.connected());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
 
@@ -6237,6 +6273,8 @@
   // Set up a larger payload than will fit in one packet.
   const std::string payload(connection_.max_packet_length(), 'a');
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
 
   // Now send some packets with no truncation.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
@@ -6347,6 +6385,8 @@
 TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicTagVector connection_options;
   // No limit on the number of packets received before sending an ack.
@@ -6840,6 +6880,8 @@
   QuicConfigPeer::SetReceivedStatelessResetToken(&config,
                                                  kTestStatelessResetToken);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   std::unique_ptr<QuicEncryptedPacket> packet(
       QuicFramer::BuildIetfStatelessResetPacket(connection_id_,
@@ -6928,6 +6970,8 @@
 
 TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiationWithConnectionClose) {
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicTagVector connection_options;
   connection_options.push_back(kINVC);
@@ -7149,6 +7193,8 @@
 TEST_P(QuicConnectionTest, ReevaluateTimeUntilSendOnAck) {
   // Enable pacing.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
 
@@ -7442,6 +7488,8 @@
   SetQuicReloadableFlag(quic_enable_server_on_wire_ping, true);
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicTagVector connection_options;
   connection_options.push_back(kSRWP);
@@ -7491,6 +7539,8 @@
       kRetransmittableOnWireTimeout);
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicTagVector connection_options;
   connection_options.push_back(kROWF);
@@ -7536,6 +7586,8 @@
       kRetransmittableOnWireTimeout);
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicTagVector connection_options;
   connection_options.push_back(kROWR);
@@ -7585,6 +7637,8 @@
       kRetransmittableOnWireTimeout);
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicTagVector connection_options;
   connection_options.push_back(kROWR);
@@ -8108,6 +8162,8 @@
             writer_->last_packet_header().destination_connection_id_included);
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   QuicConfigPeer::SetReceivedBytesForConnectionId(&config, 0);
   connection_.SetFromConfig(config);
@@ -8565,6 +8621,8 @@
   EXPECT_FALSE(connection_.IsValidStatelessResetToken(kTestToken));
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(2);
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
   // Token is different from received token.
   QuicConfigPeer::SetReceivedStatelessResetToken(&config, kTestToken);
   connection_.SetFromConfig(config);
@@ -8594,6 +8652,8 @@
     QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
         &config, kMaxAcceptedDatagramFrameSize);
     EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+    EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+    EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
     connection_.SetFromConfig(config);
   }
   std::string message(connection_.GetCurrentLargestMessagePayload() * 2, 'a');
@@ -8642,6 +8702,8 @@
     QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
         &config, kMaxAcceptedDatagramFrameSize);
     EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+    EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+    EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
     connection_.SetFromConfig(config);
     // Verify the value post-handshake.
     EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(),
@@ -8667,6 +8729,8 @@
     QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
         &config, kMaxAcceptedDatagramFrameSize);
     EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+    EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+    EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
     connection_.SetFromConfig(config);
     // Verify the value post-handshake.
     EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(),
@@ -8690,6 +8754,8 @@
   QuicConfig config;
   QuicConfigPeer::SetReceivedMaxDatagramFrameSize(&config, kFrameSizeLimit);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   // Verify the value post-handshake.
   EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), kPayloadSizeLimit);
@@ -8956,6 +9022,8 @@
   writer_->set_supports_release_time(true);
   QuicConfig config;
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_TRUE(QuicConnectionPeer::SupportsReleaseTime(&connection_));
 
@@ -8963,6 +9031,8 @@
   connection_options.push_back(kNPCO);
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   // Verify pacing offload is disabled.
   EXPECT_FALSE(QuicConnectionPeer::SupportsReleaseTime(&connection_));
@@ -9516,6 +9586,8 @@
   connection_options.push_back(k2PTO);
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
 
@@ -9551,6 +9623,8 @@
         &config, connection_.connection_id());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
       GetQuicReloadableFlag(
@@ -9603,6 +9677,8 @@
         &config, connection_.connection_id());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
       GetQuicReloadableFlag(
@@ -9654,6 +9730,8 @@
   }
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
       GetQuicReloadableFlag(
@@ -9802,6 +9880,8 @@
                                                          QuicConnectionId());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   // Verify no data can be sent at the beginning because bytes received is 0.
@@ -9874,6 +9954,8 @@
                                                          QuicConnectionId());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   // Verify no data can be sent at the beginning because bytes received is 0.
@@ -9999,6 +10081,8 @@
   connection_options.push_back(kPTOS);
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
 
@@ -10024,6 +10108,8 @@
   connection_options.push_back(kPTOS);
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
   EXPECT_EQ(0, connection_.outgoing_flow_label());
@@ -10060,6 +10146,8 @@
   connection_options.push_back(kPTOS);
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_EQ(0, connection_.outgoing_flow_label());
   connection_.EnableBlackholeAvoidanceViaFlowLabel();
@@ -10092,6 +10180,8 @@
   connection_options.push_back(kPTOS);
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_EQ(0, connection_.outgoing_flow_label());
   connection_.EnableBlackholeAvoidanceViaFlowLabel();
@@ -10448,6 +10538,8 @@
         .Times(0);
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
   connection_.SetFromConfig(received_config);
   if (missing_original_id_in_config || wrong_original_id_in_config ||
       missing_retry_id_in_config || wrong_retry_id_in_config) {
@@ -10478,6 +10570,8 @@
       &config, connection_.connection_id());
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   QuicIdleNetworkDetector& idle_network_detector =
       QuicConnectionPeer::GetIdleNetworkDetector(&connection_);
@@ -10513,6 +10607,8 @@
                                                        QuicConnectionId());
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   QuicIdleNetworkDetector& idle_network_detector =
       QuicConnectionPeer::GetIdleNetworkDetector(&connection_);
@@ -10644,6 +10740,8 @@
   QuicConfigPeer::SetReceivedOriginalConnectionId(&received_config,
                                                   TestConnectionId(0x12345));
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
   EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
       .Times(1);
   connection_.SetFromConfig(received_config);
@@ -10664,6 +10762,8 @@
   QuicConfigPeer::SetReceivedRetrySourceConnectionId(&received_config,
                                                      TestConnectionId(0x12345));
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
   EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
       .Times(1);
   connection_.SetFromConfig(received_config);
@@ -10775,6 +10875,8 @@
         &config, kMaxAcceptedDatagramFrameSize);
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   connection_.OnHandshakeComplete();
   EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -10834,6 +10936,8 @@
 
 TEST_P(QuicConnectionTest, DoNotExtendIdleTimeOnUndecryptablePackets) {
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
   // Subtract a second from the idle timeout on the client side.
@@ -10915,6 +11019,8 @@
   connection_options.push_back(kCBHD);
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_CALL(visitor_, GetHandshakeState())
       .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
@@ -10942,6 +11048,8 @@
   connection_options.push_back(kCBHD);
   config.SetInitialReceivedConnectionOptions(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   EXPECT_CALL(visitor_, GetHandshakeState())
       .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
@@ -10983,6 +11091,8 @@
         &config, connection_.connection_id());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
@@ -11016,6 +11126,8 @@
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber());
   QuicConfig config;
   connection_.SetFromConfig(config);
@@ -11337,6 +11449,8 @@
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() {
     connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
     connection_.NeuterUnencryptedPackets();
@@ -11381,6 +11495,8 @@
   rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
 
   CryptoHandshakeMessage msg;
@@ -11425,6 +11541,8 @@
   rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
 
   CryptoHandshakeMessage msg;
@@ -11478,6 +11596,8 @@
                                                          QuicConnectionId());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   EXPECT_TRUE(connection_.connected());
@@ -11615,6 +11735,8 @@
                        QuicTime::Delta::Zero(), QuicTime::Zero());
 
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.SetClientConnectionOptions(QuicTagVector{kFIDT});
   QuicConfigPeer::SetNegotiated(&config, true);
@@ -11865,6 +11987,8 @@
   QuicConfigPeer::SetReceivedStatelessResetToken(&config,
                                                  kTestStatelessResetToken);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Any4(), 12345);
   EXPECT_NE(kNewSelfAddress, connection_.self_address());
@@ -12580,6 +12704,8 @@
         &config, connection_.connection_id());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   EXPECT_FALSE(connection_.IsKeyUpdateAllowed());
@@ -12753,6 +12879,8 @@
         &config, connection_.connection_id());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   MockFramerVisitor peer_framer_visitor_;
@@ -12847,6 +12975,8 @@
         &config, connection_.connection_id());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -13040,6 +13170,8 @@
         &config, connection_.connection_id());
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   MockFramerVisitor peer_framer_visitor_;
@@ -13138,6 +13270,8 @@
   QuicConfig config;
   QuicConfigPeer::SetReceivedMinAckDelayMs(&config, /*min_ack_delay_ms=*/1);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   QuicConnectionPeer::SetAddressValidated(&connection_);
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -13183,6 +13317,8 @@
   quic_tag_vector.push_back(kAFF2);
   QuicConfigPeer::SetReceivedConnectionOptions(&config, quic_tag_vector);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   QuicConnectionPeer::SetAddressValidated(&connection_);
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -13206,6 +13342,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
 
@@ -13228,6 +13366,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
   EXPECT_CALL(visitor_, OnCryptoFrame(_))
@@ -13336,6 +13476,8 @@
   QuicConfig config;
   config.SetClientConnectionOptions(QuicTagVector{kMPQC});
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (!version().HasIetfQuicFrames()) {
     return;
@@ -13487,6 +13629,8 @@
   QuicConfig config;
   config.SetClientConnectionOptions(QuicTagVector{kMPQC});
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (!version().HasIetfQuicFrames()) {
     return;
@@ -13604,6 +13748,8 @@
                                                  kTestStatelessResetToken);
   config.SetClientConnectionOptions(QuicTagVector{kMPQC});
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (!version().HasIetfQuicFrames()) {
     return;
@@ -13670,6 +13816,8 @@
   QuicConfigPeer::SetReceivedDisableConnectionMigration(&config);
   config.SetClientConnectionOptions(QuicTagVector{kMPQC});
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   connection_.CreateConnectionIdManager();
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -13697,6 +13845,8 @@
   QuicConfig config;
   config.SetClientConnectionOptions(QuicTagVector{kMPQC});
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (!version().HasIetfQuicFrames()) {
     return;
@@ -13767,6 +13917,8 @@
   QuicConfig config;
   config.SetClientConnectionOptions(QuicTagVector{kMPQC, kMPQM});
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (!version().HasIetfQuicFrames()) {
     return;
@@ -13845,6 +13997,8 @@
   QuicConfig config;
   config.SetClientConnectionOptions(QuicTagVector{kMPQC, kMPQM});
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   if (!version().HasIetfQuicFrames()) {
     return;
@@ -14082,6 +14236,8 @@
   QuicConfigPeer::SetReceivedInitialSourceConnectionId(
       &config, connection_.connection_id());
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
 
   set_perspective(Perspective::IS_SERVER);
@@ -14167,6 +14323,8 @@
   QuicConfig config;
   QuicConfigPeer::SetReceivedMinAckDelayMs(&config, /*min_ack_delay_ms=*/1);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   connection_.SetFromConfig(config);
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
   connection_.OnHandshakeComplete();
@@ -15490,6 +15648,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.set_max_undecryptable_packets(3);
   connection_.SetFromConfig(config);
@@ -15540,6 +15700,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.set_max_undecryptable_packets(3);
   connection_.SetFromConfig(config);
@@ -15600,6 +15762,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.SetReliableStreamReset(true);
   connection_.SetFromConfig(config);
@@ -15947,6 +16111,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.set_max_undecryptable_packets(3);
   connection_.SetFromConfig(config);
@@ -16109,6 +16275,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.set_max_undecryptable_packets(3);
   connection_.SetFromConfig(config);
@@ -16462,6 +16630,8 @@
   // Call SetFromConfig so that the undecrypted packet buffer size is
   // initialized above zero.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
   connection_.RemoveEncrypter(ENCRYPTION_FORWARD_SECURE);
@@ -16506,6 +16676,8 @@
   // Call SetFromConfig so that the undecrypted packet buffer size is
   // initialized above zero.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   connection_.SetFromConfig(config);
 
@@ -17277,6 +17449,8 @@
   }
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.set_max_undecryptable_packets(100);
   connection_.SetFromConfig(config);
@@ -17536,7 +17710,6 @@
 }
 
 TEST_P(QuicConnectionTest, EcnCodepointsRejected) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   for (QuicEcnCodepoint ecn : {ECN_NOT_ECT, ECN_ECT0, ECN_ECT1, ECN_CE}) {
     if (ecn == ECN_ECT0) {
       EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
@@ -17556,7 +17729,6 @@
 }
 
 TEST_P(QuicConnectionTest, EcnCodepointsAccepted) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   for (QuicEcnCodepoint ecn : {ECN_NOT_ECT, ECN_ECT0, ECN_ECT1, ECN_CE}) {
     if (ecn == ECN_ECT0) {
       EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(true));
@@ -17579,19 +17751,8 @@
   }
 }
 
-TEST_P(QuicConnectionTest, EcnCodepointsRejectedIfFlagIsFalse) {
-  SetQuicRestartFlag(quic_support_ect1, false);
-  for (QuicEcnCodepoint ecn : {ECN_NOT_ECT, ECN_ECT0, ECN_ECT1, ECN_CE}) {
-    EXPECT_FALSE(connection_.set_ecn_codepoint(ecn));
-    EXPECT_CALL(connection_, OnSerializedPacket(_));
-    SendPing();
-    EXPECT_EQ(connection_.ecn_codepoint(), ECN_NOT_ECT);
-    EXPECT_EQ(writer_->last_ecn_sent(), ECN_NOT_ECT);
-  }
-}
 
 TEST_P(QuicConnectionTest, EcnValidationDisabled) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   QuicConnectionPeer::DisableEcnCodepointValidation(&connection_);
   for (QuicEcnCodepoint ecn : {ECN_NOT_ECT, ECN_ECT0, ECN_ECT1, ECN_CE}) {
     EXPECT_TRUE(connection_.set_ecn_codepoint(ecn));
@@ -17603,7 +17764,6 @@
 }
 
 TEST_P(QuicConnectionTest, RtoDisablesEcnMarking) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
   EXPECT_TRUE(connection_.set_ecn_codepoint(ECN_ECT1));
   QuicPacketCreatorPeer::SetPacketNumber(
@@ -17619,7 +17779,6 @@
 }
 
 TEST_P(QuicConnectionTest, RtoDoesntDisableEcnMarkingIfEcnAcked) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
   EXPECT_TRUE(connection_.set_ecn_codepoint(ECN_ECT1));
   QuicPacketCreatorPeer::SetPacketNumber(
@@ -17637,7 +17796,6 @@
 }
 
 TEST_P(QuicConnectionTest, InvalidFeedbackCancelsEcn) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
   EXPECT_TRUE(connection_.set_ecn_codepoint(ECN_ECT1));
   EXPECT_EQ(connection_.ecn_codepoint(), ECN_ECT1);
@@ -17646,7 +17804,6 @@
 }
 
 TEST_P(QuicConnectionTest, StateMatchesSentEcn) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
   EXPECT_TRUE(connection_.set_ecn_codepoint(ECN_ECT1));
   SendPing();
@@ -17662,7 +17819,6 @@
   if (!connection_.version().CanSendCoalescedPackets()) {
     return;
   }
-  SetQuicRestartFlag(quic_support_ect1, true);
   EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
   EXPECT_TRUE(connection_.set_ecn_codepoint(ECN_ECT1));
   // All these steps are necessary to send an INITIAL ping and save it to be
@@ -17686,7 +17842,6 @@
 }
 
 TEST_P(QuicConnectionTest, BufferedPacketRetainsOldEcn) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
   EXPECT_TRUE(connection_.set_ecn_codepoint(ECN_ECT1));
   writer_->SetWriteBlocked();
@@ -17700,7 +17855,6 @@
 }
 
 TEST_P(QuicConnectionTest, RejectEcnIfWriterDoesNotSupport) {
-  SetQuicRestartFlag(quic_support_ect1, true);
   MockPacketWriter mock_writer;
   QuicConnectionPeer::SetWriter(&connection_, &mock_writer, false);
   EXPECT_CALL(mock_writer, SupportsEcn()).WillOnce(Return(false));
@@ -17713,6 +17867,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.SetReliableStreamReset(false);
   connection_.SetFromConfig(config);
@@ -17727,6 +17883,8 @@
     return;
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillOnce(Return(false));
   QuicConfig config;
   config.SetReliableStreamReset(true);
   connection_.SetFromConfig(config);
diff --git a/quiche/quic/core/quic_dispatcher_test.cc b/quiche/quic/core/quic_dispatcher_test.cc
index c2ed31e..9585a15 100644
--- a/quiche/quic/core/quic_dispatcher_test.cc
+++ b/quiche/quic/core/quic_dispatcher_test.cc
@@ -3190,7 +3190,6 @@
   if (!version_.HasIetfQuicFrames()) {
     return;
   }
-  SetQuicRestartFlag(quic_support_ect1, true);
   InSequence s;
   QuicConnectionId conn_id = TestConnectionId(1);
   // Process non-CHLO packet. This ProcessUndecryptableEarlyPacket() but with
diff --git a/quiche/quic/core/quic_sent_packet_manager.cc b/quiche/quic/core/quic_sent_packet_manager.cc
index c713350..7b270f2 100644
--- a/quiche/quic/core/quic_sent_packet_manager.cc
+++ b/quiche/quic/core/quic_sent_packet_manager.cc
@@ -383,7 +383,6 @@
   // is necessary.
   QuicPacketCount newly_acked_ect = 0, newly_acked_ce = 0;
   if (ecn_counts.has_value()) {
-    QUICHE_DCHECK(GetQuicRestartFlag(quic_support_ect1));
     newly_acked_ect = ecn_counts->ect1 - previous_counts.ect1;
     if (newly_acked_ect == 0) {
       newly_acked_ect = ecn_counts->ect0 - previous_counts.ect0;
@@ -1466,8 +1465,7 @@
   last_ack_frame_.ecn_counters = ecn_counts;
   // Validate ECN feedback.
   std::optional<QuicEcnCounts> valid_ecn_counts;
-  if (GetQuicRestartFlag(quic_support_ect1)) {
-    QUIC_RESTART_FLAG_COUNT_N(quic_support_ect1, 1, 9);
+  if (ecn_queried_) {
     if (IsEcnFeedbackValid(acked_packet_number_space, ecn_counts,
                            newly_acked_ect0, newly_acked_ect1)) {
       valid_ecn_counts = ecn_counts;
diff --git a/quiche/quic/core/quic_sent_packet_manager.h b/quiche/quic/core/quic_sent_packet_manager.h
index 43176c3..2a9474e 100644
--- a/quiche/quic/core/quic_sent_packet_manager.h
+++ b/quiche/quic/core/quic_sent_packet_manager.h
@@ -412,8 +412,14 @@
 
   // Wrapper for SendAlgorithmInterface functions, since these functions are
   // not const.
-  bool EnableECT0() { return send_algorithm_->EnableECT0(); }
-  bool EnableECT1() { return send_algorithm_->EnableECT1(); }
+  bool EnableECT0() {
+    ecn_queried_ = send_algorithm_->EnableECT0();
+    return ecn_queried_;
+  }
+  bool EnableECT1() {
+    ecn_queried_ = send_algorithm_->EnableECT1();
+    return ecn_queried_;
+  }
 
   void SetSessionNotifier(SessionNotifierInterface* session_notifier) {
     unacked_packets_.SetSessionNotifier(session_notifier);
@@ -740,6 +746,11 @@
   QuicEcnCounts peer_ack_ecn_counts_[NUM_PACKET_NUMBER_SPACES];
 
   std::optional<QuicTime::Delta> deferred_send_alarm_delay_;
+
+  // If true, QuicConnection has called EnableECT0() or EnableECT1(). This is
+  // used to prevent the execution of ECN-specific code unless flag-protected
+  // code has explicitly enabled it.
+  bool ecn_queried_ = false;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/quic_sent_packet_manager_test.cc b/quiche/quic/core/quic_sent_packet_manager_test.cc
index 9efbf9a..cbe8861 100644
--- a/quiche/quic/core/quic_sent_packet_manager_test.cc
+++ b/quiche/quic/core/quic_sent_packet_manager_test.cc
@@ -17,7 +17,6 @@
 #include "quiche/quic/core/quic_packet_number.h"
 #include "quiche/quic/core/quic_time.h"
 #include "quiche/quic/core/quic_types.h"
-#include "quiche/quic/platform/api/quic_expect_bug.h"
 #include "quiche/quic/platform/api/quic_flags.h"
 #include "quiche/quic/platform/api/quic_test.h"
 #include "quiche/quic/test_tools/quic_config_peer.h"
@@ -1315,6 +1314,18 @@
   EXPECT_EQ(kRenoBytes, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
                             ->GetCongestionControlType());
 
+  // Prague Cubic is currently only supported on the client.
+  QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_SERVER);
+  options.clear();
+  options.push_back(kPRGC);
+  config.SetClientConnectionOptions(options);
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  manager_.SetFromConfig(config);
+  // This is the server, so the algorithm didn't change.
+  EXPECT_EQ(kRenoBytes, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
+                            ->GetCongestionControlType());
+
+  QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
   options.clear();
   options.push_back(kPRGC);
   config.SetClientConnectionOptions(options);
@@ -3237,9 +3248,8 @@
 }
 
 TEST_F(QuicSentPacketManagerTest, EcnCountsAreStored) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   std::optional<QuicEcnCounts> ecn_counts1, ecn_counts2, ecn_counts3;
   ecn_counts1 = {1, 0, 3};
   ecn_counts2 = {0, 3, 1};
@@ -3307,9 +3317,8 @@
 }
 
 TEST_F(QuicSentPacketManagerTest, EcnCountsReceived) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   // Basic ECN reporting test. The reported counts are equal to the total sent,
   // but more than the total acked. This is legal per the spec.
   for (uint64_t i = 1; i <= 3; ++i) {
@@ -3334,9 +3343,8 @@
 }
 
 TEST_F(QuicSentPacketManagerTest, PeerDecrementsEcnCounts) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   for (uint64_t i = 1; i <= 5; ++i) {
     SendDataPacket(i, ENCRYPTION_FORWARD_SECURE, ECN_ECT1);
   }
@@ -3376,9 +3384,8 @@
 }
 
 TEST_F(QuicSentPacketManagerTest, TooManyEcnCountsReported) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   for (uint64_t i = 1; i <= 3; ++i) {
     SendDataPacket(i, ENCRYPTION_FORWARD_SECURE, ECN_ECT1);
   }
@@ -3404,9 +3411,8 @@
 }
 
 TEST_F(QuicSentPacketManagerTest, PeerReportsWrongCodepoint) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   for (uint64_t i = 1; i <= 3; ++i) {
     SendDataPacket(i, ENCRYPTION_FORWARD_SECURE, ECN_ECT1);
   }
@@ -3432,9 +3438,8 @@
 }
 
 TEST_F(QuicSentPacketManagerTest, TooFewEcnCountsReported) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   for (uint64_t i = 1; i <= 3; ++i) {
     SendDataPacket(i, ENCRYPTION_FORWARD_SECURE, ECN_ECT1);
   }
@@ -3460,9 +3465,8 @@
 
 TEST_F(QuicSentPacketManagerTest,
        EcnCountsNotValidatedIfLargestAckedUnchanged) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   for (uint64_t i = 1; i <= 3; ++i) {
     SendDataPacket(i, ENCRYPTION_FORWARD_SECURE, ECN_ECT1);
   }
@@ -3503,9 +3507,8 @@
 }
 
 TEST_F(QuicSentPacketManagerTest, EcnAckedButNoMarksReported) {
-  if (!GetQuicRestartFlag(quic_support_ect1)) {
-    return;
-  }
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillOnce(Return(true));
+  manager_.EnableECT1();
   for (uint64_t i = 1; i <= 3; ++i) {
     SendDataPacket(i, ENCRYPTION_FORWARD_SECURE, ECN_ECT1);
   }
diff --git a/quiche/quic/core/quic_udp_socket_posix.inc b/quiche/quic/core/quic_udp_socket_posix.inc
index 1b44203..cbcfbbd 100644
--- a/quiche/quic/core/quic_udp_socket_posix.inc
+++ b/quiche/quic/core/quic_udp_socket_posix.inc
@@ -570,8 +570,8 @@
     int cmsg_type;
     unsigned char value_buf[20];
     socklen_t value_len = sizeof(value_buf);
-    if (GetQuicRestartFlag(quic_support_ect1)) {
-      QUIC_RESTART_FLAG_COUNT_N(quic_support_ect1, 9, 9);
+    if (GetQuicRestartFlag(quic_preserve_dscp_with_ecn)) {
+      QUIC_RESTART_FLAG_COUNT_N(quic_preserve_dscp_with_ecn, 1, 2);
       if (GetEcnCmsgArgsPreserveDscp(
               fd, packet_info.peer_address().host().address_family(),
               packet_info.ecn_codepoint(), cmsg_type, value_buf,
@@ -581,6 +581,9 @@
         return WriteResult(WRITE_STATUS_ERROR, EINVAL);
       }
     } else {
+      // Only some writers set QuicUdpPacketInfoBit::ECN, so verify that this
+      // is being exercised.
+      QUIC_RESTART_FLAG_COUNT_N(quic_preserve_dscp_with_ecn, 2, 2);
       cmsg_type = (cmsg_level == IPPROTO_IP) ? IP_TOS : IPV6_TCLASS;
       *(int*)value_buf = static_cast<int>(packet_info.ecn_codepoint());
       value_len = sizeof(int);
diff --git a/quiche/quic/test_tools/quic_connection_peer.cc b/quiche/quic/test_tools/quic_connection_peer.cc
index 7037c92..ccee6eb 100644
--- a/quiche/quic/test_tools/quic_connection_peer.cc
+++ b/quiche/quic/test_tools/quic_connection_peer.cc
@@ -596,11 +596,9 @@
 // static
 void QuicConnectionPeer::DisableEcnCodepointValidation(
     QuicConnection* connection) {
-  // disable_ecn_codepoint_validation_ doesn't work correctly if the flag
-  // isn't set; all tests that don't set the flag should hit this bug.
-  QUIC_BUG_IF(quic_bug_518619343_03, !GetQuicRestartFlag(quic_support_ect1))
-      << "Test disables ECN validation without setting quic_support_ect1";
   connection->disable_ecn_codepoint_validation_ = true;
+  QuicSentPacketManagerPeer::SetEcnQueried(GetSentPacketManager(connection),
+                                           true);
 }
 
 // static
diff --git a/quiche/quic/test_tools/quic_sent_packet_manager_peer.cc b/quiche/quic/test_tools/quic_sent_packet_manager_peer.cc
index a5a8cbd..2120466 100644
--- a/quiche/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/quiche/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -202,5 +202,11 @@
   return sent_packet_manager->ect1_packets_sent_[space];
 }
 
+// static
+void QuicSentPacketManagerPeer::SetEcnQueried(
+    QuicSentPacketManager* sent_packet_manager, bool ecn_queried) {
+  sent_packet_manager->ecn_queried_ = ecn_queried;
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quiche/quic/test_tools/quic_sent_packet_manager_peer.h b/quiche/quic/test_tools/quic_sent_packet_manager_peer.h
index a2b39da..7a64faf 100644
--- a/quiche/quic/test_tools/quic_sent_packet_manager_peer.h
+++ b/quiche/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -98,6 +98,9 @@
 
   static QuicPacketCount GetEct1Sent(QuicSentPacketManager* sent_packet_manager,
                                      PacketNumberSpace space);
+
+  static void SetEcnQueried(QuicSentPacketManager* sent_packet_manager,
+                            bool ecn_queried);
 };
 
 }  // namespace test