mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-07-29 03:41:11 +03:00
Add padding to QUIC short header packets
Summary: Adds paddingModulo to QuicPacketBuilder, which pads up short header packets so that the length remaining of a packet is a multiple of paddingModulo ie a message of length 25 and max packet size of 40 with a paddingModulo of 8 will get 7 padding frames to a total length of 32. (and a message of length 26 will get 6 padding frames to also go up to a total length of 32) Reviewed By: mjoras Differential Revision: D32858254 fbshipit-source-id: 99ada01108429db9f9bba1e342daf99e80385179
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6b7d667e51
commit
29ed688b58
@ -6,10 +6,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <quic/api/QuicPacketScheduler.h>
|
||||
|
||||
#include <folly/portability/GTest.h>
|
||||
|
||||
#include <quic/api/QuicPacketScheduler.h>
|
||||
#include <quic/api/QuicTransportFunctions.h>
|
||||
#include <quic/api/test/Mocks.h>
|
||||
#include <quic/client/state/ClientStateMachine.h>
|
||||
@ -517,7 +516,7 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerStreamNotExists) {
|
||||
TEST_F(QuicPacketSchedulerTest, NoCloningForDSR) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
ASSERT_FALSE(noopScheduler.hasData());
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "Juice WRLD", 0);
|
||||
EXPECT_FALSE(cloningScheduler.hasData());
|
||||
@ -543,7 +542,7 @@ TEST_F(QuicPacketSchedulerTest, NoCloningForDSR) {
|
||||
TEST_F(QuicPacketSchedulerTest, CloningSchedulerTest) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
ASSERT_FALSE(noopScheduler.hasData());
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||
EXPECT_FALSE(cloningScheduler.hasData());
|
||||
@ -610,7 +609,7 @@ TEST_P(QuicPacketSchedulerTest, NoCloningWithOnlyD6DProbes) {
|
||||
false /* isDSRPacket */);
|
||||
ASSERT_EQ(1, conn.outstandings.packets.size());
|
||||
EXPECT_TRUE(conn.outstandings.packets.back().metadata.isD6DProbe);
|
||||
FrameScheduler noopScheduler("noopScheduler");
|
||||
FrameScheduler noopScheduler("noopScheduler", conn);
|
||||
CloningScheduler cloningScheduler(
|
||||
noopScheduler, conn, "MarShall Mathers", cipherOverhead);
|
||||
EXPECT_FALSE(cloningScheduler.hasData());
|
||||
@ -619,7 +618,7 @@ TEST_P(QuicPacketSchedulerTest, NoCloningWithOnlyD6DProbes) {
|
||||
TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
ASSERT_FALSE(noopScheduler.hasData());
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||
EXPECT_FALSE(cloningScheduler.hasData());
|
||||
@ -688,7 +687,7 @@ TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
|
||||
TEST_F(QuicPacketSchedulerTest, DoNotCloneProcessedClonedPacket) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||
// Add two outstanding packets, but then mark the second one processed by
|
||||
// adding a PacketEvent that's missing from the outstandings.packetEvents set
|
||||
@ -720,7 +719,7 @@ TEST_F(QuicPacketSchedulerTest, DoNotCloneProcessedClonedPacket) {
|
||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasHandshakeData) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||
EXPECT_FALSE(cloningScheduler.hasData());
|
||||
|
||||
@ -731,7 +730,7 @@ TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasHandshakeData) {
|
||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasInitialData) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||
EXPECT_FALSE(cloningScheduler.hasData());
|
||||
|
||||
@ -742,7 +741,7 @@ TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasInitialData) {
|
||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasAppDataData) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||
EXPECT_FALSE(cloningScheduler.hasData());
|
||||
|
||||
@ -753,7 +752,7 @@ TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasAppDataData) {
|
||||
TEST_F(QuicPacketSchedulerTest, DoNotCloneHandshake) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||
// Add two outstanding packets, with second one being handshake
|
||||
auto expected = addOutstandingPacket(conn);
|
||||
@ -781,7 +780,7 @@ TEST_F(QuicPacketSchedulerTest, DoNotCloneHandshake) {
|
||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerUseNormalSchedulerFirst) {
|
||||
QuicClientConnectionState conn(
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
NiceMock<MockFrameScheduler> mockScheduler;
|
||||
NiceMock<MockFrameScheduler> mockScheduler(&conn);
|
||||
CloningScheduler cloningScheduler(mockScheduler, conn, "Mocker", 0);
|
||||
ShortHeader header(
|
||||
ProtectionType::KeyPhaseOne,
|
||||
@ -831,7 +830,7 @@ TEST_F(QuicPacketSchedulerTest, CloneWillGenerateNewWindowUpdate) {
|
||||
FizzClientQuicHandshakeContext::Builder().build());
|
||||
conn.streamManager->setMaxLocalBidirectionalStreams(10);
|
||||
auto stream = conn.streamManager->createNextBidirectionalStream().value();
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "GiantsShoulder", 0);
|
||||
PacketEvent expectedPacketEvent(
|
||||
PacketNumberSpace::AppData, addOutstandingPacket(conn));
|
||||
@ -917,7 +916,7 @@ TEST_F(QuicPacketSchedulerTest, CloningSchedulerWithInplaceBuilder) {
|
||||
bufAccessor.release(std::move(buf));
|
||||
conn.bufAccessor = &bufAccessor;
|
||||
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
ASSERT_FALSE(noopScheduler.hasData());
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "93MillionMiles", 0);
|
||||
auto packetNum = addOutstandingPacket(conn);
|
||||
@ -999,7 +998,7 @@ TEST_F(QuicPacketSchedulerTest, CloningSchedulerWithInplaceBuilderFullPacket) {
|
||||
buf->clear();
|
||||
bufAccessor.release(std::move(buf));
|
||||
|
||||
FrameScheduler noopScheduler("noopScheduler");
|
||||
FrameScheduler noopScheduler("noopScheduler", conn);
|
||||
ASSERT_FALSE(noopScheduler.hasData());
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "93MillionMiles", 0);
|
||||
EXPECT_TRUE(cloningScheduler.hasData());
|
||||
@ -1077,7 +1076,7 @@ TEST_F(QuicPacketSchedulerTest, CloneLargerThanOriginalPacket) {
|
||||
conn.udpSendPacketLen,
|
||||
std::move(cloneHeader),
|
||||
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
|
||||
FrameScheduler noopScheduler("noopScheduler");
|
||||
FrameScheduler noopScheduler("noopScheduler", conn);
|
||||
CloningScheduler cloningScheduler(
|
||||
noopScheduler, conn, "CopyCat", cipherOverhead);
|
||||
auto cloneResult = cloningScheduler.scheduleFramesForPacket(
|
||||
@ -1547,7 +1546,7 @@ TEST_F(
|
||||
bufAccessor.release(std::move(buf));
|
||||
conn.bufAccessor = &bufAccessor;
|
||||
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
ASSERT_FALSE(noopScheduler.hasData());
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "Little Hurry", 0);
|
||||
addOutstandingPacket(conn);
|
||||
@ -1591,7 +1590,7 @@ TEST_F(
|
||||
bufAccessor.release(std::move(buf));
|
||||
conn.bufAccessor = &bufAccessor;
|
||||
|
||||
FrameScheduler noopScheduler("frame");
|
||||
FrameScheduler noopScheduler("frame", conn);
|
||||
ASSERT_FALSE(noopScheduler.hasData());
|
||||
CloningScheduler cloningScheduler(noopScheduler, conn, "HotPot", 0);
|
||||
addOutstandingPacket(conn);
|
||||
@ -2038,6 +2037,179 @@ TEST_F(QuicPacketSchedulerTest, DatagramFrameWriteWhenRoomAvailable) {
|
||||
ASSERT_EQ(frames.size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(QuicPacketSchedulerTest, ShortHeaderPaddingWithSpaceForPadding) {
|
||||
QuicServerConnectionState conn(
|
||||
FizzServerQuicHandshakeContext::Builder().build());
|
||||
size_t paddingModulo = 16;
|
||||
conn.transportSettings.paddingModulo = paddingModulo;
|
||||
// create enough input data to partially fill packet
|
||||
size_t inputDataLength1 = conn.udpSendPacketLen / 2;
|
||||
size_t inputDataLength2 = inputDataLength1 + 1;
|
||||
auto inputData1 = buildRandomInputData(inputDataLength1);
|
||||
auto inputData2 = buildRandomInputData(inputDataLength2);
|
||||
|
||||
FrameScheduler scheduler = std::move(FrameScheduler::Builder(
|
||||
conn,
|
||||
EncryptionLevel::AppData,
|
||||
PacketNumberSpace::AppData,
|
||||
"streamScheduler")
|
||||
.streamFrames())
|
||||
.build();
|
||||
|
||||
ShortHeader shortHeader1(
|
||||
ProtectionType::KeyPhaseOne,
|
||||
conn.clientConnectionId.value_or(getTestConnectionId()),
|
||||
getNextPacketNum(conn, PacketNumberSpace::AppData));
|
||||
ShortHeader shortHeader2(
|
||||
ProtectionType::KeyPhaseOne,
|
||||
conn.clientConnectionId.value_or(getTestConnectionId()),
|
||||
getNextPacketNum(conn, PacketNumberSpace::AppData));
|
||||
|
||||
RegularQuicPacketBuilder builder1(
|
||||
conn.udpSendPacketLen,
|
||||
std::move(shortHeader1),
|
||||
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
|
||||
RegularQuicPacketBuilder builder2(
|
||||
conn.udpSendPacketLen,
|
||||
std::move(shortHeader2),
|
||||
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
|
||||
|
||||
DatagramFrame frame1(inputDataLength1, std::move(inputData1));
|
||||
DatagramFrame frame2(inputDataLength2, std::move(inputData2));
|
||||
writeFrame(frame1, builder1);
|
||||
writeFrame(frame2, builder2);
|
||||
|
||||
NiceMock<MockQuicStats> quicStats;
|
||||
conn.statsCallback = &quicStats;
|
||||
|
||||
EXPECT_CALL(quicStats, onShortHeaderPadding(_)).Times(1);
|
||||
auto result1 = scheduler.scheduleFramesForPacket(
|
||||
std::move(builder1), conn.udpSendPacketLen);
|
||||
EXPECT_CALL(quicStats, onShortHeaderPadding(_)).Times(1);
|
||||
auto result2 = scheduler.scheduleFramesForPacket(
|
||||
std::move(builder2), conn.udpSendPacketLen);
|
||||
|
||||
auto headerLength1 = result1.packet->header->computeChainDataLength();
|
||||
auto bodyLength1 = result1.packet->body->computeChainDataLength();
|
||||
auto packetLength1 = headerLength1 + bodyLength1;
|
||||
auto expectedPadding1 =
|
||||
(conn.udpSendPacketLen - (inputDataLength1 + headerLength1)) %
|
||||
paddingModulo;
|
||||
|
||||
auto headerLength2 = result2.packet->header->computeChainDataLength();
|
||||
auto bodyLength2 = result2.packet->body->computeChainDataLength();
|
||||
auto packetLength2 = headerLength2 + bodyLength2;
|
||||
auto expectedPadding2 =
|
||||
(conn.udpSendPacketLen - (inputDataLength2 + headerLength2)) %
|
||||
paddingModulo;
|
||||
|
||||
EXPECT_EQ(packetLength1, headerLength1 + inputDataLength1 + expectedPadding1);
|
||||
EXPECT_EQ(packetLength2, headerLength2 + inputDataLength2 + expectedPadding2);
|
||||
// ensure two similar size input data get padded up to same length
|
||||
EXPECT_EQ(packetLength1, packetLength2);
|
||||
}
|
||||
|
||||
TEST_F(QuicPacketSchedulerTest, ShortHeaderPaddingNearMaxPacketLength) {
|
||||
QuicServerConnectionState conn(
|
||||
FizzServerQuicHandshakeContext::Builder().build());
|
||||
conn.udpSendPacketLen = 1000;
|
||||
size_t paddingModulo = 50;
|
||||
conn.transportSettings.paddingModulo = paddingModulo;
|
||||
// create enough input data to almost fill packet
|
||||
size_t inputDataLength = conn.udpSendPacketLen - 20;
|
||||
auto inputData = buildRandomInputData(inputDataLength);
|
||||
|
||||
FrameScheduler scheduler = std::move(FrameScheduler::Builder(
|
||||
conn,
|
||||
EncryptionLevel::AppData,
|
||||
PacketNumberSpace::AppData,
|
||||
"streamScheduler")
|
||||
.streamFrames())
|
||||
.build();
|
||||
|
||||
ShortHeader shortHeader(
|
||||
ProtectionType::KeyPhaseOne,
|
||||
conn.clientConnectionId.value_or(getTestConnectionId()),
|
||||
getNextPacketNum(conn, PacketNumberSpace::AppData));
|
||||
|
||||
RegularQuicPacketBuilder builder(
|
||||
conn.udpSendPacketLen,
|
||||
std::move(shortHeader),
|
||||
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
|
||||
|
||||
DatagramFrame frame(inputDataLength, std::move(inputData));
|
||||
writeFrame(frame, builder);
|
||||
|
||||
NiceMock<MockQuicStats> quicStats;
|
||||
conn.statsCallback = &quicStats;
|
||||
|
||||
EXPECT_CALL(quicStats, onShortHeaderPadding(_)).Times(1);
|
||||
auto result = scheduler.scheduleFramesForPacket(
|
||||
std::move(builder), conn.udpSendPacketLen);
|
||||
|
||||
auto headerLength = result.packet->header->computeChainDataLength();
|
||||
auto bodyLength = result.packet->body->computeChainDataLength();
|
||||
|
||||
auto packetLength = headerLength + bodyLength;
|
||||
|
||||
auto expectedPadding =
|
||||
(conn.udpSendPacketLen - (inputDataLength + headerLength)) %
|
||||
paddingModulo;
|
||||
|
||||
EXPECT_EQ(packetLength, headerLength + inputDataLength + expectedPadding);
|
||||
EXPECT_EQ(packetLength, conn.udpSendPacketLen);
|
||||
}
|
||||
|
||||
TEST_F(QuicPacketSchedulerTest, ShortHeaderPaddingMaxPacketLength) {
|
||||
QuicServerConnectionState conn(
|
||||
FizzServerQuicHandshakeContext::Builder().build());
|
||||
conn.udpSendPacketLen = 1000;
|
||||
size_t paddingModulo = 50;
|
||||
conn.transportSettings.paddingModulo = paddingModulo;
|
||||
|
||||
FrameScheduler scheduler = std::move(FrameScheduler::Builder(
|
||||
conn,
|
||||
EncryptionLevel::AppData,
|
||||
PacketNumberSpace::AppData,
|
||||
"streamScheduler")
|
||||
.streamFrames())
|
||||
.build();
|
||||
|
||||
ShortHeader shortHeader(
|
||||
ProtectionType::KeyPhaseOne,
|
||||
conn.clientConnectionId.value_or(getTestConnectionId()),
|
||||
getNextPacketNum(conn, PacketNumberSpace::AppData));
|
||||
|
||||
size_t largestAckedPacketNum =
|
||||
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0);
|
||||
auto packetNumberEncoding = encodePacketNumber(
|
||||
shortHeader.getPacketSequenceNum(), largestAckedPacketNum);
|
||||
auto connectionIdSize = shortHeader.getConnectionId().size();
|
||||
|
||||
RegularQuicPacketBuilder builder(
|
||||
conn.udpSendPacketLen, std::move(shortHeader), largestAckedPacketNum);
|
||||
|
||||
// create enough input data to fully fill packet
|
||||
while (builder.remainingSpaceInPkt() >
|
||||
connectionIdSize + packetNumberEncoding.length + 1) {
|
||||
writeFrame(PaddingFrame(), builder);
|
||||
}
|
||||
|
||||
NiceMock<MockQuicStats> quicStats;
|
||||
conn.statsCallback = &quicStats;
|
||||
|
||||
EXPECT_CALL(quicStats, onShortHeaderPadding(_)).Times(1);
|
||||
auto result = scheduler.scheduleFramesForPacket(
|
||||
std::move(builder), conn.udpSendPacketLen);
|
||||
|
||||
auto headerLength = result.packet->header->computeChainDataLength();
|
||||
auto bodyLength = result.packet->body->computeChainDataLength();
|
||||
|
||||
auto packetLength = headerLength + bodyLength;
|
||||
|
||||
EXPECT_EQ(packetLength, conn.udpSendPacketLen);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
QuicPacketSchedulerTests,
|
||||
QuicPacketSchedulerTest,
|
||||
|
Reference in New Issue
Block a user