Update QuicConnection to Use ConnectionIdGeneratorInterface.

A derived class of ConnectionIdGeneratorInterface is owned by whatever owns the connection. For most servers, this will be QuicDispatcher, which in turn receives the Generator from whatever owns it.

For Envoy-based consumers of Quiche, generate a derived class of ConnectionIdGeneratorInterface and pass a reference to it into the Constructor for QuicConnection.

The MockQuicConnection and MockGfeQuicConnection classes contain their own MockConnectionIdGenerators instead of taking the interface as a constructor argument, in attempt to reduce the footprint of this CL by several dozen files. It also makes it so that MockQuicConnectionUsers don't have to worry about generators, which is good for most users.

Protected by FLAGS_quic_reloadable_flag_quic_connection_uses_abstract_connection_id_generator.

PiperOrigin-RevId: 471570565
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index ec509b7..999e174 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -253,7 +253,8 @@
     QuicSocketAddress initial_peer_address,
     QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory,
     QuicPacketWriter* writer, bool owns_writer, Perspective perspective,
-    const ParsedQuicVersionVector& supported_versions)
+    const ParsedQuicVersionVector& supported_versions,
+    ConnectionIdGeneratorInterface& generator)
     : framer_(supported_versions, helper->GetClock()->ApproximateNow(),
               perspective, server_connection_id.length()),
       current_packet_content_(NO_FRAMES_RECEIVED),
@@ -342,7 +343,8 @@
       path_validator_(alarm_factory_, &arena_, this, random_generator_, clock_,
                       &context_),
       ping_manager_(perspective, this, &arena_, alarm_factory_, &context_),
-      multi_port_probing_interval_(kDefaultMultiPortProbingInterval) {
+      multi_port_probing_interval_(kDefaultMultiPortProbingInterval),
+      connection_id_generator_(generator) {
   QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT ||
                 default_path_.self_address.IsInitialized());
 
@@ -4014,7 +4016,7 @@
       perspective_ == Perspective::IS_CLIENT
           ? default_path_.client_connection_id
           : default_path_.server_connection_id,
-      clock_, alarm_factory_, this, context());
+      clock_, alarm_factory_, this, context(), connection_id_generator_);
 }
 
 void QuicConnection::MaybeSendConnectionIdToClient() {
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 5c94c50..fd4c420 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -475,7 +475,8 @@
                  QuicConnectionHelperInterface* helper,
                  QuicAlarmFactory* alarm_factory, QuicPacketWriter* writer,
                  bool owns_writer, Perspective perspective,
-                 const ParsedQuicVersionVector& supported_versions);
+                 const ParsedQuicVersionVector& supported_versions,
+                 ConnectionIdGeneratorInterface& generator);
   QuicConnection(const QuicConnection&) = delete;
   QuicConnection& operator=(const QuicConnection&) = delete;
   ~QuicConnection() override;
@@ -1346,6 +1347,10 @@
     return defer_send_in_response_to_packets_;
   }
 
+  ConnectionIdGeneratorInterface& connection_id_generator() const {
+    return connection_id_generator_;
+  }
+
  private:
   friend class test::QuicConnectionPeer;
 
@@ -2290,6 +2295,8 @@
   // limit.
   const bool enforce_strict_amplification_factor_ =
       GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor);
+
+  ConnectionIdGeneratorInterface& connection_id_generator_;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/quic_connection_id_manager.cc b/quiche/quic/core/quic_connection_id_manager.cc
index 17f7a72..a3909f3 100644
--- a/quiche/quic/core/quic_connection_id_manager.cc
+++ b/quiche/quic/core/quic_connection_id_manager.cc
@@ -11,6 +11,7 @@
 #include "quiche/quic/core/quic_error_codes.h"
 #include "quiche/quic/core/quic_utils.h"
 #include "quiche/quic/platform/api/quic_flag_utils.h"
+#include "quiche/quic/platform/api/quic_flags.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 
 namespace quic {
@@ -278,7 +279,7 @@
     const QuicConnectionId& initial_connection_id, const QuicClock* clock,
     QuicAlarmFactory* alarm_factory,
     QuicConnectionIdManagerVisitorInterface* visitor,
-    QuicConnectionContext* context)
+    QuicConnectionContext* context, ConnectionIdGeneratorInterface& generator)
     : active_connection_id_limit_(active_connection_id_limit),
       clock_(clock),
       visitor_(visitor),
@@ -286,7 +287,8 @@
           new RetireSelfIssuedConnectionIdAlarmDelegate(this, context))),
       last_connection_id_(initial_connection_id),
       next_connection_id_sequence_number_(1u),
-      last_connection_id_consumed_by_self_sequence_number_(0u) {
+      last_connection_id_consumed_by_self_sequence_number_(0u),
+      connection_id_generator_(generator) {
   active_connection_ids_.emplace_back(initial_connection_id, 0u);
 }
 
@@ -303,18 +305,33 @@
 QuicSelfIssuedConnectionIdManager::MaybeIssueNewConnectionId() {
   const bool check_cid_collision_when_issue_new_cid =
       GetQuicReloadableFlag(quic_check_cid_collision_when_issue_new_cid);
-  QuicConnectionId new_cid = GenerateNewConnectionId(last_connection_id_);
+  absl::optional<QuicConnectionId> new_cid;
+  if (GetQuicReloadableFlag(
+          quic_connection_uses_abstract_connection_id_generator)) {
+    QUIC_RELOADABLE_FLAG_COUNT(
+        quic_connection_uses_abstract_connection_id_generator);
+    new_cid =
+        connection_id_generator_.GenerateNextConnectionId(last_connection_id_);
+  } else {
+    new_cid = GenerateNewConnectionId(last_connection_id_);
+  }
+  if (!new_cid.has_value()) {
+    QUIC_BUG_IF(quic_bug_469887433_1,
+                !GetQuicReloadableFlag(
+                    quic_connection_uses_abstract_connection_id_generator));
+    return {};
+  }
   if (check_cid_collision_when_issue_new_cid) {
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_cid_collision_when_issue_new_cid, 1,
                                  2);
-    if (!visitor_->MaybeReserveConnectionId(new_cid)) {
+    if (!visitor_->MaybeReserveConnectionId(*new_cid)) {
       QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_cid_collision_when_issue_new_cid,
                                    2, 2);
       return {};
     }
   }
   QuicNewConnectionIdFrame frame;
-  frame.connection_id = new_cid;
+  frame.connection_id = *new_cid;
   frame.sequence_number = next_connection_id_sequence_number_++;
   frame.stateless_reset_token =
       QuicUtils::GenerateStatelessResetToken(frame.connection_id);
diff --git a/quiche/quic/core/quic_connection_id_manager.h b/quiche/quic/core/quic_connection_id_manager.h
index 7f271e2..1fa48e9 100644
--- a/quiche/quic/core/quic_connection_id_manager.h
+++ b/quiche/quic/core/quic_connection_id_manager.h
@@ -14,6 +14,7 @@
 #include <memory>
 
 #include "absl/types/optional.h"
+#include "quiche/quic/core/connection_id_generator.h"
 #include "quiche/quic/core/frames/quic_new_connection_id_frame.h"
 #include "quiche/quic/core/frames/quic_retire_connection_id_frame.h"
 #include "quiche/quic/core/quic_alarm.h"
@@ -126,7 +127,8 @@
       const QuicConnectionId& initial_connection_id, const QuicClock* clock,
       QuicAlarmFactory* alarm_factory,
       QuicConnectionIdManagerVisitorInterface* visitor,
-      QuicConnectionContext* context);
+      QuicConnectionContext* context,
+      ConnectionIdGeneratorInterface& generator);
 
   virtual ~QuicSelfIssuedConnectionIdManager();
 
@@ -159,6 +161,9 @@
   // tell if a received packet has a valid connection ID.
   bool IsConnectionIdInUse(const QuicConnectionId& cid) const;
 
+  // TODO(martinduke): This class will be eliminated when
+  // FLAGS_gfe2_reloadable_flag_quic_connection_uses_abstract_connection_id_generator
+  // goes away.
   virtual QuicConnectionId GenerateNewConnectionId(
       const QuicConnectionId& old_connection_id) const;
 
@@ -189,6 +194,8 @@
   uint64_t next_connection_id_sequence_number_;
   // The sequence number of last connection ID consumed.
   uint64_t last_connection_id_consumed_by_self_sequence_number_;
+
+  ConnectionIdGeneratorInterface& connection_id_generator_;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/quic_connection_id_manager_test.cc b/quiche/quic/core/quic_connection_id_manager_test.cc
index dbd239f..c0f1333 100644
--- a/quiche/quic/core/quic_connection_id_manager_test.cc
+++ b/quiche/quic/core/quic_connection_id_manager_test.cc
@@ -10,6 +10,7 @@
 #include "quiche/quic/core/quic_error_codes.h"
 #include "quiche/quic/platform/api/quic_test.h"
 #include "quiche/quic/test_tools/mock_clock.h"
+#include "quiche/quic/test_tools/mock_connection_id_generator.h"
 #include "quiche/quic/test_tools/quic_connection_id_manager_peer.h"
 #include "quiche/quic/test_tools/quic_test_utils.h"
 
@@ -535,7 +536,7 @@
   QuicSelfIssuedConnectionIdManagerTest()
       : cid_manager_(/*active_connection_id_limit*/ 2, initial_connection_id_,
                      &clock_, &alarm_factory_, &cid_manager_visitor_,
-                     /*context=*/nullptr) {
+                     /*context=*/nullptr, connection_id_generator_) {
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
     retire_self_issued_cid_alarm_ =
         QuicConnectionIdManagerPeer::GetRetireSelfIssuedConnectionIdAlarm(
@@ -543,6 +544,18 @@
   }
 
  protected:
+  // Verify that a call to GenerateNewConnectionId() does the right thing.
+  QuicConnectionId CheckGenerate(QuicConnectionId old_cid) {
+    QuicConnectionId new_cid =
+        QuicUtils::CreateReplacementConnectionId(old_cid);
+    if (GetQuicRestartFlag(quic_abstract_connection_id_generator)) {
+      // Ready for the actual call.
+      EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(old_cid))
+          .WillOnce(Return(new_cid));
+    }
+    return new_cid;
+  }
+
   MockClock clock_;
   test::MockAlarmFactory alarm_factory_;
   TestSelfIssuedConnectionIdManagerVisitor cid_manager_visitor_;
@@ -551,6 +564,7 @@
   QuicAlarm* retire_self_issued_cid_alarm_ = nullptr;
   std::string error_details_;
   QuicTime::Delta pto_delay_ = QuicTime::Delta::FromMilliseconds(10);
+  MockConnectionIdGenerator connection_id_generator_;
 };
 
 MATCHER_P3(ExpectedNewConnectionIdFrame, connection_id, sequence_number,
@@ -563,11 +577,11 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        RetireSelfIssuedConnectionIdInOrder) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
-  QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
-  QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
-  QuicConnectionId cid4 = cid_manager_.GenerateNewConnectionId(cid3);
-  QuicConnectionId cid5 = cid_manager_.GenerateNewConnectionId(cid4);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
+  QuicConnectionId cid2 = CheckGenerate(cid1);
+  QuicConnectionId cid3 = CheckGenerate(cid2);
+  QuicConnectionId cid4 = CheckGenerate(cid3);
+  QuicConnectionId cid5 = CheckGenerate(cid4);
 
   // Sends CID #1 to peer.
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
@@ -645,10 +659,10 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        RetireSelfIssuedConnectionIdOutOfOrder) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
-  QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
-  QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
-  QuicConnectionId cid4 = cid_manager_.GenerateNewConnectionId(cid3);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
+  QuicConnectionId cid2 = CheckGenerate(cid1);
+  QuicConnectionId cid3 = CheckGenerate(cid2);
+  QuicConnectionId cid4 = CheckGenerate(cid3);
 
   // Sends CID #1 to peer.
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
@@ -728,9 +742,9 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        ScheduleConnectionIdRetirementOneAtATime) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
-  QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
-  QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
+  QuicConnectionId cid2 = CheckGenerate(cid1);
+  QuicConnectionId cid3 = CheckGenerate(cid2);
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
       .Times(3)
       .WillRepeatedly(Return(true));
@@ -787,9 +801,9 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        ScheduleMultipleConnectionIdRetirement) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
-  QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
-  QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
+  QuicConnectionId cid2 = CheckGenerate(cid1);
+  QuicConnectionId cid3 = CheckGenerate(cid2);
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
       .Times(3)
       .WillRepeatedly(Return(true));
@@ -845,9 +859,9 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        AllExpiredConnectionIdsAreRetiredInOneBatch) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
-  QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
-  QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
+  QuicConnectionId cid2 = CheckGenerate(cid1);
+  QuicConnectionId cid3 = CheckGenerate(cid2);
   QuicConnectionId cid;
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
       .Times(3)
@@ -907,7 +921,7 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        ErrorWhenRetireConnectionIdNeverIssued) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
 
   // CID #1 is sent to peer.
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
@@ -927,17 +941,20 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        ErrorWhenTooManyConnectionIdWaitingToBeRetired) {
   // CID #0 & #1 are issued.
-  EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+  QuicConnectionId last_connection_id = CheckGenerate(initial_connection_id_);
+  EXPECT_CALL(cid_manager_visitor_,
+              MaybeReserveConnectionId(last_connection_id))
       .WillOnce(Return(true));
   EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
       .WillOnce(Return(true));
   cid_manager_.MaybeSendNewConnectionIds();
 
   // Add 8 connection IDs to the to-be-retired list.
-  QuicConnectionId last_connection_id =
-      cid_manager_.GenerateNewConnectionId(initial_connection_id_);
+
   for (int i = 0; i < 8; ++i) {
-    EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+    last_connection_id = CheckGenerate(last_connection_id);
+    EXPECT_CALL(cid_manager_visitor_,
+                MaybeReserveConnectionId(last_connection_id))
         .WillOnce(Return(true));
     EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_));
     QuicRetireConnectionIdFrame retire_cid_frame;
@@ -945,8 +962,6 @@
     ASSERT_THAT(cid_manager_.OnRetireConnectionIdFrame(
                     retire_cid_frame, pto_delay_, &error_details_),
                 IsQuicNoError());
-    last_connection_id =
-        cid_manager_.GenerateNewConnectionId(last_connection_id);
   }
   QuicRetireConnectionIdFrame retire_cid_frame;
   retire_cid_frame.sequence_number = 8u;
@@ -959,7 +974,7 @@
 
 TEST_F(QuicSelfIssuedConnectionIdManagerTest, CannotIssueNewCidDueToVisitor) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
       .WillOnce(Return(false));
   if (GetQuicReloadableFlag(quic_check_cid_collision_when_issue_new_cid)) {
@@ -973,8 +988,8 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        CannotIssueNewCidUponRetireConnectionIdDueToVisitor) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
-  QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
+  QuicConnectionId cid2 = CheckGenerate(cid1);
   // CID #0 & #1 are issued.
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
       .WillOnce(Return(true));
@@ -1000,7 +1015,7 @@
 TEST_F(QuicSelfIssuedConnectionIdManagerTest,
        DoNotIssueConnectionIdVoluntarilyIfOneHasIssuedForPerferredAddress) {
   QuicConnectionId cid0 = initial_connection_id_;
-  QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
+  QuicConnectionId cid1 = CheckGenerate(cid0);
   EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
       .WillOnce(Return(true));
   absl::optional<QuicNewConnectionIdFrame> new_cid_frame =
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 2801334..9ff8413 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -41,6 +41,7 @@
 #include "quiche/quic/platform/api/quic_socket_address.h"
 #include "quiche/quic/platform/api/quic_test.h"
 #include "quiche/quic/test_tools/mock_clock.h"
+#include "quiche/quic/test_tools/mock_connection_id_generator.h"
 #include "quiche/quic/test_tools/mock_random.h"
 #include "quiche/quic/test_tools/quic_coalesced_packet_peer.h"
 #include "quiche/quic/test_tools/quic_config_peer.h"
@@ -187,11 +188,12 @@
                  QuicSocketAddress initial_peer_address,
                  TestConnectionHelper* helper, TestAlarmFactory* alarm_factory,
                  TestPacketWriter* writer, Perspective perspective,
-                 ParsedQuicVersion version)
+                 ParsedQuicVersion version,
+                 ConnectionIdGeneratorInterface& generator)
       : QuicConnection(connection_id, initial_self_address,
                        initial_peer_address, helper, alarm_factory, writer,
                        /* owns_writer= */ false, perspective,
-                       SupportedVersions(version)),
+                       SupportedVersions(version), generator),
         notifier_(nullptr) {
     writer->set_perspective(perspective);
     SetEncrypter(ENCRYPTION_FORWARD_SECURE,
@@ -611,7 +613,7 @@
             new TestPacketWriter(version(), &clock_, Perspective::IS_CLIENT)),
         connection_(connection_id_, kSelfAddress, kPeerAddress, helper_.get(),
                     alarm_factory_.get(), writer_.get(), Perspective::IS_CLIENT,
-                    version()),
+                    version(), connection_id_generator_),
         creator_(QuicConnectionPeer::GetPacketCreator(&connection_)),
         manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)),
         frame1_(0, false, 0, absl::string_view(data1)),
@@ -1493,6 +1495,7 @@
 
   QuicConnectionCloseFrame saved_connection_close_frame_;
   int connection_close_frame_count_;
+  MockConnectionIdGenerator connection_id_generator_;
 };
 
 // Run all end to end tests with all supported versions.
@@ -1873,6 +1876,11 @@
   QuicConnectionPeer::SetAddressValidated(&connection_);
 
   // Sends new server CID to client.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke([&](const QuicConnectionId& cid) {
         server_cid1 = cid;
@@ -2072,6 +2080,11 @@
 
   // Sends new server CID to client.
   QuicConnectionId new_cid;
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke([&](const QuicConnectionId& cid) {
         new_cid = cid;
@@ -2130,6 +2143,11 @@
 
   // Sends new server CID to client.
   QuicConnectionId new_cid;
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke([&](const QuicConnectionId& cid) {
         new_cid = cid;
@@ -2198,6 +2216,11 @@
   QuicConnectionId server_cid0 = connection_.connection_id();
   QuicConnectionId server_cid1;
   // Sends new server CID to client.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke([&](const QuicConnectionId& cid) {
         server_cid1 = cid;
@@ -2870,7 +2893,8 @@
 TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) {
   TestConnection connection(TestConnectionId(), kSelfAddress, kPeerAddress,
                             helper_.get(), alarm_factory_.get(), writer_.get(),
-                            Perspective::IS_SERVER, version());
+                            Perspective::IS_SERVER, version(),
+                            connection_id_generator_);
   EXPECT_EQ(Perspective::IS_SERVER, connection.perspective());
   EXPECT_EQ(1000u, connection.max_packet_length());
 }
@@ -2999,7 +3023,8 @@
   writer_->set_max_packet_size(lower_max_packet_size);
   TestConnection connection(connection_id, kSelfAddress, kPeerAddress,
                             helper_.get(), alarm_factory_.get(), writer_.get(),
-                            Perspective::IS_CLIENT, version());
+                            Perspective::IS_CLIENT, version(),
+                            connection_id_generator_);
   EXPECT_EQ(Perspective::IS_CLIENT, connection.perspective());
   EXPECT_EQ(lower_max_packet_size, connection.max_packet_length());
 }
@@ -6926,10 +6951,12 @@
 TEST_P(QuicConnectionTest, Pacing) {
   TestConnection server(connection_id_, kPeerAddress, kSelfAddress,
                         helper_.get(), alarm_factory_.get(), writer_.get(),
-                        Perspective::IS_SERVER, version());
+                        Perspective::IS_SERVER, version(),
+                        connection_id_generator_);
   TestConnection client(connection_id_, kSelfAddress, kPeerAddress,
                         helper_.get(), alarm_factory_.get(), writer_.get(),
-                        Perspective::IS_CLIENT, version());
+                        Perspective::IS_CLIENT, version(),
+                        connection_id_generator_);
   EXPECT_FALSE(QuicSentPacketManagerPeer::UsingPacing(
       static_cast<const QuicSentPacketManager*>(
           &client.sent_packet_manager())));
@@ -13294,6 +13321,11 @@
   QuicConnectionId client_cid1 = TestConnectionId(2);
   QuicConnectionId server_cid1;
   // Sends new server CID to client.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke([&](const QuicConnectionId& cid) {
         server_cid1 = cid;
@@ -13442,6 +13474,11 @@
   QuicConnectionId server_cid0 = connection_.connection_id();
   QuicConnectionId server_cid1;
   // Sends new server CID to client.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke([&](const QuicConnectionId& cid) {
         server_cid1 = cid;
@@ -13563,6 +13600,11 @@
   QuicConnectionId client_cid1 = TestConnectionId(2);
   QuicConnectionId server_cid1;
   // Sends new server CID to client.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke([&](const QuicConnectionId& cid) {
         server_cid1 = cid;
@@ -13679,6 +13721,11 @@
   QuicConnectionId client_cid1 = TestConnectionId(2);
   QuicConnectionId server_cid1;
   // Sends new server CID to client.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_)).WillOnce(Return(false));
   if (GetQuicReloadableFlag(quic_check_cid_collision_when_issue_new_cid)) {
     EXPECT_CALL(visitor_, SendNewConnectionId(_)).Times(0);
@@ -13812,6 +13859,10 @@
   ASSERT_EQ(packet_creator->GetDestinationConnectionId(), server_cid0);
 
   // Client will issue a new client connection ID to server.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator)) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, SendNewConnectionId(_))
       .WillOnce(Invoke([&](const QuicNewConnectionIdFrame& frame) {
         client_cid1 = frame.connection_id;
@@ -13970,6 +14021,10 @@
 
   // Client will issue a new client connection ID to server.
   QuicConnectionId new_client_connection_id;
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator)) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, SendNewConnectionId(_))
       .WillOnce(Invoke([&](const QuicNewConnectionIdFrame& frame) {
         new_client_connection_id = frame.connection_id;
@@ -14223,6 +14278,11 @@
   set_perspective(Perspective::IS_SERVER);
   connection_.CreateConnectionIdManager();
 
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_));
   EXPECT_CALL(visitor_, SendNewConnectionId(_));
   connection_.MaybeSendConnectionIdToClient();
@@ -14256,6 +14316,14 @@
   QuicRetireConnectionIdFrame frame;
   frame.sequence_number = 0u;
   if (connection_.connection_migration_use_new_cid()) {
+    if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+        !connection_.connection_id().IsEmpty()) {
+      EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(cid0))
+          .WillOnce(Return(TestConnectionId(456)));
+      EXPECT_CALL(connection_id_generator_,
+                  GenerateNextConnectionId(TestConnectionId(456)))
+          .WillOnce(Return(TestConnectionId(789)));
+    }
     EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
         .Times(2)
         .WillRepeatedly(Return(true));
@@ -14289,6 +14357,11 @@
   EXPECT_EQ(connection_.GetOneActiveServerConnectionId(), cid0);
 
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke(cid_recorder));
   EXPECT_CALL(visitor_, SendNewConnectionId(_));
@@ -14320,6 +14393,11 @@
 
   // Packet2 with RetireConnectionId frame trigers sending NewConnectionId
   // immediately.
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator) &&
+      !connection_.connection_id().IsEmpty()) {
+    EXPECT_CALL(connection_id_generator_, GenerateNextConnectionId(_))
+        .WillOnce(Return(TestConnectionId(456)));
+  }
   EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
       .WillOnce(Invoke(cid_recorder));
   EXPECT_CALL(visitor_, SendNewConnectionId(_));
@@ -14730,6 +14808,14 @@
       !connection_.connection_migration_use_new_cid()) {
     return;
   }
+  if (GetQuicRestartFlag(quic_abstract_connection_id_generator)) {
+    EXPECT_CALL(connection_id_generator_,
+                GenerateNextConnectionId(TestConnectionId(12)))
+        .WillOnce(Return(TestConnectionId(456)));
+    EXPECT_CALL(connection_id_generator_,
+                GenerateNextConnectionId(TestConnectionId(456)))
+        .WillOnce(Return(TestConnectionId(789)));
+  }
   EXPECT_CALL(visitor_, SendNewConnectionId(_)).Times(2);
   EXPECT_CALL(visitor_, OnRstStream(_));
   EXPECT_CALL(visitor_, OnWindowUpdateFrame(_));
diff --git a/quiche/quic/core/quic_dispatcher.h b/quiche/quic/core/quic_dispatcher.h
index b461690..e2b7761 100644
--- a/quiche/quic/core/quic_dispatcher.h
+++ b/quiche/quic/core/quic_dispatcher.h
@@ -352,6 +352,10 @@
   virtual void MaybeResetPacketsWithNoVersion(
       const quic::ReceivedPacketInfo& packet_info);
 
+  ConnectionIdGeneratorInterface& connection_id_generator() {
+    return connection_id_generator_;
+  }
+
  private:
   friend class test::QuicDispatcherPeer;
 
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h
index 284dd25..793237c 100644
--- a/quiche/quic/core/quic_flags_list.h
+++ b/quiche/quic/core/quic_flags_list.h
@@ -95,10 +95,12 @@
 QUIC_FLAG(quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false)
 // If true, validate header field character at spdy stream instead of qpack for IETF QUIC.
 QUIC_FLAG(quic_reloadable_flag_quic_validate_header_field_value_at_spdy_stream, true)
+// QuicConnection uses a library to generate connection IDs
+QUIC_FLAG(quic_reloadable_flag_quic_connection_uses_abstract_connection_id_generator, false)
+// QuicDispatcher uses a library to generate connection IDs
+QUIC_FLAG(quic_restart_flag_quic_abstract_connection_id_generator, false)
 // Store original QUIC connection IDs in the dispatcher\'s map
 QUIC_FLAG(quic_restart_flag_quic_map_original_connection_ids2, true)
-// Use a library to generate connection IDs
-QUIC_FLAG(quic_restart_flag_quic_abstract_connection_id_generator, false)
 // When the flag is true, exit STARTUP after the same number of loss events as PROBE_UP.
 QUIC_FLAG(quic_reloadable_flag_quic_bbr2_startup_probe_up_loss_events, true)
 // When true, defaults to BBR congestion control instead of Cubic.
diff --git a/quiche/quic/masque/masque_dispatcher.cc b/quiche/quic/masque/masque_dispatcher.cc
index 6e081aa..40ba112 100644
--- a/quiche/quic/masque/masque_dispatcher.cc
+++ b/quiche/quic/masque/masque_dispatcher.cc
@@ -32,11 +32,11 @@
     const ParsedQuicVersion& version,
     const ParsedClientHello& /*parsed_chlo*/) {
   // The MasqueServerSession takes ownership of |connection| below.
-  QuicConnection* connection =
-      new QuicConnection(connection_id, self_address, peer_address, helper(),
-                         alarm_factory(), writer(),
-                         /*owns_writer=*/false, Perspective::IS_SERVER,
-                         ParsedQuicVersionVector{version});
+  QuicConnection* connection = new QuicConnection(
+      connection_id, self_address, peer_address, helper(), alarm_factory(),
+      writer(),
+      /*owns_writer=*/false, Perspective::IS_SERVER,
+      ParsedQuicVersionVector{version}, connection_id_generator());
 
   auto session = std::make_unique<MasqueServerSession>(
       masque_mode_, config(), GetSupportedVersions(), connection, this,
diff --git a/quiche/quic/qbone/qbone_client_test.cc b/quiche/quic/qbone/qbone_client_test.cc
index 2f7acda..0029115 100644
--- a/quiche/quic/qbone/qbone_client_test.cc
+++ b/quiche/quic/qbone/qbone_client_test.cc
@@ -120,7 +120,7 @@
     QuicConnection* connection = new QuicConnection(
         id, self_address, peer_address, helper(), alarm_factory(), writer(),
         /* owns_writer= */ false, Perspective::IS_SERVER,
-        ParsedQuicVersionVector{version});
+        ParsedQuicVersionVector{version}, connection_id_generator());
     // The connection owning wrapper owns the connection created.
     auto session = std::make_unique<ConnectionOwningQboneServerSession>(
         GetSupportedVersions(), connection, this, config(), crypto_config(),
diff --git a/quiche/quic/qbone/qbone_session_test.cc b/quiche/quic/qbone/qbone_session_test.cc
index faa1d3a..0bc008b 100644
--- a/quiche/quic/qbone/qbone_session_test.cc
+++ b/quiche/quic/qbone/qbone_session_test.cc
@@ -19,6 +19,7 @@
 #include "quiche/quic/qbone/qbone_server_session.h"
 #include "quiche/quic/test_tools/crypto_test_utils.h"
 #include "quiche/quic/test_tools/mock_clock.h"
+#include "quiche/quic/test_tools/mock_connection_id_generator.h"
 #include "quiche/quic/test_tools/quic_connection_peer.h"
 #include "quiche/quic/test_tools/quic_session_peer.h"
 #include "quiche/quic/test_tools/quic_test_utils.h"
@@ -314,7 +315,8 @@
       client_connection_ = new QuicConnection(
           TestConnectionId(), client_address, server_address, &helper_,
           alarm_factory_.get(), new NiceMock<MockPacketWriter>(), true,
-          Perspective::IS_CLIENT, supported_versions_);
+          Perspective::IS_CLIENT, supported_versions_,
+          connection_id_generator_);
       client_connection_->SetSelfAddress(client_address);
       QuicConfig config;
       client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
@@ -333,7 +335,8 @@
       server_connection_ = new QuicConnection(
           TestConnectionId(), server_address, client_address, &helper_,
           alarm_factory_.get(), new NiceMock<MockPacketWriter>(), true,
-          Perspective::IS_SERVER, supported_versions_);
+          Perspective::IS_SERVER, supported_versions_,
+          connection_id_generator_);
       server_connection_->SetSelfAddress(server_address);
       QuicConfig config;
       server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>(
@@ -538,6 +541,7 @@
 
   std::unique_ptr<QboneServerSession> server_peer_;
   std::unique_ptr<QboneClientSession> client_peer_;
+  MockConnectionIdGenerator connection_id_generator_;
 };
 
 INSTANTIATE_TEST_SUITE_P(Tests, QboneSessionTest,
diff --git a/quiche/quic/qbone/qbone_stream_test.cc b/quiche/quic/qbone/qbone_stream_test.cc
index 8392496..d7e0c81 100644
--- a/quiche/quic/qbone/qbone_stream_test.cc
+++ b/quiche/quic/qbone/qbone_stream_test.cc
@@ -15,6 +15,7 @@
 #include "quiche/quic/qbone/qbone_constants.h"
 #include "quiche/quic/qbone/qbone_session_base.h"
 #include "quiche/quic/test_tools/mock_clock.h"
+#include "quiche/quic/test_tools/mock_connection_id_generator.h"
 #include "quiche/quic/test_tools/quic_test_utils.h"
 #include "quiche/common/simple_buffer_allocator.h"
 #include "quiche/spdy/core/spdy_protocol.h"
@@ -145,7 +146,8 @@
         QuicSocketAddress(TestLoopback(), 0),
         this /*QuicConnectionHelperInterface*/, alarm_factory_.get(),
         new DummyPacketWriter(), owns_writer, perspective,
-        ParsedVersionOfIndex(CurrentSupportedVersions(), 0)));
+        ParsedVersionOfIndex(CurrentSupportedVersions(), 0),
+        connection_id_generator_));
     clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
     session_ = std::make_unique<StrictMock<MockQuicSession>>(connection_.get(),
                                                              QuicConfig());
@@ -178,6 +180,7 @@
   MockClock clock_;
   const QuicStreamId kStreamId = QuicUtils::GetFirstUnidirectionalStreamId(
       CurrentSupportedVersions()[0].transport_version, Perspective::IS_CLIENT);
+  quic::test::MockConnectionIdGenerator connection_id_generator_;
 };
 
 // Read an entire string.
diff --git a/quiche/quic/test_tools/first_flight.cc b/quiche/quic/test_tools/first_flight.cc
index ed7dd9c..dcdeac3 100644
--- a/quiche/quic/test_tools/first_flight.cc
+++ b/quiche/quic/test_tools/first_flight.cc
@@ -20,6 +20,7 @@
 #include "quiche/quic/platform/api/quic_ip_address.h"
 #include "quiche/quic/platform/api/quic_socket_address.h"
 #include "quiche/quic/test_tools/crypto_test_utils.h"
+#include "quiche/quic/test_tools/mock_connection_id_generator.h"
 #include "quiche/quic/test_tools/quic_test_utils.h"
 
 namespace quic {
@@ -55,13 +56,13 @@
 
   void GenerateFirstFlight() {
     crypto_config_->set_alpn(AlpnForVersion(version_));
-    connection_ =
-        new QuicConnection(server_connection_id_,
-                           /*initial_self_address=*/QuicSocketAddress(),
-                           QuicSocketAddress(TestPeerIPAddress(), kTestPort),
-                           &connection_helper_, &alarm_factory_, &writer_,
-                           /*owns_writer=*/false, Perspective::IS_CLIENT,
-                           ParsedQuicVersionVector{version_});
+    connection_ = new QuicConnection(
+        server_connection_id_,
+        /*initial_self_address=*/QuicSocketAddress(),
+        QuicSocketAddress(TestPeerIPAddress(), kTestPort), &connection_helper_,
+        &alarm_factory_, &writer_,
+        /*owns_writer=*/false, Perspective::IS_CLIENT,
+        ParsedQuicVersionVector{version_}, connection_id_generator_);
     connection_->set_client_connection_id(client_connection_id_);
     session_ = std::make_unique<QuicSpdyClientSession>(
         config_, ParsedQuicVersionVector{version_},
@@ -106,6 +107,7 @@
   QuicConnection* connection_;  // Owned by session_.
   std::unique_ptr<QuicSpdyClientSession> session_;
   std::vector<std::unique_ptr<QuicReceivedPacket>> packets_;
+  MockConnectionIdGenerator connection_id_generator_;
 };
 
 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
diff --git a/quiche/quic/test_tools/quic_test_server.cc b/quiche/quic/test_tools/quic_test_server.cc
index 8c270bb..ad97b4a 100644
--- a/quiche/quic/test_tools/quic_test_server.cc
+++ b/quiche/quic/test_tools/quic_test_server.cc
@@ -94,7 +94,7 @@
     QuicConnection* connection = new QuicConnection(
         id, self_address, peer_address, helper(), alarm_factory(), writer(),
         /* owns_writer= */ false, Perspective::IS_SERVER,
-        ParsedQuicVersionVector{version});
+        ParsedQuicVersionVector{version}, connection_id_generator());
 
     std::unique_ptr<QuicServerSessionBase> session;
     if (session_factory_ == nullptr && stream_factory_ == nullptr &&
diff --git a/quiche/quic/test_tools/quic_test_utils.cc b/quiche/quic/test_tools/quic_test_utils.cc
index 39ba0a7..8d1b041 100644
--- a/quiche/quic/test_tools/quic_test_utils.cc
+++ b/quiche/quic/test_tools/quic_test_utils.cc
@@ -526,7 +526,8 @@
           /*initial_self_address=*/QuicSocketAddress(QuicIpAddress::Any4(), 5),
           initial_peer_address, helper, alarm_factory,
           new testing::NiceMock<MockPacketWriter>(),
-          /* owns_writer= */ true, perspective, supported_versions) {
+          /* owns_writer= */ true, perspective, supported_versions,
+          connection_id_generator_) {
   ON_CALL(*this, OnError(_))
       .WillByDefault(
           Invoke(this, &PacketSavingConnection::QuicConnection_OnError));
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h
index feb5719..57eb068 100644
--- a/quiche/quic/test_tools/quic_test_utils.h
+++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -37,6 +37,7 @@
 #include "quiche/quic/platform/api/quic_socket_address.h"
 #include "quiche/quic/platform/api/quic_test.h"
 #include "quiche/quic/test_tools/mock_clock.h"
+#include "quiche/quic/test_tools/mock_connection_id_generator.h"
 #include "quiche/quic/test_tools/mock_quic_session_visitor.h"
 #include "quiche/quic/test_tools/mock_random.h"
 #include "quiche/quic/test_tools/quic_framer_peer.h"
@@ -721,6 +722,19 @@
                                        QuicStreamOffset offset) {
     return QuicConnection::SendCryptoData(level, write_length, offset);
   }
+
+  MockConnectionIdGenerator& connection_id_generator() {
+    return connection_id_generator_;
+  }
+
+ private:
+  // It would be more correct to pass the generator as an argument to the
+  // constructor, particularly in dispatcher tests that keep their own
+  // reference to a generator. But there are many, many instances of derived
+  // test classes that would have to declare a generator. As this object is
+  // public, it is straightforward for the caller to use it as an argument to
+  // EXPECT_CALL.
+  MockConnectionIdGenerator connection_id_generator_;
 };
 
 class PacketSavingConnection : public MockQuicConnection {
diff --git a/quiche/quic/test_tools/simulator/quic_endpoint.cc b/quiche/quic/test_tools/simulator/quic_endpoint.cc
index 64005ec..8438432 100644
--- a/quiche/quic/test_tools/simulator/quic_endpoint.cc
+++ b/quiche/quic/test_tools/simulator/quic_endpoint.cc
@@ -34,7 +34,8 @@
   connection_ = std::make_unique<QuicConnection>(
       connection_id, GetAddressFromName(name), GetAddressFromName(peer_name),
       simulator, simulator->GetAlarmFactory(), &writer_, false, perspective,
-      ParsedVersionOfIndex(CurrentSupportedVersions(), 0));
+      ParsedVersionOfIndex(CurrentSupportedVersions(), 0),
+      connection_id_generator_);
   connection_->set_visitor(this);
   connection_->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
                             std::make_unique<NullEncrypter>(perspective));
diff --git a/quiche/quic/test_tools/simulator/quic_endpoint_base.h b/quiche/quic/test_tools/simulator/quic_endpoint_base.h
index 8eece0b..540b285 100644
--- a/quiche/quic/test_tools/simulator/quic_endpoint_base.h
+++ b/quiche/quic/test_tools/simulator/quic_endpoint_base.h
@@ -15,6 +15,7 @@
 #include "quiche/quic/core/quic_packets.h"
 #include "quiche/quic/core/quic_stream_frame_data_producer.h"
 #include "quiche/quic/core/quic_trace_visitor.h"
+#include "quiche/quic/test_tools/mock_connection_id_generator.h"
 #include "quiche/quic/test_tools/simple_session_notifier.h"
 #include "quiche/quic/test_tools/simulator/link.h"
 #include "quiche/quic/test_tools/simulator/queue.h"
@@ -127,6 +128,8 @@
   bool drop_next_packet_;
 
   std::unique_ptr<QuicTraceVisitor> trace_visitor_;
+
+  test::MockConnectionIdGenerator connection_id_generator_;
 };
 
 // Multiplexes multiple connections at the same host on the network.
diff --git a/quiche/quic/test_tools/simulator/test_harness.cc b/quiche/quic/test_tools/simulator/test_harness.cc
index e3af48e..1dfc8a2 100644
--- a/quiche/quic/test_tools/simulator/test_harness.cc
+++ b/quiche/quic/test_tools/simulator/test_harness.cc
@@ -18,8 +18,8 @@
   connection_ = std::make_unique<QuicConnection>(
       quic::test::TestConnectionId(0x10), GetAddressFromName(name),
       GetAddressFromName(peer_name), simulator, simulator->GetAlarmFactory(),
-      &writer_,
-      /*owns_writer=*/false, perspective, supported_versions);
+      &writer_, /*owns_writer=*/false, perspective, supported_versions,
+      connection_id_generator_);
   connection_->SetSelfAddress(GetAddressFromName(name));
 }
 
diff --git a/quiche/quic/tools/quic_client_base.cc b/quiche/quic/tools/quic_client_base.cc
index 6cbfc13..766aa57 100644
--- a/quiche/quic/tools/quic_client_base.cc
+++ b/quiche/quic/tools/quic_client_base.cc
@@ -165,7 +165,7 @@
       new QuicConnection(GetNextConnectionId(), QuicSocketAddress(),
                          server_address(), helper(), alarm_factory(), writer,
                          /* owns_writer= */ false, Perspective::IS_CLIENT,
-                         client_supported_versions));
+                         client_supported_versions, connection_id_generator_));
   if (can_reconnect_with_different_version) {
     session()->set_client_original_supported_versions(supported_versions());
   }
diff --git a/quiche/quic/tools/quic_client_base.h b/quiche/quic/tools/quic_client_base.h
index e9700a8..d36eba6 100644
--- a/quiche/quic/tools/quic_client_base.h
+++ b/quiche/quic/tools/quic_client_base.h
@@ -14,6 +14,7 @@
 #include "absl/base/attributes.h"
 #include "absl/strings/string_view.h"
 #include "quiche/quic/core/crypto/crypto_handshake.h"
+#include "quiche/quic/core/deterministic_connection_id_generator.h"
 #include "quiche/quic/core/http/quic_client_push_promise_index.h"
 #include "quiche/quic/core/http/quic_spdy_client_session.h"
 #include "quiche/quic/core/http/quic_spdy_client_stream.h"
@@ -348,6 +349,9 @@
   // Returns true if the corresponding of this client has active requests.
   virtual bool HasActiveRequests() = 0;
 
+  // Allows derived classes to access this when creating connections.
+  ConnectionIdGeneratorInterface& connection_id_generator();
+
  private:
   // Returns true and set |version| if client can reconnect with a different
   // version.
@@ -434,6 +438,9 @@
   // Stores the interface name to bind. If empty, will not attempt to bind the
   // socket to that interface. Defaults to empty string.
   std::string interface_name_;
+
+  DeterministicConnectionIdGenerator connection_id_generator_{
+      kQuicDefaultConnectionIdLength};
 };
 
 }  // namespace quic
diff --git a/quiche/quic/tools/quic_simple_dispatcher.cc b/quiche/quic/tools/quic_simple_dispatcher.cc
index 5fb270c..50f0636 100644
--- a/quiche/quic/tools/quic_simple_dispatcher.cc
+++ b/quiche/quic/tools/quic_simple_dispatcher.cc
@@ -50,11 +50,11 @@
     const ParsedQuicVersion& version,
     const ParsedClientHello& /*parsed_chlo*/) {
   // The QuicServerSessionBase takes ownership of |connection| below.
-  QuicConnection* connection =
-      new QuicConnection(connection_id, self_address, peer_address, helper(),
-                         alarm_factory(), writer(),
-                         /* owns_writer= */ false, Perspective::IS_SERVER,
-                         ParsedQuicVersionVector{version});
+  QuicConnection* connection = new QuicConnection(
+      connection_id, self_address, peer_address, helper(), alarm_factory(),
+      writer(),
+      /* owns_writer= */ false, Perspective::IS_SERVER,
+      ParsedQuicVersionVector{version}, connection_id_generator());
 
   auto session = std::make_unique<QuicSimpleServerSession>(
       config(), GetSupportedVersions(), connection, this, session_helper(),