Allow QUIC connections to send and receive IPv6 flow labels. Protected by FLAGS_quic_reloadable_flag_quic_support_flow_label. PiperOrigin-RevId: 685910584
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc index 6ecfbd2..c3b99ae 100644 --- a/quiche/quic/core/http/end_to_end_test.cc +++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -7747,6 +7747,38 @@ server_thread_->Resume(); } +TEST_P(EndToEndTest, FlowLabelSend) { + SetQuicReloadableFlag(quic_support_flow_label, true); + ASSERT_TRUE(Initialize()); + + const uint32_t server_flow_label = 2; + quiche::QuicheNotification set; + server_thread_->Schedule([this, &set]() { + QuicConnection* server_connection = GetServerConnection(); + if (server_connection != nullptr) { + server_connection->set_outgoing_flow_label(server_flow_label); + } else { + ADD_FAILURE() << "Missing server connection"; + } + set.Notify(); + }); + set.WaitForNotification(); + + const uint32_t client_flow_label = 1; + QuicConnection* client_connection = GetClientConnection(); + client_connection->set_outgoing_flow_label(client_flow_label); + + client_->SendSynchronousRequest("/foo"); + + EXPECT_EQ(client_flow_label, client_connection->outgoing_flow_label()); + EXPECT_EQ(server_flow_label, client_connection->last_received_flow_label()); + + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + EXPECT_EQ(server_flow_label, server_connection->outgoing_flow_label()); + EXPECT_EQ(client_flow_label, server_connection->last_received_flow_label()); +} + TEST_P(EndToEndTest, ServerReportsNotEct) { // Client connects using not-ECT. SetQuicRestartFlag(quic_support_ect1, true);
diff --git a/quiche/quic/core/quic_coalesced_packet.cc b/quiche/quic/core/quic_coalesced_packet.cc index 94180f8..b9cea82 100644 --- a/quiche/quic/core/quic_coalesced_packet.cc +++ b/quiche/quic/core/quic_coalesced_packet.cc
@@ -14,7 +14,10 @@ namespace quic { QuicCoalescedPacket::QuicCoalescedPacket() - : length_(0), max_packet_length_(0), ecn_codepoint_(ECN_NOT_ECT) {} + : length_(0), + max_packet_length_(0), + ecn_codepoint_(ECN_NOT_ECT), + flow_label_(0) {} QuicCoalescedPacket::~QuicCoalescedPacket() { Clear(); } @@ -22,8 +25,8 @@ const SerializedPacket& packet, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, quiche::QuicheBufferAllocator* allocator, - QuicPacketLength current_max_packet_length, - QuicEcnCodepoint ecn_codepoint) { + QuicPacketLength current_max_packet_length, QuicEcnCodepoint ecn_codepoint, + uint32_t flow_label) { if (packet.encrypted_length == 0) { QUIC_BUG(quic_bug_10611_1) << "Trying to coalesce an empty packet"; return true; @@ -60,6 +63,10 @@ // Do not coalesce packets with different ECN codepoints. return false; } + if (flow_label != flow_label_) { + // Do not coalesce packets with different flow labels + return false; + } } if (length_ + packet.encrypted_length > max_packet_length_) { @@ -75,6 +82,7 @@ QUIC_CODE_COUNT(QUIC_SUCCESSFULLY_COALESCED_MULTIPLE_PACKETS); } ecn_codepoint_ = ecn_codepoint; + flow_label_ = flow_label; length_ += packet.encrypted_length; transmission_types_[packet.encryption_level] = packet.transmission_type; if (packet.encryption_level == ENCRYPTION_INITIAL) {
diff --git a/quiche/quic/core/quic_coalesced_packet.h b/quiche/quic/core/quic_coalesced_packet.h index 5f3a020..f209950 100644 --- a/quiche/quic/core/quic_coalesced_packet.h +++ b/quiche/quic/core/quic_coalesced_packet.h
@@ -27,7 +27,7 @@ const QuicSocketAddress& peer_address, quiche::QuicheBufferAllocator* allocator, QuicPacketLength current_max_packet_length, - QuicEcnCodepoint ecn_codepoint); + QuicEcnCodepoint ecn_codepoint, uint32_t flow_label); // Clears this coalesced packet. void Clear(); @@ -69,6 +69,8 @@ QuicEcnCodepoint ecn_codepoint() const { return ecn_codepoint_; } + uint32_t flow_label() const { return flow_label_; } + private: friend class test::QuicCoalescedPacketPeer; @@ -95,6 +97,9 @@ // A coalesced packet shares an ECN codepoint. QuicEcnCodepoint ecn_codepoint_; + + // A coalesced packet shares an single flow label. + uint32_t flow_label_; }; } // namespace quic
diff --git a/quiche/quic/core/quic_coalesced_packet_test.cc b/quiche/quic/core/quic_coalesced_packet_test.cc index 61d30f7..82e1f49 100644 --- a/quiche/quic/core/quic_coalesced_packet_test.cc +++ b/quiche/quic/core/quic_coalesced_packet_test.cc
@@ -33,7 +33,7 @@ packet1.retransmittable_frames.push_back( QuicFrame(QuicStreamFrame(1, true, 0, 100))); ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(PTO_RETRANSMISSION, coalesced.TransmissionTypeOfPacket(ENCRYPTION_INITIAL)); EXPECT_EQ(1500u, coalesced.max_packet_length()); @@ -48,7 +48,7 @@ SerializedPacket packet2(QuicPacketNumber(2), PACKET_4BYTE_PACKET_NUMBER, buffer, 500, false, false); EXPECT_FALSE(coalesced.MaybeCoalescePacket( - packet2, self_address, peer_address, &allocator, 1500, ECN_NOT_ECT)); + packet2, self_address, peer_address, &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(coalesced.ecn_codepoint(), ECN_NOT_ECT); SerializedPacket packet3(QuicPacketNumber(3), PACKET_4BYTE_PACKET_NUMBER, @@ -57,7 +57,7 @@ packet3.encryption_level = ENCRYPTION_ZERO_RTT; packet3.transmission_type = LOSS_RETRANSMISSION; ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet3, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(1500u, coalesced.max_packet_length()); EXPECT_EQ(1000u, coalesced.length()); EXPECT_EQ(2u, coalesced.NumberOfPackets()); @@ -75,14 +75,14 @@ // Cannot coalesce packet of changed self/peer address. EXPECT_FALSE(coalesced.MaybeCoalescePacket( packet4, QuicSocketAddress(QuicIpAddress::Loopback4(), 3), peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); // Packet does not fit. SerializedPacket packet5(QuicPacketNumber(5), PACKET_4BYTE_PACKET_NUMBER, buffer, 501, false, false); packet5.encryption_level = ENCRYPTION_FORWARD_SECURE; EXPECT_FALSE(coalesced.MaybeCoalescePacket( - packet5, self_address, peer_address, &allocator, 1500, ECN_NOT_ECT)); + packet5, self_address, peer_address, &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(1500u, coalesced.max_packet_length()); EXPECT_EQ(1000u, coalesced.length()); EXPECT_EQ(2u, coalesced.NumberOfPackets()); @@ -94,7 +94,7 @@ packet6.encryption_level = ENCRYPTION_FORWARD_SECURE; EXPECT_QUIC_BUG( coalesced.MaybeCoalescePacket(packet6, self_address, peer_address, - &allocator, 1000, ECN_NOT_ECT), + &allocator, 1000, ECN_NOT_ECT, 0), "Max packet length changes in the middle of the write path"); EXPECT_EQ(1500u, coalesced.max_packet_length()); EXPECT_EQ(1000u, coalesced.length()); @@ -119,9 +119,9 @@ packet2.encryption_level = ENCRYPTION_FORWARD_SECURE; ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet2, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(1000u, coalesced.length()); EXPECT_EQ(coalesced.ecn_codepoint(), ECN_NOT_ECT); @@ -161,7 +161,7 @@ packet1.retransmittable_frames.push_back( QuicFrame(QuicStreamFrame(1, true, 0, 100))); ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(PTO_RETRANSMISSION, coalesced.TransmissionTypeOfPacket(ENCRYPTION_INITIAL)); EXPECT_EQ(1500u, coalesced.max_packet_length()); @@ -179,7 +179,7 @@ // Coalesce initial packet again. ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); SerializedPacket packet2(QuicPacketNumber(3), PACKET_4BYTE_PACKET_NUMBER, buffer, 500, false, false); @@ -187,7 +187,7 @@ packet2.encryption_level = ENCRYPTION_ZERO_RTT; packet2.transmission_type = LOSS_RETRANSMISSION; ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet2, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(1500u, coalesced.max_packet_length()); EXPECT_EQ(1000u, coalesced.length()); EXPECT_EQ(LOSS_RETRANSMISSION, @@ -211,7 +211,7 @@ buffer, 501, false, false); packet3.encryption_level = ENCRYPTION_FORWARD_SECURE; EXPECT_TRUE(coalesced.MaybeCoalescePacket(packet3, self_address, peer_address, - &allocator, 1500, ECN_NOT_ECT)); + &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(1500u, coalesced.max_packet_length()); EXPECT_EQ(1001u, coalesced.length()); EXPECT_EQ(coalesced.ecn_codepoint(), ECN_NOT_ECT); @@ -240,7 +240,7 @@ packet1.retransmittable_frames.push_back( QuicFrame(QuicStreamFrame(1, true, 0, 100))); ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, - &allocator, 1500, ECN_ECT1)); + &allocator, 1500, ECN_ECT1, 0)); EXPECT_EQ(coalesced.ecn_codepoint(), ECN_ECT1); SerializedPacket packet2(QuicPacketNumber(2), PACKET_4BYTE_PACKET_NUMBER, @@ -249,7 +249,7 @@ packet2.encryption_level = ENCRYPTION_ZERO_RTT; packet2.transmission_type = LOSS_RETRANSMISSION; EXPECT_FALSE(coalesced.MaybeCoalescePacket( - packet2, self_address, peer_address, &allocator, 1500, ECN_NOT_ECT)); + packet2, self_address, peer_address, &allocator, 1500, ECN_NOT_ECT, 0)); EXPECT_EQ(coalesced.ecn_codepoint(), ECN_ECT1); }
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc index f069d85..9be867e 100644 --- a/quiche/quic/core/quic_connection.cc +++ b/quiche/quic/core/quic_connection.cc
@@ -2623,9 +2623,9 @@ if (debug_visitor_ != nullptr) { debug_visitor_->OnPacketReceived(self_address, peer_address, packet); } - last_received_packet_info_ = - ReceivedPacketInfo(self_address, peer_address, packet.receipt_time(), - packet.length(), packet.ecn_codepoint()); + last_received_packet_info_ = ReceivedPacketInfo( + self_address, peer_address, packet.receipt_time(), packet.length(), + packet.ecn_codepoint(), packet.ipv6_flow_label()); current_packet_data_ = packet.data(); if (!default_path_.self_address.IsInitialized()) { @@ -3053,7 +3053,7 @@ const BufferedPacket& packet = buffered_packets_.front(); WriteResult result = SendPacketToWriter( packet.data.get(), packet.length, packet.self_address.host(), - packet.peer_address, writer_, packet.ecn_codepoint); + packet.peer_address, writer_, packet.ecn_codepoint, packet.flow_label); QUIC_DVLOG(1) << ENDPOINT << "Sending buffered packet, result: " << result; if (IsMsgTooBig(writer_, result) && packet.length > long_term_mtu_) { // When MSG_TOO_BIG is returned, the system typically knows what the @@ -3396,7 +3396,7 @@ *packet, send_from_address, send_to_address, helper_->GetStreamSendBufferAllocator(), packet_creator_.max_packet_length(), - GetEcnCodepointToSend(send_to_address))) { + GetEcnCodepointToSend(send_to_address), outgoing_flow_label())) { // Failed to coalesce packet, flush current coalesced packet. if (!FlushCoalescedPacket()) { QUIC_BUG_IF(quic_connection_connected_after_flush_coalesced_failure, @@ -3410,7 +3410,8 @@ *packet, send_from_address, send_to_address, helper_->GetStreamSendBufferAllocator(), packet_creator_.max_packet_length(), - GetEcnCodepointToSend(send_to_address))) { + GetEcnCodepointToSend(send_to_address), + outgoing_flow_label())) { // Failed to coalesce packet even it is the only packet, raise a write // error. QUIC_DLOG(ERROR) << ENDPOINT << "Failed to coalesce packet"; @@ -3432,7 +3433,8 @@ << " to buffered packets"; last_ecn_codepoint_sent_ = GetEcnCodepointToSend(send_to_address); buffered_packets_.emplace_back(*packet, send_from_address, - send_to_address, last_ecn_codepoint_sent_); + send_to_address, last_ecn_codepoint_sent_, + last_flow_label_sent_); break; case SEND_TO_WRITER: // Stop using coalescer from now on. @@ -3447,7 +3449,8 @@ packet->release_encrypted_buffer = nullptr; result = SendPacketToWriter( packet->encrypted_buffer, encrypted_length, send_from_address.host(), - send_to_address, writer_, GetEcnCodepointToSend(send_to_address)); + send_to_address, writer_, GetEcnCodepointToSend(send_to_address), + outgoing_flow_label()); // This is a work around for an issue with linux UDP GSO batch writers. // When sending a GSO packet with 2 segments, if the first segment is // larger than the path MTU, instead of EMSGSIZE, the linux kernel returns @@ -3482,7 +3485,8 @@ QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number << " to buffered packets"; buffered_packets_.emplace_back(*packet, send_from_address, - send_to_address, last_ecn_codepoint_sent_); + send_to_address, last_ecn_codepoint_sent_, + last_flow_label_sent_); } } @@ -3898,7 +3902,7 @@ serialized_packet.encryption_level == ENCRYPTION_FORWARD_SECURE) { first_serialized_one_rtt_packet_ = std::make_unique<BufferedPacket>( serialized_packet, self_address(), peer_address(), - GetEcnCodepointToSend(peer_address())); + GetEcnCodepointToSend(peer_address()), outgoing_flow_label()); } SendOrQueuePacket(std::move(serialized_packet)); } @@ -4132,10 +4136,12 @@ WriteResult QuicConnection::SendPacketToWriter( const char* buffer, size_t buf_len, const QuicIpAddress& self_address, const QuicSocketAddress& destination_address, QuicPacketWriter* writer, - const QuicEcnCodepoint ecn_codepoint) { + const QuicEcnCodepoint ecn_codepoint, uint32_t flow_label) { QuicPacketWriterParams params = packet_writer_params_; params.ecn_codepoint = ecn_codepoint; last_ecn_codepoint_sent_ = ecn_codepoint; + last_flow_label_sent_ = flow_label; + params.flow_label = flow_label; WriteResult result = writer->WritePacket(buffer, buf_len, self_address, destination_address, per_packet_options_, params); @@ -4898,18 +4904,21 @@ QuicConnection::BufferedPacket::BufferedPacket( const SerializedPacket& packet, const QuicSocketAddress& self_address, - const QuicSocketAddress& peer_address, const QuicEcnCodepoint ecn_codepoint) + const QuicSocketAddress& peer_address, const QuicEcnCodepoint ecn_codepoint, + uint32_t flow_label) : BufferedPacket(packet.encrypted_buffer, packet.encrypted_length, - self_address, peer_address, ecn_codepoint) {} + self_address, peer_address, ecn_codepoint, flow_label) {} QuicConnection::BufferedPacket::BufferedPacket( const char* encrypted_buffer, QuicPacketLength encrypted_length, const QuicSocketAddress& self_address, - const QuicSocketAddress& peer_address, const QuicEcnCodepoint ecn_codepoint) + const QuicSocketAddress& peer_address, const QuicEcnCodepoint ecn_codepoint, + uint32_t flow_label) : length(encrypted_length), self_address(self_address), peer_address(peer_address), - ecn_codepoint(ecn_codepoint) { + ecn_codepoint(ecn_codepoint), + flow_label(flow_label) { data = std::make_unique<char[]>(encrypted_length); memcpy(data.get(), encrypted_buffer, encrypted_length); } @@ -4927,15 +4936,17 @@ QuicConnection::ReceivedPacketInfo::ReceivedPacketInfo(QuicTime receipt_time) : receipt_time(receipt_time) {} + QuicConnection::ReceivedPacketInfo::ReceivedPacketInfo( const QuicSocketAddress& destination_address, const QuicSocketAddress& source_address, QuicTime receipt_time, - QuicByteCount length, QuicEcnCodepoint ecn_codepoint) + QuicByteCount length, QuicEcnCodepoint ecn_codepoint, uint32_t flow_label) : destination_address(destination_address), source_address(source_address), receipt_time(receipt_time), length(length), - ecn_codepoint(ecn_codepoint) {} + ecn_codepoint(ecn_codepoint), + flow_label(flow_label) {} std::ostream& operator<<(std::ostream& os, const QuicConnection::ReceivedPacketInfo& info) { @@ -5089,7 +5100,8 @@ packet->encrypted_buffer, packet->encrypted_length)); WriteResult result = SendPacketToWriter( packet->encrypted_buffer, packet->encrypted_length, self_address.host(), - peer_address, writer, GetEcnCodepointToSend(peer_address)); + peer_address, writer, GetEcnCodepointToSend(peer_address), + outgoing_flow_label()); const uint32_t writer_batch_id = result.batch_id; @@ -5986,12 +5998,12 @@ buffered_packets_.emplace_back( buffer, static_cast<QuicPacketLength>(length), coalesced_packet_.self_address(), coalesced_packet_.peer_address(), - coalesced_packet_.ecn_codepoint()); + coalesced_packet_.ecn_codepoint(), coalesced_packet_.flow_label()); } else { WriteResult result = SendPacketToWriter( buffer, length, coalesced_packet_.self_address().host(), coalesced_packet_.peer_address(), writer_, - coalesced_packet_.ecn_codepoint()); + coalesced_packet_.ecn_codepoint(), coalesced_packet_.flow_label()); if (IsWriteError(result.status)) { OnWriteError(result.error_code); return false; @@ -6004,7 +6016,7 @@ buffered_packets_.emplace_back( buffer, static_cast<QuicPacketLength>(length), coalesced_packet_.self_address(), coalesced_packet_.peer_address(), - coalesced_packet_.ecn_codepoint()); + coalesced_packet_.ecn_codepoint(), coalesced_packet_.flow_label()); } } } @@ -6363,7 +6375,8 @@ buffered_packets_.emplace_back( first_serialized_one_rtt_packet_->data.get(), first_serialized_one_rtt_packet_->length, self_address(), - peer_address(), first_serialized_one_rtt_packet_->ecn_codepoint); + peer_address(), first_serialized_one_rtt_packet_->ecn_codepoint, + first_serialized_one_rtt_packet_->flow_label); packet_buffered = true; } break; @@ -7391,6 +7404,11 @@ << context.peer_address() << " after successful validation"; } +void QuicConnection::set_outgoing_flow_label(uint32_t flow_label) { + QUICHE_DCHECK(!packet_creator_.HasPendingFrames()); + outgoing_flow_label_ = flow_label; +} + bool QuicConnection::set_ecn_codepoint(QuicEcnCodepoint ecn_codepoint) { if (!GetQuicRestartFlag(quic_support_ect1)) { return false;
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h index 93b9689..61d783d 100644 --- a/quiche/quic/core/quic_connection.h +++ b/quiche/quic/core/quic_connection.h
@@ -1436,6 +1436,18 @@ return quic_limit_new_streams_per_loop_2_; } + void set_outgoing_flow_label(uint32_t flow_label); + + // Returns the flow label used for outgoing IPv6 packets, or 0 if no + // flow label will be sent. + uint32_t outgoing_flow_label() const { return outgoing_flow_label_; } + + // Returns the flow label received on the most recent packet, or 0 if no + // flow label was received. + uint32_t last_received_flow_label() const { + return last_received_packet_info_.flow_label; + } + void OnDiscardZeroRttDecryptionKeysAlarm() override; void OnIdleDetectorAlarm() override; void OnNetworkBlackholeDetectorAlarm() override; @@ -1631,12 +1643,12 @@ BufferedPacket(const SerializedPacket& packet, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, - QuicEcnCodepoint ecn_codepoint); + QuicEcnCodepoint ecn_codepoint, uint32_t flow_label); BufferedPacket(const char* encrypted_buffer, QuicPacketLength encrypted_length, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, - QuicEcnCodepoint ecn_codepoint); + QuicEcnCodepoint ecn_codepoint, uint32_t flow_label); // Please note, this buffered packet contains random bytes (and is not // *actually* a QUIC packet). BufferedPacket(QuicRandom& random, QuicPacketLength encrypted_length, @@ -1653,6 +1665,7 @@ const QuicSocketAddress self_address; const QuicSocketAddress peer_address; QuicEcnCodepoint ecn_codepoint = ECN_NOT_ECT; + uint32_t flow_label = 0; }; // ReceivedPacketInfo comprises the received packet information. @@ -1662,7 +1675,7 @@ ReceivedPacketInfo(const QuicSocketAddress& destination_address, const QuicSocketAddress& source_address, QuicTime receipt_time, QuicByteCount length, - QuicEcnCodepoint ecn_codepoint); + QuicEcnCodepoint ecn_codepoint, uint32_t flow_label); QuicSocketAddress destination_address; QuicSocketAddress source_address; @@ -1677,6 +1690,7 @@ QuicPacketHeader header; absl::InlinedVector<QuicFrameType, 1> frames; QuicEcnCodepoint ecn_codepoint = ECN_NOT_ECT; + uint32_t flow_label = 0; // Stores the actual address this packet is received on when it is received // on the preferred address. In this case, |destination_address| will // be overridden to the current default self address. @@ -2122,7 +2136,8 @@ const QuicIpAddress& self_address, const QuicSocketAddress& destination_address, QuicPacketWriter* writer, - const QuicEcnCodepoint ecn_codepoint); + const QuicEcnCodepoint ecn_codepoint, + uint32_t flow_label); bool PeerAddressChanged() const; @@ -2552,6 +2567,11 @@ // The ECN codepoint of the last packet to be sent to the writer, which // might be different from the next codepoint in per_packet_options_. QuicEcnCodepoint last_ecn_codepoint_sent_ = ECN_NOT_ECT; + // The flow label of the last packet to be sent to the writer, which + // might be different from the next flow label in per_packet_options_. + uint32_t last_flow_label_sent_ = 0; + // The flow label to be sent for outgoing packets. + uint32_t outgoing_flow_label_ = 0; // If true, the peer has indicated that it supports the RESET_STREAM_AT frame. bool reliable_stream_reset_ = false;
diff --git a/quiche/quic/core/quic_default_packet_writer.cc b/quiche/quic/core/quic_default_packet_writer.cc index 5b4bf27..8427726 100644 --- a/quiche/quic/core/quic_default_packet_writer.cc +++ b/quiche/quic/core/quic_default_packet_writer.cc
@@ -24,6 +24,9 @@ packet_info.SetPeerAddress(peer_address); packet_info.SetSelfIp(self_address); packet_info.SetEcnCodepoint(params.ecn_codepoint); + if (GetQuicReloadableFlag(quic_support_flow_label)) { + packet_info.SetFlowLabel(params.flow_label); + } WriteResult result = QuicUdpSocketApi().WritePacket(fd_, buffer, buf_len, packet_info); if (IsWriteBlockedStatus(result.status)) {
diff --git a/quiche/quic/core/quic_packet_creator_test.cc b/quiche/quic/core/quic_packet_creator_test.cc index 0575b88..849fcca 100644 --- a/quiche/quic/core/quic_packet_creator_test.cc +++ b/quiche/quic/core/quic_packet_creator_test.cc
@@ -2324,7 +2324,7 @@ frames_.clear(); ASSERT_TRUE(coalesced.MaybeCoalescePacket( serialized, self_address, peer_address, &allocator, - creator_.max_packet_length(), ECN_NOT_ECT)); + creator_.max_packet_length(), ECN_NOT_ECT, 0)); } char buffer[kMaxOutgoingPacketSize]; size_t coalesced_length = creator_.SerializeCoalescedPacket(
diff --git a/quiche/quic/core/quic_packet_reader.cc b/quiche/quic/core/quic_packet_reader.cc index 86062fd..4cf19a6 100644 --- a/quiche/quic/core/quic_packet_reader.cc +++ b/quiche/quic/core/quic_packet_reader.cc
@@ -55,6 +55,9 @@ QuicUdpPacketInfoBit::V6_SELF_IP, QuicUdpPacketInfoBit::RECV_TIMESTAMP, QuicUdpPacketInfoBit::TTL, QuicUdpPacketInfoBit::GOOGLE_PACKET_HEADER, QuicUdpPacketInfoBit::ECN}); + if (GetQuicReloadableFlag(quic_support_flow_label)) { + info_bits.Set(QuicUdpPacketInfoBit::V6_FLOW_LABEL); + } size_t packets_read = socket_api_.ReadMultiplePackets(fd, info_bits, &read_results_); for (size_t i = 0; i < packets_read; ++i) { @@ -94,11 +97,16 @@ } else { QUIC_CODE_COUNT(quic_packet_reader_no_google_packet_header); } + uint32_t flow_label = 0; + if (result.packet_info.HasValue(QuicUdpPacketInfoBit::V6_FLOW_LABEL)) { + flow_label = result.packet_info.flow_label(); + } QuicReceivedPacket packet( result.packet_buffer.buffer, result.packet_buffer.buffer_len, now, /*owns_buffer=*/false, ttl, has_ttl, headers, headers_length, - /*owns_header_buffer=*/false, result.packet_info.ecn_codepoint()); + /*owns_header_buffer=*/false, result.packet_info.ecn_codepoint(), + flow_label); QuicSocketAddress self_address(self_ip, port); processor->ProcessPacket(self_address, peer_address, packet); }
diff --git a/quiche/quic/core/quic_packets.cc b/quiche/quic/core/quic_packets.cc index 26c59f0..40ec9a2 100644 --- a/quiche/quic/core/quic_packets.cc +++ b/quiche/quic/core/quic_packets.cc
@@ -355,13 +355,24 @@ const char* buffer, size_t length, QuicTime receipt_time, bool owns_buffer, int ttl, bool ttl_valid, char* packet_headers, size_t headers_length, bool owns_header_buffer, QuicEcnCodepoint ecn_codepoint) + : quic::QuicReceivedPacket(buffer, length, receipt_time, owns_buffer, ttl, + ttl_valid, packet_headers, headers_length, + owns_header_buffer, ecn_codepoint, + /*ipv6_flow_label=*/0) {} + +QuicReceivedPacket::QuicReceivedPacket( + const char* buffer, size_t length, QuicTime receipt_time, bool owns_buffer, + int ttl, bool ttl_valid, char* packet_headers, size_t headers_length, + bool owns_header_buffer, QuicEcnCodepoint ecn_codepoint, + uint32_t ipv6_flow_label) : QuicEncryptedPacket(buffer, length, owns_buffer), receipt_time_(receipt_time), ttl_(ttl_valid ? ttl : -1), packet_headers_(packet_headers), headers_length_(headers_length), owns_header_buffer_(owns_header_buffer), - ecn_codepoint_(ecn_codepoint) {} + ecn_codepoint_(ecn_codepoint), + ipv6_flow_label_(ipv6_flow_label) {} QuicReceivedPacket::~QuicReceivedPacket() { if (owns_header_buffer_) {
diff --git a/quiche/quic/core/quic_packets.h b/quiche/quic/core/quic_packets.h index 2a26a7b..605ed4c 100644 --- a/quiche/quic/core/quic_packets.h +++ b/quiche/quic/core/quic_packets.h
@@ -301,6 +301,11 @@ bool owns_buffer, int ttl, bool ttl_valid, char* packet_headers, size_t headers_length, bool owns_header_buffer, QuicEcnCodepoint ecn_codepoint); + QuicReceivedPacket(const char* buffer, size_t length, QuicTime receipt_time, + bool owns_buffer, int ttl, bool ttl_valid, + char* packet_headers, size_t headers_length, + bool owns_header_buffer, QuicEcnCodepoint ecn_codepoint, + uint32_t ipv6_flow_label); ~QuicReceivedPacket(); QuicReceivedPacket(const QuicReceivedPacket&) = delete; QuicReceivedPacket& operator=(const QuicReceivedPacket&) = delete; @@ -320,6 +325,11 @@ // Length of packet headers. int headers_length() const { return headers_length_; } + QuicEcnCodepoint ecn_codepoint() const { return ecn_codepoint_; } + + // Returns the IPv6 flow label in host byte order if present, or 0 otherwise. + uint32_t ipv6_flow_label() const { return ipv6_flow_label_; } + // By default, gtest prints the raw bytes of an object. The bool data // member (in the base class QuicData) causes this object to have padding // bytes, which causes the default gtest object printer to read @@ -327,8 +337,6 @@ QUICHE_EXPORT friend std::ostream& operator<<(std::ostream& os, const QuicReceivedPacket& s); - QuicEcnCodepoint ecn_codepoint() const { return ecn_codepoint_; } - private: friend class test::QuicReceivedPacketPeer; @@ -341,6 +349,8 @@ // Whether owns the buffer for packet headers. bool owns_header_buffer_; QuicEcnCodepoint ecn_codepoint_; + // IPv6 flow label. + uint32_t ipv6_flow_label_; }; // SerializedPacket contains information of a serialized(encrypted) packet.
diff --git a/quiche/quic/core/quic_packets_test.cc b/quiche/quic/core/quic_packets_test.cc index 4b64be2..3c77628 100644 --- a/quiche/quic/core/quic_packets_test.cc +++ b/quiche/quic/core/quic_packets_test.cc
@@ -130,6 +130,22 @@ EXPECT_EQ(packet.ecn_codepoint(), copy->ecn_codepoint()); } +TEST_F(QuicPacketsTest, NoFlowLabelByDefault) { + char header[4] = "bar"; + QuicReceivedPacket packet("foo", 3, QuicTime::Zero(), false, 0, true, header, + sizeof(header) - 1, false, + QuicEcnCodepoint::ECN_ECT1); + EXPECT_EQ(0, packet.ipv6_flow_label()); +} + +TEST_F(QuicPacketsTest, ExplicitFlowLabel) { + char header[4] = "bar"; + QuicReceivedPacket packet("foo", 3, QuicTime::Zero(), false, 0, true, header, + sizeof(header) - 1, false, + QuicEcnCodepoint::ECN_ECT1, 42); + EXPECT_EQ(42, packet.ipv6_flow_label()); +} + } // namespace } // namespace test } // namespace quic