From b116ac6087541d3d98031e786adbe9c733cd6df3 Mon Sep 17 00:00:00 2001 From: Qiliang Yuan Date: Mon, 19 Oct 2026 14:35:55 +0800 Subject: [PATCH] selftests/bpf: Time tc_edt from its first packet with data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tc_edt sends 1MB over a TCP connection that a BPF program shapes with EDT, and checks that the rate it measures is within 2% of the target rate. The transfer takes about 200ms, so the margin is about 4ms. The measurement starts before send_recv_data(), which first creates the sender thread and accepts the connection. On a KASAN kernel, x86_64 VM with 32 vCPUs, that takes 0.7ms when idle and up to 4.7ms with all CPUs busy, while the BPF program spreads the data over 200.08ms in the median. The test also fails without test_progs -j where everything runs slower, e.g. on s390x and with ASAN in BPF CI. Have the BPF program note when the first packet with data goes out, and start the measurement there. tc_edt run 100 times on the same VM, idle and with 32 busy loops in the background, before and after this patch: before after idle 0 of 100 failed 0 of 100 failed busy loops 3 of 100 failed 0 of 100 failed Fixes: b0f82e7ab6fb ("selftests/bpf: integrate test_tc_edt into test_progs") Signed-off-by: Qiliang Yuan Signed-off-by: Alexei Starovoitov Reviewed-by: Alexis Lothoré (eBPF Foundation) Link: https://patch.msgid.link/20261019-selftests-bpf-tc-edt-serial-v2-1-41c3813e7916@gmail.com --- .../testing/selftests/bpf/prog_tests/test_tc_edt.c | 13 ++++++++++--- tools/testing/selftests/bpf/progs/test_tc_edt.c | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_tc_edt.c b/tools/testing/selftests/bpf/prog_tests/test_tc_edt.c index 462512fb191f..1391978a3e30 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_tc_edt.c +++ b/tools/testing/selftests/bpf/prog_tests/test_tc_edt.c @@ -90,7 +90,7 @@ static void cleanup(void) remove_netns(SERVER_NS); } -static void run_test(void) +static void run_test(struct test_tc_edt *skel) { int server_fd, client_fd, err; double rate_mbps, rate_error; @@ -113,12 +113,19 @@ static void run_test(void) if (!ASSERT_OK_FD(client_fd, "connect client")) return; - ts_start = get_time_ns(); err = send_recv_data(server_fd, client_fd, TX_BYTES_COUNT); ts_end = get_time_ns(); close_netns(nstoken); ASSERT_OK(err, "send_recv_data"); + /* + * Start from the first packet with data rather than before + * send_recv_data(), which also sets up the sender. + */ + ts_start = skel->bss->tx_start_ns; + if (!ASSERT_GT(ts_start, 0, "tx_start_ns")) + return; + rate_mbps = TX_BYTES_COUNT / ((ts_end - ts_start) / 1000.0); rate_error = fabs((rate_mbps - TARGET_RATE_MBPS) * 100.0 / TARGET_RATE_MBPS); @@ -138,7 +145,7 @@ void test_tc_edt(void) if (!ASSERT_OK(setup(skel), "global setup")) return; - run_test(); + run_test(skel); cleanup(); test_tc_edt__destroy(skel); diff --git a/tools/testing/selftests/bpf/progs/test_tc_edt.c b/tools/testing/selftests/bpf/progs/test_tc_edt.c index 4f6f03122d61..69f4b16acbef 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_edt.c +++ b/tools/testing/selftests/bpf/progs/test_tc_edt.c @@ -24,6 +24,7 @@ struct { } flow_map SEC(".maps"); __uint64_t target_rate; +__uint64_t tx_start_ns; static inline int throttle_flow(struct __sk_buff *skb) { @@ -62,7 +63,8 @@ static inline int throttle_flow(struct __sk_buff *skb) return TC_ACT_OK; } -static inline int handle_tcp(struct __sk_buff *skb, struct tcphdr *tcp) +static inline int handle_tcp(struct __sk_buff *skb, struct tcphdr *tcp, + uint32_t hdr_len) { void *data_end = (void *)(long)skb->data_end; @@ -70,8 +72,12 @@ static inline int handle_tcp(struct __sk_buff *skb, struct tcphdr *tcp) if ((void *)(tcp + 1) > data_end) return TC_ACT_SHOT; - if (tcp->source == bpf_htons(9000)) + if (tcp->source == bpf_htons(9000)) { + /* Note when the first packet with data goes out */ + if (!tx_start_ns && skb->len > hdr_len + tcp->doff * 4) + tx_start_ns = bpf_ktime_get_ns(); return throttle_flow(skb); + } return TC_ACT_OK; } @@ -94,7 +100,8 @@ static inline int handle_ipv4(struct __sk_buff *skb) return TC_ACT_SHOT; if (iph->protocol == IPPROTO_TCP) - return handle_tcp(skb, (struct tcphdr *)(((void *)iph) + ihl)); + return handle_tcp(skb, (struct tcphdr *)(((void *)iph) + ihl), + sizeof(struct ethhdr) + ihl); return TC_ACT_OK; }