Commit 5be4e96e authored by Renjie Tang's avatar Renjie Tang Committed by Chromium LUCI CQ

Use QUIC core path validator for IETF QUIC connection migration probing.

Change-Id: I5fbffa18e477d5e24fe3a772f1ed97f92d9b985e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2573678
Commit-Queue: Renjie Tang <renjietang@chromium.org>
Reviewed-by: default avatarDavid Schinazi <dschinazi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#844183}
parent 4445f174
...@@ -762,6 +762,120 @@ int QuicChromiumClientSession::StreamRequest::DoRequestStreamComplete(int rv) { ...@@ -762,6 +762,120 @@ int QuicChromiumClientSession::StreamRequest::DoRequestStreamComplete(int rv) {
return rv; return rv;
} }
QuicChromiumClientSession::QuicChromiumPathValidationContext::
QuicChromiumPathValidationContext(
const quic::QuicSocketAddress& self_address,
const quic::QuicSocketAddress& peer_address,
NetworkChangeNotifier::NetworkHandle network,
std::unique_ptr<DatagramClientSocket> socket,
std::unique_ptr<QuicChromiumPacketWriter> writer,
std::unique_ptr<QuicChromiumPacketReader> reader)
: QuicPathValidationContext(self_address, peer_address),
network_handle_(network),
socket_(std::move(socket)),
writer_(std::move(writer)),
reader_(std::move(reader)) {}
QuicChromiumClientSession::QuicChromiumPathValidationContext::
~QuicChromiumPathValidationContext() = default;
NetworkChangeNotifier::NetworkHandle
QuicChromiumClientSession::QuicChromiumPathValidationContext::network() {
return network_handle_;
}
quic::QuicPacketWriter*
QuicChromiumClientSession::QuicChromiumPathValidationContext::WriterToUse() {
return writer_.get();
}
std::unique_ptr<QuicChromiumPacketWriter>
QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseWriter() {
return std::move(writer_);
}
std::unique_ptr<DatagramClientSocket>
QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseSocket() {
return std::move(socket_);
}
std::unique_ptr<QuicChromiumPacketReader>
QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseReader() {
return std::move(reader_);
}
QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
ConnectionMigrationValidationResultDelegate(
QuicChromiumClientSession* session)
: session_(session) {}
void QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
OnPathValidationSuccess(
std::unique_ptr<quic::QuicPathValidationContext> context) {
auto* chrome_context =
static_cast<QuicChromiumPathValidationContext*>(context.get());
session_->OnConnectionMigrationProbeSucceeded(
chrome_context->network(), chrome_context->peer_address(),
chrome_context->self_address(), chrome_context->ReleaseSocket(),
chrome_context->ReleaseWriter(), chrome_context->ReleaseReader());
}
void QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
OnPathValidationFailure(
std::unique_ptr<quic::QuicPathValidationContext> context) {
// Note that socket, packet writer, and packet reader in |context| will be
// discarded.
auto* chrome_context =
static_cast<QuicChromiumPathValidationContext*>(context.get());
session_->OnProbeFailed(chrome_context->network(),
chrome_context->peer_address());
}
QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
QuicChromiumPathValidationWriterDelegate(
QuicChromiumClientSession* session,
base::SequencedTaskRunner* task_runner)
: session_(session),
task_runner_(task_runner),
network_(NetworkChangeNotifier::kInvalidNetworkHandle) {}
QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
~QuicChromiumPathValidationWriterDelegate() = default;
int QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
HandleWriteError(
int error_code,
scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> last_packet) {
// Write error on the probing network is not recoverable.
DVLOG(1) << "Probing packet encounters write error " << error_code;
// Post a task to notify |session_| that this probe failed and cancel
// undergoing probing, which will delete the packet writer.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&QuicChromiumPathValidationWriterDelegate::NotifySessionProbeFailed,
weak_factory_.GetWeakPtr(), network_));
return error_code;
}
void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
OnWriteError(int error_code) {
NotifySessionProbeFailed(network_);
}
void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
OnWriteUnblocked() {}
void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
NotifySessionProbeFailed(NetworkChangeNotifier::NetworkHandle network) {
session_->OnProbeFailed(network, peer_address_);
}
void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
set_peer_address(const quic::QuicSocketAddress& peer_address) {
peer_address_ = peer_address;
}
void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
set_network(NetworkChangeNotifier::NetworkHandle network) {
network_ = network;
}
QuicChromiumClientSession::QuicChromiumClientSession( QuicChromiumClientSession::QuicChromiumClientSession(
quic::QuicConnection* connection, quic::QuicConnection* connection,
std::unique_ptr<DatagramClientSocket> socket, std::unique_ptr<DatagramClientSocket> socket,
...@@ -865,7 +979,8 @@ QuicChromiumClientSession::QuicChromiumClientSession( ...@@ -865,7 +979,8 @@ QuicChromiumClientSession::QuicChromiumClientSession(
attempted_zero_rtt_(false), attempted_zero_rtt_(false),
num_migrations_(0), num_migrations_(0),
last_key_update_reason_(quic::KeyUpdateReason::kInvalid), last_key_update_reason_(quic::KeyUpdateReason::kInvalid),
push_promise_index_(std::move(push_promise_index)) { push_promise_index_(std::move(push_promise_index)),
path_validation_writer_delegate_(this, task_runner_) {
// Make sure connection migration and goaway on path degrading are not turned // Make sure connection migration and goaway on path degrading are not turned
// on at the same time. // on at the same time.
DCHECK(!(migrate_session_early_v2_ && go_away_on_path_degrading_)); DCHECK(!(migrate_session_early_v2_ && go_away_on_path_degrading_));
...@@ -2352,6 +2467,19 @@ void QuicChromiumClientSession::OnProbeFailed( ...@@ -2352,6 +2467,19 @@ void QuicChromiumClientSession::OnProbeFailed(
/*is_success=*/false); /*is_success=*/false);
}); });
if (version().HasIetfQuicFrames()) {
auto* context = static_cast<QuicChromiumPathValidationContext*>(
connection()->GetPathValidationContext());
if (!context)
return;
if (context->network() == network &&
context->peer_address() == peer_address) {
connection()->CancelPathValidation();
}
}
LogProbeResultToHistogram(current_migration_cause_, false); LogProbeResultToHistogram(current_migration_cause_, false);
if (network != NetworkChangeNotifier::kInvalidNetworkHandle) { if (network != NetworkChangeNotifier::kInvalidNetworkHandle) {
...@@ -2418,7 +2546,16 @@ void QuicChromiumClientSession::OnNetworkDisconnectedV2( ...@@ -2418,7 +2546,16 @@ void QuicChromiumClientSession::OnNetworkDisconnectedV2(
"disconnected_network", disconnected_network); "disconnected_network", disconnected_network);
// Stop probing the disconnected network if there is one. // Stop probing the disconnected network if there is one.
if (version().HasIetfQuicFrames()) {
auto* context = static_cast<QuicChromiumPathValidationContext*>(
connection()->GetPathValidationContext());
if (context && context->network() == disconnected_network &&
context->peer_address() == peer_address()) {
connection()->CancelPathValidation();
}
} else {
probing_manager_.CancelProbing(disconnected_network, peer_address()); probing_manager_.CancelProbing(disconnected_network, peer_address());
}
if (disconnected_network == default_network_) { if (disconnected_network == default_network_) {
DVLOG(1) << "Default network: " << default_network_ << " is disconnected."; DVLOG(1) << "Default network: " << default_network_ << " is disconnected.";
default_network_ = NetworkChangeNotifier::kInvalidNetworkHandle; default_network_ = NetworkChangeNotifier::kInvalidNetworkHandle;
...@@ -2535,7 +2672,16 @@ void QuicChromiumClientSession::MigrateNetworkImmediately( ...@@ -2535,7 +2672,16 @@ void QuicChromiumClientSession::MigrateNetworkImmediately(
} }
// Cancel probing on |network| if there is any. // Cancel probing on |network| if there is any.
if (version().HasIetfQuicFrames()) {
auto* context = static_cast<QuicChromiumPathValidationContext*>(
connection()->GetPathValidationContext());
if (context && context->network() == network &&
context->peer_address() == peer_address()) {
connection()->CancelPathValidation();
}
} else {
probing_manager_.CancelProbing(network, peer_address()); probing_manager_.CancelProbing(network, peer_address());
}
MigrationResult result = MigrationResult result =
Migrate(network, ToIPEndPoint(connection()->peer_address()), Migrate(network, ToIPEndPoint(connection()->peer_address()),
...@@ -2854,7 +3000,8 @@ ProbingResult QuicChromiumClientSession::MaybeStartProbing( ...@@ -2854,7 +3000,8 @@ ProbingResult QuicChromiumClientSession::MaybeStartProbing(
return ProbingResult::DISABLED_WITH_IDLE_SESSION; return ProbingResult::DISABLED_WITH_IDLE_SESSION;
// Abort probing if connection migration is disabled by config. // Abort probing if connection migration is disabled by config.
if (config()->DisableConnectionMigration()) { if (config()->DisableConnectionMigration() ||
(version().HasIetfQuicFrames() && !connection()->use_path_validator())) {
DVLOG(1) << "Client disables probing network with connection migration " DVLOG(1) << "Client disables probing network with connection migration "
<< "disabled by config"; << "disabled by config";
HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG, HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
...@@ -2870,8 +3017,16 @@ ProbingResult QuicChromiumClientSession::StartProbing( ...@@ -2870,8 +3017,16 @@ ProbingResult QuicChromiumClientSession::StartProbing(
NetworkChangeNotifier::NetworkHandle network, NetworkChangeNotifier::NetworkHandle network,
const quic::QuicSocketAddress& peer_address) { const quic::QuicSocketAddress& peer_address) {
// Check if probing manager is probing the same path. // Check if probing manager is probing the same path.
if (probing_manager_.IsUnderProbing(network, peer_address)) if (version().HasIetfQuicFrames()) {
auto* context = static_cast<QuicChromiumPathValidationContext*>(
connection()->GetPathValidationContext());
if (context && context->network() == network &&
context->peer_address() == peer_address) {
return ProbingResult::PENDING; return ProbingResult::PENDING;
}
} else if (probing_manager_.IsUnderProbing(network, peer_address)) {
return ProbingResult::PENDING;
}
// Create and configure socket on |network|. // Create and configure socket on |network|.
std::unique_ptr<DatagramClientSocket> probing_socket = std::unique_ptr<DatagramClientSocket> probing_socket =
...@@ -2902,6 +3057,24 @@ ProbingResult QuicChromiumClientSession::StartProbing( ...@@ -2902,6 +3057,24 @@ ProbingResult QuicChromiumClientSession::StartProbing(
rtt_ms = kDefaultRTTMilliSecs; rtt_ms = kDefaultRTTMilliSecs;
int timeout_ms = rtt_ms * 2; int timeout_ms = rtt_ms * 2;
if (version().HasIetfQuicFrames() &&
current_migration_cause_ != CHANGE_PORT_ON_PATH_DEGRADING) {
probing_reader->StartReading();
path_validation_writer_delegate_.set_network(network);
path_validation_writer_delegate_.set_peer_address(peer_address);
probing_writer->set_delegate(&path_validation_writer_delegate_);
IPEndPoint local_address;
probing_socket->GetLocalAddress(&local_address);
auto context = std::make_unique<QuicChromiumPathValidationContext>(
ToQuicSocketAddress(local_address), peer_address, network,
std::move(probing_socket), std::move(probing_writer),
std::move(probing_reader));
ValidatePath(
std::move(context),
std::make_unique<ConnectionMigrationValidationResultDelegate>(this));
return ProbingResult::PENDING;
}
probing_manager_.StartProbing( probing_manager_.StartProbing(
network, peer_address, std::move(probing_socket), network, peer_address, std::move(probing_socket),
std::move(probing_writer), std::move(probing_reader), std::move(probing_writer), std::move(probing_reader),
......
...@@ -44,7 +44,9 @@ ...@@ -44,7 +44,9 @@
#include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" #include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_path_validator.h"
#include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/core/quic_server_id.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
...@@ -409,6 +411,89 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession ...@@ -409,6 +411,89 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession
DISALLOW_COPY_AND_ASSIGN(StreamRequest); DISALLOW_COPY_AND_ASSIGN(StreamRequest);
}; };
// This class contains all the context needed for path validation and
// migration.
class NET_EXPORT_PRIVATE QuicChromiumPathValidationContext
: public quic::QuicPathValidationContext {
public:
QuicChromiumPathValidationContext(
const quic::QuicSocketAddress& self_address,
const quic::QuicSocketAddress& peer_address,
NetworkChangeNotifier::NetworkHandle network,
std::unique_ptr<DatagramClientSocket> socket,
std::unique_ptr<QuicChromiumPacketWriter> writer,
std::unique_ptr<QuicChromiumPacketReader> reader);
~QuicChromiumPathValidationContext() override;
NetworkChangeNotifier::NetworkHandle network();
quic::QuicPacketWriter* WriterToUse() override;
// Transfer the ownership from |this| to the caller.
std::unique_ptr<QuicChromiumPacketWriter> ReleaseWriter();
std::unique_ptr<DatagramClientSocket> ReleaseSocket();
std::unique_ptr<QuicChromiumPacketReader> ReleaseReader();
private:
NetworkChangeNotifier::NetworkHandle network_handle_;
std::unique_ptr<DatagramClientSocket> socket_;
std::unique_ptr<QuicChromiumPacketWriter> writer_;
std::unique_ptr<QuicChromiumPacketReader> reader_;
};
// This class implements Chrome logic for path validation events associated
// with connection migration.
class NET_EXPORT_PRIVATE ConnectionMigrationValidationResultDelegate
: public quic::QuicPathValidator::ResultDelegate {
public:
explicit ConnectionMigrationValidationResultDelegate(
QuicChromiumClientSession* session);
void OnPathValidationSuccess(
std::unique_ptr<quic::QuicPathValidationContext> context) override;
void OnPathValidationFailure(
std::unique_ptr<quic::QuicPathValidationContext> context) override;
private:
// |session_| owns |this| and should out live |this|.
QuicChromiumClientSession* session_;
};
// This class is used to handle writer events that occur on the probing path.
class NET_EXPORT_PRIVATE QuicChromiumPathValidationWriterDelegate
: public QuicChromiumPacketWriter::Delegate {
public:
QuicChromiumPathValidationWriterDelegate(
QuicChromiumClientSession* session,
base::SequencedTaskRunner* task_runner);
~QuicChromiumPathValidationWriterDelegate();
// QuicChromiumPacketWriter::Delegate interface.
int HandleWriteError(
int error_code,
scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> last_packet)
override;
void OnWriteError(int error_code) override;
void OnWriteUnblocked() override;
void set_peer_address(const quic::QuicSocketAddress& peer_address);
void set_network(NetworkChangeNotifier::NetworkHandle network);
private:
void NotifySessionProbeFailed(NetworkChangeNotifier::NetworkHandle network);
// |session_| owns |this| and should out live |this|.
QuicChromiumClientSession* session_;
// |task_owner_| should out live |this|.
base::SequencedTaskRunner* task_runner_;
// The path validation context of the most recent probing.
NetworkChangeNotifier::NetworkHandle network_;
quic::QuicSocketAddress peer_address_;
base::WeakPtrFactory<QuicChromiumPathValidationWriterDelegate>
weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(QuicChromiumPathValidationWriterDelegate);
};
// Constructs a new session which will own |connection|, but not // Constructs a new session which will own |connection|, but not
// |stream_factory|, which must outlive this session. // |stream_factory|, which must outlive this session.
// TODO(rch): decouple the factory from the session via a Delegate interface. // TODO(rch): decouple the factory from the session via a Delegate interface.
...@@ -952,6 +1037,8 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession ...@@ -952,6 +1037,8 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession
std::unique_ptr<quic::QuicClientPushPromiseIndex> push_promise_index_; std::unique_ptr<quic::QuicClientPushPromiseIndex> push_promise_index_;
QuicChromiumPathValidationWriterDelegate path_validation_writer_delegate_;
base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_{this}; base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession); DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession);
......
This diff is collapsed.
...@@ -494,6 +494,35 @@ QuicTestPacketMaker::MakeDataRstAckAndConnectionClosePacket( ...@@ -494,6 +494,35 @@ QuicTestPacketMaker::MakeDataRstAckAndConnectionClosePacket(
return BuildPacket(); return BuildPacket();
} }
std::unique_ptr<quic::QuicReceivedPacket>
QuicTestPacketMaker::MakeDataRstAckAndConnectionClosePacket(
uint64_t num,
bool include_version,
quic::QuicStreamId data_stream_id,
absl::string_view data,
quic::QuicStreamId rst_stream_id,
quic::QuicRstStreamErrorCode error_code,
uint64_t largest_received,
uint64_t smallest_received,
quic::QuicErrorCode quic_error,
const std::string& quic_error_details,
uint64_t frame_type) {
InitializeHeader(num, include_version);
AddQuicAckFrame(largest_received, smallest_received);
AddQuicStreamFrame(data_stream_id, /* fin = */ false, data);
if (version_.HasIetfQuicFrames()) {
AddQuicStopSendingFrame(rst_stream_id, error_code);
}
AddQuicRstStreamFrame(rst_stream_id, error_code);
AddQuicAckFrame(largest_received, smallest_received);
AddQuicConnectionCloseFrame(quic_error, quic_error_details, frame_type);
return BuildPacket();
}
std::unique_ptr<quic::QuicReceivedPacket> std::unique_ptr<quic::QuicReceivedPacket>
QuicTestPacketMaker::MakeAckAndConnectionClosePacket( QuicTestPacketMaker::MakeAckAndConnectionClosePacket(
uint64_t num, uint64_t num,
......
...@@ -205,6 +205,20 @@ class QuicTestPacketMaker { ...@@ -205,6 +205,20 @@ class QuicTestPacketMaker {
quic::QuicErrorCode quic_error, quic::QuicErrorCode quic_error,
const std::string& quic_error_details); const std::string& quic_error_details);
std::unique_ptr<quic::QuicReceivedPacket>
MakeDataRstAckAndConnectionClosePacket(
uint64_t num,
bool include_version,
quic::QuicStreamId data_stream_id,
absl::string_view data,
quic::QuicStreamId rst_stream_id,
quic::QuicRstStreamErrorCode error_code,
uint64_t largest_received,
uint64_t smallest_received,
quic::QuicErrorCode quic_error,
const std::string& quic_error_details,
uint64_t frame_type);
std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndConnectionClosePacket( std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndConnectionClosePacket(
uint64_t num, uint64_t num,
bool include_version, bool include_version,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment