Skip to content

Commit

Permalink
Cache the negotiated config for ACKs once the transport parameters ar…
Browse files Browse the repository at this point in the history
…e received

Summary: Cache the negotiated config for what ACK type to write and which fields to use once the peer transport parameters are available. This avoids computing the config with every ack frame being written.

Reviewed By: sharmafb

Differential Revision: D70004436

fbshipit-source-id: 79354f5137c77353c3a97d4c41782a700622e986
  • Loading branch information
jbeshay authored and facebook-github-bot committed Feb 24, 2025
1 parent c6d8f76 commit 7f65f36
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 23 deletions.
26 changes: 3 additions & 23 deletions quic/api/QuicAckScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,13 @@ Optional<PacketNum> AckScheduler::writeNextAcks(

Optional<WriteAckFrameResult> ackWriteResult;

bool isAckReceiveTimestampsSupported =
conn_.transportSettings.maybeAckReceiveTimestampsConfigSentToPeer &&
conn_.maybePeerAckReceiveTimestampsConfig;

uint64_t peerRequestedTimestampsCount =
conn_.maybePeerAckReceiveTimestampsConfig.has_value()
? conn_.maybePeerAckReceiveTimestampsConfig.value()
.maxReceiveTimestampsPerAck
: 0;

uint64_t extendedAckSupportedAndEnabled =
conn_.peerAdvertisedExtendedAckFeatures &
conn_.transportSettings.enableExtendedAckFeatures;
// Disable the ECN fields if we are not reading them
if (!conn_.transportSettings.readEcnOnIngress) {
extendedAckSupportedAndEnabled &= ~static_cast<ExtendedAckFeatureMaskType>(
ExtendedAckFeatureMask::ECN_COUNTS);
}
// Disable the receive timestamps fields if we have not regoatiated receive
// timestamps support
if (!isAckReceiveTimestampsSupported || (peerRequestedTimestampsCount == 0)) {
extendedAckSupportedAndEnabled &= ~static_cast<ExtendedAckFeatureMaskType>(
ExtendedAckFeatureMask::RECEIVE_TIMESTAMPS);
}

if (extendedAckSupportedAndEnabled > 0) {
if (conn_.negotiatedExtendedAckFeatures > 0) {
// The peer supports extended ACKs and we have them enabled.
ackWriteResult = writeAckFrame(
meta,
Expand All @@ -97,7 +78,7 @@ Optional<PacketNum> AckScheduler::writeNextAcks(
conn_.transportSettings.maybeAckReceiveTimestampsConfigSentToPeer
.value_or(AckReceiveTimestampsConfig()),
peerRequestedTimestampsCount,
extendedAckSupportedAndEnabled);
conn_.negotiatedExtendedAckFeatures);
} else if (
conn_.transportSettings.readEcnOnIngress &&
(meta.ackState.ecnECT0CountReceived ||
Expand All @@ -107,8 +88,7 @@ Optional<PacketNum> AckScheduler::writeNextAcks(
// frame. In this case, we give ACK_ECN precedence over
// ACK_RECEIVE_TIMESTAMPS.
ackWriteResult = writeAckFrame(meta, builder, FrameType::ACK_ECN);
} else if (
isAckReceiveTimestampsSupported && (peerRequestedTimestampsCount > 0)) {
} else if (conn_.negotiatedAckReceiveTimestampSupport) {
// Use ACK_RECEIVE_TIMESTAMPS if its enabled on both endpoints AND the
// peer requests at least 1 timestamp
ackWriteResult = writeAckFrame(
Expand Down
31 changes: 31 additions & 0 deletions quic/api/QuicTransportFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2131,4 +2131,35 @@ void maybeScheduleAckForCongestionFeedback(
}
}

void updateNegotiatedAckFeatures(QuicConnectionStateBase& conn) {
bool isAckReceiveTimestampsSupported =
conn.transportSettings.maybeAckReceiveTimestampsConfigSentToPeer &&
conn.maybePeerAckReceiveTimestampsConfig;

uint64_t peerRequestedTimestampsCount =
conn.maybePeerAckReceiveTimestampsConfig.has_value()
? conn.maybePeerAckReceiveTimestampsConfig.value()
.maxReceiveTimestampsPerAck
: 0;

conn.negotiatedAckReceiveTimestampSupport =
isAckReceiveTimestampsSupported && (peerRequestedTimestampsCount > 0);

conn.negotiatedExtendedAckFeatures = conn.peerAdvertisedExtendedAckFeatures &
conn.transportSettings.enableExtendedAckFeatures;
// Disable the ECN fields if we are not reading them
if (!conn.transportSettings.readEcnOnIngress) {
conn.negotiatedExtendedAckFeatures &=
~static_cast<ExtendedAckFeatureMaskType>(
ExtendedAckFeatureMask::ECN_COUNTS);
}
// Disable the receive timestamps fields if we have not regoatiated receive
// timestamps support
if (!conn.negotiatedAckReceiveTimestampSupport) {
conn.negotiatedExtendedAckFeatures &=
~static_cast<ExtendedAckFeatureMaskType>(
ExtendedAckFeatureMask::RECEIVE_TIMESTAMPS);
}
}

} // namespace quic
1 change: 1 addition & 0 deletions quic/api/QuicTransportFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,4 +345,5 @@ void maybeAddPacketMark(
void maybeScheduleAckForCongestionFeedback(
const ReceivedUdpPacket& receivedPacket,
AckState& ackState);
void updateNegotiatedAckFeatures(QuicConnectionStateBase& conn);
} // namespace quic
12 changes: 12 additions & 0 deletions quic/api/test/QuicPacketSchedulerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2816,6 +2816,7 @@ TEST_F(QuicAckSchedulerTest, WriteAckReceiveTimestampsWhenEnabled) {
conn_->transportSettings.maybeAckReceiveTimestampsConfigSentToPeer =
AckReceiveTimestampsConfig();

updateNegotiatedAckFeatures(*conn_);
AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());

Expand Down Expand Up @@ -2874,6 +2875,7 @@ TEST_F(QuicAckSchedulerTest, AckExtendedNotSentIfNotSupported) {
conn_->transportSettings.enableExtendedAckFeatures =
3; // ECN + ReceiveTimestamps
conn_->peerAdvertisedExtendedAckFeatures = 0;
updateNegotiatedAckFeatures(*conn_);

AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());
Expand Down Expand Up @@ -2902,6 +2904,7 @@ TEST_F(QuicAckSchedulerTest, AckExtendedNotSentIfNotEnabled) {

conn_->transportSettings.enableExtendedAckFeatures = 0;
conn_->peerAdvertisedExtendedAckFeatures = 3; // ECN + ReceiveTimestamps;
updateNegotiatedAckFeatures(*conn_);

AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());
Expand Down Expand Up @@ -2938,6 +2941,7 @@ TEST_F(
conn_->maybePeerAckReceiveTimestampsConfig = AckReceiveTimestampsConfig();
// We don't have an ART config (i.e. we can't sent ART)
conn_->transportSettings.maybeAckReceiveTimestampsConfigSentToPeer = none;
updateNegotiatedAckFeatures(*conn_);

AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());
Expand Down Expand Up @@ -2972,6 +2976,8 @@ TEST_F(QuicAckSchedulerTest, AckExtendedNotSentIfECNFeatureNotSupported) {
conn_->transportSettings.maybeAckReceiveTimestampsConfigSentToPeer =
AckReceiveTimestampsConfig();

updateNegotiatedAckFeatures(*conn_);

AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());

Expand Down Expand Up @@ -3009,6 +3015,8 @@ TEST_F(QuicAckSchedulerTest, AckExtendedWithAllFeatures) {
// We can read ECN
conn_->transportSettings.readEcnOnIngress = true;

updateNegotiatedAckFeatures(*conn_);

AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());

Expand Down Expand Up @@ -3046,6 +3054,8 @@ TEST_F(QuicAckSchedulerTest, AckExtendedTakesPrecedenceOverECN) {
// We can read ECN
conn_->transportSettings.readEcnOnIngress = true;

updateNegotiatedAckFeatures(*conn_);

AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());

Expand Down Expand Up @@ -3083,6 +3093,8 @@ TEST_F(QuicAckSchedulerTest, AckExtendedTakesPrecedenceOverReceiveTimestamps) {
// We can read ECN
conn_->transportSettings.readEcnOnIngress = true;

updateNegotiatedAckFeatures(*conn_);

AckScheduler ackScheduler(*conn_, ackState_);
ASSERT_TRUE(ackScheduler.hasPendingAcks());

Expand Down
2 changes: 2 additions & 0 deletions quic/client/QuicClientTransportLite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,8 @@ void QuicClientTransportLite::processUdpPacketData(
}
}
}
updateNegotiatedAckFeatures(*conn_);

// TODO This sucks, but manually update the max packet size until we fix
// 0-rtt transport parameters.
if (conn_->transportSettings.canIgnorePathMTU &&
Expand Down
1 change: 1 addition & 0 deletions quic/server/state/ServerStateMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ void updateHandshakeState(QuicServerConnectionState& conn) {
TransportErrorCode::TRANSPORT_PARAMETER_ERROR);
}
processClientInitialParams(conn, std::move(*clientParams));
updateNegotiatedAckFeatures(conn);
}
if (oneRttReadCipher) {
if (conn.qLogger) {
Expand Down
6 changes: 6 additions & 0 deletions quic/state/StateData.h
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@ struct QuicConnectionStateBase : public folly::DelayedDestruction {
bool peerAdvertisedKnobFrameSupport{false};

ExtendedAckFeatureMaskType peerAdvertisedExtendedAckFeatures{0};

// Negotiated ACK related config. These don't change throughout the connection
// so cache them once we've receive the relevant transport parameters.
bool negotiatedAckReceiveTimestampSupport{false};
ExtendedAckFeatureMaskType negotiatedExtendedAckFeatures{0};

// Retransmission policies map.
folly::F14FastMap<StreamGroupId, QuicStreamGroupRetransmissionPolicy>
retransmissionPolicies;
Expand Down

0 comments on commit 7f65f36

Please sign in to comment.