Use new connection ID in connection migration on the server side.

Code is protected by connection_migration_use_new_cid_, which will be enabled by reloadable flag in follow up CL once the feature is complete.

PiperOrigin-RevId: 371119297
Change-Id: I664a8cfcc348d4528b7a5a1ad0ed1b0bc9ca1a02
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 39150b8..38117a4 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -1064,6 +1064,13 @@
     return true;
   }
 
+  if (connection_migration_use_new_cid_ &&
+      perspective_ == Perspective::IS_SERVER &&
+      self_issued_cid_manager_ != nullptr &&
+      self_issued_cid_manager_->IsConnectionIdInUse(server_connection_id)) {
+    return true;
+  }
+
   return false;
 }
 
@@ -1089,10 +1096,10 @@
     framer_.set_drop_incoming_retry_packets(true);
   }
 
-  QuicConnectionId server_connection_id =
-      GetServerConnectionIdAsRecipient(header, perspective_);
   if (!ValidateServerConnectionId(header)) {
     ++stats_.packets_dropped;
+    QuicConnectionId server_connection_id =
+        GetServerConnectionIdAsRecipient(header, perspective_);
     QUIC_DLOG(INFO) << ENDPOINT
                     << "Ignoring packet from unexpected server connection ID "
                     << server_connection_id << " instead of "
@@ -1131,6 +1138,13 @@
     return true;
   }
 
+  if (connection_migration_use_new_cid_ &&
+      perspective_ == Perspective::IS_CLIENT &&
+      self_issued_cid_manager_ != nullptr &&
+      self_issued_cid_manager_->IsConnectionIdInUse(client_connection_id)) {
+    return true;
+  }
+
   ++stats_.packets_dropped;
   QUIC_DLOG(INFO) << ENDPOINT
                   << "Ignoring packet from unexpected client connection ID "
@@ -1297,6 +1311,35 @@
             default_path_.peer_address,
             GetEffectivePeerAddressFromCurrentPacket());
 
+    if (connection_migration_use_new_cid_) {
+      auto effective_peer_address = GetEffectivePeerAddressFromCurrentPacket();
+      // Since server does not send new connection ID to client before handshake
+      // completion and source connection ID is omitted in short header packet,
+      // the server_connection_id on PathState on the server side does not
+      // affect the packets server writes after handshake completion. On the
+      // other hand, it is still desirable to have the "correct" server
+      // connection ID set on path.
+      // 1) If client uses 1 unique server connection ID per path and the packet
+      // is received from an existing path, then
+      // last_packet_destination_connection_id_ will always be the same as the
+      // server connection ID on path. Server side will maintain the 1-to-1
+      // mapping from server connection ID to path.
+      // 2) If client uses multiple server connection IDs on the same path,
+      // compared to the server_connection_id on path,
+      // last_packet_destination_connection_id_ has the advantage that it is
+      // still present in the session map since the packet can be routed here
+      // regardless of packet reordering.
+      if (IsDefaultPath(last_packet_destination_address_,
+                        effective_peer_address)) {
+        default_path_.server_connection_id =
+            last_packet_destination_connection_id_;
+      } else if (IsAlternativePath(last_packet_destination_address_,
+                                   effective_peer_address)) {
+        alternative_path_.server_connection_id =
+            last_packet_destination_connection_id_;
+      }
+    }
+
     QUIC_DLOG_IF(INFO, current_effective_peer_migration_type_ != NO_CHANGE)
         << ENDPOINT << "Effective peer's ip:port changed from "
         << default_path_.peer_address.ToString() << " to "
@@ -1742,16 +1785,20 @@
   }
 
   std::unique_ptr<QuicPacketCreator::ScopedPeerAddressContext> context;
+  const QuicSocketAddress current_effective_peer_address =
+      GetEffectivePeerAddressFromCurrentPacket();
   if (group_path_response_and_challenge_sending_closer_) {
+    QuicConnectionId client_cid, server_cid;
+    FindOnPathConnectionIds(last_packet_destination_address_,
+                            current_effective_peer_address, &client_cid,
+                            &server_cid);
     context = std::make_unique<QuicPacketCreator::ScopedPeerAddressContext>(
-        &packet_creator_, last_packet_source_address_,
-        /*update_connection_id=*/false);
+        &packet_creator_, last_packet_source_address_, client_cid, server_cid,
+        connection_migration_use_new_cid_);
   }
   if (should_proactively_validate_peer_address_on_path_challenge_) {
     QUIC_RELOADABLE_FLAG_COUNT(
         quic_group_path_response_and_challenge_sending_closer);
-    QuicSocketAddress current_effective_peer_address =
-        GetEffectivePeerAddressFromCurrentPacket();
     // Conditions to proactively validate peer address:
     // The perspective is server
     // The PATH_CHALLENGE is received on an unvalidated alternative path.
@@ -1780,7 +1827,8 @@
   // the current incoming packet, even if it's not the default path or the
   // alternative path.
   const bool success =
-      SendPathResponse(frame.data_buffer, last_packet_source_address_);
+      SendPathResponse(frame.data_buffer, last_packet_source_address_,
+                       current_effective_peer_address);
   if (GetQuicReloadableFlag(quic_drop_unsent_path_response)) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_drop_unsent_path_response);
   }
@@ -2904,8 +2952,12 @@
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response2, 4, 5);
     const PendingPathChallenge& pending_path_challenge =
         pending_path_challenge_payloads_.front();
+    // Note connection_migration_use_cid_ will depends on
+    // quic_drop_unsent_path_response flag eventually, and hence the empty
+    // effective_peer_address here will not be used.
     if (!SendPathResponse(pending_path_challenge.received_path_challenge,
-                          pending_path_challenge.peer_address)) {
+                          pending_path_challenge.peer_address,
+                          /*effective_peer_address=*/QuicSocketAddress())) {
       break;
     }
     pending_path_challenge_payloads_.pop_front();
@@ -2979,13 +3031,13 @@
   packet_creator_.SetServerConnectionId(ServerConnectionId());
 }
 
-void QuicConnection::FindMatchingClientConnectionIdOrToken(
+void QuicConnection::FindMatchingOrNewClientConnectionIdOrToken(
     const PathState& default_path,
     const PathState& alternative_path,
     const QuicConnectionId& server_connection_id,
     QuicConnectionId* client_connection_id,
     bool* stateless_reset_token_received,
-    StatelessResetToken* stateless_reset_token) const {
+    StatelessResetToken* stateless_reset_token) {
   if (!use_connection_id_on_default_path_) {
     return;
   }
@@ -3005,7 +3057,44 @@
     *stateless_reset_token = alternative_path.stateless_reset_token;
     return;
   }
-  QUIC_BUG(quic_bug_46004) << "Cannot find matching connection ID.";
+  if (!connection_migration_use_new_cid_) {
+    QUIC_BUG(quic_bug_46004) << "Cannot find matching connection ID.";
+    return;
+  }
+  auto* connection_id_data =
+      peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
+  if (connection_id_data == nullptr) {
+    return;
+  }
+  *client_connection_id = connection_id_data->connection_id;
+  *stateless_reset_token = connection_id_data->stateless_reset_token;
+  *stateless_reset_token_received = true;
+}
+
+bool QuicConnection::FindOnPathConnectionIds(
+    const QuicSocketAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    QuicConnectionId* client_connection_id,
+    QuicConnectionId* server_connection_id) const {
+  if (IsDefaultPath(self_address, peer_address)) {
+    *client_connection_id = default_path_.client_connection_id,
+    *server_connection_id = default_path_.server_connection_id;
+    return true;
+  }
+  if (IsAlternativePath(self_address, peer_address)) {
+    *client_connection_id = alternative_path_.client_connection_id,
+    *server_connection_id = alternative_path_.server_connection_id;
+    return true;
+  }
+  return false;
+}
+
+void QuicConnection::SetDefaultPathState(PathState new_path_state) {
+  default_path_ = std::move(new_path_state);
+  if (connection_migration_use_new_cid_) {
+    packet_creator_.SetClientConnectionId(default_path_.client_connection_id);
+    packet_creator_.SetServerConnectionId(default_path_.server_connection_id);
+  }
 }
 
 bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
@@ -4476,7 +4565,8 @@
     const std::string& details) {
   // Always use the current path to send CONNECTION_CLOSE.
   QuicPacketCreator::ScopedPeerAddressContext context(
-      &packet_creator_, peer_address(), /*update_connection_id=*/false);
+      &packet_creator_, peer_address(), default_path_.client_connection_id,
+      default_path_.server_connection_id, connection_migration_use_new_cid_);
   if (!SupportsMultiplePacketNumberSpaces()) {
     QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet.";
     if (!use_encryption_level_context_) {
@@ -5249,19 +5339,19 @@
   // Update the default path.
   if (IsAlternativePath(last_packet_destination_address_,
                         current_effective_peer_address)) {
-    default_path_ = std::move(alternative_path_);
+    SetDefaultPathState(std::move(alternative_path_));
   } else {
     QuicConnectionId client_connection_id;
     bool stateless_reset_token_received = false;
     StatelessResetToken stateless_reset_token;
-    FindMatchingClientConnectionIdOrToken(
+    FindMatchingOrNewClientConnectionIdOrToken(
         previous_default_path, alternative_path_,
         last_packet_destination_connection_id_, &client_connection_id,
         &stateless_reset_token_received, &stateless_reset_token);
-    default_path_ = PathState(
+    SetDefaultPathState(PathState(
         last_packet_destination_address_, current_effective_peer_address,
         client_connection_id, last_packet_destination_connection_id_,
-        stateless_reset_token_received, stateless_reset_token);
+        stateless_reset_token_received, stateless_reset_token));
     // The path is considered validated if its peer IP address matches any
     // validated path's peer IP address.
     default_path_.validated =
@@ -5468,16 +5558,16 @@
           << current_effective_peer_address << ",  self address "
           << last_packet_destination_address_;
       if (!validate_client_addresses_) {
-        QuicConnectionId client_connection_id;
+        QuicConnectionId client_cid;
         bool stateless_reset_token_received = false;
         StatelessResetToken stateless_reset_token;
-        FindMatchingClientConnectionIdOrToken(
+        FindMatchingOrNewClientConnectionIdOrToken(
             default_path_, alternative_path_,
-            last_packet_destination_connection_id_, &client_connection_id,
+            last_packet_destination_connection_id_, &client_cid,
             &stateless_reset_token_received, &stateless_reset_token);
         alternative_path_ = PathState(
             last_packet_destination_address_, current_effective_peer_address,
-            client_connection_id, last_packet_destination_connection_id_,
+            client_cid, last_packet_destination_connection_id_,
             stateless_reset_token_received, stateless_reset_token);
       } else if (!default_path_.validated) {
         QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 4, 6);
@@ -5498,7 +5588,7 @@
         QuicConnectionId client_connection_id;
         bool stateless_reset_token_received;
         StatelessResetToken stateless_reset_token;
-        FindMatchingClientConnectionIdOrToken(
+        FindMatchingOrNewClientConnectionIdOrToken(
             default_path_, alternative_path_,
             last_packet_destination_connection_id_, &client_connection_id,
             &stateless_reset_token_received, &stateless_reset_token);
@@ -5521,7 +5611,7 @@
                         << current_effective_peer_address;
           ValidatePath(
               std::make_unique<ReversePathValidationContext>(
-                  default_path_.self_address, current_effective_peer_address,
+                  default_path_.self_address, last_packet_source_address_,
                   current_effective_peer_address, this),
               std::make_unique<ReversePathValidationResultDelegate>(
                   this, peer_address()));
@@ -6438,8 +6528,34 @@
     const QuicPathFrameBuffer& data_buffer,
     const QuicSocketAddress& self_address,
     const QuicSocketAddress& peer_address,
-    const QuicSocketAddress& /*effective_peer_address*/,
+    const QuicSocketAddress& effective_peer_address,
     QuicPacketWriter* writer) {
+  if (connection_migration_use_new_cid_) {
+    {
+      QuicConnectionId client_cid, server_cid;
+      FindOnPathConnectionIds(self_address, effective_peer_address, &client_cid,
+                              &server_cid);
+      QuicPacketCreator::ScopedPeerAddressContext context(
+          &packet_creator_, peer_address, client_cid, server_cid,
+          connection_migration_use_new_cid_);
+      if (writer == writer_) {
+        ScopedPacketFlusher flusher(this);
+        // It's on current path, add the PATH_CHALLENGE the same way as other
+        // frames. This may cause connection to be closed.
+        packet_creator_.AddPathChallengeFrame(data_buffer);
+      } else {
+        std::unique_ptr<SerializedPacket> probing_packet =
+            packet_creator_.SerializePathChallengeConnectivityProbingPacket(
+                data_buffer);
+        QUICHE_DCHECK_EQ(IsRetransmittable(*probing_packet),
+                         NO_RETRANSMITTABLE_DATA);
+        QUICHE_DCHECK_EQ(self_address, alternative_path_.self_address);
+        WritePacketUsingWriter(std::move(probing_packet), writer, self_address,
+                               peer_address, /*measure_rtt=*/false);
+      }
+    }
+    return connected_;
+  }
   if (writer == writer_) {
     ScopedPacketFlusher flusher(this);
     {
@@ -6531,13 +6647,21 @@
                                       std::move(result_delegate));
 }
 
-bool QuicConnection::SendPathResponse(const QuicPathFrameBuffer& data_buffer,
-                                      QuicSocketAddress peer_address_to_send) {
+bool QuicConnection::SendPathResponse(
+    const QuicPathFrameBuffer& data_buffer,
+    const QuicSocketAddress& peer_address_to_send,
+    const QuicSocketAddress& effective_peer_address) {
+  QuicConnectionId client_cid, server_cid;
+  if (connection_migration_use_new_cid_) {
+    FindOnPathConnectionIds(last_packet_destination_address_,
+                            effective_peer_address, &client_cid, &server_cid);
+  }
   // Send PATH_RESPONSE using the provided peer address. If the creator has been
   // using a different peer address, it will flush before and after serializing
   // the current PATH_RESPONSE.
   QuicPacketCreator::ScopedPeerAddressContext context(
-      &packet_creator_, peer_address_to_send, /*update_connection_id=*/false);
+      &packet_creator_, peer_address_to_send, client_cid, server_cid,
+      connection_migration_use_new_cid_);
   QUIC_DVLOG(1) << ENDPOINT << "Send PATH_RESPONSE to " << peer_address_to_send;
   if (default_path_.self_address == last_packet_destination_address_) {
     // The PATH_CHALLENGE is received on the default socket. Respond on the same
@@ -6656,8 +6780,11 @@
     peer_issued_cid_manager_->MaybeRetireUnusedConnectionIds(
         {default_path_.server_connection_id,
          alternative_path_.server_connection_id});
+  } else {
+    peer_issued_cid_manager_->MaybeRetireUnusedConnectionIds(
+        {default_path_.client_connection_id,
+         alternative_path_.client_connection_id});
   }
-  // TODO(haoyuewang) Do the same on the server side.
 }
 
 bool QuicConnection::MigratePath(const QuicSocketAddress& self_address,
@@ -6941,7 +7068,7 @@
   }
 
   UpdatePeerAddress(original_direct_peer_address);
-  default_path_ = std::move(alternative_path_);
+  SetDefaultPathState(std::move(alternative_path_));
 
   active_effective_peer_migration_type_ = NO_CHANGE;
   ++stats_.num_invalid_peer_migration;
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 588504b..f752a55 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -1506,14 +1506,27 @@
       const QuicConnectionId& new_server_connection_id);
 
   // Given the server_connection_id find if there is already a corresponding
-  // client connection ID used on default/alternative path.
-  void FindMatchingClientConnectionIdOrToken(
+  // client connection ID used on default/alternative path. If not, find if
+  // there is an unused connection ID.
+  void FindMatchingOrNewClientConnectionIdOrToken(
       const PathState& default_path,
       const PathState& alternative_path,
       const QuicConnectionId& server_connection_id,
       QuicConnectionId* client_connection_id,
       bool* stateless_reset_token_received,
-      StatelessResetToken* stateless_reset_token) const;
+      StatelessResetToken* stateless_reset_token);
+
+  // Returns true and sets connection IDs if (self_address, peer_address)
+  // corresponds to either the default path or alternative path. Returns false
+  // otherwise.
+  bool FindOnPathConnectionIds(const QuicSocketAddress& self_address,
+                               const QuicSocketAddress& peer_address,
+                               QuicConnectionId* client_connection_id,
+                               QuicConnectionId* server_connection_id) const;
+
+  // Set default_path_ to the new_path_state and update the connection IDs in
+  // packet creator accordingly.
+  void SetDefaultPathState(PathState new_path_state);
 
   // Returns true if header contains valid server connection ID.
   bool ValidateServerConnectionId(const QuicPacketHeader& header) const;
@@ -1761,7 +1774,8 @@
 
   // Send PATH_RESPONSE to the given peer address.
   bool SendPathResponse(const QuicPathFrameBuffer& data_buffer,
-                        QuicSocketAddress peer_address_to_send);
+                        const QuicSocketAddress& peer_address_to_send,
+                        const QuicSocketAddress& effective_peer_address);
 
   // Update both connection's and packet creator's peer address.
   void UpdatePeerAddress(QuicSocketAddress peer_address);
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 741f2da..d806835 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -1875,6 +1875,87 @@
   EXPECT_EQ(1u, connection_.GetStats().num_validated_peer_migration);
 }
 
+TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServerWithMissingConnectionId) {
+  set_perspective(Perspective::IS_SERVER);
+  if (!connection_.validate_client_address() ||
+      !connection_.use_connection_id_on_default_path() ||
+      !connection_.support_multiple_connection_ids()) {
+    return;
+  }
+  QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+  EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+  QuicConnectionPeer::EnableConnectionMigrationUseNewCID(&connection_);
+
+  QuicConnectionId client_cid0 = TestConnectionId(1);
+  QuicConnectionId client_cid1 = TestConnectionId(3);
+  QuicConnectionId server_cid1;
+  SetClientConnectionId(client_cid0);
+  connection_.CreateConnectionIdManager();
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  // Prevent packets from being coalesced.
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+  QuicConnectionPeer::SetAddressValidated(&connection_);
+  connection_.OnHandshakeComplete();
+
+  // Sends new server CID to client.
+  EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+      .WillOnce(
+          Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+  EXPECT_CALL(visitor_, SendNewConnectionId(_));
+  connection_.MaybeSendConnectionIdToClient();
+
+  // Clear direct_peer_address.
+  QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
+  // Clear effective_peer_address, it is the same as direct_peer_address for
+  // this test.
+  QuicConnectionPeer::SetEffectivePeerAddress(&connection_,
+                                              QuicSocketAddress());
+  EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
+
+  const QuicSocketAddress kNewPeerAddress =
+      QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456);
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2);
+  QuicFrames frames;
+  frames.push_back(QuicFrame(frame1_));
+  ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress,
+                                   ENCRYPTION_FORWARD_SECURE);
+  EXPECT_EQ(kPeerAddress, connection_.peer_address());
+  EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+  // Send some data to make connection has packets in flight.
+  connection_.SendStreamData3();
+  EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+  // Process another packet with a different peer address on server side will
+  // start connection migration.
+  peer_creator_.SetServerConnectionId(server_cid1);
+  EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1);
+  // Do not propagate OnCanWrite() to session notifier.
+  EXPECT_CALL(visitor_, OnCanWrite()).Times(AtLeast(1u));
+
+  QuicFrames frames2;
+  frames2.push_back(QuicFrame(frame2_));
+  ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress,
+                                   ENCRYPTION_FORWARD_SECURE);
+  EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
+  EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
+
+  // Writing path response & reverse path challenge is blocked due to missing
+  // client connection ID, i.e., packets_write_attempts is unchanged.
+  EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+  // Receives new client CID from client would unblock write.
+  QuicNewConnectionIdFrame new_cid_frame;
+  new_cid_frame.connection_id = client_cid1;
+  new_cid_frame.sequence_number = 1u;
+  new_cid_frame.retire_prior_to = 0u;
+  connection_.OnNewConnectionIdFrame(new_cid_frame);
+  connection_.SendStreamData3();
+
+  EXPECT_EQ(2u, writer_->packets_write_attempts());
+}
+
 TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
   set_perspective(Perspective::IS_SERVER);
   QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
@@ -1992,11 +2073,16 @@
 
 TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
   set_perspective(Perspective::IS_SERVER);
-  if (!connection_.validate_client_address()) {
+  if (!connection_.validate_client_address() ||
+      !connection_.use_connection_id_on_default_path() ||
+      !connection_.support_multiple_connection_ids()) {
     return;
   }
   QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
   EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+  QuicConnectionPeer::EnableConnectionMigrationUseNewCID(&connection_);
+  SetClientConnectionId(TestConnectionId(1));
+  connection_.CreateConnectionIdManager();
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
   // Prevent packets from being coalesced.
   EXPECT_CALL(visitor_, GetHandshakeState())
@@ -2004,6 +2090,26 @@
   QuicConnectionPeer::SetAddressValidated(&connection_);
   connection_.OnHandshakeComplete();
 
+  QuicConnectionId client_cid0 = connection_.client_connection_id();
+  QuicConnectionId client_cid1 = TestConnectionId(2);
+  QuicConnectionId server_cid0 = connection_.connection_id();
+  QuicConnectionId server_cid1;
+  // Sends new server CID to client.
+  EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+      .WillOnce(
+          Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+  EXPECT_CALL(visitor_, SendNewConnectionId(_));
+  connection_.MaybeSendConnectionIdToClient();
+  // Receives new client CID from client.
+  QuicNewConnectionIdFrame new_cid_frame;
+  new_cid_frame.connection_id = client_cid1;
+  new_cid_frame.sequence_number = 1u;
+  new_cid_frame.retire_prior_to = 0u;
+  connection_.OnNewConnectionIdFrame(new_cid_frame);
+  auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+  ASSERT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+  ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
+
   // Clear direct_peer_address.
   QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
   // Clear effective_peer_address, it is the same as direct_peer_address for
@@ -2042,6 +2148,7 @@
   frames2.push_back(QuicFrame(frame2_));
   QuicPaddingFrame padding;
   frames2.push_back(QuicFrame(padding));
+  peer_creator_.SetServerConnectionId(server_cid1);
   ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress,
                                    ENCRYPTION_FORWARD_SECURE);
   EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
@@ -2055,6 +2162,15 @@
   EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
   EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
   EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
+  const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+  const auto* alternative_path =
+      QuicConnectionPeer::GetAlternativePath(&connection_);
+  EXPECT_EQ(default_path->client_connection_id, client_cid1);
+  EXPECT_EQ(default_path->server_connection_id, server_cid1);
+  EXPECT_EQ(alternative_path->client_connection_id, client_cid0);
+  EXPECT_EQ(alternative_path->server_connection_id, server_cid0);
+  EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid1);
+  EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1);
 
   for (size_t i = 0; i < QuicPathValidator::kMaxRetryTimes; ++i) {
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs));
@@ -2081,6 +2197,19 @@
   EXPECT_EQ(connection_.sent_packet_manager().GetSendAlgorithm(),
             send_algorithm_);
   EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+  // Verify that default_path_ is reverted and alternative_path_ is cleared.
+  EXPECT_EQ(default_path->client_connection_id, client_cid0);
+  EXPECT_EQ(default_path->server_connection_id, server_cid0);
+  EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+  EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+  auto* retire_peer_issued_cid_alarm =
+      connection_.GetRetirePeerIssuedConnectionIdAlarm();
+  ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+  EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/1u));
+  retire_peer_issued_cid_alarm->Fire();
+  EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+  EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
 }
 
 TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
@@ -13760,11 +13889,37 @@
 
 TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) {
   set_perspective(Perspective::IS_SERVER);
-  if (!connection_.validate_client_address()) {
+  if (!connection_.validate_client_address() ||
+      !connection_.use_connection_id_on_default_path() ||
+      !connection_.support_multiple_connection_ids()) {
     return;
   }
   PathProbeTestInit(Perspective::IS_SERVER);
+  QuicConnectionPeer::EnableConnectionMigrationUseNewCID(&connection_);
+  SetClientConnectionId(TestConnectionId(1));
+  connection_.CreateConnectionIdManager();
 
+  QuicConnectionId server_cid0 = connection_.connection_id();
+  QuicConnectionId client_cid0 = connection_.client_connection_id();
+  QuicConnectionId client_cid1 = TestConnectionId(2);
+  QuicConnectionId server_cid1;
+  // Sends new server CID to client.
+  EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+      .WillOnce(
+          Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+  EXPECT_CALL(visitor_, SendNewConnectionId(_));
+  connection_.MaybeSendConnectionIdToClient();
+  // Receives new client CID from client.
+  QuicNewConnectionIdFrame new_cid_frame;
+  new_cid_frame.connection_id = client_cid1;
+  new_cid_frame.sequence_number = 1u;
+  new_cid_frame.retire_prior_to = 0u;
+  connection_.OnNewConnectionIdFrame(new_cid_frame);
+  auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+  ASSERT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+  ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
+
+  peer_creator_.SetServerConnectionId(server_cid1);
   const QuicSocketAddress kNewPeerAddress =
       QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456);
   QuicPathFrameBuffer path_challenge_payload{0, 1, 2, 3, 4, 5, 6, 7};
@@ -13788,6 +13943,15 @@
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
   EXPECT_TRUE(connection_.HasPendingPathValidation());
+  const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+  const auto* alternative_path =
+      QuicConnectionPeer::GetAlternativePath(&connection_);
+  EXPECT_EQ(default_path->client_connection_id, client_cid0);
+  EXPECT_EQ(default_path->server_connection_id, server_cid0);
+  EXPECT_EQ(alternative_path->client_connection_id, client_cid1);
+  EXPECT_EQ(alternative_path->server_connection_id, server_cid1);
+  EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+  EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
 
   // Process another packet with a different peer address on server side will
   // start connection migration.
@@ -13824,6 +13988,14 @@
   EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
   EXPECT_CALL(*send_algorithm_, PopulateConnectionStats(_)).Times(AnyNumber());
   connection_.SetSendAlgorithm(send_algorithm_);
+  EXPECT_EQ(default_path->client_connection_id, client_cid1);
+  EXPECT_EQ(default_path->server_connection_id, server_cid1);
+  // The previous default path is kept as alternative path before reverse path
+  // validation finishes.
+  EXPECT_EQ(alternative_path->client_connection_id, client_cid0);
+  EXPECT_EQ(alternative_path->server_connection_id, server_cid0);
+  EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid1);
+  EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1);
 
   EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
   EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
@@ -13847,6 +14019,15 @@
   ProcessFramesPacketWithAddresses(frames3, kSelfAddress, kNewPeerAddress,
                                    ENCRYPTION_FORWARD_SECURE);
   EXPECT_EQ(NO_CHANGE, connection_.active_effective_peer_migration_type());
+  // Verify that alternative_path_ is cleared and the peer CID is retired.
+  EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty());
+  EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+  EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+  auto* retire_peer_issued_cid_alarm =
+      connection_.GetRetirePeerIssuedConnectionIdAlarm();
+  ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+  EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u));
+  retire_peer_issued_cid_alarm->Fire();
 
   // Verify the anti-amplification limit is lifted by sending a packet larger
   // than the anti-amplification limit.
@@ -13858,12 +14039,28 @@
 TEST_P(QuicConnectionTest,
        PathValidationSucceedsBeforePeerIpAddressChangeAtServer) {
   set_perspective(Perspective::IS_SERVER);
-  if (!connection_.validate_client_address()) {
+  if (!connection_.validate_client_address() ||
+      !connection_.use_connection_id_on_default_path() ||
+      !connection_.support_multiple_connection_ids()) {
     return;
   }
   PathProbeTestInit(Perspective::IS_SERVER);
+  QuicConnectionPeer::EnableConnectionMigrationUseNewCID(&connection_);
+  connection_.CreateConnectionIdManager();
+
+  QuicConnectionId server_cid0 = connection_.connection_id();
+  QuicConnectionId server_cid1;
+  // Sends new server CID to client.
+  EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+      .WillOnce(
+          Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+  EXPECT_CALL(visitor_, SendNewConnectionId(_));
+  connection_.MaybeSendConnectionIdToClient();
+  auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+  ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
 
   // Receive probing packet with new peer address.
+  peer_creator_.SetServerConnectionId(server_cid1);
   const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback4(),
                                           /*port=*/23456);
   QuicPathFrameBuffer payload;
@@ -13888,6 +14085,12 @@
   ProcessFramesPacketWithAddresses(frames1, kSelfAddress, kNewPeerAddress,
                                    ENCRYPTION_FORWARD_SECURE);
   EXPECT_TRUE(connection_.HasPendingPathValidation());
+  const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+  const auto* alternative_path =
+      QuicConnectionPeer::GetAlternativePath(&connection_);
+  EXPECT_EQ(default_path->server_connection_id, server_cid0);
+  EXPECT_EQ(alternative_path->server_connection_id, server_cid1);
+  EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
 
   // Receive PATH_RESPONSE should mark the new peer address validated.
   QuicFrames frames3;
@@ -13925,6 +14128,12 @@
   EXPECT_NE(connection_.sent_packet_manager().GetSendAlgorithm(),
             send_algorithm_);
 
+  EXPECT_EQ(default_path->server_connection_id, server_cid1);
+  EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1);
+  // Verify that alternative_path_ is cleared.
+  EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+  EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+
   // Switch to use the mock send algorithm.
   send_algorithm_ = new StrictMock<MockSendAlgorithm>();
   EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true));
@@ -14045,19 +14254,25 @@
   SetClientConnectionId(TestConnectionId(1));
 
   // Make sure server connection ID is available for the 1st validation.
+  QuicConnectionId server_cid0 = connection_.connection_id();
+  QuicConnectionId server_cid1 = TestConnectionId(2);
+  QuicConnectionId server_cid2 = TestConnectionId(4);
+  QuicConnectionId client_cid1;
   QuicNewConnectionIdFrame frame1;
-  frame1.connection_id = TestConnectionId(2);
+  frame1.connection_id = server_cid1;
   frame1.sequence_number = 1u;
   frame1.retire_prior_to = 0u;
   frame1.stateless_reset_token =
       QuicUtils::GenerateStatelessResetToken(frame1.connection_id);
   connection_.OnNewConnectionIdFrame(frame1);
+  const auto* packet_creator =
+      QuicConnectionPeer::GetPacketCreator(&connection_);
+  ASSERT_EQ(packet_creator->GetDestinationConnectionId(), server_cid0);
 
   // Client will issue a new client connection ID to server.
-  QuicConnectionId new_client_connection_id;
   EXPECT_CALL(visitor_, SendNewConnectionId(_))
       .WillOnce(Invoke([&](const QuicNewConnectionIdFrame& frame) {
-        new_client_connection_id = frame.connection_id;
+        client_cid1 = frame.connection_id;
       }));
 
   const QuicSocketAddress kSelfAddress1(QuicIpAddress::Any4(), 12345);
@@ -14075,8 +14290,8 @@
                                       &new_writer, /*owns_writer=*/false));
   QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath(&connection_);
   const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
-  EXPECT_EQ(default_path->client_connection_id, new_client_connection_id);
-  EXPECT_EQ(default_path->server_connection_id, frame1.connection_id);
+  EXPECT_EQ(default_path->client_connection_id, client_cid1);
+  EXPECT_EQ(default_path->server_connection_id, server_cid1);
   EXPECT_EQ(default_path->stateless_reset_token, frame1.stateless_reset_token);
   EXPECT_TRUE(default_path->stateless_reset_token_received);
   const auto* alternative_path =
@@ -14084,6 +14299,7 @@
   EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty());
   EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
   EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+  ASSERT_EQ(packet_creator->GetDestinationConnectionId(), server_cid1);
 
   // Client will retire server connection ID on old default_path.
   auto* retire_peer_issued_cid_alarm =
@@ -14094,7 +14310,7 @@
 
   // Another server connection ID is available to client.
   QuicNewConnectionIdFrame frame2;
-  frame2.connection_id = TestConnectionId(4);
+  frame2.connection_id = server_cid2;
   frame2.sequence_number = 2u;
   frame2.retire_prior_to = 1u;
   frame2.stateless_reset_token =
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 3d3eb67..6674ef4 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -2124,10 +2124,12 @@
          "initialized.";
   creator_->SetDefaultPeerAddress(address);
   if (update_connection_id_) {
-    QUICHE_DCHECK(address != old_peer_address_ ||
-                  ((client_connection_id == old_client_connection_id_) &&
-                   (server_connection_id == old_server_connection_id_)))
-        << ENDPOINT2;
+    // Flush current packet if connection ID changes.
+    if (address == old_peer_address_ &&
+        ((client_connection_id != old_client_connection_id_) ||
+         (server_connection_id != old_server_connection_id_))) {
+      creator_->FlushCurrentPacket();
+    }
     creator_->SetClientConnectionId(client_connection_id);
     creator_->SetServerConnectionId(server_connection_id);
   }