diff mbox series

[iproute2-next] tc_util: Add support for 64-bit hardware packets counter

Message ID 20250204123143.1146078-1-idosch@nvidia.com (mailing list archive)
State New
Delegated to: David Ahern
Headers show
Series [iproute2-next] tc_util: Add support for 64-bit hardware packets counter | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Ido Schimmel Feb. 4, 2025, 12:31 p.m. UTC
The netlink nest that carriers tc action statistics looks as follows:

[TCA_ACT_STATS]
	[TCA_STATS_BASIC]
	[TCA_STATS_BASIC_HW]

Where 'TCA_STATS_BASIC' carries the combined software and hardware
packets (32-bits) and bytes (64-bit) counters and 'TCA_STATS_BASIC_HW'
carries the hardware statistics.

When the number of packets exceeds 0xffffffff, the kernel emits the
'TCA_STATS_PKT64' attribute:

[TCA_ACT_STATS]
	[TCA_STATS_BASIC]
	[TCA_STATS_PKT64]
	[TCA_STATS_BASIC_HW]
	[TCA_STATS_PKT64]

This layout is not ideal as the only way for user space to know what
each 'TCA_STATS_PKT64' attribute carries is to check which attribute
precedes it, which is exactly what some applications are doing [1].

Do the same in iproute2 so that users with existing kernels could read
the 64-bit hardware packets counter of tc actions instead of reading the
truncated 32-bit counter.

Before:

$ tc -s filter show dev swp2 ingress
filter protocol all pref 1 flower chain 0
filter protocol all pref 1 flower chain 0 handle 0x1
  skip_sw
  in_hw in_hw_count 1
        action order 1: mirred (Egress Redirect to device swp1) stolen
        index 1 ref 1 bind 1 installed 47 sec used 23 sec
        Action statistics:
        Sent 368689092544 bytes 5760767071 pkt (dropped 0, overlimits 0 requeues 0)
        Sent software 0 bytes 0 pkt
        Sent hardware 368689092544 bytes 1465799775 pkt
        backlog 0b 0p requeues 0
        used_hw_stats immediate

Where 5760767071 - 1465799775 = 0x100000000

After:

$ tc -s filter show dev swp2 ingress
filter protocol all pref 1 flower chain 0
filter protocol all pref 1 flower chain 0 handle 0x1
  skip_sw
  in_hw in_hw_count 1
        action order 1: mirred (Egress Redirect to device swp1) stolen
        index 1 ref 1 bind 1 installed 71 sec used 47 sec
        Action statistics:
        Sent 368689092544 bytes 5760767071 pkt (dropped 0, overlimits 0 requeues 0)
        Sent software 0 bytes 0 pkt
        Sent hardware 368689092544 bytes 5760767071 pkt
        backlog 0b 0p requeues 0
        used_hw_stats immediate

[1] https://github.com/openvswitch/ovs/commit/006e1c6dbfbadf474c17c8fa1ea358918d371588

Reported-by: Joe Botha <joe@atomic.ac>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 tc/tc_util.c | 44 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/tc/tc_util.c b/tc/tc_util.c
index cf89fb7cbabc..ff0ac170730b 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -665,7 +665,8 @@  void print_tm(const struct tcf_t *tm)
 			   tm->expires / hz);
 }
 
-static void print_tcstats_basic_hw(struct rtattr **tbs, const char *prefix)
+static void print_tcstats_basic_hw(struct rtattr **tbs, const char *prefix,
+				   __u64 packets64, __u64 packets64_hw)
 {
 	struct gnet_stats_basic bs_hw;
 
@@ -674,8 +675,9 @@  static void print_tcstats_basic_hw(struct rtattr **tbs, const char *prefix)
 
 	memcpy(&bs_hw, RTA_DATA(tbs[TCA_STATS_BASIC_HW]),
 	       MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC_HW]), sizeof(bs_hw)));
+	packets64_hw = packets64_hw ? : bs_hw.packets;
 
-	if (bs_hw.bytes == 0 && bs_hw.packets == 0)
+	if (bs_hw.bytes == 0 && packets64_hw == 0)
 		return;
 
 	if (tbs[TCA_STATS_BASIC]) {
@@ -684,15 +686,16 @@  static void print_tcstats_basic_hw(struct rtattr **tbs, const char *prefix)
 		memcpy(&bs, RTA_DATA(tbs[TCA_STATS_BASIC]),
 		       MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]),
 			   sizeof(bs)));
+		packets64 = packets64 ? : bs.packets;
 
-		if (bs.bytes >= bs_hw.bytes && bs.packets >= bs_hw.packets) {
+		if (bs.bytes >= bs_hw.bytes && packets64 >= packets64_hw) {
 			print_nl();
 			print_string(PRINT_FP, NULL, "%s", prefix);
 			print_lluint(PRINT_ANY, "sw_bytes",
 				     "Sent software %llu bytes",
 				     bs.bytes - bs_hw.bytes);
-			print_uint(PRINT_ANY, "sw_packets", " %u pkt",
-				   bs.packets - bs_hw.packets);
+			print_lluint(PRINT_ANY, "sw_packets", " %llu pkt",
+				     packets64 - packets64_hw);
 		}
 	}
 
@@ -700,21 +703,40 @@  static void print_tcstats_basic_hw(struct rtattr **tbs, const char *prefix)
 	print_string(PRINT_FP, NULL, "%s", prefix);
 	print_lluint(PRINT_ANY, "hw_bytes", "Sent hardware %llu bytes",
 		     bs_hw.bytes);
-	print_uint(PRINT_ANY, "hw_packets", " %u pkt", bs_hw.packets);
+	print_lluint(PRINT_ANY, "hw_packets", " %llu pkt", packets64_hw);
+}
+
+static void parse_packets64(const struct rtattr *nest, __u64 *p_packets64,
+			    __u64 *p_packets64_hw)
+{
+	unsigned short prev_type = __TCA_STATS_MAX;
+	const struct rtattr *pos;
+
+	/* 'TCA_STATS_PKT64' can appear twice in the 'TCA_ACT_STATS' nest.
+	 * Whether the attribute carries the combined or hardware only
+	 * statistics depends on the attribute that precedes it in the nest.
+	 */
+	rtattr_for_each_nested(pos, nest) {
+		if (pos->rta_type == TCA_STATS_PKT64 &&
+		    prev_type == TCA_STATS_BASIC)
+			*p_packets64 = rta_getattr_u64(pos);
+		else if (pos->rta_type == TCA_STATS_PKT64 &&
+			 prev_type == TCA_STATS_BASIC_HW)
+			*p_packets64_hw = rta_getattr_u64(pos);
+		prev_type = pos->rta_type;
+	}
 }
 
 void print_tcstats2_attr(struct rtattr *rta, const char *prefix, struct rtattr **xstats)
 {
 	struct rtattr *tbs[TCA_STATS_MAX + 1];
+	__u64 packets64 = 0, packets64_hw = 0;
 
 	parse_rtattr_nested(tbs, TCA_STATS_MAX, rta);
+	parse_packets64(rta, &packets64, &packets64_hw);
 
 	if (tbs[TCA_STATS_BASIC]) {
 		struct gnet_stats_basic bs = {0};
-		__u64 packets64 = 0;
-
-		if (tbs[TCA_STATS_PKT64])
-			packets64 = rta_getattr_u64(tbs[TCA_STATS_PKT64]);
 
 		memcpy(&bs, RTA_DATA(tbs[TCA_STATS_BASIC]),
 		       MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]), sizeof(bs)));
@@ -740,7 +762,7 @@  void print_tcstats2_attr(struct rtattr *rta, const char *prefix, struct rtattr *
 	}
 
 	if (tbs[TCA_STATS_BASIC_HW])
-		print_tcstats_basic_hw(tbs, prefix);
+		print_tcstats_basic_hw(tbs, prefix, packets64, packets64_hw);
 
 	if (tbs[TCA_STATS_RATE_EST64]) {
 		struct gnet_stats_rate_est64 re = {0};