Add transport knob to enforce udp payload size
Summary: Adds another knob param to enforce udp payload size. This is basically a "canIgnorePathMTU" knob that client has.
MODIFY
quic/QuicConstants.h
quic/QuicConstants.h
@@ -115,8 +115,13 @@ constexpr uint64_t kDefaultQuicTransportKnobSpace = 0xfaceb001;
// Default knob id for transport knobs
constexpr uint64_t kDefaultQuicTransportKnobId = 1;
-// Default transport knob param id for disabling pmtu blackhole detection
-constexpr uint64_t kTransportKnobParamIdZeroBlackholeDetection = 0x8830;
+enum class TransportKnobParamId : uint64_t {
+ // Disabling pmtu blackhole detection
+ ZERO_PMTU_BLACKHOLE_DETECTION = 0x8830,
+ // Force udp payload size to be equal to max
+ // udp payload size
+ FORCIBLY_SET_UDP_PAYLOAD_SIZE = 0xba92,
+};
enum class FrameType : uint64_t {
PADDING = 0x00,

MODIFY
quic/server/QuicServerTransport.cpp
quic/server/QuicServerTransport.cpp
@@ -592,7 +592,8 @@ void QuicServerTransport::onTransportKnobs(Buf knobBlob) {
void QuicServerTransport::registerAllTransportKnobParamHandlers() {
registerTransportKnobParamHandler(
- kTransportKnobParamIdZeroBlackholeDetection,
+ static_cast<uint64_t>(
+ TransportKnobParamId::ZERO_PMTU_BLACKHOLE_DETECTION),
[](QuicServerConnectionState* server_conn, uint64_t val) {
CHECK(server_conn);
if (static_cast<bool>(val)) {
@@ -601,6 +602,18 @@ void QuicServerTransport::registerAllTransportKnobParamHandlers() {
<< "Knob param received, pmtu blackhole detection is turned off";
}
});
+
+ registerTransportKnobParamHandler(
+ static_cast<uint64_t>(
+ TransportKnobParamId::FORCIBLY_SET_UDP_PAYLOAD_SIZE),
+ [](QuicServerConnectionState* server_conn, uint64_t val) {
+ CHECK(server_conn);
+ if (static_cast<bool>(val)) {
+ server_conn->udpSendPacketLen = server_conn->peerMaxUdpPayloadSize;
+ LOG(INFO)
+ << "Knob param received, udpSendPacketLen is forcibly set to max UDP payload size advertised by peer";
+ }
+ });
}
} // namespace quic

MODIFY
quic/server/state/ServerStateMachine.cpp
quic/server/state/ServerStateMachine.cpp
@@ -192,6 +192,7 @@ void processClientInitialParams(
uint64_t maxUdpPayloadSize = kDefaultMaxUDPPayload;
if (packetSize) {
maxUdpPayloadSize = std::min(*packetSize, maxUdpPayloadSize);
+ conn.peerMaxUdpPayloadSize = maxUdpPayloadSize;
if (conn.transportSettings.canIgnorePathMTU) {
if (*packetSize > kDefaultMaxUDPPayload) {
// A good peer should never set oversized limit, so to be safe we

MODIFY
quic/server/test/QuicServerTransportTest.cpp
quic/server/test/QuicServerTransportTest.cpp
@@ -333,7 +333,8 @@ class QuicServerTransportTest : public Test {
server->getNonConstConn().handshakeLayer.reset(fakeHandshake);
server->getNonConstConn().serverHandshakeLayer = fakeHandshake;
// Allow ignoring path mtu for testing negotiation.
- server->getNonConstConn().transportSettings.canIgnorePathMTU = true;
+ server->getNonConstConn().transportSettings.canIgnorePathMTU =
+ getCanIgnorePathMTU();
server->getNonConstConn().transportSettings.disableMigration =
getDisableMigration();
server->setConnectionIdAlgo(connIdAlgo_.get());
@@ -372,6 +373,10 @@ class QuicServerTransportTest : public Test {
return true;
}
+ virtual bool getCanIgnorePathMTU() {
+ return true;
+ }
+
std::unique_ptr<Aead> getInitialCipher(
QuicVersion version = QuicVersion::MVFST) {
FizzCryptoFactory cryptoFactory;
@@ -584,9 +589,11 @@ class QuicServerTransportTest : public Test {
void verifyTransportParameters(std::chrono::milliseconds idleTimeout) {
EXPECT_EQ(server->getConn().peerIdleTimeout, idleTimeout);
+ if (getCanIgnorePathMTU()) {
EXPECT_EQ(
server->getConn().udpSendPacketLen, fakeHandshake->maxRecvPacketSize);
}
+ }
void deliverDataWithoutErrorCheck(
Buf data,
@@ -4290,8 +4297,31 @@ TEST_F(QuicServerTransportTest, TestRegisterAndHandleTransportKnobParams) {
}
TEST_F(QuicServerTransportTest, TestRegisterPMTUZeroBlackholeDetection) {
- server->handleKnobParams({{kTransportKnobParamIdZeroBlackholeDetection, 1}});
+ server->handleKnobParams(
+ {{static_cast<uint64_t>(
+ TransportKnobParamId::ZERO_PMTU_BLACKHOLE_DETECTION),
+ 1}});
EXPECT_TRUE(server->getConn().d6d.noBlackholeDetection);
}
+
+class QuicServerTransportForciblySetUDUPayloadSizeTest
+ : public QuicServerTransportTest {
+ public:
+ bool getCanIgnorePathMTU() override {
+ return false;
+ }
+};
+
+TEST_F(
+ QuicServerTransportForciblySetUDUPayloadSizeTest,
+ TestHandleTransportKnobParamForciblySetUDPPayloadSize) {
+ EXPECT_LT(server->getConn().udpSendPacketLen, 1452);
+ server->handleKnobParams(
+ {{static_cast<uint64_t>(
+ TransportKnobParamId::FORCIBLY_SET_UDP_PAYLOAD_SIZE),
+ 1}});
+ EXPECT_EQ(server->getConn().udpSendPacketLen, 1452);
+}
+
} // namespace test
} // namespace quic

MODIFY
quic/state/StateData.h
quic/state/StateData.h
@@ -716,6 +716,10 @@ struct QuicConnectionStateBase : public folly::DelayedDestruction {
// max_packet_size in Transport Parameters and PMTU
uint64_t udpSendPacketLen{kDefaultUDPSendPacketLen};
+ // Peer-advertised max UDP payload size, stored as an opportunistic value to
+ // use when receiving the forciblySetUdpPayloadSize transport knob param
+ uint64_t peerMaxUdpPayloadSize{kDefaultUDPSendPacketLen};
+
struct PacketSchedulingState {
StreamId nextScheduledStream{0};
StreamId nextScheduledControlStream{0};

Add transport knob to enforce udp payload size

Summary: Adds another knob param to enforce udp payload size. This is basically a "canIgnorePathMTU" knob that client has.

Reviewed By: mjoras

Differential Revision: D24586165

fbshipit-source-id: befb265a24fae8f450f323cf2d652a8b448e698c