Apply the amplification limit for all packets, not just handshake packets in ietf quic. also fixes an issue where shouldgeneratepacket doesn't check if the connection is connected. protected by gfe2_reloadable_flag_quic_move_amplification_limit.
Because of lack of cert compression, set anti_amplification_factor to 5.
This change is from pending cl/313200305.
PiperOrigin-RevId: 313595976
Change-Id: Ia67e8c8faa6c17ebc682318047dc8996df55715f
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc
index c482856..291884d 100644
--- a/quic/core/http/quic_server_session_base_test.cc
+++ b/quic/core/http/quic_server_session_base_test.cc
@@ -157,6 +157,9 @@
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
session_->config(), kMinimumFlowControlSendWindow);
session_->OnConfigNegotiated();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
}
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 8b78d7f..9e1280a 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -197,6 +197,9 @@
this->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(connection->perspective()));
+ if (this->connection()->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(this->connection());
+ }
}
~TestSession() override { DeleteConnection(); }
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index bafb0f2..41c204f 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -324,6 +324,9 @@
&helper_, &alarm_factory_, perspective, SupportedVersions(GetParam()));
session_ = std::make_unique<StrictMock<TestSession>>(connection_);
session_->Initialize();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
ON_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillByDefault(
diff --git a/quic/core/qpack/qpack_send_stream_test.cc b/quic/core/qpack/qpack_send_stream_test.cc
index c77a621..63e0f12 100644
--- a/quic/core/qpack/qpack_send_stream_test.cc
+++ b/quic/core/qpack/qpack_send_stream_test.cc
@@ -7,6 +7,7 @@
#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
@@ -66,6 +67,9 @@
SupportedVersions(GetParam().version))),
session_(connection_) {
session_.Initialize();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
session_.config(), kMinimumFlowControlSendWindow);
QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional(
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index d6c75bf..1ed056d 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2206,9 +2206,13 @@
bool QuicConnection::ShouldGeneratePacket(
HasRetransmittableData retransmittable,
IsHandshake handshake) {
+ DCHECK(handshake != IS_HANDSHAKE ||
+ QuicVersionUsesCryptoFrames(transport_version()))
+ << ENDPOINT
+ << "Handshake in STREAM frames should not check ShouldGeneratePacket";
// We should serialize handshake packets immediately to ensure that they
// end up sent at the right encryption level.
- if (handshake == IS_HANDSHAKE) {
+ if (!move_amplification_limit_ && handshake == IS_HANDSHAKE) {
if (LimitedByAmplificationFactor()) {
// Server is constrained by the amplification restriction.
QUIC_DVLOG(1) << ENDPOINT << "Constrained by amplification restriction";
@@ -2253,6 +2257,14 @@
return false;
}
+ if (move_amplification_limit_ && LimitedByAmplificationFactor()) {
+ // Server is constrained by the amplification restriction.
+ QUIC_RELOADABLE_FLAG_COUNT(quic_move_amplification_limit);
+ QUIC_CODE_COUNT(quic_throttled_by_amplification_limit);
+ QUIC_DVLOG(1) << ENDPOINT << "Constrained by amplification restriction";
+ return false;
+ }
+
if (sent_packet_manager_.pending_timer_transmission_count() > 0) {
// Force sending the retransmissions for HANDSHAKE, TLP, RTO, PROBING cases.
return true;
@@ -4033,8 +4045,12 @@
const bool flushed = packet_creator_.FlushAckFrame(frames);
if (!flushed) {
// Connection is write blocked.
- QUIC_BUG_IF(!writer_->IsWriteBlocked())
- << "Writer not blocked, but ACK not flushed for packet space:" << i;
+ QUIC_BUG_IF(
+ !writer_->IsWriteBlocked() &&
+ (!move_amplification_limit_ || !LimitedByAmplificationFactor()))
+ << "Writer not blocked and not throttled by amplification factor, "
+ "but ACK not flushed for packet space:"
+ << i;
break;
}
ResetAckStates();
@@ -4215,7 +4231,7 @@
bool QuicConnection::LimitedByAmplificationFactor() const {
return EnforceAntiAmplificationLimit() &&
bytes_sent_before_address_validation_ >=
- GetQuicFlag(FLAGS_quic_anti_amplification_factor) *
+ anti_amplification_factor_ *
bytes_received_before_address_validation_;
}
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 420f8c8..589568a 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -979,6 +979,10 @@
void OnTransportParametersReceived(
const TransportParameters& transport_parameters) const;
+ size_t anti_amplification_factor() const {
+ return anti_amplification_factor_;
+ }
+
protected:
// Calls cancel() on all the alarms owned by this connection.
void CancelAllAlarms();
@@ -1669,6 +1673,19 @@
const bool update_ack_alarm_in_send_all_pending_acks_ =
GetQuicReloadableFlag(quic_update_ack_alarm_in_send_all_pending_acks);
+
+ const bool move_amplification_limit_ =
+ GetQuicReloadableFlag(quic_move_amplification_limit);
+
+ // TODO(fayang): Change the default value of quic_anti_amplification_factor to
+ // 5 when deprecating quic_move_amplification_limit.
+ // TODO(b/153892665): Change the default value of
+ // quic_anti_amplification_factor back to 3 when cert compression is
+ // supported.
+ const size_t anti_amplification_factor_ =
+ move_amplification_limit_
+ ? 5
+ : GetQuicFlag(FLAGS_quic_anti_amplification_factor);
};
} // namespace quic
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index a9e25f0..ff29c26 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -1752,6 +1752,9 @@
void MtuDiscoveryTestInit() {
set_perspective(Perspective::IS_SERVER);
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ if (version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ }
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
// QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size
@@ -1999,6 +2002,9 @@
set_perspective(Perspective::IS_SERVER);
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ if (version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ }
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -7074,12 +7080,24 @@
ProcessPacket(1);
BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
+ if (GetQuicReloadableFlag(quic_move_amplification_limit) &&
+ QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ }
connection_.SendCryptoDataWithString("foo", 0);
EXPECT_TRUE(writer_->IsWriteBlocked());
EXPECT_FALSE(connection_.HasQueuedData());
connection_.SendCryptoDataWithString("bar", 3);
EXPECT_TRUE(writer_->IsWriteBlocked());
- EXPECT_TRUE(connection_.HasQueuedData());
+ if (GetQuicReloadableFlag(quic_move_amplification_limit) &&
+ QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ // CRYPTO frames are not flushed when writer is blocked.
+ EXPECT_FALSE(connection_.HasQueuedData());
+ } else {
+ EXPECT_TRUE(connection_.HasQueuedData());
+ }
}
TEST_P(QuicConnectionTest, BundleAckForSecondCHLO) {
@@ -10045,13 +10063,17 @@
// Verify no data can be sent at the beginning because bytes received is 0.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
connection_.SendCryptoDataWithString("foo", 0);
+ if (GetQuicReloadableFlag(quic_move_amplification_limit)) {
+ EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
+ EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA));
+ }
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Receives packet 1.
ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
const size_t anti_amplification_factor =
- GetQuicFlag(FLAGS_quic_anti_amplification_factor);
+ connection_.anti_amplification_factor();
// Verify now packets can be sent.
for (size_t i = 0; i < anti_amplification_factor; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
@@ -10086,6 +10108,48 @@
}
}
+TEST_P(QuicConnectionTest, AckPendingWithAmplificationLimited) {
+ if (!connection_.version().SupportsAntiAmplificationLimit() ||
+ !GetQuicReloadableFlag(quic_move_amplification_limit)) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber());
+ set_perspective(Perspective::IS_SERVER);
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ // Receives packet 1.
+ ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ // Send response in different encryption level and cause amplification factor
+ // throttled.
+ size_t i = 0;
+ while (connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+ connection_.SendCryptoDataWithString(std::string(1024, 'a'), i * 1024,
+ ENCRYPTION_HANDSHAKE);
+ ++i;
+ }
+ // Verify ACK is still pending.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+
+ // Fire ACK alarm and verify ACK cannot be sent due to amplification factor.
+ clock_.AdvanceTime(connection_.GetAckAlarm()->deadline() - clock_.Now());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.GetAckAlarm()->Fire();
+ // Verify ACK alarm is cancelled.
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+
+ // Receives packet 2 and verify ACK gets flushed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
+ EXPECT_FALSE(writer_->ack_frames().empty());
+}
+
TEST_P(QuicConnectionTest, ConnectionCloseFrameType) {
if (!VersionHasIetfQuicFrames(version().transport_version)) {
// Test relevent only for IETF QUIC.
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 9d5e977..ddebac2 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -183,6 +183,9 @@
this->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(connection->perspective()));
+ if (this->connection()->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(this->connection());
+ }
}
~TestSession() override { DeleteConnection(); }
diff --git a/quic/quartc/quartc_packet_writer.h b/quic/quartc/quartc_packet_writer.h
index 8c89e23..a59344c 100644
--- a/quic/quartc/quartc_packet_writer.h
+++ b/quic/quartc/quartc_packet_writer.h
@@ -106,7 +106,7 @@
QuicByteCount max_packet_size_;
// Whether packets can be written.
- bool writable_ = false;
+ bool writable_ = true;
};
} // namespace quic
diff --git a/quic/test_tools/simulator/quic_endpoint.cc b/quic/test_tools/simulator/quic_endpoint.cc
index 5f8ee56..7061898 100644
--- a/quic/test_tools/simulator/quic_endpoint.cc
+++ b/quic/test_tools/simulator/quic_endpoint.cc
@@ -55,6 +55,7 @@
// Skip version negotiation.
test::QuicConnectionPeer::SetNegotiatedVersion(connection_.get());
}
+ test::QuicConnectionPeer::SetAddressValidated(connection_.get());
connection_->SetDataProducer(&producer_);
connection_->SetSessionNotifier(this);
notifier_ = std::make_unique<test::SimpleSessionNotifier>(connection_.get());
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc
index 3dfaa1e..5c84084 100644
--- a/quic/tools/quic_simple_server_stream_test.cc
+++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -18,6 +18,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
@@ -239,6 +240,9 @@
session_.config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
session_.Initialize();
+ if (connection_->version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(connection_);
+ }
stream_ = new StrictMock<TestStream>(
GetNthClientInitiatedBidirectionalStreamId(
connection_->transport_version(), 0),