On 19/07/2025 11:30, Mohsin Bashir wrote: > Test XDP_PASS/DROP in single buffer and multi buffer mode when > XDP native support is available. > > ./drivers/net/xdp.py > TAP version 13 > 1..4 > ok 1 xdp.test_xdp_native_pass_sb > ok 2 xdp.test_xdp_native_pass_mb > ok 3 xdp.test_xdp_native_drop_sb > ok 4 xdp.test_xdp_native_drop_mb > \# Totals: pass:4 fail:0 xfail:0 xpass:0 skip:0 error:0 > > Signed-off-by: Jakub Kicinski <k...@kernel.org> > Signed-off-by: Mohsin Bashir <mohsin.ba...@gmail.com> > --- > tools/testing/selftests/drivers/net/Makefile | 1 + > tools/testing/selftests/drivers/net/xdp.py | 303 ++++++++++++++++++ > .../selftests/net/lib/xdp_native.bpf.c | 158 +++++++++ > 3 files changed, 462 insertions(+) > create mode 100755 tools/testing/selftests/drivers/net/xdp.py > create mode 100644 tools/testing/selftests/net/lib/xdp_native.bpf.c >
... > + > +static struct udphdr *filter_udphdr(struct xdp_md *ctx, __u16 port) > +{ > + void *data_end = (void *)(long)ctx->data_end; > + void *data = (void *)(long)ctx->data; > + struct udphdr *udph = NULL; > + struct ethhdr *eth = data; > + > + if (data + sizeof(*eth) > data_end) > + return NULL; > + This check assumes that the packet headers reside in the linear part of the xdp_buff. However, this assumption does not hold across all drivers. For example, in mlx5, the linear part is empty when using multi-buffer mode with striding rq configuration. This causes all multi-buffer test cases to fail over mlx5. To ensure correctness across all drivers, all direct accesses to packet data should use these safer helper functions instead: bpf_xdp_load_bytes() and bpf_xdp_store_bytes(). Related discussion and context can be found here: https://github.com/xdp-project/xdp-tools/pull/409 > + if (eth->h_proto == bpf_htons(ETH_P_IP)) { > + struct iphdr *iph = data + sizeof(*eth); > + > + if (iph + 1 > (struct iphdr *)data_end || > + iph->protocol != IPPROTO_UDP) > + return NULL; > + > + udph = (void *)eth + sizeof(*iph) + sizeof(*eth); > + } else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { > + struct ipv6hdr *ipv6h = data + sizeof(*eth); > + > + if (ipv6h + 1 > (struct ipv6hdr *)data_end || > + ipv6h->nexthdr != IPPROTO_UDP) > + return NULL; > + > + udph = (void *)eth + sizeof(*ipv6h) + sizeof(*eth); > + } else { > + return NULL; > + } > + > + if (udph + 1 > (struct udphdr *)data_end) > + return NULL; > + > + if (udph->dest != bpf_htons(port)) > + return NULL; > + > + record_stats(ctx, STATS_RX); > + > + return udph; > +}