mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-08-01 01:44:22 +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
@ -137,6 +137,8 @@ enum class TransportKnobParamId : uint64_t {
|
|||||||
MAX_PACING_RATE_KNOB = 0x4444,
|
MAX_PACING_RATE_KNOB = 0x4444,
|
||||||
// Set auto background mode (experimental)
|
// Set auto background mode (experimental)
|
||||||
AUTO_BACKGROUND_MODE = 0x5555,
|
AUTO_BACKGROUND_MODE = 0x5555,
|
||||||
|
// Set short header padding modulo size
|
||||||
|
SHORT_HEADER_PADDING_KNOB = 0x6666,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class FrameType : uint64_t {
|
enum class FrameType : uint64_t {
|
||||||
|
@ -188,7 +188,7 @@ FrameScheduler::Builder& FrameScheduler::Builder::datagramFrames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FrameScheduler FrameScheduler::Builder::build() && {
|
FrameScheduler FrameScheduler::Builder::build() && {
|
||||||
FrameScheduler scheduler(std::move(name_));
|
FrameScheduler scheduler(name_, conn_);
|
||||||
if (streamFrameScheduler_) {
|
if (streamFrameScheduler_) {
|
||||||
scheduler.streamFrameScheduler_.emplace(StreamFrameScheduler(conn_));
|
scheduler.streamFrameScheduler_.emplace(StreamFrameScheduler(conn_));
|
||||||
}
|
}
|
||||||
@ -221,7 +221,10 @@ FrameScheduler FrameScheduler::Builder::build() && {
|
|||||||
return scheduler;
|
return scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameScheduler::FrameScheduler(folly::StringPiece name) : name_(name) {}
|
FrameScheduler::FrameScheduler(
|
||||||
|
folly::StringPiece name,
|
||||||
|
QuicConnectionStateBase& conn)
|
||||||
|
: name_(name), conn_(conn) {}
|
||||||
|
|
||||||
SchedulingResult FrameScheduler::scheduleFramesForPacket(
|
SchedulingResult FrameScheduler::scheduleFramesForPacket(
|
||||||
PacketBuilderInterface&& builder,
|
PacketBuilderInterface&& builder,
|
||||||
@ -294,6 +297,17 @@ SchedulingResult FrameScheduler::scheduleFramesForPacket(
|
|||||||
writeFrame(PaddingFrame(), builder);
|
writeFrame(PaddingFrame(), builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const ShortHeader* shortHeader = builder.getPacketHeader().asShort();
|
||||||
|
if (shortHeader) {
|
||||||
|
size_t paddingModulo = conn_.transportSettings.paddingModulo;
|
||||||
|
if (paddingModulo > 0) {
|
||||||
|
size_t paddingIncrement = wrapper.remainingSpaceInPkt() % paddingModulo;
|
||||||
|
for (size_t i = 0; i < paddingIncrement; i++) {
|
||||||
|
writeFrame(PaddingFrame(), builder);
|
||||||
|
}
|
||||||
|
QUIC_STATS(conn_.statsCallback, onShortHeaderPadding, paddingIncrement);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SchedulingResult(folly::none, std::move(builder).buildPacket());
|
return SchedulingResult(folly::none, std::move(builder).buildPacket());
|
||||||
|
@ -284,7 +284,7 @@ class FrameScheduler : public QuicPacketScheduler {
|
|||||||
bool datagramFrameScheduler_{false};
|
bool datagramFrameScheduler_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit FrameScheduler(folly::StringPiece name);
|
FrameScheduler(folly::StringPiece name, QuicConnectionStateBase& conn);
|
||||||
|
|
||||||
SchedulingResult scheduleFramesForPacket(
|
SchedulingResult scheduleFramesForPacket(
|
||||||
PacketBuilderInterface&& builder,
|
PacketBuilderInterface&& builder,
|
||||||
@ -309,6 +309,7 @@ class FrameScheduler : public QuicPacketScheduler {
|
|||||||
folly::Optional<PingFrameScheduler> pingFrameScheduler_;
|
folly::Optional<PingFrameScheduler> pingFrameScheduler_;
|
||||||
folly::Optional<DatagramFrameScheduler> datagramFrameScheduler_;
|
folly::Optional<DatagramFrameScheduler> datagramFrameScheduler_;
|
||||||
folly::StringPiece name_;
|
folly::StringPiece name_;
|
||||||
|
QuicConnectionStateBase& conn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,7 +25,8 @@ class MockFrameScheduler : public FrameScheduler {
|
|||||||
public:
|
public:
|
||||||
~MockFrameScheduler() override = default;
|
~MockFrameScheduler() override = default;
|
||||||
|
|
||||||
MockFrameScheduler() : FrameScheduler("mock") {}
|
explicit MockFrameScheduler(QuicConnectionStateBase* conn)
|
||||||
|
: FrameScheduler("mock", *conn) {}
|
||||||
|
|
||||||
// override methods accepting rvalue ref since gmock doesn't support it
|
// override methods accepting rvalue ref since gmock doesn't support it
|
||||||
SchedulingResult scheduleFramesForPacket(
|
SchedulingResult scheduleFramesForPacket(
|
||||||
|
@ -6,10 +6,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <quic/api/QuicPacketScheduler.h>
|
|
||||||
|
|
||||||
#include <folly/portability/GTest.h>
|
#include <folly/portability/GTest.h>
|
||||||
|
|
||||||
|
#include <quic/api/QuicPacketScheduler.h>
|
||||||
#include <quic/api/QuicTransportFunctions.h>
|
#include <quic/api/QuicTransportFunctions.h>
|
||||||
#include <quic/api/test/Mocks.h>
|
#include <quic/api/test/Mocks.h>
|
||||||
#include <quic/client/state/ClientStateMachine.h>
|
#include <quic/client/state/ClientStateMachine.h>
|
||||||
@ -517,7 +516,7 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerStreamNotExists) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, NoCloningForDSR) {
|
TEST_F(QuicPacketSchedulerTest, NoCloningForDSR) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
ASSERT_FALSE(noopScheduler.hasData());
|
ASSERT_FALSE(noopScheduler.hasData());
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "Juice WRLD", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "Juice WRLD", 0);
|
||||||
EXPECT_FALSE(cloningScheduler.hasData());
|
EXPECT_FALSE(cloningScheduler.hasData());
|
||||||
@ -543,7 +542,7 @@ TEST_F(QuicPacketSchedulerTest, NoCloningForDSR) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, CloningSchedulerTest) {
|
TEST_F(QuicPacketSchedulerTest, CloningSchedulerTest) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
ASSERT_FALSE(noopScheduler.hasData());
|
ASSERT_FALSE(noopScheduler.hasData());
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||||
EXPECT_FALSE(cloningScheduler.hasData());
|
EXPECT_FALSE(cloningScheduler.hasData());
|
||||||
@ -610,7 +609,7 @@ TEST_P(QuicPacketSchedulerTest, NoCloningWithOnlyD6DProbes) {
|
|||||||
false /* isDSRPacket */);
|
false /* isDSRPacket */);
|
||||||
ASSERT_EQ(1, conn.outstandings.packets.size());
|
ASSERT_EQ(1, conn.outstandings.packets.size());
|
||||||
EXPECT_TRUE(conn.outstandings.packets.back().metadata.isD6DProbe);
|
EXPECT_TRUE(conn.outstandings.packets.back().metadata.isD6DProbe);
|
||||||
FrameScheduler noopScheduler("noopScheduler");
|
FrameScheduler noopScheduler("noopScheduler", conn);
|
||||||
CloningScheduler cloningScheduler(
|
CloningScheduler cloningScheduler(
|
||||||
noopScheduler, conn, "MarShall Mathers", cipherOverhead);
|
noopScheduler, conn, "MarShall Mathers", cipherOverhead);
|
||||||
EXPECT_FALSE(cloningScheduler.hasData());
|
EXPECT_FALSE(cloningScheduler.hasData());
|
||||||
@ -619,7 +618,7 @@ TEST_P(QuicPacketSchedulerTest, NoCloningWithOnlyD6DProbes) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
|
TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
ASSERT_FALSE(noopScheduler.hasData());
|
ASSERT_FALSE(noopScheduler.hasData());
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||||
EXPECT_FALSE(cloningScheduler.hasData());
|
EXPECT_FALSE(cloningScheduler.hasData());
|
||||||
@ -688,7 +687,7 @@ TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, DoNotCloneProcessedClonedPacket) {
|
TEST_F(QuicPacketSchedulerTest, DoNotCloneProcessedClonedPacket) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||||
// Add two outstanding packets, but then mark the second one processed by
|
// Add two outstanding packets, but then mark the second one processed by
|
||||||
// adding a PacketEvent that's missing from the outstandings.packetEvents set
|
// adding a PacketEvent that's missing from the outstandings.packetEvents set
|
||||||
@ -720,7 +719,7 @@ TEST_F(QuicPacketSchedulerTest, DoNotCloneProcessedClonedPacket) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasHandshakeData) {
|
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasHandshakeData) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||||
EXPECT_FALSE(cloningScheduler.hasData());
|
EXPECT_FALSE(cloningScheduler.hasData());
|
||||||
|
|
||||||
@ -731,7 +730,7 @@ TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasHandshakeData) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasInitialData) {
|
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasInitialData) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||||
EXPECT_FALSE(cloningScheduler.hasData());
|
EXPECT_FALSE(cloningScheduler.hasData());
|
||||||
|
|
||||||
@ -742,7 +741,7 @@ TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasInitialData) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasAppDataData) {
|
TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasAppDataData) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||||
EXPECT_FALSE(cloningScheduler.hasData());
|
EXPECT_FALSE(cloningScheduler.hasData());
|
||||||
|
|
||||||
@ -753,7 +752,7 @@ TEST_F(QuicPacketSchedulerTest, CloneSchedulerHasAppDataData) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, DoNotCloneHandshake) {
|
TEST_F(QuicPacketSchedulerTest, DoNotCloneHandshake) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "CopyCat", 0);
|
||||||
// Add two outstanding packets, with second one being handshake
|
// Add two outstanding packets, with second one being handshake
|
||||||
auto expected = addOutstandingPacket(conn);
|
auto expected = addOutstandingPacket(conn);
|
||||||
@ -781,7 +780,7 @@ TEST_F(QuicPacketSchedulerTest, DoNotCloneHandshake) {
|
|||||||
TEST_F(QuicPacketSchedulerTest, CloneSchedulerUseNormalSchedulerFirst) {
|
TEST_F(QuicPacketSchedulerTest, CloneSchedulerUseNormalSchedulerFirst) {
|
||||||
QuicClientConnectionState conn(
|
QuicClientConnectionState conn(
|
||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
NiceMock<MockFrameScheduler> mockScheduler;
|
NiceMock<MockFrameScheduler> mockScheduler(&conn);
|
||||||
CloningScheduler cloningScheduler(mockScheduler, conn, "Mocker", 0);
|
CloningScheduler cloningScheduler(mockScheduler, conn, "Mocker", 0);
|
||||||
ShortHeader header(
|
ShortHeader header(
|
||||||
ProtectionType::KeyPhaseOne,
|
ProtectionType::KeyPhaseOne,
|
||||||
@ -831,7 +830,7 @@ TEST_F(QuicPacketSchedulerTest, CloneWillGenerateNewWindowUpdate) {
|
|||||||
FizzClientQuicHandshakeContext::Builder().build());
|
FizzClientQuicHandshakeContext::Builder().build());
|
||||||
conn.streamManager->setMaxLocalBidirectionalStreams(10);
|
conn.streamManager->setMaxLocalBidirectionalStreams(10);
|
||||||
auto stream = conn.streamManager->createNextBidirectionalStream().value();
|
auto stream = conn.streamManager->createNextBidirectionalStream().value();
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "GiantsShoulder", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "GiantsShoulder", 0);
|
||||||
PacketEvent expectedPacketEvent(
|
PacketEvent expectedPacketEvent(
|
||||||
PacketNumberSpace::AppData, addOutstandingPacket(conn));
|
PacketNumberSpace::AppData, addOutstandingPacket(conn));
|
||||||
@ -917,7 +916,7 @@ TEST_F(QuicPacketSchedulerTest, CloningSchedulerWithInplaceBuilder) {
|
|||||||
bufAccessor.release(std::move(buf));
|
bufAccessor.release(std::move(buf));
|
||||||
conn.bufAccessor = &bufAccessor;
|
conn.bufAccessor = &bufAccessor;
|
||||||
|
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
ASSERT_FALSE(noopScheduler.hasData());
|
ASSERT_FALSE(noopScheduler.hasData());
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "93MillionMiles", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "93MillionMiles", 0);
|
||||||
auto packetNum = addOutstandingPacket(conn);
|
auto packetNum = addOutstandingPacket(conn);
|
||||||
@ -999,7 +998,7 @@ TEST_F(QuicPacketSchedulerTest, CloningSchedulerWithInplaceBuilderFullPacket) {
|
|||||||
buf->clear();
|
buf->clear();
|
||||||
bufAccessor.release(std::move(buf));
|
bufAccessor.release(std::move(buf));
|
||||||
|
|
||||||
FrameScheduler noopScheduler("noopScheduler");
|
FrameScheduler noopScheduler("noopScheduler", conn);
|
||||||
ASSERT_FALSE(noopScheduler.hasData());
|
ASSERT_FALSE(noopScheduler.hasData());
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "93MillionMiles", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "93MillionMiles", 0);
|
||||||
EXPECT_TRUE(cloningScheduler.hasData());
|
EXPECT_TRUE(cloningScheduler.hasData());
|
||||||
@ -1077,7 +1076,7 @@ TEST_F(QuicPacketSchedulerTest, CloneLargerThanOriginalPacket) {
|
|||||||
conn.udpSendPacketLen,
|
conn.udpSendPacketLen,
|
||||||
std::move(cloneHeader),
|
std::move(cloneHeader),
|
||||||
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
|
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
|
||||||
FrameScheduler noopScheduler("noopScheduler");
|
FrameScheduler noopScheduler("noopScheduler", conn);
|
||||||
CloningScheduler cloningScheduler(
|
CloningScheduler cloningScheduler(
|
||||||
noopScheduler, conn, "CopyCat", cipherOverhead);
|
noopScheduler, conn, "CopyCat", cipherOverhead);
|
||||||
auto cloneResult = cloningScheduler.scheduleFramesForPacket(
|
auto cloneResult = cloningScheduler.scheduleFramesForPacket(
|
||||||
@ -1547,7 +1546,7 @@ TEST_F(
|
|||||||
bufAccessor.release(std::move(buf));
|
bufAccessor.release(std::move(buf));
|
||||||
conn.bufAccessor = &bufAccessor;
|
conn.bufAccessor = &bufAccessor;
|
||||||
|
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
ASSERT_FALSE(noopScheduler.hasData());
|
ASSERT_FALSE(noopScheduler.hasData());
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "Little Hurry", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "Little Hurry", 0);
|
||||||
addOutstandingPacket(conn);
|
addOutstandingPacket(conn);
|
||||||
@ -1591,7 +1590,7 @@ TEST_F(
|
|||||||
bufAccessor.release(std::move(buf));
|
bufAccessor.release(std::move(buf));
|
||||||
conn.bufAccessor = &bufAccessor;
|
conn.bufAccessor = &bufAccessor;
|
||||||
|
|
||||||
FrameScheduler noopScheduler("frame");
|
FrameScheduler noopScheduler("frame", conn);
|
||||||
ASSERT_FALSE(noopScheduler.hasData());
|
ASSERT_FALSE(noopScheduler.hasData());
|
||||||
CloningScheduler cloningScheduler(noopScheduler, conn, "HotPot", 0);
|
CloningScheduler cloningScheduler(noopScheduler, conn, "HotPot", 0);
|
||||||
addOutstandingPacket(conn);
|
addOutstandingPacket(conn);
|
||||||
@ -2038,6 +2037,179 @@ TEST_F(QuicPacketSchedulerTest, DatagramFrameWriteWhenRoomAvailable) {
|
|||||||
ASSERT_EQ(frames.size(), 1);
|
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(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
QuicPacketSchedulerTests,
|
QuicPacketSchedulerTests,
|
||||||
QuicPacketSchedulerTest,
|
QuicPacketSchedulerTest,
|
||||||
|
@ -230,6 +230,10 @@ class LogQuicStats : public quic::QuicTransportStatsCallback {
|
|||||||
VLOG(2) << prefix_ << "onDatagramDroppedOnRead";
|
VLOG(2) << prefix_ << "onDatagramDroppedOnRead";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onShortHeaderPadding(size_t padSize) override {
|
||||||
|
VLOG(2) << prefix_ << "onShortHeaderPadding size=" << padSize;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string prefix_;
|
std::string prefix_;
|
||||||
};
|
};
|
||||||
|
@ -6,14 +6,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <quic/server/QuicServerTransport.h>
|
|
||||||
|
|
||||||
#include <quic/common/WindowedCounter.h>
|
#include <quic/common/WindowedCounter.h>
|
||||||
#include <quic/congestion_control/Bbr.h>
|
#include <quic/congestion_control/Bbr.h>
|
||||||
#include <quic/d6d/BinarySearchProbeSizeRaiser.h>
|
#include <quic/d6d/BinarySearchProbeSizeRaiser.h>
|
||||||
#include <quic/d6d/ConstantStepProbeSizeRaiser.h>
|
#include <quic/d6d/ConstantStepProbeSizeRaiser.h>
|
||||||
#include <quic/dsr/frontend/WriteFunctions.h>
|
#include <quic/dsr/frontend/WriteFunctions.h>
|
||||||
#include <quic/fizz/server/handshake/FizzServerQuicHandshakeContext.h>
|
#include <quic/fizz/server/handshake/FizzServerQuicHandshakeContext.h>
|
||||||
|
#include <quic/server/QuicServerTransport.h>
|
||||||
#include <quic/server/handshake/AppToken.h>
|
#include <quic/server/handshake/AppToken.h>
|
||||||
#include <quic/server/handshake/DefaultAppTokenValidator.h>
|
#include <quic/server/handshake/DefaultAppTokenValidator.h>
|
||||||
#include <quic/server/handshake/StatelessResetGenerator.h>
|
#include <quic/server/handshake/StatelessResetGenerator.h>
|
||||||
@ -854,6 +853,16 @@ void QuicServerTransport::registerAllTransportKnobParamHandlers() {
|
|||||||
server_conn->congestionController->type()));
|
server_conn->congestionController->type()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerTransportKnobParamHandler(
|
||||||
|
static_cast<uint64_t>(TransportKnobParamId::SHORT_HEADER_PADDING_KNOB),
|
||||||
|
[](QuicServerTransport* serverTransport, uint64_t val) {
|
||||||
|
CHECK(serverTransport);
|
||||||
|
serverTransport->serverConn_->transportSettings.paddingModulo = val;
|
||||||
|
VLOG(3) << fmt::format(
|
||||||
|
"SHORT_HEADER_PADDING_KNOB KnobParam received, setting paddingModulo={}",
|
||||||
|
val);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QuicConnectionStats QuicServerTransport::getConnectionsStats() const {
|
QuicConnectionStats QuicServerTransport::getConnectionsStats() const {
|
||||||
|
@ -182,6 +182,8 @@ class QuicTransportStatsCallback {
|
|||||||
|
|
||||||
virtual void onDatagramDroppedOnRead() = 0;
|
virtual void onDatagramDroppedOnRead() = 0;
|
||||||
|
|
||||||
|
virtual void onShortHeaderPadding(size_t padSize) = 0;
|
||||||
|
|
||||||
static const char* toString(PacketDropReason reason) {
|
static const char* toString(PacketDropReason reason) {
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case PacketDropReason::NONE:
|
case PacketDropReason::NONE:
|
||||||
|
@ -275,6 +275,14 @@ struct TransportSettings {
|
|||||||
// Whether to skip sending the ACK-only initial in response to crypto data in
|
// Whether to skip sending the ACK-only initial in response to crypto data in
|
||||||
// initial packet num space
|
// initial packet num space
|
||||||
bool skipInitPktNumSpaceCryptoAck{false};
|
bool skipInitPktNumSpaceCryptoAck{false};
|
||||||
|
// Whether to issue new tokens via NewToken frames.
|
||||||
|
bool issueNewTokens{false};
|
||||||
|
// Used to generate the number of frames to add to short header packets.
|
||||||
|
// Packets will have padding frames added such that the total space remaining
|
||||||
|
// in a packet is always an increment of paddingModulo, hiding the actual
|
||||||
|
// packet size from packet analysis.
|
||||||
|
// Padding Modulo of 0 turns off padding for short header packets.
|
||||||
|
size_t paddingModulo{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace quic
|
} // namespace quic
|
||||||
|
@ -67,6 +67,7 @@ class MockQuicStats : public QuicTransportStatsCallback {
|
|||||||
MOCK_METHOD0(onNewTokenReceived, void());
|
MOCK_METHOD0(onNewTokenReceived, void());
|
||||||
MOCK_METHOD0(onNewTokenIssued, void());
|
MOCK_METHOD0(onNewTokenIssued, void());
|
||||||
MOCK_METHOD0(onTokenDecryptFailure, void());
|
MOCK_METHOD0(onTokenDecryptFailure, void());
|
||||||
|
MOCK_METHOD1(onShortHeaderPadding, void(size_t));
|
||||||
};
|
};
|
||||||
|
|
||||||
class MockQuicStatsFactory : public QuicTransportStatsCallbackFactory {
|
class MockQuicStatsFactory : public QuicTransportStatsCallbackFactory {
|
||||||
|
Reference in New Issue
Block a user