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.