Add QoS dimension to packet processor result metrics.

PiperOrigin-RevId: 617205961
diff --git a/quiche/quic/qbone/qbone_packet_processor.cc b/quiche/quic/qbone/qbone_packet_processor.cc
index 75cf6d1..7fdfd0f 100644
--- a/quiche/quic/qbone/qbone_packet_processor.cc
+++ b/quiche/quic/qbone/qbone_packet_processor.cc
@@ -8,6 +8,7 @@
 #include <netinet/in.h>
 #include <netinet/ip6.h>
 
+#include <cstdint>
 #include <cstring>
 
 #include "absl/base/optimization.h"
@@ -68,10 +69,11 @@
 
 void QbonePacketProcessor::ProcessPacket(std::string* packet,
                                          Direction direction) {
+  uint8_t traffic_class = TrafficClassFromHeader(*packet);
   if (ABSL_PREDICT_FALSE(!IsValid())) {
     QUIC_BUG(quic_bug_11024_1)
         << "QuicPacketProcessor is invoked in an invalid state.";
-    stats_->OnPacketDroppedSilently(direction);
+    stats_->OnPacketDroppedSilently(direction, traffic_class);
     return;
   }
 
@@ -96,13 +98,13 @@
           output_->SendPacketToClient(*packet);
           break;
       }
-      stats_->OnPacketForwarded(direction);
+      stats_->OnPacketForwarded(direction, traffic_class);
       break;
     case ProcessingResult::SILENT_DROP:
-      stats_->OnPacketDroppedSilently(direction);
+      stats_->OnPacketDroppedSilently(direction, traffic_class);
       break;
     case ProcessingResult::DEFER:
-      stats_->OnPacketDeferred(direction);
+      stats_->OnPacketDeferred(direction, traffic_class);
       break;
     case ProcessingResult::ICMP:
       if (icmp_header.icmp6_type == ICMP6_ECHO_REPLY) {
@@ -115,17 +117,17 @@
       } else {
         SendIcmpResponse(dst, &icmp_header, *packet, direction);
       }
-      stats_->OnPacketDroppedWithIcmp(direction);
+      stats_->OnPacketDroppedWithIcmp(direction, traffic_class);
       break;
     case ProcessingResult::ICMP_AND_TCP_RESET:
       SendIcmpResponse(dst, &icmp_header, *packet, direction);
-      stats_->OnPacketDroppedWithIcmp(direction);
+      stats_->OnPacketDroppedWithIcmp(direction, traffic_class);
       SendTcpReset(*packet, direction);
-      stats_->OnPacketDroppedWithTcpReset(direction);
+      stats_->OnPacketDroppedWithTcpReset(direction, traffic_class);
       break;
     case ProcessingResult::TCP_RESET:
       SendTcpReset(*packet, direction);
-      stats_->OnPacketDroppedWithTcpReset(direction);
+      stats_->OnPacketDroppedWithTcpReset(direction, traffic_class);
       break;
   }
 }
@@ -288,4 +290,15 @@
   }
 }
 
+uint8_t QbonePacketProcessor::TrafficClassFromHeader(
+    absl::string_view ipv6_header) {
+  // Packets that reach this function should have already been validated.
+  // However, there are tests that bypass that validation that fail because this
+  // would be out of bounds.
+  if (ipv6_header.length() < 2) {
+    return 0;  // Default to BE1
+  }
+
+  return ipv6_header[0] << 4 | ipv6_header[1] >> 4;
+}
 }  // namespace quic
diff --git a/quiche/quic/qbone/qbone_packet_processor.h b/quiche/quic/qbone/qbone_packet_processor.h
index fed7a8b..b337b19 100644
--- a/quiche/quic/qbone/qbone_packet_processor.h
+++ b/quiche/quic/qbone/qbone_packet_processor.h
@@ -9,6 +9,8 @@
 #include <netinet/in.h>
 #include <netinet/ip6.h>
 
+#include <cstdint>
+
 #include "absl/strings/string_view.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/platform/api/quic_ip_address.h"
@@ -63,11 +65,16 @@
    public:
     virtual ~StatsInterface();
 
-    virtual void OnPacketForwarded(Direction direction) = 0;
-    virtual void OnPacketDroppedSilently(Direction direction) = 0;
-    virtual void OnPacketDroppedWithIcmp(Direction direction) = 0;
-    virtual void OnPacketDroppedWithTcpReset(Direction direction) = 0;
-    virtual void OnPacketDeferred(Direction direction) = 0;
+    virtual void OnPacketForwarded(Direction direction,
+                                   uint8_t traffic_class) = 0;
+    virtual void OnPacketDroppedSilently(Direction direction,
+                                         uint8_t traffic_class) = 0;
+    virtual void OnPacketDroppedWithIcmp(Direction direction,
+                                         uint8_t traffic_class) = 0;
+    virtual void OnPacketDroppedWithTcpReset(Direction direction,
+                                             uint8_t traffic_class) = 0;
+    virtual void OnPacketDeferred(Direction direction,
+                                  uint8_t traffic_class) = 0;
   };
 
   // Allows to implement a custom packet filter on top of the filtering done by
@@ -110,9 +117,6 @@
     uint8_t TransportProtocolFromHeader(absl::string_view ipv6_header) {
       return ipv6_header[6];
     }
-    uint8_t TrafficClassFromHeader(absl::string_view ipv6_header) {
-      return ipv6_header[0] << 4 | ipv6_header[1] >> 4;
-    }
 
     QuicIpAddress SourceIpFromHeader(absl::string_view ipv6_header) {
       QuicIpAddress address;
@@ -158,6 +162,9 @@
 
   static const QuicIpAddress kInvalidIpAddress;
 
+  // This function assumes that the packet is valid.
+  static uint8_t TrafficClassFromHeader(absl::string_view ipv6_header);
+
  protected:
   // Processes the header and returns what should be done with the packet.
   // After that, calls an external packet filter if registered.  TTL of the
diff --git a/quiche/quic/qbone/qbone_packet_processor_test.cc b/quiche/quic/qbone/qbone_packet_processor_test.cc
index 85cf0ca..f3361b7 100644
--- a/quiche/quic/qbone/qbone_packet_processor_test.cc
+++ b/quiche/quic/qbone/qbone_packet_processor_test.cc
@@ -355,18 +355,18 @@
 };
 
 TEST_F(QbonePacketProcessorTest, EmptyPacket) {
-  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK, _));
   SendPacketFromClient("");
 
-  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_NETWORK, _));
   SendPacketFromNetwork("");
 }
 
 TEST_F(QbonePacketProcessorTest, RandomGarbage) {
-  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK, _));
   SendPacketFromClient(std::string(1280, 'a'));
 
-  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_NETWORK, _));
   SendPacketFromNetwork(std::string(1280, 'a'));
 }
 
@@ -375,31 +375,31 @@
   packet[4] = 0;
   packet[5] = 0;
 
-  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_OFF_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToClient(IsIcmpMessage(ICMP6_DST_UNREACH)));
   SendPacketFromClient(packet);
 }
 
 TEST_F(QbonePacketProcessorTest, GoodPacketFromClient) {
-  EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_OFF_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToNetwork(_));
   SendPacketFromClient(kReferenceClientPacket);
 }
 
 TEST_F(QbonePacketProcessorTest, GoodPacketFromClientSubnet) {
-  EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_OFF_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToNetwork(_));
   SendPacketFromClient(kReferenceClientSubnetPacket);
 }
 
 TEST_F(QbonePacketProcessorTest, GoodPacketFromNetwork) {
-  EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_NETWORK));
+  EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToClient(_));
   SendPacketFromNetwork(kReferenceNetworkPacket);
 }
 
 TEST_F(QbonePacketProcessorTest, GoodPacketFromNetworkWrongDirection) {
-  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_OFF_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToClient(IsIcmpMessage(ICMP6_DST_UNREACH)));
   SendPacketFromClient(kReferenceNetworkPacket);
 }
@@ -408,7 +408,7 @@
   std::string packet(kReferenceNetworkPacket);
   packet[7] = 1;
 
-  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToNetwork(IsIcmpMessage(ICMP6_TIME_EXCEEDED)));
   SendPacketFromNetwork(packet);
 }
@@ -417,7 +417,7 @@
   std::string packet(kReferenceNetworkPacket);
   packet[6] = IPPROTO_SCTP;
 
-  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToNetwork(IsIcmpMessage(ICMP6_PARAM_PROB)));
   SendPacketFromNetwork(packet);
 }
@@ -428,7 +428,7 @@
       .WillRepeatedly(Return(ProcessingResult::SILENT_DROP));
   processor_->set_filter(std::move(filter));
 
-  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK, _));
   SendPacketFromClient(kReferenceClientPacket);
 }
 
@@ -446,7 +446,7 @@
     EXPECT_EQ(client_ip_, SourceIpFromHeader(full_packet));
     EXPECT_EQ(network_ip_, DestinationIpFromHeader(full_packet));
 
-    last_tos_ = TrafficClassFromHeader(full_packet);
+    last_tos_ = QbonePacketProcessor::TrafficClassFromHeader(full_packet);
     called_++;
     return ProcessingResult::SILENT_DROP;
   }
@@ -469,7 +469,7 @@
   TestFilter* filter = filter_owned.get();
   processor_->set_filter(std::move(filter_owned));
 
-  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK, _));
   SendPacketFromClient(kReferenceClientPacket);
   ASSERT_EQ(1, filter->called());
 }
@@ -479,7 +479,7 @@
   TestFilter* filter = filter_owned.get();
   processor_->set_filter(std::move(filter_owned));
 
-  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK))
+  EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_OFF_NETWORK, _))
       .Times(testing::AnyNumber());
   SendPacketFromClient(kReferenceClientPacket);
   ASSERT_EQ(0, filter->last_tos());
@@ -508,7 +508,7 @@
           })));
   processor_->set_filter(std::move(filter));
 
-  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_OFF_NETWORK));
+  EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_OFF_NETWORK, _));
   EXPECT_CALL(output_, SendPacketToClient(_))
       .WillOnce(Invoke([](absl::string_view packet) {
         // Explicit conversion because otherwise it is treated as a null
diff --git a/quiche/quic/qbone/qbone_packet_processor_test_tools.h b/quiche/quic/qbone/qbone_packet_processor_test_tools.h
index 3d3492d..9b0ff85 100644
--- a/quiche/quic/qbone/qbone_packet_processor_test_tools.h
+++ b/quiche/quic/qbone/qbone_packet_processor_test_tools.h
@@ -5,6 +5,8 @@
 #ifndef QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_TEST_TOOLS_H_
 #define QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_TEST_TOOLS_H_
 
+#include <cstdint>
+
 #include "absl/strings/string_view.h"
 #include "quiche/quic/platform/api/quic_test.h"
 #include "quiche/quic/qbone/qbone_packet_processor.h"
@@ -23,16 +25,16 @@
  public:
   MockPacketProcessorStats() {}
 
-  MOCK_METHOD(void, OnPacketForwarded, (QbonePacketProcessor::Direction),
-              (override));
-  MOCK_METHOD(void, OnPacketDroppedSilently, (QbonePacketProcessor::Direction),
-              (override));
-  MOCK_METHOD(void, OnPacketDroppedWithIcmp, (QbonePacketProcessor::Direction),
-              (override));
+  MOCK_METHOD(void, OnPacketForwarded,
+              (QbonePacketProcessor::Direction, uint8_t), (override));
+  MOCK_METHOD(void, OnPacketDroppedSilently,
+              (QbonePacketProcessor::Direction, uint8_t), (override));
+  MOCK_METHOD(void, OnPacketDroppedWithIcmp,
+              (QbonePacketProcessor::Direction, uint8_t), (override));
   MOCK_METHOD(void, OnPacketDroppedWithTcpReset,
-              (QbonePacketProcessor::Direction), (override));
-  MOCK_METHOD(void, OnPacketDeferred, (QbonePacketProcessor::Direction),
-              (override));
+              (QbonePacketProcessor::Direction, uint8_t), (override));
+  MOCK_METHOD(void, OnPacketDeferred,
+              (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 c313816..0f325a6 100644
--- a/quiche/quic/qbone/qbone_server_session.h
+++ b/quiche/quic/qbone/qbone_server_session.h
@@ -5,6 +5,8 @@
 #ifndef QUICHE_QUIC_QBONE_QBONE_SERVER_SESSION_H_
 #define QUICHE_QUIC_QBONE_QBONE_SERVER_SESSION_H_
 
+#include <cstdint>
+
 #include "absl/strings/string_view.h"
 #include "quiche/quic/core/quic_crypto_server_stream_base.h"
 #include "quiche/quic/core/quic_crypto_stream.h"
@@ -59,14 +61,16 @@
   void SendPacketToNetwork(absl::string_view packet) override;
 
   // QbonePacketProcessor::StatsInterface implementation.
-  void OnPacketForwarded(QbonePacketProcessor::Direction direction) override {}
-  void OnPacketDroppedSilently(
-      QbonePacketProcessor::Direction direction) override {}
-  void OnPacketDroppedWithIcmp(
-      QbonePacketProcessor::Direction direction) override {}
-  void OnPacketDroppedWithTcpReset(
-      QbonePacketProcessor::Direction direction) override {}
-  void OnPacketDeferred(QbonePacketProcessor::Direction direction) override {}
+  void OnPacketForwarded(QbonePacketProcessor::Direction direction,
+                         uint8_t traffic_class) override {}
+  void OnPacketDroppedSilently(QbonePacketProcessor::Direction direction,
+                               uint8_t traffic_class) override {}
+  void OnPacketDroppedWithIcmp(QbonePacketProcessor::Direction direction,
+                               uint8_t traffic_class) override {}
+  void OnPacketDroppedWithTcpReset(QbonePacketProcessor::Direction direction,
+                                   uint8_t traffic_class) override {}
+  void OnPacketDeferred(QbonePacketProcessor::Direction direction,
+                        uint8_t traffic_class) override {}
 
  protected:
   // QboneSessionBase interface implementation.