Add new metrics to measure throughput in QBONE. Historically, QBONE relies on metrics exported by the GFE and QUIC to measure throughput in bytes and packets: * `/gfe/gfe2/http/bytes_in` for throughput in bytes to prod. * `/gfe/gfe2/http/bytes_out` for throughput in bytes from prod. * `/gfe/gfe2/spdy4_over_quic/packets_quic_read` for throughput in packets to prod. * `/gfe/gfe2/spdy4_over_quic/connection_packet_writer_total_packets_sent` for throughput in packets from prod. The initial motivation for this CL was to add a `traffic_class` dimension to the above methods, but as that involved modified non-QBONE code I decided to implement new QBONE-specific metrics. Each of the metrics in this CL have two dimensions: * `direction`: TO_PROD or FROM_PROD * `traffic_class`: A string that represents the traffic class of the packets. A follow up CL will change the dashboard to use these metrics instead of the old ones once this is fully rolled out. PiperOrigin-RevId: 620055645
diff --git a/quiche/quic/qbone/qbone_packet_processor.cc b/quiche/quic/qbone/qbone_packet_processor.cc index 7fdfd0f..a4464d4 100644 --- a/quiche/quic/qbone/qbone_packet_processor.cc +++ b/quiche/quic/qbone/qbone_packet_processor.cc
@@ -77,6 +77,8 @@ return; } + stats_->RecordThroughput(packet->size(), direction, traffic_class); + uint8_t transport_protocol; char* transport_data; icmp6_hdr icmp_header;
diff --git a/quiche/quic/qbone/qbone_packet_processor.h b/quiche/quic/qbone/qbone_packet_processor.h index b337b19..e69e09a 100644 --- a/quiche/quic/qbone/qbone_packet_processor.h +++ b/quiche/quic/qbone/qbone_packet_processor.h
@@ -9,6 +9,7 @@ #include <netinet/in.h> #include <netinet/ip6.h> +#include <cstddef> #include <cstdint> #include "absl/strings/string_view.h" @@ -61,6 +62,9 @@ virtual void SendPacketToNetwork(absl::string_view packet) = 0; }; + // A visitor interface that allows the packet processor to collect stats + // without relying on a specific backend or exposing the entire packet. + // |traffic_class| should be extracted directly from the IPv6 header. class StatsInterface { public: virtual ~StatsInterface(); @@ -75,6 +79,8 @@ uint8_t traffic_class) = 0; virtual void OnPacketDeferred(Direction direction, uint8_t traffic_class) = 0; + virtual void RecordThroughput(size_t bytes, Direction direction, + uint8_t traffic_class) = 0; }; // Allows to implement a custom packet filter on top of the filtering done by
diff --git a/quiche/quic/qbone/qbone_packet_processor_test.cc b/quiche/quic/qbone/qbone_packet_processor_test.cc index f3361b7..cbb63ed 100644 --- a/quiche/quic/qbone/qbone_packet_processor_test.cc +++ b/quiche/quic/qbone/qbone_packet_processor_test.cc
@@ -333,6 +333,9 @@ processor_ = std::make_unique<QbonePacketProcessor>( self_ip_, client_ip_, /*client_ip_subnet_length=*/62, &output_, &stats_); + + // Ignore calls to RecordThroughput + EXPECT_CALL(stats_, RecordThroughput(_, _, _)).WillRepeatedly(Return()); } void SendPacketFromClient(absl::string_view packet) { @@ -356,9 +359,11 @@ TEST_F(QbonePacketProcessorTest, EmptyPacket) { EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK, _)); + EXPECT_CALL(stats_, RecordThroughput(0, Direction::FROM_OFF_NETWORK, _)); SendPacketFromClient(""); EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_NETWORK, _)); + EXPECT_CALL(stats_, RecordThroughput(0, Direction::FROM_NETWORK, _)); SendPacketFromNetwork(""); } @@ -476,21 +481,29 @@ TEST_F(QbonePacketProcessorTest, FilterHelperFunctionsTOS) { auto filter_owned = std::make_unique<TestFilter>(client_ip_, network_ip_); - TestFilter* filter = filter_owned.get(); processor_->set_filter(std::move(filter_owned)); EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK, _)) .Times(testing::AnyNumber()); + EXPECT_CALL(stats_, RecordThroughput(kReferenceClientPacket.size(), + Direction::FROM_OFF_NETWORK, 0)); SendPacketFromClient(kReferenceClientPacket); - ASSERT_EQ(0, filter->last_tos()); + + EXPECT_CALL(stats_, RecordThroughput(kReferenceClientPacketAF4.size(), + Direction::FROM_OFF_NETWORK, 0x80)); SendPacketFromClient(kReferenceClientPacketAF4); - ASSERT_EQ(0x80, filter->last_tos()); + + EXPECT_CALL(stats_, RecordThroughput(kReferenceClientPacketAF3.size(), + Direction::FROM_OFF_NETWORK, 0x60)); SendPacketFromClient(kReferenceClientPacketAF3); - ASSERT_EQ(0x60, filter->last_tos()); + + EXPECT_CALL(stats_, RecordThroughput(kReferenceClientPacketAF2.size(), + Direction::FROM_OFF_NETWORK, 0x40)); SendPacketFromClient(kReferenceClientPacketAF2); - ASSERT_EQ(0x40, filter->last_tos()); + + EXPECT_CALL(stats_, RecordThroughput(kReferenceClientPacketAF1.size(), + Direction::FROM_OFF_NETWORK, 0x20)); SendPacketFromClient(kReferenceClientPacketAF1); - ASSERT_EQ(0x20, filter->last_tos()); } TEST_F(QbonePacketProcessorTest, Icmp6EchoResponseHasRightPayload) {
diff --git a/quiche/quic/qbone/qbone_packet_processor_test_tools.h b/quiche/quic/qbone/qbone_packet_processor_test_tools.h index 9b0ff85..619d5ef 100644 --- a/quiche/quic/qbone/qbone_packet_processor_test_tools.h +++ b/quiche/quic/qbone/qbone_packet_processor_test_tools.h
@@ -35,6 +35,8 @@ (QbonePacketProcessor::Direction, uint8_t), (override)); MOCK_METHOD(void, OnPacketDeferred, (QbonePacketProcessor::Direction, uint8_t), (override)); + MOCK_METHOD(void, RecordThroughput, + (size_t, QbonePacketProcessor::Direction, uint8_t), (override)); }; std::string PrependIPv6HeaderForTest(const std::string& body, int hops);
diff --git a/quiche/quic/qbone/qbone_server_session.h b/quiche/quic/qbone/qbone_server_session.h index 0f325a6..74abad4 100644 --- a/quiche/quic/qbone/qbone_server_session.h +++ b/quiche/quic/qbone/qbone_server_session.h
@@ -71,6 +71,8 @@ uint8_t traffic_class) override {} void OnPacketDeferred(QbonePacketProcessor::Direction direction, uint8_t traffic_class) override {} + void RecordThroughput(size_t bytes, QbonePacketProcessor::Direction direction, + uint8_t traffic_class) override {} protected: // QboneSessionBase interface implementation.