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 <[email protected]>
---
V1 -> V2:
- Start the measurement at the first packet with data instead of running
tc_edt serially, as it also fails without -j (Alexei)
- Add before/after data
v1:
https://lore.kernel.org/r/[email protected]
---
tools/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 462512fb191f1..1391978a3e309 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 4f6f03122d61d..69f4b16acbef6 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;
}
---
base-commit: e1d84a37cba984388988d2f1ddc84561413f0db2
change-id: 20261009-selftests-bpf-tc-edt-serial-9c65af71f845
Best regards,
--
Qiliang Yuan <[email protected]>