Change IPv6 flow labels when QUIC connections have a retransmission timeout or when a new packet that creates a gap is received with a new flow lable.
PiperOrigin-RevId: 686570306
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 69dd796..8d36e98 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -992,6 +992,11 @@
level);
}
+ size_t ProcessDataPacketAtLevel(uint64_t number, bool has_stop_waiting,
+ EncryptionLevel level) {
+ return ProcessDataPacketAtLevel(number, has_stop_waiting, level, 0);
+ }
+
size_t ProcessCryptoPacketAtLevel(uint64_t number, EncryptionLevel level) {
QuicPacketHeader header = ConstructPacketHeader(number, level);
QuicFrames frames;
@@ -1019,7 +1024,7 @@
}
size_t ProcessDataPacketAtLevel(uint64_t number, bool has_stop_waiting,
- EncryptionLevel level) {
+ EncryptionLevel level, uint32_t flow_label) {
std::unique_ptr<QuicPacket> packet(
ConstructDataPacket(number, has_stop_waiting, level));
char buffer[kMaxOutgoingPacketSize];
@@ -1029,7 +1034,12 @@
buffer, kMaxOutgoingPacketSize);
connection_.ProcessUdpPacket(
kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
+ QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false,
+ 0 /* ttl */, true /* ttl_valid */,
+ nullptr /* packet_headers */, 0 /* headers_length */,
+ false /* owns_header_buffer */, ECN_NOT_ECT,
+ flow_label));
+
if (connection_.GetSendAlarm()->IsSet()) {
connection_.GetSendAlarm()->Fire();
}
@@ -9977,6 +9987,87 @@
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
}
+TEST_P(QuicConnectionTest, PtoChangesFlowLabel) {
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k1PTO);
+ connection_options.push_back(kPTOS);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ connection_.set_outgoing_flow_label(1);
+ connection_.EnableBlackholeAvoidanceViaFlowLabel();
+
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foooooo", 0, NO_FIN, &last_packet);
+ SendStreamDataToPeer(stream_id, "foooooo", 7, NO_FIN, &last_packet);
+ EXPECT_EQ(QuicPacketNumber(2), last_packet);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Fire PTO and verify the flow label has changed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_NE(1, connection_.outgoing_flow_label());
+}
+
+TEST_P(QuicConnectionTest, NewReceiveNewFlowLabelWithGapChangesFlowLabel) {
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k1PTO);
+ connection_options.push_back(kPTOS);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ connection_.EnableBlackholeAvoidanceViaFlowLabel();
+ const uint32_t flow_label = 1;
+ connection_.set_outgoing_flow_label(flow_label);
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+
+ // Receive the first packet to initialize the flow label.
+ ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL, 0);
+ EXPECT_EQ(1, connection_.outgoing_flow_label());
+
+ // Receive the second packet with the same flow label
+ ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL, flow_label);
+ EXPECT_EQ(1, connection_.outgoing_flow_label());
+
+ // Receive a packet with gap and a new flow label and verify the outgoing
+ // flow label has changed.
+ ProcessDataPacketAtLevel(4, !kHasStopWaiting, ENCRYPTION_INITIAL,
+ flow_label + 1);
+ EXPECT_NE(flow_label, connection_.outgoing_flow_label());
+}
+
+TEST_P(QuicConnectionTest,
+ NewReceiveNewFlowLabelWithNoGapDoesNotChangeFlowLabel) {
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k1PTO);
+ connection_options.push_back(kPTOS);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ connection_.EnableBlackholeAvoidanceViaFlowLabel();
+ const uint32_t flow_label = 1;
+ connection_.set_outgoing_flow_label(flow_label);
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+
+ // Receive the first packet to initialize the flow label.
+ ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL, 0);
+ EXPECT_EQ(1, connection_.outgoing_flow_label());
+
+ // Receive the second packet with the same flow label
+ ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL, flow_label);
+ EXPECT_EQ(1, connection_.outgoing_flow_label());
+
+ // Receive a packet with no gap and a new flow label and verify the outgoing
+ // flow label has not changed.
+ ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL, flow_label);
+ EXPECT_EQ(flow_label, connection_.outgoing_flow_label());
+}
+
TEST_P(QuicConnectionTest, SendCoalescedPackets) {
if (!connection_.version().CanSendCoalescedPackets()) {
return;