1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-07-30 14:43:05 +03:00

Add option to clone all CRYPTO packets at most once

Summary: Restore the buggy version of `cloneAllPacketsWithCryptoFrame`, which did allow up to two packets to be cloned in the same PTO flight but would only clone them at most once, as an optional mode of operation.

Reviewed By: mjoras

Differential Revision: D67994014

fbshipit-source-id: 16f66fd48a9a4410427ba21dea6e7f6d1eee48e6
This commit is contained in:
Jolene Tan
2025-01-15 14:08:52 -08:00
committed by Facebook GitHub Bot
parent a34b86f32a
commit a61b13a005
3 changed files with 27 additions and 11 deletions

View File

@ -938,6 +938,9 @@ SchedulingResult CloningScheduler::scheduleFramesForPacket(
if (std::find_if(frames.begin(), frames.end(), [](const auto& frame) { if (std::find_if(frames.begin(), frames.end(), [](const auto& frame) {
return frame.type() == QuicWriteFrame::Type::WriteCryptoFrame; return frame.type() == QuicWriteFrame::Type::WriteCryptoFrame;
}) != frames.end()) { }) != frames.end()) {
if (conn_.transportSettings.cloneCryptoPacketsAtMostOnce) {
continue;
}
auto mostRecentOutstandingPacketIdentifier = auto mostRecentOutstandingPacketIdentifier =
conn_.outstandings.packets.back().maybeClonedPacketIdentifier; conn_.outstandings.packets.back().maybeClonedPacketIdentifier;
if (mostRecentOutstandingPacketIdentifier == if (mostRecentOutstandingPacketIdentifier ==

View File

@ -630,14 +630,18 @@ TEST_F(QuicPacketSchedulerTest, DoNotCloneProcessedClonedPacket) {
EXPECT_EQ(expected, result.clonedPacketIdentifier->packetNumber); EXPECT_EQ(expected, result.clonedPacketIdentifier->packetNumber);
} }
class CloneAllPacketsWithCryptoFrameTest : public QuicPacketSchedulerTest, class CloneAllPacketsWithCryptoFrameTest
public WithParamInterface<bool> {}; : public QuicPacketSchedulerTest,
public WithParamInterface<std::tuple<bool, bool>> {};
TEST_P( TEST_P(
CloneAllPacketsWithCryptoFrameTest, CloneAllPacketsWithCryptoFrameTest,
TestCloneAllPacketsWithCryptoFrameTrueFalse) { TestCloneAllPacketsWithCryptoFrameTrueFalse) {
QuicClientConnectionState conn( QuicClientConnectionState conn(
FizzClientQuicHandshakeContext::Builder().build()); FizzClientQuicHandshakeContext::Builder().build());
conn.transportSettings.cloneAllPacketsWithCryptoFrame = GetParam(); auto testParams = GetParam();
conn.transportSettings.cloneAllPacketsWithCryptoFrame =
std::get<0>(testParams);
conn.transportSettings.cloneCryptoPacketsAtMostOnce = std::get<1>(testParams);
FrameScheduler noopScheduler("frame", conn); FrameScheduler noopScheduler("frame", conn);
CloningScheduler cloningScheduler(noopScheduler, conn, "cryptoClone", 0); CloningScheduler cloningScheduler(noopScheduler, conn, "cryptoClone", 0);
@ -671,7 +675,7 @@ TEST_P(
MaxDataFrame(conn.flowControlState.advertisedMaxOffset)); MaxDataFrame(conn.flowControlState.advertisedMaxOffset));
} }
// Add a third outstanding packet, which is a clone of the first packet // Add a third outstanding packet, which is a re-clone of the first packet
{ {
addInitialOutstandingPacket(conn); addInitialOutstandingPacket(conn);
conn.outstandings.packets.back().packet.frames.push_back( conn.outstandings.packets.back().packet.frames.push_back(
@ -687,6 +691,7 @@ TEST_P(
MaxDataFrame(conn.flowControlState.advertisedMaxOffset)); MaxDataFrame(conn.flowControlState.advertisedMaxOffset));
} }
// Schedule a fourth packet
std::vector<uint8_t> zeroConnIdData(quic::kDefaultConnectionIdSize, 0); std::vector<uint8_t> zeroConnIdData(quic::kDefaultConnectionIdSize, 0);
ConnectionId srcConnId(zeroConnIdData); ConnectionId srcConnId(zeroConnIdData);
LongHeader header( LongHeader header(
@ -701,18 +706,25 @@ TEST_P(
conn.ackStates.initialAckState->largestAckedByPeer.value_or(0)); conn.ackStates.initialAckState->largestAckedByPeer.value_or(0));
auto result = cloningScheduler.scheduleFramesForPacket( auto result = cloningScheduler.scheduleFramesForPacket(
std::move(builder), kDefaultUDPSendPacketLen); std::move(builder), kDefaultUDPSendPacketLen);
EXPECT_TRUE( if (conn.transportSettings.cloneAllPacketsWithCryptoFrame &&
result.clonedPacketIdentifier.has_value() && result.packet.has_value()); conn.transportSettings.cloneCryptoPacketsAtMostOnce) {
EXPECT_EQ( // First and second packets already cloned, skip all and schedule no packet
conn.transportSettings.cloneAllPacketsWithCryptoFrame ? secondPacketNum EXPECT_FALSE(result.clonedPacketIdentifier.has_value());
: firstPacketNum, EXPECT_FALSE(result.packet.has_value());
result.clonedPacketIdentifier->packetNumber); } else {
EXPECT_TRUE(
result.clonedPacketIdentifier.has_value() && result.packet.has_value());
EXPECT_EQ(
conn.transportSettings.cloneAllPacketsWithCryptoFrame ? secondPacketNum
: firstPacketNum,
result.clonedPacketIdentifier->packetNumber);
}
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
CloneAllPacketsWithCryptoFrameTest, CloneAllPacketsWithCryptoFrameTest,
CloneAllPacketsWithCryptoFrameTest, CloneAllPacketsWithCryptoFrameTest,
Bool()); Combine(Bool(), Bool()));
TEST_F(QuicPacketSchedulerTest, DoNotSkipUnclonedCryptoPacket) { TEST_F(QuicPacketSchedulerTest, DoNotSkipUnclonedCryptoPacket) {
QuicClientConnectionState conn( QuicClientConnectionState conn(

View File

@ -413,6 +413,7 @@ struct TransportSettings {
// receiving and then processing. // receiving and then processing.
bool networkDataPerSocketRead{false}; bool networkDataPerSocketRead{false};
bool cloneAllPacketsWithCryptoFrame{false}; bool cloneAllPacketsWithCryptoFrame{false};
bool cloneCryptoPacketsAtMostOnce{false};
// Use a reordering threshold heuristic of inflight / 2. // Use a reordering threshold heuristic of inflight / 2.
bool useInflightReorderingThreshold{false}; bool useInflightReorderingThreshold{false};
// Raise read callbacks for all unidirectional streams first on data // Raise read callbacks for all unidirectional streams first on data